服务器设置:Apache 2.2.14, PHP 5.3.1
我使用PHP脚本提供所有类型的文件,作为具有复杂访问权限的应用程序的一部分。到目前为止,一切都很顺利,但后来我们的一个测试用户用一个1000万像素的数码相机拍了一张照片并上传了上去。它在9mb, 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的图像渲染器无法处理更快的数据,但是:
- 我想知道一些我也想知道是否有其他的解决方法,比如一个特殊的CSS webkit属性或任何处理大图像的方法,因为256k/秒对于10mb的文件来说有点可怕。
更奇怪的是,使用ussleep()设置一个更细粒度的睡眠会导致睡眠时间为500毫秒而不是750毫秒的问题
我做了一些调查,发现没有什么特别的,但是我确实看到很多人断言Safari在执行缓存控制指令方面有问题。一个人断言:
你不需要所有这些缓存控件,只是一个max-age与Expires设置在过去,做一切你使用的所有的头[…]你使用的许多缓存控制头会导致Safari出现问题[…]最后,有些浏览器不理解文件名,只理解名称,它必须包含在Content-Type标题行中,而不是Content-Disposition行中。[…]
(见最后一个帖子在线程:http://www.codingforums.com/archive/index.php/t-114251.html旧信息,但你永远不知道…)
所以可能注释掉一些标题,看看是否有改进。
(轶事)我还看到一些旧的帖子抱怨safari通过将整个文件附加到部分文件的末尾来恢复中断的下载,以及没完没了的下载,这似乎超出了正在发送的文件长度。(传闻)
你可能想在读取文件时尝试"chunk"。
在PHP.net上有许多帖子解释了如何做到这一点:http://php.net/manual/en/function.readfile.php
试题:
ob_start();
readfile($path);
$buffer = ob_get_clean();
echo $buffer;