PHP会话基础
PHP会话基础[编辑 | 编辑源代码]
PHP会话(Session)是一种在服务器端存储用户数据的机制,用于在多个页面请求之间保持用户状态。与Cookie不同,会话数据存储在服务器上,客户端仅保存一个会话ID(通常通过Cookie传递)。这使得会话比Cookie更安全,适合存储敏感信息。
会话工作原理[编辑 | 编辑源代码]
PHP会话通过以下步骤工作:
1. 当用户第一次访问网站时,PHP会生成一个唯一的会话ID(如PHPSESSID=abc123
)。
2. 该ID通过Cookie或URL参数发送到客户端。
3. 后续请求中,客户端会发送此ID回服务器。
4. 服务器根据ID找到对应的会话数据。
基本用法[编辑 | 编辑源代码]
启动会话[编辑 | 编辑源代码]
使用session_start()
函数初始化或恢复会话:
<?php
// 必须在输出任何内容前调用
session_start();
// 设置会话变量
$_SESSION['username'] = 'john_doe';
$_SESSION['last_login'] = time();
echo "会话已启动,数据已存储。";
?>
输出:
会话已启动,数据已存储。
访问会话数据[编辑 | 编辑源代码]
会话变量通过超全局数组$_SESSION
访问:
<?php
session_start();
// 检查并访问数据
if (isset($_SESSION['username'])) {
echo "欢迎回来, " . htmlspecialchars($_SESSION['username']);
} else {
echo "请先登录。";
}
?>
销毁会话[编辑 | 编辑源代码]
清除会话数据并终止会话:
<?php
session_start();
// 清除所有会话变量
$_SESSION = array();
// 删除会话Cookie
if (ini_get("session.use_cookies")) {
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000,
$params["path"], $params["domain"],
$params["secure"], $params["httponly"]
);
}
// 销毁会话
session_destroy();
echo "会话已销毁。";
?>
会话配置[编辑 | 编辑源代码]
通过php.ini
或运行时函数配置会话:
选项 | 描述 | 默认值 |
---|---|---|
会话文件存储路径 | /tmp | ||
会话Cookie名称 | PHPSESSID | ||
Cookie有效期(秒) | 0(浏览器关闭时过期) | ||
会话数据存活时间(秒) | 1440 |
运行时配置示例:
<?php
// 设置会话Cookie1小时有效
ini_set('session.cookie_lifetime', 3600);
ini_set('session.gc_maxlifetime', 3600);
session_start();
?>
安全实践[编辑 | 编辑源代码]
1. 始终在输出前调用session_start()
2. 使用HTTPS传输会话ID
3. 定期更换会话ID防止固定攻击:
session_start();
if (rand(1, 100) <= 10) { // 10%概率重新生成ID
session_regenerate_id(true);
}
4. 限制会话有效期:
$_SESSION['LAST_ACTIVITY'] = time(); // 每次请求更新
$timeout = 1800; // 30分钟
if (isset($_SESSION['LAST_ACTIVITY']) &&
(time() - $_SESSION['LAST_ACTIVITY'] > $timeout)) {
session_unset();
session_destroy();
}
实际案例:用户登录系统[编辑 | 编辑源代码]
以下是一个简单的登录系统实现:
登录处理[编辑 | 编辑源代码]
<?php
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// 验证逻辑(简化示例)
if ($_POST['username'] === 'admin' && $_POST['password'] === 'secret') {
$_SESSION['authenticated'] = true;
$_SESSION['username'] = $_POST['username'];
$_SESSION['login_time'] = time();
header('Location: dashboard.php');
exit;
} else {
$error = "无效凭证";
}
}
?>
<!-- HTML登录表单 -->
<form method="post">
<input type="text" name="username" placeholder="用户名">
<input type="password" name="password" placeholder="密码">
<button type="submit">登录</button>
<?php if (isset($error)) echo "<p>$error</p>"; ?>
</form>
访问控制[编辑 | 编辑源代码]
<?php
// dashboard.php
session_start();
if (!isset($_SESSION['authenticated']) || !$_SESSION['authenticated']) {
header('HTTP/1.0 403 Forbidden');
echo "拒绝访问:请先登录。";
exit;
}
echo "欢迎, " . htmlspecialchars($_SESSION['username']);
echo "<br>登录时间: " . date('Y-m-d H:i:s', $_SESSION['login_time']);
?>
会话存储机制[编辑 | 编辑源代码]
PHP默认使用文件存储会话,但可通过session_set_save_handler()
自定义存储:
类型 | 优点 | 缺点 |
---|---|---|
简单,无需额外配置 | 性能较低,不适合集群 | ||
可扩展,适合分布式 | 需要额外配置 | ||
高性能,适合高并发 | 需要内存缓存服务 |
数据库存储示例(MySQL):
<?php
class MySQLSessionHandler implements SessionHandlerInterface {
private $pdo;
public function open($savePath, $sessionName) {
$this->pdo = new PDO("mysql:host=localhost;dbname=test", "user", "pass");
return true;
}
public function read($sessionId) {
$stmt = $this->pdo->prepare("SELECT data FROM sessions WHERE id = ?");
$stmt->execute([$sessionId]);
return $stmt->fetchColumn() ?: '';
}
// 其他必需方法实现...
}
$handler = new MySQLSessionHandler();
session_set_save_handler($handler, true);
session_start();
?>
数学基础:会话ID熵[编辑 | 编辑源代码]
会话ID应具有足够的随机性以防止猜测攻击。ID的熵值计算为:
其中:
- = ID长度
- = 可能的字符数
例如,使用24字符的十六进制ID(N=16):
常见问题[编辑 | 编辑源代码]
Q: 为什么session_start()
报错"Headers already sent"?
A: 这是因为在调用前输出了内容(包括空格或BOM)。确保脚本首行是<?php
,前面无任何字符。
Q: 如何在不同子域名间共享会话? A: 配置Cookie域:
ini_set('session.cookie_domain', '.example.com');
session_start();
Q: 会话数据何时被清除?
A: 默认情况下,PHP的垃圾回收器会概率性地清理超过session.gc_maxlifetime
秒未活动的会话。