mod_rewrite-fu

Over the past few years, I’ve become increasingly impressed by mod_rewrite. Today a bashed up against a problem which turned out to have a fairly elegant solution, thought it looked like a lost cause at first.

Over the past few years, I’ve become increasingly impressed by mod_rewrite. It allows one to do extraordinarily complex things with Apache. Today, I was trying to use it to implement a very large batch of redirections without resorting to hundreds of RedirectMatch directives. This is something that ought to be trivial but turns out to be slightly less than obvious.

First, I figured I’d use a text map to hold the redirection list. So I added the following to the VirtualHost configuration:

RewriteMap redirs txt:/path/to/redirs/file

Then I added the necessary stuff in .htaccess:

RewriteEngine On
RewriteBase /
RewriteRule ^(.*)$ ${redirs:$1|$1} [L]

That turned out not to work. I had the keys in the text map with leading / characters. I also realized I had the redirection URLs already URL encoded. So I discovered I needed to do the following instead:

RewriteEngine On
RewriteBase /
RewriteRule ^(.*)$ ${redirs:/$1|$1} [L,NE]

It also occurred to me that I should probably be somewhat polite and check if there is a redirection before doing it, so I updated the .htaccess as follows:

RewriteEngine On
RewriteBase /
RewriteCond ${redirs:%{REQUEST_URI}} !=""
RewriteRule ^(.*)$ ${redirs:/$1} [L,NE]

That turns out to be approximately what every other example of this particular gimmick looks like. And it mostly works. Except if the URL to be redirected contains spaces.

I spent the better part of an hour muddling around in documentation and failing at my google-fu before I twigged on something I had read several times in the mod_rewrite documentation but its utility had not sunk in. I thought, maybe I can apply a map to the lookup key in the redirs map. And mod_rewrite provides a handle little escape function. A little tinkering yielded the following in the VirtualHost configuration:

RewriteMap redirs txt:/path/to/redirs/file
RewriteMap encode int:escape

and in the .htaccess file:

RewriteEngine On
RewriteBase /
RewriteCond ${redirs:${encode:%{REQUEST_URI}}} !=""
RewriteRule ^(.*)$ ${redirs:/${encode:$1}} [L,NE]

Using the final result above, one need only ensure that spaces in the names to be redirected are encoded as %20 in the redirs file. So far, it is working perfectly and I only need to update the redirs file to change the list of redirections.

Leave a Reply

Your email address will not be published. Required fields are marked *