更新时间:2023-02-14 21:32:00
根据经验,似乎当接收到具有Content-Disposition: attachment
标头的响应时,不同的浏览器将在以下时刻显示文件下载对话框:
Empirically, it seems that when receiving responses featuring a Content-Disposition: attachment
header, different browsers will show the file download dialog at the following moments:
那么,我们的目标如下:
Our objectives, then, are as follows:
实现这些目标的方式可能是多个级别的缓冲,您可以尝试以不同的方式进行应对.
Standing in the way of these objectives are, potentially, multiple levels of buffering, which you can try to fight in different ways.
如果您具有 output_buffering
设置为Off
以外的值,PHP将自动创建一个输出缓冲区,该缓冲区存储脚本尝试发送到响应 body 的所有输出.您可以通过确保从php.ini
文件或Web服务器配置文件(例如apache.conf
或nginx.conf
)将output_buffering
设置为Off
来防止这种情况.或者,您可以在脚本的开头使用 ob_end_flush()
或 ob_end_clean()
:
If you have output_buffering
set to a value other than Off
, PHP will automatically create an output buffer which stores all output your script tries to send to the response body. You can prevent this by ensuring that you have output_buffering
set to Off
from your php.ini
file, or from a webserver config file like apache.conf
or nginx.conf
. Alternatively, you can turn off the output buffer, if one exists, at the start of your script using ob_end_flush()
or ob_end_clean()
:
if (ob_get_level()) {
ob_end_clean();
}
一旦您的输出超过了PHP输出缓冲区,它可能会被您的Web服务器缓冲.您可以尝试通过定期(例如每100行)调用 flush()
来解决此问题,尽管PHP手册对于提供任何担保不愿提供帮助,并列出了某些可能失败的特殊情况:
Once your output gets past the PHP output buffer, it may be buffered by your webserver. You can try to get around this by calling flush()
regularly (e.g. every 100 lines), although the PHP manual is hesitant about providing any guarantees, listing some particular cases where this may fail:
冲洗
...
刷新PHP的写缓冲区以及PHP正在使用的任何后端(CGI,Web服务器等).这样做有一些注意事项,试图将电流输出一直推到浏览器.
Flushes the write buffers of PHP and whatever backend PHP is using (CGI, a web server, etc). This attempts to push current output all the way to the browser with a few caveats.
flush()可能无法覆盖Web服务器的缓冲方案...
flush() may not be able to override the buffering scheme of your web server ...
多个服务器,尤其是Win32上的服务器,仍将缓冲脚本的输出,直到脚本终止,然后再将结果传输到浏览器.
Several servers, especially on Win32, will still buffer the output from your script until it terminates before transmitting the results to the browser.
Apache的服务器模块(例如mod_gzip)可能会自行缓冲,从而导致 flush()不会导致数据立即发送到客户端.
Server modules for Apache like mod_gzip may do buffering of their own that will cause flush() to not result in data being sent immediately to the client.
或者,每次尝试回显任何输出时,也可以通过调用 n ,每输出 n 行显式调用flush()
也许是一种更好的做法.
You can alternatively have PHP call flush()
automatically every time you try to echo any output, by calling ob_implicit_flush
at the start of your script - though beware that if you have gzip enabled via a mechanism that respects flush()
calls, such as Apache's mod_deflate
module, this regular flushing will cripple its compression attempts and probably result in your 'compressed' output being larger than if it were uncompressed. Explicitly calling flush()
every n lines of output, for some modest but non-tiny n, is thus perhaps a better practice.
将它们放在一起,然后,您可能应该调整脚本,使其看起来像这样:
Putting it all together, then, you should probably tweak your script to look something like this:
<?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);
?>
如果这不起作用,那么我认为您无法通过PHP代码做更多的事情来尝试解决问题-您需要弄清楚是什么导致您的Web服务器缓冲您的输出并尝试使用服务器的配置文件解决该问题.
If this doesn't work, then I don't think there's anything more you can do from your PHP code to try to resolve the problem - you need to figure out what's causing your web server to buffer your output and try to solve that using your server's configuration files.