Josh

I'm a developer in Melbourne, Australia, and co-founder of Hello Code.

Published Sun 28 October 2007

← Home

Rewriting URLs with Apache's mod_rewrite and PHP

For those of you who aren't aware, Apache provides a very nifty module called mod_rewrite which (can you guess?) lets you rewrite URLs, with or without the end-client knowing. As I've mentioned before, this can be pretty handy. No longer must your URLs look like domain.com/folder/subfolder/file.php?some_id=23. Instead you can present your users with pretty URLs like domain.com/area/action/this_is_a_unique_identifier, and anything along those lines.

There are two main reasons why you'd want to do this:

  • Accessibility for users: your users don't need to remember long GET parameters, or file extensions for that matter. URLs can become more relevant to the content and to the user.
  • Accessibility for search engines: yes, this will help you quite a lot with The Google. You now have a far bigger chance to put your relevant keywords into the URL, which is one of the places they count the most.

So let's have a look at how you'd do this.

The .htaccess file

First off, if your hosting is not on a server running Apache, you're out of luck. Also, some shared hosting providers don't allow you to use .htaccess files, so if this doesn't work that may be why.

For everyone else, a .htaccess file contains directives to Apache pertaining to the folder you put it in, and all subfolders under it (unless you specify another .htaccess to override it). You can add directives about other modules besides mod_rewrite, but we won't be dealing with that.

So without further ado, the contents:

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
</IfModule>

What this does

Line 1: Only follow these directives if mod_rewrite is loaded.
Line 2: Turn on the rewrite engine (to state the obvious).
Line 3 and 4: Only continue with rewriting if the requested file is not an existing directory (-d) or a file (-f).
Line 5: The first part of the RewriteRule is a regular expression which takes the entire URL. The second parameter tells Apache to pass this to index.php as the GET parameter url, without informing the user.

Fairly basic, right? This works for frameworks because typically the index page instantiates the framework app, which handles all actions. However if you're still dealing with separate PHP pages, you can use some further RewriteRules and regular expressions to point specific requests to different files.

Example: To rewrite requests to /blog/ to blog.php:

    RewriteRule ^blog/(.*)$ blog.php?url=$1

One index page to rule them all

If you're writing a framework, you'll probably want to use the single entry-point method where your index page farms out all requests to the controller. Here's how it might look:

<?php

    include('app/classes.php');
    include('app/app.php');

    //init our app
    $App = new App;

    //grab the mod_rewrite url
    $url = $_GET['url'];

    //if the url is empty then the user has navigated just to root
    if ($url == ''){

        //start with default controller
        $App->setController('home');

    } else {
        //grab each part of our URL - controller, action, and identifier
        $path = explode('/',$url,3);

        //pass these onto the app to handle
        $App->setController($path[0],$path[1],$path[2]);
    }

?>

Include all the classes you will need for the app, your controller, model and view superclasses, and then pass the URL to the app. Easy done.

To top