The basics of URI routing
Posted on 2012-09-22. Tagged as PHP
This post is a (free) translation of my post about URI routing on my Polish blog.
First and foremost: what is URI routing?
URI routing is a way of processing the incoming browser request and deciding, based on the URI, what application logic should be launched, what resources should be used and/or what file should be displayed. Usually, a single file (index.php in most cases) will take request and either decide what do to next or pass the request data on to a script responsible for routing, e.g., a front controller in an MVC application.
So, why is this better than simply using URL rewriting in .htaccess? Well, in the case of having only a couple of resources, say, four static pages, it's definitely enough to use .htaccess rewrites. However, imagine an application with more content, possibly dynamically generated - such as this blog. It's far better to have a single script to take care of all the application logic and, for instance, fetch data from the database while using only a limited number of resources than creating each and every subpage's physical script and then placing it in .htaccess.
Let's take Zend Framework as an example. It's an MVC framework and an application built with it will usually have a default, autogenerated .htaccess:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
Independently from the URI we might write in the browser's address bar after the application's URL, the request will always be directed to index.php (unless we hit a physically existing file). From there, it will be passed to the front controller, where it will be processed and broken down into several pieces of information. That information will be used to instantiate the correct controller and launch the correct action. In other words, the decision will be made whether the request is asking for the home page, or maybe a blog post adding form.
Since I'm not so great at explaining, I think it will be best if I just create an example piece of code, where I can show off a basic router.
In the root directory of the app, we'll place the index.php file and the .htaccess, with the contents quoted above. Let's also create a /views directory, where we'll put the view scripts.
index.php
First, let's check the URI. We can do it by checking the server superglobal and printing it out:
$uri = $_SERVER["REQUEST_URI"]; die($uri);
Now, assuming our application is available at www.example.com, we can test it out by trying to open various "subpages". The main page will display / as the URI. If we write www.example.com/foo/bar, the application will print out /foo/bar.
So it's working. We'll just have to use the received information correctly. But in the meanwhile, let's create some views:
/views/header.php
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Router test</title>
</head>
<body>
/views/footer.php
</body> </html>
Those two views will be out (basic) layout. Let's also create a few other views that will be our content. Place whatever you want in them. You can go with files such as /views/index.php, /views/about.php, /views/portfolio.php and maybe an error page: /views/404.php.
Now let's try to process the incoming request in a meaningful way. There are a number of ways to do this, but I'll just use a simple switch-case conditional statement. The complete code would look like this:
<?php
$uri = $_SERVER["REQUEST_URI"];
include "views/header.php";
switch ($uri) {
case "/":
include "views/index.php";
break;
case "/about":
include "views/about.php";
break;
case "/portfolio":
include "views/portfolio.php";
break;
default:
include "views/404.php";
header("HTTP/1.0 404 Not Found");
break;
}
include "views/footer.php";
And this should be it. Try it out, there's really no rocket science behind this.
Just let me remark that in line 17 I've used a header that returns a 404 error. This is crucial in case of a "real" application because otherwise invalid links might get indexed by search engines.
Anyway, that's it. The router example is, of course, extremely simple, but it could serve to build a more advanced application. You can download the example code in the "Download" section of this page.