Skip to content

Commit 6a4ab2e

Browse files
authored
ext/curl: show curl option name in error message (#22908)
1 parent 5d58876 commit 6a4ab2e

4 files changed

Lines changed: 52 additions & 46 deletions

File tree

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ PHP NEWS
77
possible. (NickSdot)
88

99
- Curl:
10+
. Improved cURL option validation errors to include the option name.
11+
(Sjoerd Langkemper)
1012
. Raise a value error when the callback registered with CURLOPT_READFUNCTION
1113
returns an unexpected long. (Sjoerd Langkemper)
1214

ext/curl/interface.c

Lines changed: 35 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,39 @@ ZEND_DECLARE_MODULE_GLOBALS(curl)
6262
# define php_curl_ret(__ret) RETVAL_FALSE; return;
6363
#endif
6464

65+
// php_curl_option_get_name(CURLOPT_HTTPHEADER) -> "HTTPHEADER"
66+
static const char * php_curl_option_get_name(zend_long option) {
67+
68+
#if LIBCURL_VERSION_NUM >= 0x074900
69+
const struct curl_easyoption * opt = curl_easy_option_by_id(option);
70+
if (EXPECTED(opt != NULL)) {
71+
return opt->name;
72+
}
73+
#endif
74+
75+
const char prefix[] = "CURLOPT_";
76+
const size_t prefix_len = sizeof(prefix) - 1;
77+
zend_string *key;
78+
zend_constant *constant;
79+
80+
ZEND_HASH_FOREACH_STR_KEY_PTR(EG(zend_constants), key, constant) {
81+
if (!key
82+
|| Z_TYPE(constant->value) != IS_LONG
83+
|| strncmp(ZSTR_VAL(key), prefix, prefix_len) != 0) {
84+
continue;
85+
}
86+
87+
if (Z_LVAL(constant->value) == option) {
88+
return ZSTR_VAL(key) + prefix_len;
89+
}
90+
} ZEND_HASH_FOREACH_END();
91+
return "UNKNOWN_OPTION";
92+
}
93+
6594
static zend_result php_curl_option_str(php_curl *ch, zend_long option, const char *str, const size_t len)
6695
{
6796
if (zend_char_has_nul_byte(str, len)) {
68-
zend_value_error("%s(): cURL option must not contain any null bytes", get_active_function_name());
97+
zend_value_error("%s(): cURL option CURLOPT_%s must not contain any null bytes", get_active_function_name(), php_curl_option_get_name(option));
6998
return FAILURE;
7099
}
71100

@@ -2017,7 +2046,7 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue
20172046
ch->handlers.write->method = PHP_CURL_FILE;
20182047
ZVAL_COPY(&ch->handlers.write->stream, zvalue);
20192048
} else {
2020-
zend_value_error("%s(): The provided file handle must be writable", get_active_function_name());
2049+
zend_value_error("%s(): The file handle provided for CURLOPT_FILE must be writable", get_active_function_name());
20212050
return FAILURE;
20222051
}
20232052
break;
@@ -2035,7 +2064,7 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue
20352064
ch->handlers.write_header->method = PHP_CURL_FILE;
20362065
ZVAL_COPY(&ch->handlers.write_header->stream, zvalue);
20372066
} else {
2038-
zend_value_error("%s(): The provided file handle must be writable", get_active_function_name());
2067+
zend_value_error("%s(): The file handle provided for CURLOPT_WRITEHEADER must be writable", get_active_function_name());
20392068
return FAILURE;
20402069
}
20412070
break;
@@ -2064,7 +2093,7 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue
20642093
zval_ptr_dtor(&ch->handlers.std_err);
20652094
ZVAL_COPY(&ch->handlers.std_err, zvalue);
20662095
} else {
2067-
zend_value_error("%s(): The provided file handle must be writable", get_active_function_name());
2096+
zend_value_error("%s(): The file handle provided for CURLOPT_STDERR must be writable", get_active_function_name());
20682097
return FAILURE;
20692098
}
20702099
ZEND_FALLTHROUGH;
@@ -2091,43 +2120,9 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue
20912120
HashTable *ph;
20922121
zend_string *val, *tmp_val;
20932122
struct curl_slist *slist = NULL;
2094-
const char *name = NULL;
2095-
2096-
switch (option) {
2097-
case CURLOPT_HTTPHEADER:
2098-
name = "CURLOPT_HTTPHEADER";
2099-
break;
2100-
case CURLOPT_QUOTE:
2101-
name = "CURLOPT_QUOTE";
2102-
break;
2103-
case CURLOPT_HTTP200ALIASES:
2104-
name = "CURLOPT_HTTP200ALIASES";
2105-
break;
2106-
case CURLOPT_POSTQUOTE:
2107-
name = "CURLOPT_POSTQUOTE";
2108-
break;
2109-
case CURLOPT_PREQUOTE:
2110-
name = "CURLOPT_PREQUOTE";
2111-
break;
2112-
case CURLOPT_TELNETOPTIONS:
2113-
name = "CURLOPT_TELNETOPTIONS";
2114-
break;
2115-
case CURLOPT_MAIL_RCPT:
2116-
name = "CURLOPT_MAIL_RCPT";
2117-
break;
2118-
case CURLOPT_RESOLVE:
2119-
name = "CURLOPT_RESOLVE";
2120-
break;
2121-
case CURLOPT_PROXYHEADER:
2122-
name = "CURLOPT_PROXYHEADER";
2123-
break;
2124-
case CURLOPT_CONNECT_TO:
2125-
name = "CURLOPT_CONNECT_TO";
2126-
break;
2127-
}
21282123

