服务器设置:Apache 2.2.14,PHP 5.3.1
我使用PHP脚本来提供所有类型的文件,作为具有复杂访问权限的应用程序的一部分。到目前为止,事情进展顺利,但随后我们的一位测试版用户用1000万像素的数码相机拍照并上传。它位于9 MB以北,9785570字节的北部。
出于某种原因,在Safari中(迄今为止仅在Safari中,我在5.0.5上重现了这一点)下载有时会中途停止并且永远不会完成。 Safari只是继续快乐地尝试永远加载。我不能一直重现这个问题 - 如果我反复重载,有时候下载会完成,有时则不会。没有明显的模式。
我正在监控服务器访问日志,在Safari挂起的情况下,我在离开页面后看到相应文件大小的200响应,或取消页面加载,但之前没有。
这是为文件提供服务的代码,包括标头。当下载成功并且我检查浏览器端的标题时,我看到内容类型和大小已正确设置。它是我标题中的东西吗? Safari中的东西?都?
header('Content-Type: ' . $fileContentType);
header('Content-Disposition: filename=' . basename($fpath));
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($fpath));
ob_clean();
flush();
session_write_close();
readfile($fpath);
exit;
进一步公告作为事件保证:
通过人工限制下载速度达到256k / s - 也就是说,将文件分块为256k,并在提供服务之间暂停,如
$chunksize = 1 * (256 * 1024); // how many bytes per chunk
if ($size > $chunksize) {
$handle = fopen($fpath, 'rb');
$buffer = '';
while (!feof($handle)) {
$buffer = fread($handle, $chunksize);
echo $buffer;
ob_flush();
flush();
sleep(1);
}
fclose($handle);
} else {
readfile($fpath);
}
我能够保证在任意条件下在Safari中成功显示图像文件。
512k的块大小并不能保证显示成功。
我几乎可以肯定,这里的问题是Safari的图像渲染器无法更快地处理数据,但是:
只是为了堆积在怪异上,用usleep()设置更细粒度的睡眠会导致500毫秒但不是750毫秒的睡眠时间出现问题。
答案 0 :(得分:1)
我做了一点挖掘并发现了一点具体,但我确实看到很多人断言Safari在遵守缓存控制指令方面存在问题。一个人断言:
你不需要所有那些缓存控件,只需要一个过去设置了Expires的最大年龄,你所使用的所有那些头文件所做的一切[...]你使用的许多缓存控件头都会导致Safari出现问题[...]最后,一些浏览器不理解文件名,唯一的理解名称,必须包含在Content-Type标题行中,从不在Content-Disposition行中。 [...]
(参见帖子中的最后一篇文章:http://www.codingforums.com/archive/index.php/t-114251.html旧信息,但你永远不知道......)
因此可能会注释掉一些标题,并查看是否有改进。
(轶事)我还看到一些老帖子抱怨safari都通过将整个文件附加到部分文件的末尾来恢复中断下载,并且无限下载似乎计算超出发送文件长度的字节数。 (轶事)
答案 1 :(得分:0)
您可能希望在阅读文件时尝试“分块”文件。
PHP.net上有很多帖子解释了如何做到这一点:http://php.net/manual/en/function.readfile.php
尝试:
ob_start();
readfile($path);
$buffer = ob_get_clean();
echo $buffer;