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

composer install 失败不是镜像或网络问题,而是 PHP 底层 TLS 握手卡在证书验证环节——必须同时配置 curl.cainfo 和 openssl.cafile 指向同一份最新 CA 证书文件,否则一半 HTTPS 请求会直接失败。
怎么确认真是证书链不完整?
别改配置,先让 PHP 自己说清楚:
- 运行
php -r "print_r(openssl_get_cert_locations());",重点看ini_cafile和default_cert_file是否为空、路径是否存在、文件大小是否 > 0 - 运行
curl -v https://mirrors.aliyun.com/composer/packages.json 2>&1 | grep "SSL certificate",如果也报unable to get local issuer certificate,说明是 PHP/cURL 层级失效,和 Composer 配置无关 - 运行
php --ini,确认你正在编辑的是 CLI 模式下真正生效的php.ini(尤其 phpEnv、XAMPP、Homebrew 环境常有多个)
为什么只配 curl.cainfo 或只配 openssl.cafile 不行?
PHP 内部 HTTPS 请求走两条路:cURL 扩展(如 Composer 下载包)和 OpenSSL 原生函数(如 file_get_contents()、stream context)。只设一个,另一路仍 fallback 到空信任链,错误照出。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
-
curl.cainfo控制 cURL 发起的 HTTPS 请求 -
openssl.cafile控制 OpenSSL 原生 TLS 握手(包括 Composer 的部分内部调用) - 两者必须指向**同一绝对路径**的 PEM 文件,且路径中不能含中文、空格、单反斜杠
证书文件怎么选、怎么放、怎么配?
系统自带或旧版 PHP 附带的证书大多停更于 2021 年,无法验证 ISRG Root X1 等新根证书。必须换官方维护的最新包。
- 下载地址固定为
https://curl.se/ca/cacert.pem,用curl -sS https://curl.se/ca/cacert.pem -o /path/to/cacert.pem保存(Windows 推荐C:/php/extras/ssl/cacert.pem;macOS/Linux 推荐/usr/local/etc/php/cacert.pem) - 在
php.ini中添加两行(路径必须是绝对路径、英文双引号包裹):curl.cainfo = "C:/php/extras/ssl/cacert.pem"openssl.cafile = "C:/php/extras/ssl/cacert.pem" - 改完必须关闭当前终端、新开一个——CLI 下 PHP 进程不热加载,上下文不会自动重读 ini
为什么 composer config -g cafile 经常不起作用?
这条命令只影响 Composer 自己封装的 HTTP 客户端(基于 php-http),但实际发起 HTTPS 请求的是 PHP 的 cURL 或 OpenSSL 扩展。它无法覆盖 curl.cainfo 的优先级,也不能修复底层 TLS 握手失败。
- 可能显示 “CA file configured”,但
composer install依然报错,就是典型表现 - 它对 Git 克隆、插件调用、或任何绕过 Composer HTTP 客户端的操作完全无效
- 仅当
php.ini未统一配置时,可作为临时兜底:composer config -g cafile "/path/to/cacert.pem"
ini_get('curl.cainfo') 返回 false,这些细节比选哪个镜像重要得多。










