The other day I was trying to set up a 301 Moved Permanently redirect that took one dynamic url and redirected to another dynamic url.
Searching around I found plenty of tips on how to redirect from older “ugly” style dynamic urls like “test.php?id=999” to new “clean” dynamic urls like “test/999”, but that wasn’t exactly what I needed. I needed to go from something like “page.php?id=999” to something like"page.php?id=111". Basically just a parameter substitution.
There are two ways to do 301s in an .htaccess file. One is to do a standard “redirect 301”, and the other is to use the Apache mod_rewrite module. For reference, this is what a standard “redirect 301” looks like:
redirect 301 /testpage.htm http://www.example.com/testpage2.php
This won’t work with a dynamic URL like “/testpage.htm?id=blah” though. To handle query strings properly you need to use mod_rewrite. Here is the code that ended up working:
# redirect testpage.php?id=string1 to testpage.php?id=string2
RewriteCond %{QUERY_STRING} ^id=string1$ [NC]
RewriteRule testpage http://www.example.com/testpage.php\?id=string2 [L,R=301]
The trick is that the second part of the RewriteRule – the URL to redirect to – is evaluated as a Regular Expression but has a “?” in it. This is a RegEx operator, and will break the command unless it is escaped with a “\”.
Look close at our destination URL "http://www.example.com/testpage.php\?id=string2". The URL we actually want to redirect to is "http://www.example.com/testpage.php?id=string2". Forgetting this one tiny little escape character will blow the whole thing up. :)
The dirty details:
There are plenty of good resources on mod_rewrite conditionals if you want to learn more, but it basically works like this: Apache looks at the RewriteRule, which is a pair of two Regular Expressions (RegEx): the URL we want to change, and what we want to change it to. If mod_rewrite matches the first RegEx expression then it looks at the RewriteCond to see if it should apply the RewriteRule. In this case we are just looking at the QUERY_STRING (everything after the “?”), and doing a case-insensitive [NC] match for “id=string1”. If the RewriteCond is true, then the RewriteRule goes in to effect and “testpage” is redirected to “http://www.example.com/testpage.php\?id=string2”. Just don’t forget to escape that pesky “?” in the query string!
301 Redirects are an important part of SEO and maintaining search engine rankings, so it’s nice to have another trick up your sleeve like this.
Here are some very helpful additional resources to improve your htaccess mod_rewrite-fu: