9

What is the best possible way to detect if a download is completed, because afterward I want to update the database.

I tried some of this code from the PHP manual, but it doesn't do much for me:

header("Content-Type: application/octet-stream"); 
header("Content-Length: ".filesize($file)); 
header("Content-Disposition: attachment; filename=$filename");

// buffered read not using readfile($file);

if ($fp = fopen($bestand, 'rb')) {
    while (!feof($fp)) {
        $buf = fread($fp, 4096);
        echo $buf;
        $bytesSent += strlen($buf);    /* We know how many bytes were sent to the user */
    }     
 }

if ($bytesSent == filesize($fp)) {
    //do something with db
}
reformed
  • 4,505
  • 11
  • 62
  • 88
Richard
  • 4,516
  • 11
  • 60
  • 87
  • im found a good solution implemented pure PHP: http://bytes.com/topic/php/answers/551302-how-detect-if-file-download-completed-cancelled – stefcud Aug 25 '11 at 16:08

5 Answers5

9

That's not really going to tell you if the download has completed for the user. It will tell you when you have finished sending bytes to the user, but it says nothing about how many of them the user has actually received.

In reality, there is no way with PHP (which is a server-side, not a client-side, language) to truly detect when a file download has completed. The best you can do is log the download in your database when it begins. If you absolutely, completely and totally need to know when the download has completed, you'll have to do something like embed a Java applet or use Flash. However, usually that is not the correct answer in terms of usability for your user (why require them to have Java or Flash installed just to download something from you?).

Marc W
  • 19,083
  • 4
  • 59
  • 71
  • yes, I have implemented that, and gave a return message to contact me if anything went wrong. I also used a jquery plugin to get a callback when completed and I have no page refresh. – Richard Oct 20 '09 at 09:41
  • http://php.net/function.ignore_user_abort - http://www.php.net/connection_aborted – hakre Mar 13 '13 at 12:56
  • @hakre for connection_aborted from the doc : When running PHP as a command line script only (tty). – Mike Castro Demaria Jan 11 '14 at 08:04
2

As Marc W's already pointed out php can only tell you what you've sent from the server, not what the client's received, so using strictly php is a non-starter.

But there is always the possibility of asking the user to confirm the download by pressing a button that calls a JS check by generating an MD5 hash and comparing that to the MD5 hash of the file on your server (the on-server MD5 being generated by you), and on a successful comparison use that JS script to update your db or use it to call a php-script to do the same.

You could always just ask them to check the download is what they expected and, if they hit "yes, it's fine" then update the database.


Edited: in response to OP's comment.
Thanks, but you can't depend on the users cooperativeness. Because they also have to pay for the download, it is better that I have all the controll.I think I will then update the database when the script is accessed. That seems to be the most reliable then.

How about using an Ajax control to initiate -and maintain- the download, and, on completion verifying its integrity and running an update to your db?

I'd suggest not automatically assuming your customers are going to rip you off, though, whatever you end up choosing. Asking them nicely 'did it work for you?' and, if not, leading to a bug-report might be useful for you and them.

But, regardless, while some of your users might say 'no' just for the extra copy you have to balance the cost of that against the cost of your increased workload to prevent its happening. If the cost of maintaining 'honesty' exceeds the potential/likely cost of their taking an extra copy, then there's little point.

David Thomas
  • 249,100
  • 51
  • 377
  • 410
  • Thanks, but you can't depend on the users cooperativeness. Because they also have to pay for the download, it is better that I have all the controll.I think I will then update the database when the script is accessed. That seems to be the most reliable then. – Richard Oct 14 '09 at 04:44
  • Thanks for your extra input, but you ran over the fact that you mentioned that there is an ajax way. Do you have an example for that? – Richard Oct 14 '09 at 11:12
  • Unfortunately, I don't. I don't know JS/jQuery/Ajax well enough to offer a solution. It might be worth your editing your original question to include a request -and re-tag- for Ajax, JS and/or jQuery solutions. I'm sorry I can't be of more use to you in this. – David Thomas Oct 14 '09 at 16:24
1

I don't think it's possible via php to know how many bites have been sent out (and actually downloaded via the client), since there's no way to know if the user has cancelled the download or received the entire file.

Ben Rowe
  • 28,406
  • 6
  • 55
  • 75
0

There is a solution if you are mixing php (for server side call ) an javascript (for client complete call) .

Look this answer on how to Detect when browser receives file download

I'm pretty sure you can have a good result like this. I hope this help others, Mike

Community
  • 1
  • 1
-4

The following code works. If the download is stopped by the client, the database is not updated and the link can fire again.

  $file='pathto.zip';

  header("Content-type: application/zip");
  header("Content-Disposition: attachment; filename=$file");
  header("Pragma: no-cache");
  header("Expires: 0");
  readfile("$file");

  $sql = "UPDATE YOUR TABLE"; 

  exit;
Francois
  • 27
  • 3
  • This does not work. `readfile` can't tell if the user has canceled. It returns without error, assuming the file is small enough to fit in the output buffer in one go, and then the code proceeds to the database update. Nothing is propagated upwards from the TCP layer to indicate delivery to the other side of the pipe. – David G Mar 19 '13 at 22:58