根本原因是php底层tls握手失败,需先校准系统时间(偏差超2分钟会触发相同错误),再用php -r "print_r(openssl_get_cert_locations());"确认ini_cafile和default_cert_file路径有效且文件大小>1mb,同时配置curl.cainfo与openssl.cafile为同一绝对路径的最新cacert.pem并重启终端。

根本原因不是仓库地址写错了,而是 PHP 底层 TLS 握手失败——curl.cainfo 和 openssl.cafile 指向的证书文件无效、路径错误或系统时间偏差超 2 分钟,导致无法验证镜像源(如 https://mirrors.aliyun.com/composer/)的 HTTPS 证书。
怎么确认是证书路径问题而不是镜像配置错误
别急着改 composer.json 或换源。先让 PHP 自己说话:
- 运行
php --ini,看Loaded Configuration File路径,确保你编辑的是 CLI 模式下真正生效的php.ini - 执行
php -r "print_r(openssl_get_cert_locations());",重点检查:
–ini_cafile是否为空或路径不存在
–default_cert_file对应文件是否存在且大小 > 1MB(太小说明是旧版或损坏) - 再跑一句
curl -v https://mirrors.aliyun.com/composer/packages.json,如果也报unable to get local issuer certificate,说明是 PHP/cURL 层级失效,和 Composer 配置无关
php.ini 中必须同时设置两个参数且路径一致
PHP 内部发起 HTTPS 请求分两路:cURL 扩展走 curl.cainfo,stream context 等走 openssl.cafile。只配一个,另一路仍 fallback 到空信任链。
- Windows 示例(路径用英文双引号,反斜杠需转义或换正斜杠):
curl.cainfo = "C:/php/extras/ssl/cacert.pem"openssl.cafile = "C:/php/extras/ssl/cacert.pem" - macOS/Linux 示例(必须绝对路径,不能用
~):curl.cainfo = "/usr/local/etc/php/cacert.pem"openssl.cafile = "/usr/local/etc/php/cacert.pem" - 证书文件必须从 Mozilla 官方下载:
curl -sS https://curl.se/ca/cacert.pem -o /path/to/cacert.pem(别用浏览器另存,会混入 HTML) - 改完保存后,必须关闭当前终端、新开一个——CLI 下不热加载
系统时间偏差超 2 分钟会触发一模一样的错误提示
OpenSSL 校验证书 notBefore/notAfter 时间戳,偏差超过 120 秒就直接拒连。现象和证书路径错误完全一致,但修复方式完全不同。
- Linux/macOS:
sudo timedatectl set-ntp truesudo systemctl restart systemd-timesyncd
再用timedatectl status | grep "System clock synchronized"确认输出yes - Windows(管理员 CMD):
net start w32timew32tm /config /syncfromflags:manual /manualpeerlist:"time.nist.gov pool.ntp.org"w32tm /resync - 容器环境必须先修宿主机时间;Alpine 镜像需额外安装
openntpd或挂载宿主机/etc/timezone
最容易被忽略的是:改了 php.ini 却没重启终端,或校准了时间却没验证 curl -I https://packagist.org 是否还报错——这两步漏掉任何一环,问题都会原样复现。











