我有一个生成大型CSV文件的脚本,fputcsv并将其发送到浏览器.它可以工作,但浏览器不显示文件下载提示(或开始下载文件),直到整个CSV文件在服务器端生成,这需要很长时间.
相反,我希望在仍然生成文件的其余部分时开始下载.我知道这是可能的,因为它是PHPMyAdmin中"导出数据库"选项的工作方式 - 即使您的数据库很大,只要单击"导出"按钮就会立即开始下载.
我如何调整下面的现有代码,让下载立即开始?
$csv = 'title.csv';
header( "Content-Type: text/csv;charset=utf-8" );
header( "Content-Disposition: attachment;filename=\"$csv\"" );
header( "Pragma: no-cache" );
header( "Expires: 0" );
$fp = fopen('php://output', 'w');
fputcsv($fp, array_keys($array), ';', '"');
foreach ($array as $fields)
{
fputcsv($fp, $fields, ';', '"');
}
fclose($fp);
exit();
Run Code Online (Sandbox Code Playgroud)
Mar*_*ery 10
根据经验,似乎在接收具有Content-Disposition: attachment标题的响应时,不同的浏览器将在以下时刻显示文件下载对话框:
那么,我们的目标如下:
阻碍这些目标的可能是多级缓冲,您可以尝试以不同的方式进行战斗.
如果您output_buffering设置了其他值Off,PHP将自动创建一个输出缓冲区,用于存储脚本尝试发送给响应主体的所有输出.您可以通过确保从文件或Web服务器配置文件(例如或)output_buffering设置为来阻止此操作.或者,您可以在脚本开头使用或关闭输出缓冲区(如果存在):Offphp.iniapache.confnginx.confob_end_flush()ob_end_clean()
if (ob_get_level()) {
ob_end_clean();
}
Run Code Online (Sandbox Code Playgroud)
一旦输出超过PHP输出缓冲区,它可能会被您的网络服务器缓冲.您可以尝试通过flush()定期调用(例如每100行)来解决这个问题,尽管PHP手册对提供任何保证犹豫不决,列出了一些可能失败的特殊情况:
红晕
...
刷新PHP的写缓冲区以及PHP正在使用的任何后端(CGI,Web服务器等).这会尝试将当前输出一直推送到浏览器,但需要注意几点.
flush()可能无法覆盖Web服务器的缓冲方案......
多个服务器,尤其是Win32上的服务器,仍将缓冲脚本的输出,直到它终止,然后再将结果传输到浏览器.
像mod_gzip这样的Apache服务器模块可能会自行缓冲,这会导致flush()不会导致数据立即发送到客户端.
你可以在flush()每次尝试回显任何输出时自动调用PHP ,通过ob_implicit_flush在脚本的开头调用- 但要注意,如果你通过一种尊重flush()调用的机制启用了gzip ,比如Apache的mod_deflate模块,那么这种常规的刷新将会瘫痪它的压缩尝试可能会导致您的"压缩"输出大于未压缩的输出.因此,对于一些适度但非微小的n,明确地调用flush()每n行输出可能是更好的实践.
把它们放在一起,然后,你应该调整你的脚本看起来像这样:
<?php
if (ob_get_level()) {
ob_end_clean();
}
$csv = 'title.csv';
header( "Content-Type: text/csv;charset=utf-8" );
header( "Content-Disposition: attachment;filename=\"$csv\"" );
header( "Pragma: no-cache" );
header( "Expires: 0" );
flush(); // Get the headers out immediately to show the download dialog
// in Firefox
$array = get_your_csv_data(); // This needs to be fast, of course
$fp = fopen('php://output', 'w');
fputcsv($fp, array_keys($array), ';', '"');
foreach ($array as $i => $fields)
{
fputcsv($fp, $fields, ';', '"');
if ($i % 100 == 0) {
flush(); // Attempt to flush output to the browser every 100 lines.
// You may want to tweak this number based upon the size of
// your CSV rows.
}
}
fclose($fp);
?>
Run Code Online (Sandbox Code Playgroud)
如果这不起作用,那么我认为您无法通过PHP代码尝试解决问题 - 您需要弄清楚是什么导致您的Web服务器缓冲输出并尝试使用它来解决问题您的服务器的配置文件.