session_start() 报“headers already sent”错误是因为其依赖set-cookie头,必须在任何输出(含bom、空格、html)前调用;常见原因包括文件开头/bom、include文件末尾空白、display_errors开启导致警告输出。

为什么 session_start() 会报 “headers already sent” 错误
因为 PHP 的 session 机制依赖于 Set-Cookie 响应头,而 session_start() 必须在任何输出(包括空格、BOM、echo、print、HTML)发送到浏览器前调用。一旦有输出,HTTP 头就已关闭,再调用 session_start() 就会触发这个错误。
常见触发位置和排查顺序
别急着改代码逻辑,先检查这些“隐形输出”点:
- PHP 文件开头或结尾存在空白字符(尤其是 UTF-8 BOM —— 用编辑器显示不可见字符功能确认)
-
require或include的文件(比如config.php、db.php)末尾有多余换行或空格 - 错误开启的
display_errors = On导致警告/Notice 被直接输出(例如未定义变量),抢占了 header 发送时机 - 在
session_start()前有echo、var_dump()、print_r()、甚至 HTML 注释(<!-- comment -->)
安全启用 session 的实操方式
不靠运气,用明确可控的方式启动 session:
- 把
session_start()放在所有可执行代码最顶部(<?php后立即调用),且确保该文件无任何前置输出 - 使用
session_start(['read_and_close' => true])在只读场景下减少锁竞争(如 AJAX 查询用户登录态) - 若必须在输出后操作 session(极少见),改用
session_write_close()提前释放 session 文件锁,但注意后续不能再写 session 变量 - 开发期开启
output_buffering = 4096(php.ini)可临时掩盖问题,但这是掩耳盗铃,上线前必须修复源头
调试时快速定位“谁先发了头”
错误信息末尾通常带路径和行号,比如:headers already sent by (output started at /var/www/app/auth.php:12)。重点看第 12 行及之前:
- 用
hexdump -C auth.php | head -n 20检查是否有 EF BB BF(BOM) - 在疑似文件开头加
if (headers_sent($file, $line)) { die("Headers sent at {$file}:{$line}"); } - 临时注释掉所有
include/require,逐个放开,缩小范围
BOM 和跨文件空白是最难一眼发现的点,花 2 分钟用 VS Code 的 “Show All Characters” 或 Sublime 的 “View → Show Console → print(open('file.php','rb').read()[:10])” 查一下,比改逻辑快得多。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











