diff --git a/NEWS b/NEWS index 0f3ba67434dc..96895dc4a4bc 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,10 @@ PHP NEWS . Changed run-tests.php to run test subprocesses without a shell where possible. (NickSdot) +- Curl: + . Raise a value error when the callback registered with CURLOPT_READFUNCTION + returns an unexpected long. (Sjoerd Langkemper) + - Date: . Update timelib to 2026.01. (Derick, timwolla) diff --git a/UPGRADING b/UPGRADING index ced365480707..453bae75701b 100644 --- a/UPGRADING +++ b/UPGRADING @@ -24,6 +24,11 @@ PHP 8.6 UPGRADE NOTES has materialised the property by writing into the property table. The freshly-written value is returned directly. isset() is unaffected. +- Curl: + . The callback registered with CURLOPT_READFUNCTION now throws a ValueError + when returning an integer other than 0, CURL_READFUNC_ABORT or + CURL_READFUNC_PAUSE. + - COM . It is no longer possible to clone variant objects, this is because the cloning behaviour was ill defined. @@ -602,6 +607,7 @@ PHP 8.6 UPGRADE NOTES . CURL_SEEKFUNC_OK. . CURL_SEEKFUNC_FAIL. . CURL_SEEKFUNC_CANTSEEK. + . CURL_READFUNC_ABORT. - OpenSSL: . OPENSSL_RSA_PSS_SALTLEN_DIGEST. diff --git a/ext/curl/curl.stub.php b/ext/curl/curl.stub.php index 70e87cc9b146..6953f0e97cbc 100644 --- a/ext/curl/curl.stub.php +++ b/ext/curl/curl.stub.php @@ -1788,6 +1788,11 @@ * @cvalue CURLPAUSE_SEND_CONT */ const CURLPAUSE_SEND_CONT = UNKNOWN; +/** + * @var int + * @cvalue CURL_READFUNC_ABORT + */ +const CURL_READFUNC_ABORT = UNKNOWN; /** * @var int * @cvalue CURL_READFUNC_PAUSE diff --git a/ext/curl/curl_arginfo.h b/ext/curl/curl_arginfo.h index f2929f60c4e2..ea354d16df56 100644 --- a/ext/curl/curl_arginfo.h +++ b/ext/curl/curl_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit curl.stub.php instead. - * Stub hash: d55adb230c533f4dde05e95759477dd9e1dd6efb */ + * Stub hash: 5da31d6790f9db408cac4aed3f81f7affb2849a6 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_curl_close, 0, 1, IS_VOID, 0) ZEND_ARG_OBJ_INFO(0, handle, CurlHandle, 0) @@ -574,6 +574,7 @@ static void register_curl_symbols(int module_number) REGISTER_LONG_CONSTANT("CURLPAUSE_RECV_CONT", CURLPAUSE_RECV_CONT, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CURLPAUSE_SEND", CURLPAUSE_SEND, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CURLPAUSE_SEND_CONT", CURLPAUSE_SEND_CONT, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("CURL_READFUNC_ABORT", CURL_READFUNC_ABORT, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CURL_READFUNC_PAUSE", CURL_READFUNC_PAUSE, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CURL_SEEKFUNC_OK", CURL_SEEKFUNC_OK, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CURL_SEEKFUNC_FAIL", CURL_SEEKFUNC_FAIL, CONST_PERSISTENT); diff --git a/ext/curl/interface.c b/ext/curl/interface.c index 07e53dfe0f9f..6df7cf66fbe7 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -819,7 +819,13 @@ static size_t curl_read(char *data, size_t size, size_t nmemb, void *ctx) length = MIN(nmemb, Z_STRLEN(retval)); memcpy(data, Z_STRVAL(retval), length); } else if (Z_TYPE(retval) == IS_LONG) { - length = Z_LVAL_P(&retval); + zend_long long_rv = Z_LVAL_P(&retval); + if (long_rv == 0 || long_rv == CURL_READFUNC_ABORT || long_rv == CURL_READFUNC_PAUSE) { + length = (size_t) long_rv; + } else { + zend_value_error("The CURLOPT_READFUNCTION callback must return a string or CURL_READFUNC_ABORT or CURL_READFUNC_PAUSE"); + length = CURL_READFUNC_ABORT; + } } // TODO Do type error if invalid type? zval_ptr_dtor(&retval); diff --git a/ext/curl/tests/curl_read_function_error_on_int.phpt b/ext/curl/tests/curl_read_function_error_on_int.phpt new file mode 100644 index 000000000000..30ba97737727 --- /dev/null +++ b/ext/curl/tests/curl_read_function_error_on_int.phpt @@ -0,0 +1,30 @@ +--TEST-- +error when CURLOPT_READFUNCTION returns an integer +--EXTENSIONS-- +curl +--FILE-- + 'f']); +curl_setopt($ch, CURLOPT_TIMEOUT, 2); +curl_setopt($ch, CURLOPT_READFUNCTION, "custom_readfunction" ); + +try { + curl_exec($ch); +} catch (ValueError $e) { + echo $e->getMessage() . "\n"; +} +var_dump(curl_error($ch)); +?> +--EXPECT-- +The CURLOPT_READFUNCTION callback must return a string or CURL_READFUNC_ABORT or CURL_READFUNC_PAUSE +string(29) "operation aborted by callback" diff --git a/ext/curl/tests/curl_readfunc_abort.phpt b/ext/curl/tests/curl_readfunc_abort.phpt new file mode 100644 index 000000000000..39103904fdc5 --- /dev/null +++ b/ext/curl/tests/curl_readfunc_abort.phpt @@ -0,0 +1,21 @@ +--TEST-- +Returning CURL_READFUNC_ABORT aborts the transfer +--EXTENSIONS-- +curl +--FILE-- + +--EXPECT-- +No output expected, because transfer was aborted by read function.