Warning: session_start(): Cannot send session cookie - headers already sent by
(output started at /path/to/config.php:1) in /path/to/index.php on line 3
Warning: session_start(): Cannot send session cache limiter - headers already sent
(output started at /path/to/config.php:1) in /path/to/index.php on line 3
HTTP 協議規定:Header 必須在 Body 之前發送,且 Header 發送後不可修改。
session_start() 內部需要發送 Set-Cookie Header。若在此之前已有任何輸出(哪怕一個空格、換行、BOM、錯誤信息、HTML 標籤),Web 服務器會隱式發送默認 Header 並開始輸出 Body,導致後續 session_start() 無法發送 Cookie Header。
| 來源 | 現象 | 檢測方法 | 解決 |
|---|---|---|---|
| PHP 文件 BOM | 文件開頭隱藏 3 字節 EF BB BF | 編輯器狀態欄 / file -bi / hexdump -C | 編輯器「保存為 UTF-8 無 BOM」 |
<?php 前的空白/換行 | 文件最開頭有空行/縮進 | 肉眼檢查 / head -c 20 file.php | 刪除所有前導字符,<?php 必須在第 1 行第 1 列 |
?> 後的空白/換行 | 純 PHP 文件末尾有閉合標籤及後續內容 | 肉眼檢查 | 純 PHP 文件刪除 ?>(PSR-12 推薦) |
| include/require 文件輸出 | 被包含文件有 echo/print/var_dump/HTML/空白 | 錯誤信息 output started at included_file.php:行號 | 清理被包含文件,確保無輸出 |
| 錯誤/警告輸出 | display_errors=On 導致 Warning 先於 session 輸出 | 錯誤信息顯示 Warning 內容 | 生產環境 display_errors=Off,或修復 Warning 根因 |
?>**。<?php 必須位於文件第一字節。session_start() 放在最頂部,任何 HTML/echo 之前。<?php
// 方案 A:php.ini 全局開啟(推薦開發環境)
output_buffering = 4096
// 方案 B:代碼中開啟(必須在最頂部,任何輸出前)
ob_start();
// 或帶回調處理
ob_start(function($buffer) {
return $buffer; // 可在此修改輸出
});
session_start(); // 現在安全,Cookie 存入緩衝區
// 後續業務...
// 腳本結束自動 flush 緩衝區
?>
原理:
ob_start()開啟輸出緩衝區,所有echo/ob_end_flush()時一次性發送。此時session_start()的 Header 也在緩衝區中,不會觸發「headers already sent」。
<?php
@session_start(); // 隱藏 Warning,但 Cookie 可能真正發送失敗,Session 功能失效
?>
<?php
// 在 session_start() 前臨時添加
headers_sent($file, $line);
if (headers_sent()) {
die("Headers already sent in $file at line $line");
}
session_start();
?>
<?php
// 掃描項目目錄所有 PHP 文件檢測 BOM
$dir = __DIR__;
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir));
foreach ($iterator as $file) {
if ($file->isFile() && $file->getExtension() === 'php') {
$content = file_get_contents($file->getPathname());
if (strlen($content) >= 3 && substr($content, 0, 3) === "\xEF\xBB\xBF") {
echo "BOM found: {$file->getPathname()}\n";
}
}
}
?>
<?php
// 生產環境 php.ini / 入口文件
ini_set('display_errors', '0'); // 不顯示錯誤
ini_set('log_errors', '1'); // 記錄日誌
ini_set('error_log', '/var/log/php/error.log');
error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT);
// 自定義錯誤處理器(避免錯誤輸出干擾 Header)
set_error_handler(function($severity, $message, $file, $line) {
if (!(error_reporting() & $severity)) return false;
error_log("[$severity] $message in $file:$line");
return true; // 不執行內部處理器(不輸出)
});
?>
session_start() 需發送 Cookie Header,之前有任何輸出(BOM、空白、錯誤、HTML)即觸發錯誤。?>、<?php 頂格、包含文件無輸出、session_start() 放最頂部。ob_start() 或 output_buffering = 4096,但掩蓋了代碼規範問題。display_errors=Off,統一日誌記錄,避免錯誤輸出破壞 Header。