Setting Apache fake files/directories using mod_rewrite

Swobodin's picture
Submitted by Swobodin on Mon, 2006-08-07 09:50. ::
Ever wondered how does Wikipedia use "static" pages (for example: http://en.wikipedia.org/wiki/Linux) whereas it's almost impossible to stock all the files in wiki directory?
The wikimedia platform uses mod_rewrite Apache module which allow to rewrite requested URLs on the fly.
Based on a regular expressions parser, mod_rewrite has complex yet flexible features, which allow you to manipulate the URL. You should have a basic knowledge of regular expressions.
First, configure your httpd.conf to both loading the module and allowing using .htaccess file.
# Loading module
LoadModule rewrite_module modules/mod_rewrite.so
# Allowing user_dir, change the default if any
<ifModule mod_userdir.c>
# Comment this!
#UserDir Disable
UserDir "www"
</ifModule>
# Some parameters in UserDir
<Directory /home/*/www>
#Allowing .htaccess directive
AllowOverride All
Options MultiViews Indexes FollowSymLinks
</Directory>

Restart your Apache server
service httpd restart
Suppose the directory is you are working on is /home/swobodin/www/Lab/rewrite
Let's start with a simple redirection
Create a HTML file called new.html and edit your .htaccess
# Start the engine
RewriteEngine On
# Set the rule
RewriteCond %{REQUEST_FILENAME} ! -f
RewriteCond %{REQUEST_FILENAME} ! -d
RewriteRule ^(.*)\.html$ /~>swobodin/www/Lab/rewrite/new.html [L]
It means the following:

RewriteCond sets a condition, %{REQUEST_FILENAME} is an Apache variable meaning (not too difficult to figure out) the requested file.
Any requested file that ends with html and is not a file (-f) neither a directory (-d) will be redirected to the file new.html. The L flag is like Perl's "last" or C "break", means no other rules can be added if a condition is set before.
If we had to translate the lines above to PHP, it would be like the following;
<?php
if (! is_file($_SERVER['REQUEST_URI']) && ! is_dir($_SERVER['REQUEST_URI'])) {
header("location: /~swobodin/www/Lab/rewrite/new.html");
}
?>

Now, point your browser to http://127.0.0.1/~swobodin/www/Lab/rewrite/anyfile.html
The URL doesn't change, but the content is new.html !
Let's make the operation more useful. Suppose we have req.php that accepts both id and item GET variables.
It should be like the following:
<?php
print "If you see this message then you have been successfully redirected. <br />\n";
if (isset ($_GET['id'])) {
print "id is ".$_GET['id']."<br />\n";
}
if (isset ($_GET['item'])) {
print "id is ".$_GET['i']."<br />\n";
}
?>
How if we changed the argument to an easier to memorize URL, while the directories don't physically exist?
From:
http://127.0.0.1/~swobodin/www/Lab/rewrite/req.php?id=50&item=80
to
http://127.0.0.1/~swobodin/www/Lab/rewrite/50/80/
Edit .htaccess and set the following commands:
RewriteEngine On
ReWrite_Rule ^(.*)/(.*)$ /~swobodin/www/Lab/rewrite/req.php?id=$1&item=$2
Please note: there's a method to make fake files/directories without using the mod_rewrite, but it's more complex and less reliable. It's worth to have a look at anyway:
We want to have the following URL
http://127.0.0.1/~swobodin/www/Lab/rewrite/entry/145
so that it displays: "Entry number 145"
Create a PHP file called "entry" without suffix.
<?php
$url = $_SERVER['PHP_SELF'];
$directory = basename(__FILE__);
$entry = preg_replace("/^.*$a2\/(.*$)/i",'\1',$directory);
// a regular expression to parse the entry number
print "Entry number $entry";
?>
And force the plain text file entry to be executed as PHP file on the server; edit .htaccess:
<Files entry>
ForceType application/x-httpd-php
</Files>
Not really practical, but may be useful when no rewrite mode is available.
This was only an overview about the module. For further information, you may consult http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html