Using RewriteMap for query string voodoo

I had the need today to come up with an apache rewrite that would, in some cases, change the value of a query string parameter. So for example, for requests coming from anywhere but example.com with a URI beginning “/path” and with a query string parameter named “foo” with the value beginning “bar”, I needed to rewrite the value to be “baz”. I spent some time fooling around with backreferences in the RewriteRule, but I never came up with anything that worked. Eventually, I turned to RewriteMap, which lets you specify text files, hashes, or even external scripts whose output values will be inserted into the destination for the rewrite. So in my example, here’s the apache config:

RewriteMap partner_params prg:/path/to/script.pl
RewriteCond %{HTTP_REFERER} !(.*)example.com(.*)
RewriteCond %{REQUEST_URI} ^/path
RewriteCond %{QUERY_STRING} .*foo=bar.*
RewriteRule ^(.*)$ http://mysite.com$1?${partner_params:%{QUERY_STRING}} [R=301,L]

The RewriteMap line points to a script (source to appear below) that will be executed by the RewriteRule. The first condition specifies that the referring url does not contain “example.com”. The second condition specifies that the URI begins with “/path”. And the third condition specifies that the query string must have a key named “foo” with a value beginning like “bar”. The rule itself takes any matching request and diverts it to http://mysite.com with the same URI as the original request (so something beginning “/path”), then adds a question mark to denote a query string following. Then it passes the query string to the script that RewriteMap knows as “partner_params”. that script reads from STDIN and prints to STDOUT either a newline-terminated result or the four-character response “NULL”. If not NULL, the response is what gets substituted into the RewriteRule.

So now for the script:

#!/usr/bin/perl
$| = 1;
while (<STDIN>) {
if($_ =~/foo=bar/){
$_ =~ s/foo=bar/foo=baz/gi;
}
print $_;
}

Here we simply do a substitution, looking for foo=bar and replacing with foo=baz. And voila, we’ve got custom inline query string munging based on parameters available via pretty standard apache Rewrite data. My particular example probably describes a pretty rare need, but knowing how to have a rewrite call a script to do more complex parsing than is available via apache configuration directives could be handy in a number of ways.

One thought on “Using RewriteMap for query string voodoo

  1. Hello, Daryl.

    Thanks for the post. It gave me an idea to do something I needed that is very similar to what you posted. Here you are the end result, since it might also be useful to you:

    RewriteMap idsmap txt:/etc/apache2/ids.map
    RewriteCond %{REQUEST_URI} ^/profile\.php
    RewriteCond %{QUERY_STRING} ^id=([0-9]+)$
    RewriteRule ^.* /profile/${idsmap:%1}? [R=301,L]

    Where ids.map is a plain text file with two columns. First is old id, second is new id.

    This could be useful when migrating from a software to another one and not keeping the old ids.

    Thanks.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s