Warning: session_start(): Cannot send session cache limiter - headers already sent
(output started at /path/to/file.php:3) in /path/to/file.php on line 5
HTTP 協議規定:Headers 必須在 Body 之前發送,且只能發送一次。
session_start() 需要發送 Set-Cookie Header(設置 Session ID)。如果在調用它之前**已經有任何輸出**(HTML 空白、echo、print_r、var_dump、BOM 头、錯誤信息、include 文件中的輸出),PHP 會被迫提前發送 Headers 並開始輸出 Body,導致後續 session_start() 無法發送 Cookie Header,拋出警告並**Session 功能失效**(無法讀寫 $_SESSION)。
| 場景 | 示例代碼 |
|---|---|
| 文件開頭有空白/換行 | <?php\n\nsession_start(); (?> 後的換行也算) |
| 調用前有 echo/print | echo 'test'; session_start(); |
| 包含文件輸出內容 | include 'header.php'; // 文件中有 HTML session_start(); |
| UTF-8 BOM 头 | 文件以 EF BB BF 開頭(Windows 記事本保存常見) |
| 錯誤/警告輸出 | error_reporting(E_ALL); ini_set('display_errors',1); // 觸發 Notice 即輸出 session_start(); |
| 前端框架模板輸出 | Smarty/Twig/Blade 模板渲染輸出後調用 session_start() |
原則:所有 PHP 邏輯(含 session_start)在**任何輸出**之前完成。
<?php
// 1. 頂部:配置、Session、資料庫、業務邏輯
session_start(); // 第一行業務代碼
$_SESSION['user'] = 'admin';
// 2. 獲取/處理數據
$data = getData();
// 3. 最後:輸出模板
?><!DOCTYPE html>
<html><body>
<h1>Welcome, = htmlspecialchars($_SESSION['user']) ?></h1>
</body></html>
ob_start()(快速修復)在文件**最開頭**(ob_start(),將後續所有輸出緩存到內存,腳本結束或 ob_end_flush() 時一次性發送 Headers + Body。
<?php
ob_start(); // 必須在第一行,前面連空格都不能有
session_start();
// ... 其餘代碼
echo '輸出內容'; // 實際進入緩衝區
?>
優點:不改動業務邏輯結構,兼容舊代碼。缺點:增加內存佔用(大頁面慎用),掩蓋了結構問題,調試時輸出延遲。
使用編輯器(VS Code、PhpStorm、Notepad++、Sublime)以 **UTF-8 無 BOM** 格式保存所有 PHP 文件。
grep -r $'\xEF\xBB\xBF' . --include="*.php"ini_set('display_errors', '0'); // 不在頁面顯示錯誤
error_reporting(E_ALL); // 但記錄所有級別
ini_set('log_errors', '1');
ini_set('error_log', '/var/log/php_errors.log');
防止 Notice/Warning 成為「輸出」導致 Headers Already Sent。
默認腳本結束自動寫入 Session 並鎖定文件。長請求可提前釋放鎖:
session_start();
// 讀取/寫入 $_SESSION
$_SESSION['last_visit'] = time();
// 業務邏輯耗時較長...
sleep(5);
// 提前關閉 Session 寫入,釋放鎖,允許並發請求訪問 Session
session_write_close();
// 後續耗時操作(發郵件、調用外部 API、生成報表)
// 此期間其他請求可正常 session_start() 讀取 Session
sendEmail();
generateReport();
錯誤信息 output started at /path/file.php:3 直接指明**第一個輸出的位置**。
include/require 文件,遞歸檢查被包含文件。session_start() 前**零輸出**。ob_start() + 移除 BOM + 關閉 display_errors。session_write_close() 釋放 Session 鎖。display_errors=Off,錯誤寫日志,不輸出到頁面。