9、PHP 8.4 新特性 - cURL 扩展 setopt 新增 CURLOPT_PREREQFUNCTION 选项
注意:目前文档还没有更此说明,通过代码追踪可以看到这是 PHP 8.4 新增的。
PHP 8.4 引入了 CURLOPT_PREREQFUNCTION
选项,这是 cURL 扩展中的一个新功能,允许你在请求执行之前调用一个预处理函数。此选项需要使用 libcurl 7.80.0 或更高版本构建的 PHP 8.4 才可用。
CURLOPT_PREREQFUNCTION
回调函数在初始连接建立之后、请求发送之前被调用。例如,在 HTTPS 请求中,该 CURLOPT_PREREQFUNCTION
回调会在 HTTPS 连接(包括 DNS 解析、TCP 连接和 TLS 握手)建立完成但实际的 HTTP 请求发送之前被触发。
这个回调在应用程序需要根据源地址和目标地址的 IP 地址及端口号来判断是否继续处理连接的情况下非常有用。
一些使用场景包括:
- 阻止向内网 IP 地址发起请求。
- 阻止向受制裁国家或网络中的 IP 地址发起请求。
- 仅允许向已知的 IP 地址列表发起请求,即使这些 IP 的域名可能变化。
新增常量
-
CURLOPT_PREREQFUNCTION
:整数 20312,用于curl_setopt
函数的 cURL 选项。通过设置这个选项,你可以指定一个回调函数,该函数将在初始连接建立后但在实际请求发送之前被调用。 -
CURL_PREREQFUNC_OK
:整数 1,这是回调函数的一个可能返回值。如果回调函数返回此值,则表示允许继续处理当前请求。 -
CURL_PREREQFUNC_ABORT
:整数 0,这也是回调函数的一个可能返回值。如果回调函数返回此值,则会中断当前请求,阻止其进一步执行。
CURLOPT_PREREQFUNCTION 选项
CURLOPT_PREREQFUNCTION
选项接受一个可调用对象(例如函数),并且该函数必须返回 CURL_PREREQFUNC_OK
或 CURL_PREREQFUNC_ABORT
来决定是否允许或中止请求。此回调函数在被调用时会接收到几个参数,包括 CurlHandle
对象、目标 IP 地址、源(本地)IP 地址、远程端口号以及源(本地)端口号。
如果连接被重用或者请求跟随了一个 HTTP 重定向,那么这个回调函数可能会被多次调用。
function check_is_not_local_ip_address(
\CurlHandle $ch,
string $destination_ip,
string $local_ip,
int $destination_port,
int $local_port
): int {
$isGlobalIP = filter_var($destination_ip, FILTER_VALIDATE_IP, FILTER_FLAG_GLOBAL_RANGE) !== false;
return $isGlobalIP
? CURL_PREREQFUNC_OK
: CURL_PREREQFUNC_ABORT;
}
$ch = curl_init('https://ziruchu.com');
curl_setopt($ch, CURLOPT_PREREQFUNCTION, 'check_is_not_local_ip_address');
如果 CURLOPT_PREREQFUNCTION
回调函数没有返回任何值,将会抛出一个 TypeError
。
如果 CURLOPT_PREREQFUNCTION
返回了一个既不是 CURL_PREREQFUNC_OK
也不是 CURL_PREREQFUNC_ABORT
的整数值,将会抛出一个 ValueError
。
这两种异常都会携带错误信息:“CURLOPT_PREREQFUNCTION
回调必须返回 CURL_PREREQFUNC_OK
或 CURL_PREREQFUNC_ABORT
”。在这两种情况下,回调都将被中止。
案例
<?php
// 初始化 cURL 会话
$ch = curl_init('https://ziruchu.com');
// 定义预处理函数
function prereq_function($ch) {
// 在这里你可以对请求进行修改或验证
// 比如添加一个自定义的请求头
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Custom-Header: Value']);
// 你可以在这里返回 true 或 false,来决定是否继续请求
// 如果返回 false,cURL 请求将不会被执行
return true;
}
// 设置 CURLOPT_PREREQFUNCTION 选项
curl_setopt($ch, CURLOPT_PREREQFUNCTION, 'prereq_function');
$response = curl_exec($ch);
curl_close($ch);
echo $response;