Extending Rules
You should be happy with the RewriteRule command, and if not please go back to part one. What about rewriting depending on referrer, query string, IP address, whether or not the file exists? We can do this and more by extending our rules using the RewriteCond directive.
STRING must be a server variable or a backreference from previous a RewriteCond. Backreferences work as described in mod_rewrite part one - except a backreference from a RewriteCond takes the form %N whereas it is $1 if from a RewriteRule.
CONDITION can be another regular expression, similar to a RewriteRule. Additionally, it can take special variants of the normal regular expression pattern. We will come to those later.
How does this fit into our RewriteRule? If you place a RewriteCond before a RewriteRule, the RewriteRule will only be processed if the RewriteCond evaluates to true, i.e. if the condition is met.
Enough with the theory, let\'s do something practical. Imagine you wish to prevent a certain IP address from accessing your server:
RewriteRule .* you-are-banned.html [R]
A simple example to start with. If your IP is 123.45.67.89, we show the user a "you are banned" HTML page.
Server variables are accessible through %{VAR_NAME}. Some of the most useful ones are below:
HTTP_USER_AGENT | This is the client being used to access your server. You can use this to identify the browser being used and show different content accordingly. It also allows you to block certain unfriendly bots from your server. |
HTTP_REFERER | The referring page as sent by the browser. Note that this data is unreliable and can easily be modified by the user. You can use this variable to prevent hotlinking. |
HTTP_HOST | The current hostname. Possible values include domain.com, www.domain.com, sub.domain.com, an IP address or even your localhost. |
SERVER_PORT | The current port. This value is 80 for http, 443 for https (ssl). Useful for redirecting users to force them onto the secure connection. |
REMOTE_ADDR | The remote address of the user, also known as the IP. This allows you to block harmful bots or users. |
SCRIPT_FILENAME | The name of the requested file. This is the value that would be matched against the pattern of the RewriteRule. |
QUERY_STRING | This string contains all the GET data for the request. In other words, everything after the ? in the URL. For example, the QUERY_STRING variable for a request for file.php?foo=bar&pie=good will be \'foo=bar&pie=good\' |
REQUEST_URI | The requested URI, a combination of the SCRIPT_FILENAME followed by the QUERY_STRING if there is one. |
Tip: If you want to check the contents of these variables, again you can use the phpinfo() function.
A number of the more practical uses are included in the examples menu.
Remember I mentioned special variants of the regular expressions for use as the CONDITION in a RewriteCond? Let's use another example - you want to use a nice CMS that requires every page to run through the index.php script. Already you can come up with:
We are halfway there but not quite. What if we want to get to an image, or a CSS file? In theory, we can setup our index script to output the relevant file but that is a rather long way round. Ideally, we would tell mod_rewrite to rewrite all requests to the index script unless the requested file (or directory) exists. And that we can do:
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteRule (.*) index.php?page=$1 [QSA,L]
This introduces a few new concepts, most strikingly we have two RewriteCond lines. You can use as many RewriteCond directives as you wish and the RewriteRule that follows will only be processed if all conditions are met.
If you wish to have your RewriteRule apply if just one or more conditions are met, you can override the default AND requirement of multiple conditions by using the OR flag. Exactly like a RewriteRule, flags are contained in square brackets at the end of the line. The other useful flag for a RewriteCond is again, the case insensitive NC.
Secondly, we use ! to negate the condition. We have not covered the meaning of -f yet, although you may have already guessed, so we will use another example. A condition of \.(gif|jpg|png)$ will match anything ending in an image extension. If we want to exlude images from the rewrite, we can use a condition or pattern of !\.(gif|jpg|png)$ that will only be met if its not an image (assuming comparison with STRING containing the SCRIPT_FILENAME).
And thirdly, we check if the request is an existing file or directory using -f and -d. These are the two most useful variants - once again, check the documentation for the rest.
Conclusion
So there you have it. Be sure to read through the rest of the mod_rewrite pages - we have a number of code examples and useful notes to take a look at. If you still have problems, you can setup a RewriteLog to see what the module is attempting. Thanks for reading and good luck!