You are on page 1of 45

This and many other developer references available at http:/neatinfo.com/dev_notes/_cheat http:/neatinfo.

com/dev_notes/_cheat-sheets
by Jan Zumwalt - NeatInfo.com

Notes ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________
Pg 2 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

Table of Contents
Section - 1 .htaccess tips and tricks .............................................................................................................. 6
Introduction to .htaccess.. .................................................................................................................................................... 6 .htaccess files are invisible ....................................................................................................................................................... 6 What are .htaccess files anyway? ........................................................................................................................................ 7 Is .htaccess enabled? .......................................................................................................................................................... 7

Section - 2

What .htaccess can do ................................................................................................................ 8

Control access.. ................................................................................................................................................................... 8 Custom error documents...................................................................................................................................................... 8 Password protected directories.. .......................................................................................................................................... 9 Get better protection.. ........................................................................................................................................................ 10 500 error.. .......................................................................................................................................................................... 10 Groovy things to do with .htaccess.. .................................................................................................................................. 10 custom directory index files ................................................................................................................................................ 11 Save bandwidth with .htaccess! ......................................................................................................................................... 11 Hide and deny files.. .......................................................................................................................................................... 12 <FilesMatch> ..................................................................................................................................................................... 12 More stuff.. ......................................................................................................................................................................... 13 over to you.. ....................................................................................................................................................................... 14

Section - 3

htaccess ................................................................................................................................... 15

Apache Gzip Compression ................................................................................................................................................ 15 Another method ................................................................................................................................................................. 15 Rails Cache........................................................................................................................................................................ 15 Redirect Not-WWW to WWW............................................................................................................................................. 16

Section 4

from www to non-www .............................................................................................................. 17

Security Rules .................................................................................................................................................................... 17 Enable Directory Browsing ................................................................................................................................................. 17 Disable Directory Browsing ................................................................................................................................................ 17 Customize Error Messages ................................................................................................................................................ 17 Get SSI working with HTML/SHTML .................................................................................................................................. 18 Change Default Page (order is followed!) .......................................................................................................................... 18 Block Users from accessing the site .................................................................................................................................. 18 Allow only LAN users ......................................................................................................................................................... 18 Redirect Visitors to New Page/Directory ............................................................................................................................ 18 Block site from specific referrers ........................................................................................................................................ 18 Want to show a Stealing is Bad message too?........................................................................................................... 18 Stop .htaccess (or any other file) from being viewed ......................................................................................................... 18 Avoid the 500 Error ............................................................................................................................................................ 19 Grant CGI Access in a directory......................................................................................................................................... 19 Password Protecting Directories ........................................................................................................................................ 19 Change Script Extensions .................................................................................................................................................. 19 Use MD5 Digests ............................................................................................................................................................... 19

Pg 3 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

The CheckSpelling Directive .............................................................................................................................................. 19 The ContentDigest Directive .............................................................................................................................................. 19 Enable Gzip to Save Bandwidth......................................................................................................................................... 19 Turn off magic_quotes_gpc .................................................................................................................................................. 20 Set an Expires header and enable Cache-Control ............................................................................................................. 20 Skip the download dialogue using .htaccess...................................................................................................................... 20 Using htaccess to Prevent Hacking ................................................................................................................................... 20 301 Website Redirect......................................................................................................................................................... 21 Turning on Server Side Includes (SSI) ............................................................................................................................... 21 Parse HTML files as PHP .................................................................................................................................................. 22

Section 5

Redirecting and Rewriting......................................................................................................... 23

beginning rewriting.. ........................................................................................................................................................... 23 simple rewriting .................................................................................................................................................................. 24 not-so-simple rewriting ... flat links and more ..................................................................................................................... 25 shortening URLs ................................................................................................................................................................ 27 capturing variables ............................................................................................................................................................. 27 cooler access denied ......................................................................................................................................................... 29 Ban User Agents, referrers, script-kiddies and more.. ....................................................................................................... 30 Don't let just anyone hammer your site! ............................................................................................................................. 31 prevent hot-linking .............................................................................................................................................................. 31 lose the "www" ................................................................................................................................................................... 32 multiple domains in one root .............................................................................................................................................. 32 automatic translation .......................................................................................................................................................... 33 httpd.conf ........................................................................................................................................................................... 34 inheritance.. ....................................................................................................................................................................... 34 cookies ............................................................................................................................................................................... 35 conclusion .......................................................................................................................................................................... 36

Section 6

Troubleshooting Tips ................................................................................................................ 38

Fatal Redirection ................................................................................................................................................................ 38 rewrite logging.................................................................................................................................................................... 38 debug-report.php ............................................................................................................................................................... 39

Back Page ....................................................................................................................................................... 45


Documenation .................................................................................................................................................................... 45 http://www.htaccesseditor.com/en.shtml ............................................................................................................................ 45 Tutorials ............................................................................................................................................................................. 45 References......................................................................................................................................................................... 45

Pg 4 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

Note: This is a new document and is not fully formatted (a work in progress). 2012-03-18

Pg 5 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

Section - 1 .htaccess tips and tricks


Much of the material presented here is based on an excellent tutorial at http://corz.org/serv/tricks/ aterial

Introduction to .htaccess..
This work in constant progress is some collected wisdom, stuff I've learned on the topic of .htaccess hacking, commands I've used successfully in the past, on a variety of server setups, and in most cases still do. You may mmands have to tweak the examples some to get the desired result, though, and a reliable test server is a powerful ally, preferably one with a very similar setup to your "live" server. Okay, to begin.. ar
..a win32 Apache mirror of corz.org

.htaccess files are invisible


There's a good reason why you won't see .htaccess files on the web; almost every web server in the world is configured to ignore them, by default. Same goes for most operating systems. Mainly it's the dot "." at the start, you see? If you don't see, you'll need to disable your operating system's invisible file functions, or use a text editor that allows you to open hidden files, something like bbedit on the Mac platform. On windows, showing invisibles in explorer should allow any text editor to open them, and most decent editors to save them too**. Linux dudes editors know how to find them without any help from me.

that same folder, as seen from Mac OS X

In both images, the operating system has been instructed to display invisible files. ugly, but necessary ting sometimes. You will also need to instruct your ftp client to do the same. By the way; the windows screencap is more recent than the mac one, moved files are likely being handled by handl my clever 404 script.

Pg 6 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

** even notepad can save files beginning with a dot, if you put double-quotes around the name when you save it; i.e.. ".htaccess". You can also use your ftp client to rename files beginning with a dot, even on your local filesystem; works great in FileZilla.

What are .htaccess files anyway?


Simply put, they are invisible plain text files where one can store server directives. Server directives are anything you might put in an Apache config file (httpd.conf) or even a php.ini**, but unlike those "master" directive files, these .htaccess directives apply only to the folder in which the .htaccess file resides, and all the folders inside. This ability to plant .htaccess files in any directory of our site allows us to set up a finely-grained tree of server directives, each subfolder inheriting properties from its parent, whilst at the same time adding to, or over-riding certain directives with its own .htaccess file. For instance, you could use .htacces to enable indexes all over your site, and then deny indexing in only certain subdirectories, or deny index listings site-wide, and allow indexing in certain subdirectories. One line in the .htaccess file in your root and your whole site is altered. From here on, I'll probably refer to the main .htaccess in the root of your website as "the master .htaccess file", or "main" .htaccess file. There's a small performance penalty for all this .htaccess file checking, but not noticeable, and you'll find most of the time it's just on and there's nothing you can do about it anyway, so let's make the most of it.. ** Your main php.ini, that is, unless you are running under phpsuexec, in which case the directives would go inside individual php.ini files

Is .htaccess enabled?
It's unusual, but possible that .htaccess is not enabled on your site. If you are hosting it yourself, it's easy enough to fix; open your httpd.conf in a text editor, and locate this <Directory> section.. Your DocumentRoot may be different, of course..
# This should be changed to whatever you set DocumentRoot to. # <Directory "/var/www/htdocs"> #

..locate the line that reads..


AllowOverride None

..and change it to..


AllowOverride All

Restart Apache. Now .htaccess will work. You can also make this change inside a virtual host, which would normally be preferable. If your site is hosted with someone else, check your control panel (Plesk. CPanel, etc.) to see if you can enable it there, and if not, contact your hosting admins. Perhaps they don't allow this. In which case, switch to a better web host.

Pg 7 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

Section - 2 What .htaccess can do


Almost any directive that you can put inside an httpd.conf file will also function perfectly inside an .htaccess file. Unsurprisingly, the most common use of .htaccess is to..

Control access..
.htaccess is most often used to restrict or deny access to individual files and folders. A typical example would be an "includes" folder. Your site's pages can call these included scripts all they like, but you don't want users accessing these files directly, over the web. In that case you would drop an .htaccess file in the includes folder with content something like this..
NO ENTRY! # no one gets in here! deny from all

which would deny ALL direct access to ANY files in that folder. You can be more specific with your conditions, for instance limiting access to a particular IP range, here's a handy top-level rule for a local test server..
NO ENTRY outside of the LAN! # no nasty crackers in here! order deny,allow deny from all allow from 192.168.0.0/24 # this would do the same thing.. #allow from 192.168.0

Generally these sorts of requests would bounce off your firewall anyway, but on a live server (like my dev mirror sometimes is) they become useful for filtering out undesirable IP blocks, known risks, lots of things. By the way, in case you hadn't spotted; lines beginning with "#" are ignored by Apache; handy for comments. Sometimes, you will only want to ban one IP, perhaps some persistent robot that doesn't play by the rules..
post user agent every fifth request only. hmmm. ban IP.. # someone else giving the ruskies a bad name.. order allow,deny deny from 83.222.23.219 allow from all

The usual rules for IP addresses apply, so you can use partial matches, ranges, and so on. Whatever, the user gets a 403 "access denied" error page in their client software (browser, usually), which certainly gets the message across. This is probably fine for most situations, but in part two I'll demonstrate some cooler ways to deny access, as well as how to deny those nasty web suckers, bad referrers, script kiddies and more.

