PHP 8.4: Curl: New CURLOPT_PREREQFUNCTION option

Version8.4
TypeNew Feature

The Curl extension in PHP 8.4 introduces a new option named CURLOPT_PREREQFUNCTION that allows setting a custom callable to decide if the request should be continued or aborted. This feature is available if the extension is built with libcurl 7.80.0 or later.

The CURLOPT_PREREQFUNCTION callback is called after the initial connection is established, and before the request is sent. For example in an HTTPS request, the CURLOPT_PREREQFUNCTION callback is called after the HTTPS connection (DNS + TCP + TLS) is established, before the actual HTTP request is sent.

This callback can be useful in situations where the application needs to determine if the connection should be processed depending on the IP address and the port of both source and destination.

Some of the use cases include:

  • Block making requests to intranet IP addresses
  • Block making requests to IP addresses belonging to sanctioned countries or networks
  • Only allowing requests to a known list of IP addresses, but when the DNS addresses can vary.

New constants

This feature adds three new constants:

CURLOPT_PREREQFUNCTION Curl Option

CURLOPT_PREREQFUNCTION option accepts a callable, and it must return CURL_PREREQFUNC_OK or CURL_PREREQFUNC_ABORT to allow or abort the request.

The callable is called with the CurlHandle object, destination IP address, source (local) IP address, remote port number, and source (local) port number.

If the connection is reused or the request follows an HTTP redirect, it is possible for the callback to get called multiple times.

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://php.watch');
curl_setopt($ch, CURLOPT_PREREQFUNCTION, 'check_is_not_local_ip_address');
  • If the CURLOPT_PREREQFUNCTION callback does not return any value, a TypeError is thrown.
  • If the CURLOPT_PREREQFUNCTION returns an int value other than CURL_PREREQFUNC_OK or CURL_PREREQFUNC_ABORT, a ValueError is thrown.

Both of the exceptions carry The CURLOPT_PREREQFUNCTION callback must return either CURL_PREREQFUNC_OK or CURL_PREREQFUNC_ABORT as the error message. In both situations, the callback gets aborted.


If a Curl request is aborted by the CURLOPT_PREREQFUNCTION callable, the Curl request fails with CURLE_ABORTED_BY_CALLBACK error:

$ch = curl_init('https://php.watch');
curl_setopt($ch, CURLOPT_PREREQFUNCTION, static fn($x): int => CURL_PREREQFUNC_ABORT);
curl_exec($ch);

echo curl_error($ch); // "operation aborted by pre-request callback"
echo curl_errno($ch); // CURLE_ABORTED_BY_CALLBACK (int 42)

Once the callback is set, it can be removed by setting it to null:

curl_setopt($ch, CURLOPT_PREREQFUNCTION, null);

Backward Compatibility Impact

CURLOPT_PREREQFUNCTION, CURL_PREREQFUNC_OK, and CURL_PREREQFUNC_ABORT are new global PHP constants. Because this feature requires internal handling at the PHP Curl extension level, it is not possible to backport this feature to older PHP versions.


CURLOPT_PREREQFUNCTION Implementation