Apache redirects with RewriteMap and RewriteCond 2
At work we’re migrating several thousand research articles from Zope to another CMS. The CMS folks are taking care of moving the content, but when we’re done we’re going to institute a boatload of R=301 redirects from the old URLs to the new URLs.
RewriteMap is the accepted way with mod_rewrite of handling a lot of one-to-one mappings that don’t follow any particular pattern. What I figured out today was that I can use a rewrite map in a RewriteCond statement so I only do the redirect when there’s a match in the rewrite map lookup.
Here are some snippets from my httpd.conf to illustrate:
For testing, we’ll want logging:
RewriteLog /var/log/httpd/rewrite.log
RewriteLogLevel 2
Define the map we’re using. The content of the map is ‘old_uri new_uri’ with a space separating the two. Use .txt for testing, and the below we’ll convert to a DBM.
RewriteMap research_map txt:/etc/httpd/conf/research_map.txt
Here, I got a hint from http://www.tunnell.org/blog_posts_view.php?blog_postid=3. Remember that the syntax for a RewriteCond is:
RewriteCond TestString ConditionPattern
TestString will be a map lookup of $1, where $1 is the match string of the
following RewriteRule, expressed: ${research_map:$1}
For ConditionPattern,
we will test if the TestString is lexically greater than
””, the empty string, which is what the map lookup returns when there’s no
match. Expressed: >""
RewriteCond ${research_map:$1} >"" # IE, if map result is greater than ""
So if the URL starts with /research, then
use the research_map value for the key $1 to redirect to new address
RewriteRule ^(/research/.*$) ${research_map:$1} [R=301,L]
What we end up with is a few lines of configuration that quickly let me put in place 3342 new redirects. Here’s the whole stanza:
RewriteMap research_map txt:/etc/httpd/conf/research_map.txt
RewriteCond ${research_map:$1} >"" # IE, if map result is greater than ""
RewriteRule ^(/research/.*$) ${research_map:$1} [R=301,L]
# Same thing, but lookup with a trailing slash if there isn't one
RewriteCond ${research_map:$1/} >""
RewriteRule ^(/research/.*[^/]$) ${research_map:$1/} [R=301,L]
Lastly, converting the textfile to a dbm speeds up the lookup by at least an order of magnitude.