PHP中使用$_SESSION前必须调用session_start()且不能有任何输出,否则报“Headers already sent”;setcookie()参数易错,需注意时间戳、path、domain、secure、httponly及samesite;$_COOKIE无法立即读取刚设置的值;销毁Session需清空数组、destroy文件并过期客户端Cookie。

PHP中直接用$_SESSION存数据前,必须先调用session_start(),且不能有任何输出(包括空格、BOM、echo),否则会报“Headers already sent”错误——这是90%以上初学者卡住的第一关。
session_start() 为什么总报错?
核心原因是HTTP响应头已发送,而session_start()需要在头发出前注册会话ID。常见触发点有:
- PHP文件开头存在UTF-8 BOM(尤其Windows编辑器保存时默认带)
-
session_start()之前有echo、print、HTML标签、甚至换行或空格 - 包含的其他PHP文件(如
require 'config.php')里提前输出了内容 - 启用
output_buffering可缓解,但治标不治本,建议从源头清理
调试方法:用var_dump(headers_sent($file, $line))定位哪行开始输出;用编辑器检查BOM(如VS Code右下角显示“UTF-8 with BOM”需转为“UTF-8”)。
setcookie() 的参数顺序和安全陷阱
setcookie()第3–6个参数极易配错,直接影响Cookie是否能被读取或发送:
立即学习“PHP免费学习笔记(深入)”;
- 第3个参数是
expires,必须是**时间戳(int)**,不是字符串,time() + 3600正确,'1 hour'直接失效 - 第4个参数
path设为'/'才能全站共享;设为'/admin/'则仅/admin/及其子路径可读 - 第5个参数
domain若跨子域(如user.example.com和api.example.com),必须写成'.example.com'(开头带点) - 第6个参数
secure设为true时,只在HTTPS下发送;httponly设为true可防XSS窃取(推荐始终开启) - PHP 7.3+支持第7个参数
samesite,值为'Strict'或'Lax',能有效缓解CSRF,别漏掉
示例:setcookie('token', $value, time() + 86400, '/', '.example.com', true, true) —— 这才是生产环境该写的写法。
$_COOKIE 读不到刚设的值?
这是正常现象:setcookie()只是告诉浏览器“下次请求带上这个”,当前请求的$_COOKIE仍是上一次请求携带过来的旧值。
- 刚调用
setcookie()后立刻var_dump($_COOKIE['xxx']),结果是NULL或旧值 - 要验证是否设置成功,得刷新页面或发起新请求,再看
$_COOKIE - 如果刷新后仍读不到,检查
domain和path是否匹配当前URL(比如domain设成'example.com',但访问的是www.example.com就不匹配) - 浏览器开发者工具Application → Cookies里能看到实际存储的键名、过期时间、domain/path,比盲猜可靠得多
session_destroy() 和 unset($_SESSION) 的区别
销毁Session不是“清空数组”那么简单:
-
unset($_SESSION)只是把PHP变量置为NULL,但Session文件还在服务器上,ID也未失效,下次请求仍可恢复数据 -
session_destroy()才真正删除服务器端的Session数据文件,但$_SESSION数组本身还存在(可能含残留值) - 安全做法是三步:先
$_SESSION = []清空数组,再session_destroy()删文件,最后用setcookie()把客户端的PHPSESSID设为过期(time() - 3600) - 登录态退出必须做这三步,否则攻击者拿到旧Session ID仍可能复用
Session ID重生成也很关键:登录成功后立即调用session_regenerate_id(true),防止会话固定攻击——这点常被忽略,但直接影响账户安全。



















