1. PHP 设置 Cookie 的基础语法与行为
1.1 setcookie 的基本用法
在 PHP 中,设置 Cookie 的核心是让服务器通过响应头发送 Set-Cookie,从而让浏览器在后续请求中携带该数据。这是跨请求保持状态的重要机制,但要注意 必须在输出前发送头部信息,否则会遇到 Headers 已发送的错误。
setcookie 的基本语法包含名称和值,以及可选的过期时间、路径和域等参数。常见的参数顺序为 name、value、expire、path、domain、secure、httponly,其中 expire 是一个时间戳,单位是秒,若为 0 或省略则表示会话 Cookie。
setcookie('user', 'alice', time() + 3600, '/');
通过上述代码,浏览器会收到一个名为 user、值为 alice 的 Cookie,且作用域为站点根路径 '/'。需要理解的一点是:Cookie 的值在当前请求中不会立即出现在 $_COOKIE,它会在下一次请求中随 Cookie 发送回来。
1.2 Cookie 的生存期与过期策略
Cookie 的生存期由 expire 参数控制,当 expire 指定一个未来的时间点时,浏览器会在该时间点之前一直保存该 Cookie。过期时间越晚,Cookie 保存时间越长;如设置为 0,则为会话 Cookie,在浏览器关闭时失效。
你还可以通过 path 和 domain 来限定对该 Cookie 的访问范围,例如将 path 设置为 '/' 可以让整个站点都能访问该 Cookie,而将 domain 设置为顶级域名可实现跨子域的共享。合理设置域与路径,能避免不必要的泄露和跨域问题。
setcookie('cart', 'ABC123', time() + 86400, '/shop', 'example.com');
在上面的示例中,Cookie 只在 /shop 路径及其子路径下可用,并且仅在 example.com 及其子域中携带,这对限制 Cookie 的作用域非常有帮助。
1.3 命名、编码与大小限制
Cookie 的名称应遵循一定的命名规范,一般使用字母、数字和下划线,避免使用空格和特殊字符,以免在不同浏览器或服务器间产生解析差异。
单个 Cookie 的数据大小有限制,通常约为 4KB 左右,因此不要放置大量数据。若需要存储结构化数据,推荐使用序列化或编码的方式,并在服务端进行解析。
// 存储一个简单的偏好对象(需要序列化或编码后再保存)
// 例如:json_encode([ 'theme' => 'dark' ])
setcookie('prefs', json_encode(['theme' => 'dark']), time() + 3600, '/');
在读取时,确保对取出的字符串进行合适的解码,避免直接当作对象使用引发错误。读取时记得使用相应的解码步骤。
2. 设置 Cookie 的高级选项与安全性
2.1 使用 options 数组进行更灵活的设置
自 PHP 7.3 起,setcookie 支持使用一个 options 数组来传递参数,这种方式在处理复杂的安全需求时非常直观。通过统一的选项配置,可以清晰地定义 expires、path、domain、secure、httponly、samesite 等属性。
此外,使用 options 数组还能避免在同一调用中混合旧的参数形式,从而降低出错概率。下面的示例演示了一个带有多项安全选项的 Cookie 设置。
setcookie('session', 'xyz', ['expires' => time() + 3600,'path' => '/','domain' => 'example.com','secure' => true,'httponly' => true,'samesite' => 'Lax'
]);
注意:如果使用 options 数组形式,请不要同时使用旧的带参数的 setcookie 调用,以免参数冲突。
2.2 SameSite、Secure 与 HttpOnly 的安全实践
在保护用户隐私与防护 XSS、CSRF 攻击方面,HttpOnly、Secure 以及 SameSite 是三大关键属性。HttpOnly 使脚本不可访问 Cookie,Secure 只在 HTTPS 情况下发送,SameSite 有助于降低跨站请求伪造的风险。
实践中,你应尽量让敏感数据的 Cookie 设为 HttpOnly,且在可能的场景下开启 Secure 与 SameSite。以下示例结合了这些安全属性。