21292124
if (Z_TYPE_P(zvalue) != IS_ARRAY) {
2130-
zend_type_error("%s(): The %s option must have an array value", get_active_function_name(), name);
2125+
zend_type_error("%s(): The CURLOPT_%s option must have an array value", get_active_function_name(), php_curl_option_get_name(option));
21312126
return FAILURE;
21322127
}
21332128

@@ -2139,7 +2134,7 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue
21392134
if (zend_str_has_nul_byte(val)) {
21402135
curl_slist_free_all(slist);
21412136
zend_tmp_string_release(tmp_val);
2142-
zend_value_error("%s(): cURL option %s must not contain any null bytes", get_active_function_name(), name);
2137+
zend_value_error("%s(): cURL option CURLOPT_%s must not contain any null bytes", get_active_function_name(), php_curl_option_get_name(option));
21432138
return FAILURE;
21442139
}
21452140

ext/curl/tests/bug48207.phpt

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,26 @@ $tempfile = tempnam(sys_get_temp_dir(), 'CURL_FILE_HANDLE');
3636
$fp = fopen($tempfile, "r"); // Opening 'fubar' with the incorrect readonly flag
3737

3838
$ch = curl_init($url);
39-
try {
40-
curl_setopt($ch, CURLOPT_FILE, $fp);
41-
} catch (ValueError $exception) {
42-
echo $exception->getMessage() . "\n";
39+
40+
foreach ([
41+
CURLOPT_FILE,
42+
CURLOPT_WRITEHEADER,
43+
CURLOPT_STDERR,
44+
] as $option) {
45+
try {
46+
curl_setopt($ch, $option, $fp);
47+
} catch (ValueError $exception) {
48+
echo $exception->getMessage(), "\n";
49+
}
4350
}
4451

4552
curl_exec($ch);
4653
is_file($tempfile) and @unlink($tempfile);
4754
isset($tempname) and is_file($tempname) and @unlink($tempname);
4855
?>
4956
--EXPECT--
50-
curl_setopt(): The provided file handle must be writable
57+
curl_setopt(): The file handle provided for CURLOPT_FILE must be writable
58+
curl_setopt(): The file handle provided for CURLOPT_WRITEHEADER must be writable
59+
curl_setopt(): The file handle provided for CURLOPT_STDERR must be writable
5160
Hello World!
5261
Hello World!

ext/curl/tests/bug68089.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@ try {
1616
?>
1717
Done
1818
--EXPECT--
19-
curl_setopt(): cURL option must not contain any null bytes
19+
curl_setopt(): cURL option CURLOPT_URL must not contain any null bytes
2020
Done

0 commit comments

Comments
 (0)