Simple mod_rewrite RewriteRule for messy legacy url's - apache

Launching a new website for a new client. Their old site has about 50 products and unfortunately, the old product names do not match up to the new URL pattern
Old URL Examples:
example.com/products.aspx?category=Foo&product=SuperLongNoBreakProductNameIDDescription
example.com/products.aspx?category=Foo&product=ProductNameDescription&var1=1293.123
example.com/products.aspx?category=Bar&product=ProductCategoryProdNameRandomNumbers
(The old URL's are sometimes hitting 150+ characters.)
New URL's:
example.com/products/category/actual-product-name
There's no set, recognizable pattern to go from the old product name to the new one. There is for the category.
I've tried simple mod_alias Redirects, but understand that I need a RewriteRule instead. But I'm having problems. All I need is a 1-to-1 redirect for each of these 50 URL's. I thought I could do something like:
RewriteRule ^/products.aspx?category=Foo&product=ProductName
/products/category/new-product-name/ [R=301,NC]
But that isn't working. I know this should be simple, but I am stuck. Any ideas?

Use the pattern below for the rest of your redirect urls. Note that you escape special characters e.g. ? , . and space by adding a \ in front of them
RewriteEngine on
RewriteBase /
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /products\.aspx\?category=Foo&product=SuperLongNoBreakProductNameIDDescription [NC]
RewriteRule ^ /products/category/new-product-name/ [R=301,NC]

Have a look at the RewriteMap directive of mod_rewrite.
You can specify in a text file something like:
products.aspx?category=Foo&product=SuperLongNoBreakProductNameIDDescription /products/category/new-product-name
And in your httpd.conf
RewriteMap productmap /path/to/map/file.txt
RewriteRule ^(.*) ${productmap:$1} [R=301,NC]
Tip: If it's a permanent redirect you want, make sure you set an appropriate Cache-Control and Expires header to instruct browsers to cache the 301.

You can try something like this:
RewriteEngine On
RewriteCond %{QUERY_STRING} ^category=Foo&product=ProductName$
RewriteRule ^products\.aspx$ /products/category/new-product-name/? [R=301,L]
Notes:
In per-dir (.htaccess) context, the per-dir prefix is stripped, so you can't start the RewriteRule pattern with ^/.
You have to use RewriteCond to match against the query string.
As stated in another answer, a RewriteMap solution might be suited to this situation, if you have access to httpd.conf / the vhost definition for this site. I'm not sure how that works with query strings though.
For something like this, it might be a better solution to rewrite all of these URLs to a server side script, and use the script to do the HTTP redirect for each URL.

Related

.htaccess redirect according to PHP parameters

I'm trying to build some redirections with my .htaccess file to deal with some old forum url. I want the redirections to be made according to the PHP parameters (the topic ID).
For instance, something like
RewriteEngine On
RedirectPermanent /forum/viewtopic.php?t=123 /page1.html
RedirectPermanent /forum/viewtopic.php?t=345 /page7.html
RedirectPermanent /forum/viewtopic.php?t=89 /page3.html
The old and new URL are not related to each other (no PHP parameter has to be kept or something). I want to decide manually in my .htaccess file what to do for each topic ID.
But I can't manage to do that so easily. I tried many things, but nothing works.
Is this possible ? Any idea ?
Thanks a lot !
Edit : additional question : I want to add a global redirection of all the folder /forum to the root of the site ("/"). I guess I can place it after the others, so if no other rule is trigered, this one will be trigered.
I'm trying some things like
RewriteRule ^forum /? [L,R=301]
But everything I have tried so far redirects me to the "page1.html" (my first rule). Any idea why ? Thanks a lot !
You can't match against the query string using mod_alias's Redirect, RedirectMatch, etc. You need to use mod_rewrite and match against the %{QUERY_STRING} variable:
RewriteEngine On
RewriteCond %{QUERY_STRING} ^t=123$
RewriteRule ^forum/viewtopic\.php$ /page1.html? [L,R=301]
RewriteCond %{QUERY_STRING} ^t=345$
RewriteRule ^forum/viewtopic\.php$ /page7.html? [L,R=301]
RewriteCond %{QUERY_STRING} ^t=89$
RewriteRule ^forum/viewtopic\.php$ /page3.html? [L,R=301]
NOte that RewriteEngine is a mod_rewrite directive, not mod_alias. So it has no affect at all on the RedirectPermanent directives.

Apache htaccess rewrite (Pretty URLs)

I have a sneaking suspicion this is not possible, but figured I would ask regardless.
Is it at all possible to take a URL passed to a server in the form of:
http://domain.com/index.php?Action=Controller/Action&one=1&two=2&three=3
And rewrite it to appear as:
http://domain.com/Controller/Action/1/2/3
I am trying to clean up an borderline ancient project to support "Pretty URLs" and I would really like to make the URLs display a bit nicer. I know I could setup a 301 header redirect to the new URL, but I would prefer to avoid that overhead if at all possible.
Any thoughts?
Thanks!
To get
http://domain.com/index.php?Action=Controller/Action&one=1&two=2&three=3
To appear as
http://domain.com/Controller/Action/1/2/3
You will need to use %{QUERY_STRING} to capture the query string data. Your .htaccess file will look like this:
RewriteEngine On
RewriteCond %{QUERY_STRING} ^Action=Controller/Action&one=(\d+)&two=(\d+)&three=(\d+)
RewriteRule ^.+ /Controller/Action/%1/%2/%3 [R=301,L]
This will set up a permanent redirect to the new page. You can play around and test .htaccess rewrite rules here: htaccess.madewithlove.be
You can use this code in your DOCUMENT_ROOT/.htaccess file:
RewriteEngine On
RewriteBase /
RewriteRule ^([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/?$ index.php?Action=$1/$2&one=$3&two=$4&three=$5 [L,QSA]

301 redirect but change URL to all lower case in apache

I'd like to set up a 301 redirect in Apache to change the case of the original address before redirecting. So for example if someone enters:
www.website1.com/UsErOfMiXedCase
it should forward to
www.website2.com/userofmixedcase
Would this be a redirect or would it need to be a rewrite? I'm not fussed about individual page forwarding (eg www.website2.com/userofmixedcase/whatever.php) - just www.website1.com/whatever.
Thank you in advance,
Richard
You need to define the rewrite map using Apache's internal tolower function. This can only be done in vhost or server config, and will result in an error if you try to put these directives in an htaccess file:
RewriteEngine On
RewriteMap lowercase int:tolower
Then, in your htaccess file, you can use something like this above any rewrite rules you already have. The redirect rules must be before whatever rules you may have that does routing:
# check that the lower case version of the URI is different than the unchanged URI
RewriteCond %{REQUEST_URI} ^/([^/]+)$
RewriteCond ${lowercase:%1}::%1 !^(.*)::\1$
RewriteRule ^/?(.+)$ http://www.website2.com/${lowercase:$1} [L,R=301]
This will redirect a request like http://www.website1.com/UsErOfMiXedCase to http://www.website2.com/userofmixedcase, thus replacing the URL in the browser's address bar with the one that's all lowercase. Note that it won't affect URLs with multiple path nodes, e.g. http://www.website1.com/SoMe/PathName/UsErOfMiXedCase. If you want it to affect all requests including ones that have multiple paths/subdirectories, then you need to change this line:
RewriteCond %{REQUEST_URI} ^/([^/]+)$
to:
RewriteCond %{REQUEST_URI} ^/(.+)$
You are wanting to use mod-rewrite for this. Something like:
RewriteRule ^/(.*) http://website2.com/$1 [NC]
That is a very general rule, so anything after the leading slash will be lower case. You may want to only do the lower case for specific portions of URL, but I cannot speak to that.
You probably should eyeball the Apache mod-rewrite documentation about the NC flag about this as well.
hth!

mod_rewrite doesn't work both directions

I get an original url:
www.mydomain.com/menu/?myid=29&mypage=pizza-hut.html
with the following mod_rewrite code:
Options +FollowSymLinks
RewriteEngine on
RewriteRule ^menu/([^/]*)/([^/]*)\.html$ /menu/?pid=$1&alias=$2 [L]
I get this nice url:
www.mydomain.com/menu/29/pizza-hut.html
so, both url above reference the same page...right!
now the real deal is,
WHY when I type the url,the original one:
www.mydomain.com/menu/?myid=29&mypage=pizza-hut.html
it doesn't redirect to
www.mydomain.com/menu/29/pizza-hut.html
it keeps its original one in the address bar, is there any line I should add?
Essentially, all the links you generate should be the nice urls. Don't have links like /menu/?myid=29&mypage=pizza-hut.html in any of your pages. Use the clean URLs that you've ensured to route correctly on the back end that look like this: www.mydomain.com/menu/29/pizza-hut.html
The rules that you have rewrite on the server the nice looking urls to what your content understands (e.g. /menu/?myid=29&mypage=pizza-hut.html). That's the most important part. If you want to correct all the direct requests for the ugly URLs, you need to first make sure all your pages start using the nice looking ones, then you can maybe do something like this:
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /menu/?\?myid=([^&]+)&mypage=([^&\ ]+)
RewriteRule ^menu/?$ /menu/%1/%2? [R=301,L]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /menu/?\?myid=([^&]+)&mypage=([^&\ ]+)
RewriteRule ^menu/?$ /menu/%1/%2.\html? [R=301,L]
Note the ? following the .\html

Trouble with advanced .htaccess redirect

I'm migrating a custom coded blog over to Wordpress, and have to set up a redirect that will handle all of the blog posts.
I need to redirect from this:
/oldblogdirectory/Old_Blog_Posts_Looked_Like_This.htm
to:
/newblogdirectory/new-blog-posts-look-like-this/
Any ideas on the regex for a redirect like this?
Gumbo's approach is certainly the way to do it. I made two test directories:
oldblogdir/archives/blog_posts_look_like_this.htm
newblogdir/archives/blog-posts-look-like-this
And the following RewriteRules redirect successfully. They are only slightly changed to Gumbo's proposal:
RewriteEngine on
RewriteBase /
RewriteRule ^(oldblogdir/archives/[^_]*)_(.*) $1-$2 [N]
RewriteRule ^oldblogdir/archives/(.*?)\.htm$ newblogdir/archives/$1 [R,NC,L]
Note that the [N] causes the .htaccess file to be re-evaluated until the RegEx no longer matches. Therefore you should put it at the very top of the file.
Try this mod_rewrite rules:
RewriteEngine on
RewriteRule ^(oldblogdirectory/[^_]*)_([^_]*)_(.*) /$1-$2-$3 [N]
RewriteRule ^(oldblogdirectory/[^_]*)_(.*) /$1-$2
RewriteRule ^oldblogdirectory/(.+)\.htm$ /newdirectory/$1/ [L,R=301]
But for the uppercase to lowercase conversion you’ll either need a mapping like the internal tolower function or you use PHP for both.