个性化阅读
专注于IT技术分析

如何从Symfony 3中的控制器发送文件作为响应

本文概述

从控制器返回文件(任何类型的文件)作为响应, 是可以轻松实现的常规任务。要在Symfony控制器中提供静态文件, 建议你使用BinaryFileResponse类。此类表示传递文件的HTTP响应(它扩展了Response类)。

A.在浏览器中返回文件

你可以返回要在浏览器中查看的文件(如果支持), 因为它没有自定义内容配置, 因此直接返回BinaryFileResponse类:

<?php

namespace myBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

// Import the BinaryFileResponse
use Symfony\Component\HttpFoundation\BinaryFileResponse;

class DefaultController extends Controller
{
    public function indexAction()
    {
        // You only need to provide the path to your static file
        // $filepath = 'path/to/TextFile.txt';

        // i.e Sending a file from the resources folder in /web
        // in this example, the TextFile.txt needs to exist in the server
        $publicResourcesFolderPath = $this->get('kernel')->getRootDir() . '/../web/public-resources/';
        $filename = "TextFile.txt";

        // This should return the file located in /mySymfonyProject/web/public-resources/TextFile.txt
        // to being viewed in the Browser
        return new BinaryFileResponse($publicResourcesFolderPath.$filename);
    }
}

如果你确定返回的文件不会在浏览器中查看, 而是会下载, 则也可以使用上一个代码段。但是, 如果需要下载文件, 我们建议你强制文件的模仿, 并将内容处置设置为附件, 如以下示例所示。

B.返回文件下载

有时, 你需要返回要在控制器中下载的文件, 因此需要使用BinaryFileResponse类, 但是需要修改响应的处理方式, 并在标题中添加将要下载的文件的模仿类型。这非常适合你希望客户下载而不是在线阅读的文件, 例如PDF, 文档文件, 图像和视频:

<?php

namespace myBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

// Import required classes
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\HttpFoundation\File\MimeType\FileinfoMimeTypeGuesser;

class DefaultController extends Controller
{
    public function indexAction()
    {
        // You only need to provide the path to your static file
        // $filepath = 'path/to/TextFile.txt';

        // i.e Sending a file from the resources folder in /web
        // in this example, the TextFile.txt needs to exist in the server
        $publicResourcesFolderPath = $this->get('kernel')->getRootDir() . '/../web/public-resources/';
        $filename = "TextFile.txt";

        // This should return the file to the browser as response
        $response = new BinaryFileResponse($publicResourcesFolderPath.$filename);

        // To generate a file download, you need the mimetype of the file
        $mimeTypeGuesser = new FileinfoMimeTypeGuesser();

        // Set the mimetype with the guesser or manually
        if($mimeTypeGuesser->isSupported()){
            // Guess the mimetype of the file according to the extension of the file
            $response->headers->set('Content-Type', $mimeTypeGuesser->guess($publicResourcesFolderPath.$filename));
        }else{
            // Set the mimetype of the file manually, in this case for a text file is text/plain
            $response->headers->set('Content-Type', 'text/plain');
        }

        // Set content disposition inline of the file
        $response->setContentDisposition(
            ResponseHeaderBag::DISPOSITION_ATTACHMENT, $filename
        );

        return $response;
    }
}

如你所见, 在以下示例中, 如果支持, 则使用FileinfoMimeTypeGuesser类猜测要下载的文件的MIME类型, 否则, 你需要手动提供MIME类型。

BinaryFileResponse将自动处理请求中的Range和If-Range标头。它还支持X-Sendfile(有关Nginx和Apache, 请参见)。取决于应用程序标头的静态文件的传递称为X-Sendfile功能。要使用它, 你需要确定是否应该信任X-Sendfile-Type标头, 如果使用以下方法, 请调用trustXSendfileTypeHeader():

BinaryFileResponse::trustXSendfileTypeHeader();

返回一个动态创建的文件

发送动态创建的文件时, 必须将Content-Disposition标头添加到响应中。在常规HTTP响应中, Content-Disposition响应标头是一个标头, 用于指示内容是否应在浏览器中内联显示, 即作为网页还是作为网页的一部分, 或作为此附件中的附件情况下, 将其下载并保存在本地。在这种情况下, 我们的文件不存在于服务器的存储中, 而是存在于内存和变量中。

虽然为基本文件下载创建此标头很容易, 但使用非ASCII文件名则涉及更多。 makeDisposition()抽象了简单API背后的艰苦工作:

<?php

namespace myBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

// Include the Response and ResponseHeaderBag
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;

class DefaultController extends Controller
{
    public function indexAction()
    {
        // Provide a name for your file with extension
        $filename = 'TextFile.txt';
        
        // The dinamically created content of the file
        $fileContent = "Hello, this is the content of my File";
        
        // Return a response with a specific content
        $response = new Response($fileContent);

        // Create the disposition of the file
        $disposition = $response->headers->makeDisposition(
            ResponseHeaderBag::DISPOSITION_ATTACHMENT, $filename
        );

        // Set the content disposition
        $response->headers->set('Content-Disposition', $disposition);

        // Dispatch request
        return $response;
    }
}

前一个控制器的indexAction的执行应在浏览器中自动生成一个文本文件的下载, 文件名为TextFile, 扩展名为.txt。如果要直接在浏览器中查看文件, 可以将ResponseHeaderBag :: DISPOSITION_ATTACHMENT更改为ResponseHeaderBag :: DISPOSITION_INLINE。

Symfony 3.2

随着Symfony 3.2的发布, 控制器上有一个新方法, 即file, 它强制在浏览器中下载文件:

use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;

public function fileAction()
{
    // load the file from the filesystem
    $file = new File('/path/to/some_file.pdf');

    return $this->file($file);

    // rename the downloaded file
    return $this->file($file, 'custom_name.pdf');

    // display the file contents in the browser instead of downloading it
    return $this->file('invoice_3241.pdf', 'my_invoice.pdf', ResponseHeaderBag::DISPOSITION_INLINE);
}

玩得开心 !

赞(0)
未经允许不得转载:srcmini » 如何从Symfony 3中的控制器发送文件作为响应

评论 抢沙发

评论前必须登录!