Best way to implement a download counter?

2020-04-10 06:17发布

Say a user clicks on a link to download a file. The user gets the save as dialogue box but then clicks on cancel. How do you detect this? Meaning if the user hits the cancel link or doesn't get the whole file, the server should not record that the file was downloaded.

标签: php
5条回答
2楼-- · 2020-04-10 06:45

When a server sends a file, it doesn't just stream over the wire instantly, there are ack packets that have to go between client and server sending the file out one chunk at a time.

All one has to do is have some sort of process that sends the file to the user in a managed way, so that you can hook an event on wherever the "last" block of the file is flushed to the user.

Now granted, the user might never recieve this last block, but if they ask for the last block ( which is what ack packets are doing ) then either they, or the underlying network protocol has accepted that they've received all the blocks preceding that last block, and that one may proceed to send the last block.

Now assuming that

  1. Your webserver does no buffering.
  2. That when your webserver blocks your program from executing while it relays the information you are sending.

All one needs is a simple construct like this: ( Pseudo Code ).

1: Open File $foo; 
2: Loop while $foo is not EOF
     3: read  700kilobits from file $foo; 
     4: print 700kilobits of read data to web server
     5: execute webserver 'flush' which blocks until flush is complete. 
     6: <-- Loop
7: If all chunks of 700kilobits were read before user aborted transaction
     8: report file was downloaded. 

Edit Unkwntech's answer is effectively the same as my own.
His answer is however PHP specific and I wanted to provide a more language generic solution, primarily, because I've developed a distaste for PHP, and am loath to need to write code for it and set up a web-server and test it works just to prove a point that I know from experience works.
Apologies for being too lazy in this regard.

查看更多
做个烂人
3楼-- · 2020-04-10 06:55

In the past I have done this:

header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
flush()
log()
exit;

log should only run after readfile is complete meaning the entire file has been streamed to the user. It's been a while since I have done this and I don't know where the exact code is so this may not be exact but it should get you going.

EDIT I found the above code on php.net and it is more or less what I was describing, this method should work.

查看更多
萌系小妹纸
4楼-- · 2020-04-10 07:03

one way would be to write some PHP that handles actually delivering the file in question supplied as a $_REQUEST parameter. That script would do the actual work of logging the download

查看更多
Melony?
5楼-- · 2020-04-10 07:09

Are you talking about any file? If it's a program you can have it make a call to the server on install? Other than that I agree with Jonathan, not really sure you have access to that.

查看更多
家丑人穷心不美
6楼-- · 2020-04-10 07:10

I think some HTTPd's don't log files into the access log until the request is rendered complete. You could try writing something that parses the log, greps the filename, and counts the number of lines.

Edit: Just tried with nginx. Confirmed my theory. I believe the same is true for Apache.

Edit #2: Why was this modded down? It's actually the correct answer according to the dupe-link on SO. I stand vindicated.

查看更多
登录 后发表回答