Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

CURLOPT_READFUNCTION Callback Validates Its Return Value

A CURLOPT_READFUNCTION callback is expected to return the chunk of data to upload, the empty string, CURL_READFUNC_ABORT, or CURL_READFUNC_PAUSE. Until PHP 8.6, an invalid return value, such as an arbitrary integer, was passed straight to libcurl, which simply aborted the transfer without any diagnostic from PHP. In PHP 8.6, curl_exec() throws a ValueError when the callback returns something other than a string, CURL_READFUNC_ABORT, or CURL_READFUNC_PAUSE.

PHP code

<?php

$docroot = sys_get_temp_dir() . '/curlrf' . getmypid();
mkdir($docroot);
file_put_contents($docroot . '/upload.php', '<?php echo "ok";');

$port = 8391;
$server = proc_open(
    PHP_BINARY . ' -S 127.0.0.1:' . $port . ' -t ' . escapeshellarg($docroot),
    [1 => ['pipe', 'w'], 2 => ['pipe', 'w']],
    $pipes
);
usleep(500000);

$ch = curl_init('http://127.0.0.1:' . $port . '/upload.php');
curl_setopt($ch, CURLOPT_UPLOAD, true);
curl_setopt($ch, CURLOPT_INFILESIZE, 5);
curl_setopt($ch, CURLOPT_READFUNCTION, function ($ch, $fh, $length) {
    return 999;
});
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);

try {
    $result = curl_exec($ch);
    var_dump($result);
} catch (\ValueError $e) {
    echo $e->getMessage(), "\n";
}

proc_terminate($server);
proc_close($server);
unlink($docroot . '/upload.php');
rmdir($docroot);

?>

Before

bool(false)

After

The CURLOPT_READFUNCTION callback must return a string or CURL_READFUNC_ABORT or CURL_READFUNC_PAUSE

PHP version change

This behavior changed in 8.6.

See Also

Error Messages

Extension

© 2023-2026, Damien Seguy - Exakat