Apache Rewrite Rules - Path Style - apache

I am coming from the IIS world to Apache and would appreciate some help on the rewrite rules.
I want this relative path:
/index.php?go=order&id=12345
to be rewritten as:
/go/order/id/12345
Also, if there are more parameters, they should be converted to path format:
/index.php?go=order&id=12345&action=process
becomes
/go/order/id/12345/action/process
How do I achieve this please? Thanks for any input.

Try putting this in your vhost config:
RewriteEngine On
# Start converting query parameters to path
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /index\.php\?[^\ ]+
RewriteCond %{QUERY_STRING} ^([^=]+)=([^&]+)&?(.*)$
RewriteRule ^(.*)$ $1/%1/%2?%3 [L]
# done converting, remove index.php and redirect browser
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /index\.php\?[^\ ]+
RewriteCond %{QUERY_STRING} ^$
RewriteRule ^/index.php/(.*)$ /$1 [R=301,L]
# internally rewrite paths to query strings
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/index\.php
RewriteRule ^/([^/]+)/([^/]+)/?(.*) /$3?$1=$2 [L,QSA]
# No more path, rewrite to index.php
RewriteRule ^/$ /index.php [L]
These rules will make it so if you type in a URL like http://yourdomain.com/index.php?a=b&1=2&z=x in your browser, the browser will get redirected to http://yourdomain.com/a/b/1/2/z/x. When the clean looking URL gets requested, the 2nd set of rules internally rewrites it back to /index.php?a=b&1=2&z=x. If you want to put these rules in an htaccess file (in your document root), you need to remove all the leading slashes in the RewriteRule's. So ^/ needs to be ^ in the last 3 rules.
Note that if you simply go to http://yourdomain.com/index.php, without a query string, nothing gets rewritten.

Related

mod_rewrite - how do I match a URL, but not it's subdirectories?

I have an ecommerce site, with product URLs in the following format: site.com/product/long-product-title-here?sku=skugoeshere and want it in this format: site.com/product/long-product-title-here/skugoeshere
One reason for the query is that each page could have multiple variations of the same product.
I'm trying to use mod_rewrite to make it look nicer using the following:
# RewriteCond %{QUERY_STRING} ^sku=(.+)$
# RewriteCond %{REQUEST_URI} product/([^/]+)$
# RewriteRule /([^/]+)$ /$1/%1 [R=301,L]
But this goes into a redirect loop of the form site.com/product/title/title/title...
How do I make the pattern only match the original URL?
Put this code in your DOCUMENT_ROOT/.htaccess file:
RewriteEngine On
# external redirect from actual URL to pretty one
RewriteCond %{THE_REQUEST} \s/+([^/]+/[^/]+)\?sku=([^\s&]+) [NC]
RewriteRule ^ /%1/%2? [R=302,L]
# internal forward from pretty URL to actual one
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{QUERY_STRING} !(?:^|&)sku=[^&]+
RewriteRule ^([^/]+/[^/]+)/([^/]+)/?$ /$1?sku=$2 [L,QSA]
skip the leading slash here
RewriteRule /([^/]+)$ $1/%1 [R=301,L]
^ no slash here

altering requests with two rewrite rules

So my webserver is serving up files like file_name.php. I want to make it so requests for file-name.php gets transparently redirected to file_name.php and that requests for file_name.php get explicitly redirected via a 301 redirect to file-name.php.
ie. you request file_name.php and you get 301 redirected to file-name.php which transparently loads file_name.php instead.
Unfortunately, the .htaccess file I've written to accomplish this isn't working. Here it is:
# make it so files with slashes that don't exist transparently redirect to files with underscores
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^-]*)-([^-]*)$ $1_$2
RewriteRule ^([^-]*)-([^-]*)-([^-]*)$ $1_$2_$3
# make it so files with underscores that do exist explicitely redirect to files with slashes
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^([^_]*)_([^_]*)$ /$1-$2 [L,R=301]
RewriteRule ^([^_]*)_([^_]*)_([^_]*)$ /$1-$2-$3 [L,R=301]
On their own they work but together it results in an infinite loop.
Any ideas?
This was really an interesting problem.
Code that I'm suggesting is a generic recursion based code that will translate each _ by - in URL externally (no matter how many underscore are there). While internally it will do the reverse translation and load the actual URL.
# Only single underscore do an external 301 redirect
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s/+([^_]+)_([^_\s]*) [NC]
RewriteRule ^ /%1-%2 [R=301,L]
# Recursively translate each _ to - in URL and do external 302 redirect
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s/+([^_]+)_([^\s]*) [NC]
RewriteRule ^ /%1-%2 [R,L]
# Recursively translate - to _ to load actual URL internally
RewriteRule ^([^-]+)-(.*)$ /$1_$2 [L]
Because the URI gets rewritten then plugged back into the rewrite engine, you'd get a redirect loop. You have to externally redirect by matching against the request and not the URI. Also, rewrite conditions only apply to the immediately following rewrite rule, so you need to duplicate them for each of your rules:
# make it so files with slashes that don't exist transparently redirect to files with underscores
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^-]*)-([^-]*)$ $1_$2 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^-]*)-([^-]*)-([^-]*)$ $1_$2_$3 [L]
# make it so files with underscores that do exist explicitely redirect to files with slashes
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /([^_]*)_([^_]*)_([^_\ \?]*)
RewriteRule ^ /%1-%2-%3 [L,R=301]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /([^_]*)_([^_\ \?]*)
RewriteRule ^ /%1-%2 [L,R=301]

Apache mod_rewrite for SEO urls, but rewrite to 404 if file doesn't exist

