【问题标题】:Determining successful download using php readfile使用 php readfile 确定成功下载
【发布时间】:2012-02-04 23:21:00
【问题描述】:

我需要知道用户是否选择了下载然后单击了取消按钮,这与 readfile 有错误不同。我检查了 readfile 函数返回的计数,但即使用户从“另存为”对话框取消下载,它也会显示文件中的字节数。

需要这样做的原因是因为我的网站有一次性下载,其中成员允许其他用途一次下载他们的文件,然后该权限就消失了。但是,如果成员单击下载按钮然后决定不立即下载它,我不希望我的数据库得到更新以显示他们获得了文件。

这涉及知识产权保护,因为文件是上传它们的成员的财产,我需要对其他成员下载文件的确切内容进行审计跟踪,以防它们开始在互联网上传播。但如果 readfile 函数总是反映文件大小(意味着这些字节以某种方式传输),我无法知道文件是否实际下载。

我看过很多关于这个主题的帖子,但是对于经常需要的问题没有真正的解决方案 - 他们是否下载了它?仅仅知道他们点击了下载按钮并不能真正说明他们是否决定继续下载,因为“另存为”对话框允许某人取消下载的实际完成。

为了完整起见,这是我在 readfile 函数之前的下载代码:

    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
    header("Content-Disposition: attachment; filename=$download_name");
    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("sub/$doc_file"));
    ob_clean();
    flush();
    $wasdownloaded = readfile("sub/$doc_file");

【问题讨论】:

标签: php download readfile


【解决方案1】:

您首先需要ignore_user_abort()

这将允许您的脚本在用户点击取消或退出后继续执行。

然后您必须print 输出文件并不断检查connection_aborted()

header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header("Content-Disposition: attachment; filename=$download_name");
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("sub/$doc_file"));
ob_clean();
flush();

$fp=fopen("sub/$doc_file","rb");

while(!feof($fp))
{
    print(fread($fp,1024*8));

    flush();
    ob_flush();
    if( connection_aborted() )
    {
        //do code for handling aborts
    }
}

【讨论】:

  • 您的意思是根本不使用 readfile,这就是这里的结果,对吧?但是 fopen 和 fread 策略是否仍会为用户提供相同的保存/取消对话框以将文件保存到磁盘?
  • 是的,只要您设置了正确的标题,浏览器就会下载而不是显示。文件的输出方式并不能确定文件是“下载”还是“显示”,由标题控制。此外,如果您使用这种方式,请确保在 conneciton_aborted 检查中有退出、死亡或中断调用,否则它将继续将文件发送到服务器输出缓冲区
  • 我想知道连接中止是否仅在文件仍在下载到临时文件时才有效。如果我单击“另存为”框中的取消按钮,上面的代码不会改变动态并且仍然显示为已完成。我用来测试的文件是 50K,所以它下载到下载文件夹中的临时文件的速度比我点击取消按钮要快得多,而且除了依靠它之外,真的不是解决方案
  • 不错。我不知道那个 connection_aborted() 函数。这对我有很大帮助。我会看看我的访问者是否有足够的耐心来下载一些大文件,即使我的网络服务器可以提供很小的下载速度。
【解决方案2】:

在 php.net 上使用此评论:http://www.php.net/manual/en/function.fread.php#72716fclose 上,您将能够确定文件是否已成功下载,因为您正在检查用户是否中止与connection_status() 的连接

【讨论】:

    【解决方案3】:

    我担心正确的答案是“不可能” - 让我解释一下:您可能能够正确地确定文件何时越线,但您无法可靠地确定客户是否将其丢弃或不是。

    示例(按时间顺序):

    • MSIE 上的用户单击下载并显示“保存位置”对话框。
    • 当此对话框打开时,会在后台开始下载。
    • 用户在对话框中四处导航或什么都不做(电话响了,他在说话)
    • 后台下载完成,您的脚本认为下载完成
    • 用户点击“取消”
    • MSIE 删除临时文件,下载内容永远不会以用户可访问的形式存储

    结果:

    • 用户将文件视为“未下载” - 他是正确的
    • 您的应用程序将文件视为“已正确下载” - 这是正确的

    【讨论】:

    • 嗯,这不是好消息。哎呀,在另存为框中有一个显示取消的按钮,但是如果所做的只是不将临时文件重命名为保存的文件,那有什么好处呢?在我看来,任何需要一次性下载的人都必须能够知道它是否真的有效,以便他们可以将其标记为已完成并删除下载权限
    猜你喜欢
    • 2022-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多