PHP: Serve a file for download without providing the direct link

Solution 1:

There is even an example of this on php.net

<?php
// We'll be outputting a PDF
header('Content-type: application/pdf');

// It will be called downloaded.pdf
header('Content-Disposition: attachment; filename="downloaded.pdf"');

// The PDF source is in original.pdf
readfile('original.pdf');
?> 

Or expand that a bit with

<?php
if ( can_this_file_be_downloaded() ) {
  header('Content-type: application/pdf');
  header('Content-Disposition: attachment; filename="invoice.pdf"');
  readfile("{$_GET['filename']}.pdf");
} else {
  die("None shall pass");
}
?>

Solution 2:

Sam has the answer. Also put them in a directory with .htaccess:

Authname Private
AuthType basic
require user noadmittance

That will keep out direct access if they know the url. You can still read it from your PHP script with readfile().

Solution 3:

I found for this excellent guide: How to serve big files through PHP.

Especially useful is the lighttpd trick - If your PHP happens to run under lighhtpd, script only needs to set "X-Sendfile" header, and lighttpd will read and send the file for you (and it well knows how to send files).

UPDATE:

Lighttpd has this feature and there is a mod_xsendfile for Apache2.

(Quoted from NginX documentation)