有个项目提供文件下载,因为需要检测用户是否完成了下载,有下面一段代码...
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不能返回?不知道解释的清不清楚
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不能返回?不知道解释的清不清楚
$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);
谢谢版主,等你等的好幸苦,试了你的方法,甚至加上了'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();
}
浏览器接收header后,会立即接收后续的数据。在浏览器解析header的同时,下载已经开始了,只不过下载到缓存里的。
服务器端通过这个信息才能确定
例如你提到的 Transfer-Encoding:chunked,最后必定是\r\n0\r\n\r\n结束的
客户端收到这7个字节时返回一个约定的信息给服务器端,服务器端接收到就确定完成如果服务器端没有接收到返回的信息,只能从超时或者捕捉连接异常确认客户端未完成
建议用socket和keep-alive去做这事如果客户端不能控制,例如只是浏览器访问,是没有返回信息的
但下载中途按cancel应该会发送一个关闭连接的信息给服务器端,socket能捕捉这个关闭的
可以检测一下socket.send()发送了多少字节
不过这样很不靠谱,正如你说的小文件可能已经全部发送了,但客户端只是收进缓存,cancel只是没做写文件或类似move的操作例如csdn的资源下载,好几M大的文件,我通常都是“秒杀”,选好文件名按OK就立即传完了,都不知道csdn怎么做到的……