答案是运行php -r "print_r(openssl_get_cert_locations());"确认default_cert_file和ini_cafile是否为空、无效或不一致;若异常,则需在CLI实际生效的php.ini中同步配置绝对路径的curl.cainfo与openssl.cafile指向同一最新cacert.pem,并重启终端或服务。

php -r "print_r(openssl_get_cert_locations());" 输出为空或路径无效
这是最直接的线索:如果 default_cert_file 是空字符串、null,或指向一个根本不存在的文件(比如 C:/php/extras/ssl/cacert.pem 但该路径下没这个文件),PHP 的 OpenSSL 就会 fallback 到空信任链,所有 HTTPS 请求都失败。
别只看报错里有没有 “certificate verify failed”,先运行这行命令确认事实:
php -r "print_r(openssl_get_cert_locations());"
- 检查输出中的
default_cert_file和ini_cafile字段值是否一致、是否为绝对路径 - 用
ls -l /path/to/file(Linux/macOS)或dir C:path oile(Windows)验证文件是否存在、大小是否 > 0 KB - 如果路径是符号链接(如
/etc/ssl/certs/ca-certificates.crt),用readlink -f看真实路径,并确认该文件可读(权限至少是644)
curl.cainfo 和 openssl.cafile 必须同时配置且路径完全一致
只配 curl.cainfo 或只配 openssl.cafile 都不够。Composer 内部调用可能走 cURL,也可能走 PHP 原生 stream context(依赖 OpenSSL),二者配置不统一就会出现“有时行、有时不行”的诡异现象。
在 CLI 模式下真正生效的 php.ini(运行 php --ini 查看 Loaded Configuration File)末尾添加这两行:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
curl.cainfo = "/usr/local/etc/php/cacert.pem" openssl.cafile = "/usr/local/etc/php/cacert.pem"
- 路径必须是绝对路径;Windows 上避免单反斜杠(
C:php...❌),改用正斜杠(C:/php/...)或双反斜杠(C:\php\...) - 两个值必须一字不差——哪怕多一个空格、少一个引号,PHP 都不会报错,但配置不生效
- Linux/macOS 下确保文件权限为
644,且 PHP 进程用户有读取权限(例如 Alpine 容器里常需apk add ca-certificates)
下载 cacert.pem 的权威来源与存放位置
别用系统自带的 bundle,尤其别信“中文版 CA 库”这种说法——CA 证书是标准 PEM 格式,没有语言版本,只有新旧之分。唯一可靠来源是 Mozilla 维护的官方列表:
https://curl.se/ca/cacert.pem
- Linux/macOS 推荐存到:
/usr/local/etc/php/cacert.pem(Homebrew 用户可用/opt/homebrew/etc/ca-certificates/cert.pem) - Windows 推荐存到:
C:/php/extras/ssl/cacert.pem(路径中不要有空格或中文) - 下载命令示例:
curl -sS https://curl.se/ca/cacert.pem -o /usr/local/etc/php/cacert.pem - 验证是否下载成功:
head -n 2 /usr/local/etc/php/cacert.pem应看到-----BEGIN CERTIFICATE-----
改完 php.ini 后为什么 composer install 还报错
常见原因是配置没真正加载——CLI 模式下,PHP 不会自动 reload php.ini,你必须关掉当前终端窗口,新开一个再试。
验证是否生效,不是看 Composer 是否成功,而是让 PHP 自己说话:
php -r "var_dump(ini_get('curl.cainfo'));"
php -r "print_r(openssl_get_cert_locations());"
- 两者的输出必须显示你刚写的路径,且
file_get_contents(ini_get('curl.cainfo')) !== false返回true - Web 环境(Apache/Nginx + php-fpm)必须重启对应服务,不能只刷新页面
-
composer config --global cafile对这类底层握手失败完全无效,它只影响 Composer 自封装的 HTTP 客户端,不触碰 PHP 的 OpenSSL/cURL 栈
php.ini,而你只改了其中一个;或者改完后没关终端,以为重跑命令就生效了。

















