先确认session_start()是否真正启动:调用后立即检查session_status()===PHP_SESSION_ACTIVE是否为true;确保无任何输出(含空格、BOM)在其前发生;检查浏览器Cookies中是否存在PHPSESSID;验证session.save_path可写及cookie参数配置正确。

别从“教程”开始学 PHP 会话——直接动手改代码、看报错、查 session_status(),才是最快上手的方式。
为什么 session_start() 总报 “headers already sent”?
这不是语法错误,是执行顺序和环境问题。只要在 session_start() 前有任何输出(哪怕一个空格、BOM 字符、echo、print、甚至 HTML 开头),PHP 就无法发送 session cookie 头,立刻报错。
- 用编辑器确认文件是 UTF-8 without BOM 编码(Sublime / VS Code / PHPStorm 都有显式选项)
- 检查当前文件顶部有没有空白行、空格,或
<?php前有没有字符 - 如果用了
require或include,被引入的文件也必须满足上述条件——错误提示里的 “line X” 往往只是第一个输出位置,不是根源 - 临时加一句
var_dump(headers_sent());在session_start()前,能立刻验证是否已发头
$_SESSION 存了数据,刷新后却为空?
说明 session 数据根本没写入,或写入后无法读回。常见原因不是代码写错了,而是底层链路断了。
- 运行
var_dump(session_save_path());看路径,再用is_writable(session_save_path())检查是否可写(尤其 Windows 下 IIS 或某些 Docker 环境常因权限失败) - 浏览器是否禁用了 Cookie?默认 session 靠
PHPSESSIDcookie 传递;可临时加两行测试 URL 传参:ini_set('session.use_cookies', 0); ini_set('session.use_trans_sid', 1);(仅调试用,勿上线) - 子域名不一致时(如登录页在
auth.example.com,跳转到app.example.com),需提前调用session_set_cookie_params(['domain' => '.example.com']),且必须在session_start()之前 - 隐私模式窗口反复开闭会重置 cookie,别用它做连贯性测试
并发请求下 session 数据卡住、页面假死?
PHP 默认用文件存 session,session_start() 会给对应 session 文件加锁,直到脚本结束或手动释放。AJAX 请求、轮询、多标签页都可能互相阻塞。
立即学习“PHP免费学习笔记(深入)”;
- 一旦你修改了
$_SESSION,立刻调用session_write_close()—— 它会把当前数据写入存储并释放文件锁,后续代码还能读$_SESSION,但不能再写 - 不要等整个脚本跑完才写:比如登录成功后赋值
$_SESSION['user_id'] = 123;,紧接着就session_write_close();,再跳转或返回 JSON - 若需长期保持写权限(如长轮询),考虑切换 session handler:用 Redis(
session.save_handler = redis)或数据库,彻底避开文件锁
怎么安全地用 $_SESSION 存敏感信息?
它本身不加密、不签名、不绑定 IP 或 UA,只靠 session ID 作唯一标识。直接存密码、token 原文等于裸奔。
- 绝不存
$_SESSION['password']或$_SESSION['api_token']—— 改用服务端缓存(如 Redis)+ 随机 key,session 里只存该 key - 需要校验时用
hash_equals()对比 token,避免时序攻击 - 启用
session.use_strict_mode = 1(php.ini 或ini_set()),拒绝未初始化的 session ID,防会话固定攻击 - 登录后务必调用
session_regenerate_id(true),销毁旧 session 文件并生成新 ID
真正卡住人的从来不是 $_SESSION['xxx'] = yyy 这一行代码,而是 session ID 怎么来、存在哪、谁有权读、什么时候过期、并发时谁先写——这些环节任何一个松动,都会让 session 表现得“时灵时不灵”。调试时优先看 session_id() 和 session_status() 返回值,比盲目 echo 更快定位问题。



















