应更新系统证书或配置composer信任指定ca证书;先用composer diagnose定位ssl错误,再通过php -r检查openssl证书路径,修复cafile指向或追加内网根证书,最后用composer config --global cafile指定。

composer install 时提示 “SSL certificate problem” 怎么办
直接禁用 SSL 验证不是解法,而是掩盖问题的临时补丁。真正要处理的是 curl 或 openssl 层面对证书链的信任缺失,常见于企业代理、自建 CA、旧系统 OpenSSL 版本过低或证书缓存损坏。
- 先确认错误是否复现:
composer diagnose会明确告诉你哪一步卡在 SSL(比如curl error 60) - 别急着加
-n或改disable-tls—— 这会让所有包下载走明文 HTTP,有中间人风险 - 优先检查系统级证书路径是否被覆盖:运行
php -r "print_r(openssl_get_cert_locations());",看default_cert_file指向的文件是否存在、可读 - 若用 macOS Homebrew PHP,常见问题是
cafile指向了空文件或过期的curl-ca-bundle.crt;可手动更新:brew install ca-certificates && brew link --force ca-certificates
如何让 composer 信任自签名或内网 CA 证书
开发环境连公司私有 Packagist 或 Satis 仓库时,必须显式注入根证书,否则 composer update 一定失败。
- 把你的 PEM 格式根证书(比如
company-root-ca.crt)追加到系统默认证书文件末尾,或单独保存为/usr/local/etc/php/cert.pem - 告诉 Composer 用它:
composer config --global cafile /usr/local/etc/php/cert.pem - 验证是否生效:
composer config --global cafile应输出路径;再跑一次composer diagnose,SSL 部分应显示 “OK” - 注意:PHP 的
openssl.cafileini 设置和 Composer 的cafile是两套逻辑,前者影响所有 PHP SSL 调用,后者只影响 Composer 自身的 HTTP 客户端
Windows 上 composer 使用代理后 SSL 失败的典型原因
不是代理本身的问题,而是 Windows 下 Composer 默认用 PHP 内置 stream_context 发起 HTTPS 请求,而代理配置(http_proxy 环境变量)不自动透传到 TLS 层,导致握手时仍直连目标域名但走代理隧道,证书校验错乱。
- 最稳方案:不用系统代理,改用
composer config --global http-proxy https://user:pass@proxy.company.com:8080(注意协议写https://,即使代理是 HTTP) - 如果代理强制要求 NTLM 认证,PHP stream 不支持,得换方案:用
CNTLM或px做本地认证中转,再让 Composer 连http://127.0.0.1:3128 - 别碰
php.ini里的openssl.cafile—— Windows PHP 安装包自带的证书 bundle 经常残缺,强行指定反而更糟
为什么 composer self-update 也会 SSL 报错
因为 Composer 自身更新走的是 GitHub Releases API(https://api.github.com),它对证书链完整性比普通包源更敏感,尤其当你系统 OpenSSL
- 先试
curl -I https://api.github.com,如果也报 SSL 错误,说明是底层问题,不是 Composer 特有 - Linux 用户可更新 CA 包:
sudo apt update && sudo apt install --reinstall ca-certificates(Debian/Ubuntu) - macOS 用户避免用 MacPorts 的 PHP,Homebrew 的
php+ca-certificates组合最可靠 - 极端情况(如离线环境),可手动下载最新 PHAR:
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');",但需核对 SHA384 签名
证书问题从来不是“配个参数就完事”,关键在厘清信任链从哪断——是系统缺根证书、PHP 没读对路径、代理干扰了 TLS 握手,还是网络中间设备做了 SSL 解密。每种场景对应的修复点完全不同,混用方案只会让问题更模糊。








