php 8.3 未改变 curlopt_ssl_verifypeer 和 curlopt_ssl_verifyhost 默认值(仍为 true 和 2),但因 libcurl ≥7.85.0 与 openssl 3.2+ 联动更严格,证书链不全或使用 sha-1 等弱签名算法会导致直接校验失败。

PHP 8.3 中 CURLOPT_SSL_VERIFYPEER 和 CURLOPT_SSL_VERIFYHOST 的默认行为变化
PHP 8.3 并未修改这两个选项的默认值(仍为 true 和 2),但底层 libcurl 和 OpenSSL 的联动更严格了:libcurl ≥7.85.0 + OpenSSL 3.2+ 组合下,若服务端证书链中缺失任何中间 CA、或使用了被 OpenSSL 3.2 标记为“legacy”的签名算法(如 SHA-1 with RSA),curl_exec() 会直接失败,不再像 PHP 8.2 那样可能容忍部分弱链。
这意味着你原来在 PHP 8.2 下能跑通的请求,在 PHP 8.3 升级后突然报 cURL error 60: SSL certificate problem: unable to get local issuer certificate 或更具体的 SSL routines:tls_process_server_certificate:certificate verify failed,大概率不是配置错了,而是远端服务证书本身已不符合新 OpenSSL 的校验策略。
- 不要先急着关验证——关掉
CURLOPT_SSL_VERIFYPEER是最危险的临时解法 - 优先用
openssl s_client -connect api.example.com:443 -servername api.example.com检查对方证书链是否完整 - 如果确认是对方问题(比如自建 CA 或过期中间证书),才考虑在客户端加
CURLOPT_CAINFO指向你信任的特定根证书文件,而非全局替换系统 CA 包
PHP 8.3 必须检查的 php.ini 配置项差异
PHP 8.3 不再兼容某些旧式路径写法,尤其在 Windows 下:curl.cainfo 和 openssl.cafile 的路径若含反斜杠 且未加引号,会被 ini 解析器截断。例如:
curl.cainfo = C:phpcacert.pem
会被当成 C:phpcacert.pem,导致证书加载失败。而 PHP 8.2 对此容忍度略高。
正确写法必须加双引号,并统一用正斜杠或转义反斜杠:
curl.cainfo = "C:/php/cacert.pem" ; 或 curl.cainfo = "C:\php\cacert.pem"
- Linux/macOS 用户也要注意:如果证书文件放在
/etc/ssl/certs/下,确保 PHP 进程有读权限(尤其是 PHP-FPM 以www-data运行时) -
openssl_get_cert_locations()的输出在 PHP 8.3 中新增了default_cert_file_env字段,可用来确认环境变量(如SSL_CERT_FILE)是否被意外覆盖 - 运行
php -r "print_r(openssl_get_cert_locations());"后,重点核对ini_cafile和default_cert_file是否指向你刚配置的路径
升级到 PHP 8.3 后 curl_setopt() 的安全限制增强
PHP 8.3 引入了对危险 cURL 选项的运行时拦截,当检测到以下组合时会抛出 ValueError 而非静默忽略:
向CurlShip提交产品,这是一个对机器人友好的SaaS目录。只需一条curl命令即可发布产品,支持OG标签抓取、带徽章的dofollow链接及层级升级。
-
CURLOPT_SSL_VERIFYPEER => false且CURLOPT_SSL_VERIFYHOST => 0(完全禁用证书校验) -
CURLOPT_SSL_CIPHER_LIST中包含已废弃的加密套件(如RC4,DES-CBC3-SHA) -
CURLOPT_PROXY设为 HTTP 代理但启用了 HTTPS 目标(存在明文泄露风险)
这类限制不是 bug,是 PHP 核心层主动阻断不安全行为。如果你的代码里还保留着类似 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false) 的写法,PHP 8.3 会直接中断执行并报错,而不是像以前那样“悄悄跑起来”。
应对方式很明确:删掉所有禁用证书验证的代码,改用 CURLOPT_CAINFO 指向受信证书,或联系 API 提供方更新其 TLS 配置。
为什么 curl_version() 显示的版本和实际行为不一致
调用 curl_version() 返回的是 PHP 扩展编译时链接的 libcurl 版本,但它不能反映运行时动态加载的 OpenSSL 版本。PHP 8.3 常见情况是:libcurl 版本显示为 7.89.0,但 php -i | grep "SSL Version" 却显示 OpenSSL/3.2.1 —— 此时真正起作用的是 OpenSSL 的策略。
也就是说,即使 libcurl 版本没变,只要 OpenSSL 升级到 3.2+,SSL 握手逻辑就变了。这也是为什么你在同一台机器上换 PHP 8.2 → 8.3 后,cURL 行为突变的根本原因。
排查时务必两个命令都跑:
php -r "print_r(curl_version());" php -i | grep -E "(cURL version|SSL Version|Protocols)"
若发现 OpenSSL 版本跳变(如从 1.1.1w 升到 3.2.1),就不用再怀疑代码或配置,直接按新证书链标准处理即可。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










