PHP Cookie 与 Session:状态管理完全指南
Cookie vs Session 区别
两者都是用来在无状态的 HTTP 协议上保存状态的机制。
- Cookie:数据存储在浏览器端,大小限制约 4KB,可长期存储
- Session:数据存储在服务器端,浏览器只保存一个 Session ID,大小无限制
一、Cookie 操作
设置 Cookie
<?php\n// 基本设置\nsetcookie('username', '张三');\n\n// 完整参数\nsetcookie('token', 'abc123xyz', [\n 'expires' => time() + 86400 * 7, // 7天后过期\n 'path' => '/', // 整站有效\n 'domain' => '.example.com', // 域名(带点表示所有子域)\n 'secure' => true, // 仅 HTTPS 传输\n 'httponly' => true, // 禁止 JS 读取(防 XSS)\n 'samesite' => 'Strict', // CSRF 防护:Strict/Lax/None\n]);\n?>
读取 Cookie
<?php\n// 在 $_COOKIE 超全局变量中读取\n$username = $_COOKIE['username'] ?? '';\n$token = $_COOKIE['token'] ?? '';\n\n// 注意:Cookie 第一次设置后,需要刷新页面才能在 $_COOKIE 中读取\n?>
删除 Cookie
<?php\n// 把过期时间设为过去的时间即可删除\nsetcookie('username', '', time() - 3600, '/');\nsetcookie('token', '', time() - 1, '/');\n?>
Cookie 常用场景
<?php\n// 记住用户名\n$remember_user = $_COOKIE['remember_user'] ?? '';\nif ($remember_user) {\n echo "上次登录的用户名:{$remember_user}";\n}\n\n// 语言偏好\n$lang = $_COOKIE['lang'] ?? 'zh-CN';\n\n// 主题偏好\n$theme = $_COOKIE['theme'] ?? 'light';\n?>
二、Session 操作
开启 Session
<?php\n// 必须在任何输出之前调用\nsession_start();\n\n// 配置 Session(开启后)\nsession_name('MY_SESSION_ID');\nsession_save_path('/var/lib/php/sessions');\n\n// Session 垃圾回收配置(php.ini)\n// session.gc_maxlifetime = 1440(24分钟无活动则过期)\n// session.gc_probability = 1\n// session.gc_divisor = 100\n?>
读写 Session
<?php\nsession_start();\n\n// 存储数据\n$_SESSION['user_id'] = 1;\n$_SESSION['username'] = '张三';\n$_SESSION['role'] = 'admin';\n$_SESSION['login_time'] = time();\n\n// 读取数据\necho $_SESSION['username'];\n\n// 检查登录状态\nif (isset($_SESSION['user_id'])) {\n echo "欢迎,用户 #{$_SESSION['user_id']}";\n} else {\n echo "请先登录";\n}\n\n// 删除单个键\nunset($_SESSION['login_time']);\n\n// 销毁所有会话(登出)\nsession_destroy();\n?>
Session 配置详解
<?php\nsession_start([\n 'cookie_lifetime' => 0, // 0=浏览器关闭失效,其他数字为指定秒数\n 'cookie_path' => '/',\n 'cookie_domain' => '',\n 'cookie_secure' => isset($_SERVER['HTTPS']), // HTTPS 自动开启\n 'cookie_httponly' => true, // 禁止 JS 读取 Cookie\n 'cookie_samesite' => 'Strict', // CSRF 防护\n 'name' => 'SESSION_ID', // Session Cookie 名称\n 'gc_probability' => 1,\n 'gc_divisor' => 100,\n 'gc_maxlifetime' => 1800, // 30分钟无活动过期\n]);\n?>
三、实战:完整的登录/登出流程
<?php\n// login.php - 处理登录\nsession_start();\n\nif ($_SERVER['REQUEST_METHOD'] === 'POST') {\n $username = $_POST['username'] ?? '';\n $password = $_POST['password'] ?? '';\n\n // 验证用户(这里简化,实际从数据库查)\n if ($username === 'admin' && password_verify($password, '$2y$10$...')) {\n // 登录成功\n session_regenerate_id(true); // 防止 Session Fixation 攻击\n $_SESSION['user_id'] = 1;\n $_SESSION['username'] = $username;\n $_SESSION['login_time'] = time();\n\n // 记住我(选填)\n if (!empty($_POST['remember'])) {\n $token = bin2hex(random_bytes(32));\n // 保存 token 到数据库\n setcookie('remember_token', $token, time() + 86400 * 30, '/', '', true, true);\n }\n\n header('Location: dashboard.php');\n exit;\n } else {\n $error = '用户名或密码错误';\n }\n}\n?>
<?php\n// auth.php - 需要登录才能访问的页面\nsession_start();\n\nif (empty($_SESSION['user_id'])) {\n header('Location: login.php');\n exit;\n}\n\necho "欢迎,{$_SESSION['username']}";\n?>
<?php\n// logout.php - 登出\nsession_start();\n\n// 清除 Session\n$_SESSION = [];\n\n// 清除 Session Cookie\nif (ini_get('session.use_cookies')) {\n $params = session_get_cookie_params();\n setcookie(\n session_name(),\n '',\n time() - 42000,\n $params['path'],\n $params['domain'],\n $params['secure'],\n $params['httponly']\n );\n}\n\nsession_destroy();\nheader('Location: login.php');\nexit;\n?>
四、Session 存储驱动
<?php\n// 默认:文件存储(php.ini: session.save_handler = files)\n// 存储在系统临时目录(如 /tmp)\n\n// Redis 存储(生产环境推荐)\nsession_save_path('tcp://127.0.0.1:6379?prefix=PHP SESSION:');\n\n// 数据库存储\n// session_set_save_handler() 自定义存储逻辑\nclass DatabaseSessionHandler {\n private $pdo;\n\n public function open($path, $name): bool { ... }\n public function read($id): string { ... }\n public function write($id, $data): bool { ... }\n public function destroy($id): bool { ... }\n public function gc($maxlifetime): bool { ... }\n}\n\n$handler = new DatabaseSessionHandler($pdo);\nsession_set_save_handler($handler);\nsession_start();\n?>
五、安全最佳实践
- Session Fixation:登录后执行
session_regenerate_id(true)
- XSS 防护:设置
httponly=true,禁止 JS 读取 Cookie - CSRF 防护:用
samesite=Strict/Lax+ 表单 Token
- HTTPS:生产环境必须开启 HTTPS,设置
secure=true - Session 过期:设置合理的
gc_maxlifetime
- 敏感操作:重新验证密码后再执行敏感操作
<?php\n// 完整的 CSRF Token 验证\nsession_start();\n\n// 生成 Token\nif (empty($_SESSION['csrf_token'])) {\n $_SESSION['csrf_token'] = bin2hex(random_bytes(32));\n}\n\n// 验证 Token(POST 请求)\nif ($_SERVER['REQUEST_METHOD'] === 'POST') {\n $token = $_POST['csrf_token'] ?? '';\n if (!hash_equals($_SESSION['csrf_token'], $token)) {\n die('CSRF 验证失败');\n }\n}\n\n// 表单中输出 Token\n// echo '<input type="hidden" name="csrf_token" value="' . $_SESSION['csrf_token'] . '">';\n?>
总结
- Cookie 存客户端(4KB限制),Session 存服务器端(无限制)
- 登录状态用 Session,记住用户名用 Cookie
- 登录后必须
session_regenerate_id(true)防 Session Fixation
httponly + secure + samesite