<?php
$file = "/path/to/some/file.txt";
$filename = basename($file);
if(file_exists($file))
{
// Send download headers
header('Pragma: public');
header('Last-Modified: '.gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate'); // HTTP/1.1
header('Cache-Control: pre-check=0, post-check=0, max-age=0'); // HTTP/1.1
header("Content-Transfer-Encoding: none");
header("Content-Type: application/octetstream; name=\"" . $filename . "\""); // IE & Opera
header("Content-Type: application/octet-stream; name=\"" . $filename . "\""); // The rest
header("Content-Disposition: attachment; filename=\"" . $filename . "\"");
header('Content-Disposition: inline; filename="' . $filename . '"');
header("Content-length: " . filesize($file));
// Send file contents
readfile($file);
}
else
{
echo "Invalid request";
}
?>
<?php // RAY_force_download.php
error_reporting(E_ALL);
// DEMONSTRATE HOW TO CAUSE A FILE DOWNLOAD
// REQUIRED FOR USE WITH THE PHP date() FUNCTIONS
date_default_timezone_set('America/New_York');
// A FILE TO DOWNLOAD - THIS LINK COULD COME IN THE URL VIA $_GET, OR COULD BE GENERATED INSIDE THE SCRIPT
$url = "http://www.LAPRBass.com/piechart.png";
// THE USE CASE FOR THE FUNCTION
force_download($url);
// FUNCTION TO FORCE A DOWNLOAD FROM A FILE
function force_download($filename)
{
// GET THE CONTENTS OF THE FILE
$filedata = file_get_contents($filename);
if ($filedata)
{
// GET A NAME FOR THE FILE
$basename = basename($filename);
// THESE HEADERS ARE USED ON ALL BROWSERS
header("Content-Type: application-x/force-download");
header("Content-Disposition: attachment; filename=$basename");
header("Content-length: ".(string)(strlen($filedata)));
header("Expires: ".gmdate("D, d M Y H:i:s", mktime(date("H")+2, date("i"), date("s"), date("m"), date("d"), date("Y")))." GMT");
header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
// THIS HEADER MUST BE OMITTED FOR IE 6+
if (FALSE === strpos($_SERVER["HTTP_USER_AGENT"], 'MSIE '))
{
header("Cache-Control: no-cache, must-revalidate");
}
// THIS IS THE LAST HEADER
header("Pragma: no-cache");
// FLUSH THE HEADERS TO THE BROWSER?
flush(); // NOT SURE THIS IS NECESSARY
// CAPTURE THE FILE IN THE OUTPUT BUFFERS - WILL BE FLUSHED AT SCRIPT END
ob_start();
echo $filedata;
}
// ERROR
else
{
die("ERROR: UNABLE TO OPEN $filename");
}
}
You can wrap that script with some kind of PHP authentication, perhaps integrating a data base that contains a record showing that the client has paid for the download. You might use a design that is sort of like the "handshake" in this article.
#1. Never keep the actual files in a web-accessible directory.
#2. Use a PHP script to access the file contents from outside the document root, and then stream it to the browser (combination of header() and readfile() lines - about 10-15 lines of code).
#3. Use the script to validate the user's permissions to access the requested file.
The bulk of the work is in step 3, because the "validation" varies per project. The most common and easy method is to have a database backend that gets updated whenever a user makes a purchase of an item, and the script simply checks the user ID when they're logged in to see if they purchased the item. If so, it streams the file. If not, it rejects with a message to indicate they need to purchase the item first.
If you want to be ultra-safe about it, then you generate a random token when the person buys the item. This token is good for one use. When they click on a link that passes the token to the download script, the download script first marks the token as used and then streams the file. This prevents the end user from sharing his credentials and letting others log in and copy the file, too.
However, all this does is handle the server-side permissions. Trying to prevent the file from being physically copied and distributed after it's been downloaded is a different story and that gets FAR FAR more complicated.