Request Script


PHP Routing

Routing in terms of a web application is the selection of content based on the user’s request URI. Typically, routing is very intuitive for PHP, as with most web languages; the user asks for /foo.php and the server executes and serves up /foo.php.

However, an idea I picked up from ASP.NET MVC is their notion of routing. In this way, urls actually look a bit more human-readable, and you can get rid of all the file extensions. Not all the concepts of MVC may translate over to PHP, but the basic idea is to have all requests go first to a routing script which will determine which code to execute from there.

For example, if you had a website which had a forum, you might not want to have the url look like /post.php?postid=12345678. You could instead, make the url /post/12345678/this-is-the-posts-title. This looks a lot better and is very easy to route.

So to set up routing for PHP, first you must get all traffic to get to your routing script. To do this, add the following to your .htaccess file:

# Turn on the RewriteEngine
RewriteEngine On

# Rules
RewriteCond %{REQUEST_FILENAME} !/content/*
RewriteRule .? routing.php

Now let’s analyze each line of the file:

RewriteEngine On

This turns the rewrite engine on in Apache. The mod_rewrite engine needs to be enabled for this to work, but this should come installed and enabled with most PHP installations.

RewriteCond %{REQUEST_FILENAME} !/content/*
RewriteRule .? routing.php

The first line is a condition for rewriting. In the example, I have that the request filename NOT be /content/*. The reason for this is that I do not like static content to need to go through routing. So I would put all images, CSS, and JS somewhere in /content/.

The second line basically just makes all other requests now point to routing.php. This file is the one which will do the routing and which every request will end up going through.

So now let’s take a look at routing.php

session_start(); // if you are using PHP sessions on your site

// put all common included here like connecting to databases, class includes, etc.
// ...

$requestUri = $_SERVER['REQUEST_URI'];

// get rid of query params
$i = strpos($requestUri, '?');
if($i !== false)
	$requestUri = substr($requestUri, 0, $i);

$urlParts = explode('/', $requestUri);

// do your routing logic here! Here's a trivial example
$script = $urlParts[1] . 'page.php';

// execute routed script

The above code should be fairly self explanatory. It assumes that you want your url structure to be /{pageName} mapping to the file /{pageName}/page.php. You can put whatever you want though. Also, the above code puts the header and footer includes in so you don’t need to have them in each of your page scripts (or session_start(), or those common includes you put in the routing script!).

Here is an example of just the routing logic for the forum example earlier:

// ...

// url structure was /post/{postId}/{postTitleEncoded}
if($urlParts[1] == 'post')
	$postId = $urlParts[2]; // $postId should be available to the included script file
	// we're ignoring the post title part of the url. It's for human-readability and SEO
	$script = 'post.php';
// more routing logic if needed
// ...

// ...

Now post.php can use $postId for its logic. This allows it not to have to worry about the header, footer, or any other common scripts, or sanitizing any input as the routing logic should be able to handle all that.

One immediate concern I had was for performance. I thought about it for a while, and I think there is minimal to no impact on performance, as long as you have that !/content/* exception. If PHP routing is used for anything but PHP files, that’s where the problem would lie. The routing script will probably always be in memory since it’s used for every page call and the implementation of Apache and PHP should (famous last words) be able to handle a single page being hit over and over just as well as several different pages being hit, if not better.

Some people prefer mod_rewrite for handling all of their routing, but sometimes you may need some logic beyond basic string matching. For example, if the user is logged in or has a certain right access, they might be routed to a different page than others. Also, some kinds or basic validation and sanitation can be done in routing that you wouldn’t be able to do in mod_rewrite.

We’re Back!

So for the past week or so the site has been down. I had some problems with my old hosting company; they ended up deleting the website with no backup.

Luckily, there are ways to recover the HTML at least by using Bing and the site: modifier. So with the HTML content recovered, I manually copy and pasted all the posts back into the site. Phew! Then came the task of actually re-styling the site, which I won’t even go into here, but rest assured that my weekend has pretty much been dominated by this.

The moral of the story, back your websites up. Even though your hosting company may claim to backup your files, experience has shown me that they don’t always.

On a lighter note, I have changed hosting to I know the guy personally, and I know there won’t be any problems with his hosting.

Sortable Table… Updated!

After using my original Sortable Table for some time now, I’ve noticed something that could be better. Namely, type-awareness! I added the ability to declare each column as containing common type of data like numbers and dates as well as giving the functionality to enable writing custom sort functions.

Source: sortableTable.js
Example: Example

To declare a column as containing numbers, give the associated thclass="number". As you may guess, it basically just parses the string as a float (using parseFloat) before comparing, so “11″ will come after “2″. To sort dates, add class="date" to the th. This simply uses the Date.parse function before comparing.

Now that the “easy” ones were out of the way, I thought about how to give the developer a way to define their own sorting function, since strings, numbers, and dates won’t be the only things that should exist in a sortable table, for example, move ratings.

To do this, add class="custom_sortFunc" to your th where sortFunc is the JavaScript function you want to use to sort. This function should take two arguments and return an integer. The return value should be less than 0 if the first argument should be before the second, 0 if they’re equal sort-wise, and greater than 0 if the first should go after the second.

In the example, you see the following:

var movieRatings = new Array('G', 'PG', 'PG-13', 'R', 'NR');
function movieRatingSort(str1, str2)
	return movieRatings.indexOf(str1) - movieRatings.indexOf(str2);

My movie ratings th has class="custom_movieRatingSort". That’s all!

Note that there is no error checking in the way of checking to see that the custom sort function takes two arguments nor that the return type is an int, so funky things may happen if you give it an invalid function.