Apache mod_rewrite? Pah! Rewriting URLs without using mod_rewrite
Written by Richard Heyes, RGraph author, on 23rd June 2021
If there's anything that strikes fear into many-a-developers heart and turns it to stone,
it's having to face the prospect of writing mod_rewrite
Apache
directives.
Actually, it may just be me, but I really don't like it.
So why do it at all? I've just converted the RGraph website to use a different way of doing
things that is far more straightforward and easier to handle, particularly if you're
comfortable with a server-side scripting language like php
.
I've been using php
now for over 20 years and whilst I'm not fully au-fait on recent versions
or additions to the language (the last version I used as a fully-paid-up server-side
developer was around the version 5.2 era) I'm still very confident with it when you
compare it with something like, say, Apache
configuration. Particularly my hosting company's
version of it which I'm adamant is not a standard implementation.
So imagine my sheer delight when I had the random thought (which I presume others might have
had long, long ago) of handling rewrites with php
. Oh, how wonderful that would be. So that's
what I've done with the RGraph website and oh how well it works! It's so much easier to
work with from day to day and has the potential to save a lot of time and heartache.
How does it work?
It's very simple to implement and involves a small snippet of Apache
configuration
(which is not that difficult to understand) and a php
script (which can be as simple or as
complex as you wish).
This small snippet of Apache
configuration can go in a .htaccess
file and, in my
case, goes in the .htaccess
file in each directory (I only have a small number
of directories on the website). This example is from the .htaccess
file which
is located in the /blog
directory.
RewriteEngine On RewriteBase /blog RewriteCond %{REQUEST_URI} !-d RewriteCond %{REQUEST_FILENAME} !\.(png|gif|jpg|jpeg|css|js|ttf|xml|bz2|gz|tar|zip|csv)$ RewriteRule .* _router.php [L]
Now, breaking that down, the first line turns on mod_rewrite
, the second line
(which may or may not be required - I'm sure that I've not used it in the past) sets the
directory (this file is located in the /blog
directory remember) and the
third, fourth and fifth lines are the rewrite rules which send everything to the _router.php
php
script. Let's break down that rule (RewriteRule .+ _router.php [L]
):
The RewriteRule
is the name of the directive,
the .+
matches the filename (one or more characters in this case - so any filename)
and the _router.php
is the name of a php
script (located in the /blog
directory) that handles the job of looking
at the request and deciding what to do with it. the [L]
flag tells mod_rewrite
that this is the last rule. It's not really needed in this case as there's nothing else in the
.htaccess
file.
So what happens then? Well, in the _router.php
script, it's a simple matter of
either redirecting to a different URL or, if you want to keep the URL in the navigation bar,
show the correct content. So you can:
-
Redirect by sending the relevant
http
headers like this:http_response_code(301); // Send a permanent redirect response code header('Location: ' . '/some/where/else.html'); // Send the new location header exit; // End the PHP script
-
Show the relevant content. In this case, if you want to keep the URL in the address bar,
you can use the
require
orinclude
php
functions to show the correct content like this:$file = basename($_SERVER['REQUEST_URI']); if ($file === 'authors') { require('authors.html'); exit; }
Or alternatively if the file exists on your filesystem you could just show it:$file = basename($_SERVER['REQUEST_URI']); if (file_exists($file) { require($file); exit; }
What happens with subdirectories?
If you have a .htaccess
file and a _router.php
in the /blog
directory (for example) then due to the way that .htaccess
files are handled by Apache
,
the /blog/.htaccess
file will be checked even when you're requesting a file in a
subdirectory.
So if you request the file /blog/foo/bar.html
in your browser then the
/blog/.htaccess
will be checked and the /blog/_router.php
file (or
whatever you may have called it) will be called. In that case, the $_SERVER['REQUEST_URI']
PHP
variable will contain the full address of the page, which in this example is
/blog/foo/bar.html
.
What if I've turned off override files?
If you've turned off override files (.htaccess
is an override file) then this
method provides an extra advantage. Normally, editing the server configuration files requires
you to restart the server for any changes to be picked up but with this method, you wouldn't be
editing the server configuration files to add a redirect/rewrite. You would add the above
configuration once and then to add a new redirect/rewrite or to modify an existing one you can just
change the _router.php
file and the new change is effective immediately.
Performance considerations
Unless your server is experiencing meltdown
levels of traffic then you're unlikely to notice any difference in performance. The extra
versatility that this method brings (especially if you're comfortable with php
) compared to
having to struggle with Apache
configuration and mod_rewrite
directives is well
worth it in my opinion.