Search code examples
php.htaccesshttp-redirecthttp-status-code-404

htaccess - redirect to error pages issue (with slash or without slash)


There is an issue with redirection to error pages: example.com/test - will redirect to 404 error page

but example.com/test/ - will go to the white "File not found." page

to mention:

  • it was working properly until some time ago (maybe update of PHP version ??)
  • same behavior with www/http/https version of the links
  • standard structure of the links is www.example.com/test/

.htaccess file code

<Files .htaccess>
order allow,deny
deny from all
</Files>

RewriteEngine On
RewriteRule ^([^/]+)/$ $1.php
RewriteRule ^([^/]+)/([^/]+)/$ /$1/$2.php
RewriteRule sample/(.*)/(.*)/$ /sample.php?$1=$2

ErrorDocument 400 /400.php
ErrorDocument 401 /401.php
ErrorDocument 403 /403.php
ErrorDocument 404 /404.php
ErrorDocument 410 /410.php

Solution

  • The difference with your URLs that end in a trailing slash is that they are unconditionally rewritten to the corresponding .php file. The URLs that do not end in a trailing slash are not rewritten - nothing happens.

    You are seeing the same basic "File not found" response when you directly request a non-existent .php file, regardless of whether the request is rewritten (by your rules) or not.

    The "problem" might be due to the way PHP is implemented on your server. For instance, if all *.php requests are proxied to an alternative backend process then this is going to bypass your .htaccess file on the application server and the "basic" 404 response you are seeing is possibly coming from the proxy, not your application server.

    You may be able to resolve this by first checking that the .php exists before rewriting to it (so it doesn't trigger a 404). And if none of your URLs contain a .php extension, you could also force any direct request for .php files to 404 (on your server, before the request is proxied - if that is what's happening).

    RewriteEngine On
    RewriteRule ^([^/]+)/$ $1.php
    RewriteRule ^([^/]+)/([^/]+)/$ /$1/$2.php
    RewriteRule sample/(.*)/(.*)/$ /sample.php?$1=$2
    

    The first two rules can also be combined into one. You are missing L flags on all your rules. You need to ensure that MultiViews is disabled, otherwise the last rule will not work.

    Also, the regex in the last rule needs to be anchored and made more specific since it is matching too much, eg. /sample/foo/bar/baz/qux will be rewritten to /sample.php?foo/bar/baz=qux, which I assume is not the intention.

    Try the following instead:

    Options -MultiViews
    
    RewriteEngine On
    
    # Force any direct request for ".php" files to 404
    RewriteCond %{ENV:REDIRECT_STATUS} ^$
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule \.php$ - [R=404]
    
    # Rewrite to ".php" file - 1 or 2 path segments
    RewriteCond %{DOCUMENT_ROOT}/$1.php -f
    RewriteRule ^([^/]+(/[^/]+)?)/$ $1.php [L]
    
    # Rewrite "/sample/one/two/"
    RewriteRule ^sample/([^/]+)/([^/]+)/$ sample.php?$1=$2 [L]
    

    Reference:

    Another recent question that has a very similar issue and was resolved in the same way:
    Custom 404 error handler in htaccess not working for non-existent ".php" files