在 PHP 中,header()、setcookie() 等發送 HTTP 頭部的函數必須在任何實際輸出(包括空白字符、換行)之前調用,否則會拋出 Headers already sent 錯誤。輸出緩衝(Output Buffering)機制允許我們將腳本輸出暫存於伺服器內存,延遲發送至瀏覽器,從而靈活控制頭部輸出順序。
| 函數 | 說明 |
|---|---|
ob_start() | 開啟輸出緩衝,後續輸出(echo、print、HTML 等)暫存於緩衝區,不直接發送給瀏覽器。 |
ob_get_contents() | 返回當前緩衝區內容(字符串),若緩衝未開啟則返回 false。 |
ob_get_length() | 返回緩衝區內容長度(位元組),未開啟則返回 false。 |
ob_end_flush() | 發送緩衝區內容至瀏覽器並關閉緩衝區。 |
ob_end_clean() | 丟棄緩衝區內容並關閉緩衝區,不輸出任何內容。 |
flush() | 刷新 PHP 輸出緩衝至 Web 伺服器(不影響輸出緩衝區本身),常配合 ob_flush() 使用。 |
<?php
ob_start(); // 1. 開啟緩衝
echo '調試信息:用戶登入成功'; // 2. 輸出暫存
header('Location: dashboard.php'); // 3. 發送重定向頭部(此時無任何實際輸出)
ob_end_flush(); // 4. 發送緩衝內容並關閉(瀏覽器收到頭部後會跳轉,調試信息通常不會被看到)
?>
關鍵點:若移除 ob_start(),echo 會直接輸出,導致 header() 失敗。
<?php
ob_start(function ($buffer) {
// 替換敏感詞、壓縮 HTML、注入 CSRF token 等
return str_replace('舊域名.com', '新域名.com', $buffer);
});
echo '<a href="https://舊域名.com">鏈接</a>';
ob_end_flush(); // 經過回調處理後輸出
?>
ob_start() 可多次調用,形成堆疊,需成對調用 ob_end_flush() / ob_end_clean()。flush() 僅將 PHP 緩衝推送到 Web 伺服器(如 Apache/Nginx),後者可能仍有自己的緩衝策略(如 gzip、fastcgi_buffer)。ob_start('ob_gzhandler') 同時實現壓縮。php.ini 設定:output_buffering = 4096 可全局啟用 4KB 緩衝,但顯式調用 ob_start() 更可控。掌握輸出緩衡控制是 PHP 開發進階的必備技能。合理使用 ob_start() 系列函數,不僅能解決「Headers already sent」難題,還能實現頁面壓縮、內容替換、異步輸出等高級功能,提升應用靈活性與用戶體驗。