Smart 404

How To

I recently reorganized this web site. I renamed many of the pages by changing the file extension from .shtml to .php. In the end I broke a lot of URLs. Yeah, that was bad, but there is a good solution for this problem: the Smart 404.

The Concept

Most web servers allow you to specify your own 404 error page. I created a smart 404.php file that captures the requested URI and does something special depending on what value is in that URI. In my case only the file extension changed. It was easy to write a rule that creates the potential new file name, checks to see if that file exists and redirect the user there if it does exist.

$requestedpage = $_SERVER["REQUEST_URI"];
$basepath = '/usr/local/username/public_html';
$requestedpagephp = str_replace(".shtml", ".php", $requestedpage);
$potentialfile = $basepath.$requestedpagephp;

if (file_exists($potentialfile)) {
   header("Location:$requestedpagephp\n\n");
} else {
    // output html for 404 page
    // like maybe a nice sitemap instead of a less helpful
    // "file not found" message
}

Added Bonus

Chances are that I didn't catch all the bad links within the site. To make sure I know when a 404 event happens, I added code to send me an email containing the URI the user was trying to get to and referring URL (if there is one). Don't add the send command until you think you have fixed all your internal links. Otherwise you will get a LOT of email. Because this is really just a debug tool to fix broken links, you might want to send yourself the email only if the referer is from your site. What is cool about this is that it will also catch broken images.

$referer = $_SERVER["HTTP_REFERER"];
$requestedpage = $_SERVER["REQUEST_URI"];
$basepath = '/usr/local/username/public_html';
$requestedpagephp = str_replace(".shtml", ".php", $requestedpage);
$potentialfile = $basepath.$requestedpagephp;

$recipient = 'email@example.com';
$subject = '404';
$message = "There is a bad link to\n";
$message .= "$requestedpage\n\non\n$referer";
mail($recipient, $subject, $message, "X-Mailer: PHP/" . phpversion());

if (file_exists($potentialfile)) {
   header("Location:$requestedpagephp\n\n");
} else {
    // output html for 404 page
    // like maybe a nice sitemap instead of a less helpful
    // "file not found" message
}