Custom error documents..


I guess I should briefly mention that .htaccess is where most folk configure their error documents. Usually with sommething like this..
the usual method. the "err" folder (with the custom pages) is in the root # custom error documents ErrorDocument 401 /err/401.php ErrorDocument 403 /err/403.php ErrorDocument 404 /err/404.php ErrorDocument 500 /err/500.php

You can also specify external URLs, though this can be problematic, and is best avoided. One quick and simple method is to specify the text in the directive itself, you can even use HTML (though there is probably a limit to how much HTML you can squeeze onto one line). Remember, for Apache 1; begin with a ", but DO NOT end with one. For Apache 2, you can put a second quote at the end, as normal.
measure twice, quote once..

Pg 8 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

# quick custom error "document".. ErrorDocument 404 "<html><head><title>NO!</title></head><body><h2><tt>There is nothing here.. go away quickly!</tt></h2></body></html>

Using a custom error document is a Very Good Idea, and will give you a second chance at your almost-lost visitors. I recommend you download mine. But then, I would.

Password protected directories..


The next most obvious use for our .htaccess files is to allow access to only specific users, or user groups, in other words; password protected folders. a simple authorisation mechanism might look something like this..
a simple sample .htaccess file for password protection: AuthType Basic AuthName "restricted area" AuthUserFile /usr/local/var/www/html/.htpasses require valid-user

You can use this same mechanism to limit only certain kinds of requests, too..
only valid users can POST in here, anyone can GET, PUT, etc: AuthType Basic AuthName "restricted area" AuthUserFile /usr/local/var/www/html/.htpasses <Limit POST> require valid-user </Limit>

You can find loads of online examples of how to setup authorization using .htaccess, and so long as you have a real user (or create one, in this case, 'jimmy') with a real password (you will be prompted for this, twice) in a real password file (the -c switch will create it)..

htpasswd -c /usr/local/var/www/html/.htpasses jimmy ..the above will work just fine. htpasswd is a tool that comes free with Apache, specifically for making and updating password files, check it out. The windows version is the same; only the file path needs to be changed; to wherever you want to put the password file.

Note: if the Apache bin/ folder isn't in your PATH, you will need to cd into that directory before performing the
command. Also note: You can use forward and back-slashes interchangeably with Apache/php on Windows, so this would work just fine. htpasswd -c c:/unix/usr/local/Apache2/conf/.htpasses jimmy Relative paths are fine too; assuming you were inside the bin/ directory of our fictional Apache install, the following would do exactly the same as the above. htpasswd -c ../conf/.htpasses jimmy Naming the password file .htpasses is a habit from when I had to keep that file inside the web site itself, and as web servers are configured to ignore files beginning with .ht, they too, remain hidden. If you keep your password file outside the web root (a better idea), then you can call it whatever you like, but the .ht_something habit is a good one to keep, even inside the web tree, it is secure enough for our basic purpose.. Once they are logged in, you can access the remote_user environmental variable, and do stuff with it.. the remote_user variable is now available..
RewriteEngine on RewriteCond %{remote_user} !^$ [nc] RewriteRule ^(.*)$ /users/%{remote_user}/$1

Which is a handy directive, utilizing mod_rewrite; a subject I delve into far more deeply, in part two. Pg 9 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

Get better protection..


