PHP 会话管理
HTTP 是无状态协议——每次请求都是独立的,服务器默认记不住"你是谁"。但 Web 应用需要"登录一次就记住",购物车要跨页面保留,这些都需要会话机制。PHP 内置 Cookie 和 Session,让跨请求状态管理开箱即用。
1. Cookie:存在浏览器的小数据
Cookie 是服务器发给浏览器的一段小数据,浏览器会在后续每次请求都带回来。常用于:记住用户偏好、跟踪(分析)、轻量状态。
<?php
// 设置 Cookie:setcookie 必须在任何输出之前调用
// setcookie(name, value, expire, path, domain, secure, httponly)
setcookie("user", "小明", time() + 3600, "/");
// 1 小时后过期(time() 是当前 Unix 时间戳)
// 读取 Cookie(下次请求才能读到)
echo $_COOKIE["user"] ?? "无"; // 下一次访问页面时显示 小明
// 删除 Cookie:设过期时间为过去
setcookie("user", "", time() - 3600, "/");
// Cookie 限制
// - 必须在输出之前设置(不能在 echo 之后)
// - 大小约 4KB
// - 每个域名一般限制 50 个
// - 用户可在浏览器禁用几个限制和要点:
- 4KB 上限、每域名约 50 个——存小数据,别塞大对象。
- setcookie 必须在任何输出之前——和
header()一样,因为它是 HTTP 头。哪怕一个空格也不行。 - 下次请求才能读到:当前请求设置后,浏览器要下次请求才会带回来。
- 用户可禁用:重要状态别完全依赖 Cookie,提供降级方案。
- 不要存敏感数据:Cookie 在浏览器里,用户可看可改,容易被窃取。
2. Cookie 安全属性(必懂!)
默认 Cookie 不安全——会被 JS 偷(XSS)、会被中间人窃听、会被跨站发送(CSRF)。设置安全属性能从根本上防御:
<?php
// 安全 Cookie:加 httponly 和 secure 标志
setcookie("session_id", $sid, [
"expires" => time() + 3600,
"path" => "/",
"secure" => true, // 仅 HTTPS 传输
"httponly" => true, // JS 不能通过 document.cookie 读取(防 XSS)
"samesite" => "Lax", // 防 CSRF(PHP 7.3+)
]);
// httponly 强烈建议开启:即使有 XSS 也偷不到 Cookie
// secure 在 HTTPS 上线后必须开- httponly:JavaScript 读不到,防 XSS 偷 Cookie。默认就该开。
- secure:只在 HTTPS 上传输,防中间人窃听。HTTPS 网站必开。
- samesite:控制跨站是否发送。
Lax或Strict防 CSRF。
3. Session:存在服务器的状态
Session 把数据存在服务器,只在浏览器存一个Session ID(通过 Cookie 传递)。这解决了 Cookie 不安全、容量小的缺点:
<?php
// session_start 必须在使用 session 的页面最前面调用
session_start();
// 存数据
$_SESSION["user_id"] = 42;
$_SESSION["username"] = "小明";
$_SESSION["login_time"] = time();
// 读数据(其他页面)
echo $_SESSION["username"] ?? "未登录";
// 检查是否登录
function isLogin(): bool {
return isset($_SESSION["user_id"]);
}
// 删除单个 session 数据
unset($_SESSION["temp"]);
// 清空所有 session 数据
$_SESSION = [];
session_destroy(); // 销毁 session 文件4. Session 工作原理
理解原理比记 API 重要:
Session 工作原理:
1. 用户第一次访问,session_start() 检测不到 SID Cookie
2. PHP 生成一个唯一 ID(如 a3f...),
通过 Set-Cookie 发给浏览器(PHPSESSID=...)
3. 在服务器创建文件 /var/lib/php/sessions/sess_a3f...
4. 之后用户每次请求都带这个 Cookie
5. PHP 据此找到对应文件,把数据加载到 $_SESSION
6. 程序结束时 PHP 把 $_SESSION 写回文件
关键点:
- session 数据存在服务器,Cookie 只存 ID
- 比 Cookie 安全:用户看不到数据内容
- 大小无 4KB 限制
- 默认存储为文件,大网站用 Redis/Memcached 存储关键术语:
- Session ID(SID):服务器生成的唯一标识,默认通过名为
PHPSESSID的 Cookie 传递。 - Session 文件:默认存在
/var/lib/php/sessions/,文件名sess_<SID>,内容是序列化的$_SESSION。 - session_start():每个使用 session 的页面都要调用,作用是加载当前请求的 session 数据。
5. 完整登录实战
登录、保护页面、登出——这是 PHP Web 开发的核心三连击:
<?php
// 登录页面 login.php
session_start();
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$username = trim($_POST["username"] ?? "");
$password = $_POST["password"] ?? "";
// 从数据库查用户(伪代码)
$user = findUserByUsername($username);
// 验证密码(password_verify 第 16 章详讲)
if ($user && password_verify($password, $user["password_hash"])) {
// 登录成功:把用户信息存进 session
session_regenerate_id(true); // 防止 session 固定攻击
$_SESSION["user_id"] = $user["id"];
$_SESSION["username"] = $user["name"];
header("Location: /dashboard.php");
exit;
} else {
$error = "用户名或密码错误";
}
}
// 受保护页面 dashboard.php
session_start();
if (!isset($_SESSION["user_id"])) {
header("Location: /login.php");
exit;
}
echo "欢迎," . htmlspecialchars($_SESSION["username"]);
// 登出 logout.php
session_start();
$_SESSION = [];
session_destroy();
header("Location: /login.php");几个关键安全点:
- 密码用 password_hash / password_verify:绝不明文存密码,详见第 16 章。
- 登录成功后 session_regenerate_id(true):删除旧 session 文件,生成新 SID——防止 session 固定攻击(攻击者预先设置 SID)。
- 受保护页面统一检查:把"是否登录"封装成函数或中间件,每个受保护页面都调用。
- 登出清空 + 销毁:既要清
$_SESSION也要session_destroy()。
6. Session 配置(php.ini)
关键配置项:
session.cookie_httponly = 1— Session Cookie 设 httponly,默认就开。session.cookie_secure = 1— 仅 HTTPS(上线后开)。session.cookie_samesite = "Lax"— 防 CSRF。session.gc_maxlifetime = 1440— session 数据保留秒数(默认 24 分钟)。session.save_handler = redis— 大网站用 Redis 替代文件存储。
也可以在代码里运行时改:ini_set("session.gc_maxlifetime", 3600);——但必须在 session_start() 之前。
7. Cookie vs Session 选哪个?
- 敏感数据(登录状态、用户 ID):用 Session。
- 非敏感偏好(主题、语言、最近浏览):用 Cookie,减轻服务器压力。
- "记住我":Cookie 存长期 token,服务端校验。不要把 user_id 明文存 Cookie!
- 大流量网站:Session 集中存 Redis,多台服务器共享。
8. Flash 数据(一次性消息)
"提交成功后跳转显示一条提示,刷新就消失"——这种叫 flash 消息。用 session 实现:
- 设置:
$_SESSION["flash"] = "操作成功"; - 显示后立即 unset:
echo $_SESSION["flash"]; unset($_SESSION["flash"]); - 常见于 PRG 模式(Post / Redirect / Get)的提示信息。
小结
这一章你掌握了 PHP 会话管理的全部内容:Cookie 读写和安全属性、Session 原理、登录登出实战、Session 配置。下一篇面向对象——用类和对象组织更复杂的代码。
← 上一篇 PHP 表单处理
下一篇 PHP 面向对象 →