PHP: Session与登录

Cookie 把数据存在用户浏览器,Session 把数据存在服务器。登录状态、购物车、权限信息——这些不该让用户接触的数据就该用 Session。这节课你还能写出你的第一个登录系统。

1. Session 是什么?

Session 是服务器为每个用户创建的私有存储空间。服务器只给浏览器一个含有 Session ID 的 Cookie,所有数据都留在服务器:

TEXT 📖 仅展示
Cookie:                    Session:
只存 Session ID           存储实际数据(用户名、权限、购物车...)
┌──────────┐              ┌─────────────────────┐
│ PHPSESSID│ ──匹配──→   │ user: 小明           │
│ abc123   │              │ login: true          │
└──────────┘              │ cart: [3件商品]      │
  在浏览器                  │ role: admin          │
                           └─────────────────────┘
                              在服务器
💡 提示: Session vs Cookie:Cookie 存浏览器(用户可见/可改),Session 存服务器(安全)。但 Session 依赖 Cookie 传 ID——浏览器禁 Cookie 时 Session 会失效。


2. session_start() — 启动会话

使用 Session 前必须调用 session_start()。它做两件事:

  1. 如果浏览器带了 Session ID Cookie → 加载对应的服务器数据
  2. 如果没带 → 创建新 Session,生成新 Session ID,发 Cookie
PHP
<?php
// session 必须在任何 HTML 输出之前启动
session_start();

// 存储数据
$_SESSION['username'] = "小明";
$_SESSION['login_time'] = date("Y-m-d H:i:s");

// 读取数据
echo "欢迎,{$_SESSION['username']}!";
echo "登录时间:{$_SESSION['login_time']}";
?>
🔥 易错: session_start() 必须在任何输出(echo、HTML、甚至 PHP 标签前的空格)之前调用,否则报 headers already sent 错误。把它放在文件最顶部。


3. $_SESSION — 像普通数组一样使用

PHP
<?php
session_start();

// 存储任何 PHP 数据类型
$_SESSION['user'] = [
    'id'   => 101,
    'name' => '小明',
    'role' => 'member'
];
$_SESSION['cart'] = [
    ['name' => 'PHP教程', 'price' => 39.90, 'qty' => 2],
    ['name' => 'MySQL入门', 'price' => 29.90, 'qty' => 1],
];

// 读取
echo $_SESSION['user']['name'];  // 小明

// 删除某个 Session 变量
unset($_SESSION['cart']);

// 修改
$_SESSION['user']['role'] = 'admin';
?>

▶ 示例:用 Session 实现购物车

PHP
<?php
session_start();

// 初始化购物车
if (!isset($_SESSION['cart'])) {
    $_SESSION['cart'] = [];
}

// 添加商品
if (isset($_POST['add'])) {
    $item = $_POST['add'];
    $_SESSION['cart'][$item] = ($_SESSION['cart'][$item] ?? 0) + 1;
}

echo "<h3>购物车</h3>";
foreach ($_SESSION['cart'] as $item => $qty) {
    echo "{$item} × {$qty}<br>";
}
?>
<form method='POST'>
    <button name='add' value='PHP教程'>加入 PHP教程</button>
    <button name='add' value='MySQL入门'>加入 MySQL入门</button>
</form>
▶ 试一试

4. 登录系统实战

▶ 示例:完整登录系统

PHP 📖 仅展示
<?php
// login.php — 登录系统
session_start();

// 预定义的测试用户(实际项目中存在数据库)
$users = [
    'admin' => '123456',
    'xiaoming' => 'password123',
];

$error = '';

// 已登录?跳转到首页
if (isset($_SESSION['user'])) {
    header("Location: profile.php");
    exit;
}

// 处理登录请求
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $username = trim($_POST['username'] ?? '');
    $password = $_POST['password'] ?? '';

    if (isset($users[$username]) && $users[$username] === $password) {
        // 验证通过:存入 Session
        $_SESSION['user'] = [
            'username'    => $username,
            'login_time'  => date("Y-m-d H:i:s"),
            'last_active' => time(),
        ];
        
        // 登录成功,跳转到个人信息页
        header("Location: profile.php");
        exit;
    } else {
        $error = "用户名或密码错误";
    }
}
?>

<h3>用户登录</h3>
<?php if ($error): ?>
    <p style="color:red"><?= htmlspecialchars($error) ?></p>
<?php endif; ?>

