Php 为什么';当我导出数据时,下载窗口会在浏览器中显示很长时间

Php 为什么';当我导出数据时,下载窗口会在浏览器中显示很长时间,php,zend-framework,export,export-to-csv,Php,Zend Framework,Export,Export To Csv,我尝试将数据从数据库导出到.csv。当我点击“导出链接”时,若有大量数据,我很长一段时间都不会在浏览器中看到“保存”窗口。如果脚本看起来像挂起了一段时间,并且在很长一段时间后可以在浏览器中看到“保存”窗口,则可能会非常混乱。 控制器中的代码如下所示: $this->_helper->layout->disableLayout(); $this->_helper->viewRenderer->setNoRender(); $fil

我尝试将数据从数据库导出到.csv。当我点击“导出链接”时,若有大量数据,我很长一段时间都不会在浏览器中看到“保存”窗口。如果脚本看起来像挂起了一段时间,并且在很长一段时间后可以在浏览器中看到“保存”窗口,则可能会非常混乱。 控制器中的代码如下所示:

$this->_helper->layout->disableLayout();
        $this->_helper->viewRenderer->setNoRender();
        $fileName = $list->list_name . '.csv';

        $this->getResponse()->setHeader('Content-Type', 'text/csv; charset=utf-8')
                            ->setHeader('Content-Disposition', 'attachment; filename="'. $fileName . '"');      

        $contacts = new Contact();
        $contacts->export($listId);
Export方法逐个读取记录,并按如下方式打印:

    $fp = fopen('php://output', 'w');        
    foreach ($mongodbCursor as $subscriber) {
           $row = formRow($subscriber);
       fputcsv($fp, $row);
        }       
  foreach ($mongodbCursor as $subscriber) {
           $row = formRow($subscriber);
    echo '"' . implode('","', $row) . '"' . "\r\n";
    ob_flush();
    flush();                    

  }       
我看到一些保存winow的应用程序几乎立即出现,当您单击“保存”时,您可以看到下载的进度

我试图替换:

    $this->getResponse()->setHeader('Content-Type', 'text/csv; charset=utf-8')
                        ->setHeader('Content-Disposition', 'attachment; filename="'. $fileName . '"');
关于这一点:

    header('Content-Type: text/csv; charset=utf-8');
    header('Content-Disposition: attachment; filename="'. $fileName . '"');
到目前为止,它没有起到任何作用。 我想知道在从数据库中逐个读取所有数据之前是否可以发送头?
谢谢你的帮助。

嗯,我不熟悉php://output,我的应用程序用fopen、fwrite、fclose将我的信息写入一个临时文件,然后我用类似的头()将其发送出去;选项

            $filesize = filesize("tmp/export.csv");
            header("Content-Type: text/csv");
            header("Content-Disposition: attachment; filename=\"export.csv\"");
            header("Conent-Length: $filesize");
            readfile("tmp/export.csv");
            unlink("tmp/export.csv");
            exit;

这一个会立即显示浏览器的下载窗口。

您可以尝试执行以下操作:

  • 调用header函数,而不是
    $this->getResponse()->setHeader()
    (响应内容可能保存在缓冲区中,并且只有在完成导出时才输出)
  • 尝试直接回显内容,而不是向php://output (如果在此之前设置了标题,则所有回显内容都将放置在生成的CSV文件中)
编辑

fputcsv
替换为下面的
print\u row
之类的函数

function print_row($row) {
        echo '"' . implode('","', $row) . '"' . "\r\n"; 
}
该函数以数组形式获取第一个参数,添加
并回显到内容

// $file = path of file

header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
exit;

来源:

尝试在
内容类型
值中使用
应用程序/强制下载
而不是
文本/csv

header("Content-Type: application/force-download; name=\"" . $fileName . "\""); 
这将强制使用实际的下载框,而不是仅在浏览器中显示内容

以下是来自以下网站的一些文档:

Mime application/force download通常表示为Mime application/x-force-download,通常与PHP代码结合使用以触发下载框,而不是在Web浏览器中显示内容

例如,如果您的网站上有一个文件,您希望用户下载而不是在Web浏览器中查看,则可以在文件的标题内容类型字段中输入相应的mime应用程序/强制下载代码。请注意,mime应用程序/强制下载不是注册的mime类型。此外,在PHP代码中使用时mime应用程序/强制下载的错误拼写包含“x-”前缀


