Looking to serve up images outside your document root? This article will discuss how to do this with Apache and PHP.
Storing your images away from your server's document root is a good design decision if you don't want anyone knowing where the true file path is.
Because your HTML markup is exposed, anyone knows where your images are stored.

In the example above, it is clear where the image is stored relative to the document root. This poses potential abuses such as someone hotlinking to image.jpg fully knowing the location. For people who run image intensive sites like photo galleries and photography websites, you may want to keep this path out of sight by using what I will call a image proxy locator using your favorite programming language.

Here we slide in a PHP file to be executed in the src attribute of an HTML image tag. Alogn with it a query string that specifies the filename of the image. Hidden is the true location of the the image file.
imagelocator.php
class ImageLocator {
static $allowedMimeTypes = array("jpg" => "image/jpeg",
"png" => "image/png",
"gif" => "image/gif");
static function ValidateImagePath($basepath, $filename) {
// Make sure filename is set
if (!isset($filename))
ImageLocator::SendErrorHeader(404);
// Make sure filename has minimum length (.ext)
if (strlen($filename) <= 4)
ImageLocator::SendErrorHeader(404);
// Make sure its a legal image extension
$pathParts = pathinfo($filename);
if (!array_key_exists($pathParts["extension"], ImageLocator::$allowedMimeTypes))
ImageLocator::SendErrorHeader(404);
// Fix up directory separators
$bLastChar = substr($basepath, -1, 1) == "/" ? true : false;
$bFirstChar = substr($filename, 0, 1) == "/" ? true : false;
if ($bLastChar && $bFirstChar)
$imagepath = substr($basepath, 0, strlen($basepath)-1) . $filename;
elseif (!$bLastChar && !$bFirstChar)
$imagepath = $basepath . "/" . $filename;
else
$imagepath = $basepath . $filename;
// Make sure the image file exists
if (!file_exists($imagepath))
ImageLocator::SendErrorHeader(404);
return($imagepath);
}
static function SendErrorHeader($error) {
switch($error) {
case 400:
header("HTTP/1.0 400 Bad Request");
break;
case 401:
header("HTTP/1.0 401 Unauthorized");
break;
case 403:
header("HTTP/1.0 403 Forbidden");
break;
case 404:
default:
header("HTTP/1.0 404 Not Found");
break;
}
// no more processing needed
exit;
}
static function SendImageHeader($imagepath) {
$pathParts = pathinfo($imagepath);
$extension = $pathParts["extension"];
$mimeType = ImageLocator::$allowedMimeTypes[$extension];
header("Content-type: image/" . $mimeType);
readfile($imagepath);
}
}
// This gets executed via the img src
$imagePath = ImageLocator::ValidateImagePath("C:/MyPics", $_GET["filename"]);
ImageLocator::SendImageHeader($imagePath);
Take the PHP code above and save it to your document root on your Apache server. Call the file imagelocator.php.
Now notice above the path to "C:/MyPics". In this case I'm running this on a Windows XP client but you could change this as appropriate if you have Linux running. This is the real path to the location of your images. You will definitely want to change this.
Next place the test.jpg file in this directory and then go to your browser and surf to imagelocator.php. You should now see the image appear.