URL rewrites with Apache and PHP
We all love fancy URLs.
- You get to hide your file extensions, e.g tinypress.co/about (no .html, .php or whatever)
- You get to do interesting RESTful patterns, e.g
twitter.com/[username]/status/[tweet id]
which are not only good for SEO but are beautiful and can easily be guessed by users.
The common approach to URL rewrites in Apache is to use the popular mod_rewrite. You simply create a .htaccess file where you turn on the rewrite engine (the rewrite mod must be enabled already) and add some rewrite rules.
Here is a sample .htaccess rewrite that “masks” the URL [domain]/showposts.php?tag=php
as [domain]/tag/php
The user types [domain]/tag/php
(or clicks a similar link) and that shows in the address bar. However, under the hood, the url is converted to showposts.php?tag=php
.
Our showposts.php
script will then look something like this.
It is that simple for few rewrites but can get quite complex and messy when you have to handle a lot of rewrites. Let’s look at a scenerio. Consider the Fonenode API for example. There are 5 resources (Response, Calls, Numbers, Groups and Billing) and over 16 methods in all. The endpoint for the methods are like these:
- /v1/calls/
- /v1/calls/quick
- /v1/calls/[call id]
- /v1/responses/
- /v1/responses/[response id]
While it may not be a big deal to write rewrites for 16 endpoints, it is not scalable. As your resources/endpoints grow, it becomes more complex.
Option 2 - Rewrite with MultiViews
One simpler way to achieve rewrite is using the MultiView option. (mod_negotiation must be enabled for this). It is still not an elaborate solution but you can easily use it to
- Hide URL extensions.
- Redirect RESTful URLs to a base file
If we replace out htaccess with this
and create a file tags.php
, we can visit [domain]/tags
instead of [domain]/tags.php
and everything will work as should (as 1 above). If we visit [domain]/tags/php
, Apache serves the tags.php
file i.e redirects to the base file (2 above). The full path is accessible via the $_SERVER['PATH_INFO']
variable and you can use that inside your base script.
So in tags.php
, we can have
Option 3 - using a route file
A completely different approach is to redirect all traffic to a file and that file takes care of routing by matching the intended URL and using switch/if case to include the necessary file. This is more flexible.
Back to htaccess, we can have:
What that means is if the file or directory typed in the address bar doesn’t exist, redirect to route.php?url/user/typed
. So say the user types [domain]/about/company
, the URL is converted to route.php?about/company
in the “background”.
Our route.php
file will then look like this
I try to keep that simple but you should get the idea. By using this method you have just one controller for your routes and you can easily manage lots of URL rewrites. Where it gets interesting is you can create even more elegant solutions using this technique.