Symfony2 - 强制文件下载

Xav*_*avi 53 php header download symfony

我正在尝试在用户点击下载链接时下载文件.

在控制器中:

    $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;
Run Code Online (Sandbox Code Playgroud)

这是打开保存文件的对话框,但它说文件是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;
Run Code Online (Sandbox Code Playgroud)

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

最后,将"setContent"行切换为:

    $response->setContent(file_get_contents($filename));
Run Code Online (Sandbox Code Playgroud)

它返回一个PHP错误:

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

关于如何实现这一点的任何线索?我之前在PHP中做过(没有MVC),但我不知道通过Symfony2做什么可能会遗漏...

也许解决方案是在PHP.INI中设置memory_limit,但我想这不是最好的做法......

den*_*ite 84

最舒服的解决方案是

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

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

return $response;
Run Code Online (Sandbox Code Playgroud)

  • 这应该是Symfony2/3的接受答案.很好的解决方案! (6认同)

Xav*_*avi 49

首先,感谢大家的回复.我终于在没有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;
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助!

  • 最后一行是错误的:它将文件长度附加到响应.(readfiles将文件内容发送到输出缓冲区并返回文件长度,该文件长度也通过响应发送给用户) (3认同)
  • 我认为`return $ response;`代码末尾缺少`. (3认同)
  • 谢谢.它节省了我的时间. (2认同)

lis*_*nko 14

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

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

return new Response('', 200, array('X-Accel-Redirect' => $filename));
Run Code Online (Sandbox Code Playgroud)

UPD1:配置了mod_xsendfile的apache代码:

return new Response('', 200, array(
    'X-Sendfile'          => $filename,
    'Content-type'        => 'application/octet-stream',
    'Content-Disposition' => sprintf('attachment; filename="%s"', $filename))
);
Run Code Online (Sandbox Code Playgroud)


Pas*_*cal 8

不知道它是否可以提供帮助,但事实application/octet-stream并非如此application/octect-stream


COi*_*Oil 7

从Symfony 3.2开始,您可以使用file()控制器助手,它是创建BinaryFileResponse前面答案中提到的快捷方式:

public function fileAction()
{
    // send the file contents and force the browser to download it
    return $this->file('/path/to/some_file.pdf');
}
Run Code Online (Sandbox Code Playgroud)


Jay*_*ion 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;
Run Code Online (Sandbox Code Playgroud)