1

I have a couple of specific URLs that I want to display differently on my website, like this:

RewriteRule ^contact$ contact.php

To get ride of the ".php" extension.

And to be SEO friendly (to avoid having 2 different URLS pointing to the same page), I also want to do a 301 redirect between the old URL and the new one:

Redirect 301 /contact.php http://www.example.com/contact  

Each of the lines above works well separately. But if I add them both in my htaccess, I have a redirect loop, and nothing is displayed on my website. How can I fix that?

In the end, if I either type "/contact" or "/contact.php", I want to see the contact page with the url "/contact".

4 Answers 4

1

I had to ask this question myself. It is surprisingly tricky to do. Olaf Dietsche provided the solution of using an environment variable:

RewriteRule ^contact$ contact.php [L,E=CLEAN_CONTACT_URL:1]
RewriteCond %{ENV:REDIRECT_CLEAN_CONTACT_URL} !1
RewriteRule ^contact\.php$ /contact [R=301,L]

That way the redirect only gets executed when contact.php is the actual URL, not the rewritten URL.

I tested it with my own server to verify that it works:

$ curl -s --head http://example.com/contact.php
HTTP/1.1 301 Moved Permanently
Date: Sun, 27 Jul 2014 16:28:01 GMT
Server: Apache
Location: http://example.com/contact
Content-Type: text/html; charset=iso-8859-1

$ curl -s --head http://example.com/contact
HTTP/1.1 200 OK
Date: Sun, 27 Jul 2014 16:28:01 GMT
Server: Apache
Content-Type: text/html; charset=UTF-8

The reason that you set the CLEAN_CONTACT_URL environment variable but then read it as REDIRECT_CLEAN_CONTACT_URL is explained here.

2
  • Thanks, this looks like what I want. However, when I copy/past your code, I still get a redirect loop.
    – pimpampoum
    Jul 27, 2014 at 13:08
  • I updated the answer after debugging it. I had forgotten the REDIRECT_ prefix when testing the environment variable. Jul 27, 2014 at 16:33
1

Yes you would. You are telling Apache to take any reference to contact and rewrite the URI to contact.php then telling Apache to take any contact.php reference and change it to /contact which gets captured again by the first rule.

Here is what you are missing. For each rewrite or redirect, Apache makes the change then starts the whole matching process over again. So after your RewriteRule, Apache is converting the request to contact.php and after your Redirect, Apache is converting the request almost back to what it was originally.

If you are using the file name contact.php for SEO purposes, I would drop this concept. File names do help as much as the (apparent) directory name. As well, single keyword file names do not seem to matter much at all especially when it is such a common word. There are exceptions of course. Brand names with product names seem to matter. In this case, just do things the old fashioned way- a proper link and no fancy stuff.

Your redirect is correct. I would use it, however, I would not use specifically named PHP files such as contact.php. It just confuses things. Instead, I would stick with index.php which should be your DirectoryIndex. Unless you have several files within your /contact directory, this should work okay. If you do this, you can remove your RewriteRule and everything should work fine.

Clear as mud?

6
  • Thanks, but not sure to understand everything. Right now my website uses "/contact.php" and I find the "php" ugly, so I'd like to use "/contact" instead. My SEO concern is if I only do a RewriteRule, then I would have two different urls (/contact and /contact.php) pointing to the same page, which is not good. To avoid that I want to also do a 301 redirect, which creates the loop.
    – pimpampoum
    Jul 26, 2014 at 19:10
  • If you rename your contact.php to index.php which is likely the default page name as defined by the directive DirectoryIndex in your sites configuration file, and just use your redirect statement, it will likely work. You will have what you want. Otherwise, you will always have this loop using the two statements. Try it quickly. It won't harm anything to do a quick test.
    – closetnoc
    Jul 26, 2014 at 22:44
  • I already have an index.php: example.com/index.php and example.com/contact.php. And I now want to have example.com/contact, that why I need both a 301 redirect and a RewriteRule for my contact page. The question is how I can make that work without creating a loop.
    – pimpampoum
    Jul 27, 2014 at 8:03
  • You can try to move example.com/contact.php to example.com/contact/index.php, this way you would avoid having the rewrite rule. Jul 27, 2014 at 11:26
  • Sure, it would work, but this is a really ugly solution.
    – pimpampoum
    Jul 27, 2014 at 13:14
0

Use the [L] flag on your rewrite rule and place your redirect before it. (I'm going to use a rewrite here as well)

RewriteRule ^/contact\.php$ http://www.example.com/contact [R=301,L]
RewriteRule ^contact$ /contact.php [L]

When the first rule is encountered it matches the /contact.php request and is the last rule processed. The redirect to /contact does not match the first rule but it will match the second which is served up transparently from /contact.php

I haven't tested this but it should work.

2
  • Thanks, I just tried that. Using the "/contact" url works, however when I type "/contact.php", the page url stays "contact.php" instead of showing "/contact".
    – pimpampoum
    Jul 27, 2014 at 8:01
  • The first RewriteRule pattern (^/contact\.php$) will never match in per-directory .htaccess files since the directory prefix is removed for the purpose of the match. However, changing this to ^contact\.php$ will then result in a rewrite loop. An additional condition is required in order to prevent the rewrite loop.
    – MrWhite
    Nov 27, 2014 at 1:48
0

You are mixing the mod_alias and mod_rewrite modules, which means that the end result is often unexpected.

You should only use mod_rewrite in your case, that is, repöace your

Redirect 301 /contact.php http://www.example.com/contact

with

RewriteRule contact.php http://www.example.com/contact [R=301,L]

And then, as Dave mentioned, you should use the [L] flag to stop RewriteRule processing.

2
  • I tried: RewriteRule contact.php example.com/contact [R=301,L] with RewriteRule ^contact$ /contact.php [L] => doesn't work. When I go "/contact.php", the url stays "contact.php" instead of becoming "/contact".
    – pimpampoum
    Jul 27, 2014 at 8:13
  • Whilst this is true (mod_alias and mod_rewrite directives should not be mixed), the fact that both modules are used here is not actually the cause of the rewrite loop in this instance.
    – MrWhite
    Nov 27, 2014 at 1:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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