我不知道这是否是一个好的解决方案,我没有对它进行太多的探索,但它似乎正在发挥作用。 在我将一些数据添加到缓冲区之后,在导出之前,在标题之后,它将停止

    header('Content-Type: text/csv; charset=utf-8');
    header('Content-Disposition: attachment; filename="'. $fileName . '"');

    echo str_pad('', ini_get('output_buffering'));      
    ob_flush();
    flush();

    Model_Subscriber1::exportList($listId);
为了使它在控制器中工作,我在Zend Bootstrap.php中添加了:

/**
 * hint to the dispatcher that it should not use output buffering to capture output generated by action controllers.
 *  By default, the dispatcher captures any output and appends it to the response object body content. 
 */
protected function _initFront()
{
    $frontController = Zend_Controller_Front::getInstance();
    $frontController->setParam('disableOutputBuffering', 1);        
}
在这种情况下,我很快在浏览器中获得下载窗口,然后导出数据,这可能需要相当长的时间。我不知道这个解决方案现在是否可以接受。我很高兴在这里发表您的意见。 它会导致将空数据添加到导出文件时出现问题。 所以,我把它改为控制器

    header('Content-Type: text/csv; charset=utf-8');
    header('Content-Disposition: attachment; filename="'. $fileName . '"');

    Model_Subscriber1::exportList($listId);
并更改导出为以下内容的函数:

    $fp = fopen('php://output', 'w');        
    foreach ($mongodbCursor as $subscriber) {
           $row = formRow($subscriber);
       fputcsv($fp, $row);
        }       
  foreach ($mongodbCursor as $subscriber) {
           $row = formRow($subscriber);
    echo '"' . implode('","', $row) . '"' . "\r\n";
    ob_flush();
    flush();                    

  }       


您的函数可能希望在长操作之前调用flush/ob_flush,并让HTTP头在长操作之前发送到客户端。

您这样导出的文件的最大大小是多少?我现在不明白您的意思,导入什么?这段代码是为了发出cvs,脚本在其上面写了几行。最大文件大小是无限的(在我的例子中,它读取数据库条目,即使一次导出数千条条目也没有问题)在您的代码中,我只看到输出某些文件的内容,对吗?没有从数据库中获取的代码。我的意思是,如果从数据库中获取所有数据很长,则可能需要相当长的时间才能将其写入您稍后输出的临时文件,对吗?因此,在从数据库获取所有数据之前,用户不会看到下载窗口。不是really在一秒钟内测试了大约2000个库存项目(大约30个数据库字段的varchar(128))CSV。如果您有500K或1M个项目,则会出现问题。在从数据库读取所有数据之前,用户将看不到下载窗口。您能告诉我如何替换:$fp=fopen($fp)吗php://output“,”w“;fputcsv($fp,$row);直接回显是什么意思?是手动回显字段值、命令、新行吗?是的,我的意思是可以直接回显每个CSV行,例如
“值”、“值2”"\r\n
。我将编辑答案并添加一个您可以使用的示例函数。我尝试用标题函数代替响应类的方法,但现在没有任何帮助。好的,很好。也尝试将
fputcsv
替换为
php://output
使用上面的函数,让我们看看是否有更显著的改进。我尝试了将其替换为echo“.”。内爆(“,“,$row)。“。\r\n”;。我不会快速显示下载窗口,页面会挂起一段时间,只有在加载数据时,才会显示下载窗口,我单击“确定”,然后立即获取文件。您能解释一下您的想法以及我的代码有什么问题吗?我的想法强制从文件链接下载,我不知道您的代码有什么问题。它似乎没有回答我的问题。你能告诉我,为什么在手动模式下,他们在设置标题后会显示“清除();刷新()”?你的意思是使用如下标题:标题('Content-Type:application/force download;charset=utf-8');标题('Content-Disposition:attachment;filename=“.$filename.”);问题似乎是,我的头只有在从数据库获取数据后才会发送,在此期间,头不会发送到客户端。因此,我不确定某些类型的头是否有问题,因为它们有很长一段时间没有发送。这似乎不是一个标准的mime,可以