Prevent Direct Access of Files With PHP

A common problem new developers encounter is when they have an area of their website made private, how do they prevent non-logged-in users from going straight to a non-php file like a word document? There are solutions involving htaccess files but these typically can’t easily be integrated with your PHP user management system. The quick and dirty solution is to store the files above the webroot (can’t access it via http) and use a PHP script like this one to check if the user is logged-in and if so, stream them the file.

Here’s a quick one I wrote up- this should get you started:

< ?php
/***************************************************
* This file will serve up files that are stored
* above the web root. For members-only files.
****************************************************/

// CHECK FOR MEMBER LOGGED IN HERE, or include this into a file
// which already checks for member logged in..

// ****** Array of Private Files*******

$privateFilesPath[1] = "/home/username/privatedocs/file1.doc";
$privateFilesName[1] = "file1.doc";
$privateFilesMime[1] = "application/msword";

$privateFilesPath[2] ="/home/username/privatedocs/file2.txt";
$privateFilesName[2] = "file2.txt";
$privateFilesMime[2] = "text/plain";

// *************************

$index = intval($_GET['id']);

if(array_key_exists($index, $privateFilesPath)){

	$filepath = $privateFilesPath[$index];

	header('Content-Description: File Transfer');
	header("Content-type: ".$privateFilesMime[$index]);
	header("Content-Disposition: attachment; filename=".$privateFilesName[$index]);
	header("Content-Length: " . filesize($filepath));
	header("Cache-Control: private"); // Required for IE6 opening PDFs.

	ob_clean();
	flush();
	readfile($filepath);

}else{
   echo("File Not Found.");
}


exit(); // Remove this if including this script into another file.

?>

(EDIT: Nov. 7, 2008 – made some corrections to the provided code.)
If you are getting an error opening PDFs like this: “There was an error opening this document. This file cannot be found.”, you need this header: header(“Cache-Control: private”);