I have a very small site with my .htaccess set up to allow urls like:
mysite.com/brand/login
mysite.com/brand/dashboard
mysite.com/controller
These all redirect to:
mysite.com/driver.php?___=brand/login
mysite.com/driver.php?___=brand/dashboard
mysite.com/driver.php?___=controller
I'm simply using one rewrite rule for this:
RewriteRule ^(([a-zA-Z0-9\-\_]+/?)*)$ index.php?___=$1 [L,QSA]
But anyway, it works great, until I have a page with the same name as a folder in my site.
// I navigate to:
mysite.com/javascript
// The site automatically provides a 301 redirect to
mysite.com/javascript/? ___=javascript
And now that ugly URL is showing up in my users' browsers. Is there any way to tell the site that I want to take care of all redirects myself?
EDIT: I determined this using fiddler. Another example:
Welp found the answer right after posting this. This line in .htaccess fixed the problem.
DirectorySlash Off
I then, of course, had to clear my browser cache to make it forget about the 301.
https://httpd.apache.org/docs/2.4/mod/mod_dir.html#directoryslash
The DirectorySlash directive determines whether mod_dir should fixup
URLs pointing to a directory or not.
Typically if a user requests a resource without a trailing slash,
which points to a directory, mod_dir redirects him to the same
resource, but with trailing slash
And a security warning:
Turning off the trailing slash redirect may result in an information
disclosure. Consider a situation where mod_autoindex is active
(Options +Indexes) and DirectoryIndex is set to a valid resource (say,
index.html) and there's no other special handler defined for that URL.
In this case a request with a trailing slash would show the index.html
file. But a request without trailing slash would list the directory
contents.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
i am newbie of php
How to create simple remove .php extension with .htaccess page?
My aims is type this url http://site/Test
it can visit hello.php content, anyone know how to do that?? thx
I have one folder that call "Test", there are two file on "Test" Folder
Test/
-hello.php
-.htaccess
hello.php
<?php echo "Hello World"; ?>
.htaccess
RewriteEngine on
RewriteRule ^(.*)$ $1.php
finally, it is not successful
it display the following error message
**Internal Server Error**
The server encountered an internal error or misconfiguration and was unable to complete your request.
anyidea to solve this??? Thank you very much
My aims is type this url http://site/Test it can visit hello.php content, anyone know how to do that?
This isn't simply "file extension removal". If it was then /Test would serve the content from /Test.php. In your example, you are wanting to serve the contents of an entirely different file.
Rewriting the request with mod_rewrite
Since you are requesting a directory (/Test/) and wanting to serve a file from within that directory and the .htaccess file itself is actually located in that directory, you would need to write your RewriteRule like this:
RewriteRule ^$ hello.php [L]
In .htaccess (directory context), the RewriteRule pattern matches the URL-path relative to the location of the .htaccess file. So, in this case the URL-path we are matching against is simply an empty string, ie. ^$, since we are wanting to match /Test/<nothing>.
Likewise, when the susbtitution string (ie. hello.php) is relative (as it is here), it is relative to the location of the .htaccess file. So, in this case it effectively rewrites the request to /Test/hello.php (it's actually the absolute filesystem path, eg. /var/www/user/public_html/Test/hello.php - after the directory-prefix is added back).
Additional issues with this example
Since you are rewriting a request that would otherwise map to a physical directory there are a couple of potential issues you need to be aware of...
You should request the directory with a trailing slash, ie. /Test/, not /Test (as you stated in your initial example), otherwise mod_dir will issue a 301 redirect to append the slash before your rewrite is successful.
(There are ways to avoid the trailing slash, but this does increase the complexity and requires further manual rewrites.)
An additional complication occurs if there is a DirectoryIndex document in this subdirectory. eg. /Test/index.php. In this case mod_dir issues an internal subrequest to the DirectoryIndex document (eg. index.php) and this takes priority over your internal rewrite. (Your rewrite does still occur, but mod_dir "wins".) If this is the case then you can rewrite the DirectoryIndex document instead of an empty URL-path. For example:
RewriteRule ^index\.php$ hello.php [L]
This is perhaps counter-intuitive, as we are now rewriting the internal subrequest that mod_dir has issued in a later pass through the file.
You could handle both scenarios and make index.php optional. For example:
RewriteRule ^(index\.php)?$ hello.php [L]
RewriteRule ^(.*)$ $1.php
Your example would result in an internal rewrite loop (500 Internal Server Error response) since the pattern ^(.*)$ also matches the rewritten URL and it gets stuck in an endless loop. (The rewriting process doesn't just consist of a single pass through the file. The process repeats until the URL passes through unchanged.)
(Incidentally, this IS an extensionless URL type of rewrite, but it doesn't help you achieve what you stated in your example.)
There are various ways to prevent this "endless loop":
Use a more specific regex, that won't also match the rewritten URL. eg. a regex that excludes a dot such as ^([^.]+)$.
Use a RewriteCond (condition) directive that prevents the rule being triggered on the rewritten URL. eg. Exclude .php files or check that the request does not map to a file, etc.
Use the END flag on the RewriteRule to stop all further processing by the rewrite engine.
Alternative - change the DirectoryIndex
Instead of using mod_rewrite, as explained above, to internally rewrite the request, we could instead change the DirectoryIndex document.
This only works in this particular case where you are requesting a directory and wanting to serve a file from that directory (although strictly speaking the file could be anywhere).
The DirectoryIndex is the document that mod_dir will look for when requesting a directory (eg. /test/). By default, it looks for index.html (and often index.php) and possibly others. If a DirectoryIndex document is not found, you get a 403 Forbidden when requesting that directory (assuming auto-directory indexes are disabled).
For example, you could set the following:
DocumentIndex hello.php
And now when you request /Test/, mod_dir will serve hello.php in that directory.
However, this method (by itself) is limiting and potentially confusing for readers of your code (if changing the DirectoryIndex on a directory by directory basis). It is generally expected that the DirectoryIndex document(s) is consistent throughout your site.
The weirdest thing. Both rewrite rules are working on our Test server but the second one locations is not working on Production and adds a / at the end of locations/ for some reason. The configuration is the same on both servers.
I am trying to simplify the URL without renaming the file. So that if the user enters site.php/locations it will load the content of the redirect page but retain the simplified URL
Any ideas as to why the locations redirect is not working?
RewriteEngine on
RewriteBase /
// The next two are statements are just for context. They preceded the faq and locations forward
RewriteCond %{REQUEST_URI} ^/index.php$
RewriteRule (.*) / [R=301,L]
// The two rewrites that I want
RewriteRule ^faq$ /faq-mailbox-account.php [NC,L]
RewriteRule ^locations$ /choose-digital-mailbox-location.php [NC,L]
... on Production and adds a / at the end of locations/ for some reason
This will happen if locations exists as a physical directory on the filesystem. (Or existed and the response was cached.)
If you request /locations and /locations exists as a physical directory then mod_dir will issue a 301 external redirect to append the trailing slash - ordinarily, this is necessary in order to "fix" the URL.
This external "redirect" by mod_dir will happen regardless of whether your rule matches or not*1, since it is "only" an internal rewrite and not another redirect. (*1 In fact, it does match and the rewrite does occur, but it is effectively overridden by the mod_dir redirect.)
You could append an optional slash to your RewriteRule pattern, eg. ^locations/?$ - but the redirect will still occur first if you are requesting /locations without the trailing slash. You would need to request a URL that already contains the trailing slash.
You could prevent mod_dir from appending the trailing slash using DirectorySlash Off, however, this potentially has other implications for your system.
Note also, that since this is a 301 (permanent) redirect, it will likely be cached persistently by your browser. So, if the /locations directory has since been deleted on the server, the browser will still redirect the user until all client-side caches have been cleared also.
The configuration is the same on both servers.
So, there is (or was) a /locations directory on both servers?
If the configuration is the same on both servers then you would get the same response, so there must be some difference. Or, there is a client-side caching issue.
So that if the user enters site.php/locations
I assume you meant site.com/locations - otherwise, the directives you posted have no hope of working, as they simply won't match.
The problem was due to a symbolically linked drive on Prod
I have been trying for hours now to create this .htaccess file without luck.
I have redeveloped my site and my SEO is a bit all over the place. For Google's and my users' sake, I need a .htaccess file that:
Redirects http://example.com/* to https://example.com/*
Redirects *.example.com/*.php to https://example.com/*
Redirects *.example.com/*/ to https://example.com/*
So to clarify, forces SSL, removes trailing slashes and .php extensions in a Google friendly (301-redirect) way. Or any combination of the above.
This should do it - for all listed cases
Redirect permanent / https://secure.example.com/
Ref: https://wiki.apache.org/httpd/RedirectSSL
I have clean path with the same name as existing directory.
I use these .htaccess rules to support clean path for the path:
RewriteCond ${REQUEST_URI} ^/mydir
RewriteCond ${REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
everything works correctly (I have a "mydir" clean path working and I can access existing files in the /mydir directory directly), but apache appends the trailing slash all the time to requests.
I request http://domain.com/mydir, and it redirects me 301 to http://domain.com/mydir/.
What is the reason?
Trailing slash after /mydir/ is added by an Apache module called mod_dir that adds a trailing slash after all the directories. This is due to this setting turned on by default:
DirectorySlash On
You can turn it off using:
DirectorySlash Off
However it might expose some directories by showing their listings.
Security Warning
Turning off the trailing slash redirect may result in an information
disclosure. Consider a situation where mod_autoindex is active
(Options +Indexes) and DirectoryIndex is set to a valid resource (say,
index.html) and there's no other special handler defined for that URL.
In this case a request with a trailing slash would show the index.html
file. But a request without trailing slash would list the directory
contents.
Apache's proper URL always ends in a slash /. Because it treats URL's as if they were a disk file path (which always ends in a slash). If it's not there, the server needs to take one additional step to internally add it. I say let it be.
Plus Google (supposedly) likes the trailing slashes.
I say keep it as is.
Please read more: http://cdivilly.wordpress.com/2014/03/11/why-trailing-slashes-on-uris-are-important/
and here: http://bit.ly/1uSvbfy :)
I have changed the CMS to my site and it has rewritten the URLs to be more friendly but I have 20 pages which are linked on different sites across the web. I want when people click those old links for them to be redirected to their new respective posts.
I was at first thinking of using a PHP array with a javascript redirect but now I'm thinking .htaccess mod-rewrite would be best.
Whats the best way to have specific URLs redirect to their new URLs?
Use the .htaccess file for redirects. For example:
# This allows you to redirect index.html to a specific url
Redirect /index.html http://example.com/location/
Add some regex to match your rewrites and send to the dynamically created remote url. For example:
# Dynamic redirect
RedirectMatch 301 yourUrl/\(.*)\$ http://external.com/someUrl.html?dynamicVal=$1
That would send ...yourUrl/123 -> http://external.com/someUrl.html?dynamicVal=123
If you are talking about URLs on your pages, then the best way is to edit all such pages with current proper URLs.
If you are talking about "what to do when someone hits my old URL (from their bookmarks or by clicking a link on another site, for example) then the best way is to redirect (with code 301) such requests to a new location using Apache's URL Rewrite module.
Example:
# Activate Rewrite Engine
RewriteEngine On
# redirect to another page on the same site
RewriteRule ^mypage.php /other/mypage.php [R=301,L,QSA]
# redirect to another page on ANOTHER site
RewriteRule ^mypage.php http://www.anothersite.com/mypage.php [R=301,L,QSA]
Here is the link to Apache's manual for mod-rewrite.
Another useful place -- Mod_Rewrite Forums.
Apache supports different modules to rewrite/redirect requested URIs:
mod_alias with Alias and AliasMatch for internal rewriting, as well as Redirect and RedirectMatch for external redirecting
mod_rewrite with RewriteRule for internal rewriting and external redirecting
The main difference between the mod_alias and mod_rewrite directives is that mod_alias’s Alias and Redirect directives work with path prefix patterns while the other directives (i.e. AliasMatch, RedirectMatch, and RewriteRule) work with regular expressions.
A path prefix pattern is always always matched when it’s a qualified prefix of the requested path and the remaining path segments are automatically appended to the target path. Here’s an example:
Redirect /foo/bar http://other.example/quux
If /foo/bar is requested, it’s getting redirected to http://other.example/quux; likewise /foo/bar/baz is getting redirected to http://other.example/quux/baz. Alias works alike but just internally.
In opposite to that, AliasMatch, RedirectMatch, and RewriteRule work with regular expressions and can be used not just to match path prefixes. Here’s an example:
RedirectMatch ^/foo/bar$ http://other.example/quux
If /foo/bar is requested, it’s getting redirected to http://other.example/quux (just like the Redirect example above). But if /foo/bar/quux is requested, it’s not getting redirected as ^/foo/bar$ doesn’t match /foo/bar/quux.
Futher differences between mod_alias and mod_rewrite are that mod_rewrite can also examine other parts of the URI except the path and even HTTP request header fields. It does also allow more complex operations with multiple conditions.