Apache mod_rewrite RewriteRule with query string
I was converting some mod_rewrite rules from the Lighttpd webserver to Apache today.
![]()
While Lighttpd and Apache both have request rewriting modules with pretty equivalent functionality, there are some significant differences nonetheless. Specifically, I was trying to rewrite a URL of the form:
/script?key=123abcxyz
to a file on the local disk:
/abc/123/123abcxyz
In Lighttpd, I had a single rewrite rule handling both the URL and its query string:
"^/script?key=(([0-9a-f]{3})([0-9a-f]{3}).*)" => "/$2/$3/$1"
The regular expression might be a little confusing at first, but its reasonably straight forward.
My first thought was that I could do pretty much exactly the same thing with an Apache RewriteRule, like so:
RewriteRule ^/script?key=(([0-9a-f]{3})([0-9a-f]{3}).*) /$2/$3/$1
Unfortunately this won’t work – the RewriteRule will only be passed the URL – that is, /script without the query string (?key=foo).
So how do you make the RewriteRule aware of the value of the query string to rewrite to the local on-disk file correctly? You must have a RewriteCond directive preceeding the RewriteRule. RewriteCond can run a grouping regular expression over the query string, and RewriteRule can pull those groups out of the previous RewriteCond with a special syntax:
RewriteCond %{QUERY_STRING} key=(([0-9a-f]{3})([0-9a-f]{3}).*)
RewriteRule ^/script /%2/%3/%1
So there you are – how to have an Apache RewriteRule operate on parts of the query string as well as on the URL. The solution ends up being a little more convoluted under Apache than under Lighttpd, but is still manageable.







Thank you, I was ripping my hair out about this. I’m creating a search engine with pretty URLs that are feed through a framework routed by index.php. parsing the get string two different ways was not a smart option because not only would look ugly but I’d have to parse the $_GET array in two different ways.
I’m at a new crossroadds now though because the search form allows for checkboxes which are passed as an array which in a query string looks something like >> option[]=1&option[]=3&option[]=7
So this is going to be a pain in the ass
Thanks though!
Ahh, perfect! I was just wondering why it wasn’t working!