结论:必须在session_start()前禁止任何输出,否则报“headers already sent”错误;因其依赖http响应头,而响应头须在所有输出前发送。

直接说结论:别用 session_start() 前输出任何内容,包括空格、BOM、echo、HTML 标签——否则铁定报错“headers already sent”。
为什么 session_start() 一调就报错“headers already sent”
PHP 的 session 依赖 HTTP 响应头(Set-Cookie),而响应头必须在任何实际输出之前发送。一旦你写了 echo、输出了空格、文件开头有 UTF-8 BOM,或者引入了带输出的文件,PHP 就再也发不出 session 头了。
常见诱因:
- PHP 文件开头有空行或空格(连
<?php前都不能有) - 被
include或require的配置文件末尾多了一个换行 - 编辑器保存为 UTF-8 with BOM(尤其是 Windows 上的记事本、某些旧版 IDE)
- 在
session_start()前用了print_r($_GET)、var_dump()调试
session_start() 的参数怎么选才不踩坑
它不是无脑调用就行。默认行为在多数场景下反而容易出问题,尤其涉及子域名、HTTPS 或安全策略时。
推荐写法(兼顾安全与兼容):
session_start([
'cookie_httponly' => true,
'cookie_secure' => isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on',
'use_strict_mode' => true,
'cookie_samesite' => 'Lax'
]);
关键点说明:
-
cookie_httponly:防止 JS 读取PHPSESSID,必开 -
cookie_secure:只在 HTTPS 下发送 cookie,线上环境务必判断并启用 -
use_strict_mode:拒绝客户端传来的非法 session_id,防会话固定攻击 -
cookie_samesite:设为Lax可平衡 CSRF 防御和表单提交兼容性 - 不要手动设
session_name()或session_id(),除非真有跨系统共享需求
session 在 CLI 环境或 API 接口里为啥不生效
CLI 模式下没有 HTTP 请求上下文,session_start() 会静默失败(或抛 warning),且无法设置 cookie;纯 JSON API 也不该依赖传统 session cookie。
真实场景应对方式:
- CLI 脚本需要状态?改用
apcu_store()或 Redis 存临时数据,别碰 session - 前后端分离的 API:用 JWT 或数据库 token 表管理登录态,
session_start()对它没意义 - 如果硬要在 API 中复用 Web 端 session(比如混合架构),确保请求带
Cookie: PHPSESSID=xxx,且服务端没禁用session.use_cookies = 1 - 检查
session.save_handler:默认files在容器或无写入权限目录下会静默失败,可用var_dump(session_status() === PHP_SESSION_ACTIVE)验证是否真启动成功
最常被忽略的一点:session 生命周期不是靠 session_start() 控制的,而是由 session.gc_maxlifetime 和存储后端共同决定。哪怕你每秒都调一次 session_start(),超时后照样销毁——别以为“常开 session 就不会过期”。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