The authentication examples above assume that your web server supports "Basic" http authorisation, as far as I know they all do (it's in the Apache core). Trouble is, some browsers aren't sending password this way any more, personally I'm looking to php to cover my authorization needs. Basic auth works okay though, even if it isn't actually very secure - your password travels in plain text over the wire, not clever. If you have php, and are looking for a more secure login facility, check out pajamas. It's free. If you are looking for a password-protected download facility (and much more, besides), check out my distro machine, also free.

500 error..
If you add something that the server doesn't understand or support, you will get a 500 error page, aka.. "the server did a boo-boo". Even directives that work perfectly on your test server at home may fail dramatically at your real site. In fact this is a great way to find out if .htaccess files are enabled on your site; create one, put some gibberish in it, and load a page in that folder, wait for the 500 error. if there isn't one, probably they are not enabled. If they are, we need a way to safely do live-testing without bringing the whole site to a 500 standstill. Fortunately, in much the same way as we used the <Limit> tag above, we can create conditional directives, things which will only come into effect if certain conditions are true. The most useful of these is the "ifModule" condition, which goes something like this.. only if PHP is loaded, will this directive have any effect (switch the 4 for a 5 if using php5)
<ifModule mod_php4.c> php_value default_charset utf-8 </ifModule>

..which placed in your master .htaccess file, that would set the default character encoding of your entire site to utf-8 (a good idea!), at least, anything output by PHP. If the PHP4** module isn't running on the server, the above .htaccess directive will do exactly nothing; Apache just ignores it. As well as proofing us against knocking the server into 500 mode, this also makes our .htaccess directives that wee bit more portable. Of course, if your syntax is messed-up, no amount of if-module-ing is going to prevent a error of some kind, all the more reason to practice this stuff on a local test server. ** note: if you are using php5, you would obviously instead use <ifModule mod_php5.c>.

Groovy things to do with .htaccess..


So far we've only scratched the surface. Aside from authorisation, the humble .htaccess file can be put to all kinds of uses. If you've ever had a look in my public archives you will have noticed that that the directories are fully browsable, just like in the old days before adult web hosts realized how to turn that feature off! A line like this.. bring back the directories!
Options +Indexes +MultiViews +FollowSymlinks

..will almost certainly turn it back on again. And if you have mod_autoindex.c installed on your server (probably, yes), you can get nice fancy indexing, too.. show me those files!
<IfModule mod_autoindex.c> IndexOptions FancyIndexing </ifModule>

Pg 10 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

..which, as well as being neater, allows users to click the titles and, for instance, order the listing by date, or file size, or whatever. It's all for free too, built-in to the server, we're just switching it on. You can control certain parameters too.. let's go all the way!
<IfModule mod_autoindex.c> IndexOptions FancyIndexing IconHeight=16 IconWidth=16 </ifModule>

Other parameters you could add include.


NameWidth=30 DescriptionWidth=30 IconsAreLinks SuppressHTMLPreamble (handy!)

I'm not mentioning the "XHTML" parameter in Apache2, because it still isn't! Anyways, I've chucked one of my old fancy indexing .htaccess file onsite for you to have some fun with. Just add readme.html and away you go! note: these days I use a single header files for all the indexes.
HeaderName /inc/header.html

.. and only drop in local "readme" files. Check out the example, and my public archives for more details.

custom directory index files


While I'm here, it's worth mentioning that .htaccess is where you can specify which files you want to use as your indexes, that is, if a user requests /foo/, Apache will serve up /foo/index.html, or whatever file you specify. You can also specify multiple files, and Apache will look for each in order, and present the first one it finds. It's generally setup something like.
DirectoryIndex index.html index.php index.htm

It really is worth scouting around the Apache documentation, often you will find controls for things you imagined were uncontrollable, thereby creating new possibilities, better options for your website. My experience of the magic "LAMP" (Linux-Apache-MySQL-PHP) has been.. "If you can imagine that it can be done, it can be done". Swap "Linux" for any decent operating system, the "AMP" part runs on most of them. Okay, so now we have nice fancy directories, and some of them password protected, if you don't watch out, you're site will get popular, and that means bandwidth..

Save bandwidth with .htaccess!


If you pay for your bandwidth, this wee line could save you hard cash.. save me hard cash! and help the internet!
<ifModule mod_php4.c> php_value zlib.output_compression 16386 </ifModule>

All it does is enables PHP's built-in transparent zlib compression. This will half your bandwidth usage in one stroke, more than that, in fact. Of course it only works with data being output by the PHP module, but if you design your pages with this in mind, you can use php echo statements, or better yet, php "includes" for your

Pg 11 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

plain html output and just compress everything! Remember, if you run phpsuexec, you'll need to put php directives in a local php.ini file, not .htaccess. See here for more details.

Hide and deny files..


Do you remember I mentioned that any file beginning with .ht is invisible? .."almost every web server in the world is configured to ignore them, by default" and that is, of course, because .ht_anything files generally have server directives and passwords and stuff in them, most servers will have something like this in their main configuration.. Standard setting..
<Files ~ "^\.ht"> Order allow,deny Deny from all Satisfy All </Files>

which instructs the server to deny access to any file beginning with .ht, effectively protecting our .htaccess and other files. The "." at the start prevents them being displayed in an index, and the .ht prevents them being accessed. This version.. ignore what you want
<Files ~ "^.*\.([Ll][Oo][Gg])"> Order allow,deny Deny from all Satisfy All </Files>

tells the server to deny access to *.log files. You can insert multiple file types into each rule, separating them with a pipe "|", and you can insert multiple blocks into your .htaccess file, too. I find it convenient to put all the files starting with a dot into one, and the files with denied extensions into another, something like this.. the whole lot
# deny all .htaccess, .DS_Store $h and ._* (resource fork) files <Files ~ "^\.([Hh][Tt]|[Dd][Ss]_[Ss]|[_])"> Order allow,deny Deny from all Satisfy All </Files> # deny access to all .log and .comment files <Files ~ "^.*\.([Ll][Oo][Gg]|[cC][oO][mM][mM][eE][nN][tT])"> Order allow,deny Deny from all Satisfy All </Files>

would cover all ._* resource fork files, .DS_Store files (which the Mac Finder creates all over the place) *.log files, *.comment files and of course, our .ht* files. You can add whatever file types you need to protect from direct access. I think it's clear now why the file is called ".htaccess".

<FilesMatch>
These days, using <FilesMatch> is preferred over <Files>, mainly because you can use regular expression in the conditions (very handy), produce clean, more readable code. Here's an example. which I use for my phpgenerated style sheets.. parse file.css and file.style with the php machine..
# handler for phpsuexec.. <FilesMatch "\.(css|style)$">

Pg 12 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

SetHandler application/x-httpd-php </FilesMatch>

Any files with a *.css or *.style extension will now be handled by php, rather than simply served up by Apache. And because you can use regexp, you could do stuff like <FilesMatch "\.s?html$">, which is handy. Any <Files> statements you come across can be advantageously replaced by <FilesMatch> statements. Good to know.

More stuff..
At the end of my .htaccess files, there always seems to be a section of "stuff"; miscellaneous commands, mainly php flags and switches; so it seems logical to finish up the page with a wee selection of those.. php flags, switches and other stuff..
# let's enable php (non-cgi, aka. 'module') for EVERYTHING..' AddType application/x-httpd-php5 .htm .html .php .blog .comment .inc # better yet.. AddHandler php5-script .php # legacy php4 version..' AddType application/x-httpd-php .htm .html .php .blog .comment .inc # don't even think about setting this to 'on' php_value register_globals off # no session id's in the URL PULEEZE! php_value session.use_trans_sid 0 # should be the same as.. php_flag session.use_trans_sid off # using both should also work fine! # php error logs.. php_flag display_errors off php_flag log_errors on php_value track_errors on php_value error_log /home/cor/errors/phperr.log # if you like to collect interesting php system shell access and web hack scripts # get yourself a SECURE upload facility, and just let the script-kiddies come # in no time you will have a huge selection of fascinating code. If you want folk to # also upload zips and stuff, you might want to increase the upload capacities.. php_value upload_max_filesize 12M php_value post_max_size 12M # php 5 only, afaik. handy when your server isn't where YOU are. php_value date.timezone Europe/Aberdeen # actually, Europe/Aberdeen isn't a valid php timezone, so that won't work. # I recommend you check the php manual for this function, because many crazy places ARE!

Note: For most of the flags I've tested, you can use on/off and true/false interchangeably, as well as 0/1, also php_value and php_flag can be switched around while things continue to work as expected! I guess, logically, booleans should always be php_flag, and values, php_value; but suffice to say, if some php erm, directive isn't working, these would all be good things to fiddle with! Of course, the php manual explains all. The bottom line is; both will work fine, but if you use the wrong type in .htaccess, say, set a php_flag using php_value, a php ini_get() command, for instance, would return true, even though you had set the value to off, because it reads off value as a string, which of course evaluates to not-zero, i.e. 1, or "true". If you don't rely on get_ini(), or similar, it's not a problem, though clearly it's better to get it right from the start. By the way; one of the values above is incorrectly set. Did you spot it? Most php settings, you can override inside your actual scripts, but I do find it handy to be able to set defaults for a folder, or an entire site, using .htaccess. Pg 13 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

over to you..
That should get you started with .htaccess, quite easy when you know how. If you really want to bend your brain out of shape, follow the link below for part two of the series, where I delve into the arcane mysteries of URL rewriting.

Pg 14 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

Section - 3 htaccess
Apache Gzip Compression
The following snippet enables the Gzip compression for everything except compressed images. Gzipping your content usually reduces the response size by about 70%. Do you want to learn more? Watch how Gzip compression works and why its so important.
# Enables compression for everything except compressed images. # See http://httpd.apache.org/docs/2.0/mod/mod_deflate.html # Required mod_deflate and mod_headers <IfModule mod_deflate.c> <IfModule mod_headers.c> <Location /> # Insert filter SetOutputFilter DEFLATE # Netscape 4.x has some problems... BrowserMatch ^Mozilla/4 gzip-only-text/html # Netscape 4.06-4.08 have some more problems BrowserMatch ^Mozilla/4\.0[678] no-gzip # MSIE masquerades as Netscape, but it is fine # BrowserMatch \bMSIE !no-gzip !gzip-only-text/html # NOTE: Due to a bug in mod_setenvif up to Apache 2.0.48 # the above regex won't work. You can use the following # workaround to get the desired effect: BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html # Don't compress images SetEnvIfNoCase Request_URI \ \.(?:gif|jpe?g|png)$ no-gzip dont-vary # Make sure proxies don't deliver the wrong content Header append Vary User-Agent env=!dont-vary </Location> </IfModule> </IfModule>

Another method
# compress text, html, javascript, css, xml: AddOutputFilterByType DEFLATE text/plain AddOutputFilterByType DEFLATE text/html AddOutputFilterByType DEFLATE text/xml AddOutputFilterByType DEFLATE text/css AddOutputFilterByType DEFLATE application/xml AddOutputFilterByType DEFLATE application/xhtml+xml AddOutputFilterByType DEFLATE application/rss+xml AddOutputFilterByType DEFLATE application/javascript AddOutputFilterByType DEFLATE application/x-javascript

Rails Cache
Pg 15 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

The following two snippets are meant to be used in combination with Rails page caching. They instruct Apache to look for a cached resource in the /cache folder and serve the content from the directory if the file exists.
RewriteEngine On RewriteCond %{DOCUMENT_ROOT}/cache%{REQUEST_URI}.html -f RewriteRule ^(.*)$ /cache/$1.html [QSA,L]

RewriteEngine On RewriteCond %{DOCUMENT_ROOT}/cache/%{HTTP_HOST}%{REQUEST_URI}.html -f RewriteRule ^(.*)$ /cache/%{HTTP_HOST}/$1.html [QSA,L]

Redirect Not-WWW to WWW


This is a really generic Not-WWW to WWW configuration script. Unlike most existing scripts, it doesnt force you to manually inject the server name. Just include the snippets and youre ready. If you are looking for a less exotic configuration, have a look at the How to 301 redirect Not-WWW to WWW version question at Search Marketing Arena.
# More details available at http://www.askapache.com/htaccess/http-https-rewriterule-redirect.html RewriteEngine On RewriteCond %{SERVER_PORT}s ^(443(s)|[0-9]+s)$ RewriteRule ^(.+)$ - [env=thes:%2] RewriteCond %{HTTP_HOST} !^www\.(.+) [NC] RewriteRule ^/(.*)$ http%{ENV:thes}://www.%{HTTP_HOST}/$1 [R=301,L]

The conventional approach is RewriteEngine on RewriteCond % ^yourdomain.com [NC] RewriteRule ^(.*)$ http://www.yourdomain.com/$1 [L,R=301]

Pg 16 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

Section 4 from www to non-www


RewriteEngine on RewriteCond % ^www.yourdomain.com [NC] RewriteRule ^(.*)$ http://yourdomain.com/$1 [L,R=301

Security Rules
In the attempt to reduce the amount of spam comments sent to my blogs, I extracted some recurrent patterns from my server logs and created some super-simple rules to kick out automated script. Basically, this is the same idea behind mod_security, with the (huge) difference my set of rules it much more simple but much more lightweight.
# Block some user agents from posting RewriteEngine On RewriteCond %{HTTP_USER_AGENT} ^-$ [OR] RewriteCond %{HTTP_USER_AGENT} ^(Jakarta\sCommons\-HttpClient) [NC] RewriteCond %{REQUEST_METHOD} ^POST$ RewriteRule . - [F,L] # Block libwww-perl/5.805 from attempting to exploit security vulnerabilities RewriteEngine On RewriteCond %{HTTP_USER_AGENT} ^libwww\-perl/.+ [NC] RewriteCond %{QUERY_STRING} . RewriteRule . - [F,L] # Block generic Java-based clients RewriteEngine On RewriteCond %{HTTP_USER_AGENT} ^Java/1\.6\.0_04 [NC] RewriteRule . - [F,L]

RewriteEngine On RewriteCond %{HTTP_USER_AGENT} ^\-$ [NC] RewriteRule . - [F,L]

All configuration snippets are available free of charge and without any warranty. Use them at your own risk.

Enable Directory Browsing


Options +Indexes ## block a few types of files from showing IndexIgnore *.wmv *.mp4 *.avi

Disable Directory Browsing


Options All -Indexes

Customize Error Messages


ErrorDocument 403 /forbidden.html ErrorDocument 404 /notfound.html ErrorDocument 500 /servererror.html Pg 17 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

Get SSI working with HTML/SHTML


AddType text/html .html AddType text/html .shtml AddHandler server-parsed .html AddHandler server-parsed .shtml # AddHandler server-parsed .htm

Change Default Page (order is followed!)


DirectoryIndex myhome.htm index.htm index.php

Block Users from accessing the site


<limit GET POST PUT> order deny,allow deny from 202.54.122.33 deny from 8.70.44.53 deny from .spammers.com allow from all </limit>

Allow only LAN users


order deny,allow deny from all allow from 192.168.0.0/24

Redirect Visitors to New Page/Directory


Redirect oldpage.html http://www.domainname.com/newpage.html Redirect /olddir http://www.domainname.com/newdir/

Block site from specific referrers


RewriteEngine on RewriteCond %{HTTP_REFERER} site-to-block\.com [NC] RewriteCond %{HTTP_REFERER} site-to-block-2\.com [NC] RewriteRule .* - [F]
Block Hot Linking/Bandwidth hogging

RewriteEngine on RewriteCond %{HTTP_REFERER} !^$ RewriteCond %{HTTP_REFERER} !^http://(www\.)?mydomain.com/.*$ [NC] RewriteRule \.(gif|jpg)$ - [F]

Want to show a Stealing is Bad message too?


Add this below the Hot Link Blocking code: RewriteRule \.(gif|jpg)$ http://www.mydomain.com/dontsteal.gif [R,L]

Stop .htaccess (or any other file) from being viewed


<files file-name> order allow,deny Pg 18 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

deny from all </files>

Avoid the 500 Error


# Avoid 500 error by passing charset AddDefaultCharset utf-8

Grant CGI Access in a directory


Options +ExecCGI AddHandler cgi-script cgi pl # To enable all scripts in a directory use the following # SetHandler cgi-script

Password Protecting Directories


Use the .htaccess Password Generator and follow the brief instructions!

Change Script Extensions


AddType application/x-httpd-php .gne gne will now be treated as PHP files! Similarly, x-httpd-cgi for CGI files, etc.

Use MD5 Digests


Performance may take a hit but if thats not a problem, this is a nice option to turn on. ContentDigest On

The CheckSpelling Directive


From Jens Meiert: CheckSpelling corrects simple spelling errors (for example, if someone forgets a letter or if any character is just wrong). Just add CheckSpelling On to your htaccess file.

The ContentDigest Directive


As the Apache core features documentation says: This directive enables the generation of Content-MD5 headers as defined in RFC1864 respectively RFC2068. The Content-MD5 header provides an end-to-end message integrity check (MIC) of the entity-body. A proxy or client may check this header for detecting accidental modification of the entity-body in transit. Note that this can cause performance problems on your server since the message digest is computed on every request (the values are not cached). Content-MD5 is only sent for documents served by the core, and not by any module. For example, SSI documents, output from CGI scripts, and byte range responses do not have this header. To turn this on, just add ContentDigest On.

Enable Gzip to Save Bandwidth


# BEGIN GZIP <ifmodule mod_deflate.c> # Combine the below two lines - I've split it up for presentation AddOutputFilterByType DEFLATE text/text text/html text/plain text/xml text/css application/x-javascript application/javascript </ifmodule> Pg 19 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

# END GZIP

Turn off magic_quotes_gpc


# Only if you use PHP <ifmodule mod_php4.c> php_flag magic_quotes_gpc off </ifmodule>

Set an Expires header and enable Cache-Control


<ifmodule mod_expires.c> ExpiresActive On ExpiresDefault "access plus 1 seconds" ExpiresByType text/html "access plus 7200 seconds" ExpiresByType image/gif "access plus 518400 seconds" ExpiresByType image/jpeg "access plus 518400 seconds" ExpiresByType image/png "access plus 518400 seconds" ExpiresByType text/css "access plus 518400 seconds" ExpiresByType text/javascript "access plus 216000 seconds" ExpiresByType application/x-javascript "access plus 216000 seconds" </ifmodule> <ifmodule mod_headers.c> # Cache specified files for 6 days <filesmatch "\.(ico|flv|jpg|jpeg|png|gif|css|swf)$"> Header set Cache-Control "max-age=518400, public" </filesmatch> # Cache HTML files for a couple hours <filesmatch "\.(html|htm)$"> Header set Cache-Control "max-age=7200, private, must-revalidate" </filesmatch> # Cache PDFs for a day <filesmatch "\.(pdf)$"> Header set Cache-Control "max-age=86400, public" </filesmatch> # Cache Javascripts for 2.5 days <filesmatch "\.(js)$"> Header set Cache-Control "max-age=216000, private" </filesmatch> </ifmodule>

Skip the download dialogue using .htaccess


Usually when you try to download something from a web server you get a request asking whether you want to save the file or open it. To avoid that you can use the below code on your .htaccess file
AddType application/octet-stream .pdf AddType application/octet-stream .zip AddType application/octet-stream .mov

Using htaccess to Prevent Hacking


Pg 20 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

If you want to increase the security level of your website, you can chuck these few lines of codes to prevent some common hacking techniques by detecting malicious URL patterns.
RewriteEngine On # proc/self/environ? no way! RewriteCond %{QUERY_STRING} proc/self/environ [OR] # Block out any script trying to set a mosConfig value through the URL RewriteCond %{QUERY_STRING} mosConfig_[a-zA-Z_]{1,21}(=|\%3D) [OR] # Block out any script trying to base64_encode crap to send via URL RewriteCond %{QUERY_STRING} base64_encode.*(.*) [OR] # Block out any script that includes a <script> tag in URL RewriteCond %{QUERY_STRING} (<|%3C).*script.*(>|%3E) [NC,OR] # Block out any script trying to set a PHP GLOBALS variable via URL RewriteCond %{QUERY_STRING} GLOBALS(=|[|\%[0-9A-Z]{0,2}) [OR] # Block out any script trying to modify a _REQUEST variable via URL RewriteCond %{QUERY_STRING} _REQUEST(=|[|\%[0-9A-Z]{0,2}) # Send all blocked request to homepage with 403 Forbidden error! RewriteRule ^(.*)$ index.php [F,L]

301 Website Redirect


Did you know that search engine crawlers think that 'www.spauldinghill.org' and 'spauldinghill.org' are two different websites!? We need to help the crawlers out and tell them that the two URLs are the same. We can do this with a 301 (moved permanently) redirect. The code below will redirect requests for 'spauldinghill.org' to 'www.spauldinghill.org.
RewriteEngine On RewriteCond %{HTTP_HOST} !^www\.spauldinghill\.org RewriteRule (.*) http://www.spauldinghill.org/$1 [R=301,L]

Turning on Server Side Includes (SSI)


The file paths in this snippet are specific for OS X 10.6.x so if you are running some other kind of Linux base system just do a couple of greps in /etc/apache (/etc/httpd on RHEL systems) to find out which files to edit. Please note that since we like our HTML files to have a .html file extension we enable our server to check every file that is executable. Also the 'ServerAdmin' line has a non-valid email on purpose to avoid spam. First you need to add the include type so Apache knows that .shtml files should be parsed. This should be in your main Apache configuration file so just search for '.shtml' in the file. The lines are usually commented out, so just uncomment them: In the file /private/etc/apache2/httpd.conf #AddType text/html .shtml #AddOutputFilter INCLUDES .shtml just delete the '#'
AddType text/html .shtml AddOutputFilter INCLUDES .shtml

Now we need our server to check all .html files that are executable to see if there are SSI's to execute. This can be done by adding the XBitHack option to your VirtualHost context: In the file /private/etc/apache2/extra/httpd-vhosts.conf
<VirtualHost *:80> ServerAdmin adminspauldinghill.org DocumentRoot "/Sites/Spauldinghill" ServerName spauldinghill-stage ServerAlias spauldinghill-stage XBitHack On </VirtualHost>

While we are in the VirtualHost context we need to enable Includes for the directory where all of our HTML files live.
<VirtualHost *:80> ServerAdmin adminspauldinghill.org

Pg 21 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

DocumentRoot "/Sites/Spauldinghill" ServerName spauldinghill-stage ServerAlias spauldinghill-stage XBitHack On <Directory /Sites/Spauldinghill> Options +Includes </Directory> </VirtualHost>

Now restart apache and see 1998 technology come to life :)


