本文目录导读:

在 PHP 中,分区 Cookie(Partitioned Cookie) 是一种通过 Partitioned 属性实现的 Cookie 隔离机制。
这是为了解决第三方 Cookie 被浏览器逐步禁用后,跨站资源(如嵌入的 iframe)无法保持登录状态的问题。
什么是分区 Cookie?
- 传统 Cookie:按域名存储,一个网站总能读取自己域名的 Cookie。
- 分区 Cookie:在传统域名基础上,额外加上顶级站点(Top-Level Site)作为存储分区。
- 浏览器为每个顶级站点维护一个独立的 Cookie 存储槽。
简单说:
example.com的 Cookie 在a.com和b.com下是彼此隔离的,即使它们都访问example.com的资源。
PHP 中设置分区 Cookie
PHP 的 setcookie() 函数从 PHP 7.3 开始支持 samesite 数组参数,但 Partitioned 属性是较新的功能,需要:
- PHP 7.3+(需要手动拼装)
- PHP 8.x(原生支持)
使用 setcookie() 的 options 数组(推荐)
<?php
// 传统方式(PHP 7.3+)
setcookie('session_id', 'abc123', [
'expires' => time() + 3600,
'path' => '/',
'domain' => 'example.com', // 你的域名
'secure' => true, // 必须 HTTPS
'httponly' => true,
'samesite' => 'None', // 必须为 None
'partitioned' => true // 📌 启用分区
]);
?>
注意:PHP 8.0 的
setcookie()还没有partitioned参数,需要通过 Header 方式手动设置。
手动设置 Header(兼容所有 PHP 版本)
<?php
$cookieName = 'session_id';
$cookieValue = 'abc123';
$expires = time() + 3600;
$path = '/';
$domain = 'example.com';
$secure = true;
$httponly = true;
// 拼接完整 Cookie 字符串
$header = sprintf(
'%s=%s; Expires=%s; Path=%s; Domain=%s; Secure; HttpOnly; SameSite=None; Partitioned',
$cookieName,
urlencode($cookieValue),
gmdate('D, d M Y H:i:s T', $expires),
$path,
$domain
);
header("Set-Cookie: $header", false);
?>
使用 PHP 8.2+ 原生支持
<?php
// PHP 8.2+ 直接支持 partitioned 参数
setcookie(
'session_id',
'abc123',
[
'expires' => time() + 3600,
'path' => '/',
'domain' => 'example.com',
'secure' => true,
'httponly' => true,
'samesite' => 'None',
'partitioned' => true
]
);
?>
验证 Cookie 是否正确设置
在浏览器开发者工具(F12)→ Application → Cookies 中查看:
Name: session_id
Value: abc123
Domain: example.com
Path: /
Expires: ...
Secure: ✅
HttpOnly: ✅
SameSite: None
Partitioned: ✅ ← 必须有这个标记
读取分区 Cookie
读取方式与普通 Cookie 完全一样,PHP 会自动处理分区逻辑:
<?php
if (isset($_COOKIE['session_id'])) {
echo "Session ID: " . $_COOKIE['session_id'];
} else {
echo "未找到 Cookie";
}
?>
删除分区 Cookie
<?php
// 设置过期时间为过去的时间即可
setcookie('session_id', '', [
'expires' => time() - 3600,
'path' => '/',
'domain' => 'example.com',
'secure' => true,
'httponly' => true,
'samesite' => 'None',
'partitioned' => true
]);
?>
使用场景
| 场景 | 是否适合使用 Partitioned |
|---|---|
| 普通网站内部登录状态 | ❌ 不需要 |
| 嵌入 iframe 的第三方服务(支付、聊天、地图) | ✅ 需要 |
| 跨站图片/资源加载 | ✅ 可能需要 |
| 跨域 JS 调用 API | ❌ 不适用(需 CORS) |
注意事项与坑
| 问题 | 说明 |
|---|---|
| 必须 HTTPS | Partitioned 要求 Secure 属性,必须使用 HTTPS |
| SameSite=None 必须一起设置 | Partitioned 必须与 SameSite=None 配合使用 |
| 浏览器兼容性 | Chrome 115+、Edge 115+、Firefox 126+ 支持;Safari 部分支持 |
| 移动端限制 | Android WebView 较旧版本不支持 |
| 调试困难 | 分区 Cookie 在不同站点下是隔离的,调试时需要切换场景 |
完整示例(实际使用)
<?php
// 设置分区 Cookie
function setPartitionedCookie($name, $value, $expires = 3600) {
$secure = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off');
$cookieOptions = [
'expires' => time() + $expires,
'path' => '/',
'secure' => $secure,
'httponly' => true,
'samesite' => 'None',
// PHP 8.2+ 支持;旧版本用手动方式
'partitioned' => true
];
setcookie($name, $value, $cookieOptions);
}
// 使用
setPartitionedCookie('user_token', 'abc123', 86400);
// 读取
if (isset($_COOKIE['user_token'])) {
$token = $_COOKIE['user_token'];
// 验证 token...
}
?>
| 方法 | PHP 版本 | 推荐度 |
|---|---|---|
setcookie() + options |
PHP 8.2+ | ⭐⭐⭐ 最简洁 |
| 手动 Header 拼接 | PHP 7.3+ | ⭐⭐⭐ 兼容性最好 |
| Header 手动方式 | 任意版本 | ⭐⭐ 老项目可选 |
最重要的一点:Partitioned 必须搭配 Secure + SameSite=None,否则浏览器会忽略该属性,同时要确保你的服务器支持 HTTPS。