Earlier today, I was trying to remove the php
file extension when people visit my website using .htaccess
. (Sort of like https://tecadmin.net/remove-file-extension-from-url-using-htaccess/)
Below is my .htaccess
file:
#Remove php file extensions
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.] )$ $1.php [NC,L]
RewriteEngine on
RewriteCond %{THE_REQUEST} /([^.] )\.php [NC]
RewriteRule ^ /%1 [NC,L,R]
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^ %{REQUEST_URI}.php [NC,L]
The code seems to be doing its job, but I quickly noticed a problem. http://example.com/page
and http://example.com/page.php
works perfectly fine, but when I visit http://example.com/page/
, the server returns an internal server error. (500)
I tried looking online on how to fix this, but I came up empty. Does anyone know how to fix this problem?
CodePudding user response:
RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^([^\.] )$ $1.php [NC,L] RewriteEngine on RewriteCond %{THE_REQUEST} /([^.] )\.php [NC] RewriteRule ^ /%1 [NC,L,R] RewriteCond %{REQUEST_FILENAME}.php -f RewriteRule ^ %{REQUEST_URI}.php [NC,L]
Your first and last rules are doing the same sort of thing (appending the .php
extension via an internal rewrite), however, they are doing it slightly differently and arguably incorrectly. And you certainly don't need both.
The 500 error when requesting /page/
is caused by a rewrite-loop. The first rule rewrites the request to /page/.php
. The last rule then rewrites the request a 2nd time to /page/.php.php
and then again to /page/.php.php.php
etc. etc. Because REQUEST_FILENAME
is /page
in all cases and so %{REQUEST_FILENAME}.php
(in the condition) is not necessarily the same as %{REQUEST_URI}.php
(the URL being rewritten to).
Try the following instead:
Options -MultiViews
RewriteEngine On
# Remove php file extensions
RewriteCond %{THE_REQUEST} \s/([^.] )\.php [NC]
RewriteRule ^ /%1 [R=301,L]
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^([^.] )$ $1.php [L]
The redirect that removes the .php
extension should probably be a 301 (permanent) redirect, once you have confirmed that this works as intended.
The NC
flags on the RewriteRule
directives were superfluous.
There's no need to backslash-escape literal dots when used inside a regex character class. The dots carry no special meaning here. So, [^.]
is the same as [^\.]
. (Although you escaped one and not the other.)
This now checks for the same file %{DOCUMENT_ROOT}/$1.php
that is being rewritten to in the RewriteRule
substitution string, ie. $1.php
.
NB: I've explicitly disabled MultiViews to ensure that these directives are not overridden by mod_negotiation.
This will now result in a 404 should /page/
(with a trailing slash) be requested. If this should return the same as /page
then this should be implemented as an additional redirect, to remove the trailing slash.