Here's another issue I couldn't find a simple answer to. I'm building a website in PHP, and I want a simple front controller. In other words, I want every bit of traffic to run through a central script that farms out the traffic by parsing the URL. And I want it to be silent – I don't want the user to know the redirects are happening. Now, I could do this with query strings – that's like http://mysite.com/index.php?page=foo&action=bar But that's ugly, and it gets complicated fast.

Instead, I want to do it in the user-friendly, semantically meaningful, SEO-ok way, like: http://mysite.com/foo/bar I want to use the path structure instead of the query string. This is a common pattern for Ruby and Python, but maybe less so in PHP. So, here's how I did it.

(Note: This isn't rocket science. Yet it was still hard to find. And I'm sure there are 1000 ways this could be done better, cleaner, faster, more. But I'm a functional coder. I don't care if it's the most elegant, I care if it works. And this works.)

There are two parts to the controller. The first is the .htaccess file. I'm using XAMPP on Windows Vista as my development environment. If you need help getting .htaccess to work there, check out my earlier post.

RewriteEngine on
RewriteCond $1 !^(index\.php|lib|parts|pages|images|robots\.txt)
RewriteRule ^(.*)$ /your/webroot/index.php/$1 [L]

Here's what this does. (Full disclosure: I adapted this from CodeIgniter's model…) The first line enables mod_rewrite. It's a must. The second line sets the conditions for the rewrite. It says, rewrite everything except what's listed in the parenthesis. If you have additional directories that you keep images, css files, or other things in, you just add them to the list in parens with a '|' between. Finally, the last line sends everything through the main controller, which is index.php, but without actually changing the URL in the address bar. This part is what makes the whole thing transparent to the user. Good stuff.

Ok, so now, we can type something like 'http://mysite.com/foo/bar' and it will silently redirect to 'http://mysite/com/index.php/foo/bar'. So now all we have to do is set up index.php to handle the incoming request. Now, there are lots of more object oriented ways to do this, but for my purposes, the simple procedural way works best: a switch statement.

< ?
//A file with all the common configuration, like web roots, security,
//database, language, etc.
require_once('lib/config.php')

//Your header, the same regardless of the page
require_once('parts/header.php')

//This is the content area that will change based on the URL. 
//My div is called 'textarea'. Yours might be called something else.
//echo "
"; //The switch statement $url = substr($_SERVER['REQUEST_URI'], strlen(URLROOT)); switch($url){ case (''): require_once('pages/root.php'); break; case ('foo'): require_once('pages/foo.php'); break; case ('bar'): require_once('pages/bar.php'); break; default: //the default is an error! require_once('pages/error.php'); break; } //End your content div here //echo ''; //Your footer, the same regardless of the page require_once('parts/footer.php') ?>

That's it. No mystery. In that first line of PHP ($url = …), I get the path string that's in the address bar – so this will show what the user typed before we did the redirect. Then, in my config.php I've set a global variable called 'URLROOT' that corresponds to the path in my local environment. Using substr, I snip out only the part of the path that comes after the root, and feed that to my switch statement.

Like I said, I'm sure a more experienced coder has 1000 better ways to do this. But, give it a try. It worked for me!