<form method="POST" action="">
    <p>
        <label>用户名:</label>
        <input type="text" name="username" required>
    </p>
    <p>
        <label>密码:</label>
        <input type="password" name="password" required>
    </p>
    <button type="submit">登录</button>
</form>
<p style="color:#888">测试账号:admin / 123456</p>
逻辑代码 43 行(超过 40 行限制,仅展示)
PHP
<?php
// profile.php — 个人中心(需要登录)
session_start();

// 未登录?跳转到登录页
if (!isset($_SESSION['user'])) {
    header("Location: login.php");
    exit;
}

$user = $_SESSION['user'];
?>

<h2>个人中心</h2>
<p>用户名:<?= htmlspecialchars($user['username']) ?></p>
<p>登录时间:<?= $user['login_time'] ?></p>

<a href="logout.php">退出登录</a>

(1) 退出登录

PHP
<?php
// logout.php
session_start();

// 方式 1:只清除用户数据
unset($_SESSION['user']);

// 方式 2:完全清空 Session
session_unset();    // 清空 $_SESSION 数组
session_destroy();  // 删除服务器端 Session 文件

// 跳转到登录页
header("Location: login.php");
exit;
?>
操作 函数 说明
清变量 unset($_SESSION['key']) 删除特定项
清全部 session_unset() 清空 $_SESSION 数组
删文件 session_destroy() 删除服务器端 Session 数据
删 Cookie setcookie(session_name(),'',time()-3600,'/') 删除浏览器端 PHPSESSID
💡 提示: 退出登录的标准流程:session_unset()session_destroy() → 删除 PHPSESSID Cookie → 跳转到登录页。


5. Session 生命周期

TEXT 📖 仅展示
用户首次访问 → PHP 创建 Session 文件(如 sess_abc123)
                ↓
          存入 $_SESSION 数据
                ↓
          发 Cookie: PHPSESSID=abc123 给浏览器
                ↓
下次访问 → 浏览器带上 PHPSESSID=abc123
                ↓
          PHP 找到 sess_abc123 文件,加载数据到 $_SESSION
                ↓
... 用户离开(关闭浏览器或不活动很久之后) ...
                ↓
垃圾回收机制 → 删除过期 Session 文件

Session 默认 24 分钟后过期(php.ini 的 session.gc_maxlifetime = 1440 秒)。这个时间是文件最后修改时间算起,不是用户最后活动时间。


6. Session 安全配置

PHP
<?php
// 在 session_start() 之前配置
ini_set('session.cookie_httponly', 1);  // JS 不可读(防 XSS)
ini_set('session.cookie_secure', 1);    // 仅 HTTPS(生产环境必须)
ini_set('session.cookie_samesite', 'Lax');  // 防 CSRF
ini_set('session.use_strict_mode', 1);  // 拒绝未初始化的 Session ID

session_start();
?>
💡 提示: session.use_strict_mode = 1 防止攻击者伪造 Session ID(攻击者编造一个不存在的 ID,PHP 会拒绝并创建新 Session)。


Cookie Session
数据存储位置 用户浏览器 服务器
安全性 低(用户可查看/修改) 高(用户拿不到)
容量 4KB 无限制(受服务器磁盘限制)
性能 每次请求发送 不占带宽(只在服务器查)
依赖 独立 依赖 Cookie(传 Session ID)
适用场景 记住偏好、轻量状态 登录、权限、购物车

❓ 常见问题

Q 关闭浏览器后 Session 就消失了吗?
A Session 数据还在服务器端(等垃圾回收删除),但浏览器端的 PHPSESSID Cookie 默认关闭浏览器就没了。下次打开浏览器时因为找不到 Session ID,PHP 会创建新 Session。
Q 多个用户同时登录互相影响吗?
A 不会,每个用户有自己的 Session(有不同的 Session ID)。$_SESSION 是当前用户的,不会混。
Q 浏览器禁用了 Cookie,Session 还能用吗?
A 默认不能,因为 Session ID 靠 Cookie 传递。可以通过 URL 参数传递(PHPSESSID=abc123),但非常不安全——Session ID 会留在浏览器历史、书签、服务器日志中。

📖 小节

📝 作业

  1. 基于上面的代码,部署完整的登录系统(login.php → profile.php → logout.php)。
  2. 给个人中心页面增加"修改密码"功能(从预定义用户数组中验证)。
  3. 加一个简单的权限控制:只有 role === 'admin' 的用户才能看到页面上的"管理后台"链接。
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