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()。它做两件事:
- 如果浏览器带了 Session ID Cookie → 加载对应的服务器数据
- 如果没带 → 创建新 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>
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)。
7. Cookie 与 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 会留在浏览器历史、书签、服务器日志中。📖 小节
- Session 数据存服务器,Cookie 只传 Session ID
session_start()启动会话,必须在任何输出之前$_SESSION像普通数组一样存取数据- 登录流程:验证 →
$_SESSION['user'] = ...→ 跳转 - 退出登录:
session_unset()+session_destroy()+ 跳转 - 安全配置:httponly + secure + samesite + strict_mode
- Session 适合登录状态 / 购物车 / 权限等安全数据
📝 作业
- 基于上面的代码,部署完整的登录系统(login.php → profile.php → logout.php)。
- 给个人中心页面增加"修改密码"功能(从预定义用户数组中验证)。
- 加一个简单的权限控制:只有
role === 'admin'的用户才能看到页面上的"管理后台"链接。