| 特性 | Cookie | Session |
|---|---|---|
| 存储位置 | 客户端浏览器(文件/内存) | 服务器端(文件/数据库/内存/Redis等) |
| 机制类型 | 客户端维持状态 | 服务器端维持状态 |
| 标识传递 | 自动随请求发送 | 依赖 Session ID(通常存 Cookie 或 URL 重写) |
| 安全性 | 可被窃取/篡改/禁用 | 数据不直接暴露给客户端,相对安全 |
| 生命周期 | 可设置过期时间,持久化或会话级 | 服务器控制,默认浏览器关闭失效(会话 Cookie) |
| 存储容量 | 单个 ~4KB,域名下共 ~20-50 个 | 受服务器存储限制,理论无上限 |
联系:Session ID 通常保存在 Cookie 中(名为 PHPSESSID 或 JSESSIONID),浏览器每次请求自动携带,服务器据此关联会话数据。若客户端禁用 Cookie,则需通过 URL 重写或表单隐藏字段传递 Session ID。
服务器使用类似哈希表的结构存储 Session 数据,Key 为 Session ID,Value 为序列化后的会话数据(PHP 默认用文件,键名格式 sess_)。
Set-Cookie: PHPSESSID=abc123; path=/,浏览器自动回传。/page;jsessionid=abc123/page?jsessionid=abc123<input type="hidden" name="PHPSESSID" value="abc123">(老旧做法,已少用)。错误。 服务器不会因浏览器关闭而立即删除 Session。Session 仅在以下情况被销毁:
session_destroy()。session.gc_maxlifetime(默认 1440 秒)未活动,被垃圾回收清理。“消失”的假象源于:默认 Session ID 存储在会话 Cookie(内存)中,浏览器关闭后 Cookie 丢失,下次访问无法关联原 Session。若将 Cookie 持久化到硬盘或手工携带原 Session ID,依然能恢复会话。
session.gc_probability / session.gc_divisor 概率(默认 1/1000)执行 GC,扫描 session.save_path 下过期文件并删除。session.save_path 使用 N;/path 分级存储,GC 将失效,需自建 Cron 脚本清理。session.name(默认 PHPSESSID)。setcookie() 发送到客户端(必须在任何输出前)。sess_),反序列化填充 $_SESSION 超全局数组。对 $_SESSION 的读写仅在内存中进行,性能极高。
将 $_SESSION 序列化写回 Session 文件,关闭资源。此阶段可执行 session_regenerate_id() 更换 ID(常用于登录后提权、防固定攻击)。
| 方法 | 效果 |
|---|---|
setcookie(session_name(), '', time()-8000000, '/') | 让客户端 Cookie 立即过期,服务端数据暂存 |
unset($_SESSION) | 清空当前脚本 $_SESSION,写入空数据,Session 文件仍在 |
session_destroy() | 彻底删除 $_SESSION、Session 文件及 Session ID(最彻底) |
通过 session_set_save_handler() 注册六个回调函数,完全接管存储逻辑(如存入 MySQL、Redis、MongoDB)。
<?php
function open($save_path, $session_name) { global $sess_save_path; $sess_save_path = $save_path; return true; }
function close() { return true; }
function read($id) { global $sess_save_path; return (string)@file_get_contents("$sess_save_path/sess_$id"); }
function write($id, $sess_data) { global $sess_save_path; $fp = @fopen("$sess_save_path/sess_$id", "w"); return $fp ? fwrite($fp, $sess_data) : false; }
function destroy($id) { global $sess_save_path; return @unlink("$sess_save_path/sess_$id"); }
function gc($maxlifetime) { global $sess_save_path; foreach (glob("$sess_save_path/sess_*") as $f) { if (filemtime($f) + $maxlifetime < time()) @unlink($f); } return true; }
session_set_save_handler('open', 'close', 'read', 'write', 'destroy', 'gc');
session_start();
// 后续 $_SESSION 操作自动调用上述回调
?>
| 参数 | 默认值 | 说明 |
|---|---|---|
| session.save_handler | files | 存储驱动:files/user/memcached/redis 等 |
| session.save_path | /tmp | 文件存储路径,支持 N;/path 分级 |
| session.name | PHPSESSID | Cookie 键名 |
| session.gc_probability | 1 | GC 概率分子 |
| session.gc_divisor | 1000 | GC 概率分母 |
| session.gc_maxlifetime | 1440 | 最大生存时间(秒) |
| session.cookie_lifetime | 0 | Cookie 生命周期(0=会话级) |
| session.cookie_path | / | Cookie 有效路径 |
| session.cookie_domain | Cookie 有效域名 | |
| session.use_strict_mode | 0 | 严格模式拒绝未初始化 ID |
session.cookie_httponly=1 防 XSS 窃取,session.cookie_secure=1 仅 HTTPS 传输。session_regenerate_id(true) 旧 ID 删除,防会话固定攻击。