views:

232

answers:

4

I'm trying to use mod_rewrite to redirect URLs from a URL from an old host to a new one that uses a different URL format. The new host zero-pads the ID to six digits as follows:

Old URL:

http://www.example.com/script.cgi?page_id=123

Needs to redirect to:

http://archive.example.com/000123/

This is what I have so far:

RewriteCond %{QUERY_STRING} ^page_id=([0-9]+)$
RewriteRule ^script\.cgi http://archive.example.com/%1/? [R=301,L]

This is redirects to:

http://archive.example.com/123/

Is there any way to achieve the zero-padding with mod_rewrite or will I just have to write a handler script to redirect to the proper URL?

+2  A: 

Not an elegant solution, but you can set up six different rules:

RewriteCond %{QUERY_STRING} ^page_id=([0-9]{1})$
RewriteRule ^script\.cgi http://archive.example.com/00000%1/? [R=301,L]

RewriteCond %{QUERY_STRING} ^page_id=([0-9]{2})$
RewriteRule ^script\.cgi http://archive.example.com/0000%1/? [R=301,L]

RewriteCond %{QUERY_STRING} ^page_id=([0-9]{3})$
RewriteRule ^script\.cgi http://archive.example.com/000%1/? [R=301,L]

RewriteCond %{QUERY_STRING} ^page_id=([0-9]{4})$
RewriteRule ^script\.cgi http://archive.example.com/00%1/? [R=301,L]

RewriteCond %{QUERY_STRING} ^page_id=([0-9]{5})$
RewriteRule ^script\.cgi http://archive.example.com/0%1/? [R=301,L]

RewriteCond %{QUERY_STRING} ^page_id=([0-9]+)$
RewriteRule ^script\.cgi http://archive.example.com/%1/? [R=301,L]
Zed
Beat me to it! I think this'll probably be the only way. At least it's only six digits.
Dave Forgac
A: 

Ok, I realized I could achieve the results I wanted with the following:

RewriteCond %{QUERY_STRING} ^page_id=([0-9]{1})$
RewriteRule ^script\.cgi http://archive.example.com/00000%1/? [R=301,L]

RewriteCond %{QUERY_STRING} ^page_id=([0-9]{2})$
RewriteRule ^script\.cgi http://archive.example.com/0000%1/? [R=301,L]

RewriteCond %{QUERY_STRING} ^page_id=([0-9]{3})$
RewriteRule ^script\.cgi http://archive.example.com/0000%1/? [R=301,L]

RewriteCond %{QUERY_STRING} ^page_id=([0-9]{4})$
RewriteRule ^script\.cgi http://archive.example.com/00%1/? [R=301,L]

RewriteCond %{QUERY_STRING} ^page_id=([0-9]{5})$
RewriteRule ^script\.cgi http://archive.example.com/0%1/? [R=301,L]

RewriteCond %{QUERY_STRING} ^page_id=([0-9]{6})$
RewriteRule ^script\.cgi http://archive.example.com/%1/? [R=301,L]

Is there any other way to do this without the multiple rules though?

Dave Forgac
So StackOverflow has installed the new telepathy plugin :)
Zed
+1  A: 

The other option is to use a RewriteMap and have a script generate the URL to redirect to.

RewriteMap zeropad prg:/usr/local/zeropad.pl

RewriteCond %{QUERY_STRING} ^page_id=([0-9]+)$
RewriteRule ^script\.cgi ${zeropad:%1} [R=301,L]

And /usr/local/zeropad.pl is an executable script containing something like

#!/usr/bin/perl
$| = 1; #We don't want buffering
while (<STDIN>) {
    printf("http://archive.example.com/%06d/?\n",$_);
}

You can use whatever executable you like instead of a Perl one. The idea is to have it print out (with a trailing newline) the URL to redirect to. It has to work in a loop reading STDIN, as Apache will launch the script once and be calling the same instance repeatedly. It cannot buffer its output, because Apache will wait for its output (until a newline) before completing the rewrite.

Vinko Vrsalovic
+1  A: 

Here are two more elegant solutions:

  1. Using N flag to add one zero at a time until we have six digits:

    RewriteCond %{QUERY_STRING} ^(([^&]*&)*)page_id=([0-9]{1,5})(&.*)?$
    RewriteRule ^script\.cgi$ $0?page_id=0%3 [N]
    RewriteCond %{QUERY_STRING} ^([^&]*&)*page_id=([0-9]{6})(&.*)?$
    RewriteRule ^script\.cgi$ http://archive.example.com/%2/? [R=301,L]
    
  2. Using an additional RewriteCond to prepend five zeros and then get just the last six digits:

    RewriteCond %{QUERY_STRING} ^(([^&]*&)*)page_id=([0-9]+)(&.*)?$
    RewriteCond 00000%3 [0-9]{6}$
    RewriteRule ^script\.cgi$ http://archive.example.com/%0/? [R=301,L]
    

The complex pattern applied on QUERY_STRING is just to consider additional URL parameters. And I prefer the second solution as it is just one rule and more comprehensive.

Gumbo