FooBar:~ root# apachectl configtest Syntax OK FooBar:~ root# apachectl restart

Nice urls

# <.htaccess> RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ $1.php [L,QSA] # http://domain/about -> http://domain/about.php # -- or -# <.htaccess> RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php?q=$1 [L,QSA] # http://domain/about -> http://domain/index.php?q=about
Ban a user RewriteEngine on RewriteCond %(HTTP_REFERER) ^http://(www.)?domain_to_ban.com RewriteRule .* http://www.google.com [L] Re-route <VirtualHost *:80> ServerName www.your-domain.com ProxyPreserveHost on ProxyPass /cp http://localhost:5678/cp ProxyPass /db/ http://localhost:5984/ </VirtualHost> or <VirtualHost *:80> ServerName www.your-domain.com RewriteRule ^/(cp|db/|static/|www/)(.*)$ http://localhost:5678/$1$2 [P] <VirtualHost>

Parse HTML files as PHP


URL: http://snippets.dzone.com/posts/show/459 Add this to your .htaccess file in Apache:
AddType application/x-httpd-php .html

End Of Section Pg 22 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

Section 5 Redirecting and Rewriting


"The great thing about mod_rewrite is it gives you all the configurability and flexibility of Sendmail. The downside to mod_rewrite is that it gives you all the configurability and flexibility of Sendmail."
- Brian Behlendorf, Apache Group One of the more powerful tricks of the .htaccess hacker is the ability to rewrite URLs. This enables us to do some mighty manipulations on our links; useful stuff like transforming Very Long URL's into Short, Cute URLs, transforming dynamic ?generated=page&URL's into /friendly/flat/links, redirect missing pages, preventing hot-linking, performing automatic language translation, and much, much more. Make no mistake, mod_rewrite is complex. This isn't the subject for a quick bite-size tech-snack, probably not even a week-end crash-course, I've seen guys pull off some real cute stuff with mod_rewrite, but with kudos-hat tipped firmly towards that bastard operator from hell, Ralf S. Engelschall, author of the magic module itself, I have to admit that a great deal of it still seems so much voodoo to me. The way that rules can work one minute and then seem not to the next, how browser and other inbetween network caches interact with rules and testing rules is often baffling, maddening. When I feel the need to bend my mind completely out of shape, I mess around with mod_rewrite! After all this, it does work, and while I'm not planning on taking that week-end crash-course any time soon, I have picked up a few wee tricks myself, messing around with web servers and web sites, this place.. The plan here is to just drop some neat stuff, examples, things that have proven useful, and work on a variety of server setups; there are Apache's all over my LAN, I keep coming across old .htaccess files stuffed with past rewriting experiments that either worked; and I add them to my list, or failed dismally; and I'm surprised that more often these days, I can see exactly why! Very little here is my own invention. Even the bits I figured out myself were already well documented, I just hadn't understood the documents, or couldn't find them. Sometimes, just looking at the same thing from a different angle can make all the difference, so perhaps this humble stab at URL Rewriting might be of some use. I'm writing it for me, of course. but I do get some credit for this..
# time to get dynamic, see.. RewriteRule (.*)\.htm $1.php

beginning rewriting..
Whenever you use mod_rewrite (the part of Apache that does all this magic), you need to do..
you only need to do this once per .htaccess file: Options +FollowSymlinks RewriteEngine on

..before any ReWrite rules. note: +FollowSymLinks must be enabled for any rules to work, this is a
Pg 23 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

security requirement of the rewrite engine. Normally it's enabled in the root and you shouldn't have to add it, but it doesn't hurt to do so, and I'll insert it into all the examples on this page, just in case*. The next line simply switches on the rewrite engine for that folder. if this directive is in you main .htaccess file, then the ReWrite engine is theoretically enabled for your entire site, but it's wise to always add that line before you write any redirections, anywhere.
* Although highly unlikely, your host may have +FollowSymLinks enabled at the root level, yet disallow its addition in .htaccess; in which case, adding +FollowSymLinks will break your setup (probably a 500 error), so just remove it, and your rules should work fine. Important: While some of the directives on this page may appear split onto two lines in your browser, in your .htaccess file they must exist completely on one line. If you drag-select and copy the directives on this page, they should paste just fine into any text editor.

