Composer self-update暴露系统OpenSSL补丁问题,因其依赖PHP cURL扩展发起HTTPS请求,而cURL直连底层OpenSSL;若系统OpenSSL未更新至1.1.1+并打关键补丁(如ISRG Root X1信任链),则无法协商Packagist强制启用的TLS 1.2+及现代密码套件,导致握手阶段失败,典型错误为cURL error 35或ssl connect error。

为什么 self-update 会暴露系统 OpenSSL 补丁问题
因为 composer self-update 依赖 PHP 的 cURL 扩展发起 HTTPS 请求,而 cURL 又直连底层 OpenSSL。一旦系统 OpenSSL 未打补丁(比如没更新到 1.1.1+),就无法协商 Packagist 服务端强制启用的 TLS 1.2+ 和现代密码套件——这不是 Composer 能绕过的逻辑层问题,而是握手阶段就被 OS 底层拦截。
典型现象是卡在 cURL error 35: SSL connect error 或直接超时,composer diagnose 会明确报出 curl: (35) SSL connect error,而非网络不通或 DNS 失败。
- CentOS 7 默认 OpenSSL 1.0.2k 已停止维护,不支持 TLS 1.3,且部分被禁用的旧密码套件会导致握手失败
- Ubuntu 18.04 LTS 的 openssl 包若未执行
apt upgrade,可能仍停留在 1.1.1-1ubuntu2.x,缺少 2025 年后关键补丁 - macOS Homebrew 安装的 PHP 若未同步更新
openssl@3,其绑定的 libssl 可能不含 ISRG Root X1 信任链补丁
验证 OpenSSL 是否已打关键补丁
别只看版本号,要确认实际运行时加载的是哪个 OpenSSL 实例,并检查它是否包含必需补丁:
- 运行
openssl version -a,重点看built on日期——必须晚于 2025 年 3 月(ISRG Root X1 全面启用时间) - 运行
php -i | grep -i "openssl version",确认 PHP 加载的 OpenSSL 版本与上一步一致;若不一致,说明 PHP 编译时链接了旧库 - 执行
openssl s_client -connect packagist.org:443 -tls1_2,成功返回证书链即表示 TLS 1.2 可通;若报ssl handshake failed,说明补丁缺失或配置错误
self-update 失败时如何区分是系统补丁问题还是镜像缓存问题
两者表现相似,但排查路径完全不同:
- 如果是系统补丁问题:
curl -v https://packagist.org/packages.json同样失败,且错误信息含SSL certificate problem或SSL connect error - 如果是镜像缓存导致的“假最新”:
composer self-update --mirror https://getcomposer.org/能成功升级,但用国内镜像(如阿里云)时始终提示Up to date即使版本明显旧 - 临时绕过镜像验证:
COMPOSER_DISABLE_TLS=true composer self-update若能跑通,基本可排除系统补丁问题,指向镜像或网络中间设备干扰
补丁更新后仍 self-update 失败的隐藏原因
即使 OpenSSL 已更新,PHP 仍可能加载旧 CA 证书或错误路径:
- 运行
php -r "print_r(openssl_get_cert_locations());",检查default_cert_file指向的文件是否存在、大小是否 ≥ 200KB(权威 cacert.pem 当前约 350KB) - 若路径为
/etc/ssl/certs/ca-certificates.crt,但ls -l显示它是 0 字节符号链接或权限为000,PHP 就读不到任何证书 - Windows 用户常改了
php.ini里的openssl.cafile,却忘了 CLI 和 Web SAPI 使用不同 ini 文件——务必用php --ini确认正在编辑的是 CLI 配置 - macOS Homebrew PHP 默认不读系统证书路径,必须显式配置
curl.cainfo和openssl.cafile指向/usr/local/etc/php/cacert.pem(需手动下载并放置)
self-update 都会在 TLS 握手那一步静默失败。


















