我有许多脚本在执行时回显进度,因为它们长时间运行.每个处理的每个循环数据行的末尾基本上都执行以下操作:
echo '.';
@ob_flush();
flush();
Run Code Online (Sandbox Code Playgroud)
这工作好多年,然后我在几台服务器上升级到PHP 5.3.x和Apache 2.2.x. 现在,即使我用空格填充缓冲区或设置"ob_implicit_flush(1)",我也无法通过命令显示输出.
一台服务器仍然显示输出,但它是块.它可能需要将近5分钟,然后屏幕上突然出现一串点.使用其他服务器,在脚本完成执行之前我什么也得不到.
我已经尝试查看php.ini和httpd.conf文件,看看我是否能弄清楚不同服务器之间的变化,但我显然遗漏了一些东西.
我也尝试在受影响的脚本中禁用.htaccess中的mod_deflate,但这也无济于事(禁用用于立即解决问题的mod_gzip).
请有人指出我正确的方向吗?无法实时监控脚本执行会导致各种问题,但我们不能再继续使用这些旧的PHP版本了.
在一个更奇怪的方面,我确实尝试将服务器降级到PHP 5.2.17,但在降级后输出缓冲区问题仍然存在.这让我怀疑它与Apache处理PHP输出的方式有关,因为Apache 2已经存在.
sym*_*ean 13
ob_flush()(flush())只刷新PHP缓冲区 - 网络服务器本身维护一个缓冲区.虽然听起来很奇怪,但提前刷新缓冲区实际上会降低服务器的吞吐量,因此最近版本的apache会更加积极地缓冲.使用HTTP分块编码时,还存在与压缩和部分渲染相关的可怕问题.
如果要逐步向页面添加内容,请使用ajax或websockets一次添加一些内容.
这个问题更多地与您的服务器(apache)而不是php版本有关.
一种选择是禁用输出缓冲,但性能可能会在站点的其他部分受到影响
output_buffering=off从服务器配置中设置php ini指令(),包括.htaccess文件.所以我在.htaccess文件中使用以下内容来禁用仅为该文件的output_buffering:
<Files "q.php">
php_value output_buffering Off
</Files>
Run Code Online (Sandbox Code Playgroud)
然后在我的静态服务器配置中,我只需要AllowOverride Options=php_value(或更大的锤子AllowOverride All),以便在.htaccess文件中允许它.
禁用Nginx的缓冲(将"proxy_buffering off;"添加到配置文件并重新启动Nginx
最初可能是原始问题中描述的变化是新设置使用的是FastCgi(http://www.fastcgi.com/mod_fastcgi/docs/mod_fastcgi.html),并且启用缓冲是默认设置.
但还有其他因素需要检查:
如果你正在使用Fcgid,那么这也有缓冲:http://httpd.apache.org/mod_fcgid/mod/mod_fcgid.html#fcgidoutputbuffersize
如果PHP和Apache之间的字符集不匹配 - 这可以解决问题.
mod_deflate和mod_gzip也是缓冲区(如原始问题中所述)
所以要检查的步骤是:
刷新PHP缓冲区 - (如问题中所述)
关闭Apache缓冲 - 添加php_value output_buffering off.htaccess
禁用用于缓解通货紧缩的mods - 禁用mod_deflate和mod_gzip
确保您的char编码在PHP和Apache之间匹配 - default_charset = "utf-8";在php.ini和AddDefaultCharset utf-8httpd.conf中添加)
在FastCgi或Fcgid中禁用缓冲 - 您可以通过添加-flush选项在FastCgi中禁用缓冲.上面链接中的详细信息.上面列出了Fcgid的选项.
据我所知,这些是服务器上唯一的缓冲区; 显然,服务器和浏览器之间的其他设备也可以缓冲,例如代理可以在传递之前等待提供完整输出.Fiddler(https://www.telerik.com/fiddler)这样做,它经常让我知道,直到我记得.
有可能解决此问题,不需要您编辑现有脚本或修改服务器配置以停止缓冲输出.通过使用包装器脚本,您可以在后台从提供Web请求的php脚本开始长时间运行的进程.然后,您可以将长时间运行的进程的输出通过管道传输到文本文件中,该文件可以通过轮询轻松读取以查找脚本的当前进度.示例如下:
<?php
// long_process.php
echo "I am a long running process ";
for ($i = 0; $i < 10; $i++) {
echo ".";
sleep(1);
}
echo " Processing complete";
?>
Run Code Online (Sandbox Code Playgroud)
<?php
// proc_watcher.php
$output = './output.txt';
if ($_GET['action'] == 'start') {
echo 'starting running long process<br>';
$handle = popen("nohup php ./long_process.php > $output &", 'r');
pclose($handle);
} else {
echo 'Progress at ' . date('H:i:s') . '<br>';
echo file_get_contents($output);
}
$url = 'proc_watcher.php';
?>
<script>
window.setTimeout(function() {
window.location = '<?php echo $url;?>';
}, 1000);
</script>
Run Code Online (Sandbox Code Playgroud)
如果向proc_watcher.php?action=start脚本发送Web请求,则应在后台启动长时间运行的进程,然后每秒将输出文件的内容返回到Web浏览器.
这里的技巧是命令行nohup php ./long_process.php > ./output.txt &,它在后台运行进程并将输出发送到文件而不是STDOUT.
| 归档时间: |
|
| 查看次数: |
3515 次 |
| 最近记录: |