KBD

Keith Devens .com

Friday, July 4, 2008 Flag waving
I was talking recently to a friend who teaches at MIT. His field is hot now and every year he... – Paul Graham
← Quote about programmingDoes Google treat periods as word separators? →

Daily link icon Monday, May 24, 2004

Clean URLs with mod_rewrite and PHP

What follows are the two main pieces of mod_rewrite that I ever use. I've posted these in separate places before, so this is mostly just to aggregate them in one place, as well as to explain how I make sure all URLs on my site are "clean".

First, these rules pass any request for a file that doesn't exist through the "dispatcher", a PHP script which can then do whatever it wants to. It serves as a Front controller (in that article's terminology, Apache acts as the "controller" while dispatcher.php acts as the "dispatcher"). Importantly, note that with the second line commented out, like I have it, this also bypasses directory handling (mod_dir) which means that any index.php, index.html, etc. will never be called. I prefer it this way mainly because I don't like mod_dir sticking trailing slashes on the end of any my URLs. I have a strict policy that no URL on my site can end with a slash (try appending a slash to a URL on my site, I dare you). The way I do it, no URLs have extensions (except images and things that I want to be served directly by Apache) so everything can look like a directory anyway.

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
#RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /dispatcher.php [L]

All of the mod_rewrite directives I list here I have in my .htaccess file in my document root. Note that the slash before dispatcher.php is important, as an analysis of mod_rewrite logs shows that while it would work without the leading slash, having the leading slash makes the translation take fewer steps (which is presumably more efficient).

The way I handle my content is that I have a special "content" directory outside of my document root and my dispatcher parses the URL and serves up what you want if it exists. This way I avoid cluttering up my document root. I don't personally use the following rewrite rules because of this, and because I serve things through the front controller rather than directly, but if you use the following rules, any .php file in your document root will be able to be served without an extension.

RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule . %{REQUEST_FILENAME}.php [L]

Of course, this has to go before the above directives, otherwise it won't be run because dispatcher will get things first. To prevent the files from being accessed with the .php extension, you may want to implement some logic, possibly using auto_prepend_file, to do a permanent redirect from the .php version to the sans-.php version. Because the regular expressions in mod_rewrite don't support non-greedy matching, I don't think there's any way do that redirect in mod_rewrite itself, you need to use PHP for that. It can be as simple as something like:

<?php
if(substr($filename, -4) == '.php')
    
setHttpLocation(substr($filename,0,-4)); #take off the .php
?>

In fact, that's taken almost directly from my dispatcher. setHttpLocation() is straightforward -- leaving it in there makes it work as good pseudocode.

Then, to handle subdirectories in this scheme, you can use subdir.php to represent the subdirectory root (instead of having something like subdir/index.php), and then subdir/whatever.php to handle subdir/whatever).

The other way you can make clean URLs with PHP is by using the following directive in your .htaccess file:

DefaultType application/x-httpd-php

That will make any file not recognized by Apache, including files without extensions, be served as PHP, but this creates problems if you want to have subdirectories since you can't have a file and a directory with the same name.

Update (Jul 9, 04): Note that if you use the dispatcher.php mod_rewrite rules above, you should also add dispatcher.php to your DirectoryIndex setting.

Update (Jul 13, 04): Also see this. You'll probably want to change one of the above lines to "RewriteRule . %{REQUEST_FILENAME}.php%{PATH_INFO} [L]".

← Quote about programmingDoes Google treat periods as word separators? →

Comments XML gif

Sparticus (http://iamsparticus.co.uk) wrote:

That will make any file not recognized by Apache, including files without extensions, be served as PHP, but this creates problems if you want to have subdirectories since you can't have a file and a directory with the same name.

Thank you! For ages I was wondering why my test page (iamsparticus.co.uk/bilfred) was not working sans extension, but it's because I set it up as a subdomain to test some stuff ages ago. Woo!

∴ Sparticus | 25-May-2004 10:20am est | http://iamsparticus.co.uk | #4685

Feel free to post a comment below. Please see my comment policy.

Formatting Rules (No HTML):

  • **bold**, *italic*, _underlined_, --strikeout--
  • "text"="url" creates a link, and URLs are auto-highlighted
  • Blockquote: Like e-mail, begin paragraph with > (greater-than sign)
  • Lists: begin paragraph with *,-, or + (unordered), or # (ordered)
  • Code block: ?!code:language=perl|php|sql|javascript|etc.{\n}...{\n}?!/code

:
(will be your IP address if blank)
: (optional)
(Will not be shown on site)

: (optional)
:

July 2008
SunMonTueWedThuFriSat
 12345
6789101112
13141516171819
20212223242526
2728293031 



RSS feed RSS feed for Keith's Weblog
Atom feed Atom feed for Keith's Weblog
Weblog archive
Recent comments
  on 5 posts

Recent comments XML

Girls, please don't get breast implants

> And no, you will not be receiving​a picture.

:-(...

Keith: Jul 2, 6:05am

Javascript clone function

This is a clever way to clone an​object if you are using YAHOO UI.​Same tec...

Antonio: Jul 1, 12:47pm

I hate Norton Antivirus

Oh just one other thing norton is​great at keeping people out of your​compu...

kevin.sands: Jul 1, 12:50am

Terminator 3 was awful

I think the biggest reason why T3​totally blew was because Edward​Furlong g...

76.167.172.64: Jun 29, 3:06am

Generated in about 0.194s.

(Used 8 db queries)

mobile phone