答案是php openssl证书路径未正确配置导致tls握手卡死。需运行php -r "print_r(openssl_get_cert_locations());"确认default_cert_file有效性,并在cli生效的php.ini中同时设置curl.cainfo和openssl.cafile指向同一最新cacert.pem绝对路径,改完必须重启终端或服务。

“SSL connection timeout”不是网络慢,而是 TLS 握手卡死在证书验证环节——本质是 PHP 的 OpenSSL 无法完成证书链校验,必须修复 CA 证书路径,不能只换镜像或调超时。
curl error 28 或 SSL connection timeout 的真实原因
这类报错常出现在 composer install 卡在 Loading composer repositories 或 Downloading https://... 阶段,错误里带 cURL error 28、Operation timed out 或 SSL connection timeout。这不是 DNS 解析失败,也不是网速问题,而是:
- PHP 内置的 cURL 扩展在发起 HTTPS 请求时,尝试做 TLS 握手 + 证书链验证,但本地找不到可信根证书(或证书过期),导致握手无限等待直至超时
- 系统级
curl命令能通(如curl -I https://packagist.org成功),但 PHP 的curl_exec()失败,说明 PHP 和系统用了两套 CA 信任库 - 即使已切阿里云镜像,只要证书链不全,照样卡在 TLS 层,换源无效
验证是否为 CA 证书问题的三行命令
别急着改配置,先用这三行快速定位:
- 运行
php -r "print_r(openssl_get_cert_locations());",重点看default_cert_file和ini_cafile是否为空、路径是否存在、文件最后修改时间是否早于 2023 年(旧证书不含 ISRG Root X1) - 运行
curl -v https://packagist.org/packages.json 2>&1 | grep "SSL certificate",如果也报unable to get local issuer certificate,说明是系统/PHP 层级证书失效 - 运行
php --ini,确认你编辑的是 CLI 模式下真正生效的php.ini(尤其 Docker、phpEnv、多版本 PHP 环境里常有多个 ini 文件)
Windows/macOS/Linux 统一修复方案
核心动作:下载最新官方 cacert.pem,并在 php.ini 中**同时设置**两个参数,指向同一文件路径,然后重启 PHP 环境:
- 从 curl.se 官方 CA 包 下载最新
cacert.pem,保存到稳定路径(如C:/phpEnv/php/extras/ssl/cacert.pem或/usr/local/etc/php/cacert.pem) - 在
php.ini中添加两行(路径必须完全一致,且用正斜杠或双反斜杠):curl.cainfo="/usr/local/etc/php/cacert.pem"openssl.cafile="/usr/local/etc/php/cacert.pem" - Windows 用户注意:
phpEnv或XAMPP下改完必须关闭并重开终端;Apache/Nginx 需重启服务;CLI PHP 不热加载 ini - Linux/macOS 更推荐系统级更新:
sudo apt install --reinstall ca-certificates(Debian/Ubuntu)或brew reinstall ca-certificates(macOS + Homebrew),再检查openssl_get_cert_locations()输出中的capath是否指向新证书目录
为什么 config -g cafile 或 secure-http=false 无效
这些 Composer 级别配置不触达底层 cURL/SSL 初始化逻辑:
-
composer config -g cafile /path/to/cert.pem在 Composer 2.x 中已被弃用,实际不生效 -
composer config -g secure-http false只影响源类型校验,不绕过 PHP cURL 的证书验证,且会暴露中间人攻击风险 - 禁用验证(如设
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false))属于临时调试手段,上线环境严禁使用 - Docker 构建中若未显式安装
ca-certificates,容器启动时证书路径为空,php.ini配置再准也没用
最易被忽略的一点:PHP CLI 和 Web SAPI(如 PHP-FPM)可能加载不同的 php.ini,而 composer 命令走的是 CLI 模式。CI 脚本中若没显式指定 php --ini 或确认 COMPOSER_HOME,修复很可能只在本地生效,上线即复现。











