实现下载计数器的最佳方式?

时间:2009-01-14 01:45:21

标签: php

假设用户点击链接下载文件。用户将保存为对话框,然后单击取消。你怎么发现这个?这意味着如果用户点击取消链接或没有获得整个文件,则服务器不应记录该文件已下载。

5 个答案:

答案 0 :(得分:3)

过去我做过这个:

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只应在readfile完成后运行,这意味着整个文件已经流式传输给用户。我已经有一段时间了,我不知道确切的代码在哪里,所以这可能不准确,但它应该让你去。

编辑我在php.net上找到了上面的代码,它或多或少是我所描述的,这种方法应该工作。

答案 1 :(得分:2)

我认为在请求完成之前,某些HTTPd不会将文件记录到访问日志中。你可以尝试编写一些解析日志的东西,压缩文件名,并计算行数。

编辑:刚试过nginx。证实了我的理论。我相信Apache也是如此。

编辑#2:为什么这个改变了?根据SO上的欺骗链接,它实际上是正确的答案。我站得住了。

答案 2 :(得分:1)

当服务器发送文件时,它不会立即通过网络流,有一些ack数据包必须在客户端和服务器之间进行,一次发送一个数据块。

所有人必须做的是拥有某种以托管方式将文件发送给用户的进程,以便您可以将事件挂钩到文件的“最后”块刷新给用户的任何位置。

现在被授予,用户可能永远不会收到最后一个块,但如果他们要求最后一个块(这是ack数据包正在做什么),那么他们或者底层网络协议已经接受他们已经收到所有在最后一个块之前的块,并且可以继续发送最后一个块。

现在假设

  1. 您的网络服务器没有缓冲。
  2. 当您的网络服务器阻止您的程序执行时,它会传输您正在发送的信息。
  3. 所有人都需要这样一个简单的结构:(伪代码)。

    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. 
    

    编辑 Unkwntech的答案与我自己的答案实际上相同 然而,他的答案是PHP特定的,我想提供更多的语言通用解决方案,主要是因为我已经厌恶PHP,并且不愿意为它编写代码并设置Web服务器并测试它的工作原理只是为了证明我从经验中所知道的一点 抱歉在这方面太懒惰。

答案 3 :(得分:0)

你在谈论任何档案吗?如果它是一个程序,你可以让它在安装时调用服务器?除此之外,我同意Jonathan的意见,并不确定你是否可以访问它。

答案 4 :(得分:0)

一种方法是编写一些PHP来处理实际提供有问题的文件,作为$ _REQUEST参数提供。该脚本将执行记录下载的实际工作