2026 年 10 月 21 日,PHP 官方发布紧急安全公告:PHP 8.5.12、8.4.27、8.3.36、8.2.35 同步修复两个可导致未授权远程代码执行的严重漏洞,CVSS v4.0 评分均为 9.2。本文先拆解公告要点,再按 PHP 7.4 / 8.0 / 8.1 / 8.2 / 8.3 / 8.4 / 8.5 七个版本分别给出可执行的升级路线与兼容性注意事项。

一、公告核心:两个 9.2 分 RCE 漏洞

这次不是常规的 bug 修复版本,而是安全版本。两个漏洞都能在应用代码执行之前被触发,其中 mod_php 场景的风险最高。

CVE 编号问题类型触发机制
CVE-2026-109618OOM 内存耗尽处理缺陷内存耗尽中断了 PHP,内部请求数据只完成部分初始化,请求清理阶段可能把非法数据当成合法数据处理
CVE-2026-109619全局状态残留请求级内部状态在内存释放后仍然存活,同一 worker 处理的下一个请求可能读到脏状态

影响范围:所有对外提供 Web 请求的 PHP 安装,包括 PHP-FPM、Apache mod_php、php-cgi、FrankenPHP 与 LiteSpeed。官方已确认 mod_php 存在无需认证即可在应用代码运行前触发的利用方式。

⚠️
修复版本
8.5.12、8.4.27、8.3.36、8.2.35。官方明确表示没有完整缓解手段,升级是唯一的彻底方案。

二、先确认自己在哪个版本

升级前必须先确认业务实际加载的 PHP 二进制,避免出现"CLI 升了、FPM 没升"的情况。

bash check-php.sh
php -v
php -m
php --ini

# 查看 FPM 实际加载的二进制与配置
ps -ef | grep php-fpm
php-fpm -v

# 站点侧验证(以 FPM 为准,而不是 CLI)
curl -s https://your-site/phpinfo.php | grep -i "PHP Version"
ℹ️
小技巧
在应用入口临时输出 PHP_VERSION 与 php_sapi_name(),可以快速确认线上到底是 FPM 还是 mod_php,以及具体补丁号。

三、版本支持周期总表

PHP 每个分支的节奏是:活跃支持 2 年,之后仅修关键安全问题 2 年,满 4 年进入 EOL。对照下表可以先判断"能不能只打补丁"。

分支初始发布活跃支持至安全支持至当前状态本次官方版本
PHP 7.42019-11-282021-11-282022-11-28EOL无(仅源码 backport 分支)
PHP 8.02020-11-262022-11-262023-11-26EOL无(仅源码 backport 分支)
PHP 8.12021-11-252023-11-252025-12-31EOL无(仅源码 backport 分支)
PHP 8.22022-12-082024-12-312026-12-31仅安全维护8.2.35
PHP 8.32023-11-232025-12-312027-12-31仅安全维护8.3.36
PHP 8.42024-11-212026-12-312028-12-31活跃支持8.4.27
PHP 8.52025-11-202027-12-312029-12-31当前稳定版8.5.12

可以看到,7.4、8.0、8.1 已经完全没有官方安全更新,这次公告只为它们提供了最小源码 backport,适合自行编译或使用 LTS 厂商补丁的场景。普通业务应当尽快跨到受支持的分支。

四、分版本升级攻略

1. PHP 7.4:不要修修补补,直接规划跨版本

PHP 7.4 已于 2022 年 11 月 28 日 EOL。官方这次只提供了 PHP-7.4-CVE-2026-109618-109619 源码分支,没有官方二进制包。

  • 能自编译:拉取该分支,按原有 configure 参数重新编译并替换。
  • 用发行版或商业 LTS:联系厂商确认是否已回移补丁。
  • 两者都不满足:把升级列为最高优先级,目标直接定 PHP 8.3 / 8.4 / 8.5,不要停在同样 EOL 的 8.0。

7.4 → 8.0 的主要断点:

  • each()、create_function()、money_format() 等函数被移除。
  • 默认错误级别改为 E_ALL,未定义变量从 Notice 升级为 Warning,很多老项目会突然"报错变多"。
  • 字符串与数字比较规则变化,例如 0 == "foo" 在 PHP 8 中为 false。
  • 非静态方法被静态调用会直接致命错误。
  • real 类型、魔术引号、PHP 4 风格构造器全部移除。
  • assert() 不再执行字符串参数。
  • 算术与位运算传入非法类型会抛出 TypeError。

建议先用兼容性扫描把问题一次性捞出来,再动生产环境。

bash compat-scan.sh
composer require --dev phpcompatibility/php-compatibility
vendor/bin/phpcs -p . --standard=PHPCompatibility --runtime-set testVersion 8.5

# 也可以用 rector 做自动化改写
composer require --dev rector/rector
vendor/bin/rector process src --dry-run

2. PHP 8.0:同样 EOL,用 backport 或直接跳到 8.3+

PHP 8.0 于 2023 年 11 月 26 日 EOL,官方提供 PHP-8.0-CVE-2026-109618-109619 源码分支。生产环境不建议继续停留。

