错误源于cURL默认校验SSL证书但本地缺失可信CA包;应下载cacert.pem、在php.ini中配置curl.cainfo路径并重启服务,禁用验证仅限临时调试。

curl_exec()报错“SSL certificate problem: unable to get local issuer certificate”
这是 PHP cURL 访问 HTTPS 接口时最常遇到的证书验证失败错误,本质是 cURL 默认启用 SSL 证书校验,但本地找不到可信 CA 证书包(ca-bundle.crt)或路径不对。
常见诱因包括:Windows 下未配置 curl.cainfo、Linux 系统缺少 ca-certificates 包、或 PHP 编译时未链接 OpenSSL 正确版本。
- 先确认是否真缺证书:运行
php -r "print_r(openssl_get_cert_locations());",检查default_cert_file路径是否存在且可读 - 若路径为空或文件不存在,手动下载 Mozilla CA 包(如 cacert.pem),保存为 UTF-8 无 BOM 格式
- 在
php.ini中添加:curl.cainfo = "/path/to/cacert.pem"(Windows 用正斜杠或双反斜杠) - 重启 Web 服务或 PHP-FPM,再测试
使用 curl_setopt() 绕过证书验证的风险与适用场景
临时调试可以禁用证书验证,但绝不该用于生产环境——这等于放弃 HTTPS 的身份认证和加密保障,中间人攻击可直接解密通信。
仅限本地开发、测试自签名证书服务、或对接内网无 CA 签发的 HTTPS 接口时谨慎使用。
立即学习“PHP免费学习笔记(深入)”;
- 必须同时设置两项:
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false)和curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false) - 只设
CURLOPT_SSL_VERIFYPEER为false而不设CURLOPT_SSL_VERIFYHOST,cURL 仍可能报错 “unable to connect to ssl host” - PHP 7.0+ 若启用了
open_basedir,CURLOPT_CAINFO指定的证书路径需在允许范围内,否则静默失效
发送 POST 数据时 content-type 与数据格式不匹配导致 400/415 错误
HTTPS 请求本身没问题,但后端拒绝处理,往往是因为 Content-Type 头和实际发送的数据格式对不上。比如接口要求 application/json,却用 http_build_query() 发送表单数据。
- 发 JSON:设置
Content-Type: application/json,并用json_encode($data)作为CURLOPT_POSTFIELDS值 - 发表单(x-www-form-urlencoded):不设
Content-Type(cURL 自动加),直接传http_build_query($data) - 上传文件:必须用
CURLOPT_POSTFIELDS传数组,键名为字段名,值为@/path/to/file(PHP 5.6+ 推荐用CurlFile对象) - 注意:PHP 5.6+ 默认开启
safe_mode兼容性已移除,@语法需显式启用CURLOPT_SAFE_UPLOAD = false(不推荐)或改用CurlFile
curl_multi_exec() 并发 HTTPS 请求时证书复用与性能陷阱
批量调用多个 HTTPS 接口时,如果每个句柄都重复初始化 CA 验证逻辑,会显著拖慢速度;更隐蔽的问题是,并发下证书路径配置可能被某个请求覆盖或读取冲突。
- 所有
curl_init()句柄共享同一套 SSL 设置:在curl_multi_init()后统一调用curl_setopt($ch, CURLOPT_CAINFO, $certPath)即可,无需每个单独设 - 避免在循环中反复
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true)—— 这个值默认就是 true,冗余调用无意义 - 高并发下建议限制最大连接数:
curl_multi_setopt($mh, CURLMOPT_MAXCONNECTS, 20),防止系统级 socket 耗尽 - 证书文件若放在 NFS 或网络存储上,多进程并发读取可能触发 I/O 瓶颈,应确保
cacert.pem在本地磁盘
false。











