有个项目提供文件下载,因为需要检测用户是否完成了下载,有下面一段代码...
ignore_user_abort(true);
if ($fd = fopen($filePath, 'rb')) {
session_write_close();
if ($start_offset > 0)
            fseek($fd, $start_offset);
while (!feof($fd)) {
     print (fread($fd, 16384));
} fclose($fd);
}
if (connection_aborted()){
 ...
}
else {
 ...
}
...现在出现了一个问题是,如果是大文件,没什么事,如果是小文件,当用户看到选择存储目录对话框稍等一会然后点cancel时,服务器端已将文件全部发送了,所以在做if (connection_aborted())时是false
想问问有没有什么方法,在比如说第一个print后发现用户还没有开始下载则暂停print,或者有没有办法禁止诸如buffering之类的以使在用户没有接受是block这个print,也就是print不能返回?不知道解释的清不清楚

解决方案 »

  1.   

    一般来说,我们可以通过直接让URL指向一个位于Document Root下面的文件,来引导用户下载文件。但是, 这样做,就没办法做一些统计, 权限检查, 等等的工作。于是,很多时候,我们采用让PHP来做转发,为用户提供文件下载。 
     $file = "/tmp/dummy.tar.gz"; header("Content-type: application/octet-stream"); header('Content-Disposition: attachment; filename="' . basename($file) . '"'); header("Content-Length: ". filesize($file)); readfile($file);
      

  2.   

    PHP服务端脚本,那是浏览器的行为了,php是有心无力。
      

  3.   

    把 if (connection_aborted()){... 放一个在循环内
      

  4.   


    谢谢版主,等你等的好幸苦,试了你的方法,甚至加上了'Transfer-Encoding:chunked',还是不管用,因为我看到其实在用户选择ok或者cancel之前浏览器已经开始下载了,所以如果是小文件就有几率在他选择之前文件已经下载结束,而connection并没有aborted还有没有其他建议可以我试试??不知道http协议里有没有什么特别隐蔽的header可以禁止用户提前下载啊,我在科幻世界了呵呵
    header('Transfer-Encoding:chunked');
    ob_flush();
    flush();
    ...
    while (!feof($fd)) {
    if (connection_aborted()){
    fclose($fd);
    break;
    }
    $data = fread($fd, 16384);
    if (strlen($data)){
    echo dechex(strlen($data)), "\r\n", $data, "\r\n";
    }

    ob_flush();
    flush();
    }
      

  5.   

    服务器发送header,紧接着是文件数据
    浏览器接收header后,会立即接收后续的数据。在浏览器解析header的同时,下载已经开始了,只不过下载到缓存里的。
      

  6.   

    是否下载完成只能在客户端检测,如果你的项目不能控制客户端就无法检测如果服务器端和客户端都能控制的话,可以在客户端接收完整后返回一个信息给服务器端
    服务器端通过这个信息才能确定
    例如你提到的 Transfer-Encoding:chunked,最后必定是\r\n0\r\n\r\n结束的
    客户端收到这7个字节时返回一个约定的信息给服务器端,服务器端接收到就确定完成如果服务器端没有接收到返回的信息,只能从超时或者捕捉连接异常确认客户端未完成
    建议用socket和keep-alive去做这事如果客户端不能控制,例如只是浏览器访问,是没有返回信息的
    但下载中途按cancel应该会发送一个关闭连接的信息给服务器端,socket能捕捉这个关闭的
    可以检测一下socket.send()发送了多少字节
    不过这样很不靠谱,正如你说的小文件可能已经全部发送了,但客户端只是收进缓存,cancel只是没做写文件或类似move的操作例如csdn的资源下载,好几M大的文件,我通常都是“秒杀”,选好文件名按OK就立即传完了,都不知道csdn怎么做到的……
      

  7.   

    底层协议的问题,跟语言无关,如果双方有约定,php也可以的