Ok, first thing first, the browser need to know the file location to download it. Anyone opening a standard browser dev tool like Firebug will be able to see in plain text the URL of your file.
Now, I suppose you want to protect your file from unauthorised download. If that is what you want, there is a way for that using session.
On your first page, you will put your code to check if the download is authorized. You will then put in session the current with something that identify the file. Anything that is unique for the file will do, like the database id.
$_SESSION['download_key'] = time();
Then, you redirect to a page with a html meta like this
<meta http-equiv="refresh" content="5;/download.php?file=download_key" />
This is the page where you will say "Thank you fine lad for downloading my awesome file". Note that you can also put the content of the "content" attribute in a header file if you like, like this
Note that the 5 is the number of second until the download file dialog box appear.
Then on download.php you will do the following :
1- Check which file was requested using the $_GET['file'].
2- Then you check if the download_key exists in session. If not, you exit the script like that
if (!isset($_SESSION['download_key'])) die('Unauthorized');
3- Then you check if the timestamps is older than some arbitrary time limit. Here with 30 sec
if ($_SESSION['download_key'] - time() > 30) die('Unauthorized');
4- Finally, if all check out, you send the file like that
header('Content-disposition: attachment; filename=myfile.ext');
header('Content-type: bin/x-file-type'); //Change for the correct mimetype
After the readfile, you will put the code to set the download to 1 in the database.
And that's it, protected file download, and anybody using the URL directly will be greeted by a big "unauthorized" text.
I'd also like to add that if you have a big file (more than say a few kilobyte), you may be better off disabling output buffering, since that will mean that php will keep a copy of the file in memory for the whole duration of the download. With the readfile function, php will send it to the browser as it read it on the disk and thus will use less memory (and will start to send data sooner).
EDIT : What make it work is the following
I actually inverted the sequence : the visitor is first redirected to the thank you page which contain a Refresh header/tag. The magic of the Refresh header is that it redirect AFTER the content is loaded. Once on the thank you page, the browser seeing that header then wait for the specified time while showing the page, then redirect to the download. Once redirected, the browser see that its a file to be downloaded and instead of changing the page, just show the download file dialog. Once the user click OK, the download will start but he will stay on the same page.
In a nutshell, you don't need to redirect after the file download, since you are already on the thank you page! I don't think it's even possible to redirect after a file download. Just look at what happen when you click on a link that point to a direct file on the webserver. The browser prompt for download, but does not cut your navigation. Once the download is started, you can happily click away from the page with the link. By the time the download is over, you may be on a completely different Website. That is why you can only show the thank you page before. But if you put a zero for the refresh header/tag, the download prompt will appear as soon as the page is loaded, so it's almost as if the two were simultaneous (in the eye of the visitor)
Thanks for that, there's a lot in there to help me refine what I've got. However, what I don't understand is what happens when you get to this download page. Because you can't echo anything before the header and you can't echo anything after the header as it is read as part of the file, how can you redirect/link the user back to a page of any substance without them using the back arrow!
Thanks Laurent - that's exactly the way I've gone with now. DOing it in reverse and just getting the scrip to change the header rather than the actual page. And thanks for the tip about ob-flush with big files - hadn't thought of that!