setcookie('auth', 'token123', ['expires' => time() + 7200,'path' => '/','secure' => true,'httponly' => true,'samesite' => 'Strict'
]);
在使用跨域认证或第三方集成时,需要仔细评估 SameSite 策略对业务的影响,必要时结合服务端会话机制进行补充。
2.3 跨子域与路径的 Cookie 设置技巧
跨子域共享某些 Cookie 时,通常需要将域设为顶级域名,例如 domain=.example.com(注意不同浏览器对点号的处理差异,实际使用中通常省略前导点)。
路径的设置也会影响 Cookie 的传递范围,将 path 设置为根路径 '/' 可以让站点内的页面共享同一个 Cookie,而将 path 限制在特定子路径则只能在该路径及其子路径中可用。
setcookie('prefs', 'v1', ['expires' => time() + 3600,'path' => '/','domain' => 'example.com'
]);
总之,域名和路径的组合决定了 Cookie 的可见性范围,需与应用架构和子域策略配合使用。
3. 读取、更新与删除 Cookie 的实践
3.1 读取 Cookie 的值
浏览器在每次请求时会把符合域名、路径及安全要求的 Cookie放在请求头中,PHP 通过 $_COOKIE 超全局变量来访问这些数据。在读取前,先判断键名是否存在,以避免未定义的提示。
常见的读取方式是使用 空合并运算符,如 $_COOKIE['name'] ?? null,这在 PHP 7 及以上版本中非常方便。
$username = $_COOKIE['user'] ?? null;
if ($username !== null) {// 使用 $username
}
需要注意的是:$_COOKIE 的值仅代表上一请求中浏览器发送的 Cookie,当前请求对 Cookie 的修改不会即时反映,直到下一次请求。
3.2 更新 Cookie 的值或扩展有效期
更新 Cookie 的常规做法是再次调用 setcookie,使用相同的名称、相同的路径和域,但给定新的值或新的过期时间。这相当于覆盖原有的 Cookie。
请务必记得,除非使用相同的路径和域,否则浏览器可能将其视为不同的 Cookie,从而导致覆盖失败。
setcookie('user', 'bob', time() + 3600, '/');
如果需要在当前请求内保持一致性,请在设置新值后,直接在服务端更新 $_COOKIE(这通常需要在下一个请求中体现),以避免状态不一致的问题。
// 在更新后,下一次请求才会在 $_COOKIE 中看到新值
$_COOKIE['user'] = 'bob';
3.3 删除 Cookie 的方法
删除 Cookie 的标准做法是将其过期时间设置为过去的时间点,并保持原有的域与路径匹配,以便浏览器删除对应的记忆。
另外,为了确切地反映当前状态,可以在删除后也清空服务端变量以及局部缓存。请看以下示例。
setcookie('user', '', time() - 3600, '/');
执行删除后,最好也调用 unset($_COOKIE['user']); 以避免当前请求中继续误用已删除的变量。
unset($_COOKIE['user']);3.4 将复杂数据存储在 Cookie 中(JSON 编码/解码)
如果需要在 Cookie 中保存结构化数据,应该先在服务端进行编码(如 JSON 编码),再保存到 Cookie。同时,读取时需要进行相应解码。这样可以保持数据结构的灵活性和兼容性。
示例中,将一个偏好对象编码并写入 Cookie;随后读取时再解码为数组。
$prefs = ['theme' => 'dark', 'layout' => 'grid'];
setcookie('prefs', json_encode($prefs), time() + 86400, '/');
读取时则进行解码,确保处理 JSON 解析错误的场景:使用 json_decode 并处理返回值。
$prefsRaw = $_COOKIE['prefs'] ?? '{}';
$prefs = json_decode($prefsRaw, true);
if (!is_array($prefs)) {$prefs = [];
} 

