I do think that's because it rewrites it like example.com/test/.php
Yes, that is what's happening. But it will do this repeatedly (causing a rewrite-loop) until the server "breaks" with a 500 Internal Server Error.
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php
The "problem" with this is that you aren't necessarily testing the existence of the same file in the RewriteCond
directive that you are rewriting to in the RewriteRule
directive.
So, this will cause an error (rewrite-loop / 500 Internal Server Error) when appending a slash because REQUEST_FILENAME
is /abs/path/to/test
(the resolved filesystem path) and /abs/path/to/test.php
exists, but it internally rewrites the request to test/.php
because $1
is test/
(captured from the URL-path). It will do this repeatedly until the server aborts with an error.
You need to make sure you are always testing the same thing in the condition as you are rewriting to later.
See my answer to the following question on ServerFault with a detailed explanation of this behaviour: https://serverfault.com/questions/989333/using-apache-rewrite-rules-in-htaccess-to-remove-html-causing-a-500-error
Additional points...
- You are missing the
L
flag, so processing continues on to the next rule.
- The first condition that checks the request does not map to a directory is not required, since you are already checking that
<whatever>.php
exists as a file.
- Minor point, but there is no need to backslash-escape a literal dot in the TestString (1st argument to the
RewriteCond
directive) - this is not a regex.
For example, use the following instead:
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule (.*) $1.php [L]
Now, %{DOCUMENT_ROOT}/$1.php
in the RewriteCond
directive refers to the same string/file as $1.php
in the substitution string.
So, when you request /test/
, it will now be testing /abs/path/to/test/.php
in the RewriteCond
directive, which doesn't exist, so nothing happens (results in a 404). /test
and test/
are, after all, different URLs.
Aside:
RewriteCond %{REQUEST_URI} ^(.*)//(.*)$
RewriteRule . %1/%2 [R=301,L]
This redirect is in the wrong place. It should be the first rule, not the last.