simple rewriting
Simply put, Apache scans all incoming URL requests, checks for matches in our .htaccess file and rewrites those matching URLs to whatever we specify. something like this..
all requests to whatever.htm will be sent to whatever.php: Options +FollowSymlinks RewriteEngine on RewriteRule ^(.*)\.htm$ $1.php [NC]

Handy for anyone updating a site from static htm (you could use .html, or .htm(.*), .htm?, etc) to dynamic php pages; requests to the old pages are automatically rewritten to our new urls. no one notices a thing, visitors and search engines can access your content either way. leave the rule in; as an added bonus, this enables us to easily split php code and its included html structures into two separate files, a nice idea; makes editing and updating a breeze. The [NC] part at the end means "No Case", or "case-insensitive"; more on the switches, later. Folks can link to whatever.htm or whatever.php, but they always get whatever.php in their browser, and this works even if whatever.htm doesn't exist! But I'm straying.. As it stands, it's a bit tricky; folks will still have whatever.htm in their browser address bar, and will still keep bookmarking your old .htm URL's. Search engines, too, will keep on indexing your links as .htm, some have even argued that serving up the same content from two different places could have you penalized by the search engines. This may or not bother you, but if it does, mod_rewrite can do some more magic..
this will do a "real" external redirection: Options +FollowSymlinks RewriteEngine on RewriteRule ^(.+)\.htm$ http://corz.org/$1.php [R,NC]

This time we instruct mod_rewrite to do a proper external rewrite, aka, "redirection". Now, instead of just background rewriting on-the-fly, the user's browser is physically redirected to a new URI, and whatever.php appears in their browser's address bar - search engines and other spidering entities will automatically update their links to the .php versions; everyone wins. You can take your time with the updating, too. Note: if you use [R] alone, it defaults to sending an HTTP "MOVED TEMPORARILY" redirection, aka, "302". But you can send other codes, like so..
this performs the exact same as the previous example RewriteRule.

Pg 24 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

RewriteRule ^(.+)\.htm$ http://corz.org/$1.php [R=302,NC]

Okay, I sent the exact same code, but I didn't have to. For details of the many 30* response codes you can send, see here. Most people seem to want to send 301, aka, "MOVED PERMENENTLY". Note: if you add an "L" flag to the mix; meaning "Last Rule", e.g. [R=302,NC,L]; Apache will stop processing rules for this request at that point, which may or may not be what you want. Either way, it's useful to know.

not-so-simple rewriting ... flat links and more


You may have noticed, the above examples use regular expression to match variables. What that simply means is.. match the part inside (.+) and use it to construct "$1" in the new URL. In other words, (.+) = $1 you could have multiple (.+) parts and for each, mod_rewrite automatically creates a matching $1, $2, $3, etc, in your target (aka. 'substitution') URL. This facility enables us to do all sorts of tricks, and the most common of those, is the creation of "flat links".. Even a cute short link like http://mysite/grab?file=my.zip is too ugly for some people, and nothing less than a true old-school solid domain/path/flat/link will do. Fortunately, mod_rewrite makes it easy to convert URLs with query strings and multiple variables into exactly this, something like..
a more complex rewrite rule: Options +FollowSymlinks RewriteEngine on RewriteRule ^files/([^/]+)/([^/]+).zip /download.php?section=$1&file=$2 [NC]

would allow you to present this link as.. http://mysite/files/games/hoopy.zip and in the background have that transparently translated, server-side, to.. http://mysite/download.php?section=games&file=hoopy which some script could process. You see, many search engines simply don't follow our ?generated=links, so if you create generating pages, this is useful. However, it's only the dumb search engines that can't handle these kinds of links; we have to ask ourselves.. do we really want to be listed by the dumb search engines? Google will handle a good few parameters in your URL without any problems, and the (hungry hungry) msn-bot stops at nothing to get that page, sometimes again and again and again I personally feel it's the search engines that should strive to keep up with modern web technologies, in other words; we shouldn't have to dumb-down for them. But that's just my opinion. Many users will prefer /files/games/hoopy.zip to /download.php?section=games&file=hoopy but I don't mind either way. As someone pointed out to me recently, presenting links as standard/flat/paths means you're less likely to get folks doing typos in typed URL's, so something like..
an even more complex rewrite rule: Options +FollowSymlinks RewriteEngine on RewriteRule ^blog/([0-9]+)-([a-z]+) http://corz.org/blog/index.php?archive=$1-$2 [NC]

would be a neat trick, enabling anyone to access my blog archives by doing..


Pg 25 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

http://corz.org/blog/2003-nov in their browser, and have it automagically transformed server-side into.. http://corz.org/blog/index.php?archive=2003-nov which corzblog would understand. It's easy to see that with a little imagination, and a basic understanding of posix regular expression, you can perform some highly cool URL manipulations. Here's the basics of regexp (expanded from the Apache mod_rewrite documentation)..

Escaping: \char escape that particular char For instance to specify special characters.. [].()\ etc. Text: . [chars] [^chars] text1|text2 Any single character (on its own = the entire URI) Character class: One of following chars Character class: None of following chars Alternative: text1 or text2 (i.e. "or")

e.g. [^/] matches any character except / (foo|bar)\.html matches foo.html and bar.html Quantifiers: ? 0 or 1 of the preceding text * 0 or N of the preceding text + 1 or N of the preceding text

(hungry)

e.g. (.+)\.html? matches foo.htm and foo.html (foo)?bar\.html matches bar.html and foobar.html Grouping: (text) Grouping of text Either to set the borders of an alternative or for making backreferences where the nthe group can be used on the target of a RewriteRule with $n e.g. Anchors: ^ $ Start of line anchor End of line anchor An anchor explicitly states that the character right next to it MUST ^(.*)\.html foo.php?bar=$1

Pg 26 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

be either the very first character ("^"), or the very last character ("$") of the URI string to match against the pattern, e.g.. ^foo(.*) matches foo and foobar but not eggfoo (.*)l$ matches fool and cool, but not foo

shortening URLs
One common use of mod_rewrite is to shorten URL's. Shorter URL's are easier to remember and, of course, easier to type. An example..
beware the regular expression: Options +FollowSymlinks RewriteEngine On RewriteRule ^grab /public/files/download/download.php

this rule would transform this user's URL.. http://mysite/grab?file=my.zip server-side, into.. http://mysite/public/files/download/download.php?file=my.zip which is a wee trick I use for my distro machine, among other things. everyone likes short URL's, and so will you; using this technique, you can move /public/files/download/ to anywhere else in your site, and all the old links still work fine; simply alter your .htaccess file to reflect the new location. edit one line, done - nice - means even when stuff is way deep in your site you can have cool links like this.. /trueview/sample.php <div> <a href="http://corz.org/trueview/php/sample.php"> /trueview/php/sample.php</a> </div> and this; links which are not only short, but flat..

capturing variables
Slapping (.*) onto the end of the request part of a ReWriteRule is just fine when using a simple $_GET variable, but sometimes you want to do trickier things, like capturing particular variables and converting them into other variables in the target URL. Or something else.. When capturing variables, the first thing you need to know about, is the [QSA] flag, which simply tags all the original variables back onto the end of the target url. This may be all you need, and will happen automatically for simple rewrites. The second thing, is %{QUERY_STRING}, an Apache server string we can capture variables from, using simple RewriteCond (aka. conditional ) statements.
RewriteCond is similar to doing if...then...do in many programming languages. If a certain

condition is true, then do the rewrite that follows.. In the following example, the RewriteCond statement checks that the query string has the foo variable set, and captures its value while it's there. In other words, only requests for /grab that have the variable foo set, will be rewritten, and while we're at it, we'll also switch foo, for bar, just because we can..
capturing a $_GET variable:

Pg 27 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

Options +FollowSymlinks RewriteEngine On RewriteCond %{QUERY_STRING} foo=(.*) RewriteRule ^grab(.*) /page.php?bar=%1

would translate a link/user's request for..


http://domain.com/grab?foo=bar

server-side, into..
http://domain.com/page.php?bar=bar

Which is to say, the user's browser would be fed page.php (without an [R] flag in the RewriteRule, their address bar would still read /grab?foo=bar). The variable bar would be available to your script, with its value set to bar. This variable has been magically created, by simply using a regular ? in the target of the RewriteRule, and tagging on the first captured backreference, %1.. ?bar=%1 Note how we use the % character, to specify variables captured in RewriteCond statements, aka "Backreferences". This is exactly like using $1 to specify numbered backreferences captured in RewriteRule patterns, except for strings captured inside a RewriteCond statement, we use % instead of $. Simple. You can use the [QSA] flag in addition to these query string manipulations, merge them. In the next example, the value of foo becomes the directory in the target URL, and the variable file is magically created. The original query string is then tagged back onto the end of the whole thing..
QSA Overkill! Options +FollowSymlinks RewriteEngine On RewriteCond %{QUERY_STRING} foo=(.+) RewriteRule ^grab/(.*) /%1/index.php?file=$1 [QSA]

So a request for..
http://domain.com/grab/foobar.zip?level=5&foo=bar

is translated, server-side, into..


http://domain.com/bar/index.php?file=foobar.zip&level=5&foo=bar

Depending on your needs, you could even use flat links and dynamic variables together, something like this could be useful..
mixing flat and dynamic links in a single ruleset.. Options +FollowSymlinks RewriteEngine On RewriteCond %{QUERY_STRING} version=(.+) RewriteRule ^grab/([^/]+)/(.*) /%1/index.php?section=$1&file=$2 [QSA]

By the way, you can easily do the opposite, strip a query string from a URL, by simply putting a ? right at the end of the target part. This example does exactly that, whilst leaving the actual URI intact..
just a demo! Options +FollowSymlinks RewriteEngine On

Pg 28 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

