Htaccess Rewrites are enabled by using the Apache module mod_rewrite, which is one of the most powerful Apache modules and features availale. Htaccess Rewrites through mod_rewrite provide the special ability to Rewrite requests internally as well as Redirect request externally.
When the url in your browser's location bar stays the same for a request it is an internal rewrite, when the url changes an external redirection is taking place. This is one of the first, and one of the biggest mental-blocks people have when learning about mod_rewrite... But I have a secret weapon for you to use, a new discovery from years of research that makes learning mod_rewrite drastically quicker and easier. It truly does or I wouldn't be saying so in the introduction of this article.
Despite the tons of examples and docs, mod_rewrite is voodoo. Damned cool voodoo, but still voodoo.
-- Brian Moore
Note: After years of fighting to learn my way through rewriting urls with mod_rewrite, I finally had a breakthrough and found a way to outsmart the difficulty of mod_rewrite that I just couldn't seem to master. The Mod_Rewrite RewriteCond/RewriteRule Variable Value Cheatsheet is the one-of-a-kind tool that changed the game for me and made mod_rewriting no-harder than anything else.
So keep that mod_rewrite reference bookmarked and you will be able to figure out any RewriteRule or RewriteCond, an amazing feat considering it took me a LONG time to figure this stuff out on my own. But that was before the craziness, one of the most challenging and productive .htaccess experiments I've done... An experiment so ILL it's sick like a diamond disease on your wrist! $$$. That mod_rewrite experiment/tutorial was the culmination of many different advanced mod_rewrite experiments I had done in the past and included most of my very best .htaccess tricks. With the cheatsheet it's no longer Voodoo.. Its just what you do. Now lets dig in!
If you really want to take a look, check out the mod_rewrite.c and mod_rewrite.h files.
Be aware that mod_rewrite (RewriteRule, RewriteBase, and RewriteCond) code is executed for each and every HTTP request that accesses a file in or below the directory where the code resides, so it's always good to limit the code to certain circumstances if readily identifiable.
For example, to limit the next 5 RewriteRules to only be applied to .html and .php files, you can use the following code, which tests if the url does not end in .html or .php and if it doesn't, it will skip the next 5 RewriteRules.
RewriteRule !\.(html|php)$ - [S=5] RewriteRule ^.*-(vf12|vf13|vf5|vf35|vf1|vf10|vf33|vf8).+$ - [S=1]
Options +FollowSymLinks RewriteEngine On RewriteBase /
Options +FollowSymLinks RewriteEngine On RewriteBase / RewriteCond %{HTTP_HOST} !^www\.askapache\.com$ [NC] RewriteRule ^(.*)$ https://www.askapache.com/$1 [R=301,L]
Sometimes your rewrites cause infinite loops, stop it with one of these rewrite code snippets.
RewriteCond %{REQUEST_URI} ^/(stats/|missing\.html|failed_auth\.html|error/).* [NC] RewriteRule .* - [L] RewriteCond %{ENV:REDIRECT_STATUS} 200 RewriteRule .* - [L]
This is probably my favorite, and I use it on every site I work on. It allows me to update my javascript and css files in my visitors cache's simply by naming them differently in the html, on the server they stay the same name. This rewrites all files for /zap/j/anything-anynumber.js to /zap/j/anything.js and /zap/c/anything-anynumber.css to /zap/c/anything.css
RewriteRule ^zap/(j|c)/([a-z]+)-([0-9]+)\.(js|css)$ /zap/$1/$2.$4 [L]
When you use flash on your site and you properly supply a link to download flash that shows up for non-flash aware browsers, it is nice to use a shortcut to keep your code clean and your external links to a minimum. This code allows me to link to site.com/getflash/
for non-flash aware browsers.
RewriteRule ^getflash/?$ http://www.adobe.com/shockwave/download/download.cgi?P1_Prod_Version=ShockwaveFlash [NC,L,R=307]
On many sites, the page will be displayed for both page.html and page.html?anything=anything, which hurts your SEO with duplicate content. An easy way to fix this issue is to redirect external requests containing a query string to the same uri without the query_string.
RewriteCond %{THE_REQUEST} ^[A-Z]+ /.*\ HTTP RewriteCond %{QUERY_STRING} !^$ RewriteRule .* https://www.askapache.com%{REQUEST_URI}? [R=301,L]
This .htaccess rewrite example invisibly rewrites requests for all Adobe pdf files to be handled by /cgi-bin/pdf-script.php
RewriteRule ^(.+)\.pdf$ /cgi-bin/pdf-script.php?file=$1.pdf [L,NC,QSA]
For sites using multiviews or with multiple language capabilities, it is nice to be able to send the correct language automatically based on the clients preferred language.
RewriteCond %{HTTP:Accept-Language} ^.*(de|es|fr|it|ja|ru|en).*$ [NC] RewriteRule ^(.*)$ - [env=prefer-language:%1]
This allows access to all files by php fopen, but denies anyone else.
RewriteEngine On RewriteBase / RewriteCond %{THE_REQUEST} ^.+$ [NC] RewriteRule .* - [F,L]
If you are looking for ways to block or deny specific requests/visitors, then you should definately read Blacklist with mod_rewrite. I give it a 10/10
This can be very handy if you want to serve media files or special downloads but only through a php proxy script.
RewriteEngine On RewriteBase / RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /([^/]+)/.* HTTP [NC] RewriteRule .* - [F,L]
Options +FollowSymLinks RewriteEngine On RewriteBase / RewriteCond %{HTTP_HOST} !^askapache\.com$ [NC] RewriteRule ^(.*)$ http://askapache.com/$1 [R=301,L]
Uses a RewriteCond Directive to check QUERY_STRING for passkey, if it doesn't find it it redirects all requests for anything in the /logged-in/ directory to the /login.php script.
RewriteEngine On RewriteBase / RewriteCond %{QUERY_STRING} !passkey RewriteRule ^/logged-in/(.*)$ /login.php [L]
If the QUERY_STRING has any value at all besides blank than the?
at the end of /login.php? tells mod_rewrite to remove the QUERY_STRING from login.php and redirect.
RewriteEngine On RewriteBase / RewriteCond %{QUERY_STRING} . RewriteRule ^login\.php /login.php? [L]
An error message related to this isRequest exceeded the limit of 10 internal redirects due to probable configuration error. Use 'LimitInternalRecursion' to increase the limit if necessary. Use 'LogLevel debug' to get a backtrace.
or you may seeRequest exceeded the limit
,probable configuration error
,Use 'LogLevel debug' to get a backtrace
, orUse 'LimitInternalRecursion' to increase the limit if necessary
RewriteCond %{ENV:REDIRECT_STATUS} 200 RewriteRule .* - [L]
RewriteRule ^(.*)\.php$ /$1.html [R=301,L]
Redirects all files that end in .html to be served from filename.php so it looks like all your pages are .html but really they are .php
RewriteRule ^(.*)\.html$ $1.php [R=301,L]
Options +FollowSymLinks RewriteEngine On RewriteBase / # If the hour is 16 (4 PM) Then deny all access RewriteCond %{TIME_HOUR} ^16$ RewriteRule ^.*$ - [F,L]
Converts all underscores "_" in urls to hyphens "-" for SEO benefits... See the full article for more info.
Options +FollowSymLinks RewriteEngine On RewriteBase / RewriteRule !\.(html|php)$ - [S=4] RewriteRule ^([^_]*)_([^_]*)_([^_]*)_([^_]*)_(.*)$ $1-$2-$3-$4-$5 [E=uscor:Yes] RewriteRule ^([^_]*)_([^_]*)_([^_]*)_(.*)$ $1-$2-$3-$4 [E=uscor:Yes] RewriteRule ^([^_]*)_([^_]*)_(.*)$ $1-$2-$3 [E=uscor:Yes] RewriteRule ^([^_]*)_(.*)$ $1-$2 [E=uscor:Yes] RewriteCond %{ENV:uscor} ^Yes$ RewriteRule (.*) http://d.com/$1 [R=301,L]
Options +FollowSymLinks RewriteEngine On RewriteBase / RewriteCond %{HTTP_HOST} !^www\.[a-z-]+\.[a-z]{2,6} [NC] RewriteCond %{HTTP_HOST} ([a-z-]+\.[a-z]{2,6})$ [NC] RewriteRule ^/(.*)$ http://%1/$1 [R=301,L]
RewriteEngine On RewriteBase / RewriteCond %{HTTP_HOST} \.([a-z-]+\.[a-z]{2,6})$ [NC] RewriteRule ^/(.*)$ http://%1/$1 [R=301,L]
RewriteEngine On RewriteBase / RewriteCond %{HTTP_HOST} \.([^\.]+\.[^.0-9]+)$ RewriteRule ^(.*)$ http://%1/$1 [R=301,L]
Full article:Redirecting Wordpress Feeds to Feedburner
RewriteEngine On RewriteBase / RewriteCond %{REQUEST_URI} ^/feed\.gif$ RewriteRule .* - [L] RewriteCond %{HTTP_USER_AGENT} !^.*(FeedBurner|FeedValidator) [NC] RewriteRule ^feed/?.*$ http://feeds.feedburner.com/apache/htaccess [L,R=302] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L]
Article: Request Methods
RewriteEngine On RewriteBase / RewriteCond %{REQUEST_METHOD} !^(GET|PUT) RewriteRule .* - [F]
RewriteEngine On RewriteBase / RewriteCond %{HTTP_REFERER} !^$ RewriteCond %{HTTP_REFERER} !^http://(www\.)?askapache\.com/.*$ [NC] RewriteRule \.(gif|jpg|swf|flv|png)$ /feed/ [R=302,L]
RewriteEngine On SetEnvIfNoCase X-Forwarded-For .+ proxy=yes SetEnvIfNoCase X-moz prefetch no_access=yes # block pre-fetch requests with X-moz headers RewriteCond %{ENV:no_access} yes RewriteRule .* - [F,L]
This module uses a rule-based rewriting engine (based on a regular-expression parser) to rewrite requested URLs on the fly. It supports an unlimited number of rules and an unlimited number of attached rule conditions for each rule, to provide a really flexible and powerful URL manipulation mechanism. The URL manipulations can depend on various tests, of server variables, environment variables, HTTP headers, or time stamps. Even external database lookups in various formats can be used to achieve highly granular URL matching.
This module operates on the full URLs (including the path-info part) both in per-server context (
httpd.conf
) and per-directory context (.htaccess
) and can generate query-string parts on result. The rewritten result can lead to internal sub-processing, external request redirection or even to an internal proxy throughput.Further details, discussion, and examples, are provided in the detailed mod_rewrite documentation.
If you aren't already comfortable using mod_rewrite then I recommend this excellent mod_rewrite guide by one of my favorite mod_rewrite gurus that I've met.