default_cert_file是PHP OpenSSL默认信任CA证书的关键路径,由编译时硬编码决定,需通过php.ini中openssl.cafile覆盖;推荐下载最新CA bundle并配置该参数,禁用SSL验证仅限调试。

php -r "print_r(openssl_get_cert_locations());" 输出的 default_cert_file 是关键
这个值决定了 PHP OpenSSL 默认信任哪些 CA 证书。它不是读取系统 /etc/ssl/certs/ca-certificates.crt,也不是自动继承 curl.cainfo;它是 PHP 编译时硬编码的路径,运行时只能靠 openssl.cafile 覆盖。如果输出中 default_cert_file 为空、指向不存在的文件,或内容过期,file_get_contents('https://...') 和 cURL 都会报 unable to get local issuer certificate。
设置 openssl.cafile 比重编译 PHP 安全且有效
绝大多数场景下,你不需要重新编译 PHP 或 OpenSSL——只需让 PHP 知道一个有效的 PEM 格式 CA bundle 文件位置即可。操作分三步:
- 下载最新 CA bundle,例如从 curl.se/cacert.pem 保存为
/usr/local/share/ca-bundle.crt - 在
php.ini中添加一行:openssl.cafile=/usr/local/share/ca-bundle.crt - 重启 PHP-FPM 或 Apache(CLI 模式需确保该 ini 被加载,可用
php --ini确认)
验证是否生效:再次运行 php -r "print_r(openssl_get_cert_locations());",确认 default_cert_file 已更新为你指定的路径,且文件可读。
别用 CURLOPT_SSL_VERIFYPEER => false 掩盖问题
临时加 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false) 或 stream_context_create(['ssl' => ['verify_peer' => false]]) 确实能绕过证书错误,但后果严重:
立即学习“PHP免费学习笔记(深入)”;
- PHP 8.0+ CLI 下会触发
E_WARNING,部分云环境(如某些 Serverless 运行时)直接拒绝执行 - HTTPS 退化为明文传输级别,中间人攻击完全无防护
- 掩盖了真实配置缺陷,后续换环境或升级后突然失败
它只是调试手段,绝不能进生产代码。
自签名证书或内网 HTTPS 抓取要额外处理
如果你抓的是自己签发的证书(如 localhost+2.pem)、或企业内网 CA 颁发的证书,CA bundle 里没有对应根证书,此时:
- 把你的根证书(PEM 格式)追加到
/usr/local/share/ca-bundle.crt末尾,再重启服务 - 或单独指定:在
php.ini中设openssl.cafile=/path/to/your-ca-bundle.crt,确保包含该根证书 - 不要只放域名证书,必须是完整的信任链(根 + 中间证书),否则仍会验证失败
最易被忽略的一点:PHP 不会自动拼接证书链,openssl_x509_read() 只读单个证书,而 HTTPS 请求验证依赖的是 CA bundle 中的根证书——哪怕你代码里传了完整链文件,也得确保那个根在 openssl.cafile 所指文件里。



















