我尝试将数据从数据库导出到.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);
导出方法逐个读取记录并打印如下内容:
$fp = fopen('php://output', 'w');
foreach ($mongodbCursor as $subscriber) {
$row = formRow($subscriber);
fputcsv($fp, $row);
}
我看到在某些应用程序上保存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 将我的信息写入一个临时文件,之后我用类似的 header(); 选项给出它。
$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_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;
来源: http://php.net/manual/en/function.readfile.php
尝试在Content-Type
值中使用application/force-download
而不是text/csv
。
header("Content-Type: application/force-download; name='"" . $fileName . "'"");
这将强制使用实际的下载框,而不仅仅是在浏览器中显示内容。
以下是来自 MIME 应用程序的一些文档:
Mime application/force-download,通常表示为 mime application/x-force-download,通常与 PHP 代码结合使用以触发下载框,而不是用于在 Web 浏览器中显示内容。
例如,如果您的网站上有一个文件,您希望用户下载而不是在 Web 浏览器中查看,则可以在文件的标头内容类型字段中输入相应的 MIME 应用程序/强制下载代码。请注意,MIME 应用程序/强制下载不是已注册的 MIME 类型。此外,当在PHP代码中使用时,mime application/force-download的首选拼写包含"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);
和 chang 函数导出到这样的东西:
foreach ($mongodbCursor as $subscriber) {
$row = formRow($subscriber);
echo '"' . implode('","', $row) . '"' . "'r'n";
ob_flush();
flush();
}
您的函数可能希望在长时间操作之前调用 flush/ob_flush,并让 HTTP 标头在长进程之前发送到客户端。