RewriteCond %{QUERY_STRING} . RewriteRule foo.php(.*) /foo.php? [L] ?

The RewriteCond statement only allows requests that have something in their query string, to be processed by the RewriteRule, or else we'd end up in that hellish place, dread to all mod_rewriters.. the endless loop. RewriteCond is often used like this; as a safety-net. If all you are after is a /simple/flat/link/ to server-side.php?query=variable translation, use something like this..
a simple flat link with two "path" variables.. Options +FollowSymlinks RewriteEngine On RewriteRule ^/([^/]+)/([^/]+)/? /index.php?first-var=$1&second-var=$2 [QSA]

cooler access denied


In part one I demonstrated a drop-dead simple mechanism for denying access to particular files and folders. The trouble with this is the way our user gets a 403 "Access Denied" error, which is a bit like having a door slammed in your face. Fortunately, mod_rewrite comes to the rescue again and enables us to do less painful things. One method I often employ is to redirect the user to the parent folder..
they go "huh?.. ahhh!" # send them up! Options +FollowSymlinks RewriteEngine on RewriteRule ^(.*)$ ../ [NC]

It works great, though it can be a wee bit tricky with the URLs, and you may prefer to use a harder location, which avoids potential issues in indexed directories, where folks can get in a loop..
they go damn! Oh! # send them exactly there! Options +FollowSymlinks RewriteEngine on RewriteRule ^(.*)$ /comms/hardware/router/ [NC]

Sometimes you'll only want to deny access to most of the files in the directory, but allow access to maybe one or two files, or file types, easy..
deny with style! # users can load only "special.zip", and the css and js files. Options +FollowSymlinks RewriteEngine On RewriteCond %{REQUEST_FILENAME} !^(.+)\.css$ RewriteCond %{REQUEST_FILENAME} !^(.+)\.js$ RewriteCond %{REQUEST_FILENAME} !special.zip$ RewriteRule ^(.+)$ /chat/ [NC]

Here we take the whole thing a stage further. Users can access .css (stylesheet) and Javascript files without problem, and also the file called "special.zip", but requests for any other file types are immediately redirected back up to the main "/chat/" directory. You can add as many types as you need. You could also bundle the filetypes into one line using | (or) syntax, though individual lines are perhaps clearer. Here's what's currently cooking inside my /inc/ directory..
all-in-one control.. RewriteEngine on Options +FollowSymlinks # allow access with no restrictions to local machine at 192.168.1.3

Pg 29 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

RewriteCond %{REMOTE_ADDR} !192.168.1.3 # allow access to all .css and .js in sub-directories.. RewriteCond %{REQUEST_URI} !\.css$ RewriteCond %{REQUEST_URI} !\.js$ # allow access to the files inside img/, but not a directory listing.. RewriteCond %{REQUEST_URI} !img/(.*)\. # allow access to these particular files... RewriteCond %{REQUEST_URI} !comments.php$ RewriteCond %{REQUEST_URI} !corzmail.php$ RewriteCond %{REQUEST_URI} !digitrack.php$ RewriteCond %{REQUEST_URI} !gd-verify.php$ RewriteCond %{REQUEST_URI} !post-dumper.php$ RewriteCond %{REQUEST_URI} !print.php$ RewriteCond %{REQUEST_URI} !source-dump.php$ RewriteCond %{REQUEST_URI} !textview.php$ RewriteRule ^(.*)$ / [R,NC,L]

Ban User Agents, referrers, script-kiddies and more..


There are many valid reasons to ban a particular request from sucking up your site's resources; resources that could be better served to valid, interested users. It might be some cross-site attack script, or inward link from a place you don't want to be associated with, or perhaps a web sucker or download manager, whatever; .htaccess + mod_rewrite provides ways to protect your content from unwanted "guests". The basic formula is standard if-then logic: if the request meets a particular CONDITION, then REWRITE the request. The "conditions" can be many things; perhaps the referrer header sent by their browser (the site they came from), or the page they asked for, or a particular query parameter, or the type of client (browser, etc.) they are using, or any other piece of information Apache has attached to the request. Here's an example which will deny access to "Teleport Pro", a download manager which is known to suck, hard..
Who need's a local copy, when I'm right here?.. RewriteCond %{HTTP_USER_AGENT} ^Teleport\ Pro [NC] RewriteRule . abuse.txt [L]

It's your site, and just like your home, you have every right to exert some control over who gets in. You may have a huge list of user agents you'd rather not have eating your bandwidth; so use the [OR] flag, and line 'em up..
A little garlic for the net vampires.. RewriteCond %{HTTP_USER_AGENT} RewriteCond %{HTTP_USER_AGENT} RewriteCond %{HTTP_USER_AGENT} RewriteCond %{HTTP_USER_AGENT} RewriteCond %{HTTP_USER_AGENT} # etc.. RewriteCond %{HTTP_USER_AGENT} RewriteRule . abuse.txt [L] ^BackWeb [NC,OR] ^Bandit [NC,OR] ^BatchFTP [NC,OR] ^BecomeBot [NC,OR] ^BlackWidow [NC,OR] ^Net\ Vampire [NC]

This forms the basis of what often becomes a HUGE list of ban-lines. Remember, we aren't limited to user agent strings..
Suckers, h4x0rz, kiddies, cross-site scripters and more.. Bye now! # why not come visit me directly? RewriteCond %{HTTP_REFERER} \.opendirviewer\. [NC,OR] # this prevents stoopid cross-site discovery attacks.. RewriteCond %{THE_REQUEST} \?\ HTTP/ [NC,OR] # please stop pretending to be the Googlebot.. RewriteCond %{HTTP_REFERER} users\.skynet\.be.* [NC,OR] # really, we need a special page for these twats.. RewriteCond %{QUERY_STRING} \=\|w\| [NC,OR] RewriteCond %{THE_REQUEST} etc/passwd [NC,OR] RewriteCond %{REQUEST_URI} owssvr\.dll [NC,OR] # you can probably work these out..

Pg 30 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

RewriteCond RewriteCond # etc.. RewriteCond RewriteRule

%{QUERY_STRING} \=\|w\| [NC,OR] %{THE_REQUEST} \/\*\ HTTP/ [NC,OR] %{HTTP_USER_AGENT} Sucker [NC] . abuse.txt [L]

Fortunately, mod_rewrite can parse enormous lists of ban-lines in milliseconds, so feel free to be as specific and comprehensive as required. As ever, thorough testing is strongly recommended. Simply send requests matching your conditions and see what happens. And importantly; normal requests, too. Firefox, Opera, Konqueror, and most other decent browsers, allow you to alter the user agent string; though you would quickly find the process tedious in a testing situation. Far better to use some tool better designed to send fake HTTP requests.. It's not too difficult to mock up a web request on the command-line with any-old user agent using a scripting language like php or Perl, if you have these things available (read: most Linux/UNIX/BSD/etc. as well as many other OS). Many examples exist online. In fact, you could quickly create a suite of tests, designed to interrogate all your rewrite rules, with results logging and much more, if required. cURL is always useful for jobs like this, so long as you don't add a cURL banline! On a Windows desktop, Sam Spade can send a single spoofed request with a couple of clicks, along with a stack of similarly handy tricks, and regularly proves itself invaluable.

Don't let just anyone hammer your site!


While I'm on the subject of abusive web clients, you will probably have noticed that many clients (bots, spiders, automated suckers and such) like to disguise their user agent information, in fact any information, in an attempt to bring your site to its knees, hammering your pages umpteen times per second in the process. Not good. If you are interested in a way to defeat hammering web clients regardless of who they pretend to be or whether or not they accept cookies or any such malarkey, protecting your valuable server resources for genuine clients, check out: Anti-Hammer. It's free.

prevent hot-linking
Believe it or not, there are some webmasters who, rather than coming up with their own content will steal yours. Really! Even worse, they won't even bother to copy to their own server to serve it up, they'll just link to your content! no, it's true, in fact, it used to be incredibly common. These days most people like to prevent this sort of thing, and .htaccess is one of the best ways to do it. This is one of those directives where the mileage variables are at their limits, but something like this works fine for me..
how DARE they! Options +FollowSymlinks # no hot-linking RewriteEngine On RewriteCond %{HTTP_REFERER} !^$ RewriteCond %{HTTP_REFERER} !^http://(www\.)?corz\.org/ [NC] RewriteCond %{REQUEST_URI} !hotlink\.(gif|png) [NC] RewriteRule .*\.(gif|jpg|png)$ http://corz.org/img/hotlink.png [NC] <div> <a

Pg 31 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

href="http://corz.org/img/hotlink.png" title="(opens in a new window - apple-click (shift-click on peecees) for a new tab instead)"> http://corz.org/img/hotlink.png</a> [NC]<br /> </div>

You may see the last line broken into two, but it's all one line (all the directives on this page are). Let's have a wee look at what it does.. We begin by enabling the rewrite engine, as always. The first RewriteCond line allows direct requests (not from other pages - an "empty referrer") to pass unmolested. The next line means; if the browser did send a referrer header, and the word "corz.org" is not in the domain part of it, then DO rewrite this request. The all-important final RewriteRule line instructs mod_rewrite to rewrite all matched requests (anything without "corz.org" in its referrer) asking for gifs, jpegs, or pngs, to an alternative image. There are loads of ways you can write this rule; Google for "hot-link protection" and get a whole heap. Simple is best. You could send a wee message instead, or direct them to some evil script, or something. Mine is a simple corz.org logo, which I think is rather clever. Actually, these days, I do something even cleverer-er..

lose the "www"


I'm often asked how I prevent the "www" part showing up at my site, so I guess I should add something about that. Briefly, if someone types http://www.corz.org/ into their browser (or uses the www part for any link at corz.org) it is redirected to the plain, rather neat, http://corz.org/ version. This is easy to achieve, like so..
beware the regular expression: Options +FollowSymlinks RewriteEngine on RewriteCond %{http_host} ^www\.corz\.org [NC] RewriteRule ^(.*)$ http://corz.org/$1 [R=301,NC]

