Cookie 与 Session 核心区别
| 特性 | Cookie | Session |
| 存储位置 | 客户端浏览器 | 服务器端 |
| 容量限制 | 单条 ~4KB,域名下 ~20-50 条 | 受服务器存储限制 |
| 生命周期 | 可设置过期时间,持久化或会话级 | 服务器控制,默认浏览器关闭失效 |
| 安全性 | 可见、可篡改、可被窃取 (XSS/CSRF) | 数据不直接暴露,相对安全 |
| 传输方式 | 每次请求自动随 Header 发送 | 仅传 Session ID (通常存 Cookie) |
联系:Session ID 默认存储在名为 PHPSESSID 的 Cookie 中。
Cookie 工作原理
- 服务器调用
setcookie(),在 HTTP 响应头发送 Set-Cookie: name=value; expires=...; path=/; domain=...; HttpOnly; Secure。
- 浏览器按域名/路径/过期时间存储。
- 后续请求同域名/路径下自动在
Cookie 请求头回传。
- PHP 自动解析填充
$_COOKIE 超全局数组。
setcookie() 完整语法
bool setcookie(
string $name,
string $value = "",
int $expires_or_options = 0,
string $path = "",
string $domain = "",
bool $secure = false,
bool $httponly = false
)
// PHP 7.3+ 支持选项数组
setcookie('name', 'value', [
'expires' => time() + 3600,
'path' => '/',
'domain' => '.example.com',
'secure' => true, // 仅 HTTPS 传输
'httponly' => true, // 禁止 JS 访问 (防 XSS)
'samesite' => 'Lax' // CSRF 防护: None|Lax|Strict
]);
参数详解
- name:Cookie 名称(键)。
- value:值,自动
urlencode,读取时自动 urldecode。避免存敏感明文。
- expires:Unix 时间戳。
0 或省略 = 会话 Cookie(浏览器关闭失效)。time()+3600 = 1 小时后过期。过去时间 = 删除。
- path:生效路径。
/ = 全站。默认当前脚本目录。
- domain:生效域名。
.example.com 含子域;example.com 仅当前域。默认当前域。
- secure:
true 仅 HTTPS 发送。
- httponly:
true 禁止 document.cookie 读取,**强烈建议开启**。
- samesite:
Lax (默认,顶级导航发送)、Strict (仅同站)、None (跨站需 secure=true)。
实战代码示例
创建 Cookie
<?php
// 会话级,全站,仅 HTTPS+HttpOnly
setcookie('user_id', '12345', [
'expires' => 0,
'path' => '/',
'secure' => true,
'httponly' => true,
'samesite' => 'Lax'
]);
// 持久化 30 天,根域共享
setcookie('remember_token', 'abcdef', [
'expires' => time() + 86400 * 30,
'path' => '/',
'domain' => '.example.com',
'secure' => true,
'httponly' => true,
'samesite' => 'Lax'
]);
?>
读取 Cookie
<?php
if (isset($_COOKIE['user_id'])) {
$uid = $_COOKIE['user_id']; // 自动 urldecode
echo "欢迎用户 $uid";
} else {
echo "请先登录";
}
?>
销毁 Cookie
<?php
// 设置过期时间为过去
setcookie('user_id', '', [
'expires' => time() - 3600,
'path' => '/',
'domain' => '.example.com', // 必须与创建时一致
'secure' => true,
'httponly' => true
]);
?>
关键注意事项(避坑指南)
| 陷阱 | 说明 | 对策 |
| 输出前调用 | setcookie 必须在任何 echo、HTML、空白、BOM 之前,否则 "Headers already sent" | 重构代码:逻辑先行,输出在后;或开启 output_buffering |
| 当前页不可读 | 刚 setcookie 后 $_COOKIE 不会立即更新,需刷新/下一请求 | 逻辑上区分“设置”与“读取”请求,或手工 $_COOKIE['name'] = $val 同步 |
| 域名/路径不匹配 | 删除/读取时 domain/path 必须与创建时**完全一致** | 统一常量定义 COOKIE_DOMAIN、COOKIE_PATH |
| 中文值乱码 | Cookie 规范仅支持 ASCII,中文需自行 urlencode/base64_encode | 存储前 urlencode($val),读取后 urldecode (PHP 自动处理) |
| 大小超限 | 单条 4KB,含名/值/属性 | 仅存 ID/Token,大数据存 Session/数据库 |
| 用户禁用 Cookie | 功能失效 | 关键流程降级到 Session/URL 传参,或引导用户开启 |
安全最佳实践
- 敏感数据不入 Cookie:仅存非敏感标识(用户 ID、加密 Token),真实权限数据存在服务端 Session/数据库。
- 全站 HTTPS + Secure + HttpOnly + SameSite=Lax:防御窃听、XSS、CSRF 三重保护。
- 签名/加密 Cookie 值:防篡改。
$val = base64_encode($data . '|' . hash_hmac('sha256', $data, $secret)),读取时验签。
- 定期轮换 Token:登录态 Token 设短过期,配合 Refresh Token 机制。
- 前端 JS 仅读非 HttpOnly Cookie:如需 JS 访问,单独设非 HttpOnly Cookie 存非敏感偏好设置。