New Website

I've made a new website, as lynx.io is dead. You can find it here: http://macr.ae/—it's similar in format to lynx.io, but has better articles, and they're all written by me.

JavaScript disabled

While it will still mostly work, a lot of this site's functionality relies on JavaScript - please enable it for the best experience.

Using mod_rewrite to create friendlier URLs

mod_rewrite is an Apache module used for rewriting a URL at the server level, making the URL a lot friendlier. For example, if a user goes to example.com/article/421 they will in fact be shown example.com/article.php?id=421, but they still think they're accessing /article/421. This is a different to redirect, as a redirect completely changes the page the user is on, telling them that they're on article.php, but mod_rewrite does not - this makes the URL look a lot friendlier, while not requiring millions of pages.

Where is it already used?

Many (if not most) PHP sites use mod_rewrite, such as:

Also, more than a few scripts use mod_rewrite, including (among others), WordPress, Joomla, Drupal, MediaWiki and most CMS platforms.

Using mod_rewrite

To use mod_rewrite, you simply have to have the mod_rewrite installed (and enabled) on your Apache server. To see whether you have mod_rewrite enabled, create a PHP info file and search for "mod_rewrite". If it is installed, it should appear into the "Apache loaded modules" section.

A very simple example

This example will simply display bar.html where foo.html is requested. Firstly, we need to create the foo.html and bar.html files. Technically we don't actually have to create foo.html because the server will just ignore it, but I am putting it there anyway so we can easily tell if it doesn't work. Unless you are confident with mod_rewrite, I would always recommend creating that file. Obviously, when we move onto more complicated examples, you can't create every file.

Create foo.html with the following:

<b>Error:</b> mod_rewrite seems to have failed.

bar.html:

<h1>Welcome!</h1>
<p>The mod_rewrite is successfully working!</p>

The, add the following lines to your .htaccess file:

RewriteEngine On
RewriteRule ^foo.html$ bar.html

Make sure that the .htaccess is in the same directory as the html files, the open foo.html. You should see the message saying that the rewrite worked. If it didn't, check the following:

If it still isn't working, feel free to ask in a comment and someone (probably me) will reply as soon as they can.

How did it work, though?

The structure of a RewriteRule is as follows:

RewriteRule pattern replacement [flags]

RewriteRule - the name of the command, lets Apache know that we want to rewrite something.

pattern - regex pattern which will be applied to the URL that has just been requested.

replacement - If the pattern returns true, the file specified as the replacement is requested instead. As it is regex, you can include backreferences, which should be written as $n

[flags] - flags are optional. They should be surrounded by square brackets and separated by a comma. Here are a list of the most comment flags:

A full list is available on the apache website.

A more complex example

In this example, we are going to redirect people requesting article/124/ to article.php?id=124. You do not need the /article/ directory to exist, but article.php must obviously exist, or you will get a 404 error. Put the following code in article.php:

<?php
if (isset($_REQUEST['id']) && is_int($_REQUEST['id'])) {
    echo 'You requested article ' . $_REQUEST['id'];
}

Then, add the following couple of lines to your .htaccess file:

RewriteEngine On
RewriteRule ^article/([^/\.]+)/?$ article.php?id=$1 [L]

Accessing /article/124 should now display:

You requested article 124

How does it work?

Lets work through the rule, seeing exactly what everything does.

If you wanted to make it more secure, you could replace ([^/\.]+) with something which makes sure the characters are numbers. This adds some extra security against injections, but does not display a nice error; just a 404 error. You could replace ([^\/.]+) with ([0-9]+), which simply checks for one or more integer between 0 and 9, and saves it as a backlist.

If you still wanted a friendly error, you can use:

RewriteEngine On
RewriteRule ^article/([0-9]+)/?$ article.php?id=$1 [L]
RewriteRule ^article/.+/?$ hackattempt.html [L]

Because of the [L] flag, any value that is requested from the article directory that is a number will return true to the first rule, meaning the second rule won't be tested. If it is not a number but is still requested from that directory, they will be send hackattempt.html


That's all - I hope this article has helped, feel free to share where you have used it and how it has helped.

About Callum Macrae:

Callum Macrae is the founder of lynx.io and a JavaScript developer from the United Kingdom. He is currently writing his first book, to be published by O'Reilly Media.

You can view more articles by this author here.

Tags: php seo mod_rewrite

Comments

No comments; leave one below.

says:

Add comment

 

You can use markdown in comments (press "m" for a cheatsheet).

Enable JavaScript to post a comment

Markdown Cheat Sheet

# This is an <h1> tag
## This an <h2> tag
###### This is an <h6> tag

Inline markup: _this text is italic_, **this is bold**, and `code()`.

[Link text](link URL "Optional title")
[Google](http://google.com/ "Google!")

![Alt text](image URL)

![This is a fish](images/fish.jpg)

1. Ordered list item 1
2. Ordered list item 2

* Unordered list item 1
* Unordered list item 2
* Item 2a
* Item 2b

And some code:

// Code is indented by one tab
echo 'Hello world!';

Horizontal rules are done using four or more hyphens:

----

> This is a blockquote

This is an <h1> tag

This an <h2> tag

This is an <h6> tag

Inline markup: this text is italic, this is bold, and code().

Link text Google

This is a fish

  1. Ordered list item 1
  2. Ordered list item 2
  • Unordered list item 1
  • Unordered list item 2
    • Item 2a
    • Item 2b

And some code:

// Code is indented by one tab
echo 'Hello world!';

Horizontal rules are done using four or more hyphens:


This is a blockquote

Toggle MarkDown / HTML (t), full reference or close this