You don't need to be touched by genius to see what's going on here. There are other ways you could write this rule, but again, simple is best. Like most of the examples here, the above is pasted directly from my own main .htaccess file, so you can be sure it works perfectly. In fact, I recently updated it so that I could share rules between my dev mirror and live site without any .htaccess editing..
here's what I'm currently using: Options +FollowSymlinks RewriteEngine on RewriteCond %{HTTP_HOST} ^www\.(.*) [NC] RewriteRule ^(.*)$ http://%1/$1 [R=301,NC,L]

multiple domains in one root


If you are in the unfortunate position of having your sites living on a host that doesn't support multiple domains, you may be forced to roll your own with .htaccess and mod_rewrite. So long as your physical directory structure is well thought-out, this is fairly simple to achieve. For example, let's say we have two domains, pointing at a single hosted root; domain-one.com and domain-two.com. In our web server root, we simply create a folder for each domain, perhaps one/, and two/ then in our main (root) .htaccess, rewrite all incoming requests, like this..
Pg 32 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

All requests NOT already rewritten into these folders, transparently rewrite..

#two domains served from one root.. RewriteCond %{HTTP_HOST} domain-one.com RewriteCond %{REQUEST_URI} !^/one RewriteRule ^(.*)$ one/$1 [L] RewriteCond %{HTTP_HOST} domain-two.com RewriteCond %{REQUEST_URI} !^two RewriteRule ^(.*)$ two/$1 [L]

All requests for the host domain-one.com are rewritten (not R=redirected) to the one/ directory, so long as they haven't already been rewritten there (the second RewriteCond). Same story for domain-two.com. Note the inconsistency in the RewriteCond statement; !^/dir-name and !^dirname should both work fine. But needless to say, if you get a 500 error on your server, that would be a good place to start looking! Also note, with such a simple domain & folder naming scheme, you could easily merge these two rule sets together. This would be unlikely in the real world though, which is why I left them separate; but still, worth noting. Other general settings and php directives can also go in this root .htaccess file, though if you have any further rewrite you'd like to perform; short URL's, htm to php conversion and what-not; it's probably easier and clearer to do those inside the sub-directory's .htaccess files.

automatic translation
If you don't read English, or some of your guests don't, here's a neat way to have the wonderful Google translator provide automatic on-the-fly translation for your site's pages. Something like this..
they simply add their country code to the end of the link, or you do.. Options +FollowSymlinks RewriteEngine on RewriteRule ^(.*)-fr$ http://www.google.com/translate_c?hl=fr&sl=en&u=http://corz.org/$1 RewriteRule ^(.*)-de$ http://www.google.com/translate_c?hl=de&sl=en&u=http://corz.org/$1 RewriteRule ^(.*)-es$ http://www.google.com/translate_c?hl=es&sl=en&u=http://corz.org/$1 RewriteRule ^(.*)-it$ http://www.google.com/translate_c?hl=it&sl=en&u=http://corz.org/$1 RewriteRule ^(.*)-pt$ http://www.google.com/translate_c?hl=pt&sl=en&u=http://corz.org/$1

[R,NC] [R,NC] [R,NC] [R,NC] [R,NC]

You can create your menu with its flags or whatever you like, and add the country code to end of the links.. <a href="page.html-fr" id="... Want to see this page in French? Although it is handy, and I've been using it here for a couple of years here at the org for my international blog readers, all two of them, heh. Almost no one knows about it, mainly because I don't have any links . One day I'll probably do a wee toolbar with flags and what-not. Perhaps not. Trouble is, the Google translator stops translating after a certain amount of characters (which seems to be increasing, good), though these same rules could easily be applied to other translators, and if you find a good one, one that will translate a really huge document on-the-fly, do let me know! If you wanted to be really clever, you could even perform some some kind of IP block check and present the correct version automatically, but that is outside the scope of this document. note: this may be undesirable for pages where technical commands are given (like this page) because the commands will also be translated. "RewriteEngine dessus" will almost certainly get you a 500 error page!
Pg 33 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

Another thing you might like to try; rather than individual country flags; fr, de, etc., use the "u" flag, for "Universal". In theory, Google will check the client's location, and automatically translate to that language. One line in your .htaccess would cover all languages, and automatically cover new ones as Google adds them. While I'm here, slightly related; you can do a similar thing browser-side, create a "bookmarklet" (a regular bookmark, except that it "does something"), using this code for the location..
the same sort of thing, except browser-side.. javascript:void(location.href='http://translate.google.com/translate?u='+location.href)

..which you will instinctively learn to click at the merest whiff of unrecognizable text, I reckon. Put it in your toolbar somewhere visible, is my sincere recommendation.

httpd.conf
Remember, if you put these rules in the main server conf file (usually httpd.conf) rather than an .htaccess file, you'll need to use ^/... ... instead of ^... ... at the beginning of the RewriteRule line, in other words, add a slash.

inheritance..
If you are creating rules in sub-folders of your site, you need to read this. You'll remember how rules in top folders apply to all the folders inside those folders too. we call this "inheritance". normally this just works. but if you start creating other rules inside subfolders you will, in effect, obliterate the rules already applying to that folder due to inheritance, or "decendancy", if you prefer. not all the rules, just the ones applying to that subfolder. a wee demonstration.. Let's say I have a rule in my main /.htaccess which redirected requests for files ending .htm to their .php equivalent, just like the example at the top of this very page. now, if for any reason I need to add some rewrite rules to my /osx/.htaccess file, the .htm >> .php redirection will no longer work for the /osx/ subfolder, I'll need to reinsert it, but with a crucial difference..
this works fine, site-wide, in my main .htaccess file # main (top-level) .htaccess file.. # requests to file.htm goto file.php Options +FollowSymlinks RewriteEngine on RewriteRule ^(.*)\.htm$ http://corz.org/$1.php [R=301,NC]

Here's my updated /osx/.htaccess file, with the .htm >> .php redirection rule reinserted..
but I'll need to reinsert the rules for it to work in this sub-folder # /osx/.htaccess file.. Options +FollowSymlinks RewriteEngine on RewriteRule some rule that I need here RewriteRule some other rule I need here RewriteRule ^(.*)\.htm$ http://corz.org/osx/$1.php [R=301,NC]

Spot the difference in the subfolder rule, highlighted in red. you must add the current path to the new rule. now it works again, and all the osx/ subfolders will be covered by the new rule. if you remember this, you can go replicating rewrite rules all over the place.

Pg 34 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

If it's possible to put your entire site's rewrite rules into the main .htaccess file, and it probably is; do that, instead, like this..
it's a good idea to put all your rules in your main .htaccess file.. # root /.htaccess file.. Options +FollowSymlinks RewriteEngine on # .htm >> .php is now be covered by our main rule, there's no need to repeat it. # But if we do need some /osx/-specific rule, we can do something like this.. RewriteRule ^osx/(.*)\.foo$ /osx/$1.bar [R=301,NC]

Note, no full URL (with domain) in the second example. Don't let this throw you; with or without is functionally identical, on most servers. Essentially, try it without the full URL first, and if that doesn't work, sigh, and add it - maybe on your next host! The latter, simpler form is preferable, if only for its tremendous portability it offers - my live site, and my development mirror share the exact same .htaccess files - a highly desirable thing. By the way, it perhaps doesn't go without saying that if you want to disable rewriting inside a particular subfolder, where it is enabled further up the tree, simply do:
handy for avatar folders, to allow hot-linking, etc.. RewriteEngine off

cookies
Lastly, a quick word about cookies. While it's easy enough to set cookies in .htaccess without any mod_rewrite..
create a cookie called "example-cookie", and set its value to "true".. Header set Set-Cookie "example-cookie=true"

..you will need it to read the cookie information back again, and "do stuff" with it. It's easy. For example, to check if the above cookie exists and has the correct value set, we could simply do..
check for that same cookie + value.. Options +FollowSymlinks RewriteEngine on RewriteCond %{HTTP_COOKIE} !example-cookie=true RewriteRule .* /err/401.php

..which could easily form the basis of a simple authentication system. As with any RewriteCond, you can get pretty complex, checking multiple cookies, utilizing regexp and more, but that's enough to get you started. You will probably want to add another RewriteCond to prevent looping on the 401. I'll leave that as an exercise.

While I'm at it, note, you can also set cookies with a RewriteRule. Check this..
Set a cookie with this visitor's "Original Referer", using RewriteRule.. SetEnvIf Referer "^https?://(.*)/" myref=$1 RewriteCond %{HTTP_REFERER} !^$ RewriteCond %{HTTP_REFERER} !corz.org [NC] RewriteRule . - [cookie=original-referer:%{ENV:myref}:.%{HTTP_HOST}:1440:/]

The first line checks the value of the "Referer" header (usually sent by the browser - by the way, the
Pg 35 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

misspelling of "referrer" annoys a lot of people, but its hard-coded into the web now) Let's say the referring URI is "http://corz.org/blog/", which matches (of course it matches, all Referers will match!) so the part between "https?://" and the next occurring slash ("/") of the referring URI is captured inside the braces () and then backreferenced (by the use of "$1", 1 = the first captured string, in this case "corz.org"), that value being stored in an Environment Variable (Apache has loads of them created on every request, your IP address, browser type, time of the request, remote port, loads...) named "myref". In other words: myref=corz.org You might be asking, "Why not simply use SetEnvIf Referer (.*) myref=$1 to capture the entire referer string?". The reason is because the captured colon (":"), when expanded with %{ENV:myref} construct, will split the cookie statement in the wrong place, ":" being the delimiter. It's a bit bug-like, but predictable. You can take the risk and try and capture everything after the domain (using SetEnvIf Referer "^https?://(.*)" myref=$1), if there is no colon in the URI, it will work fine, capturing query strings and all. Then we do a couple of RewriteCond conditions, the first to prevent "empty" referers (where no referer information is sent) and the second to prevent resetting the cookie with the name of our own domain*. Then it's down to business.. * If you are wondering, "Why not use %{HTTP_HOST} instead of corz.org, create universal code?", as far as I know, it's not possible to test one server variable against another with a RewriteCond without using Atomic Back References and some serious POSIX 1003.2+ Jiggery-Pokery. It's generally best to hard-code in the domain name. Anyway.. The RewriteRule, its simple dot "." expression, again matching every single request, passing the request straight through (to any remaining .htaccess code, by use of the "-") without altering the URI in any way, and while it's at it sets the browser's cookie variable "original-referer" to the value of the Apache variable "myref", which is currently "corz.org", accessing this variable by use of the "%{ENV:<Name-of-Environment-Variable>}" construct. The domain of the cookie is set to "corz.org". Note, it's best practice to use a preceding dot in "www"-less, or other sub-less domains). The cookie will expire in approximately 1440 minutes (24 hours). The cookie "path" is set to "/", covering the entire site. Job done. Finally, having said ALL that, I'd still much rather use PHP sessions wherever possible, and if taking a chance on something more permanent, with a persistent cookie, php (or similar) is still a better place to be coding this sort of stuff.

