I have a problem with my .htacces code, because it produces an 500 internal server error instead of a 404 error, like it should.
The 500 internal error is only caused if I try to open a page in a directory which is actually a file. For example, in the root of my website, there is the file biography.php
. https://example.com/biography.php
redirects to https://example.com/biography/
.
But when I try to open the non-existing page https://example.com/biography/test/
, it shows an 500 internal server error instead of the expected 404 error.
This is my .htacces code. The last 6 lines seem to cause the issue, because without them, the expected 404 error is displayed instead of the 500 internal server error. But without them, https://example.com/biography.php
doesn't redirect to https://example.com/biography/
…
Maybe there is a redirect loop or something like that? I just copied the code from the internet, so I'm not able to troubleshoot it myself.
Options -Indexes
AddDefaultCharset UTF-8
ServerSignature Off
DirectoryIndex index.php
RewriteEngine On
RewriteBase /
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} !^example.com$ [NC]
RewriteRule ^(.*)$ https://example.com/$1 [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule !(^$|\.[a-zA-Z0-9]{1,5}|/)$ %{REQUEST_URI}/ [R=301,L]
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^((/?[^/] ){1,2})/$ $1.php [L]
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s([^.] )\.php [NC]
RewriteRule ^ %1 [R=301]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*?)/?$ $1.php [NC,L]
Thank you for your help! I hope you can understand my issue! I appreciate it! :)
CodePudding user response:
RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME}.php -f RewriteRule ^(.*?)/?$ $1.php [NC,L]
The rewrite-loop (which causes the 500 error) is caused by the last rule (3 directives) because the condition that checks %{REQUEST_FILENAME}.php -f
is not necessarily checking the same file that you are rewriting to in the RewriteRule
substitution string (ie. $1.php
).
When you request /biography/test/
you end up checking whether /biography.php
exists (which it does), but you end up rewriting the request to /biography/test.php
(which does not exist) - which causes a rewrite loop.
See my answer to the following question on ServerFault for a more detailed explanation: https://serverfault.com/questions/989333/using-apache-rewrite-rules-in-htaccess-to-remove-html-causing-a-500-error
The last rule should instead be written like this:
# Rewrite to append the ".php" extension as required.
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^(.*?)/?$ $1.php [L]
This now checks that the target file exists before appending the .php
extension to the same URL-path.
There's no need for two conditions. And the NC
flag is not required here.
RewriteCond %{ENV:REDIRECT_STATUS} ^$ RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s([^.] )\.php [NC] RewriteRule ^ %1 [R=301]
However, your redirect to remove the .php
extension is not strictly correct either. This will also erroneously remove the .php
"extension" should it appear in the query string part of the URL. And you are missing the L
flag. You also don't need both conditions.
Use something like the following instead:
# Remove ".php" extension from requested URL-path
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(. )\.php$ /$1 [R=301,L]
Summary
# Remove ".php" extension from requested URL-path
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(. )\.php$ /$1 [R=301,L]
# Rewrite to append the ".php" extension as required.
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^(.*?)/?$ $1.php [L]