I've been trying to figure this out for two hours, and I give up. I want to externally redirect about.php to about/, and also have about/ internally redirect to about.php

RewriteRule ^about/$ /test/about.php [L]    
RewriteRule ^about\.php$ /test/about/ [R,L]

Both of these rules work fine by themselves, but when they're combined they cause an endless loop (since each rule undoes the other one).

How can I combine them without causing an endless loop?

EDIT: In the "related" tab it shows a question that's exactly the same as this that I just couldn't seem to find myself through Google, and the solution works perfectly:

Using a .htaccess to RewriteRule and Redirect 301 at the same time?


RewriteRule ^about/$ /test/about.php [L,E=CLEAN_CONTACT_URL:1]
RewriteRule ^about\.php$ /test/about/ [R=301,L]

works exactly the way that I wanted, I just didn't know how to use RewriteCond to do something like this. Now I'm glad I posted my question!

  • Yes you would get a loop. When you say internally, do you mean internal IP addresses?
    – closetnoc
    Nov 26, 2014 at 19:54
  • I guess it would be good to know the range too. Can you provide the IP address range you are intending if it applies?
    – closetnoc
    Nov 26, 2014 at 19:56
  • I'm not sure if that's the right term for it - by "internally" I meant redirecting without changing the URL in the address bar (like, about/ shows the content of about.php) and this is just in general, I want mydomain.com/about.php to change to mydomain.com/about/ in the address bar, but still have mydomain.com/about/ show the content of about.php
    – onyxmoron
    Nov 26, 2014 at 19:56
  • Do you mean this for different sets of user?
    – closetnoc
    Nov 26, 2014 at 19:57
  • You cannot do both without distinguishing a case for when this should happen. Often this is for internal company IP addresses. But it could be on a directory by directory basis. Do you have a directory list where you want exceptions?
    – closetnoc
    Nov 26, 2014 at 20:01

1 Answer 1

RewriteRule ^about/$ /test/about.php [L]    
RewriteRule ^about\.php$ /test/about/ [R,L]

This is probably just your example, but this shouldn't actually result in a rewrite loop because of the additional /test subdirectory in the substitution. (/test/about.php won't match the pattern ^about\.php$)

But anyway, assuming you want to (internally) rewrite /about/ to /about.php and (externally) redirect /about.php back to /about/ (user friendly URL), then your solution can be optimised. There is no need to set an environment variable. (Note also, that you only need to do the external redirection if you are changing an existing URL structure. If this is a new site and the "unfriendly" URLs have not been indexed or exposed, then the external redirection is not necessary.)

Generally, external redirections should come before any internal rewrites. The rewrite loop can be avoided by checking against %{THE_REQUEST}, which contains the initial HTTP request. (so, no need for the environment variable to remember state.) So this can be rewritten as:

RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /about\.php
RewriteRule ^about\.php$ /about/ [R=301,L]

RewriteRule ^about/$ /about.php [L]

As mentioned, %{THE_REQUEST} contains the initial HTTP request (which does not change), which is of the form: GET /about.php HTTP/1.1

It's also good practise to separate rule sets with a blank line once you start using RewriteCond directives to make it clear (more readable) that the RewriteCond directive only applies to the single RewriteRule directive that follows.

Checking for about.php in the RewriteRule (as well as RewriteCond) might seem unnecessary at first, since the RewriteCond directive is what actually prevents the rewrite loop, but this is actually required for efficiency. Since the RewriteRule is tested first, this ensures that only relevant requests are processed.

Not the answer you're looking for? Browse other questions tagged or ask your own question.