在長時間運行的 PHP 任務(如批量導入、報表生成、視頻轉碼)中,即時反饋進度能顯著提升用戶體驗。本文介紹一種無需 JavaScript 輪詢、純 PHP 實現的流式進度條方案。
利用 PHP 的輸出緩衝控制函數(ob_start()、flush()、ob_flush())配合瀏覽器的分塊渲染特性,將進度更新以 HTML 片段形式實時推送至客戶端。
<html>
<head>
<style type="text/css"><!--
.progress-container { margin: 10px; width: 300px; }
.progress-bar { height: 24px; border: 1px solid #ccc; background: #f0f0f0; border-radius: 4px; overflow: hidden; }
.progress-fill { height: 100%; background: linear-gradient(90deg, #4caf50, #8bc34a); transition: width 0.3s; display: flex; align-items: center; justify-content: center; color: white; font-weight: bold; }
.progress-text { text-align: center; margin-top: 5px; font-family: monospace; }
--></style>
</head>
<body>
<div class="progress-container">
<div class="progress-bar"><div class="progress-fill" id="bar" style="width:0%">0%</div></div>
<div class="progress-text" id="text">準備開始...</div>
</div>
<?php
if (ob_get_level() == 0) ob_start();
echo str_pad('', 4096)."<br />\n"; // 觸發瀏覽器開始渲染
for ($i = 0; $i <= 100; $i += 4) {
// 更新進度條寬度與文字
echo "<script>document.getElementById('bar').style.width='$i%'; document.getElementById('bar').textContent='$i%'; document.getElementById('text').textContent='進度: $i%';</script>\n";
flush();
ob_flush();
usleep(100000); // 模擬任務耗時 0.1 秒
}
ob_end_flush();
?>
<div class="progress-text">任務完成!</div>
</body>
</html>
| 技術點 | 作用 | 注意事項 |
|---|---|---|
str_pad('', 4096) | 發送足夠填充觸發瀏覽器渲染 | 不同瀏覽器門檻不同,4KB 較保險 |
flush() + ob_flush() | 雙重刷新確保數據送達客戶端 | 需關閉 gzip 壓縮或啟用 zlib.output_compression=Off |
usleep() | 微秒級延遲模擬真實任務 | 實際項目替換為真實業務邏輯 |
| 內聯 Script 更新 DOM | 無需 AJAX 輪詢即時更新 UI | 現代項目建議改用 Server-Sent Events 或 WebSocket |
php.ini 設定 zlib.output_compression=Off 或代碼中 @ini_set('zlib.output_compression', 0)proxy_buffering off; proxy_cache off; 禁用代理緩衝雖然現代 Web 開發傾向於前後端分離架構,但這種純 PHP 流式輸出方案在快速原型、內部工具、遷移專案中依然具有不可替代的輕量優勢。理解其底層機制,更能幫助你在架構選型時做出理性判斷。