Blog Mod_rewrite: Attempting to bend RewriteMap, RewriteCond, and RewriteRule to my will...
Jeremy Tunnell at
RewriteEngine On RewriteMap redirects txt:/home/.../.../rewriterules.map RewriteRule ^(.*)$ ${redirects:$1|$1} [R,L,NC]
How does it work? (See here for details.)
The first line turns on mod_rewrite. The next line sets the location of the map file (the two column list of source/destinations). The third line sets a RewriteRule that says "take everything in the request uri" (.*), and search the RewriteMap redirects for a match. If we have a match, the user's browser gets a redirect and is forwarded to the new uri. If we don't get a match, i've specified with the $1 backreference that the user is to be transparently passed on to the uri he requested.
The problem is that when Apache doesn't find a match in the rewritemap, we get a new request for the same uri...which runs through the process, ending in a request for the same uri...and so on. Because I want to redirect the user instead of handling the change transparently, I keep running into an infinite loop problem.
So we use a RewriteCond.
RewriteEngine On RewriteMap redirects txt:/home/.../.../rewriterules.map RewriteCond ${redirects:$1} >"" [NC] RewriteRule ^(.*)$ ${redirects:$1|$1} [R,L,NC]
We basically say "Look up the uri from the following RewriteRule ($1 means look ahead to the next RewriteRule. We could look behind to the last RewriteCond by using %1.) and if it is lexically greater than the empty string then do the Rewrite. Otherwise, skip it.
Version 2
I never got the [NC] switches to work so I just converted everything to lowercase before I do the comparisons (You must make sure your map is all lowercase).
RewriteEngine On RewriteMap redirects txt:/home/.../.../rewriterules.map RewriteMap lowercase int:tolower RewriteCond ${lowercase:%{REQUEST_URI}|NONE} ^(.+)$ RewriteCond ${redirects:%1} >"" RewriteRule ^(.*)$ ${redirects:%1} [R,L]
Links
- Check out here for more good mod_rewrite explanations
- Mod Rewrite Tutorial
- No more endless loops
- Lots of rewrite examples
Archived Comments
Thanks for this tip, was having a problem with an infinite loop on a rewrite map - this helped.
Posted by James on September 14th, 2007
Found this via Google. Thanks for the tip!
Posted by foo on February 10th, 2008
Thank you for sharing this missing part of the Apache documentation. Worked great for me.
Posted by Fredrik Nygren on March 17th, 2008
Thank you very much
Posted by sohbet on December 13th, 2008
thx for this great article, i searched for hours!
Posted by Felix on January 23rd, 2009
Thanks for this article, solved a little typo in my script and only noticed it after looking at this article.
Posted by Web Design Sydney Melbourne Brisbane on March 17th, 2009
Oh, can I kiss your toes?
Seriously, I didn't grok the bit about using rewritemaps in a RewriteCond before. Thanks!
Peter
Posted by Peter Burkholder on July 14th, 2009
Thanks for this!
Just one thing - the syntax for the "greater than the empty string" is wrong - >"" fails to match certain things (for example, if the result of your rewritemap is the number 9). The correct syntax is "> " (note the order of the quotes), which matches any ascii value lexically greater than space (char(32)).
Posted by Andy Theyers on July 20th, 2009
Here's a little solution I came up with for making my URLs prettier and getting search engines to repoint to the new URL. I have a products db that has uppercase word keys for each product that points to the numeric product id. Then I have a reverse db that contains the same in the opposite order. So far this seems to work..
RewriteMap uppercase int:toupper
RewriteMap products dbm:conf/products.dbm
RewriteMap rproducts dbm:conf/rproducts.dbm
# 301 redirect ugly product URL to user-friendly word based URL.
RewriteCond %{QUERY_STRING} ^partNumber=(d*)$
RewriteCond ${rproducts:%1} >""
RewriteRule ^/product.html$ /product/${rproducts:%1|%1}? [R=301,L]
# Convert user-friendly word based product URL internally to ugly URL with part number.
RewriteRule ^/product/(D.*)$ /product.html?partNumber=${products:${uppercase:$1}} [E=PAGE:product.html]
Posted by MikeFM on July 28th, 2009
Hi, I am working on the rewritemap and rewriterule for my website. actually requirement is like i have one website whose address is http://www.myside1.com now since i am going to retire this website so i need to redirect most of the pages to new website. i want to use map file for this. i have created this mapping file where i want to keep maping like /folder1/page1.html http://newwebsite.com/content/view/hello.html in this way i want to use the redirection. i dont want to hardcode the each redirect rule. I can have /folder2/page1.html also. Could you please help me to have the correct rule.
Posted by yashjimmy on July 09th, 2010