必须设为绝对路径且文件存在可读、格式为pem,windows用正斜杠或双反斜杠,含空格或中文需加引号;修改后须重启web服务或php-fpm,再通过php -r "echo ini_get('curl.cainfo');"和openssl_get_cert_locations()验证是否生效。

curl.cainfo 在 php.ini 里怎么设才生效
必须填绝对路径,且文件存在、可读、格式是 PEM。Windows 下路径里的反斜杠要写成正斜杠或双反斜杠,比如 curl.cainfo = "C:/php/cacert.pem" 或 curl.cainfo = "C:\php\cacert.pem"。如果路径含中文或空格,不加引号会解析失败;加了引号但路径错误,PHP 不报错,只是静默忽略该配置。
改完后一定要重启 PHP-FPM 或 Apache/Nginx 进程,仅刷新网页无效。验证是否生效:运行 php -r "echo ini_get('curl.cainfo');",输出应为完整路径;再执行 php -r "print_r(openssl_get_cert_locations());",确认 default_cert_file 和 curl.cainfo 指向同一文件。
用 curl_setopt(CURLOPT_CAINFO) 临时指定证书时常见错误
这个选项只对当前 cURL 句柄有效,但容易被其他库覆盖。比如 Guzzle 默认会读取 curl.cainfo,如果你在 new GuzzleHttpClient() 时传了 ['verify' => '/path/to/cacert.pem'],它内部会调用 curl_setopt($ch, CURLOPT_CAINFO, ...) —— 这没问题;但如果同时又设置了 ['verify' => false],就会优先禁用校验,CAINFO 被忽略。
-
CURLOPT_CAINFO的值必须是字符串,不能是相对路径或__DIR__ . '/cacert.pem'这种动态拼接(除非你确保运行时路径稳定) - 若用
file_exists()检查证书文件,请确认 Web 服务器用户(如 www-data、nginx)有读取权限 - 不要和
CURLOPT_SSL_VERIFYPEER => false混用,后者会让前者完全失效
macOS 上 PHP 找不到系统证书的典型表现与修复
Homebrew 安装的 PHP 常默认使用系统 OpenSSL,但 macOS 的钥匙串根证书不直接暴露为 PEM 文件。现象是 openssl_get_cert_locations() 返回的 default_cert_file 是空或指向不存在路径,curl_exec() 报错 cURL error 60。
推荐做法不是下载第三方 cacert.pem,而是复用 Homebrew OpenSSL 的证书包:
- 先装
brew install openssl@3 - 确认证书文件存在:
ls /opt/homebrew/etc/openssl@3/cert.pem - 在
php.ini中同时设置:curl.cainfo = "/opt/homebrew/etc/openssl@3/cert.pem"和openssl.cafile = "/opt/homebrew/etc/openssl@3/cert.pem" - 别忘了重启 PHP 服务
ThinkPHP 或 Laravel 等框架里 verify=false 的真实影响
框架封装的 HTTP 客户端(如 hinkacadeHttp::get() 或 GuzzleHttpClient)把 'verify' => false 当作开关,底层仍会调用 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false) 和 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false)。这不只是跳过证书签发者检查,还会关闭域名匹配(SNI 验证),导致中间人攻击面扩大。
生产环境绝对不要用。哪怕只是临时调试,也要确认:
- 代码没被误提交到 Git
- 配置项没被写进公共 config 文件
- CI/CD 流水线不会加载该配置
真正容易被忽略的是:某些云函数或容器环境(如 Alpine Linux)连基础 CA 包都没预装,curl.cainfo 设了也白设——得先用 apk add ca-certificates 补上系统级证书,再配 PHP。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











