File Structure
Structuring your files should be done in such a way that all the files are easy to get to. Here’s an example of the layout I would regularly use to structure my files.

Generally speaking, files and folders should be in lower case to allow for better usability. It’s often useful to put stuff like your CSS, Images and Javascript in separate folders just so they’re easier to find. Separate files are fine to leave in the base directory.
Most of the time though, you’re not going to be using a static website, and often your website will utilize PHP in some form or another. PHP and MySQL give you a lot more freedom when it comes to your website, and the content in it. For instance, in the image above you’ll notice that there’s a folder called tutorials, where one would probably want to put tutorials. Instead of doing this however, we could have a single file in the base directory called tutorial.php. The innards of tutorials.php would look something like this:
The PHP
<?php
/* Connection to the MySQL Database */
mysql_connect("localhost", "admin", "") or die(mysql_error());
mysql_select_db("test") or die(mysql_error());
/* Checks for the ?id= part in the url */
if($_GET['id']) {
/* Put the ID in a variable */
$id = (int)$_GET['id'];
/* Run a MySQL Query to get the row with that id */
$query = mysql_query("SELECT * FROM tutorials WHERE id = '".$id."'") or die(mysql_error());
/* Put the query into an array */
while($row = mysql_fetch_array($query)) {
/* Show the contents and name of that array */
echo"<strong>".$row['name']."</strong><br />";
echo $row['content'];
}
}
?>
The table I’m using in this database can be created with this simple little code:
The MySQL
CREATE TABLE `tutorials` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(45) NOT NULL,
`content` LONGTEXT NOT NULL,
PRIMARY KEY (`id`)
)
So now rather than creating separate file every time you write a tutorial, you can just put it all in this table (most web hosting plans come with some way to alter databases and tables), or you could set up a system to submit data to the table. Similarly, you could have ?id=1&category=2 by altering the code slightly, and checking for $_GET['category']
Now this may all seem rather spiffy, but search engines don’t like the whole “?id=” bit at the end of the URL. It leaves them bewildered and wondering what exactly you’re trying to say. This is bad, because we all know how important search traffic can be to websites.
.htaccess can fix that
To use .htaccess, make a file in the directory that tutorials.php is in, called, well, .htaccess. .htaccess is a way for us to override default settings and change stuff around as we see fit (on a directory level). We’re going to use a method called mod_rewrite, which basically modifies and rewrites the urls, so they’ll work in different places. To change what we had (i.e. tutorials.php?id=1) into what we want (tutorials/1) we would do the following:
RewriteEngine On
RewriteRule ^tutorials/([0-9]+)$ tutorials.php?id=$1
First of all, we turn on the rewrite engine as it were, by saying RewriteEngine On. We then define a RewriteRule, which is basically a rule that will be put in place and happen every time a user goes to a certain URL. Think of the rewrite rule with this syntax:
RewriteRule ^oldfile.htm$ newfile.htm
oldfile.htm will be rewritten to newfile.htm, so when the user goes to oldfile.htm they will be presented with newfile.htm. This is just a basic example to show you how it works. You’ll notice a ^ sign and a $ sign. The ^ represents the start of the pattern you’re looking to rewrite to. The dollar sign denotes the end of this, and the bit after that is what you’re trying to change.
You’ll notice in the original example we have ([0-9]+). This is called regular expression or regex. It basically is a holder for any number. The [0-9] bit says that this is supposed to be a number, and the + means it can be any amount of numbers, i.e. 10000. Similarly you could have [a-z] for a lower case letter.
Another thing you may notice is the $1 in the bit after the dollar sign. The $1 refers back to the regex we used in the bit before the dollar sign. In other words, if the original url was tutorials.php?id=1, then the rewritten url would become tutorials/1. Similarly if you had a url like this: tutorials.php?id=1&cat=5&order=asc, you could have a url like tutorials/1/5/asc by using $1, $2 and $3 where $1 is 1, $2 is 5 and $3 is asc.
Flags
Flags allow you to add a direction to your rewrite rules. In other words, they allow you to add a bit more instruction to what you’re doing. Flags are just added to the end of your rewrite rule like so:
RewriteRule ^old.htm$ new.htm [L]
Examples of Common Flags
- [L] which stands for Last. As soon as this is read, no following rules are processed (if the rule is used that is).
- [R] which stands for Redirect. You can accompany this with a number for instance:[R=301] Permanently Moved; [R=302] Temporarily Moved. 302 is the default.
- [F] which stands for Forbidden. Any rule with this on the end will return a 403 Error when you go to that file/directory.
- [NC] which stands for No Case. This means instead of doing [a-zA-Z] when you want to check for both cases you can just add [NC] to the end.
- [QSA] stands for Query String Append. In other words, the query string (bit after ?) in the original string will be appended to the end of the rewritten URL.
- [S] stands for Skip. You can set it to skip the next number of x rules by doing this: [S=x]
- Multiple flags are seperated by a comma, i.e. [NC,L].
Regex in Action
So if you wanna be a pro when it comes to regex, you’re gonna need to know how to use some of the following operators:
- [] Square brackets group together sets of characters that can be mixed in any way.
- () Brackets are a way to create a variable
- . Dots mean any character
- ^ Circumflex in Regex means not, so
[^a-z] means not any letter a-z
- \s is whitespace
- ? means zero or one of the preceding element
- * means zero or more of the preceding element
- + means one or more of the preceding element
Examples of this
Here are a bunch of examples to help you get your head around this
- If you wanted any mix of letters and numbers you would use
([a-zA-Z0-9]+).
- If you wanted any combination of letters and a number you would do
([A-Za-z]+[0-9]).
- If you want any letter you would do
(.*)
- If you want to select any letter abc multiple times you would do
([abc]+
- Similarly it’s possible to check for characters and letters, and store each as separate variables, i.e.
([a-zA-Z]+)([0-9]+)
Rewrite Conditions
I thought it would be a good idea to put a short bit on rewrite conditions in here too. The Syntax for rewrite conditions is as follows:
RewriteCond string condition
RewriteCond is useful, since if it’s before a RewriteRule, that Rewrite Rule won’t work unless the Rewrite Condition is true.
The string is a keyword of some sort and the condition is what you want that string to be. These are in the form %{string}.
List of String Keywords
- HTTP Headers:
HTTP_USER_AGENT, HTTP_REFERER, HTTP_COOKIE, HTTP_FORWARDED, HTTP_HOST, HTTP_PROXY_CONNECTION, HTTP_ACCEPT
- Connections and Requests:
REMOTE_ADDR, REMOTE_HOST, REMOTE_PORT, REMOTE_USER, REMOTE_IDENT, REQUEST_METHOD, SCRIPT_FILENAME, PATH_INFO, QUERY_STRING, AUTH_TYPE
- Server:
DOCUMENT_ROOT, SERVER_ADMIN, SERVER_NAME, SERVER_ADDR, SERVER_PORT, SERVER_PROTOCOL, SERVER_SOFTWARE
- Time:
TIME_YEAR, TIME_MON, TIME_DAY, TIME_HOUR, TIME_MIN, TIME_SEC, TIME_WDAY, TIME
- Specials:
API_VERSION, THE_REQUEST, REQUEST_URI, REQUEST_FILENAME, IS_SUBREQ, HTTPS
You can put any of those keywords in the place of the word string. After that it’s just a case of checking for a condition. Conditions can be a regular string, or a regular expression. In the condition you can use characters and special directives, for instance:
> (greater than), < (less than), = (equal)
-f checks if the string bit is a file
-d checks if the string bit is a directory
-s checks if the string bit has a size
[OR] or operator, i.e. RewriteCond .... [OR] RewriteCond .... [OR] .. etc
So now that we have all that, an example of a Rewrite Condition would be as follows:
RewriteCond %{HTTP_USER_AGENT} ^Mozilla.*
RewriteRule ^/$ /index5.html [L]
Which just redirects the user to index5.html if they have a Mozilla browser.
Final Words
I hope this tutorial has been of some help to you. Mod_Rewrite is a very useful module, and the rewrite rule will help you be more search engine friendly as well has help you to redirect things. Finally, you might wanna check out this cheat sheet. It’s got a ton of useful information on it to help you when you’re having mod_rewrite woes.
Comments
Thanks for the tutorial, I needed a simple explanation on how to do this and this was great!
Great tutorial. Very informative. Thanks!
Nice tutorial. I have question:
How do I write a rule to redirect all the HTTP requests to HTTPS, coming to one a called “secure” under the document root. I tried below ones but they are not working.
1)
RewriteEngine on
RewriteRule ^secure/(.*)$ https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
2)
RewriteEngine on
RewriteRule ^secure/(.*)$ https://xyz.com/index.html [R=301,L]
Note: Above one, I put in the Virtual Host section in the HTTPD.CONF file. I am not using .htaccess file.
Thank you.
Very useful post..
I hope there will be a part2 of URL Rewriting , with more emphasis on advanced regex patterns :)