在 PHP 開發中,「Warning: Cannot modify header information - headers already sent by」是開發者極常遇到的經典錯誤。本文將從錯誤成因、核心解決方案、輸出緩衝機制原理,以及 BOM 編碼陷阱等多個維度,為你提供徹底的解決思路。
典型觸發代碼如下:
session_start();
$_SESSION['username'] = $username;
echo "<script language='javascript'>location.href='../admin.php';</script>";
exit();
執行後拋出警告:Warning: Cannot modify header information - headers already sent by...
HTTP 協議規定:Header 必須在 Body 之前發送。一旦腳本輸出任何內容(包括空白字符、HTML 標籤、echo/print 輸出),Web 服務器即啟動 Header 發送流程,後續再調用 header()、session_start()、setcookie() 等修改 Header 的函數,便會觸發此錯誤。
修改 php.ini,將 output_buffering 設為 On 或具體數值(預設 4096 Bytes):
output_buffering = On
重啟 Apache/Nginx 後生效。此舉會在內存中緩衝所有輸出,腳本結束或調用 ob_end_flush() 時再一次性發送 Header + Body,從根本上避免順序衝突。
原理:PHP 將 echo、print 等輸出寫入內存緩衝區,直到緩衝區寫滿或腳本結束,才經 TCP 傳給瀏覽器。配合 ob_start() 可手動擴大緩衝空間,確保大量輸出也不會過早觸發 Header 發送。
若啟用緩衝後仍報錯,極大概率是文件保存為 UTF-8 with BOM 格式。BOM 為文件開頭的 3 個隱藏字節(EF BB BF),用於標識編碼,但 PHP 不會忽略它,導致在任何 Header 操作前已有輸出。
補充:BOM 導致 Cookie/Session 失效,也是 WordPress 後台白屏的常見原因之一。
從架構層面杜絕輸出先於 Header:
header()、session_start()、setcookie() 放在 任何輸出之前(包括 HTML、空白行、BOM)| 誤區 | 正確做法 |
|---|---|
| 在 HTML 標籤前後夾雜 PHP 輸出 | 統一在文件頂部完成 Header/Session 操作 |
| include/require 引入的文件含 BOM 或前置空白 | 所有引入文件均用無 BOM 編碼,且無輸出 |
| 依賴 output_buffering 掩蓋架構缺陷 | 緩衝是保護網,規範代碼結構才是根本 |
若不想改 php.ini,可在腳本入口手動啟用:
<?php
ob_start(); // 開啟輸出緩衝
// 所有業務邏輯、header、session 操作
// ...
// 輸出 HTML
?>
<!DOCTYPE html>
<html>...</html>
<?php
ob_end_flush(); // 發送緩衝內容並關閉緩衝
?>
「Headers already sent」本質是輸出順序違反 HTTP 協議。解決優先級:
掌握輸出緩衝機制,不僅能解決此錯誤,更能優化大數據輸出性能、實現靜態頁緩存等進階應用。