I have the following in my htaccess:
RewriteEngine On RewriteRule ^reset-password/?$ /pwreset.php [NC,L]
It works perfectly, the question is whether it would also be possible to automatically redirect it to the new path when the PHP file is accessed directly?
For example: example.com/pwreset.php
>> example.com/reset-password
There are several pages, so I needed something practical.
UPDATE:
RewriteRule .* - [E=URL:https://user.example.com] RewriteRule ^pwreset.php$ %{ENV:URL}/reset-password [R=301,L] RewriteRule ^reset-password$ pwreset.php [END] RewriteRule ^clientarea.php$ %{ENV:URL}/home [R=301,L] RewriteRule ^home$ clientarea.php [END] RewriteRule ^logout.php$ %{ENV:URL}/logout [R=301,L] RewriteRule ^logout$ logout.php [END]
The difficulty is with links like this: user.example.com/clientarea.php?action=services
When accessed it redirects to: user.example.com/home?action=services
I need that in the case of these links the redirection occurs to: user.example.com/services
Can you help me with this new rule? And also how to simplify it all.
Advertisement
Answer
To externally redirect direct requests for /pwreset.php
to /reset-password
you can do something like the following before your existing internal rewrite:
RewriteCond %{ENV:REDIRECT_STATUS} ^$ RewriteRule ^pwreset.php$ /reset-password [R=301,L]
The condition that checks against the REDIRECT_STATUS
env var is necessary in order to avoid a redirect loop, since we only want to redirect direct requests the user has made and not rewritten requests by the other directive. REDIRECT_STATUS
is empty on the initial request and set to “200” (as in 200 OK) after the first successful rewrite.
Test first with a 302 (temporary) redirect to avoid potential caching issues.
UPDATE#1: is there any way to put that in the same rule? Because there are many pages, then I would have to practically duplicate each line.
No, if you are using a single .htaccess
file and you want to do everything via .htaccess
then you would need to repeat the two directives (RewriteCond
and RewriteRule
) for each external redirect. Without the RewriteCond
directive (condition), the rewritten request would also be redirected – creating an endless loop.
However, you could use a 2nd .htaccess
file in a subdirectory to handle the redirects. This would avoid the additional condition for every rule.
For example, instead of redirecting pwreset.php
as explained above. You could internally rewrite all requests for .php
files (assuming you are not accessing any .php
files directly) to a subdirectory that contains another .htaccess
with the necessary redirects.
Change the above redirect to a rewrite of the form:
# Rewrite all direct requests for `.php` files to a subdirectory RewriteCond %{ENV:REDIRECT_STATUS} ^$ RewriteRule (.+.php)$ /redirect-handler/$1 [L]
Where
/redirect-handler
is a physical subdirectory.Create
/redirect-handler/.htaccess
with the necessary redirects:# Redirect direct requests for .php files to the canonical URL. # If we are here then we know that the .php file has been called directly # so do not need an additional condition before each rule. RewriteEngine On RewriteRule ^pwreset.php$ /reset-password [R=301,L] RewriteRule ^another.php$ /canonical-url [R=301,L]
Another alternative is to rewrite the request to a PHP script, instead of a subdirectory containing another .htaccess
file and perform the redirect in PHP instead.
For example, your initial “redirect” becomes:
# Rewrite all direct requests for `.php` files to PHP script RewriteCond %{ENV:REDIRECT_STATUS} ^$ RewriteCond %{REQUEST_URI} !^/redirect-handler.php$ RewriteRule (.+.php)$ /redirect-handler.php?url=$1 [L]
Then, in /redirect-handler.php
you would check the $_GET['url']
var for the PHP file being requested. (Or just check the $_SERVER['REQUEST_URI']
superglobal.) Lookup the desired canonical URL and either 301 “redirect” if the request maps to a valid URL or return a 404.
You could take this a step further and manage everything in PHP – in a single script. This has the obvious advantage that you have just a single list (PHP assoc array or DB table) that contains the PHP file/canonical-url mapping. Apart from the initial rewrites in .htaccess
, you would not need to update .htaccess
when URLs are added/removed/updated. Although you might need modify your existing pages, depending on how you are including files etc. (?)
UPDATE#2: Using a single .htaccess
file… If you are on Apache 2.4 (as opposed to 2.2) then you can just use the END
flag on the internal rewrite (instead of the L
flag) and this will avoid having to specify the additional condition (RewriteCond
directive) on the “redirect”.
For example:
RewriteEngine On # Canonical redirects... RewriteRule ^pwreset.php$ /reset-password [R=301,L] : # Internal rewrites... RewriteRule ^reset-password$ pwreset.php [END] :
Unlike the L
flag, the END
flag stops all processing, thus preventing the rewrite engine starting over.
Note that I made a few small changes to your initial rewrite…
- Removed the
NC
flag – do you really need a case-insensitive match? This would otherwise potentially create a duplicate content issue, but you should be consistently linking to a single canonical URL. - Removed the optional trailing slash on the
RewriteRule
pattern. (Same reason as above.) - Removed the slash prefix on the
RewriteRule
substitution string – it’s not required and simplifies the rewrite (it now rewrites to a filesystem path – which is what it is – rather than a URL-path).
This is much simpler than the methods outlined above! (Although those methods do still have their purpose.)