conclusion
In short, mod_rewrite enables you to send browsers from anywhere to anywhere. You can create rules based not simply on the requested URL, but also on such things as IP address, browser agent (send old browsers to different pages, for instance), and even the time of day; the possibilities are practically limitless.
Pg 36 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

The ins-and outs of mod_rewrite syntax are topic for a much longer document than this, and if you fancy experimenting with more advanced rewriting rules, I urge you to check out the Apache documentation.

If you have Apache installed on your system.. there will likely be a copy of the Apache manual,
right here, and the excellent mod_rewriting guide, lives right here. do check out the URL Rewriting Engine notes for the juicy syntax bits. That's where I got the cute quote for the top of the page, too. ;o) Cor

Pg 37 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

Section 6 Troubleshooting Tips


Fatal Redirection
If you start messing around with 301 redirects [R=301], aka. "Permanently Redirected", and your rule isn't working, you could give yourself some serious headaches.. Once the browser has been redirected permanently to the wrong address, if you then go on to alter the wonky rule, your browser will still be redirected to the old address (because it's a browser thing), and you may even go on to fix, and then break the rule all over again without ever knowing it. Changes to 301 redirects can take a long time to show up in your browser. Solution: restart your browser, or use a different one. Better Solution: Use [R] instead of [R=301] while you are testing . When you are 100% certain the rule does exactly as it's expected to, then switch it to [R=301] for your live site.

rewrite logging..
When things aren't working, you may want to enable rewrite logging. I'll assume you are testing these mod_rewrite directives on your development mirror, or similar setup, and can access the main httpd.conf file. If not, why not? Testing mod_rewrite rules on your live domain isn't exactly ideal, is it? Anyway, put this somewhere at the foot of your http.conf..
Expect large log files.. # # ONLY FOR TESTING REWRITE RULES!!!!! # RewriteLog "/tmp/rewrite.log" #RewriteLogLevel 9 RewriteLogLevel 5

Set the file location and logging level to suit your own requirements. If your rule is causing your Apache to loop, load the page, immediately hit your browser's "STOP" button, and then restart Apache. All within a couple of seconds. Your rewrite log will be full of all your diagnostic information, and your server will carry on as before. Setting a value of 1 gets you almost no information, setting the log level to 9 gets you GIGABYTES! So you must remember to comment out these rules and restart Apache when you are finished because, not only will rewrite logging create space-eating files, it will seriously impact your web server's performance.
RewriteLogLevel 5 is very useful, but 2 is probably enough information for most issues. debug-report.php A php script to make your mod_rewrite life easier.

When things aren't working as you would expect, rewrite logging is a good option, but on a hosted server, you probably won't have that option, without access to httpd.conf. Fortunately, what's usually required is no more than a quick readout of all the current server variables, $_GET array, and so on; so you can see exactly what happened to the request. For another purpose, I long ago created debug.php, and later, finding all this information useful in
Pg 38 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

chasing down wonky rewrites, created a "report" version, which rather than output to a file, spits the information straight back into your browser, as well as $_POST, $_SESSION, and $_SERVER arrays, special variables, like __FILE__, and much more. Usage is simple; you make it your target page, so in a rule like this..
RewriteRule ^(.*)\.html$ /catch-all.php?var=$1

You would have a copy of debug-report.php temporarily renamed to catch-all.php in the root of your server, and type http://testdomain.org/foobar.html into your address bar and, with yer mojo working, debug-report.php leaps into your browser with a shit-load of exactly the sort of information you need to figure out all this stuff. When I'm messing with mod_rewrite, debugreport.php saves me time, a lot. It's way faster than enabling rewrite logging, too. Also, it's free..

debug-report.php
<?php /*

debug-report.php
$du_version = '0.4.5r'; // TUE Aug 23, 2005 corz.org debug unit instant report version (aka "du")

This version stores nothing, doesn't care about outside variables, simply displays the report in the browser. you can get debug.php to do this by passing ?output=true but this version is useful in situations where passing extra variables is not possible or not desirable. it's handy anyhow. for more details see debug.php ;o) (or (c) corz.org 2003 -> */ // handy here for when duplicating into subfolders for test // change indicates which subfolder - handy for mod_rewrite tests.. // $title = 'debug report..@ '; // check session capabilities.. // multiple refreshes of page will increase the counter.. //ini_set ('session.name', 'debug'); @session_start(); $time = array_sum(explode(' ', microtime(true))); // check the title bar when ?output=true if (!isset($_SESSION['debug'])) { $_SESSION['debug'] = '0'; } else { $_SESSION['debug']++; }

Pg 39 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

// basic cookie test (should run 1 behind the view counter) if (isset($_COOKIE['debug_cookie'])) { $foo = (integer) $_COOKIE['debug_cookie']; $foo++; setcookie ('debug_cookie', $foo, time() + (60*60*24));// i day } else { setcookie ('debug_cookie', '0', time() + (60*60*24)); } // some example debugging lines. // keeping the debug lines hard left makes them easy to find..//:debug: debug("\n".$title.$time."\n\n");//:debug: // some path info.. debug('HTTP_HOST:'.$_SERVER['HTTP_HOST']."\n");//:debug: debug('SCRIPT_NAME:'.$_SERVER['SCRIPT_NAME']."\n");//:debug: debug('SCRIPT_NAME: (realpath)'.realpath($_SERVER['SCRIPT_NAME'])."\n\n");//:debug: debug('SCRIPT_FILENAME:'.$_SERVER['SCRIPT_FILENAME']."\n");//:debug: debug('SCRIPT_FILENAME (realpath)'.realpath($_SERVER['SCRIPT_FILENAME'])."\n\n");//:debug: debug('PHP_SELF:'.$_SERVER['PHP_SELF']."\n");//:debug: debug('PHP_SELF (realpath)'.realpath($_SERVER['PHP_SELF'])."\n\n");//:debug: debug('__FILE__:'.__FILE__."\n");//:debug: debug('__FILE__ (realpath)'.realpath(__FILE__)."\n\n");//:debug: debug('$main page path (fixed): '.substr($_SERVER['SCRIPT_FILENAME'], 0, (strrpos($_SERVER['SCRIPT_FILENAME'],'/') + 1))."\n\n");//:debug: debug('path from site root: '.substr($_SERVER['SCRIPT_NAME'],0,(strrpos($_SERVER['SCRIPT_NAME'],'/')+1))."\n\n");//:debug: debug('this file path (fixed): '.str_replace( "\\\\", "/", dirname( __FILE__ ) . "/" )."\n\n");//:debug: // $HTTP_SERVER_VARS.. debug("\n\n".'$_SERVER variables..'."\n\n");//:debug: while (list($key, $val) = each($_SERVER)) {//:debug: debug($key.chr(9).$val."\n"); }//:debug: if (is_array($HTTP_ENV_VARS)) { debug("\nenvironment variables..\n\n");//:debug: while (list($key, $val) = each($HTTP_ENV_VARS)) {//:debug: debug($key.chr(9).$val."\n"); }//:debug: } if (is_array($HTTP_COOKIE_VARS)) { debug("\ncookie variables..\n\n");//:debug: while (list($key, $val) = each($HTTP_COOKIE_VARS)) {//:debug: debug($key.chr(9).$val."\n"); }//:debug: } debug("\n\nrequest variables..\n");//:debug: debug("\n".'$_GET: '."\t".print_r($_GET, true)."\n\n");//:debug: debug("\n".'$_POST: '."\t".print_r($_POST, true)."\n\n\n");//:debug: debug("\n".'$_REQUEST: '."\t".print_r($_REQUEST, true)."\n\n");//:debug: debug("\n".'$_SESSION: '."\t".print_r($_SESSION, true)."\n");//:debug: debug("\n".'$GLOBALS: '."\t".print_r($GLOBALS, true)."\n");//:debug: debug("\n\n");//:debug: // final output debug('out');//:debug: echo ' <html><head><title>',$title,' - corz debug unit v',$du_version,' .. viewed ',@$_SESSION['debug'],' times [cookie increment: ',@$_COOKIE['debug_cookie'],']</title></head><body> <pre>',$debug_string,'</pre></body>';

Pg 40 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

/* function:debug() */ function debug($data) { global $debug_string; $debug_string .= $data; }/* end function debug() */ ?>

Pg 41 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

Notes ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________
Pg 42 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

Notes ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________
Pg 43 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

Notes ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________
Pg 44 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

Back Page

Documenation
http://www.thejackol.com/htaccess-cheatsheet/ http://www.htaccesseditor.com/en.shtml

Tutorials
http://httpd.apache.org/docs/current/howto/htaccess.html http://www.freewebmasterhelp.com/tutorials/htaccess/ http://corz.org/serv/tricks/

References
http://www.javascriptkit.com/howto/htaccess.shtml http://www.htaccesstools.com/ http://corz.org/serv/tricks/htaccess.php

Pg 45 of 45 By: Jan Zumwalt - NeatInfo.com Apache / Htaccess Reference May 15, 2012 Copyright 2005-2012

You might also like