« All Software Development Articles

Simple Control / Routing in PHP using Mod_rewrite

10/17/2017

Introduction

On many modern sites visitors will see a descriptive URL, one that may contain the name of the article or app they are using and does not contain query string parameters. These addresses are commonly believed to be popular for search engine optimization (SEO) and simply look nice.

Install and Configure Mod_rewrite

For a simple version of how to achieve this on a LAMP stack, start by activating mod_rewrite in Apache 2.4. On Ubuntu/Debian based systems enter the following commands.


sudo a2enmod rewrite
sudo apachectl restart

Now we will modify the Apache configuration to allow .htaccess files to modify configuration based on the current directory. Edit the configuration file at /etc/apache2/apache2.conf. Assuming you are hosting your site out of /var/www/html, locate the section with the starting block . Ensure this section has the AllowOverride setting set to All. Following symlinks is often useful as well. Require all granted means to allow access to any files under that directory. The block for should look like the following.


<Directory /var/www/>
    Options FollowSymLinks
    AllowOverride All
    Require all granted
</Directory>

I prefer to remove the Indexes option as I don't like to reveal files but that is a personal preference. Again restart Apache with the apachectl command above.

Htaccess File

To create the redirect file, create a file named .htaccess (beginning with dot) at the root of your web directory. Note that .htaccess file rules are inherited for subdirectories, with subdirectory .htaccess rules taking precedence. In that file add the following lines.


RewriteEngine On
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^(.*)$ ./index.php/$1

The first line enables the rewrite engine for this directory. The second line sets the engine to only rewrite for files that don't exist. This allows other static content like images and scripts to be served normally. The last line says that any address that passes the condition in the line above should be rewritten as /index.php/[URL].

  The RewriteCond above does have the drawback that any PHP file (or other file) that exists will be served normally if the URL is correctly typed, bypassing your control/routing. This is something to take into consideration when developing your framework and can be fixed by more advanced RewriteCond rules. For example, one I saw is RewriteCond %{REQUEST_URI} !\.(jpg|png|css|js)$ which would take effect for any file not ending in those extensions. As in all PHP applications, be aware not to place backend code (data access, security, etc.) in PHP files that could be accessed directly by clients.

Control / Routing

One way to begin processing the incoming request is to parse the $_SERVER['PHP_SELF'] environment variable along with $_SERVER['REQUEST_URI']. Something like below can parse out your base path and intended sub path.


$index_pos = strpos($_SERVER['PHP_SELF'], "index.php");
$base_path = substr($_SERVER['PHP_SELF'], 0, $index_pos);
$navPath = substr($_SERVER['REQUEST_URI'], strlen($basePath));

  If you have query strings coming in you may need to strip them off while parsing. Experiment and see what these variables hold.

Capturing the base path is often useful for creating sites that might move around their path, such as in a development environment versus a production environment. The rewrite path is the remainder of the path and can be used to look up an article slug in a database or whatever purpose you need. You can choose to do some backend work, route to a view, leverage classes and implement an MVC structure, or simply include another PHP file for display.

Done

Thanks for reading about how to generate pretty URLs on your LAMP stack. Feedback? Did I get something wrong? Let me know on my contact page.

Have a nice day.