8.0 → 8.1 的升级要点:

  • 把 null 传给非空的内部函数参数开始产生弃用警告,例如 strlen(null)。
  • 字符串插值 ${var} 写法弃用,改用 {$var}。
  • strftime()、gmstrftime()、FILTER_SANITIZE_STRING、Serializable 接口弃用。
  • 新增 enum、readonly 属性、Fiber、never 返回类型、交集类型,可顺手做代码现代化。

3. PHP 8.1:已 EOL,本次只能走源码 backport

PHP 8.1 的安全支持已于 2025 年 12 月 31 日结束。官方公告写得很明确:8.1 及更早版本不再接收更新,只提供最小源码回移。

  • 短期:使用 PHP-8.1-CVE-2026-109618-109619 分支自行编译,或等发行版/LTS 厂商补丁。
  • 中期:至少升到 8.2.35,生产建议直接到 8.4.27 或 8.5.12。

8.1 → 8.2 的升级要点:

  • 动态属性弃用:给未声明属性赋值会触发 Deprecated,需要显式声明属性,或加 #[\AllowDynamicProperties]。
  • utf8_encode()、utf8_decode() 弃用,改用 mb_convert_encoding()。
  • ${} 字符串插值正式弃用。
  • strtolower()、strtoupper() 不再受 locale 影响。
  • 对 $GLOBALS 的整体写入受到限制。
  • 新增 readonly class、DNF 类型、独立 null/false/true 类型、Random 扩展。

4. PHP 8.2:必须升到 8.2.35,并在年底前迁出

8.2 目前仅剩安全维护,2026 年 12 月 31 日 EOL,只剩两个多月。这次务必先升到 8.2.35 堵住漏洞,同时把迁移到 8.4 / 8.5 排进计划。

bash upgrade-82.sh
# Debian / Ubuntu(Ondrej 源已提供 8.2.35)
sudo apt update
sudo apt install --only-upgrade php8.2-cli php8.2-fpm php8.2-common \
  php8.2-mysql php8.2-curl php8.2-mbstring php8.2-xml php8.2-zip

# RHEL 系(Remi)
sudo dnf upgrade -y php82-php-cli php82-php-fpm php82-php-common

sudo systemctl restart php8.2-fpm
php-fpm -v

8.2 → 8.3 的升级要点:

  • 无参调用 get_class()、get_parent_class() 弃用,需显式传对象。
  • MT_RAND_PHP 随机模式弃用。
  • 新增类型化类常量、#[\Override] 属性、json_validate()、动态类常量获取 Foo::{$name}。
  • readonly 属性在 clone 过程中允许重新初始化。

5. PHP 8.3:升到 8.3.36,重点是 8.4 的隐式 nullable

8.3 的活跃支持已于 2025 年 12 月 31 日结束,安全支持到 2027 年 12 月 31 日。本次升级到 8.3.36 即可。

8.3 → 8.4 最容易踩的坑:隐式 nullable 参数弃用。下面这种写法在 8.4 会持续产生弃用警告:

php before.php
<?php
// PHP 8.4 之前可以,8.4 起弃用
function findUser(int $id = null) {}

// 正确写法:显式声明可空
function findUser(?int $id = null) {}

其他 8.4 变化:

  • E_STRICT 常量弃用。
  • 新增 property hooks、非对称可见性、new 链式调用可省略括号。
  • 新增 array_find()、array_any()、array_all()、mb_trim() 等函数。
  • 新增 #[\Deprecated] 用户态弃用标记。

6. PHP 8.4:升到 8.4.27,活跃支持年底结束

8.4 仍在活跃支持期,但活跃支持到 2026 年 12 月 31 日结束。先升级到 8.4.27,再评估是否在年内切到 8.5。

8.4 → 8.5 的主要变化:

特性说明
管道操作符 |>把值从左到右依次传给可调用对象,减少中间变量
clone() with克隆对象的同时覆盖指定属性,适合 readonly 类
#[\NoDiscard]返回值未被使用时产生警告,防止忽略重要返回
URI 扩展内置 RFC 3986 / WHATWG URL 解析、规范化与修改能力
常量表达式中的闭包静态闭包与一等可调用可作为属性参数等常量表达式
持久化 cURL Share 句柄跨请求复用连接初始化结果,降低重复开销

7. PHP 8.5:当前稳定版,升到 8.5.12

8.5 是当前推荐的生产分支,活跃支持到 2027 年 12 月 31 日,安全支持到 2029 年 12 月 31 日。本次直接升级到 8.5.12。

⚠️
关于 PHP 8.6
同日官方发布了 PHP 8.6.0 RC4,下一个候选版 RC5 计划于 2026 年 11 月 5 日发布。RC 版本仅用于测试,切勿部署到生产环境。

五、通用升级操作(按部署方式)

Ubuntu / Debian(Ondřej Surý 源)

bash ubuntu-upgrade.sh
sudo apt update
sudo apt install -y software-properties-common
sudo add-apt-repository -y ppa:ondrej/php
sudo apt update

