如何使用Response对象强制下载Symfony 2中的.csv文件?

时间:2012-04-24 22:42:21

标签: csv symfony download

我正在使用Symfony 2创建一个“下载”控制器,它的唯一目的是发送标题,以便我可以强制下载.csv文件,但它无法正常工作。

$response = new Response();
$response->headers->set('Content-Type', "text/csv");
$response->headers->set('Content-Disposition', 'attachment; filename="'.$fileName.'"');
$response->headers->set('Pragma', "no-cache");
$response->headers->set('Expires', "0");
$response->headers->set('Content-Transfer-Encoding', "binary");
$response->headers->set('Content-Length', filesize($fileName));
$response->prepare();
$response->sendHeaders();
$response->setContent(readfile($fileName));
$response->sendContent();

$fileName是一个"info.csv"字符串。这是我在我的控制器内的行为,没有退货声明。当我尝试返回Response对象时,文件的内容显示在浏览器中,而不是我想要的结果。

我发现的问题是,在某些页面中,我确实得到了info.csv file,但在其他一些页面中,我得到的是一条消息:

No webpage was found for the web address: http://mywebpage.com/download Error 6 (net::ERR_FILE_NOT_FOUND): The file or directory could not be found.

我完全确定该文件存在,所以必定还有其他问题。此外,routing.yml工作正常,因为我从其他页面获取文件也链接到该路径。 Apache错误日志没有显示任何相关内容。

有没有人强行在Symfony 2上下载.csv文件?如果是这样,我做错了什么?

6 个答案:

答案 0 :(得分:35)

这是一个在生产中运作良好的最小例子:

class MyController
public function myAction()

    $response = $this->render('ZaysoAreaBundle:Admin:Team/list.csv.php',$tplData);

    $response->headers->set('Content-Type', 'text/csv');
    $response->headers->set('Content-Disposition', 'attachment; filename="teams.csv"');

    return $response;

如果您愿意,可以使用新响应和response-> setContent替换渲染调用。

你对控制器内部没有返回语句的评论令人费解。控制器返回响应。让框架负责将内容发送到浏览器。

答案 1 :(得分:7)

我意识到这篇文章有点陈旧,奇怪的是,除了这篇文章在stackoverflow之外,几乎没有关于如何在symfony 2中进行CSV导出的好资源。

无论如何,我将上面的例子用于客户竞赛网站并且效果很好。但是今天我收到了一封电子邮件,经过我自己的测试后,代码已经坏了 - 我能够通过少量结果获得下载工作,但是数据库现在可以导出超过31,000行,它只是显示文本或者铬,基本上什么也没做。

对于任何有大数据导出问题的人来说,这就是我为了上班而做的事情,基本上做了Cerad建议的替代方式:

    $filename = "export_".date("Y_m_d_His").".csv";
    $response = $this->render('AppDefaultBundle:Default:csvfile.html.twig', array('data' => $data));

    $response->setStatusCode(200);
    $response->headers->set('Content-Type', 'text/csv');
    $response->headers->set('Content-Description', 'Submissions Export');
    $response->headers->set('Content-Disposition', 'attachment; filename='.$filename);
    $response->headers->set('Content-Transfer-Encoding', 'binary');
    $response->headers->set('Pragma', 'no-cache');
    $response->headers->set('Expires', '0');

    $response->prepare();
    $response->sendHeaders();
    $response->sendContent();

编辑:经过更多测试并提高允许的最大秒数后,我意识到之前的代码是在顶部打印出标题,所以我已经更新了代码。

答案 2 :(得分:6)

这对我有用,可以导出CSV和JSON。

Twig文件命名为:export.csv.twig,export.json.twig

控制器:

class PrototypeController extends Controller {

public function exportAction(Request $request) {

    $data = array("data" => "test");

    $format = $request->getRequestFormat();

    if ($format == "csv") {
        $response = $this->render('PrototypeBundle:Prototype:export.' . $format . '.twig', array('data' => $data));
        $filename = "export_".date("Y_m_d_His").".csv";
        $response->headers->set('Content-Type', 'text/csv');
        $response->headers->set('Content-Disposition', 'attachment; filename='.$filename);

        return $response;
    } else if ($format == "json") {
        return new Response(json_encode($data));
    }
}
}

路由:

prototype_export:
    pattern:  /export/{_format}
    defaults: { _controller: PrototypeBundle:Prototype:export, _format: json }
    requirements:
        _format:  csv|json

The Twigs:

export.csv.twig(在这里做你的逗号分隔,这只是一个测试)

{% for row in data %}
{{ row }}
{% endfor %} 

export.json.twig(数据发送json_encoded,此文件为空)

希望这有帮助!

答案 3 :(得分:0)

这就是我设法让Silex返回CSV的方法:

// $headers in an array of strings
// $results are the records returned by a PDO query
 $stream = function() use ($headers, $results) {
    $output = fopen('php://output', 'w');
    fputcsv($output, $headers);
    foreach ($results as $rec)
    {
        fputcsv($output, $rec);
    }

    fclose($output);
};

return $app->stream($stream, 200, array(
    'Content-Type' => 'text/csv',
    'Content-Description' => 'File Transfer',
    'Content-Disposition' => 'attachment; filename="test.csv"',
    'Expires' => '0',
    'Cache-Control' => 'must-revalidate',
    'Pragma' => 'public',
));

您可能还需要使用Javascript做一些Jiggery Pokery(我正在通过AJAX下载),但这post是使它工作所需的全部。

答案 4 :(得分:0)

您可以在每种情况下使用的简单功能,可导出csv以供下载...

public function getResponse(array $data, $filename, $headers = array())
{
    if(substr(strtolower($filename), -4) == '.csv') {
        $filename = substr($filename, 0, -4);
    }

    $tmpFile = $this
        ->_getContainer()
        ->get('kernel')
        ->getRootDir()
        . '/../var/tmp_'.substr(md5(time()),0,5);

    if(file_exists($tmpFile)) unlink($tmpFile);

    $handle = fopen($tmpFile, 'w');

    foreach ($data as $i => $row) {

        $row = (array) $row;

        if($i == 0) fputcsv($handle, array_keys($row));

        fputcsv($handle, $row);

    }

    fclose($handle);

    $Response = new Response(file_get_contents($tmpFile));

    unlink($tmpFile);

    $filename = preg_replace('[^a-z0-9A-Z_]', '', $filename);

    $headers = array_merge([
        'Expires' => 'Tue, 01 Jul 1970 06:00:00 GMT',
        'Cache-Control' => 'max-age=0, no-cache, must-revalidate, proxy-revalidate',
        'Content-Disposition' => 'attachment; filename='.$filename.'.csv',
        'Content-Type' => 'text/csv',
        'Content-Transfer-Encoding' => 'binary',
    ], $headers);

    foreach ($headers as $key => $val) {
        $Response->headers->set($key, $val);
    }

    return $Response;
}

答案 5 :(得分:-1)

如何使用Sonata的导出器:

use Exporter\Writer\CsvWriter;
/**
 * @param array $orders
 */
public function exportToCsv($orders)
{
    $rootdir = $this->get('kernel')->getRootDir();
    $filename = $rootdir . '/data/orders.csv';
    unlink($filename);
    $csvExport = new CsvWriter($filename);
    $csvExport->open();
    foreach ($orders as $order)
    {
        $csvExport->write($order);
    }
    $csvExport->close();
    return;

}

如果文件已经存在,它会崩溃,因此unlink-command。