编程 PHP 8.5 的 cURL 变化:持久 share handle、INFILESIZE_LARGE 与新的 curl_getinfo 字段

2026-09-28 21:03:49

PHP 8.5 的 cURL 变化:持久 share handle、INFILESIZE_LARGE 与新的 curl_getinfo 字段

来源:PHP 8.5 UPGRADING / New Features(php.net/migration85.new-features.php、php-src UPGRADING、PHP 8.5.0 Release Announcement、8.5 release page)。

curl_share_init_persistent():请求结束后不销毁的 share handle

PHP 8.5 新增 curl_share_init_persistent()。它创建的 share handle 不会在 PHP 请求结束时销毁;如果进程中已经存在一套相同 share options 集合的持久 share handle,就会直接复用这一份,避免每次请求重新初始化 cURL handle 的开销,连接复用等也随之受益。这是它与 curl_share_init() 的主要差别——后者按请求创建、请求结束即消失。

$share = curl_share_init_persistent();
curl_share_setopt($share, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
curl_share_setopt($share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT);

$ch = curl_init('https://example.com/api');
curl_setopt($ch, CURLOPT_SHARE, $share);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$body = curl_exec($ch);

RFC:

适用与坑

  • 适合请求密度高、目标是同一批主机的场景:DNS 解析和连接建立的结果可以跨请求留着。
  • 不适合多租户、多账号的场景。share handle 是按 share options 集合复用的,不是一个请求一份;把不同账号、不同租户的请求塞进同一套共享选项里,缓存下来的连接、认证上下文会跟着被复用。
  • 长驻进程(常驻 worker、Swoole / RoadRunner / FrankenPHP 一类)里,这个 handle 的存活期是进程级而不是请求级。不要指望请求边界把它回收掉;需要隔离时就换一套 share options,让它们各自落到不同的持久 handle 上。

curl_getinfo() 新增三个字段

  • CURLINFO_USED_PROXY(需要 libcurl >= 8.7.0):上一次传输没走代理为 0,走了为非零。
  • CURLINFO_HTTPAUTH_USED、CURLINFO_PROXYAUTH_USED(需要 libcurl >= 8.12.0):位掩码,指示上一个请求实际用到的 HTTP 认证 / 代理认证方法,取值对应 CURLAUTH_* 常量。

curl_getinfo() 返回数组时,信息同样以 used_proxy、httpauth_used、proxyauth_used 键提供。

$info = curl_getinfo($ch);
var_dump($info['used_proxy']);     // 0 或非零
var_dump($info['httpauth_used']);  // CURLAUTH_* 位掩码
var_dump($info['proxyauth_used']);

// 也可以单独取
$usedProxy = curl_getinfo($ch, CURLINFO_USED_PROXY);

排代理不生效的问题时,used_proxy 比猜环境变量直观;排查认证方式降级(例如本来想用 Digest 结果走了 Basic)时看 httpauth_used。注意这些值描述的是「上一次传输」,handle 复用时会随之更新,读之前先确认它对应的是哪次请求。另外它们是 libcurl 能力,跑之前用 curl_version() 对一下 libcurl 版本。

CURLOPT_INFILESIZE_LARGE

CURLOPT_INFILESIZE 是 CURLOPT_INFILESIZE_LARGE 的安全替代。在某些系统上,CURLOPT_INFILESIZE 即使在 64 位系统上也只接受 32 位有符号整数,上限 2.0 GiB;CURLOPT_INFILESIZE_LARGE 接受系统能处理的最大整数值。

$path = '/data/big.iso';

curl_setopt($ch, CURLOPT_UPLOAD, true);
curl_setopt($ch, CURLOPT_INFILE, fopen($path, 'rb'));
curl_setopt($ch, CURLOPT_INFILESIZE_LARGE, filesize($path));

上传超过 2 GiB 的文件时换用 LARGE。若跑在 32 位 PHP 上,int 本身仍是 32 位,这个选项解决的是 libcurl 侧的限制,不是 PHP 侧的。

CURLOPT_FOLLOWLOCATION 的 CURLFOLLOW_* 值

curl_easy_setopt 为 CURLOPT_FOLLOWLOCATION 增加了三个取值:

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, CURLFOLLOW_FIRSTONLY);
  • CURLFOLLOW_OBEYCODE:更严格地按重定向是否允许来跟随。
  • CURLFOLLOW_FIRSTONLY:只跟第一个重定向,不再继续。
  • CURLFOLLOW_ALL:等价于把 CURLOPT_FOLLOWLOCATION 设为 true。

抓取里常见的是拿 CURLFOLLOW_FIRSTONLY 观察一跳之后的落点,或在需要逐跳记录时用 CURLFOLLOW_OBEYCODE 收紧跟随条件;只想沿用旧行为就写 CURLFOLLOW_ALL。

PHP 8.5 其他变化

管道操作符 |>、clone with、#[\NoDiscard] 与 (void) 转换、常量表达式里支持闭包 / 一等可调用、常量上的属性、#[\Override] 可用于属性、静态属性非对称可见性、Fatal Error 带 backtrace、final 属性可用构造器提升、array_first() / array_last()、get_error_handler() / get_exception_handler()、URI 扩展、setcookie / setrawcookie 支持 partitioned key、新增 Grapheme / Intl 相关函数。

弃用项:反引号作为 shell_exec() 别名、递增非数字字符串、以分号结束 case 等。

复制全文 生成海报 PHP cURL HTTP客户端 连接复用 接口对接

推荐文章

程序员茄子在线接单