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.