首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

深度解析 PHP ob_flush 与 flush 区别:输出缓冲控制完全指南

     編輯:PHP 綜合知識

刷新缓冲区的双剑合璧:ob_flush() 与 flush() 详解

PHP 输出缓冲控制是实现长连接、进度条、实时日志、流式下载的关键。ob_flush() 与 flush() 常配对使用,但操作对象完全不同。本文从原理、调用顺序、SAPI 差异、浏览器行为四个维度深度解析。

核心结论先行

函数操作对象生效条件
ob_flush()PHP 内部输出缓冲区开启了 output_buffering 或 ob_start()
flush()Web Server (Apache/Nginx) 缓冲区PHP 以 Module/Handler 运行(非 CGI/CLI)

正确调用顺序:ob_flush(); flush(); —— 先推出 PHP 缓冲,再推出 Server 缓冲。

一、何时需要刷新缓冲区

  1. 长耗时任务进度反馈:文件处理、数据导入、批量发送邮件/短信
  2. 大文件流式下载:避免一次性读入内存,边读边输出
  3. 实时日志/监控页面:Server-Sent Events (SSE) 或长轮询
  4. 避免代理/浏览器缓冲延迟:某些中间件缓存完整响应后再转发

二、为什么要刷新:数据流向模型

PHP 脚本
    ↓ echo/print
PHP output_buffering (ob_* 系列控制)
    ↓ ob_flush()
SAPI 层 (Apache mod_php / php-fpm)
    ↓ flush() → ap_rflush / fcgi_write
Web Server 发送缓冲区
    ↓ 网络传输
浏览器接收缓冲区 (256B/换行/标签触发渲染)
    ↓ 解析渲染
用户可见内容

三、SAPI 运行模式差异

SAPI 模式flush() 效果说明
Apache mod_php (Handler)✅ 有效调用 ap_rflush 刷新 Apache 输出桶
Apache mod_php (Filter)✅ 有效同上
PHP-FPM (FastCGI)⚠️ 依赖配置需 Nginx fastcgi_buffering off; 禁用缓冲
CGI❌ 无效请求结束一次性输出
CLI✅ 有效直接刷新 stdout,无 Server 层

四、中间件与浏览器的「隐形缓冲」

  • mod_gzip / mod_deflate:压缩模块会缓冲内容直到压缩块完成,导致 flush() 失效
  • Nginx fastcgi_buffering:默认开启,缓存 FastCGI 响应至 fastcgi_buffers 大小
  • CDN/代理:Cloudflare 等可能缓存完整响应
  • 浏览器渲染阈值:
    • IE/Edge:需接收 256 字节才开始渲染
    • Chrome/Firefox:通常等待 <body> 或 <table> 闭合
    • 通用技巧:输出 str_repeat(' ', 1024) 或 <!-- padding --> 填充

五、完整实战示例:实时进度条

<?php
// 禁用 PHP 输出缓冲(如 php.ini 已开启)
while (ob_get_level()) ob_end_clean();

// 禁用压缩(防止中间件缓冲)
@apache_setenv('no-gzip', 1);
@ini_set('zlib.output_compression', 0);
@ini_set('implicit_flush', 1);

header('Content-Type: text/html; charset=utf-8');
// 填充触发浏览器渲染
echo str_repeat('<!-- padding -->', 256);

for ($i = 1; $i <= 100; $i++) {
    echo "<script>document.getElementById('progress').style.width='$i%';</script>";
    echo "<script>document.getElementById('text').innerText='$i%';</script>";
    
    // 关键:双刷新
    ob_flush();
    flush();
    
    usleep(50000); // 模拟耗时操作
}
?>
<html>
<body>
    <div style="width:300px;border:1px solid #ccc">
        <div id="progress" style="width:0%;background:#09f;height:20px"></div>
    </div>
    <span id="text">0%</span>
</body>
</html>

六、常见失效排查清单

  1. 检查 output_buffering 是否过大(建议 Off 或 4096)
  2. 确认 zlib.output_compression = Off
  3. Nginx: fastcgi_buffering off; 在 location 块中
  4. Apache: 禁用 mod_deflate 或 SetEnv no-gzip 1
  5. 测试 CLI 模式隔离问题:php script.php | cat
  6. 添加 Content-Length 或 Transfer-Encoding: chunked

七、现代替代方案

  • Server-Sent Events (SSE):单向实时推送,浏览器原生支持
  • WebSocket:双向通信,适合高频交互
  • ReactPHP / Amp / Swoole:异步非阻塞框架,原生支持流式响应
  • Symfony HttpFoundation StreamedResponse:优雅封装流式输出
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved