向Safari提供大(图像?)文件的问题

时间:2011-07-07 16:50:48

标签: php apache safari download

服务器设置: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的图像渲染器无法更快地处理数据,但是:

  • 我想知道某些
  • 我还想知道是否有其他类型的解决方法,如特殊的CSS webkit属性或处理大型图像的任何方法,因为256k /秒对于10 MB文件来说是可怕的。

只是为了堆积在怪异上,用usleep()设置更细粒度的睡眠会导致500毫秒但不是750毫秒的睡眠时间出现问题。

2 个答案:

答案 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;