`Warning: Cannot modify header information - headers already sent by ...` 表示 **HTTP 頭部已發送**,隨後嘗試調用 `header()`、`setcookie()`、`session_start()` 等發送頭部的函數失敗。
HTTP 協議規定:**頭部必須在內容主體之前發送,且只能發送一次**。任何輸出(`echo`、HTML 空白、BOM、錯誤信息)都會導致 PHP 發送頭部並開始輸出主體。
| 原因 | 典型代碼 | 解決方案 |
|---|---|---|
| 文件開頭有空白/換行/BOM | ` | 刪除空白;用編輯器「另存為無 BOM UTF-8」 |
| header/setcookie/session_start 前有輸出 | `echo '...'; header('Location:...');` | 移動頭部操作到**所有輸出之前** |
| 包含文件輸出了內容 | `include 'config.php';` 文件末尾有 `?>` 後空白 | **純 PHP 文件省略結束標籤 `?>`** |
| 錯誤/警告輸出 | `Warning: include(...)` 在 header 前 | 開發環境顯示錯誤,生產環境 `display_errors=Off` + `log_errors=On` |
| Session 自動啟動輸出 | `session.auto_start = On` 且輸出在前 | 關閉 `session.auto_start`,手動控制 `session_start()` 位置 |
在腳本**最頂部**(`
頁面
| 場景 | 對策 |
|---|---|
| 文件下載 | 先 `header()` 設置類型/離線名,再 `readfile()`/`echo` 內容;大文件用 `ob_end_clean()` 清除前序緩衝 |
| AJAX 返回 JSON | 確保 `header('Content-Type: application/json')` 在任何 `echo`/`print` 前;框架通常自動處理 |
| 重定向後仍有代碼執行 | `header('Location: ...'); exit;` **必須跟 `exit`/`die`**,否則腳本繼續執行可能輸出 |
| Composer 自動加載器輸出 | 檢查 `vendor/autoload.php` 末尾無 `?>` 及空白;正規包無此問題 |
遵循「先邏輯後輸出」、杜絕 BOM、善用緩衝,徹底告別 headers already sent 錯誤。