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 个
// - 用户可在浏览器禁用

几个限制和要点:

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 上线后必须开

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 存储

关键术语:

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");

几个关键安全点:

6. Session 配置(php.ini)

关键配置项:

也可以在代码里运行时改:ini_set("session.gc_maxlifetime", 3600);——但必须在 session_start() 之前。

7. Cookie vs Session 选哪个?

8. Flash 数据(一次性消息)

"提交成功后跳转显示一条提示,刷新就消失"——这种叫 flash 消息。用 session 实现:

小结

这一章你掌握了 PHP 会话管理的全部内容:Cookie 读写和安全属性、Session 原理、登录登出实战、Session 配置。下一篇面向对象——用类和对象组织更复杂的代码。

← 上一篇 PHP 表单处理

下一篇 PHP 面向对象

✈️💬