编程 PHP 8.6 改了 session 三个默认值:跨站 POST 的登录和支付回跳会先挂

2026-10-29 20:01:15

PHP 8.6 RC3:调用点不报错、升级后登录先坏的那几处

实测基线是 PHP 8.6.0RC3,8.6.0 GA 计划 2026-11-19。下面是 release candidate 上的观察,不是稳定版结论。示例代码在 michalwolinski/php-8-6-new-features。

弃用还会发 notice,下面这几处不发。同一份代码,调用点没有任何提示,行为已经变了。这也是要读 release notes 而不只是扫 changelog 标题的原因。

session:三个默认值一次全翻

这组是安全修复,也是会让登录流程先坏的那组。8.5 与 8.6 的 ini 默认值对照(实测):

; PHP 8.5 - measured defaults
session.use_strict_mode = 0
session.cookie_httponly = 0
session.cookie_samesite = (unset)

; PHP 8.6 - measured defaults
session.use_strict_mode = 1 ; rejects session ids the server never issued
session.cookie_httponly = 1 ; document.cookie cannot read it
session.cookie_samesite = "Lax" ; not sent on cross-site requests, except top-level navigations

三条各自先坏什么:

  • session.use_strict_mode = 1:服务端没存储过的 session id 一律拒收,用来堵 session fixation。默认值是对的,但对任何接受过外部传入 id 的自定义 save handler 来说就是行为变更——以前能进的自定义 id,现在被丢掉。
  • session.cookie_httponly = 1:document.cookie 读不到 session cookie。前端有读它做埋点、拼请求头、判断登录态的 JS,直接失效。
  • session.cookie_samesite = "Lax":最微妙的一条。带 Lax 的 cookie 不随跨站 POST 发出。接受其他 origin 表单 POST 的应用会收不到 cookie;支付回跳、OAuth 回调这类跳到本站再用 POST 提交的流程同理。

迁移就三行,写在 php.ini 里显式声明:

session.use_strict_mode = 0
session.cookie_httponly = 0
session.cookie_samesite = None
session.cookie_secure = 1

SameSite=None 必须配 cookie_secure=1,否则浏览器拒收这条 cookie。注意这只是把新默认值显式写回旧行为,不是「关掉修复」——值仍然在配置里,读代码的人一眼能看到你在依赖什么。不写这三行,等于要调试一个升级前还好好的登录。

session 相关设置里含 NUL 字节的值,现在会告警并保持原值不变。

DOM 属性:报错换了,反射的答案也换了

文档里标 @readonly 的那批属性(DOMNode::$nodeType 这一类)现在用 asymmetric visibility 声明。写它得到的错误是:

Cannot modify private(set) property DOMNode::$nodeType from global scope

措辞不重要,重要的是反射层面的变化:ReflectionProperty::isWritable() 对它们返回 false。靠反射判断「能不能写」再决定是否写入的代码,会拿到不同答案。

array_intersect():转换顺序变了

array_intersect() 的值转换顺序发生变化。对带状态 __toString() 的值——每次调用返回不同内容的那种——结果会不一样。数组里放这类对象的地方要单独测。

SplFileObject::fgetcsv():$escape 还在改的路上

$escape 参数的默认值正在变,现在只是先告警。告警是期限,不是变更本身。要么显式传参,要么用 setCsvControl() 设好。

升级节奏:工作量分布不均

最硬的反对理由是日历:8.6 还在 RC,RC3 是最新 tag。如果你在 8.3/8.4 且痛点不在这些地方,这个版本主要是人体工程学和清理,值得升,但不紧急。

工作量在弃用清单上,而且分布不均。碰自定义 session handler、SplFileObject 读 CSV、继承自 ArrayObject 的 ArrayIterator 方法、mb_ereg_*,那是真迁移;只是 is_long()、doubleval()、spl_object_hash(),那是查找替换。

有四处足够静默,值得上线前先写测试:

  • session 的 SameSite=Lax 默认值破坏跨站 POST 登录流程;
  • array_intersect() 的转换顺序对带状态 __toString() 的值改变结果;
  • 从 @readonly 改成 private(set) 的 DOM 属性在反射层面回答不同;
  • SplFileObject::fgetcsv() 的 escape 默认值正在变化,所以现在先告警。

部分新 API 由平台决定

装不上就用不了:Intl 新增项需要 ICU 63(数字区间格式)和 ICU 74(spoof checker),Sodium KEM 需要 libsodium 1.0.22+,GMP 新函数需要 GNU MP 且 MPIR 构建里没有,polling 后端取决于操作系统提供哪个。

推荐文章

程序员茄子在线接单