Take the 2-minute tour ×

What's the best way to implement a URL interpreter / dispatcher, such as found in Django and RoR, in PHP?

It should be able to interpret a query string as follows:

  • /users/show/4 maps to
    • area = Users
    • action = show
    • Id = 4
  • /contents/list/20/10 maps to
    • area = Contents
    • action = list
    • Start = 20
    • Count = 10
  • /toggle/projects/10/active maps to
    • action = toggle
    • area = Projects
    • id = 10
    • field = active

Where the query string can be a specified GET / POST variable, or a string passed to the interpreter.

Edit: I'd prefer an implementation that does not use mod_rewrite.

Edit: This question is not about clean urls, but about interpreting a URL. Drupal uses mod_rewrite to redirect requests such as http://host/node/5 to http://host/?q=node/5. It then interprets the value of $_REQUEST['q']. I'm interested in the interpreting part.

share|improve this question
Remember that to remove the ?q= you need mod_rewrite - you need to pass through the variables to the script at some point. CodeIgniter uses URLs with the format of /index.php/controller/action/whatever, and then you can use mod_rewrite to remove the index.php :) –  Jamie Rumbelow Oct 15 '09 at 7:30
add comment

7 Answers

If appropriate, you can use one that already exists in an MVC framework.

Check out projects such as -- in no particular order -- Zend Framework, CakePHP, Symfony, Code Ignitor, Kohana, Solar and Akelos.

share|improve this answer
add comment

have a look at the cakephp implementation as an example:



You could also do something with mod_rewrite:

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} -f
    RewriteRule ^(.*)$ $1 [L]
    RewriteRule ^([a-z]{2})/(.*)$ $2?lang=$1 [QSA,L]

This would catch urls like /en/foo /de/foo and pass them to index.php with GET parameters 'lang' amd 'url'. Something similar can be done for 'projects', 'actions' etc

share|improve this answer
add comment

Why specifically would you prefer not to use mod_rewrite? RoR uses mod_rewrite. I'm not sure how Django does this, but mod_php defaults to mapping URLs to files, so unless you create a system that writes a separate PHPfile for every possible URL (a maintenance nightmare), you'll need to use mod_rewrite for clean URLs.

share|improve this answer
By using PHP, you know it's there and working. So it's basically the If mod_rewrite.c that bothers me. Django uses python, and I know that Drupal uses PHP. –  Jrgns Oct 14 '08 at 18:48
Drupal uses mod_rewrite to get the type of clean URLs you're seeking, as does every PHP CMS. Python has its own version of mod_rewrite, URLconf. The IfModule is there to provide an ugly URL fallback where mod_rewrite is unavailable. But it's widely available. You should really try it out. –  Scott Reynen Oct 15 '08 at 5:49
The most Drupal does with mod_rewrite is to redirect /drupal/node/5 to /drupal/index.php?q=node/5 and to check if the browser is trying to access other files. It then interprets the $_REQUEST['q'], where it checks for aliases, and breaks it up in different parts. –  Jrgns Oct 15 '08 at 7:05
Oh, and I have tried it out, but I prefer the flexibility / familiarity of PHP's string handling functions. I do use mod_rewrite to create clean urls the same way drupal does. –  Jrgns Oct 15 '08 at 7:07
add comment

What you are describing in your question should actually be the URL mapper part. For that, you could use a PEAR package called Net_URL_Mapper. For some information on how to use that class, have a look at this unit test.

share|improve this answer
add comment

The way that I do this is very simple.
I use wordpress' .htaccess file:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

What this .htaccess does is when something returns a 404, it sends the user to index.php.

In the above, /index.php is the "interpreter" for the URL.
In index.php, I have something along the lines of:

$req = explode("/",$req);

The second line splits up the URL into sections based on "/". You can have

$area = $req['0'];
$action= $req['1'];
$id = $req['2'];

What I end up doing is:

function get_page($offset) {//offset is the chunk of URL we want to look at
    $req = $_SERVER['REQUEST_URI'];
    $page = $req[$offset];
    return $page;
$area   = get_page(0);
$action = get_page(1);
$id     = get_page(2);

Hope this helps!

share|improve this answer
Getting the different chunks is easy. I want the code to be able to spot that it's a area/action/id url, or a action/area/id/field url, or someting totally different. –  Jrgns Feb 26 '09 at 12:08
add comment

Just to second @Cheekysoft's suggestion, check out the Zend_Controller component of the Zend Framework. It is an implementation of the Front Controller pattern that can be used independently of the rest of the framework (assuming you would rather not use a complete MVC framework).

And obviously, CakePHP is the most similar to the RoR style.

share|improve this answer
add comment

I'm doing a PHP framework that does just what you are describing - taking what Django is doing, and bringing it to PHP, and here's how I'm solving this at the moment:

To get the nice and clean RESTful URLs that Django have (http://example.com/do/this/and/that/), you are unfortunately required to have mod_rewrite. But everything isn't as glum as it would seem, because you can achieve almost the same thing with a URI that contains the script's filename (http://example.com/index.php/do/this/and/that/). My mod_rewrite just forwards all calls to that format, so it's almost as usable as without the mod_rewrite trick.

To be truthful, I'm currently doing the latter method by GET (http://example.com/index.php?do/this/and/that/), and fixing stuff in case there are some genuine GET variables passed around. But my initial research says that using the direct slash after the filename should be even easier. You can dig it out with a certain $_SERVER superglobal index and doesn't require any Apache configuration. Can't remember the exact index off-hand, but you can trivially do a phpinfo() testpage to see how stuff look like under the hood.

Hope this helps.

share|improve this answer
I'm not sure I understand what you're trying to say? –  Jrgns Oct 16 '09 at 22:14
add comment

Your Answer


