Having issues with .htaccess
rewrite rules. Passing a URL to the browser from users email that includes a token for password reset.
Current .htaccess
rules:
Options +FollowSymLinks -MultiViews
RewriteEngine On
RewriteBase /
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\.DOMAIN\.com [NC]
RewriteRule ^(.*)$ https://DOMIAN.com/$1 [L,R=301]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php [L]
RewriteCond %{THE_REQUEST} ^(?:GET|POST)\ /.*\.php\ HTTP.*$ [NC]
RewriteRule ^(.*)\.php$ $1 [R=301,L]
when user trying to go to
example.com/activate/00803e6632236414ebcdc34c7e7690d764e567083fac6
produces these errors in debug
example.com/activate/00803e6632236414ebcdc34c7e7690d764e567083fac6.php.php.php.php.php.php.php.php.php.php
So I update .htaccess per your notes below like this:
Options +FollowSymLinks -MultiViews
RewriteEngine On
RewriteBase /
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\.EXAMPLE\.com [NC]
RewriteRule ^(.*)$ https://EXAMPLE.com/$1 [L,R=301]
RewriteCond %{THE_REQUEST} ^(?:GET|POST)\ /.*\.php\ HTTP.*$ [NC]
RewriteRule ^(.*)\.php$ $1 [R=301,L]
# Rewrite extensionless ".php" URLs
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule (.+) $1.php [L]
# Rewrite "/<file>/<code>" to "/<file>.php/<code>"
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^([^/]+)/([a-f0-9])$ $1.php/$2 [L]
And I get the following error:
AH00128: File does not exist: /var/www/html/htdocs/activate/00803e6632236414ebcdc34c7e7690d764e567083fac6
RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME}\.php -f RewriteRule ^(.*)$ $1.php [L]
The problem with this rule is that you are checking one filesystem path (ie. %{REQUEST_FILENAME}\.php
) and rewriting to another ($1.php
). These do not necessarily refer to the same thing. For a request to /activate/foo
, where activate
is not a filesystem directory then REQUEST_FILENAME
is of the form /var/www/html/htdocs/activate
(so the file check is successful since /var/www/html/htdocs/activate.php
exists), but it rewrites the request to activate/foo.php
(using the $1
backreference) - which does not exist. It will do this repeatedly, appending .php
each time (until it reaches an internal rewrite limit; default 10).
Aside#1: There is no need to check that the request does not map to a directory and does not map to a file before checking that the request+.php
does map to a file. That's 3 (expensive) filesystem checks when only one is required.
Aside#2: You also don't need to backslash escape the literal dot in the TestString (first argument), since this is an "ordinary" string, not a regex.
This rule needs to be corrected, so that you are testing the same file-path that you are ultimately rewriting to. For example:
# Rewrite extensionless ".php" URLs
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule (.+) $1.php [L]
You then need an additional rule to rewrite the request /activate/<code>
to /activate.php/<code>
(passing /<code>
to your script as path-info). This could be "hardcoded" if this is a one-off. For example:
# Rewrite "/activate/<code>" to "/activate.php/<code>"
RewriteRule ^(activate)/([a-f0-9]+)$ $1.php/$2 [L]
(I'm assuming <code>
is a hexadecimal sequence, which appears to be the case in your example.)
Or make it more generic, if you have similar requests. eg. /<file>/<code>
to /<file>.php/<code>
. For example:
# Rewrite "/<file>/<code>" to "/<file>.php/<code>"
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^([^/]+)/([a-f0-9]+)$ $1.php/$2 [L]
Aside:
RewriteCond %{THE_REQUEST} ^(?:GET|POST)\ /.*\.php\ HTTP.*$ [NC] RewriteRule ^(.*)\.php$ $1 [R=301,L]
This rule (external redirect) should be before the above rewrites.