您可以使用以下代码在 Symfony 中提供文件:
$response = new BinaryFileResponse($filepath);
// Set headers
$response->headers->set('Cache-Control', 'private');
$response->headers->set('Content-Type', $file->getMimeType());
$response->headers->set('Content-Disposition', $response->headers->makeDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
$file->getName()
));
return $response;
确保您还拥有:
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
如何获得$file 在您链接的Finder component 的文档中进行了说明。当您将代码放在 AppBundle 中的控制器中时,您可以使用:
$filepath = __DIR__ . '/../Resources/myfile.txt';
或者您可以使用相对于您的应用程序根目录的路径:
$rootDir = $this->get('kernel')->getRootDir();
$filepath = $rootDir. '/src/AppBundle/Resources/myfile.txt';
$filepath 也可以是绝对路径,但请确保网络服务器可以从该路径读取。只要您使用网络服务器 docroot 之外的路径(可能是 <your app root>/web),您就可以使用投票者和 PHP 中的其他自定义逻辑来控制对文件的访问。
获取 $file 对象:
为了构建您的文件对象,您可能会使用 Finder 组件,但这实际上只不过是 SPL filehandling 的包装器。因此,您也可以使用:
$file = new \SplFileInfo($filepath);
为什么选择 BinaryFileResponse?
发送大文件时,PHP 可能会将整个文件读入内存,然后再将其作为响应发送给客户端。这可能会导致 PHP 内存不足。使用BinaryFileResponse 通过逐块读取文件并将这些块流式传输到客户端来避免这种情况。因此,切勿使用Response 对象发送大文件。
使用 X-Sendfile:
虽然使用上面的代码可以防止 PHP 内存不足,但它仍然会在发送文件时让 PHP 保持忙碌。当您有一个繁忙的网络服务器时,您可能希望尽可能多地保留 PHP 进程以免费呈现网页,而不是流式传输文件。
幸运的是,而不是这个:
Request ----> Webserver ----> PHP-FPM ----> File
Response <--- Webserver <---- PHP-FPM <---- File
你可以这样做:
Request ----> Webserver ----> PHP-FPM
Response <--- Webserver <---- PHP-FPM
^ |
| |
| V
File
这是通过使用X-Sendfile 完成的。
太邪恶了,怎么用?
让X-Sendfile 工作需要两个简单的步骤:
- 在您的响应中添加一个标头,告诉您的网络服务器它应该提供一个文件。
- 配置您的网络服务器以读取该标头并实际服务器该文件。
标头的名称以及您的网络服务器的配置方式取决于您使用的网络服务器类型:
请注意,Nginx 将其称为 X-Accel。您传递给 Nginx 的标头是 X-Accel-Redirect,但这是唯一的区别。