« Veotag picking up steam | Main | Zoom...splat! »

interesting mod_rewrite tricks for zencart

So I receive a request from one of my co-workers to do the following:

Please redirect https://xxx.yyy.org/index.php?main_page=product_info&products_id=21 https://xxx.yyy.org/index.php?main_page=product_info&cPath=8&products_id=21 and https://xxx.yyy.org/index.php?main_page=product_info&products_id=138 https://xxx.yyy.org/index.php?main_page=product_info&cPath=8&products_id=138 to

http://www.zzz.com/abcdefgh/nnnnn.htm


Now, the site that's being rewritten from is a big ol’ PHP application (Zencart) and it’s not really amenable to just going in and toying with—it has a nice administrative interface, but nothing obvious that lets you do a redirect from a random item in the inventory.

“Ah”, I say, “time for mod_rewrite, Apache's answer to everything.”

Well, it’s not that simple, you see.

You might think a simple RewriteRule would suffice, rewriting the whole URL at once:

RewriteRule /^index\.php\?main_page=product_info&products_id=21$ http://www.zzz.com/abcdefgh/nnnnn.htm [R]
But that won’t work, because RewriteRule only works on the URL. In this case, the URL is just https://xxx.yyy.org/index.php, and we don’t want to rewrite THAT, because, well, there are other things on the site they’d still like to sell. Remember—the trick is to match on the stuff after the question mark, and that isn't accessible to RewriteRule!

It is accessible, however, via the variable %{QUERY_STRING}. (This took me half an hour of looking and finding.) That is because the query part (that important stuff after the question mark) gets handled differently when the web server receives and parses the URL: the expectation is that whatever the URL indicates, it is something that consumes input to generate output (so it isn’t a static page, generally speaking).
In this case, RewriteCond is the thing that does the trick. I have to chain four of them together to get them all to work, but the following did the trick:

RewriteCond %{QUERY_STRING} ^main_page=product_info&products_id=21$ [OR]
RewriteCond %{QUERY_STRING} ^main_page=product_info&cPath=8&products_id=21$ [OR]
RewriteCond %{QUERY_STRING} ^main_page=product_info&products_id=138$ [OR]
RewriteCond %{QUERY_STRING} ^main_page=product_info&cPath=8&products_id=138$

RewriteRule ^/index\.php http://www.zzz.com/abcdefgh/nnnnn.htm [R=permanent]


The [OR]s at the end of the first three lines mean “combine this rule with the next one”, the RewriteRule then says “for the URIs beginning with index.php, that have already matched the conditions above me, rewrite the URL to be the new, foreign one, using an HTTP redirect with a ‘moved permanently’ condition (HTTP response code 301)”.

This appears to have done the trick, and now everyone is happier.

OK, so it isn’t heavy wizardry, but it might be useful elsewhere.

TrackBack

TrackBack URL for this entry:
http://www.jbaltz.com/mt/mt-tb.cgi/28

Comments

For me, your posting marked the end of hours of frustration in trying to figure out why the '?' was messing up my RewriteRule. It's all so clear now!

Thanks!

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)