I'm unable to find the answer for this, so please let me know if it's been resolved before.
I'm using mod_rewrite to do "pretty" URLs, but if you request a file that doesn't exist (like, a typo) it will redirect and add .php a bunch of times and then fail. The code I have below:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ http://inquisito.rs/$1/ [R=301,l]
RewriteRule ^(.*)/$ /$1.php [L]
So if you go to http://inquisito.rs/aion/ it will show you the aion page, but if you go to, lets say, inquisito.rs/aio/ on accident, it gives this
http://inquisito.rs/aio.php.php.php.php.php.php.php.php.php.php.php.php.php.php.php.php.php.php.php.php/
Thanks in advance, I can't tell you how many times I've used information from here to resolve issues at work and at home.
Using the example you've given, this is how the rules are applied:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f # /aio/ is not a file, so this matched
RewriteCond %{REQUEST_URI} !(.*)/$ # This DOES NOT match, because you have a trailing slash
RewriteRule ^(.*)$ http://inquisito.rs/$1/ [R=301,L] # This rule doesn't run, because the condition above wasn't met
# This rule is separate from the RewriteConds above
RewriteRule ^(.*)/$ /$1.php [L] # This does match because of the lack of RewriteConds and because you have a trailing slash
Try this (untested) set of rules instead:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f # Make sure no matching file exists
RewriteCond %{REQUEST_URI} !\.php$ # Don't match requests that already end .php
RewriteCond %{REQUEST_URI} !(.*)/$ # Check for missing trailing slash
RewriteRule ^(.*)$ http://inquisito.rs/$1/ [R=301,L] # Redirect with trailing slash
# Separate rule
RewriteCond %{REQUEST_URI} !\.php$ # Don't match requests that already end .php
RewriteRule ^(.*)/$ /$1.php [L] # Internal redirect to matching PHP file
It's important to note that all matching RewriteRules cause a new request to be processed by htaccess again.

Apache ModRewrite Working in vhost but not .htaccess

I have the following mod rewrites:
RewriteEngine On
# rest api rewrites
RewriteCond %{REQUEST_URI} /api/v [NC]
RewriteRule ^(.*)$ /index.php/$1 [L,QSA]
# main application rewrite
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d
RewriteRule ^/[a-zA-Z0-9\-\_/]+?$ /index.html [L,QSA]
When I put these into my vhost config, everything works as excepted however when I put this into my .htaccess file, the first rewrite does an infinite loop (the log show an INTERNAL REWRITE) and the second rewrite doesn't work at all.
Why would these rewrites would in the vhost but not my .htaccess file?
The first rule loops because your target matches the regex, so once it rewrites the first time and the rules loop, the ^(.*)$ matches the URI that you've just rewritten to (/index.php/etc...`), so it causes an infinite loop (or loops as many times as the internal redirect limit is configured to). You need to add a condition to prevent the looping:
# rest api rewrites
RewriteCond %{REQUEST_URI} !^/index\.php
RewriteCond %{REQUEST_URI} /api/v [NC]
RewriteRule ^(.*)$ /index.php/$1 [L,QSA]
The second rule doesn't get applied at all because the URI being put through rules in an htaccess file has the leading slash stripped off (because htaccess is essentially like a <Directory> in vhost/server config), so you need to at least make that leading slash optional:
# main application rewrite
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d
RewriteRule ^/?[a-zA-Z0-9\-\_/]+?$ /index.html [L,QSA]

mod redirect rule

I just want to redirect the URL through the mod rewrite ruls. I have applied this rule excluding (R=301)
Example :
from http:///webapp/wcs/stores/servlet/en/marksandspencer to http:///en/marksandspencer
I am using this rules for the mod redirect rules.
RewriteEngine on
RewriteCond %{REQUEST_URI} !^(/)?$
RewriteCond %{REQUEST_URI} !^/webapp.*$
RewriteCond %{REQUEST_URI} !^/wcsstore.*$
RewriteRule ^/(.*)$ /webapp/wcs/stores/servlet/$1 [PT,NC,L,QSA]
RewriteRule ^/webapp/wcs/stores/servlet/(.*) /$1 [NE,L,QSA]
RewriteRule ^(/)?$ /webapp/wcs/stores/servlet/en/marksandspencer [PT,NC,L]
No idea what you're trying to do, but if you're using Apache 2.0 or higher, the leading slash is stripped off of URI's when matching is done within a RewriteRule. Also, you have a rule that looks like you're adding a /webapp/wcs/stores/servlet/ to the beginning of a URI, then the very next rule it looks like you are removing it. This will probably cause a loop.
Taking a wild guess at what you are trying to do, I think you need to add a condition to the 2nd rule, and remove the leading slashes:
# internally rewrite URI by appending "/webapp/wcs/stores/servlet/" to the front
RewriteCond %{REQUEST_URI} !^(/)?$
RewriteCond %{REQUEST_URI} !^/webapp.*$
RewriteCond %{REQUEST_URI} !^/wcsstore.*$
RewriteRule ^(.*)$ /webapp/wcs/stores/servlet/$1 [PT,NC,L,QSA]
# if a request is made with "/webapp/wcs/stores/servlet/" in it, redirect to a URI with it stripped
RewriteCond %{THE_REQUEST} ^(GET/POST)\ /webapp/wcs/stores/servlet/
RewriteRule ^webapp/wcs/stores/servlet/(.*) /$1 [R=301,L,QSA]
RewriteRule ^$ /webapp/wcs/stores/servlet/en/marksandspencer [PT,NC,L]