【问题标题】:CakePHP 3 output .ctp template as CSV fileCakePHP 3 将 .ctp 模板输出为 CSV 文件
【发布时间】:2019-01-03 15:08:37
【问题描述】:

在 CakePHP 3.5.13 中,我有一个控制器动作如下:

class ReportController extends AppController
{
    public function download($id, $format)
    {

    }
}

我想要做的是将报告 ID 和格式(例如 XLSX、CSV)的参数传递给 download 函数,例如/report/download/123/csv 将获取报告 123 的数据并将其输出为 CSV。

我的报告所需的所有数据都保存在一个数组中,$data。我想创建单独的模板(.ctp 文件)以每种所需格式格式化我的数据,然后让download() 函数将它们发送到浏览器以供下载。

所以我调整了我的功能如下:

public function download($id, $format)
{
    $data = // ... Model data in array format

    $filename = '123'; // filename for the download

    switch ($format):
        case 'csv':
            header('Content-type: text/csv');
            header('Content-Disposition: attachment; filename="'.$filename.'.csv"');

            $this->viewBuilder()->setLayout('ajax');
            $this->set('data', $data);
            $this->render('download_csv');
        break;
    endswitch;
}

这会正确呈现我从Template/Report/download_csv.ctp 获得的模板。它也在 ajax 布局中正确呈现($this->viewBuilder()->setLayout('ajax'); 表示它使用Template/Layout/ajax.ctp,因此不包含任何“包装”HTML)。

当访问/report/download/123/csv 时,浏览器会发送一个名为123.csv 的文件,其中包含我请求的数据。但是,响应类型是text/html,而不是我的控制器操作中指定的text/csv

这会导致文件内容格式不正确 - 它会将其视为 HTML 而不是 CSV。例如,如果我的 download_csv.ctp 模板中有以下内容:

"Field 1", "123\n456",
"Field 2", "789"

在 Excel 中按字面意思输出:

我猜这个问题是由于响应实际上是 HTML 而不是 CSV,但我不确定。

我的问题是,是否可以以这种方式使用 .ctp 文件并以指定格式将它们作为下载输出到浏览器?

我知道路由和 URL 扩展还可以做其他事情,但这个问题与这些无关。我也不想使用插件/扩展。我想知道是否可以使用$this->render() 并让Cake 渲染一个模板,该模板以请求的格式发送到浏览器以供下载?

【问题讨论】:

标签: php csv cakephp


【解决方案1】:

调用render() 将简单地呈现给定模板并使用呈现的数据填充响应正文,而不管响应将发生什么,以及它正在发送的内容类型如何 - 所以答案是肯定的,您可以渲染模板并将其作为下载提供。

Excel 没有按预期导入数据,很可能与 CakePHP 没有任何关系,因为 CSV 文件不包含任何内容类型信息。也许您在导入文件时选择了错误的文本限定符 (")。

话虽如此,控制器不应该输出数据,包括标题!在控制器中输出数据会导致各种问题,从测试环境中无法识别数据,到无法发送标头,甚至数据被截断。相反,请使用适当的响应对象方法相应地准备下载响应,在您的情况下,您正在寻找 withType()withDownload(),例如:

case 'csv':
    $this->response = $this->response->withType('csv');
    $this->response = $this->response->withDownload($filename. '.csv');

    $this->viewBuilder()->setLayout('ajax');
    $this->set('data', $data);
    $this->render('download_csv');
break;

这将添加正确的 Content-TypeContent-Disposition 标头。

另见:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-16
    • 1970-01-01
    • 2017-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多