From ba0f9fb501b34e2155e710f05a4bf03bb5f74a80 Mon Sep 17 00:00:00 2001 From: Ayesh Karunaratne Date: Wed, 21 Feb 2024 07:46:22 +0700 Subject: [PATCH] ext/curl: Add `feature_info` assoc array to `curl_version()` (#13439) The `phpinfo()` section of the Curl extension lists individual features supported by the particular ext-Curl + libcurl build. However, the `curl_version()` function return values do not indicate the same level of details. `curl_version()` has a `protocols` key that returns an array of all protocols supported by the build. But the `features` key is a bitmask of all the features. Checking the availability of certain feature requires knowing the corresponding `CURL_VERSION` constant, and checking the availability of the constant and a bitmask check for it in the `features` value. For example, to determine HTTP2 support, it requires evaluating: ```php defined('CURL_VERSION_HTTP2') && (curl_version()['features'] & CURL_VERSION_HTTP2 === CURL_VERSION_HTTP2) ``` To make feature availability checks more intuitive, this adds a new `feature_list` key to `curl_version()` output array. With it, checking for individual features availability is easier, and does not require inspecting the availability of the `CURL_VERSION` constant and the `features` key. ```php !empty(curl_version()['feature_list']['HTTP2']); ``` --- NEWS | 1 + UPGRADING | 3 + ext/curl/interface.c | 63 +++++++++++++++++++ .../tests/curl_version_features-array.phpt | 54 ++++++++++++++++ 4 files changed, 121 insertions(+) create mode 100644 ext/curl/tests/curl_version_features-array.phpt diff --git a/NEWS b/NEWS index f4af9459479a8..c141fbb026b3a 100644 --- a/NEWS +++ b/NEWS @@ -18,6 +18,7 @@ PHP NEWS - Curl: . Deprecated the CURLOPT_BINARYTRANSFER constant. (divinity76) . Bumped required libcurl version to 7.61.0. (Ayesh) + . Added feature_list key to the curl_version() return value (Ayesh) - Date: . Added DateTime[Immutable]::createFromTimestamp. (Marc Bennewitz) diff --git a/UPGRADING b/UPGRADING index 1afaae9701a2f..036a4a9a75e56 100644 --- a/UPGRADING +++ b/UPGRADING @@ -252,6 +252,9 @@ PHP 8.4 UPGRADE NOTES - Curl: . The CURLOPT_BINARYTRANSFER constant is deprecated. + . curl_version() returns an additional feature_list value, which is an + associative array of all known Curl features, and whether they are + supported (true) or not (false). - Date: . Calling DatePeriod::__construct(string $isostr, int $options = 0) is diff --git a/ext/curl/interface.c b/ext/curl/interface.c index a4c8b941adc3b..60481947dddea 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -261,6 +261,7 @@ PHP_MINFO_FUNCTION(curl) php_info_print_table_row(2, "Age", str); /* To update on each new cURL release using src/main.c in cURL sources */ + /* make sure to sync this list with curl_version as well */ if (d->features) { struct feat { const char *name; @@ -1000,6 +1001,68 @@ PHP_FUNCTION(curl_version) CAAL("version_number", d->version_num); CAAL("age", d->age); CAAL("features", d->features); + /* Add an array of features */ + { + struct feat { + const char *name; + int bitmask; + }; + + unsigned int i; + zval feature_list; + array_init(&feature_list); + + /* Sync this list with PHP_MINFO_FUNCTION(curl) as well */ + static const struct feat feats[] = { + {"AsynchDNS", CURL_VERSION_ASYNCHDNS}, + {"CharConv", CURL_VERSION_CONV}, + {"Debug", CURL_VERSION_DEBUG}, + {"GSS-Negotiate", CURL_VERSION_GSSNEGOTIATE}, + {"IDN", CURL_VERSION_IDN}, + {"IPv6", CURL_VERSION_IPV6}, + {"krb4", CURL_VERSION_KERBEROS4}, + {"Largefile", CURL_VERSION_LARGEFILE}, + {"libz", CURL_VERSION_LIBZ}, + {"NTLM", CURL_VERSION_NTLM}, + {"NTLMWB", CURL_VERSION_NTLM_WB}, + {"SPNEGO", CURL_VERSION_SPNEGO}, + {"SSL", CURL_VERSION_SSL}, + {"SSPI", CURL_VERSION_SSPI}, + {"TLS-SRP", CURL_VERSION_TLSAUTH_SRP}, + {"HTTP2", CURL_VERSION_HTTP2}, + {"GSSAPI", CURL_VERSION_GSSAPI}, + {"KERBEROS5", CURL_VERSION_KERBEROS5}, + {"UNIX_SOCKETS", CURL_VERSION_UNIX_SOCKETS}, + {"PSL", CURL_VERSION_PSL}, + {"HTTPS_PROXY", CURL_VERSION_HTTPS_PROXY}, + {"MULTI_SSL", CURL_VERSION_MULTI_SSL}, + {"BROTLI", CURL_VERSION_BROTLI}, +#if LIBCURL_VERSION_NUM >= 0x074001 /* Available since 7.64.1 */ + {"ALTSVC", CURL_VERSION_ALTSVC}, +#endif +#if LIBCURL_VERSION_NUM >= 0x074200 /* Available since 7.66.0 */ + {"HTTP3", CURL_VERSION_HTTP3}, +#endif +#if LIBCURL_VERSION_NUM >= 0x074800 /* Available since 7.72.0 */ + {"UNICODE", CURL_VERSION_UNICODE}, + {"ZSTD", CURL_VERSION_ZSTD}, +#endif +#if LIBCURL_VERSION_NUM >= 0x074a00 /* Available since 7.74.0 */ + {"HSTS", CURL_VERSION_HSTS}, +#endif +#if LIBCURL_VERSION_NUM >= 0x074c00 /* Available since 7.76.0 */ + {"GSASL", CURL_VERSION_GSASL}, +#endif + }; + + for(i = 0; i < sizeof(feats) / sizeof(feats[0]); i++) { + if (feats[i].name) { + add_assoc_bool(&feature_list, feats[i].name, d->features & feats[i].bitmask ? true : false); + } + } + + CAAZ("feature_list", &feature_list); + } CAAL("ssl_version_number", d->ssl_version_num); CAAS("version", d->version); CAAS("host", d->host); diff --git a/ext/curl/tests/curl_version_features-array.phpt b/ext/curl/tests/curl_version_features-array.phpt new file mode 100644 index 0000000000000..b58443a92d834 --- /dev/null +++ b/ext/curl/tests/curl_version_features-array.phpt @@ -0,0 +1,54 @@ +--TEST-- +Test curl_version() - feature_list functionality +--EXTENSIONS-- +curl +--FILE-- + get_debug_type($v), $info_curl['feature_list'])); + + ob_start(); + phpinfo(); + $phpinfo = ob_get_clean(); + + foreach ($info_curl['feature_list'] as $key => $value) { + if (!is_bool($value)) { + throw new Exception('Found non-bool value'); + } + + if (!str_contains($phpinfo, $key .' => ' . $value ? 'Yes' : 'No')) { + throw new Exception($key . ' not found in Curl phpinfo()'); + } + } + + echo "Complete"; +?> +--EXPECTF-- +Array +( + [AsynchDNS] => bool + [CharConv] => bool + [Debug] => bool + [GSS-Negotiate] => bool + [IDN] => bool + [IPv6] => bool + [krb4] => bool + [Largefile] => bool + [libz] => bool + [NTLM] => bool + [NTLMWB] => bool + [SPNEGO] => bool + [SSL] => bool + [SSPI] => bool + [TLS-SRP] => bool + [HTTP2] => bool + [GSSAPI] => bool + [KERBEROS5] => bool + [UNIX_SOCKETS] => bool + [PSL] => bool + [HTTPS_PROXY] => bool + [MULTI_SSL] => bool + [BROTLI] => bool +%A +) +Complete