【问题标题】:Sending hude csv file directly to browser output does not work将hude csv文件直接发送到浏览器输出不起作用
【发布时间】:2014-11-14 15:21:54
【问题描述】:

由于 MS Excel 无法recognize CSV files as of utf-8 encoding,我尝试手动创建一个在 BOM 前缀之前的文件。但在我的情况下,我需要将它发送给用户/浏览器打开而不是保存在磁盘上。 诀窍是,对于少量数据 ~1-10 它运行良好,但是当要输出大量记录时,它无法在浏览器(Google Chrome,FF)中输出,而是将结果打印为 HTML。您可以尝试在 GET 请求中使用不同的 count 参数:http://tarex.ru/index.php?r=user/pricelist&file=1&count=100

代码

        $limit =  $_GET['count'] ? $_GET['count'] : 10;
        $filename= 'test.csv';  
        $out = fopen('php://output', 'w');  // open to out in browser
        fwrite($out, "\xEF\xBB\xBF");  // prepend BOM  
        $counter=0;
        foreach(Assortment::model()->findAll(  'measure_unit<>"" AND price>0' ) as $d)
        {
            $arr = array( $d->article2, $d->title, $d->oem,  $d->make, $d->availability , $d->getPrice(Yii::app()->user->id), $d->getDiscountOpt(Yii::app()->user->id) );
            fputcsv($out, $arr, ';'); //delimiter - ;
            if ($counter++ > $limit) break;
        }  
        header('Content-type: text/csv; charset=utf-8');
        header('Content-Disposition: attachment; filename="' . $filename . '"');
        fclose($out);   

有什么解决办法吗?

更新

在 turutosiya 的建议下,我终于用Yii::app()-&gt;request-&gt;sendFile 完成了。

    $filename='test.csv';         
    $filepath = Yii::app()->basePath . '/../files/'. $filename;
    $out      = fopen($filepath, 'w'); 
// writing csv ...
    fwrite($out, "\xEF\xBB\xBF");  //  put BOM at the beginning of file
    fputcsv($out, $arr, ';');
    foreach(Assortment::model()->findAll() as $d)
    {
        $arr = array( $d->article2, $d->title, $d->oem,  $d->make, $d->availability);
        fputcsv($out, $arr, ';'); // separator - ;  
    }  
    fclose($out); 
    Yii::app()->request->sendFile($filename,   @file_get_contents($filepath)); 

【问题讨论】:

  • header() 方法不用于在 $out 资源处理程序上设置标头信息...我认为只有在 Chrome、FF 正在猜测文件类型时才起作用
  • 当我删除它header() method,输出总是在屏幕上(html)
  • header() 业务 ONLY 应用于 http 部分。它不会更改您发送的数据或在客户端上如何保存/查看数据的任何内容。通过删除 content-type 标头,您只是允许服务器使用其默认的 mime 类型,即 text/html。

标签: php excel csv output


【解决方案1】:

我建议使用xSendFile()方法下载大文件。

$limit    =  $_GET['count'] ? $_GET['count'] : 10;
$filename = 'test.csv';
$filepath = '/path/to/xsendfile-enabled/dir/' . $filename;
$out      = fopen($filepath, 'w');
//
// write csv ...
//
fclose($out);
Yii::app()->request->xSendFile(filepath, array(
    'saveName' => $filename
));

【讨论】:

  • 谢谢你的方法,你给了。但它返回一个空文件:在文档中:要使此方法工作,Web 服务器应启用 X-SENDFILE 选项/模块,并应发送适当的 xHeader... 如果此选项被禁用Web 服务器,当调用此方法时,将打开下载配置对话框,但下载的文件将有 0 个字节。 这里必须是这种情况。如果服务器是共享服务器,如何设置此选项?
  • @IgorSavinkin 你会要求服务器管理员启用 x-sendfile 吗?
  • 我只用了Yii::app()-&gt;request-&gt;sendfile
【解决方案2】:

对于原始代码,问题可能在于您在末尾有 header 语句。如果输出那么大,则该 Web 服务器将第一个数据块刷新到浏览器,然后该浏览器接收没有这些标头的数据。从那一刻起,发送标头为时已晚。

所以先生成这些标题:

    $limit =  $_GET['count'] ? $_GET['count'] : 10;
    $filename= 'test.csv';  
    $out = fopen('php://output', 'w');  // open to out in browser
    header('Content-type: text/csv; charset=utf-8');
    header('Content-Disposition: attachment; filename="' . $filename . '"');
    fwrite($out, "\xEF\xBB\xBF");  // prepend BOM  
    //
    // rest of output generating code comes here
    //
    fclose($out);   

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-12-10
    • 1970-01-01
    • 2014-12-09
    • 1970-01-01
    • 1970-01-01
    • 2016-04-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多