PHP Cookie过期时间必须用秒级Unix时间戳整数,传错类型会静默失效;推荐用$options数组写法并校验时区与NTP同步。

PHP 中的 Cookie 过期时间必须用 Unix 时间戳(秒级),不是毫秒,也不是字符串日期;设错就变成会话 Cookie 或立即失效。
setcookie() 的 expires 参数只能是整数时间戳
很多人把 strtotime("2026-12-31") 或 new DateTime("next week")->getTimestamp() 直接传给旧版 setcookie() 七参数形式,结果发现 Cookie 没生效——因为旧接口只接受第 3 个参数为 int,其他类型会被静默转成 0,等效于不设过期时间。
- ✅ 正确:使用
time() + 86400、strtotime("+30 days"),并确保结果是整数(可用(int)强制转换) - ❌ 错误:传入
"2026-12-31"字符串、null、空数组,或在旧接口里传["expires" => ...]数组 - ⚠️ 注意:
strtotime()在时区不一致时可能返回false,务必检查返回值是否为整数,否则setcookie()会静默失败
会话 Cookie 和持久化 Cookie 的边界很窄
只要 expires 参数是 0、未传、或传了无效值(如负数、非数字),浏览器就按会话 Cookie 处理——关浏览器就丢,哪怕你写了 setcookie("x", "y", 0)。
- ✅ 持久化:明确传一个未来的时间戳,比如
time() + 2592000(30 天) - ✅ 删除:传一个过去的时间戳,如
time() - 3600,且value设为空字符串 - ⚠️ 坑点:开发环境常开 Xdebug 或输出调试信息,导致 header 已发送,
setcookie()直接失败但无报错;用headers_sent()检查
PHP 7.3+ 推荐用 $options 数组写法
老式七参数调用(setcookie($name, $value, $expire, $path, $domain, $secure, $httponly))容易错位,尤其当 $domain 为空却漏掉它时,后面参数全偏移。
立即学习“PHP免费学习笔记(深入)”;
- ✅ 推荐:
setcookie("theme", "dark", ["expires" => time() + 604800, "path" => "/", "secure" => true, "httponly" => true]) - ✅ 所有键名清晰,
expires支持直接传 int 或 DateTimeInterface 实例(PHP 8.0+) - ⚠️ 注意:
expires在$options中仍是秒级时间戳,不是DateTime对象本身;PHP 8.0+ 才支持自动调用getTimestamp()
时区和服务器时间不准会导致过期逻辑错乱
Cookie 过期由浏览器根据自身系统时间 + 服务端发来的 Expires 或 Max-Age 判断。如果服务器时间比客户端快 5 分钟,用户刚登录就可能被立刻登出。
- ✅ 确保服务器启用 NTP 同步(如
systemctl status chronyd) - ✅ 不依赖本地时区做计算:用
date_default_timezone_set("UTC")统一基准,再算time() + N - ⚠️ 避免用
date("U")替代time(),二者在时区设置下行为一致,但time()更直白、无副作用
最易被忽略的是:浏览器是否真的收到了 Set-Cookie 响应头。不要只看 $_COOKIE,用 DevTools 的 Network → Response Headers 确认字段存在且 Expires 值合理——有时候问题不在 PHP,而在反向代理(如 Nginx)清除了 Set-Cookie 头。



















