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

PHP session_start() 報錯「Headers Already Sent」原因徹底解析與解決方案

     編輯:PHP 相關知識

錯誤現象

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/printecho '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, </h1>
</body></html>

✅ 方案二:輸出緩衝 ob_start()(快速修復)

在文件**最開頭**(ob_start(),將後續所有輸出緩存到內存,腳本結束或 ob_end_flush() 時一次性發送 Headers + Body。

<?php
ob_start(); // 必須在第一行,前面連空格都不能有
session_start();
// ... 其餘代碼
echo '輸出內容'; // 實際進入緩衝區
?>

優點:不改動業務邏輯結構,兼容舊代碼。缺點:增加內存佔用(大頁面慎用),掩蓋了結構問題,調試時輸出延遲。

✅ 方案三:移除 BOM 头

使用編輯器(VS Code、PhpStorm、Notepad++、Sublime)以 **UTF-8 無 BOM** 格式保存所有 PHP 文件。

  • VS Code:右下角編碼點擊 → "Save with Encoding" → "UTF-8"
  • Notepad++:編碼 → 轉為 UTF-8 (無 BOM)
  • 批量檢查: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 並鎖定文件。長請求可提前釋放鎖:

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 直接指明**第一個輸出的位置**。

  • 打開該文件第 3 行,檢查是否有空白、HTML、echo、include 輸出。
  • 若指向 include/require 文件,遞歸檢查被包含文件。
  • 若行號為 1,極大概率是 BOM 头或

總結

  1. 核心規則:session_start() 前**零輸出**。
  2. 最佳實踐:代碼分層,邏輯在前,模板在後(MVC 模式天然避免此問題)。
  3. 快速修復:文件頂部 ob_start() + 移除 BOM + 關閉 display_errors。
  4. 性能優化:長任務中使用 session_write_close() 釋放 Session 鎖。
  5. 生產環境:display_errors=Off,錯誤寫日志,不輸出到頁面。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved