Extensionless URLs with .htaccess

Posted Jan. 14, 2009 by Gabriel Hurley

After a number of roundabout tries, I managed to get URL rewriting working the way I wanted to so that I could make pretty extensionless URLs for my websites (e.g. domain.com/thispage).

Because I personally found htaccess and mod-rewrite to be poorly documented except for the painfully technical apache documentation, I thought I'd break down the code I'm using:

  1. Options +FollowSymlinks

    First, just to be on the safe side, we make sure that the FollowSymlinks option is enabled so the server will actually process and follow our "fictional" URLs.

  2. RewriteEngine On

    RewriteEngine is the mod-rewrite worker that is going to do all our work, so we have to turn it on.

  3. RewriteBase /yourdir

    This lets us set any directory as the base for rewriting and makes it easier to write our regular expressions and rewrites since we don't have to deal with pesky base directories. It's also really handy when migrating the code from a directory on a development server to the live site's root.

  4. RewriteCond %{REQUEST_URI} !(\.[^./]+)$

    Since we don't want to make any existing files inaccessible, we make sure that the URI (in this case the part of the URL after our base directory) doesn't have a file extension. The regular expression more literally checks that it "does not contain a period followed by one or more characters that is not a period or a slash."

  5. RewriteCond %{REQUEST_FILENAME} !-d

    This tells the Rewrite Engine not to rewrite the URL if it matches an existing name on the server with the directory flag (i.e. if it is a directory).

  6. RewriteCond %{REQUEST_FILENAME} !-f

    And this one, similarly, tells it not to rewrite the names of existing files.

  7. RewriteRule ^(.*) yourscript.php?yourargument=$1 [PT]

    Finally, we have the actual rewriting rule. Since what I want to do is pass variables to a PHP script to load content, this is how my rule is set up. This matches essentially any number or combination of characters after our RewriteBase that we set earlier, and passes pieces matched inside the parentheses to wherever we put our $numbered variables in our rewritten URL. So the first set of parentheses goes to $1, a second set would go to $2, and so on. Finally, if you want to chain the output of one rewrite rule to the next you set the [PT] flag to allow for passthrough of the rewritten URLs.

One important note: The way the RewriteEngine works is a little funny given how a human would read the code... It actually tests the condition regular expression in your RewriteRule before it tests any of the conditions specified above the rule by RewriteCond. So in order for any of your conditions to be tested the whole thing first has to find a valid match to operate on.

Lastly, in case you want to copy and paste, here's the whole code together, ready to be plopped into a .htaccess file and give you extensionless URLs by passing variables to scripts:

Options +FollowSymlinks
RewriteEngine On
RewriteBase /yourdir
RewriteCond %{REQUEST_URI} !(\.[^./]+)$
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*) yourscript.php?yourargument=$1 [PT]

Happy coding!


Two comments:

Post A Comment