I'm setting up a 404 page on a project on my localhost (MAMP) and in my .htaccess
file I’ve included the following code:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.+) $1.php [NC,L]
</IfModule>
ErrorDocument 404 http://localhost:8888/project/public/404.php
The 404.php page sits at the same level as .htaccess
file in a public folder below the project root:
project
— publicFolder
— privateFolder
The Issue
When I include the code within the <IfModule mod_rewrite.c>
it throws an error when I type in a 404 page URL (i.e. a page that doesn't exist). When I remove this <IfModule mod_rewrite.c>
code block the problem goes away. The error message is:
Internal Server Error
The server encountered an internal error or misconfiguration and was unable to complete your request.
Please contact the server administrator at you@example.com to inform them of the time this error occurred, and the actions you performed just before this error.
More information about this error may be available in the server error log.
When I check the apache error log, as recommended in the above message I get the following:
[core:error] [pid 2575] [client ::1:51038] AH00124: Request exceeded the limit of 10 internal redirects due to probable configuration error. Use 'LimitInternalRecursion' to increase the limit if necessary. Use 'LogLevel debug' to get a backtrace.
I suspect the issue may be to do with the line that removes the .php
file extension on all of the pages, i.e.RewriteRule (.+) $1.php [NC,L]
My Question
How do I get the clean URL code inside the <IfModule mod_rewrite.c>
block to stop throwing an internal server error when a user goes to what should be a 404 page?
Any help great appreciated.
Your issue simply is that you indeed implement an endless rewriting loop.
Have a try using that variant with an additional condition:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.+)$ $1.php [L]
You need to understand that the L
flag you are using indeed terminates the rewriting, but only for the current cycle . Whenever a rewriting cycle alters (rewrites) the processed request a new cycle is started. Until the request is stable, so is not rewritten again. Since the rewritten target again matches your conditions and the rule's matching pattern you again rewrite the request in your implementation. Which ultimately results in a request to something like /foo.php.php.php.php.php
, appending one ".php" for every rewriting cycle.
An alternative would be to use the younger [END]
¸ flag here instead of the older [L]
flag. The END flag completely terminates the rewriting process, ignoring any other rules. So you need to be sure that rule really is the last that should get applied. Using that flag you won't need the additional condition, since the complete termination obviously prevents an endless rewriting loop.
In general I would advise to not use distributed configuration files for this (".htaccess"). But to implement such rules in the actual http server's central host configuration. And use absolute paths there.
That typically prevents a lot of confusing and side effects.
Certainly there may be other issues here that do not get immediately clear from the question you asked. But above is an obvious issue.
Always test using a fresh anonymous browser window, always make deep reloads in the browser to prevent client side caching effects while testing.