Symfony强制下载响应中断文本文件


Symfony Force Download Response breaks text files

我已经根据这个答案为我的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;
}

由于我仍然不知道是什么导致了不同的行为,它并不像我希望的那样安全可靠,但到目前为止,它做得很好。