Url Routing with PHP – Part One
Most PHP frameworks use some variation of the front controller pattern to centralize common code and logic. There are advantages and disadvantages to this. I am going to ignore those for now. In fact the first part of this series will explore a simple procedural URL routing method that contains many of the disadvantages. In later articles we will build upon this basis and address the disadvantages.
Requirements
- PHP
- Apache with mod_rewrite enabled.
Redirecting with mod_rewrite
This article doesn't discuss mod_rewrite and the .htaccess in detail, the following .htaccess file is sufficient for the needs of our simple front controller. The .htaccess file should be placed in the same directory as the front controller script. All requests will be sent to index.php while requests for a file or directory that does exist will bypass the mod_rewrite rules and be served directly by the web server.
file: .htaccess
-
Options +FollowSymLinks
-
IndexIgnore */*
-
# Turn on the RewriteEngine
-
RewriteEngine On
-
# Rules
-
RewriteCond %{REQUEST_FILENAME} !-f
-
RewriteCond %{REQUEST_FILENAME} !-d
-
RewriteRule . index.php
The Entry Point
I chose a simple format for the incoming URL, a command followed by its parameters separated by forward slashes "/".
For example:
www.example.com/command/parameter1/parameter2/
in this example $requestURI would contain.
This works fine except in the case where the front controller is not in the root directory.
For example:
www.example.com/myapps/app1/command/parameter1/parameter2/
in this case $requestURI would contain.
-
Array ( [0] => [1] => myapps [2] => app1 [3] => command [4] => parameter1 [5] => parameter2 [6] => )
To filter out the path to the front controller we will need to use the $_SERVER['SCRIPT_NAME'] variable.
In the above example $scriptName would contain.
Array ( [0] => [1] => myapps[2] => app1 [3] => index.php )
Which can be used to remove the path and script name from the URI.
Note: As you can see the explode method leaves an empty array member at the first position. This will be fixed by the following code.
-
-
{
-
if ($requestURI[$i] == $scriptName[$i])
-
{
-
}
-
}
-
After the code above $command would contain.
Array ( [0] => command [1] => parameter1 [2] => parameter2 [3] => )
Dispatching the command
Now that we have a command with its parameters stored in an array it is trivial to handle them via a switch statement. The following is a short example.
-
switch($command[0])
-
{
-
-
case 'commandOne' :
-
break;
-
-
case 'commandTwo' :
-
break;
-
-
default:
-
echo 'That command does not exist.';
-
break;
-
}
Try it out
You can visit examples.phpaddiction.com/urlrouter/part_1/ to see it in action and download the sample code.
Next up
The next part in the series will focus on moving the URL router into a class and out of the global namespace.
Update I've updated the .htaccess per the comment made by DrBacchus.
Comments
39 Responses to “Url Routing with PHP – Part One”
Leave a Reply
that's sweet ! Can't wait to read part-2
Oi Friend,
for script to function correctly is necessary to add the following line before "FOR"
— LINE TO ADD —-
$scriptNameArray = array_values($scriptName);
— LINE TO ADD —-
for($i= 0; $i
Copy and paste seems to have bit me! I've fixed the code now Diego. Thanks for the catch.
Doug
For users of PHP 4.3.0+ I believe lines 4-10 in the second source code example can be simplified by making use of the array_diff_assoc function like so:
$command = array_diff_assoc($requestURI, $scriptName);
Untested, so I could be wrong, but just a thought. Nice tutorial!
array_diff_assoc() may work I haven't tried it either. I picked the longer for loop to make what was happening in the sample code clearer. I'll try it out though and see.
Update:
$commandArray = array_diff_assoc($requestURI,$scriptName);
$commandArray = array_values($commandArray);
The above works fine. The article isn't really about how you parse the URLs though, off hand I can think of dozens of schemes. The point is actually being able to translate some arbitrary format into a command array.. or in later articles a command object.
Your rewrite conditions are slightly inaccurate:
RewriteCond %{REQUEST_FILENAME} !-f [OR]
RewriteCond %{REQUEST_FILENAME} !-d
Because this is an OR condition, the rewrite rule will always be run. (A OR B) is TRUE when either A or B is true. Any argument will always be either (not a file) or (not a directory). You need to remove the [OR] there, otherwise a request for index.php will cause a loop.
What you want is "if it's not a file AND it's not a directory":
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
You are correct, I need to edit the article, in later versions of the sample code I removed the [OR].
How do you use mod_rewrite on the sam server? Thank you!
Why not use something simple like:
substr($_SERVER['REQUEST_URI'], strlen($_SERVER['SCRIPT_NAME']));
to distinguish between the script name and the parameters, then explode on that?
Just an idea.
You might also want to filter out multiple slashes in anticipation of exploding on the '/' as your separator.
$rawParams = preg_replace('@[\/]{2,}@', '/', $rawParams);
It's simply awesome !
Ty
What is the advantage to doing all this? Why not have the PHP script parse the path instead of Apache? Why learn two (possibly conflicting) languages?
I'm not sure I understand your question, The point of the artice is to have the PHP script parse the path.
re: What is the advantage to doing all this?
If you're referring to the usage of mod_rewrite, the point is (IMHO) to hide index.php from the URL so that instead of http://example.com/index.php?action=foo/bar or http://example.com/?action=foo/bar you can use http://example.com/foo/bar
If you're looking for motivation, read http://www.w3.org/Provider/Style/URI
With this method, is it possible to get error404 message at all for non-existent 'pages'?
Hi,
nice tutorial you wrote here. I built a similar class for PHP, that works fine. But now, there's a problem:
I'd like to route urls like the MediaWiki uses. That means urls like http://localhost/user:Test/param1/param2 But when I call these addresses i receive the message (from Apache) that the access has been denied. Do you know any solutions to this problem?
Thanks for the tutorial and greetings
Nice and brilliant script.
So simple.
ANother helpful url is found here.
Routing in php
Php routing
Hi guys,
I'm newbie to all this stuff. I am wondering if i could do the following WITHOUT CHANGING THE URL
http://example.com/foo/bar
to call
http://example.com/foo?article_name="bar"
Thanks in advance
Hi all,
I am wonder whether your Rewrite Rull works with Apache on Window plateform or not.
Here's My Version!
.htaccess
RewriteEngine on
RewriteCond $1 !^(index\.php|img|css|js)
RewriteRule ^(.*)$ /index.php/$1 [L]
.php
abstract class URI {
protected $pathArray = array();
protected $path;
public function __construct() {
global $HTTP_SERVER_VARS;
$this->pathArray = explode("/",$HTTP_SERVER_VARS["REQUEST_URI"]);
}
public function getPathByNumber($pathNumber){
if (substr($this->pathArray[1], -4, 4) == '.php') {
$this->path = mysql_escape_string($this->pathArray[$pathNumber + 1]);
}else {
$this->path = mysql_escape_string($this->pathArray[$pathNumber]);
}
return $this->path;
}
} //ends URI class
Thanks for your tutorial.
[...] here you can find probably a solution for your problem Url Routing with PHP – Part One : phpaddiction __________________ Need a custom web application PHP/MySQL, have a big project please PM Me ! [...]
[...] –see http://www.phpaddiction.com/tags/axial/url-routing-with-php-part-one/ [...]
Thank you for the tutorial. FYI, the link to sample code for part 1 is broken (getting a 500 error).
Hello
As a fresh http://www.phpaddiction.com user i only wanted to say hello to everyone else who uses this site :>
What about to mention something about RewriteBase when files not in root dir!
Example does not have source code for downloading like it is promised there.
This is really helpful, nice code, nice technique, awesome!!!
Thanks a lot mate!
The line 6 in .htaccess must be
RewriteCond %{REQUEST_FILENAME} !-f[AND]
I setup the patter and it works great except for on gliche… I was wondering if anyone else has and issue with image references when an extra slash is added to the URI. i.e. If the url is…
http://www.mysite.com/command/action – images are referenced fine as…
http://www.mysite.com/command/images/my.gif
however if http://www.mysite.com/command/action/ – broken reference as…
http://www.mysite.com/command/action/images/my.gif
Anyone have any thoughts on where to look?
@WB I think you shoudl use tirm('/',$url)…
Hi,
I am new user.
I want to redirect
http://myurl.com/profile/username
to
http://myurl.com/username
I have tried this through .htaccess but CSS and connection breaks.
Is there any other way to do this.
Thanx in Advance.
Hi there,
do someone have any code for htccess or php so that i can redirect my own made extension file to the respective php file, but the browser shows the extension by me.
like if i type a url link
http://www.yourdomain.com/index.jove
but internally it will display the content of http://www.yourdomain.com/index.php
while showing the
http://www.yourdomain.com/index.jove in the browser window.
It doesn't work.
$requestURI is empty.
Hi! I was surfing and found your blog post… nice! I love your blog.
Cheers! Sandra. R.
Hi. Thanks for this Tutorial. I enjoyed it.
Just a minor note on all these attempts to get command and parameters by comparing paths – that's not necessary if you store the request in a $_GET parameter like this:
<samp>RewriteRule (.*) index.php?r=$ [L,QSA]</samp>
This way you can drop all the string comparing and extract all parameters with one <samp>explode('/',$_GET['r']);</samp>
Thanks for this Doug, its a simple post and suppose people have there own ways in which they get round the problem, but it explains the concept to wanabe php developers really well. Quick point Eric (last commentor) point is good but can i would advise newbies to avoid.
Hello,
I have a site made with symfony 1.1 and i whant to change it with
another site made with 1.2.
my proplem is that i whant to change some URL…
For example i have a url thath looks like this on my old site:
http://www.sejur-extern.ro/Egipt/Sharm-El-Sheikh
On my new site it will be:
http://www.sejur-extern.ro/turism-extern/Egipt/Sharm-El-Sheikh.html
How can i get the old url if google sends someone on it…and change
it in my new one?
Thank you!
[...] on the internet about URL routing i found Axial Routing, i liked it and decided to base my code on that tutorial. I abused the singletons a little and [...]
Agree 100%