必须同时配置curl.cainfo和openssl.cafile为同一绝对路径的cacert.pem文件,否则composer https请求会因某一路扩展证书校验失败而报错;改php.ini后须关闭并重启终端生效。

curl.cainfo 和 openssl.cafile 必须同时设对
Composer 的 HTTPS 请求会分两路走:cURL 扩展(如下载 zip)和 OpenSSL 原生函数(如 stream_context_create)。只配 curl.cainfo,openssl.cafile 仍为空,就会在某些包解析阶段报 SSL certificate problem: unable to get local issuer certificate。
必须用绝对路径、英文双引号包裹,且指向同一个有效的 cacert.pem 文件:
- 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" - 路径不能含
~、中文、空格;文件大小应 > 200 KB(过小说明下载不全)
改完 php.ini 后必须重启终端
CLI 模式下 PHP 不热加载配置,php --ini 显示的 Loaded Configuration File 改了也没用,进程不重载就还是旧上下文。常见现象是:改完 php.ini,php -r "print_r(openssl_get_cert_locations());" 输出的 ini_cafile 仍是空或旧路径。
正确操作只有一步:关闭当前终端窗口,新开一个,再验证。别信“重载”“刷新”这类无效动作。
系统时间偏差超 2 分钟会伪装成证书过期
报 SSL certificate problem: certificate has expired,但你知道镜像源没换、证书也刚更新——大概率是本地时钟快了或慢了。OpenSSL 校验证书的 notBefore/notAfter 字段,偏差 ≥ 120 秒直接拒绝连接。
验证方式最简单:date 对比 time.is。修复方法因系统而异:
- Linux/macOS:
sudo timedatectl set-ntp true && sudo systemctl restart systemd-timesyncd,再timedatectl status | grep "synchronized"确认输出yes - Windows(管理员运行):
w32tm /config /syncfromflags:manual /manualpeerlist:"time.nist.gov pool.ntp.org"→w32tm /resync
composer config -g cafile 是无效兜底
这条命令只影响 Composer 自己封装的 HTTP 客户端(基于 php-http),但底层发起 HTTPS 请求的是 PHP 的 cURL 或 OpenSSL 扩展。它既不能覆盖 curl.cainfo 的优先级,也无法修复 TLS 握手失败。
典型失效场景:
-
composer config -g cafile显示已设置,但composer install仍报错 - Git 克隆私有仓库、插件执行远程调用时照样失败
- CI 环境中完全不起作用(因为没读 Composer 配置)
它只在 php.ini 完全不可控时临时用一次,比如老旧 Docker 容器里没有 root 权限改配置——但那不是常态,不该当成正解。











