tags:

views:

313

answers:

5

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.

A: 

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.

Sean
+2  A: 

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.

Andrew
I'm not sure why some things here are modded down. I just had a question I submitted "closed" by somebody because "it wasn't a real question," when in fact it was.
Jonathan Sampson
I changed my vote after reading it a second time, The structure of your sentence lead me to mis-interpret it the first time for some reason.
Kent Fredric
A: 

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

Scott Evernden
+1  A: 

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.

Kent Fredric
very interesting - and have you tested this solution?
Steven A. Lowe
@kent thanks for the note I was going to point that out but I didn't want to sound like an ass.
Unkwntech
+2  A: 

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.

Unkwntech
This only works for huge files
jdelator
This should work for any file, regardless of size, readfile streams the file to the user log cannot be run until readfile has completed.
Unkwntech
I would put a "flush" call after readfile(); just to be safe.
Kent Fredric
Also, with my recent upvote, your score reads "5432", congrats :D
Kent Fredric
@kent you'r probably correct about the flush, I intend to do some testing a bit later so see for sure, and I didn't even notice the 5432 until you said it. LOL THX.
Unkwntech
I was going to post what Kent said. A final flush ensures the file was "sent". Of course even this doesn't stop the user from hitting cancel.
jmucchiello
I havn't had the opertunity to test it, but it makes sense so I have added it.
Unkwntech
It does not work; the web server does not block while the save as dialog is on the user's screen. What happens is that PHP sends the I/O request to the web server, which in turn hands it off the the O/S. It only seems to work because with larger files, "cancel" terminates PHP before the I/O is done.
Nathan Strong