Blog

Url Routing with PHP – Part Two

Posted by:

This is the second part of a series, I assume you have read Url Routing with PHP – Part One as it covers the basics that I’ll build on in Part Two.

Requirements

  • Apache with mod_rewrite enabled
  • PHP

Assign Responsibilities

The first problem I want to address is that there are two different things going on with the script in part one. 1. The parsing of the URL to obtain a command array and 2. The actual dispatch of the command by the switch statement. I want to create an architecture that easily allows changing the way incoming URLs are formatted, and also the substitution of alternative dispatch schemes.

Standardized Command Objects

To achieve this goal, I create a standard command object. This will allow changing the way the urls are interpreted or dispatched as long as the interpreter creates command objects and the dispatcher accepts them.

  1. class Axial_Command
  2.         {
  3.         var $commandName = ;
  4.         var $parameters = array();
  5.        
  6.         function Axial_Command($commandName,$parameters)
  7.                 {
  8.                 $this->commandName = $commandName;
  9.                 $this->parameters = $parameters;
  10.                 }
  11.         function getCommandName()
  12.                 {
  13.                 return $this->commandName;
  14.                 }
  15.         function getParameters()
  16.                 {
  17.                 return $this->parameters;
  18.                 }
  19.         }

Interpreting URLs

Next we need a class that handles interpreting the incoming URL and creating a command object. The following class uses the same method as in part one and creates commands based on a simple format for the incoming URL, a command followed by its parameters separated by forward slashes.

  1. class Axial_UrlInterpreter
  2.         {
  3.  
  4.         function Axial_UrlInterpreter()
  5.                 {
  6.                 $requestURI = explode(‘/’, $_SERVER[‘REQUEST_URI’]);
  7.                 $scriptName = explode(‘/’,$_SERVER[‘SCRIPT_NAME’]);
  8.                         for($i= 0;$i < sizeof($scriptName);$i++)
  9.                                 {
  10.                                 if ($requestURI[$i] == $scriptName[$i])
  11.                                         {
  12.                                         unset($requestURI[$i]);
  13.                                         }
  14.                                 }
  15.                 $commandArray = array_values($requestURI);
  16.                 $commandName = $commandArray[0];
  17.                 $parameters = array_slice($commandArray,1);
  18.                 $this->command = new Axial_Command($commandArray[0],$parameters);
  19.                      }
  20.        
  21.         function getCommand()
  22.                 {
  23.                 return $this->command;
  24.          }
  25.         }

Dispatching Commands

And finally we can pass the command object to the dispatcher. In order to keep the code simple I use a switch statement that includes different scripts based on the command. There are many other methods that could be used in fact thats the point the of architecture I’m presenting.

  1. class Axial_CommandDispatcher
  2.         {
  3.         var $command;
  4.         function Axial_CommandDispatcher($command)
  5.                 {
  6.                 $this->command = $command;
  7.                 }
  8.  
  9.         function Dispatch()
  10.                 {
  11.                 switch ($this->command->getCommandName())
  12.                         {
  13.                         case ‘commandOne’ :
  14.                                 include(‘commandone.php’);
  15.                                 break;
  16.                         case ‘commandTwo’ :
  17.                                 include(‘commandtwo.php’);
  18.                                 break;
  19.                         case :
  20.                                 include(‘root.php’);
  21.                                 break;
  22.                         default:
  23.                                 include(‘default.php’);
  24.                                 break;
  25.                         }
  26.                 }
  27.         }

Put it all together

In the first part of this series I used an .htaccess file to redirect to index.php. The same .htaccess is all we need now. Our new index.php will look a bit different though. With the changes from part one made we can now substitute different classes to handle the interpretation of URLs or command dispatching easily.

  1. include(‘axial.command.php’);
  2. include(‘axial.urlinterpreter.php’);
  3. include(‘axial.commanddispatcher.php’);
  4. $urlInterpreter = new Axial_UrlInterpreter();
  5. $command = $urlInterpreter->getCommand();
  6. $commandDispatcher = new Axial_CommandDispatcher($command);
  7. $commandDispatcher->Dispatch();

Try it out

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

Next up

In the next part of this series I will explore some ways to get rid of the switch statement in the dispatcher and create a small framework to hang your code from.

17


About the Author

Discussion

  1. L!MP  April 6, 2007

    replace

    $this->command = new Axial_Command($commandArray[0],$parameters);

    to

    $this->command = new Axial_Command($commandName ,$parameters);

  2. Doug Hill  April 7, 2007

    Sure, either way works, It is quicker to leave out the array access and perhaps the clearer style, thanks for the pointer.

  3. Roman  April 8, 2007

    I use $_SERVER['PATH_INFO']. This way I only get what is past the script path.

  4. Doug Hill  April 9, 2007

    Roman: I decided against using PATH_INFO since it wouldn't allow for separators other than forward slashes "/". I wanted the entire URL after the script not just the directories. Also I found that support for PATH_INFO wasn't the same across PHP versions.

  5. Tom  May 18, 2009

    I dont understand why is a url router?

    Here an example of an url router:

    $listRoutes = array(
    "home" => "",
    "articleHome" => "articles",
    "news" => "articles/news",
    "category" => "articles/",
    "article" => "articles//article-.html"
    );

    foreach ($listRoutes AS $name => $route)
    {
    if (strpos($route,'<') === false)
    {
    echo "Static $name: ".(match_static_route($url,$route) ? 'Yes' : 'No');
    }
    else
    {
    echo "Dynamic $name: ".(count($r = match_dynamic_route2($url,$route)) != 0 ? 'Yes':'No')." — ";
    print_r($r);
    }
    }

    function match_static_route($url,$route)
    {
    return $url == $route;
    }

    function match_dynamic_route2($url,$route)
    {
    $result = array();

    $route = str_replace("/","\/",$route);
    $route = str_replace("<","(?P",">[^\/]*)",$route);

    if (preg_match("/$route$/",$url,$matches) > 0)
    {
    foreach ($matches AS $key=>$value)
    {
    if (!is_numeric($key))
    {
    $result[$key] = $value;
    }
    }
    }

    return $result;
    }

    You can exploit the parameters on $r.

  6. Carlo  June 25, 2009

    Please can you Tom from the previous comment or someone else explain to me the point?

    What does that mean "you can exploit". Also the introducing sentence is not quite clear for me, I am not english.

    But I see in the code some interesting point, so I'd like to understand the whole thing

    Thank You
    Carlo

  7. Johan Hultin  June 28, 2009

    I don't really like the whole thing with cases there, I'd say it's quite static and should be worked on to be more dynamic, I will work on it and see if I find any neat solution

  8. stunaz  July 29, 2009

    There is a bug on that script.
    we can see it on the example. while testing the link with two parameters, the css style disappear.
    how can we fix that?

  9. stunaz  July 29, 2009

    i mean in the example that we download from the link

  10. vulo  October 5, 2009

    While using the url router,
    in the functions that I am using instead of variables I get

    AC_RunActiveContent.js
    Scripts
    robots.txt, loaded into the urls – array
    and the the actual url (for example – events, ot contacts)

    Also I think it is reloading the page every time. with these values into the urls – array

    Have anyone idea why this is happening.
    Regards
    Vulo

  11. IT Support London  November 24, 2009

    i cant get the code to work arghhhh!

  12. Anonymous  May 29, 2010

    Great Article.

    //
    // Shorter way of parsing the path.
    //
    array_diff (
    explode('/', $_SERVER['REQUEST_URI']),
    explode('/', $_SERVER['SCRIPT_NAME'])
    );

  13. Laptop Repair London  August 16, 2011

    Been looking for ways to go around with some codes putting URL to PHP codes, thanks for the codes. Surely helped a lot.

  14. Sepehr  October 27, 2011

    Thank you "Anonymous" for shorter way of parsing the path.
    And of course thanks to the author!

  15. wuttdan  April 4, 2012

    Great.

  16. David  April 16, 2012

    The problem is, what if the user accesses http://localhost/index.php

  17. Ben  February 20, 2013

    What about URis like this? /command/action?state=somethingInHere&facebook=true

    I neet it, to authenticate with facebook

Add a Comment