向Safari提供大型(图像?)文件时出现问题


Problem serving large (image?) files to Safari

服务器设置: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;