61

当用户单击下载链接时,我正在尝试下载文件。

在控制器中:

    $response = new Response();
    $response->headers->set('Content-type', 'application/octect-stream');
    $response->headers->set('Content-Disposition', sprintf('attachment; filename="%s"', $filename));
    $response->headers->set('Content-Length', filesize($filename));

    return $response;

这是打开对话框以保存文件,但它说文件是 0 字节。并将其更改为:

        $response = new Response();
        $response->headers->set('Content-type', 'application/octect-stream');
        $response->headers->set('Content-Disposition', sprintf('attachment; filename="%s"', $filename));
        $response->headers->set('Content-Length', filesize($filename));
        $response->headers->set('Content-Transfer-Encoding', 'binary');
        $response->setContent(readfile($filename));

        return $response;

我得到一堆奇怪的字符而不是文件下载对话框。

最后,将“setContent”行切换为:

    $response->setContent(file_get_contents($filename));

它返回一个 PHP 错误:

致命错误:允许的内存大小...

关于如何实现这一目标的任何线索?我以前在 PHP 中做过(没有 MVC),但我不知道通过 Symfony2 做这件事会缺少什么......

也许解决方案是在 PHP.INI 中设置 memory_limit,但我想这不是最佳实践......

4

7 回答 7

92

最舒服的解决方案是

use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;

$response = new BinaryFileResponse($file);
$response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT);

return $response;
于 2015-12-03T12:13:07.753 回答
50

我终于在没有 X-SendFile 的情况下解决了这个问题(这可能是最佳实践)。无论如何,对于那些无法让 X-Sendfile apache 模块工作(共享主机)的人,这里有一个解决方案:

// Generate response
$response = new Response();

// Set headers
$response->headers->set('Cache-Control', 'private');
$response->headers->set('Content-type', mime_content_type($filename));
$response->headers->set('Content-Disposition', 'attachment; filename="' . basename($filename) . '";');
$response->headers->set('Content-length', filesize($filename));

// Send headers before outputting anything
$response->sendHeaders();

$response->setContent(file_get_contents($filename));

return $response;
于 2012-10-23T07:19:04.987 回答
15

您不应该使用 PHP 来下载文件,因为这是 Apache 或 Nginx 服务器的任务。最好的选择是使用 X-Accel-Redirect(在 Nginx 的情况下)/X-Sendfile(在 Apache 的情况下)头文件下载。

以下操作片段可以与配置的 Nginx 一起使用以从 Symfony2 下载文件:

return new Response('', 200, array('X-Accel-Redirect' => $filename));

UPD1:配置了 mod_xsendfile 的 apache 代码:

return new Response('', 200, array(
    'X-Sendfile'          => $filename,
    'Content-type'        => 'application/octet-stream',
    'Content-Disposition' => sprintf('attachment; filename="%s"', $filename))
);
于 2012-10-22T11:29:05.340 回答
9

不知道能不能帮上忙,但application/octet-stream没用application/octect-stream

于 2012-10-22T21:13:15.283 回答
9

从 Symfony 3.2 开始,您可以使用file() 控制器助手,它是创建 a 的快捷方式,BinaryFileResponse如前一个答案中所述:

public function fileAction()
{
    // send the file contents and force the browser to download it
    return $this->file('/path/to/some_file.pdf');
}
于 2017-01-03T14:02:17.340 回答
6

+1 亚历山大回应。

但是如果不能使用X-Sendfile,则应该使用2.2中添加的BinaryFileResponse:http: //symfony.com/doc/current/components/http_foundation/introduction.html#serving-files

在我的项目中,结果是

$response = new \Symfony\Component\HttpFoundation\BinaryFileResponse($dir .DIRECTORY_SEPARATOR. $zipName);

$d = $response->headers->makeDisposition(
    ResponseHeaderBag::DISPOSITION_ATTACHMENT,
    $zipName
   );

$response->headers->set('Content-Disposition', $d);

return $response;
于 2015-02-04T06:39:16.803 回答
3

对于那些没有设置标题选项的人:

download属性可能会有所帮助,具体取决于您需要支持的浏览器:

<a href="{file url}" download>

或者

<a href="{file url}" download="{a different file name}">

并非所有旧版浏览器都支持此功能。有关浏览器支持,请参阅此页面:

https://www.w3schools.com/tags/att_a_download.asp

于 2017-03-01T19:50:32.970 回答