php httpS 请求失败主因是环境缺失或配置错位,需检查 Openssl/curl 扩展启用、证书路径正确及 CA 证书链有效,禁用证书验证仅限临时调试。

PHP 默认支持 https 请求,但前提是底层 cURL 或 OpenSSL 扩展已正确编译并链接到可用的 OpenSSL 库,且运行时能加载可信 CA 证书链。问题往往不出在 PHP 代码本身(比如 file_get_contents('https://...') 或 curl_exec()),而在于环境缺失或配置错位。
检查 PHP 是否已启用 OpenSSL 和 cURL 支持
直接运行 php -m | grep -E '^(openssl|curl)$'。若无输出,说明对应扩展未启用;若只有 curl 没有 openssl,cURL 可能是用系统自带的 NSS 或 GnuTLS 编译的,不支持标准 PEM 证书路径,也无法验证 HTTPS 证书链。
- 确认
extension=openssl在php.ini中未被注释,且extension_dir指向正确的 .so/.dll 路径 - 运行
php -r "print_r(openssl_get_cert_locations());"查看 PHP 认为的默认证书路径 —— 这个路径必须存在且包含有效的 CA bundle(如ca-bundle.crt或ca-certificates.crt) - 如果输出中
default_cert_file是空或指向不存在的文件,后续 HTTPS 请求会因“unable to get local issuer certificate”失败
重新编译 PHP 以链接自建 OpenSSL(非必要勿动)
仅当系统 OpenSSL 版本过旧(如 centos 7 默认 1.0.2)、或需启用 FIPS/国密等特殊特性时,才需手动编译 OpenSSL 并让 PHP 链接它。多数现代发行版(ubuntu 22.04+、CentOS 8+)自带的 OpenSSL 1.1.1+ 已足够安全且兼容 PHP 7.4+ / 8.x。
- 编译 OpenSSL 时加
--prefix=/usr/local/openssl,安装后确保/usr/local/openssl/bin/openssl version可执行 - 编译 PHP 时指定
--with-openssl=/usr/local/openssl,而非--with-openssl-dir(后者已被弃用) - 编译后运行
ldd $(php-config --extension-dir)/openssl.so | grep ssl,确认链接的是你刚装的 OpenSSL 库,而非系统旧版 - 注意:PHP 8.2+ 不再支持 OpenSSL 1.0.x,强行链接会导致启动报错
undefined symbol: OPENSSL_sk_num
正确配置 CA 证书链(最常出问题的环节)
PHP 不读取系统级的 /etc/ssl/certs/ca-certificates.crt(除非你显式设置),也不自动从 curl.cainfo 或 openssl.cafile 加载 —— 它只认自己编译时硬编码的路径,或运行时通过 ini 配置覆盖。
立即学习“PHP免费学习笔记(深入)”;
- 下载最新 Mozilla CA bundle:
curl -o /usr/local/share/ca-bundle.crt https://curl.se/ca/cacert.pem - 在
php.ini中添加两行:openssl.cafile=/usr/local/share/ca-bundle.crtcurl.cainfo=/usr/local/share/ca-bundle.crt - 若使用 composer,还需设置环境变量
export COMPOSER_CAFILE=/usr/local/share/ca-bundle.crt,否则composer install仍可能失败 - 重启 PHP-FPM 或 apache 后,再次运行
php -r "print_r(openssl_get_cert_locations());",确认default_cert_file已更新为你指定的路径
绕过证书验证不是解决方案
设 CURLOPT_SSL_VERIFYPEER => false 或 stream_context_create([... 'verify_peer' => false ...]) 会让 HTTPS 退化为明文 HTTP 级别安全性,且现代 PHP(8.0+)在 CLI 模式下对未验证连接会触发 E_WARNING,某些云环境甚至直接拒绝执行。
- 临时调试可用,但上线前必须移除
- 内网自签证书场景,应把内网 CA 的 PEM 文件追加到你的
ca-bundle.crt末尾,而不是关验证 -
openssl.cafile支持绝对路径,不支持相对路径或 ~ 符号;路径权限需确保 PHP 进程用户(如 www-data)可读
真正卡住人的从来不是“怎么编译”,而是编译完没改 php.ini,或者改了但没重启服务,又或者证书路径写错了一级目录——这些地方一错,file_get_contents('https://api.github.com') 就会静默返回 false,连错误信息都要开 error_reporting(E_ALL) 才看得见。