[PHP-CVS] [php-src] master: ext/curl: show curl option name in error message (#22908)
[email protected] (Sjoerd Langkemper via GitHub)
| Newsgroups | php.cvs |
|---|---|
| Message-ID | <[email protected]> |
Author: Sjoerd Langkemper (Sjord)
Committer: GitHub (web-flow)
Pusher: arnaud-lb
Date: 2026-08-06T13:10:54+02:00
Commit: https://github.com/php/php-src/commit/6a4ab2ed305aaba30f76bcd3a531c33972546304
Raw diff: https://github.com/php/php-src/commit/6a4ab2ed305aaba30f76bcd3a531c33972546304.diff
ext/curl: show curl option name in error message (#22908)
Changed paths:
M NEWS
M ext/curl/interface.c
M ext/curl/tests/bug48207.phpt
M ext/curl/tests/bug68089.phpt
Diff:
diff --git a/NEWS b/NEWS
index 96895dc4a4bc..fd4d58dd3c20 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,8 @@ PHP NEWS
possible. (NickSdot)
- Curl:
+ . Improved cURL option validation errors to include the option name.
+ (Sjoerd Langkemper)
. Raise a value error when the callback registered with CURLOPT_READFUNCTION
returns an unexpected long. (Sjoerd Langkemper)
diff --git a/ext/curl/interface.c b/ext/curl/interface.c
index 6df7cf66fbe7..8c6d6a0c1f20 100644
--- a/ext/curl/interface.c
+++ b/ext/curl/interface.c
@@ -62,10 +62,39 @@ ZEND_DECLARE_MODULE_GLOBALS(curl)
# define php_curl_ret(__ret) RETVAL_FALSE; return;
#endif
+// php_curl_option_get_name(CURLOPT_HTTPHEADER) -> "HTTPHEADER"
+static const char * php_curl_option_get_name(zend_long option) {
+
+#if LIBCURL_VERSION_NUM >= 0x074900
+ const struct curl_easyoption * opt = curl_easy_option_by_id(option);
+ if (EXPECTED(opt != NULL)) {
+ return opt->name;
+ }
+#endif
+
+ const char prefix[] = "CURLOPT_";
+ const size_t prefix_len = sizeof(prefix) - 1;
+ zend_string *key;
+ zend_constant *constant;
+
+ ZEND_HASH_FOREACH_STR_KEY_PTR(EG(zend_constants), key, constant) {
+ if (!key
+ || Z_TYPE(constant->value) != IS_LONG
+ || strncmp(ZSTR_VAL(key), prefix, prefix_len) != 0) {
+ continue;
+ }
+
+ if (Z_LVAL(constant->value) == option) {
+ return ZSTR_VAL(key) + prefix_len;
+ }
+ } ZEND_HASH_FOREACH_END();
+ return "UNKNOWN_OPTION";
+}
+
static zend_result php_curl_option_str(php_curl *ch, zend_long option, const char *str, const size_t len)
{
if (zend_char_has_nul_byte(str, len)) {
- zend_value_error("%s(): cURL option must not contain any null bytes", get_active_function_name());
+ zend_value_error("%s(): cURL option CURLOPT_%s must not contain any null bytes", get_active_function_name(), php_curl_option_get_name(option));
return FAILURE;
}
@@ -2017,7 +2046,7 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue
ch->handlers.write->method = PHP_CURL_FILE;
ZVAL_COPY(&ch->handlers.write->stream, zvalue);
} else {
- zend_value_error("%s(): The provided file handle must be writable", get_active_function_name());
+ zend_value_error("%s(): The file handle provided for CURLOPT_FILE must be writable", get_active_function_name());
return FAILURE;
}
break;
@@ -2035,7 +2064,7 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue
ch->handlers.write_header->method = PHP_CURL_FILE;
ZVAL_COPY(&ch->handlers.write_header->stream, zvalue);
} else {
- zend_value_error("%s(): The provided file handle must be writable", get_active_function_name());
+ zend_value_error("%s(): The file handle provided for CURLOPT_WRITEHEADER must be writable", get_active_function_name());
return FAILURE;
}
break;
@@ -2064,7 +2093,7 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue
zval_ptr_dtor(&ch->handlers.std_err);
ZVAL_COPY(&ch->handlers.std_err, zvalue);
} else {
- zend_value_error("%s(): The provided file handle must be writable", get_active_function_name());
+ zend_value_error("%s(): The file handle provided for CURLOPT_STDERR must be writable", get_active_function_name());
return FAILURE;
}
ZEND_FALLTHROUGH;
@@ -2091,43 +2120,9 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue
HashTable *ph;
zend_string *val, *tmp_val;
struct curl_slist *slist = NULL;
- const char *name = NULL;
-
- switch (option) {
- case CURLOPT_HTTPHEADER:
- name = "CURLOPT_HTTPHEADER";
- break;
- case CURLOPT_QUOTE:
- name = "CURLOPT_QUOTE";
- break;
- case CURLOPT_HTTP200ALIASES:
- name = "CURLOPT_HTTP200ALIASES";
- break;
- case CURLOPT_POSTQUOTE:
- name = "CURLOPT_POSTQUOTE";
- break;
- case CURLOPT_PREQUOTE:
- name = "CURLOPT_PREQUOTE";
- break;
- case CURLOPT_TELNETOPTIONS:
- name = "CURLOPT_TELNETOPTIONS";
- break;
- case CURLOPT_MAIL_RCPT:
- name = "CURLOPT_MAIL_RCPT";
- break;
- case CURLOPT_RESOLVE:
- name = "CURLOPT_RESOLVE";
- break;
- case CURLOPT_PROXYHEADER:
- name = "CURLOPT_PROXYHEADER";
- break;
- case CURLOPT_CONNECT_TO:
- name = "CURLOPT_CONNECT_TO";
- break;
- }
if (Z_TYPE_P(zvalue) != IS_ARRAY) {
- zend_type_error("%s(): The %s option must have an array value", get_active_function_name(), name);
+ zend_type_error("%s(): The CURLOPT_%s option must have an array value", get_active_function_name(), php_curl_option_get_name(option));
return FAILURE;
}
@@ -2139,7 +2134,7 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue
if (zend_str_has_nul_byte(val)) {
curl_slist_free_all(slist);
zend_tmp_string_release(tmp_val);
- zend_value_error("%s(): cURL option %s must not contain any null bytes", get_active_function_name(), name);
+ zend_value_error("%s(): cURL option CURLOPT_%s must not contain any null bytes", get_active_function_name(), php_curl_option_get_name(option));
return FAILURE;
}
diff --git a/ext/curl/tests/bug48207.phpt b/ext/curl/tests/bug48207.phpt
index 086f949ff63d..6487076e9ee3 100644
--- a/ext/curl/tests/bug48207.phpt
+++ b/ext/curl/tests/bug48207.phpt
@@ -36,10 +36,17 @@ $tempfile = tempnam(sys_get_temp_dir(), 'CURL_FILE_HANDLE');
$fp = fopen($tempfile, "r"); // Opening 'fubar' with the incorrect readonly flag
$ch = curl_init($url);
-try {
- curl_setopt($ch, CURLOPT_FILE, $fp);
-} catch (ValueError $exception) {
- echo $exception->getMessage() . "\n";
+
+foreach ([
+ CURLOPT_FILE,
+ CURLOPT_WRITEHEADER,
+ CURLOPT_STDERR,
+] as $option) {
+ try {
+ curl_setopt($ch, $option, $fp);
+ } catch (ValueError $exception) {
+ echo $exception->getMessage(), "\n";
+ }
}
curl_exec($ch);
@@ -47,6 +54,8 @@ is_file($tempfile) and @unlink($tempfile);
isset($tempname) and is_file($tempname) and @unlink($tempname);
?>
--EXPECT--
-curl_setopt(): The provided file handle must be writable
+curl_setopt(): The file handle provided for CURLOPT_FILE must be writable
+curl_setopt(): The file handle provided for CURLOPT_WRITEHEADER must be writable
+curl_setopt(): The file handle provided for CURLOPT_STDERR must be writable
Hello World!
Hello World!
diff --git a/ext/curl/tests/bug68089.phpt b/ext/curl/tests/bug68089.phpt
index b8733c5066b8..c175df5248fe 100644
--- a/ext/curl/tests/bug68089.phpt
+++ b/ext/curl/tests/bug68089.phpt
@@ -16,5 +16,5 @@ try {
?>
Done
--EXPECT--
-curl_setopt(): cURL option must not contain any null bytes
+curl_setopt(): cURL option CURLOPT_URL must not contain any null bytes
Done