# 以 PHP 8.5 为例,安装业务实际用到的扩展
sudo apt install -y php8.5-cli php8.5-fpm php8.5-common \
  php8.5-mysql php8.5-curl php8.5-mbstring php8.5-xml php8.5-zip

# 确认仓库里拿到的补丁号
apt-cache policy php8.5-fpm

# CLI 默认版本切换
sudo update-alternatives --set php /usr/bin/php8.5

# FPM 重启
sudo systemctl restart php8.5-fpm

# Apache 用户还需要切换模块
sudo a2dismod php8.2
sudo a2enmod php8.5
sudo systemctl restart apache2

CentOS / RHEL / Rocky / AlmaLinux(Remi 源)

bash rhel-upgrade.sh
sudo dnf install -y https://rpms.remirepo.net/enterprise/remi-release-9.rpm
sudo dnf module reset php -y
sudo dnf module enable php:remi-8.5 -y

# 升级现有 PHP 包
sudo dnf upgrade -y 'php*'

# 检查版本并重启 FPM
php -v
sudo systemctl restart php-fpm

Windows

  1. 从 windows.php.net 下载 8.5.12 对应线程安全 / 非线程安全压缩包。
  2. 先备份现有 PHP 目录和 php.ini。
  3. 替换二进制文件,保留原 php.ini,按需更新 extension_dir 与扩展行。
  4. 重启 Apache / IIS / php-fpm,执行 php -v 与 php -m 核对。

Docker

dockerfile Dockerfile
FROM php:8.5.12-fpm

RUN docker-php-ext-install pdo_mysql mysqli mbstring

# 构建并滚动更新
# docker compose build
# docker compose up -d

源码编译

bash build-php.sh
./configure --prefix=/usr/local/php-8.5.12 \
  --with-fpm --enable-mbstring --with-pdo-mysql --with-curl
make -j"$(nproc)"
sudo make install

# 用新前缀安装,验证通过后再切换软链
sudo ln -sfn /usr/local/php-8.5.12 /usr/local/php
sudo systemctl restart php-fpm

六、升级前检查清单

  • 备份 php.ini、扩展清单(php -m)、FPM pool 配置与业务代码。
  • 对比升级前后的扩展:diff <(php7.4 -m) <(php8.5 -m)。
  • 扫描废弃函数与语法:each(、create_function、${、隐式 nullable 参数。
  • 执行 composer check-platform-reqs,确认依赖声明的 PHP 版本范围。
  • 先升级 CLI 并跑测试,再升级 FPM;先灰度一台,再全量。
  • 保留旧版本包或旧镜像 tag,确保可在 10 分钟内回滚。

七、实在无法立即升级:官方临时缓解

官方强调这些措施只能降低特定攻击路径的暴露面,不能替代升级。

针对 CVE-2026-109618(OOM 路径)

  • 将 memory_limit 设为 -1,并通过 FPM pool 或 Apache 配置的 php_admin_value 下发,防止应用层改回有限值。
  • 限制请求体:不需要上传时 post_max_size = 8M,需要上传时 post_max_size = 32M,并保证 upload_max_filesize 小于它。
  • 在 Web 服务器或代理层限制解码后的请求大小、字段数、multipart 段数、请求头数量与嵌套深度,且要覆盖没有有效 Content-Length 的请求。
  • 使用容器或 cgroup 做可用性隔离,避免使用 RLIMIT_AS / RLIMIT_DATA。

针对 CVE-2026-109619(全局状态残留)

  • 设置 session.upload_progress.enabled=0,并重启所有 worker。必须写在 php.ini、FPM pool 或服务器配置中,不能依赖 ini_set() 或 .user.ini。
  • PHP 8.5 额外设置 fatal_error_backtraces=0,同样重启全部 worker。
  • 清理每次请求都会触发诊断信息的废弃配置项,隐藏报错(error_reporting、display_errors、@)没有作用。
  • 修复攻击者可触发的致命错误与执行超时,包括回调、上传、导入与清理逻辑中的失败路径。

八、升级后验证

bash verify.sh
php -v
php-fpm -v
php -r 'echo PHP_VERSION, " / ", php_sapi_name(), PHP_EOL;'

# 确认 FPM 已使用新二进制
ps -ef | grep php-fpm

# 健康检查
curl -I https://your-site/

# 关键 ini 是否生效
php -i | grep -E "memory_limit|post_max_size|session.upload_progress"

九、行动建议

当前版本立即动作中期规划
PHP 7.4自编译 backport 分支或找 LTS 厂商直接迁移到 8.3 / 8.4 / 8.5
PHP 8.0自编译 backport 分支或找 LTS 厂商直接迁移到 8.3 / 8.4 / 8.5
PHP 8.1自编译 backport 分支或找 LTS 厂商至少升 8.2.35,建议 8.4 / 8.5
PHP 8.2立即升 8.2.352026-12-31 前迁出
PHP 8.3立即升 8.3.36评估 8.5.12
PHP 8.4立即升 8.4.27活跃支持年底结束,规划 8.5
PHP 8.5立即升 8.5.12保持补丁跟进
安全补丁没有"下次再说"。
能升就升,升不了就隔离,别让一个未认证请求跑在旧版本上。