根本原因是PHP的OpenSSL扩展绑定的libssl版本过旧(如1.0.2及以下),不支持TLS 1.2+,而Packagist强制要求现代TLS协议;需升级PHP使其链接OpenSSL 1.1.1+库,并验证php -i | grep -i "openssl library"确认版本达标。

为什么 Composer install 会报 SSL handshake failed 错误
根本原因是 PHP 的 OpenSSL 扩展底层调用的 libssl 版本太老(比如 OpenSSL 1.0.2 或更早),而 Packagist 和大多数现代 Composer 源强制要求 TLS 1.2+,旧版 OpenSSL 不支持 SNI 或无法协商安全协议,直接断连。典型错误信息是:SSL handshake failed、Unable to connect to repo.packagist.org 或 cURL error 35: SSL connect error。
这不是 Composer 配置问题,也不是网络代理问题——即使 curl -I https://repo.packagist.org 能通,PHP 的 curl 扩展仍可能失败,因为 PHP 绑定的是自己编译时链接的 OpenSSL 库,而非系统最新版本。
检查当前 PHP 使用的 OpenSSL 版本
运行 php -r "print_r(openssl_get_cert_locations());" 查看 PHP 加载的证书路径和 OpenSSL 版本;更直接的方式是:php -i | grep -i openssl。重点关注 OpenSSL Library Version 和 OpenSSL Header Version 是否一致,且是否 ≥ 1.1.1。
- 若显示
OpenSSL 1.0.2u或更低,基本确定是根源 - 若两个版本不一致(如 header 是 1.1.1,library 是 1.0.2),说明 PHP 编译时链接了旧库
-
openssl version -a显示系统最新版本没用——PHP 不一定用它
升级 PHP 的 OpenSSL 依赖(非单纯升级系统 OpenSSL)
关键点:不能只用 apt upgrade openssl 或 brew upgrade openssl,必须让 PHP 重新链接到新版 OpenSSL 库。常见路径:
- Ubuntu/Debian:重装 php 系列包,确保源支持新版 OpenSSL,例如用
ondrej/phpPPA 并安装php8.2-cli(自带 OpenSSL 1.1.1+) - macOS + Homebrew:先
brew install openssl@1.1,再brew reinstall php@8.2 --with-openssl=/opt/homebrew/opt/openssl@1.1(路径按实际调整) - 源码编译 PHP:configure 时显式指定
--with-openssl=/usr/local/ssl(指向新版 OpenSSL 安装前缀) - Docker:基础镜像别用
php:8.1-apache这类可能含旧 OpenSSL 的旧标签,改用php:8.2-cli-bookworm(Debian 12 自带 OpenSSL 3.0)
验证:升级后再次运行 php -i | grep -i "openssl library",确认输出为 OpenSSL 1.1.1w 或 OpenSSL 3.0.x。
临时绕过但不推荐的应急方案
仅限调试或离线环境测试,**绝不可用于生产或 CI**:
- 设置环境变量禁用 TLS 验证:
export COMPOSER_DISABLE_TLS=1(等价于--disable-tls),但会降级为 HTTP,存在中间人风险 - 修改 Composer 全局配置强制走 HTTP:
composer config -g repo.packagist.org.url http://repo.packagist.org,同样不安全 - 用
composer install --no-plugins --no-scripts有时能跳过部分 HTTPS 请求,但无法解决composer update或元数据拉取失败
真正稳定的解法永远是让 PHP 的 OpenSSL 库达标——握手失败不是网络问题,是密码学能力缺失。很多团队卡在“试了代理、换了源、清了缓存还是失败”,其实就差重新编译或重装一次 PHP。


















