首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

解決 PHP "Cannot modify header information - headers already sent" 錯誤的三大核心方案與原理深度解析

     編輯:PHP 綜合知識

經典錯誤 Warning: Cannot modify header information - headers already sent by... 困擾無數 PHP 開發者。本文從 HTTP 協議層面剖析成因,提供三大徹底解決方案與最佳實踐。

錯誤觸發典型場景

<?php
session_start();
$_SESSION['username'] = $username;
// 輸出 HTML/JS 導致 Header 已送出
echo "<script>location.href='../admin.php';</script>";
exit;
?>

任何在 header()、session_start()、setcookie() 之前的輸出(包括空白字元、BOM、HTML、echo/print、錯誤訊息)都會導致 HTTP Header 提前送出,後續 Header 操作即失敗。

方案一:啟用 Output Buffering(輸出緩衝)── 最簡單有效

方法 1:修改 php.ini(全域生效)

output_buffering = 4096  ; 或 On(無限制緩衝),單位位元組

原理:PHP 將輸出先存入內部緩衝區(預設 4KB),直到腳本結束或緩衝區滿才發送給瀏覽器,此期間可隨意呼叫 Header 相關函式。

方法 2:腳本開頭呼叫 ob_start()(局部控制)

<?php
ob_start(); // 開啟輸出緩衝,必須在任何輸出之前
session_start();
$_SESSION['username'] = $username;
echo "<script>location.href='../admin.php';</script>";
// 腳本結束自動 flush,或手動 ob_end_flush()
?>

進階:ob_start('ob_gzhandler') 可同時啟用 GZIP 壓縮輸出。

方案二:消除 BOM(Byte Order Mark)── 隱形殺手

現象:檔案以 UTF-8 with BOM 編碼儲存,開頭三個位元組 EF BB BF 會被 PHP 直接輸出,導致 Header 提前送出。

檢測:hexdump -C file.php | head -1 或編輯器(VS Code、Notepad++、PhpStorm)右下角編碼顯示。

解決:全專案統一使用「UTF-8 無 BOM」編碼儲存。現代編輯器預設即為無 BOM,僅舊版 Windows 記事本會強制加入 BOM。

影響:BOM 亦會導致 session_start() 失效、Cookie 無法送出、XML/JSON 輸出解析錯誤。

方案三:架構層面徹底分離輸出與邏輯(MVC/模板引擎)

  • 控制器僅處理邏輯、設定變數、呼叫 header()/session_start()。
  • 視圖檔案僅負責輸出 HTML,不包含任何 PHP 邏輯判斷。
  • 使用模板引擎(Twig、Blade、Smarty)或框架(Laravel、Symfony、Yii)強制分離。

Output Buffering 運作原理深度解析

  1. 腳本啟動,PHP 內核準備輸出緩衝區(若 output_buffering 開啟或呼叫 ob_start())。
  2. 所有 echo、print、HTML 區塊輸出寫入緩衝區,不發送給 TCP 層。
  3. header()、setcookie()、session_start() 將 Header 存入內部 Header 列表,不立即發送。
  4. 腳本結束或呼叫 ob_end_flush(),PHP 依序發送:Header 列表 → 空行 → 緩衝區內容。
  5. 若緩衝區超過限制(預設 4KB),自動 flush 發送,後續 Header 操作將失效。

常見誤區與避坑指南

誤區正確認知
set_time_limit() 影響 Header 發送無關,set_time_limit 控制腳本最大執行秒數
在 include/require 檔案中輸出不算算!被包含檔案的輸出同樣會觸發 Header 送出
只有 echo 才算輸出print、printf、var_dump、HTML 區塊、錯誤訊息、BOM 皆算
用 ob_start() 就能無限制輸出記憶體耗盡仍會崩潰,大量輸出應改用串流 fwrite(STDOUT, ...) 或分塊 flush

快速診斷腳本

<?php
// 放在專案入口檔案最頂端,檢測是否已有輸出
if (headers_sent($file, $line)) {
    error_log("Headers already sent in $file on line $line");
    // 開發環境可直接 die 顯示
    // die("Headers sent at $file:$line");
}
?>

掌握 HTTP Header 輸出機制、啟用 Output Buffering、杜絕 BOM、採用分層架構,即可徹底根治此經典錯誤。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved