Url Routing with PHP – Part One

Most PHP frameworks use some variation of the front controller pattern to centralize common code and logic. There are advantages and disadvantages to this. I am going to ignore those for now. In fact the first part of this series will explore a simple procedural URL routing method that contains many of the disadvantages. In later articles we will build upon this basis and address the disadvantages.

Requirements

Redirecting with mod_rewrite

This article doesn't discuss mod_rewrite and the .htaccess in detail, the following .htaccess file is sufficient for the needs of our simple front controller. The .htaccess file should be placed in the same directory as the front controller script. All requests will be sent to index.php while requests for a file or directory that does exist will bypass the mod_rewrite rules and be served directly by the web server.

file: .htaccess

  1. Options +FollowSymLinks
  2. IndexIgnore */*
  3. # Turn on the RewriteEngine
  4. RewriteEngine On
  5. #  Rules
  6. RewriteCond %{REQUEST_FILENAME} !-f
  7. RewriteCond %{REQUEST_FILENAME} !-d
  8. RewriteRule . index.php

The Entry Point

I chose a simple format for the incoming URL, a command followed by its parameters separated by forward slashes "/".

For example:
www.example.com/command/parameter1/parameter2/

  1. $requestURI = explode('/', $_SERVER['REQUEST_URI']);

in this example $requestURI would contain.

  1. Array ( [0] => [1] => command [2] => parameter1 [3] => parameter2 [4] => )

This works fine except in the case where the front controller is not in the root directory.

For example:
www.example.com/myapps/app1/command/parameter1/parameter2/

in this case $requestURI would contain.

  1. Array ( [0] => [1] => myapps [2] => app1 [3] => command [4] => parameter1 [5] => parameter2  [6] => )

To filter out the path to the front controller we will need to use the $_SERVER['SCRIPT_NAME'] variable.

  1. $requestURI = explode('/', $_SERVER['REQUEST_URI']);
  2. $scriptName = explode('/',$_SERVER['SCRIPT_NAME']);

In the above example $scriptName would contain.

Array ( [0] => [1] => myapps[2] => app1 [3] => index.php )

Which can be used to remove the path and script name from the URI.
Note: As you can see the explode method leaves an empty array member at the first position. This will be fixed by the following code.

  1. $requestURI = explode('/', $_SERVER['REQUEST_URI']);
  2. $scriptName = explode('/',$_SERVER['SCRIPT_NAME']);
  3.  
  4. for($i= 0;$i < sizeof($scriptName);$i++)
  5.         {
  6.       if ($requestURI[$i]     == $scriptName[$i])
  7.               {
  8.                 unset($requestURI[$i]);
  9.             }
  10.       }
  11.  
  12. $command = array_values($requestURI);

After the code above $command would contain.

Array ( [0] => command [1] => parameter1 [2] => parameter2  [3] => )

Dispatching the command

Now that we have a command with its parameters stored in an array it is trivial to handle them via a switch statement. The following is a short example.

  1. switch($command[0])
  2.       {
  3.  
  4.       case 'commandOne' :
  5.                 echo 'You entered command: '.$command[0];
  6.                 break;
  7.  
  8.       case 'commandTwo' :
  9.                 echo 'You entered command: '.$command[0];
  10.                 break;
  11.  
  12.       default:
  13.                 echo 'That command does not exist.';
  14.                   break;
  15.       }

Try it out

You can visit examples.phpaddiction.com/urlrouter/part_1/ to see it in action and download the sample code.

Next up

The next part in the series will focus on moving the URL router into a class and out of the global namespace.

Update I've updated the .htaccess per the comment made by DrBacchus.

Comments

39 Responses to “Url Routing with PHP – Part One”

  1. Tim on April 2nd, 2007 9:58 am
    Gravatar

    that's sweet ! Can't wait to read part-2

  2. Diego Anzlin on April 2nd, 2007 2:11 pm
    Gravatar

    Oi Friend,

    for script to function correctly is necessary to add the following line before "FOR"

    — LINE TO ADD —-
    $scriptNameArray = array_values($scriptName);
    — LINE TO ADD —-

    for($i= 0; $i

  3. Doug Hill on April 2nd, 2007 2:29 pm
    Gravatar

    Copy and paste seems to have bit me! I've fixed the code now Diego. Thanks for the catch.
    Doug

  4. Matthew Turland on April 6th, 2007 2:59 pm
    Gravatar

    For users of PHP 4.3.0+ I believe lines 4-10 in the second source code example can be simplified by making use of the array_diff_assoc function like so:

    $command = array_diff_assoc($requestURI, $scriptName);

    Untested, so I could be wrong, but just a thought. Nice tutorial!

  5. Doug Hill on April 7th, 2007 12:46 am
    Gravatar

    array_diff_assoc() may work I haven't tried it either. I picked the longer for loop to make what was happening in the sample code clearer. I'll try it out though and see.

    Update:
    $commandArray = array_diff_assoc($requestURI,$scriptName);
    $commandArray = array_values($commandArray);

    The above works fine. The article isn't really about how you parse the URLs though, off hand I can think of dozens of schemes. The point is actually being able to translate some arbitrary format into a command array.. or in later articles a command object.

  6. DrBacchus on April 23rd, 2007 6:22 pm
    Gravatar

    Your rewrite conditions are slightly inaccurate:

    RewriteCond %{REQUEST_FILENAME} !-f [OR]
    RewriteCond %{REQUEST_FILENAME} !-d

    Because this is an OR condition, the rewrite rule will always be run. (A OR B) is TRUE when either A or B is true. Any argument will always be either (not a file) or (not a directory). You need to remove the [OR] there, otherwise a request for index.php will cause a loop.

    What you want is "if it's not a file AND it's not a directory":

    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d

  7. Doug Hill on April 23rd, 2007 11:43 pm
    Gravatar

    You are correct, I need to edit the article, in later versions of the sample code I removed the [OR].

  8. Peter Mansen on June 2nd, 2007 5:14 pm
    Gravatar

    How do you use mod_rewrite on the sam server? Thank you!

  9. IndridCold on July 16th, 2007 6:24 pm
    Gravatar

    Why not use something simple like:

    substr($_SERVER['REQUEST_URI'], strlen($_SERVER['SCRIPT_NAME']));

    to distinguish between the script name and the parameters, then explode on that?

    Just an idea.

  10. IndridCold on July 16th, 2007 6:47 pm
    Gravatar

    You might also want to filter out multiple slashes in anticipation of exploding on the '/' as your separator.

    $rawParams = preg_replace('@[\/]{2,}@', '/', $rawParams);

  11. Jesús Flores on September 11th, 2007 6:42 am
    Gravatar

    It's simply awesome ! :) Ty

  12. What is a URL? on November 23rd, 2007 11:51 pm
    Gravatar

    What is the advantage to doing all this? Why not have the PHP script parse the path instead of Apache? Why learn two (possibly conflicting) languages?

  13. Doug Hill on November 24th, 2007 12:33 am
    Gravatar

    I'm not sure I understand your question, The point of the artice is to have the PHP script parse the path.

  14. Peter on December 18th, 2007 8:52 pm
    Gravatar

    re: What is the advantage to doing all this?

    If you're referring to the usage of mod_rewrite, the point is (IMHO) to hide index.php from the URL so that instead of http://example.com/index.php?action=foo/bar or http://example.com/?action=foo/bar you can use http://example.com/foo/bar

    If you're looking for motivation, read http://www.w3.org/Provider/Style/URI

  15. Rauli on December 30th, 2007 1:28 pm
    Gravatar

    With this method, is it possible to get error404 message at all for non-existent 'pages'?

  16. Alessandro Motta on March 21st, 2008 4:32 am
    Gravatar

    Hi,
    nice tutorial you wrote here. I built a similar class for PHP, that works fine. But now, there's a problem:

    I'd like to route urls like the MediaWiki uses. That means urls like http://localhost/user:Test/param1/param2 But when I call these addresses i receive the message (from Apache) that the access has been denied. Do you know any solutions to this problem?

    Thanks for the tutorial and greetings

  17. SMartcoder on March 26th, 2008 2:48 am
    Gravatar

    Nice and brilliant script.
    So simple.

    ANother helpful url is found here.

    Routing in php
    Php routing

  18. jay on April 16th, 2008 10:25 am
    Gravatar

    Hi guys,

    I'm newbie to all this stuff. I am wondering if i could do the following WITHOUT CHANGING THE URL

    http://example.com/foo/bar
    to call
    http://example.com/foo?article_name="bar"

    Thanks in advance :)

  19. Vitou on June 10th, 2008 10:40 pm
    Gravatar

    Hi all,
    I am wonder whether your Rewrite Rull works with Apache on Window plateform or not.

  20. Donatello on June 13th, 2008 11:44 pm
    Gravatar

    Here's My Version!

    .htaccess

    RewriteEngine on
    RewriteCond $1 !^(index\.php|img|css|js)
    RewriteRule ^(.*)$ /index.php/$1 [L]

    .php


    abstract class URI {

    protected $pathArray = array();

    protected $path;

    public function __construct() {

    global $HTTP_SERVER_VARS;

    $this->pathArray = explode("/",$HTTP_SERVER_VARS["REQUEST_URI"]);
    }

    public function getPathByNumber($pathNumber){

    if (substr($this->pathArray[1], -4, 4) == '.php') {
    $this->path = mysql_escape_string($this->pathArray[$pathNumber + 1]);
    }else {
    $this->path = mysql_escape_string($this->pathArray[$pathNumber]);
    }

    return $this->path;
    }

    } //ends URI class

  21. Cakka on July 29th, 2008 1:12 am
    Gravatar

    Thanks for your tutorial.

  22. mod_rewrite problems - DesignersTalk on September 9th, 2008 7:35 am
    Gravatar

    [...] here you can find probably a solution for your problem Url Routing with PHP – Part One : phpaddiction __________________ Need a custom web application PHP/MySQL, have a big project please PM Me ! [...]

  23.   Url Routing with PHP - Part One by ??? on September 21st, 2008 6:03 am
  24. lewen7er9 on December 16th, 2008 10:51 am
    Gravatar

    Thank you for the tutorial. FYI, the link to sample code for part 1 is broken (getting a 500 error).

  25. SiCEramiSip on December 18th, 2008 11:07 pm
    Gravatar

    Hello

    As a fresh http://www.phpaddiction.com user i only wanted to say hello to everyone else who uses this site :>

  26. Peter on February 8th, 2009 5:47 pm
    Gravatar

    What about to mention something about RewriteBase when files not in root dir!
    Example does not have source code for downloading like it is promised there.

  27. vtec sohc on April 5th, 2009 6:50 am
    Gravatar

    This is really helpful, nice code, nice technique, awesome!!!

    Thanks a lot mate!

  28. rudak on April 11th, 2009 11:50 am
    Gravatar

    The line 6 in .htaccess must be
    RewriteCond %{REQUEST_FILENAME} !-f[AND]

  29. WB on April 16th, 2009 10:23 am
    Gravatar

    I setup the patter and it works great except for on gliche… I was wondering if anyone else has and issue with image references when an extra slash is added to the URI. i.e. If the url is…

    http://www.mysite.com/command/action – images are referenced fine as…
    http://www.mysite.com/command/images/my.gif

    however if http://www.mysite.com/command/action/ – broken reference as…
    http://www.mysite.com/command/action/images/my.gif

    Anyone have any thoughts on where to look?

  30. boris on April 29th, 2009 5:12 am
    Gravatar

    @WB I think you shoudl use tirm('/',$url)…

  31. Umer on June 3rd, 2009 7:32 am
    Gravatar

    Hi,
    I am new user.
    I want to redirect
    http://myurl.com/profile/username
    to
    http://myurl.com/username

    I have tried this through .htaccess but CSS and connection breaks.

    Is there any other way to do this.

    Thanx in Advance.

  32. Jove Sharma on July 1st, 2009 12:19 pm
    Gravatar

    Hi there,

    do someone have any code for htccess or php so that i can redirect my own made extension file to the respective php file, but the browser shows the extension by me.

    like if i type a url link
    http://www.yourdomain.com/index.jove

    but internally it will display the content of http://www.yourdomain.com/index.php

    while showing the
    http://www.yourdomain.com/index.jove in the browser window.

  33. Neuromancer on August 22nd, 2009 3:23 am
    Gravatar

    It doesn't work.

    $requestURI is empty.

  34. sandrar on September 10th, 2009 5:50 pm
    Gravatar

    Hi! I was surfing and found your blog post… nice! I love your blog. :) Cheers! Sandra. R.

  35. Erik on September 13th, 2009 4:26 pm
    Gravatar

    Hi. Thanks for this Tutorial. I enjoyed it.

    Just a minor note on all these attempts to get command and parameters by comparing paths – that's not necessary if you store the request in a $_GET parameter like this:
    <samp>RewriteRule (.*) index.php?r=$ [L,QSA]</samp>
    This way you can drop all the string comparing and extract all parameters with one <samp>explode('/',$_GET['r']);</samp>

  36. Matthew Fedak on October 22nd, 2009 8:00 am
    Gravatar

    Thanks for this Doug, its a simple post and suppose people have there own ways in which they get round the problem, but it explains the concept to wanabe php developers really well. Quick point Eric (last commentor) point is good but can i would advise newbies to avoid.

  37. sethhhh on February 7th, 2010 5:40 pm
    Gravatar

    Hello,

    I have a site made with symfony 1.1 and i whant to change it with
    another site made with 1.2.
    my proplem is that i whant to change some URL…
    For example i have a url thath looks like this on my old site:
    http://www.sejur-extern.ro/Egipt/Sharm-El-Sheikh

    On my new site it will be:
    http://www.sejur-extern.ro/turism-extern/Egipt/Sharm-El-Sheikh.html

    How can i get the old url if google sends someone on it…and change
    it in my new one?

    Thank you!

  38. Quotes aka Bash.org/QDB clone | x2 // activeStyle on March 1st, 2010 8:17 pm
    Gravatar

    [...] on the internet about URL routing i found Axial Routing, i liked it and decided to base my code on that tutorial. I abused the singletons a little and [...]

  39. click here on August 22nd, 2010 4:40 pm
    Gravatar

    Agree 100%

Leave a Reply




XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>