我已经根据这个答案为我的Symfony应用程序创建了一个函数:https://stackoverflow.com/a/13025363/1749653
功能如下:
public function getForceDownloadResponse($file_path, $file_name){
$file_info = finfo_open(FILEINFO_MIME_TYPE);
$mine_type = finfo_file($file_info, $file_path.$file_name);
finfo_close($file_info);
$response = new Response();
$response->headers->set('Cache-Control', 'private');
$response->headers->set('Content-type', $mine_type);
$response->headers->set('Content-Disposition', 'attachment; filename="' . $file_name . '"');
$response->headers->set('Content-length', filesize($file_path.$file_name));
$response->sendHeaders();
$response->setContent(readfile($file_path.$file_name));
return $response;
}
一切都很顺利。。。直到有人尝试用它下载文本文件。由于某些原因,所有文本文件都是用错误的文件名下载的。它们都遵循这样的模式:实际文件名-,附件例如:newtext.txt-,attachmentetc
经过一番调查,我只发现整个文本文件有一处不规则。不知怎的,响应头字段被复制了。二进制文件将输出如下内容:
Cache-Control:private
Connection:close
Content-Disposition:attachment; filename="Jellyfish.jpg"
Content-Length:775702
Content-Type:image/jpeg
Date:Mon, 10 Nov 2014 09:14:41 GMT
Server:Apache/2.4.7 (Win32) OpenSSL/1.0.1e PHP/5.5.6
任何文本文件都将如下所示:
Cache-Control:private
Cache-Control:private
Connection:Keep-Alive
Content-Disposition:attachment; filename="full.txt"
Content-Disposition:attachment; filename="full.txt"
Content-Length:15
Content-Type:text/plain; charset=UTF-8
Date:Mon, 10 Nov 2014 09:06:00 GMT
Keep-Alive:timeout=5, max=97
Server:Apache/2.4.7 (Win32) OpenSSL/1.0.1e PHP/5.5.6
我怀疑这种非故意行为的根源在于导致ContentHeader行为的原因。但我一辈子都搞不清楚这些是怎么发生的。
因此,如果有人更多地了解这些是如何产生的,是什么可能导致他们这样做,甚至是如何彻底解决问题,我们将不胜感激。
终于想通了。张贴在这里,以防有人,某个地方有类似的问题,并发现它很有用:
所以。事实证明,有问题的线路是这样的:
$response-sendHeaders()
对于二进制文件,这一行对于它的工作至关重要。文本文件不需要它,事实上会像上面看到的那样崩溃。我还没有弄清楚它为什么会这样。但解决方案是简单地检查请求的文件是否是文本文件。(除了.html文件的内置例外,但这更多的是项目的可选功能/怪癖,因此可以安全地忽略)
这就是这个功能现在的样子,它工作得很好:
public function getForceDownloadResponse($file_path, $file_name){
$file_info = finfo_open(FILEINFO_MIME_TYPE);
$mime_type = finfo_file($file_info, $file_path.$file_name);
$text = (substr(finfo_file($file_info, $file_path.$file_name), 0, 4) == 'text') ? 1 : 0;
finfo_close($file_info);
$response = new Response();
$response->headers->set('Cache-Control', 'private');
$response->headers->set('Content-type', $mime_type);
$response->headers->set('Content-Disposition', 'attachment; filename="' . $file_name . '"');
$response->headers->set('Content-length', filesize($file_path.$file_name));
if(!$text || $mime_type == 'text/html'){
$response->sendHeaders();
}
$response->setContent(readfile($file_path.$file_name));
return $response;
}
由于我仍然不知道是什么导致了不同的行为,它并不像我希望的那样安全可靠,但到目前为止,它做得很好。