長時間運行腳本(如導出大文件、爬蟲進度條)需實時向瀏覽器輸出進度。單用 flush() 常因 PHP 輸出緩衝、Web 服務器緩衝、瀏覽器緩衝導致無效。本文給出 Linux/Windows 通用的「三層緩衝突破」方案。
<?php
// 1. 關鍵:發送 Header 告訴瀏覽器不緩存、開始輸出
header('Content-Type: text/html; charset=utf-8');
header('X-Accel-Buffering: no'); // 關閉 Nginx fastcgi_buffering(關鍵!)
// 2. 開啟 PHP 輸出緩衝控制
ob_start(); // 開啟輸出緩衝
ob_implicit_flush(true); // 可選:隱式刷新(每次輸出自動 flush)
for ($i = 1; $i <= 10; $i++) {
echo $i . '<br />' . "\n";
// 3. 三層刷新:PHP ob_flush → PHP flush → 系統級 flush
ob_flush(); // 刷新 PHP 內部緩衝區到 SAPI
flush(); // 刷新 SAPI 到 Web 服務器/客戶端
usleep(500000); // 模擬耗時操作 0.5 秒
}
ob_end_flush(); // 結束
?>
[PHP 代碼 echo/print]
↓
[PHP 內部 output_buffering (ob_start)]
↓ ob_flush()
[SAPI 層 (mod_php/php-fpm)]
↓ flush()
[Web 服務器 (Apache/Nginx) 緩衝區]
↓ (需關閉 gzip/buffering)
[網絡傳輸]
↓
[瀏覽器緩衝區 (通常需 >256 字節才渲染)]
↓
[用戶可見]
| 層級 | 配置項 | 建議值/操作 | 位置 |
|---|---|---|---|
| PHP | output_buffering | Off 或 0 | php.ini / .user.ini / ini_set() |
| PHP | zlib.output_compression | Off | php.ini |
| Nginx | fastcgi_buffering | off | location 塊或 http 塊 |
| Nginx | gzip | off (對該 location) | location 塊 |
| Apache | mod_deflate / mod_gzip | 關閉或排除該路徑 | .htaccess / httpd.conf |
| 瀏覽器 | 最小渲染字節 | 輸出 > 256 字節或用 <br> 強制換行 | 代碼中控制 |
# nginx.conf 或 site conf location 塊
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
# 關鍵兩行:
fastcgi_buffering off; # 禁用 FastCGI 緩衝,實時推送
proxy_buffering off; # 若有反代層也要關
}
echo str_repeat(' ', 256) 填充或用 <br> 換行觸發渲染。header('Content-Encoding: none') 或 Nginx 關 gzip)。responseBufferLimit="0"。若需雙向實時或高頻推送,建議遷移至 SSE(單向、HTTP 兼容、自動重連)或 WebSocket(雙向),避開 HTTP 短輪詢/長連接的緩衝地獄。