PHP Regular expresssion URL Router
In this tutorial we will create a PHP URL router. The developer using the router will be able to define these routes with regular expressions, these will then map to a file, class and method which will be called – very similar to Django’s routing. By using regular expressions to define our URLs we get maximum customizability. /class/method/ based URL routing is too restrictive sometimes. We will assume the user is using an apache or similar web server with mod_rewite enabled. You can adapt this router and use it in your web application or framework.
Quick Note: This is taken straight out of one of my applications. I have a singleton registry object called $core which you’ll see referenced many times. I suggest you make your own or use global variables.
.htaccess
First of all we need to create a .htaccess file in the root directory of your project. We turn the RewriteEngine on, and then declare a rule to route everything except images/js/css through our index.php file. So even if the person goes to www.yoursite.com/directory/file.php , rather than executing that file it will execute our index.php instead.
RewriteEngine on RewriteRule !\.(js|ico|txt|gif|jpg|png|css)$ index.php
If your building a framework or application you’ll probably have some ini/bootstrapping code that you want to run here. The router itself is procedural so include it at the bottom of index.php.
Declaring the Routes
We define our routes in an array called $urls (naming matters). You can declare these anywhere before the router is included. In the array key we declare our regular expression. I’ve listed a couple as examples below. The first matches to the root – as if someone went to www.yoursite.com. This gets mapped to application/views/blog.php , then the index() method in the blog class is executed. The second is slightly more complex and captures a value called slug. This value is then passed as a parameter in the individual_post() method when it is executed.
$urls = array( // "Regex to match" => "path_to_file.php___className___functionName", "(^[/]$)" => "application/views/blog.php___blog___index", // No captured values "(/post/(?P <slug>\w.*)$)" => "application/views/blog.php___blog___individual_post", );
The Router Itself
The operation of the router itself is pretty simple:
- Figure out the URI the user requested
- Try and match one of the defined regular expressions to that URI
- If it does match, see if there are any captured matches (eg. our slug name above)
- If there are matches, call the appropriate method and pass them as a parameter
First we need to figure out the URI. For example if they went to www.yoursite.com/blog/first-post/ , we would just want to capture the /blog/first-post/ so it matches our regular expressions. The code below does that with a series of str_replace()s.
$already_there = str_replace('index.php', '', $_SERVER['SCRIPT_NAME']);
$slightly = str_replace($_SERVER['SCRIPT_NAME'], "", $_SERVER['REQUEST_URI']);
$uri = '/' . str_replace($already_there, '', $slightly);
We will then iterate through our defined URL routes/regular expressions and try to get a match.
foreach($urls as $regex => $mapper)
{
if (preg_match($regex, $uri, $matches))
{
$matches is an array that is populated when a URL pattern is matched. If we are capturing a value (eg. slug in the above example) then there will be a key called ’slug’ and the value it captured in the array. If there is only one item in the $matches array, then there the user didn’t try to capture any values in their regular expression so we don’t need to pass any arguments in the method that we call. We simply explode the $val variable to get the filename, class name and method name, then call it.
If however we iterate across a key that isn’t numeric, then we know there is a value that is getting captured. We simply get that and pass it as an argument when we call the method.
foreach($matches as $key => $val)
{
if(count($matches) == 1)
{
$foo = explode("___", $mapper);
//Include the view they specified
include($core->settings->application_path . $foo[0]);
//Instantiate a new class they specified
$bar = new $foo[1]();
//Call the function they specified
$bar->$foo[2]();
}
//Make sure the key is not numeric - some extra garbage preg_match() gives us.
if(!is_numeric($key))
{
//Split the value they defined up into sections
$foo = explode("___", $mapper);
//Include the view they specified
include($core->settings->application_path . $foo[0]);
//Instantiate a new class they specified
$bar = new $foo[1]();
//Call the function they specified
$bar->$foo[2]($val);
//echo $key . ' -> ' . $val . '';
}
}
break;
Theres also a place to indicate to the user that there we no matches – it’s up to you if you want to give a custom error page, 404, whatever.
}
else
{
//echo "A match was not found.";
}
}


June 24, 2009
[...] more from the original source: PHP Regular expresssion URL Router | jQuery Development | Flex Development | Zend Framework Developm… Share and [...]