使用PHP Session在不同脚本间安全传递变量的教程
在PHP开发中,我们经常会遇到需要在多个页面或脚本之间共享数据的场景,比如用户登录后保存用户信息、购物车数据存储等。这时候使用Session是最常用也最安全的方案之一,它可以在服务器端存储用户相关的数据,不同脚本之间通过Session ID来访问对应的数据,避免了通过URL参数或Cookie传递敏感信息的风险。
什么是PHP Session
Session是服务器端的会话机制,当用户第一次访问网站时,服务器会为该用户创建一个唯一的Session ID,并通过Cookie或者URL重写的方式传递给客户端。后续客户端每次请求时都会携带这个Session ID,服务器根据ID找到对应的Session数据,从而实现跨脚本的数据共享。
和Cookie不同,Session的数据存储在服务器端,客户端只能拿到Session ID,无法直接获取存储的敏感内容,因此安全性更高。
Session的基本使用步骤
使用Session传递变量主要分为三个步骤:开启Session、存储变量、读取变量,下面我们逐一说明。
1. 开启Session
在使用Session之前,必须先调用session_start()函数开启Session,这个函数会检查当前请求是否携带了有效的Session ID,如果没有则会创建新的Session并生成对应的ID。注意session_start()必须在所有输出(包括HTML标签、echo输出等)之前调用,否则会报错。
<?php // 开启Session,必须在任何输出之前调用 session_start(); ?>
2. 在Session中存储变量
Session开启后,所有的Session数据都存储在$_SESSION超全局数组中,我们可以直接给这个数组赋值来存储需要共享的变量,这些变量会在当前会话的所有脚本中可用。
<?php
session_start();
// 存储用户登录信息到Session
$_SESSION['user_id'] = 1001;
$_SESSION['username'] = '张三';
$_SESSION['is_login'] = true;
// 存储购物车数据
$_SESSION['cart'] = [
['product_id' => 1, 'num' => 2],
['product_id' => 3, 'num' => 1]
];
echo '变量已存储到Session';
?>3. 在其他脚本中读取Session变量
同一个会话下的其他脚本,只要先调用session_start()开启Session,就可以直接通过$_SESSION数组读取之前存储的变量。
<?php
session_start();
// 检查用户是否登录
if (isset($_SESSION['is_login']) && $_SESSION['is_login'] === true) {
echo '欢迎回来,' . $_SESSION['username'] . ',你的用户ID是:' . $_SESSION['user_id'];
// 读取购物车数据
if (!empty($_SESSION['cart'])) {
echo '<br>你的购物车中有' . count($_SESSION['cart']) . '种商品';
}
} else {
echo '你还未登录,请先登录';
}
?>Session的安全注意事项
虽然Session本身比Cookie安全,但如果使用不当也会存在风险,下面是几个需要注意的安全点:
- 不要在Session中存储过于敏感的信息,比如用户密码的明文,即使存在服务器端,也应该只存储密码的哈希值。
- 注意Session的过期时间,默认情况下Session的过期时间由服务器的
session.gc_maxlifetime配置决定,我们也可以手动设置过期时间,避免用户长时间不操作后仍保留敏感数据。 - 避免Session劫持:可以使用HTTPS传输数据,防止Session ID被中间人窃取;也可以定期重新生成Session ID,调用
session_regenerate_id()函数即可。
手动设置Session过期时间示例
我们可以通过设置Session的生存周期,让超过指定时间未活动的Session自动失效。
<?php
// 设置Session存活时间为30分钟(1800秒)
$session_lifetime = 1800;
ini_set('session.gc_maxlifetime', $session_lifetime);
session_set_cookie_params($session_lifetime);
session_start();
// 记录用户最后一次活动的时间
if (!isset($_SESSION['last_activity'])) {
$_SESSION['last_activity'] = time();
} else {
// 如果超过30分钟没有活动,销毁Session
if (time() - $_SESSION['last_activity'] > $session_lifetime) {
session_unset();
session_destroy();
echo '会话已过期,请重新登录';
exit;
}
// 更新最后活动时间
$_SESSION['last_activity'] = time();
}
?>销毁Session
当用户退出登录或者需要清除Session数据时,不能只删除$_SESSION数组的内容,需要按照正确的步骤销毁Session,避免残留数据。
<?php
session_start();
// 第一步:清空Session数组
$_SESSION = array();
// 第二步:如果需要,删除客户端的Session 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
session_destroy();
echo '已成功退出登录';
?>常见问题说明
很多开发者会遇到Session变量无法传递的问题,大部分原因都是没有在读取Session的脚本中调用session_start(),或者session_start()之前有输出内容。另外如果服务器禁用了Session功能,也会导致无法使用,这时候需要检查php.ini中的session.save_handler配置是否为files或者对应的可用存储方式。
如果需要跨子域使用Session,还需要设置Session的Cookie作用域,比如设置为.ipipp.com,这样所有ipipp.com的子域都可以共享同一个Session。
<?php
// 设置Session Cookie的作用域为父域,支持子域共享
ini_set('session.cookie_domain', '.ipipp.com');
session_start();
?>