diff --git a/ext/filter/logical_filters.c b/ext/filter/logical_filters.c index 0dd307122345c..a8f34e0e8e35a 100644 --- a/ext/filter/logical_filters.c +++ b/ext/filter/logical_filters.c @@ -20,6 +20,7 @@ #include "filter_private.h" #include "ext/standard/url.h" #include "ext/pcre/php_pcre.h" +#include "ext/uri/php_uri.h" #include "zend_multiply.h" @@ -89,6 +90,8 @@ #define FORMAT_IPV4 4 #define FORMAT_IPV6 6 +#define URL_OPTION_URI_PARSER_CLASS "uri_parser_class" + static bool _php_filter_validate_ipv6(const char *str, size_t str_len, int ip[8]); static bool php_filter_parse_int(const char *str, size_t str_len, zend_long *ret) { /* {{{ */ @@ -591,7 +594,6 @@ static bool php_filter_is_valid_ipv6_hostname(const zend_string *s) void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ { - php_url *url; size_t old_len = Z_STRLEN_P(value); php_filter_url(value, flags, option_array, charset); @@ -600,52 +602,66 @@ void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ RETURN_VALIDATION_FAILED } - /* Use parse_url - if it returns false, we return NULL */ - url = php_url_parse_ex(Z_STRVAL_P(value), Z_STRLEN_P(value)); + /* Parse options */ + zval *option_val; + zend_string *parser_name; + int parser_name_set; + FETCH_STR_OPTION(parser_name, URL_OPTION_URI_PARSER_CLASS); + + uri_handler_t *uri_handler = php_uri_get_handler(parser_name_set ? parser_name : NULL); + if (uri_handler == NULL) { + zend_throw_error(NULL, "Invalid URI parser used"); + RETURN_VALIDATION_FAILED + } - if (url == NULL) { + /* Parse the URI - if it fails, we return NULL */ + php_uri *uri = php_uri_parse_to_struct(uri_handler, Z_STRVAL_P(value), Z_STRLEN_P(value), URI_COMPONENT_READ_NORMALIZED_ASCII, true); + if (uri == NULL) { RETURN_VALIDATION_FAILED } - if (url->scheme != NULL && - (zend_string_equals_literal_ci(url->scheme, "http") || zend_string_equals_literal_ci(url->scheme, "https"))) { + if (uri->scheme != NULL && + (zend_string_equals_literal_ci(uri->scheme, "http") || zend_string_equals_literal_ci(uri->scheme, "https"))) { - if (url->host == NULL) { - goto bad_url; + if (uri->host == NULL) { + php_uri_struct_free(uri); + RETURN_VALIDATION_FAILED } if ( + /* Skipping these checks is possible because the new URI implementations perform comprehensive validations. */ + strcmp(uri_handler->name, URI_PARSER_PHP) == 0 && /* An IPv6 enclosed by square brackets is a valid hostname.*/ - !php_filter_is_valid_ipv6_hostname(url->host) && + !php_filter_is_valid_ipv6_hostname(uri->host) && /* Validate domain. * This includes a loose check for an IPv4 address. */ - !php_filter_validate_domain_ex(url->host, FILTER_FLAG_HOSTNAME) + !php_filter_validate_domain_ex(uri->host, FILTER_FLAG_HOSTNAME) ) { - php_url_free(url); + php_uri_struct_free(uri); RETURN_VALIDATION_FAILED } } - if ( - url->scheme == NULL || - /* some schemas allow the host to be empty */ - (url->host == NULL && (!zend_string_equals_literal(url->scheme, "mailto") && !zend_string_equals_literal(url->scheme, "news") && !zend_string_equals_literal(url->scheme, "file"))) || - ((flags & FILTER_FLAG_PATH_REQUIRED) && url->path == NULL) || ((flags & FILTER_FLAG_QUERY_REQUIRED) && url->query == NULL) + if (uri->scheme == NULL || + /* some schemes allow the host to be empty */ + (uri->host == NULL && (!zend_string_equals_literal(uri->scheme, "mailto") && !zend_string_equals_literal(uri->scheme, "news") && !zend_string_equals_literal(uri->scheme, "file"))) || + ((flags & FILTER_FLAG_PATH_REQUIRED) && uri->path == NULL) || ((flags & FILTER_FLAG_QUERY_REQUIRED) && uri->query == NULL) ) { -bad_url: - php_url_free(url); + php_uri_struct_free(uri); RETURN_VALIDATION_FAILED } - if ((url->user != NULL && !is_userinfo_valid(url->user)) - || (url->pass != NULL && !is_userinfo_valid(url->pass)) + if (strcmp(uri_handler->name, URI_PARSER_PHP) == 0 && + ( + (uri->user != NULL && !is_userinfo_valid(uri->user)) || + (uri->password != NULL && !is_userinfo_valid(uri->password)) + ) ) { - php_url_free(url); + php_uri_struct_free(uri); RETURN_VALIDATION_FAILED - } - php_url_free(url); + php_uri_struct_free(uri); } /* }}} */ diff --git a/ext/filter/tests/062.phpt b/ext/filter/tests/062.phpt new file mode 100644 index 0000000000000..2623443314ad4 --- /dev/null +++ b/ext/filter/tests/062.phpt @@ -0,0 +1,184 @@ +--TEST-- +filter_var() and FILTER_VALIDATE_URL with different URI parsers +--EXTENSIONS-- +filter +--FILE-- + $parserName])); + } + + var_dump(filter_var("qwe", FILTER_VALIDATE_URL, ["uri_parser_class" => $parserName])); + var_dump(filter_var("http://qwe", FILTER_VALIDATE_URL, ["uri_parser_class" => $parserName])); + var_dump(filter_var("http://", FILTER_VALIDATE_URL, ["uri_parser_class" => $parserName])); + var_dump(filter_var("/tmp/test", FILTER_VALIDATE_URL, ["uri_parser_class" => $parserName])); + var_dump(filter_var("http://www.example.com", FILTER_VALIDATE_URL, ["uri_parser_class" => $parserName])); + var_dump(filter_var("http://www.example.com", FILTER_VALIDATE_URL, ["uri_parser_class" => $parserName, "flags" => FILTER_FLAG_PATH_REQUIRED])); + var_dump(filter_var("http://www.example.com/path/at/the/server/", FILTER_VALIDATE_URL, ["uri_parser_class" => $parserName, "flags" => FILTER_FLAG_PATH_REQUIRED])); + var_dump(filter_var("http://www.example.com/index.html", FILTER_VALIDATE_URL, ["uri_parser_class" => $parserName, "flags" => FILTER_FLAG_QUERY_REQUIRED])); + var_dump(filter_var("http://www.example.com/index.php?a=b&c=d", FILTER_VALIDATE_URL, ["uri_parser_class" => $parserName, "flags" => FILTER_FLAG_QUERY_REQUIRED])); +} + +echo "RFC3986:\n"; +validateUrls(Uri\Rfc3986Uri::class); + +echo "\nWHATWG:\n"; +validateUrls(Uri\WhatWgUri::class); + +echo "Done\n"; +?> +--EXPECT-- +RFC3986: +string(29) "http://example.com/index.html" +string(32) "http://www.example.com/index.php" +string(31) "http://www.example/img/test.png" +string(27) "http://www.example/img/dir/" +string(26) "http://www.example/img/dir" +string(79) "http://www.thelongestdomainnameintheworldandthensomeandthensomemoreandmore.com/" +bool(false) +bool(false) +string(261) "http://kDTvHt1PPDgX5EiP2MwiXjcoWNOhhTuOVAUWJ3TmpBYCC9QoJV114LMYrV3Zl58.kDTvHt1PPDgX5EiP2MwiXjcoWNOhhTuOVAUWJ3TmpBYCC9QoJV114LMYrV3Zl58.kDTvHt1PPDgX5EiP2MwiXjcoWNOhhTuOVAUWJ3TmpBYCC9QoJV114LMYrV3Zl58.CQ1oT5Uq3jJt6Uhy3VH9u3Gi5YhfZCvZVKgLlaXNFhVKB1zJxvunR7SJa.com." +bool(false) +string(48) "http://[2001:0db8:0000:85a3:0000:0000:ac1f:8001]" +string(50) "http://[2001:db8:0:85a3:0:0:ac1f:8001]:123/me.html" +string(36) "http://[2001:db8:0:85a3::ac1f:8001]/" +string(12) "http://[::1]" +string(31) "http://cont-ains.h-yph-en-s.com" +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +string(18) "file:///tmp/test.c" +string(26) "ftp://ftp.example.com/tmp/" +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +string(18) "mailto:foo@bar.com" +string(17) "news:news.php.net" +string(14) "file://foo/bar" +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +string(10) "http://qwe" +bool(false) +bool(false) +string(22) "http://www.example.com" +bool(false) +string(42) "http://www.example.com/path/at/the/server/" +bool(false) +string(40) "http://www.example.com/index.php?a=b&c=d" + +WHATWG: +string(29) "http://example.com/index.html" +string(32) "http://www.example.com/index.php" +string(31) "http://www.example/img/test.png" +string(27) "http://www.example/img/dir/" +string(26) "http://www.example/img/dir" +string(79) "http://www.thelongestdomainnameintheworldandthensomeandthensomemoreandmore.com/" +bool(false) +bool(false) +string(261) "http://kDTvHt1PPDgX5EiP2MwiXjcoWNOhhTuOVAUWJ3TmpBYCC9QoJV114LMYrV3Zl58.kDTvHt1PPDgX5EiP2MwiXjcoWNOhhTuOVAUWJ3TmpBYCC9QoJV114LMYrV3Zl58.kDTvHt1PPDgX5EiP2MwiXjcoWNOhhTuOVAUWJ3TmpBYCC9QoJV114LMYrV3Zl58.CQ1oT5Uq3jJt6Uhy3VH9u3Gi5YhfZCvZVKgLlaXNFhVKB1zJxvunR7SJa.com." +bool(false) +string(48) "http://[2001:0db8:0000:85a3:0000:0000:ac1f:8001]" +string(50) "http://[2001:db8:0:85a3:0:0:ac1f:8001]:123/me.html" +string(36) "http://[2001:db8:0:85a3::ac1f:8001]/" +string(12) "http://[::1]" +string(31) "http://cont-ains.h-yph-en-s.com" +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +string(18) "file:///tmp/test.c" +string(26) "ftp://ftp.example.com/tmp/" +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +string(18) "mailto:foo@bar.com" +string(17) "news:news.php.net" +string(14) "file://foo/bar" +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +string(10) "http://qwe" +bool(false) +bool(false) +string(22) "http://www.example.com" +bool(false) +string(42) "http://www.example.com/path/at/the/server/" +bool(false) +string(40) "http://www.example.com/index.php?a=b&c=d" +Done diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c index d53e55aa15547..3b8f1af91d3d2 100644 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@ -23,7 +23,7 @@ #include "php.h" #include "ext/standard/file.h" -#include "ext/standard/url.h" +#include "ext/uri/php_uri.h" #include "streams/php_streams_int.h" #include "zend_smart_str.h" #include "php_openssl.h" @@ -2620,23 +2620,28 @@ static zend_long php_openssl_get_crypto_method( /* }}} */ static char *php_openssl_get_url_name(const char *resourcename, - size_t resourcenamelen, int is_persistent) /* {{{ */ + size_t resourcenamelen, int is_persistent, php_stream_context *context) /* {{{ */ { - php_url *url; - if (!resourcename) { return NULL; } - url = php_url_parse_ex(resourcename, resourcenamelen); - if (!url) { + uri_handler_t *uri_handler = php_stream_context_get_uri_handler("ssl", context); + if (uri_handler == NULL) { + return NULL; + } + + uri_internal_t *internal_uri = php_uri_parse(uri_handler, resourcename, resourcenamelen, true); + if (internal_uri == NULL) { return NULL; } - if (url->host) { - const char * host = ZSTR_VAL(url->host); - char * url_name = NULL; - size_t len = ZSTR_LEN(url->host); + char * url_name = NULL; + zval host_zv; + zend_result result = php_uri_get_host(internal_uri, URI_COMPONENT_READ_RAW, &host_zv); + if (result == SUCCESS && Z_TYPE(host_zv) == IS_STRING) { + const char * host = Z_STRVAL(host_zv); + size_t len = Z_STRLEN(host_zv); /* skip trailing dots */ while (len && host[len-1] == '.') { @@ -2646,13 +2651,12 @@ static char *php_openssl_get_url_name(const char *resourcename, if (len) { url_name = pestrndup(host, len, is_persistent); } - - php_url_free(url); - return url_name; } - php_url_free(url); - return NULL; + php_uri_free(internal_uri); + zval_ptr_dtor(&host_zv); + + return url_name; } /* }}} */ @@ -2750,7 +2754,7 @@ php_stream *php_openssl_ssl_socket_factory(const char *proto, size_t protolen, #endif } - sslsock->url_name = php_openssl_get_url_name(resourcename, resourcenamelen, !!persistent_id); + sslsock->url_name = php_openssl_get_url_name(resourcename, resourcenamelen, !!persistent_id, context); return stream; } diff --git a/ext/reflection/tests/ReflectionExtension_getDependencies_variation2.phpt b/ext/reflection/tests/ReflectionExtension_getDependencies_variation2.phpt index be13fe27a8202..60527c0b369f2 100644 --- a/ext/reflection/tests/ReflectionExtension_getDependencies_variation2.phpt +++ b/ext/reflection/tests/ReflectionExtension_getDependencies_variation2.phpt @@ -8,7 +8,9 @@ $standard = new ReflectionExtension('standard'); var_dump($standard->getDependencies()); ?> --EXPECTF-- -array(1) { +array(%d) { + ["uri"]=> + %s(8) "Required" ["session"]=> %s(8) "Optional" } diff --git a/ext/soap/php_http.c b/ext/soap/php_http.c index 71f32d4b9d107..18356be4be2ef 100644 --- a/ext/soap/php_http.c +++ b/ext/soap/php_http.c @@ -18,6 +18,7 @@ #include "php_soap.h" #include "ext/hash/php_hash.h" /* For php_hash_bin2hex() */ +#include "ext/uri/php_uri.h" static char *get_http_header_value_nodup(char *headers, char *type, size_t *len); static char *get_http_header_value(char *headers, char *type); @@ -162,7 +163,7 @@ void http_context_headers(php_stream_context* context, } } -static php_stream* http_connect(zval* this_ptr, php_url *phpurl, int use_ssl, php_stream_context *context, int *use_proxy) +static php_stream* http_connect(zval* this_ptr, php_uri *uri, int use_ssl, php_stream_context *context, int *use_proxy) { php_stream *stream; zval *tmp, ssl_proxy_peer_name; @@ -182,8 +183,8 @@ static php_stream* http_connect(zval* this_ptr, php_url *phpurl, int use_ssl, ph port = Z_LVAL_P(proxy_port); *use_proxy = 1; } else { - host = ZSTR_VAL(phpurl->host); - port = phpurl->port; + host = ZSTR_VAL(uri->host); + port = uri->port; } tmp = Z_CLIENT_CONNECTION_TIMEOUT_P(this_ptr); @@ -247,21 +248,21 @@ static php_stream* http_connect(zval* this_ptr, php_url *phpurl, int use_ssl, ph /* Set peer_name or name verification will try to use the proxy server name */ if (!context || (tmp = php_stream_context_get_option(context, "ssl", "peer_name")) == NULL) { - ZVAL_STR_COPY(&ssl_proxy_peer_name, phpurl->host); + ZVAL_STR_COPY(&ssl_proxy_peer_name, uri->host); php_stream_context_set_option(PHP_STREAM_CONTEXT(stream), "ssl", "peer_name", &ssl_proxy_peer_name); zval_ptr_dtor(&ssl_proxy_peer_name); } smart_str_append_const(&soap_headers, "CONNECT "); - smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->host)); + smart_str_appends(&soap_headers, ZSTR_VAL(uri->host)); smart_str_appendc(&soap_headers, ':'); - smart_str_append_unsigned(&soap_headers, phpurl->port); + smart_str_append_unsigned(&soap_headers, uri->port); smart_str_append_const(&soap_headers, " HTTP/1.1\r\n"); smart_str_append_const(&soap_headers, "Host: "); - smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->host)); - if (phpurl->port != 80) { + smart_str_appends(&soap_headers, ZSTR_VAL(uri->host)); + if (uri->port != 80) { smart_str_appendc(&soap_headers, ':'); - smart_str_append_unsigned(&soap_headers, phpurl->port); + smart_str_append_unsigned(&soap_headers, uri->port); } smart_str_append_const(&soap_headers, "\r\n"); proxy_authentication(this_ptr, &soap_headers); @@ -335,18 +336,15 @@ static bool in_domain(const zend_string *host, const zend_string *domain) } } -int make_http_soap_request(zval *this_ptr, - zend_string *buf, - char *location, - char *soapaction, - int soap_version, - zval *return_value) -{ +int make_http_soap_request( + zval *this_ptr, zend_string *buf, zend_string *location, char *soapaction, + int soap_version, const zend_string *uri_parser_class, zval *return_value +) { zend_string *request; smart_str soap_headers = {0}; smart_str soap_headers_z = {0}; size_t err; - php_url *phpurl = NULL; + php_uri *uri = NULL; php_stream *stream; zval *tmp; int use_proxy = 0; @@ -432,8 +430,13 @@ int make_http_soap_request(zval *this_ptr, stream = NULL; } - if (location != NULL && location[0] != '\000') { - phpurl = php_url_parse(location); + if (location != NULL && ZSTR_VAL(location)[0] != '\000') { + uri_handler_t *uri_handler = php_uri_get_handler(uri_parser_class); + if (uri_handler == NULL) { + zend_argument_value_error(6, "must be a valid URI parser name"); + return FALSE; + } + uri = php_uri_parse_to_struct(uri_handler, ZSTR_VAL(location), ZSTR_LEN(location), URI_COMPONENT_READ_NORMALIZED_ASCII, true); } tmp = Z_CLIENT_STREAM_CONTEXT_P(this_ptr); @@ -450,8 +453,10 @@ int make_http_soap_request(zval *this_ptr, } try_again: - if (phpurl == NULL || phpurl->host == NULL) { - if (phpurl != NULL) {php_url_free(phpurl);} + if (uri == NULL || uri->host == NULL) { + if (uri != NULL) { + php_uri_struct_free(uri); + } if (request != buf) { zend_string_release_ex(request, 0); } @@ -462,10 +467,10 @@ int make_http_soap_request(zval *this_ptr, } use_ssl = 0; - if (phpurl->scheme != NULL && zend_string_equals_literal(phpurl->scheme, "https")) { + if (uri->scheme != NULL && zend_string_equals_literal(uri->scheme, "https")) { use_ssl = 1; - } else if (phpurl->scheme == NULL || !zend_string_equals_literal(phpurl->scheme, "http")) { - php_url_free(phpurl); + } else if (uri->scheme == NULL || !zend_string_equals_literal(uri->scheme, "http")) { + php_uri_struct_free(uri); if (request != buf) { zend_string_release_ex(request, 0); } @@ -478,7 +483,7 @@ int make_http_soap_request(zval *this_ptr, old_allow_url_fopen = PG(allow_url_fopen); PG(allow_url_fopen) = 1; if (use_ssl && php_stream_locate_url_wrapper("https://", NULL, STREAM_LOCATE_WRAPPERS_ONLY) == NULL) { - php_url_free(phpurl); + php_uri_struct_free(uri); if (request != buf) { zend_string_release_ex(request, 0); } @@ -489,22 +494,22 @@ int make_http_soap_request(zval *this_ptr, return FALSE; } - if (phpurl->port == 0) { - phpurl->port = use_ssl ? 443 : 80; + if (uri->port == 0) { + uri->port = use_ssl ? 443 : 80; } /* Check if request to the same host */ if (stream != NULL) { - php_url *orig; + php_uri *orig; tmp = Z_CLIENT_HTTPURL_P(this_ptr); if (Z_TYPE_P(tmp) == IS_OBJECT && instanceof_function(Z_OBJCE_P(tmp), soap_url_class_entry) && - (orig = Z_SOAP_URL_P(tmp)->url) != NULL && + (orig = Z_SOAP_URL_P(tmp)->uri) != NULL && ((use_proxy && !use_ssl) || (((use_ssl && orig->scheme != NULL && zend_string_equals_literal(orig->scheme, "https")) || (!use_ssl && orig->scheme == NULL) || (!use_ssl && !zend_string_equals_literal(orig->scheme, "https"))) && - zend_string_equals(orig->host, phpurl->host) && - orig->port == phpurl->port))) { + zend_string_equals(orig->host, uri->host) && + orig->port == uri->port))) { } else { ZVAL_NULL(Z_CLIENT_HTTPSOCKET_P(this_ptr)); php_stream_close(stream); @@ -526,12 +531,12 @@ int make_http_soap_request(zval *this_ptr, } if (!stream) { - stream = http_connect(this_ptr, phpurl, use_ssl, context, &use_proxy); + stream = http_connect(this_ptr, uri, use_ssl, context, &use_proxy); if (stream) { php_stream_to_zval(stream, Z_CLIENT_HTTPSOCKET_P(this_ptr)); ZVAL_LONG(Z_CLIENT_USE_PROXY_P(this_ptr), use_proxy); } else { - php_url_free(phpurl); + php_uri_struct_free(uri); if (request != buf) { zend_string_release_ex(request, 0); } @@ -556,7 +561,7 @@ int make_http_soap_request(zval *this_ptr, object_init_ex(url_zval, soap_url_class_entry); soap_url_object *url_obj = Z_SOAP_URL_P(url_zval); - url_obj->url = phpurl; + url_obj->uri = uri; if (context && (tmp = php_stream_context_get_option(context, "http", "protocol_version")) != NULL && @@ -569,24 +574,24 @@ int make_http_soap_request(zval *this_ptr, smart_str_append_const(&soap_headers, "POST "); if (use_proxy && !use_ssl) { - smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->scheme)); + smart_str_appends(&soap_headers, ZSTR_VAL(uri->scheme)); smart_str_append_const(&soap_headers, "://"); - smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->host)); + smart_str_appends(&soap_headers, ZSTR_VAL(uri->host)); smart_str_appendc(&soap_headers, ':'); - smart_str_append_unsigned(&soap_headers, phpurl->port); + smart_str_append_unsigned(&soap_headers, uri->port); } - if (phpurl->path) { - smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->path)); + if (uri->path) { + smart_str_appends(&soap_headers, ZSTR_VAL(uri->path)); } else { smart_str_appendc(&soap_headers, '/'); } - if (phpurl->query) { + if (uri->query) { smart_str_appendc(&soap_headers, '?'); - smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->query)); + smart_str_appends(&soap_headers, ZSTR_VAL(uri->query)); } - if (phpurl->fragment) { + if (uri->fragment) { smart_str_appendc(&soap_headers, '#'); - smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->fragment)); + smart_str_appends(&soap_headers, ZSTR_VAL(uri->fragment)); } if (http_1_1) { smart_str_append_const(&soap_headers, " HTTP/1.1\r\n"); @@ -594,10 +599,10 @@ int make_http_soap_request(zval *this_ptr, smart_str_append_const(&soap_headers, " HTTP/1.0\r\n"); } smart_str_append_const(&soap_headers, "Host: "); - smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->host)); - if (phpurl->port != (use_ssl?443:80)) { + smart_str_appends(&soap_headers, ZSTR_VAL(uri->host)); + if (uri->port != (use_ssl?443:80)) { smart_str_appendc(&soap_headers, ':'); - smart_str_append_unsigned(&soap_headers, phpurl->port); + smart_str_append_unsigned(&soap_headers, uri->port); } if (!http_1_1 || Z_TYPE_P(Z_CLIENT_KEEP_ALIVE_P(this_ptr)) == IS_FALSE) { smart_str_append_const(&soap_headers, "\r\n" @@ -739,14 +744,14 @@ int make_http_soap_request(zval *this_ptr, PHP_MD5Init(&md5ctx); PHP_MD5Update(&md5ctx, (unsigned char*)"POST:", sizeof("POST:")-1); - if (phpurl->path) { - PHP_MD5Update(&md5ctx, (unsigned char*)ZSTR_VAL(phpurl->path), ZSTR_LEN(phpurl->path)); + if (uri->path) { + PHP_MD5Update(&md5ctx, (unsigned char*)ZSTR_VAL(uri->path), ZSTR_LEN(uri->path)); } else { PHP_MD5Update(&md5ctx, (unsigned char*)"/", 1); } - if (phpurl->query) { + if (uri->query) { PHP_MD5Update(&md5ctx, (unsigned char*)"?", 1); - PHP_MD5Update(&md5ctx, (unsigned char*)ZSTR_VAL(phpurl->query), ZSTR_LEN(phpurl->query)); + PHP_MD5Update(&md5ctx, (unsigned char*)ZSTR_VAL(uri->query), ZSTR_LEN(uri->query)); } PHP_MD5Final(hash, &md5ctx); @@ -787,18 +792,18 @@ int make_http_soap_request(zval *this_ptr, smart_str_appendl(&soap_headers, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp)); } smart_str_append_const(&soap_headers, "\", uri=\""); - if (phpurl->path) { - smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->path)); + if (uri->path) { + smart_str_appends(&soap_headers, ZSTR_VAL(uri->path)); } else { smart_str_appendc(&soap_headers, '/'); } - if (phpurl->query) { + if (uri->query) { smart_str_appendc(&soap_headers, '?'); - smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->query)); + smart_str_appends(&soap_headers, ZSTR_VAL(uri->query)); } - if (phpurl->fragment) { + if (uri->fragment) { smart_str_appendc(&soap_headers, '#'); - smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->fragment)); + smart_str_appends(&soap_headers, ZSTR_VAL(uri->fragment)); } if ((tmp = zend_hash_str_find(Z_ARRVAL_P(digest), "qop", sizeof("qop")-1)) != NULL && Z_TYPE_P(tmp) == IS_STRING) { @@ -865,10 +870,10 @@ int make_http_soap_request(zval *this_ptr, zval *tmp; if (((tmp = zend_hash_index_find(Z_ARRVAL_P(data), 1)) == NULL || Z_TYPE_P(tmp) != IS_STRING || - strncmp(phpurl->path?ZSTR_VAL(phpurl->path):"/",Z_STRVAL_P(tmp),Z_STRLEN_P(tmp)) == 0) && + strncmp(uri->path?ZSTR_VAL(uri->path):"/",Z_STRVAL_P(tmp),Z_STRLEN_P(tmp)) == 0) && ((tmp = zend_hash_index_find(Z_ARRVAL_P(data), 2)) == NULL || Z_TYPE_P(tmp) != IS_STRING || - in_domain(phpurl->host, Z_STR_P(tmp))) && + in_domain(uri->host, Z_STR_P(tmp))) && (use_ssl || (tmp = zend_hash_index_find(Z_ARRVAL_P(data), 3)) == NULL)) { if (!first_cookie) { smart_str_appends(&soap_headers, "; "); @@ -1047,15 +1052,15 @@ int make_http_soap_request(zval *this_ptr, } } if (!zend_hash_index_exists(Z_ARRVAL(zcookie), 1)) { - char *t = phpurl->path?ZSTR_VAL(phpurl->path):"/"; + char *t = uri->path?ZSTR_VAL(uri->path):"/"; char *c = strrchr(t, '/'); if (c) { add_index_stringl(&zcookie, 1, t, c-t); } } if (!zend_hash_index_exists(Z_ARRVAL(zcookie), 2)) { - add_index_str(&zcookie, 2, phpurl->host); - GC_ADDREF(phpurl->host); + add_index_str(&zcookie, 2, uri->host); + GC_ADDREF(uri->host); } zend_symtable_update(Z_ARRVAL_P(cookies), name.s, &zcookie); @@ -1143,39 +1148,46 @@ int make_http_soap_request(zval *this_ptr, char *loc; if ((loc = get_http_header_value(ZSTR_VAL(http_headers), "Location:")) != NULL) { - php_url *new_url = php_url_parse(loc); + uri_handler_t *uri_handler = php_uri_get_handler(uri_parser_class); + if (uri_handler == NULL) { + efree(loc); + zend_argument_value_error(6, "must be a valid URI parser name"); + return FALSE; + } + + php_uri *new_uri = php_uri_parse_to_struct(uri_handler, loc, strlen(loc), URI_COMPONENT_READ_NORMALIZED_ASCII, true); efree(loc); - if (new_url != NULL) { + if (new_uri != NULL) { zend_string_release_ex(http_headers, 0); zend_string_release_ex(http_body, 0); - if (new_url->scheme == NULL && new_url->path != NULL) { - new_url->scheme = phpurl->scheme ? zend_string_copy(phpurl->scheme) : NULL; - new_url->host = phpurl->host ? zend_string_copy(phpurl->host) : NULL; - new_url->port = phpurl->port; - if (new_url->path && ZSTR_VAL(new_url->path)[0] != '/') { - if (phpurl->path) { - char *t = ZSTR_VAL(phpurl->path); + if (new_uri->scheme == NULL && new_uri->path != NULL) { + new_uri->scheme = new_uri->scheme ? zend_string_copy(new_uri->scheme) : NULL; + new_uri->host = new_uri->host ? zend_string_copy(new_uri->host) : NULL; + new_uri->port = new_uri->port; + if (new_uri->path && ZSTR_VAL(new_uri->path)[0] != '/') { + if (new_uri->path) { + char *t = ZSTR_VAL(new_uri->path); char *p = strrchr(t, '/'); if (p) { - zend_string *s = zend_string_alloc((p - t) + ZSTR_LEN(new_url->path) + 2, 0); + zend_string *s = zend_string_alloc((p - t) + ZSTR_LEN(new_uri->path) + 2, 0); strncpy(ZSTR_VAL(s), t, (p - t) + 1); ZSTR_VAL(s)[(p - t) + 1] = 0; - strcat(ZSTR_VAL(s), ZSTR_VAL(new_url->path)); - zend_string_release_ex(new_url->path, 0); - new_url->path = s; + strcat(ZSTR_VAL(s), ZSTR_VAL(new_uri->path)); + zend_string_release_ex(new_uri->path, 0); + new_uri->path = s; } } else { - zend_string *s = zend_string_alloc(ZSTR_LEN(new_url->path) + 2, 0); + zend_string *s = zend_string_alloc(ZSTR_LEN(new_uri->path) + 2, 0); ZSTR_VAL(s)[0] = '/'; ZSTR_VAL(s)[1] = 0; - strcat(ZSTR_VAL(s), ZSTR_VAL(new_url->path)); - zend_string_release_ex(new_url->path, 0); - new_url->path = s; + strcat(ZSTR_VAL(s), ZSTR_VAL(new_uri->path)); + zend_string_release_ex(new_uri->path, 0); + new_uri->path = s; } } } - phpurl = new_url; + uri = new_uri; if (--redirect_max < 1) { add_soap_fault(this_ptr, "HTTP", "Redirection limit reached, aborting", NULL, NULL, SOAP_GLOBAL(lang_en)); @@ -1235,20 +1247,20 @@ int make_http_soap_request(zval *this_ptr, } if (Z_TYPE(digest) != IS_UNDEF) { - php_url *new_url = emalloc(sizeof(php_url)); + php_uri *new_uri = emalloc(sizeof(php_uri)); zval_ptr_dtor(Z_CLIENT_DIGEST_P(this_ptr)); ZVAL_COPY_VALUE(Z_CLIENT_DIGEST_P(this_ptr), &digest); - *new_url = *phpurl; - if (phpurl->scheme) phpurl->scheme = zend_string_copy(phpurl->scheme); - if (phpurl->user) phpurl->user = zend_string_copy(phpurl->user); - if (phpurl->pass) phpurl->pass = zend_string_copy(phpurl->pass); - if (phpurl->host) phpurl->host = zend_string_copy(phpurl->host); - if (phpurl->path) phpurl->path = zend_string_copy(phpurl->path); - if (phpurl->query) phpurl->query = zend_string_copy(phpurl->query); - if (phpurl->fragment) phpurl->fragment = zend_string_copy(phpurl->fragment); - phpurl = new_url; + *new_uri = *uri; + if (uri->scheme) uri->scheme = zend_string_copy(uri->scheme); + if (uri->user) uri->user = zend_string_copy(uri->user); + if (uri->password) uri->password = zend_string_copy(uri->password); + if (uri->host) uri->host = zend_string_copy(uri->host); + if (uri->path) uri->path = zend_string_copy(uri->path); + if (uri->query) uri->query = zend_string_copy(uri->query); + if (uri->fragment) uri->fragment = zend_string_copy(uri->fragment); + uri = new_uri; efree(auth); zend_string_release_ex(http_headers, 0); diff --git a/ext/soap/php_http.h b/ext/soap/php_http.h index df24c0d26fa84..17e780ec60a26 100644 --- a/ext/soap/php_http.h +++ b/ext/soap/php_http.h @@ -19,12 +19,10 @@ #ifndef PHP_HTTP_H #define PHP_HTTP_H -int make_http_soap_request(zval *this_ptr, - zend_string *request, - char *location, - char *soapaction, - int soap_version, - zval *response); +int make_http_soap_request( + zval *this_ptr, zend_string *buf, zend_string *location, char *soapaction, + int soap_version, const zend_string *uri_parser_class, zval *return_value +); int proxy_authentication(zval* this_ptr, smart_str* soap_headers); int basic_authentication(zval* this_ptr, smart_str* soap_headers); diff --git a/ext/soap/php_soap.h b/ext/soap/php_soap.h index 1eea30c62e905..48f8fb50591cb 100644 --- a/ext/soap/php_soap.h +++ b/ext/soap/php_soap.h @@ -27,6 +27,7 @@ #include "zend_smart_str.h" #include "php_ini.h" #include "SAPI.h" +#include "ext/uri/php_uri.h" #include #include @@ -255,7 +256,7 @@ static zend_always_inline zval *php_soap_deref(zval *zv) { #define Z_CLIENT_LAST_RESPONSE_HEADERS_P(zv) OBJ_PROP_NUM(Z_OBJ_P(zv), 35) typedef struct soap_url_object { - php_url *url; + php_uri *uri; zend_object std; } soap_url_object; diff --git a/ext/soap/soap.c b/ext/soap/soap.c index 35b87c83959ea..89b13c4972d9b 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -233,9 +233,9 @@ static void soap_url_object_free(zend_object *obj) { soap_url_object *url_obj = soap_url_object_fetch(obj); - if (url_obj->url) { - php_url_free(url_obj->url); - url_obj->url = NULL; + if (url_obj->uri) { + php_uri_struct_free(url_obj->uri); + url_obj->uri = NULL; } zend_object_std_dtor(&url_obj->std); @@ -2783,28 +2783,28 @@ PHP_METHOD(SoapClient, __getLastResponseHeaders) /* {{{ SoapClient::__doRequest() */ PHP_METHOD(SoapClient, __doRequest) { - zend_string *buf; - char *location, *action; - size_t location_size, action_size; + zend_string *buf, *location, *uri_parser_class = NULL; + char *action; + size_t action_size; zend_long version; bool one_way = 0; zval *this_ptr = ZEND_THIS; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sssl|b", + if (zend_parse_parameters(ZEND_NUM_ARGS(), "SSsl|bS!", &buf, - &location, &location_size, + &location, &action, &action_size, - &version, &one_way) == FAILURE) { + &version, &one_way, &uri_parser_class) == FAILURE) { RETURN_THROWS(); } if (SOAP_GLOBAL(features) & SOAP_WAIT_ONE_WAY_CALLS) { one_way = 0; } if (one_way) { - if (make_http_soap_request(this_ptr, buf, location, action, version, NULL)) { + if (make_http_soap_request(this_ptr, buf, location, action, version, uri_parser_class, NULL)) { RETURN_EMPTY_STRING(); } - } else if (make_http_soap_request(this_ptr, buf, location, action, version, + } else if (make_http_soap_request(this_ptr, buf, location, action, version, uri_parser_class, return_value)) { return; } diff --git a/ext/soap/soap.stub.php b/ext/soap/soap.stub.php index 15d4ef1e6bd3e..851b32042bd19 100644 --- a/ext/soap/soap.stub.php +++ b/ext/soap/soap.stub.php @@ -605,7 +605,7 @@ public function __getLastRequestHeaders(): ?string {} public function __getLastResponseHeaders(): ?string {} /** @tentative-return-type */ - public function __doRequest(string $request, string $location, string $action, int $version, bool $oneWay = false): ?string {} + public function __doRequest(string $request, string $location, string $action, int $version, bool $oneWay = false, ?string $uriParserClass = null): ?string {} /** @tentative-return-type */ public function __setCookie(string $name, ?string $value = null): void {} diff --git a/ext/soap/soap_arginfo.h b/ext/soap/soap_arginfo.h index f69659b4b0f84..cc420f3849b81 100644 --- a/ext/soap/soap_arginfo.h +++ b/ext/soap/soap_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 4277993645a3f560c7a9971466fabf2d451bc92d */ + * Stub hash: 24e266bf0933d5622f2a341db5b694ecb1740f13 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_use_soap_error_handler, 0, 0, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, enable, _IS_BOOL, 0, "true") @@ -124,6 +124,7 @@ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_SoapClient___doR ZEND_ARG_TYPE_INFO(0, action, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, version, IS_LONG, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, oneWay, _IS_BOOL, 0, "false") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, uriParserClass, IS_STRING, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_SoapClient___setCookie, 0, 1, IS_VOID, 0) diff --git a/ext/soap/tests/SoapServer/__getLastResponse.phpt b/ext/soap/tests/SoapServer/__getLastResponse.phpt index 83c20d3c3a49c..900a880359731 100644 --- a/ext/soap/tests/SoapServer/__getLastResponse.phpt +++ b/ext/soap/tests/SoapServer/__getLastResponse.phpt @@ -18,7 +18,7 @@ class LocalSoapClient extends SoapClient { $this->server->addFunction("f"); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { ob_start(); $this->server->handle($request); $response = ob_get_contents(); diff --git a/ext/soap/tests/any.phpt b/ext/soap/tests/any.phpt index 6b08e395c2b1a..c25748997aba5 100644 --- a/ext/soap/tests/any.phpt +++ b/ext/soap/tests/any.phpt @@ -33,7 +33,7 @@ class TestSoapClient extends SoapClient { $this->server->addFunction('echoAnyElement'); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { ob_start(); $this->server->handle($request); $response = ob_get_contents(); diff --git a/ext/soap/tests/bugs/bug28969.phpt b/ext/soap/tests/bugs/bug28969.phpt index 71de59939f8de..661e1fc82277d 100644 --- a/ext/soap/tests/bugs/bug28969.phpt +++ b/ext/soap/tests/bugs/bug28969.phpt @@ -18,7 +18,7 @@ class LocalSoapClient extends SoapClient { $this->server->addFunction('test'); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { ob_start(); $this->server->handle($request); $response = ob_get_contents(); diff --git a/ext/soap/tests/bugs/bug29795.phpt b/ext/soap/tests/bugs/bug29795.phpt index 1db3226ab171f..395d3b6c7ec61 100644 --- a/ext/soap/tests/bugs/bug29795.phpt +++ b/ext/soap/tests/bugs/bug29795.phpt @@ -12,7 +12,7 @@ class LocalSoapClient extends SoapClient { parent::__construct($wsdl, $options); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { return <<server->addFunction('EchoString'); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { ob_start(); $this->server->handle($request); $response = ob_get_contents(); diff --git a/ext/soap/tests/bugs/bug29844.phpt b/ext/soap/tests/bugs/bug29844.phpt index 7f5178ec6db7a..c98c3041bbb6a 100644 --- a/ext/soap/tests/bugs/bug29844.phpt +++ b/ext/soap/tests/bugs/bug29844.phpt @@ -22,7 +22,7 @@ class LocalSoapClient extends SoapClient { $this->server->setClass('hello_world'); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { ob_start(); $this->server->handle($request); $response = ob_get_contents(); diff --git a/ext/soap/tests/bugs/bug30045.phpt b/ext/soap/tests/bugs/bug30045.phpt index a84b73a7830f8..7dac3d0266311 100644 --- a/ext/soap/tests/bugs/bug30045.phpt +++ b/ext/soap/tests/bugs/bug30045.phpt @@ -21,7 +21,7 @@ class LocalSoapClient extends SoapClient { $this->server->addFunction('foo'); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { $xml = simplexml_load_string($request); echo $xml->children("http://schemas.xmlsoap.org/soap/envelope/")->Body->children("http://test-uri")->children()->param1->asXML(),"\n"; unset($xml); diff --git a/ext/soap/tests/bugs/bug30106.phpt b/ext/soap/tests/bugs/bug30106.phpt index d924a5bb8b32a..0a891b4cb59dd 100644 --- a/ext/soap/tests/bugs/bug30106.phpt +++ b/ext/soap/tests/bugs/bug30106.phpt @@ -21,7 +21,7 @@ class LocalSoapClient extends SoapClient { $this->server->addFunction("getContinentList"); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { echo $request; ob_start(); $this->server->handle($request); diff --git a/ext/soap/tests/bugs/bug30175.phpt b/ext/soap/tests/bugs/bug30175.phpt index ab0ab5cc11c7f..9f17f60162dd8 100644 --- a/ext/soap/tests/bugs/bug30175.phpt +++ b/ext/soap/tests/bugs/bug30175.phpt @@ -9,7 +9,7 @@ soap.wsdl_cache_enabled=0 class LocalSoapClient extends SoapClient { - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { return << server->addFunction('test'); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { ob_start(); $this->server->handle($request); $response = ob_get_contents(); diff --git a/ext/soap/tests/bugs/bug31695.phpt b/ext/soap/tests/bugs/bug31695.phpt index ba8a6ae000618..0d95cc6cfe67c 100644 --- a/ext/soap/tests/bugs/bug31695.phpt +++ b/ext/soap/tests/bugs/bug31695.phpt @@ -19,7 +19,7 @@ class LocalSoapClient extends SoapClient { $this->server->addFunction("Test"); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { echo "$location\n"; ob_start(); $this->server->handle($request); diff --git a/ext/soap/tests/bugs/bug31755.phpt b/ext/soap/tests/bugs/bug31755.phpt index cf8987db3ee13..c4b2c622b6af1 100644 --- a/ext/soap/tests/bugs/bug31755.phpt +++ b/ext/soap/tests/bugs/bug31755.phpt @@ -5,7 +5,7 @@ soap --FILE-- server->addFunction('test'); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { ob_start(); $this->server->handle($request); $response = ob_get_contents(); diff --git a/ext/soap/tests/bugs/bug32941.phpt b/ext/soap/tests/bugs/bug32941.phpt index 0b4ac3ab30efd..85f4434f06592 100644 --- a/ext/soap/tests/bugs/bug32941.phpt +++ b/ext/soap/tests/bugs/bug32941.phpt @@ -5,7 +5,7 @@ soap --FILE-- server->addFunction('EchoString'); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { ob_start(); $this->server->handle($request); $response = ob_get_contents(); diff --git a/ext/soap/tests/bugs/bug34643.phpt b/ext/soap/tests/bugs/bug34643.phpt index 5c23cbd7c7b37..27542c2c2870a 100644 --- a/ext/soap/tests/bugs/bug34643.phpt +++ b/ext/soap/tests/bugs/bug34643.phpt @@ -23,7 +23,7 @@ class LocalSoapClient extends SoapClient { $this->server->setClass('fp'); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { ob_start(); $this->server->handle($request); $response = ob_get_contents(); diff --git a/ext/soap/tests/bugs/bug35142.phpt b/ext/soap/tests/bugs/bug35142.phpt index 5f46bbf84113c..d596c5eb54432 100644 --- a/ext/soap/tests/bugs/bug35142.phpt +++ b/ext/soap/tests/bugs/bug35142.phpt @@ -25,7 +25,7 @@ class TestSoapClient extends SoapClient { $this->server->addFunction('PostEvents'); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { echo "$request\n"; ob_start(); $this->server->handle($request); diff --git a/ext/soap/tests/bugs/bug35273.phpt b/ext/soap/tests/bugs/bug35273.phpt index 93e54626c5266..c35d545851feb 100644 --- a/ext/soap/tests/bugs/bug35273.phpt +++ b/ext/soap/tests/bugs/bug35273.phpt @@ -7,7 +7,7 @@ soap.wsdl_cache_enabled=0 --FILE-- server->addFunction('PostEvents'); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { echo "$request\n"; $this->server->handle($request); return $response; diff --git a/ext/soap/tests/bugs/bug36226.phpt b/ext/soap/tests/bugs/bug36226.phpt index 38ece5d0b87a0..c1d86ce4b3d92 100644 --- a/ext/soap/tests/bugs/bug36226.phpt +++ b/ext/soap/tests/bugs/bug36226.phpt @@ -25,7 +25,7 @@ class TestSoapClient extends SoapClient { $this->server->addFunction('PostEvents'); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { echo "$request\n"; ob_start(); $this->server->handle($request); diff --git a/ext/soap/tests/bugs/bug36999.phpt b/ext/soap/tests/bugs/bug36999.phpt index 04673649da232..d4ed65621e2a0 100644 --- a/ext/soap/tests/bugs/bug36999.phpt +++ b/ext/soap/tests/bugs/bug36999.phpt @@ -20,7 +20,7 @@ class LocalSoapClient extends SoapClient { $this->server->addFunction('echoLong'); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { ob_start(); $this->server->handle($request); $response = ob_get_contents(); diff --git a/ext/soap/tests/bugs/bug37083.phpt b/ext/soap/tests/bugs/bug37083.phpt index 441b51022b8a6..8e5326e03439f 100644 --- a/ext/soap/tests/bugs/bug37083.phpt +++ b/ext/soap/tests/bugs/bug37083.phpt @@ -7,7 +7,7 @@ soap.wsdl_cache=3 --FILE-- diff --git a/ext/soap/tests/bugs/bug38004.phpt b/ext/soap/tests/bugs/bug38004.phpt index 7953487ab1ece..3ca5aeda814f8 100644 --- a/ext/soap/tests/bugs/bug38004.phpt +++ b/ext/soap/tests/bugs/bug38004.phpt @@ -21,7 +21,7 @@ class TestSoapClient extends SoapClient { $this->server->addFunction('Test'); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { ob_start(); $this->server->handle($request); $response = ob_get_contents(); diff --git a/ext/soap/tests/bugs/bug38005.phpt b/ext/soap/tests/bugs/bug38005.phpt index ca3944ebc3db3..67837861ea5eb 100644 --- a/ext/soap/tests/bugs/bug38005.phpt +++ b/ext/soap/tests/bugs/bug38005.phpt @@ -19,7 +19,7 @@ class TestSoapClient extends SoapClient { $this->server->addFunction('Test'); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { ob_start(); $this->server->handle($request); $response = ob_get_contents(); diff --git a/ext/soap/tests/bugs/bug38055.phpt b/ext/soap/tests/bugs/bug38055.phpt index b066bf892e37a..ad951b537f238 100644 --- a/ext/soap/tests/bugs/bug38055.phpt +++ b/ext/soap/tests/bugs/bug38055.phpt @@ -22,7 +22,7 @@ class TestSoapClient extends SoapClient { $this->server->addFunction('Test'); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { ob_start(); $this->server->handle($request); $response = ob_get_contents(); diff --git a/ext/soap/tests/bugs/bug38067.phpt b/ext/soap/tests/bugs/bug38067.phpt index 2f25a87a1cf37..962e0c29d253f 100644 --- a/ext/soap/tests/bugs/bug38067.phpt +++ b/ext/soap/tests/bugs/bug38067.phpt @@ -21,7 +21,7 @@ class TestSoapClient extends SoapClient { $this->server->addFunction('Test'); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = 0, ?string $uriParserClass = null): string { ob_start(); $this->server->handle($request); $response = ob_get_contents(); diff --git a/ext/soap/tests/bugs/bug38536.phpt b/ext/soap/tests/bugs/bug38536.phpt index 5865e6a904ab9..c64772ccbc734 100644 --- a/ext/soap/tests/bugs/bug38536.phpt +++ b/ext/soap/tests/bugs/bug38536.phpt @@ -7,7 +7,7 @@ soap.wsdl_cache_enabled=0 --FILE-- diff --git a/ext/soap/tests/bugs/bug39815.phpt b/ext/soap/tests/bugs/bug39815.phpt index 51178e40e5b89..0eeb18cf416fb 100644 --- a/ext/soap/tests/bugs/bug39815.phpt +++ b/ext/soap/tests/bugs/bug39815.phpt @@ -23,7 +23,7 @@ class LocalSoapClient extends SoapClient { $this->server->addFunction('test'); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { ob_start(); $this->server->handle($request); $response = ob_get_contents(); diff --git a/ext/soap/tests/bugs/bug42692.phpt b/ext/soap/tests/bugs/bug42692.phpt index 5ed9254b51726..fe4840d9268de 100644 --- a/ext/soap/tests/bugs/bug42692.phpt +++ b/ext/soap/tests/bugs/bug42692.phpt @@ -19,7 +19,7 @@ class TestSoap extends SoapClient { $this->server->addFunction("checkAuth"); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { ob_start(); $this->server->handle($request); $response = ob_get_contents(); diff --git a/ext/soap/tests/bugs/bug43045.phpt b/ext/soap/tests/bugs/bug43045.phpt index f1e3af7765b67..79a746e1692f9 100644 --- a/ext/soap/tests/bugs/bug43045.phpt +++ b/ext/soap/tests/bugs/bug43045.phpt @@ -16,7 +16,7 @@ class TestSoapClient extends SoapClient { $this->server = new SoapServer($wsdl, $options); $this->server->addFunction('test'); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { ob_start(); $this->server->handle($request); $response = ob_get_contents(); diff --git a/ext/soap/tests/bugs/bug44882.phpt b/ext/soap/tests/bugs/bug44882.phpt index 73049602aaf9c..93857fd3b27ba 100644 --- a/ext/soap/tests/bugs/bug44882.phpt +++ b/ext/soap/tests/bugs/bug44882.phpt @@ -8,7 +8,7 @@ soap.wsdl_cache_enabled=0 diff --git a/ext/soap/tests/bugs/bug46419.phpt b/ext/soap/tests/bugs/bug46419.phpt index e12adfb08f20c..090f4e08a5b8a 100644 --- a/ext/soap/tests/bugs/bug46419.phpt +++ b/ext/soap/tests/bugs/bug46419.phpt @@ -17,7 +17,7 @@ class LocalSoapClient extends SoapClient { $this->server->addFunction('bar'); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { ob_start(); $this->server->handle($request); $response = ob_get_contents(); diff --git a/ext/soap/tests/bugs/bug47021.phpt b/ext/soap/tests/bugs/bug47021.phpt index af12d7c4c39c5..19b034b9eed23 100644 --- a/ext/soap/tests/bugs/bug47021.phpt +++ b/ext/soap/tests/bugs/bug47021.phpt @@ -57,9 +57,9 @@ $options = [ class BugSoapClient extends SoapClient { - public function __doRequest($request, $location, $action, $version, $one_way = null): string + public function __doRequest($request, $location, $action, $version, $one_way = null, ?string $uriParserClass = null): string { - $response = parent::__doRequest($request, $location, $action, $version, $one_way); + $response = parent::__doRequest($request, $location, $action, $version, $one_way, $uriParserClass); var_dump(strlen($response)); diff --git a/ext/soap/tests/bugs/bug50675.phpt b/ext/soap/tests/bugs/bug50675.phpt index e4bad4ffdfacf..bc6a47577e2b7 100644 --- a/ext/soap/tests/bugs/bug50675.phpt +++ b/ext/soap/tests/bugs/bug50675.phpt @@ -6,7 +6,7 @@ soap server->setObject(new testSoap()); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { ob_start(); $this->server->handle($request); $response = ob_get_contents(); diff --git a/ext/soap/tests/bugs/bug54911.phpt b/ext/soap/tests/bugs/bug54911.phpt index 3247563dba496..0b1daec31345c 100644 --- a/ext/soap/tests/bugs/bug54911.phpt +++ b/ext/soap/tests/bugs/bug54911.phpt @@ -5,7 +5,7 @@ soap --FILE-- diff --git a/ext/soap/tests/bugs/bug66049.phpt b/ext/soap/tests/bugs/bug66049.phpt index e48845a8a142b..c31d0d7bcccdf 100644 --- a/ext/soap/tests/bugs/bug66049.phpt +++ b/ext/soap/tests/bugs/bug66049.phpt @@ -15,7 +15,7 @@ function soap_string_from_xml($str) } class TestSoapClient extends SoapClient { - function __doRequest($request, $location, $action, $version, $one_way = 0): ?string { + function __doRequest($request, $location, $action, $version, $one_way = 0, ?string $uriParserClass = null): ?string { $res=' diff --git a/ext/soap/tests/bugs/bug69085.phpt b/ext/soap/tests/bugs/bug69085.phpt index 3572efa5e381d..5974ce425319a 100644 --- a/ext/soap/tests/bugs/bug69085.phpt +++ b/ext/soap/tests/bugs/bug69085.phpt @@ -9,7 +9,7 @@ soap.wsdl_cache_enabled=0 #[AllowDynamicProperties] class MySoapClient extends SoapClient { - public function __doRequest($request, $location, $action, $version, $one_way = 0): string { + public function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { echo $request, "\n"; return ''; } diff --git a/ext/soap/tests/bugs/bug69668.phpt b/ext/soap/tests/bugs/bug69668.phpt index b93163c164de1..75fe05d5c2ed1 100644 --- a/ext/soap/tests/bugs/bug69668.phpt +++ b/ext/soap/tests/bugs/bug69668.phpt @@ -5,7 +5,7 @@ soap --FILE-- '', 'uri' => 'http://example.org']) extends SoapClient { - public function __doRequest($request, $location, $action, $version, $one_way = 0): string { + public function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { echo $request; return ''; } diff --git a/ext/soap/tests/bugs/bug71996.phpt b/ext/soap/tests/bugs/bug71996.phpt index a6b2a71765b54..d78661ad3273e 100644 --- a/ext/soap/tests/bugs/bug71996.phpt +++ b/ext/soap/tests/bugs/bug71996.phpt @@ -6,7 +6,7 @@ soap '', 'uri' => 'http://example.org']) extends SoapClient { - public function __doRequest($request, $location, $action, $version, $one_way = 0): string { + public function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { echo $request, "\n"; return ''; } diff --git a/ext/soap/tests/bugs/bug73237.phpt b/ext/soap/tests/bugs/bug73237.phpt index 643c99a8c22a3..32ee055706354 100644 --- a/ext/soap/tests/bugs/bug73237.phpt +++ b/ext/soap/tests/bugs/bug73237.phpt @@ -7,7 +7,7 @@ soap.wsdl_cache_enabled=0 --FILE-- trueCampaignMember00vi0000011VMgeAAG00vi0000011VMgeAAG701i0000001lreeAAASent00Qi000001UrbYFEAZLeadangela.lansbury@cbs.com1 EOF; diff --git a/ext/soap/tests/bugs/bug77141.phpt b/ext/soap/tests/bugs/bug77141.phpt index 4a86b6af902b4..67b07d598650a 100644 --- a/ext/soap/tests/bugs/bug77141.phpt +++ b/ext/soap/tests/bugs/bug77141.phpt @@ -5,7 +5,7 @@ soap --FILE-- WSDL_CACHE_NONE, 'trace' => 1, ]) extends SoapClient { - public function __doRequest($request, $location, $action, $version, $one_way = 0): string { + public function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { echo $request, "\n"; return ''; } diff --git a/ext/soap/tests/bugs/gh18640.phpt b/ext/soap/tests/bugs/gh18640.phpt index 493659eca30c7..4e76d699b3266 100644 --- a/ext/soap/tests/bugs/gh18640.phpt +++ b/ext/soap/tests/bugs/gh18640.phpt @@ -9,7 +9,7 @@ YuanchengJiang $wsdl = __DIR__."/bug35142.wsdl"; class TestSoapClient extends SoapClient { - function __doRequest($request, $location, $action, $version, $one_way = 0): ?string { + function __doRequest($request, $location, $action, $version, $one_way = 0, ?string $uriParserClass = null): ?string { var_dump($request); return ''; } diff --git a/ext/soap/tests/bugs/segfault_assertion_props.phpt b/ext/soap/tests/bugs/segfault_assertion_props.phpt index 75cefa57642e0..f11ea61f7cd3f 100644 --- a/ext/soap/tests/bugs/segfault_assertion_props.phpt +++ b/ext/soap/tests/bugs/segfault_assertion_props.phpt @@ -7,7 +7,7 @@ soap --FILE-- diff --git a/ext/soap/tests/classmap002.phpt b/ext/soap/tests/classmap002.phpt index 626b9f8ff66b5..13c82c1b53838 100644 --- a/ext/soap/tests/classmap002.phpt +++ b/ext/soap/tests/classmap002.phpt @@ -7,7 +7,7 @@ soap.wsdl_cache_enabled=0 --FILE-- diff --git a/ext/soap/tests/classmap003.phpt b/ext/soap/tests/classmap003.phpt index 322445fa16af6..31839f841f8f3 100644 --- a/ext/soap/tests/classmap003.phpt +++ b/ext/soap/tests/classmap003.phpt @@ -34,7 +34,7 @@ class LocalSoapClient extends SoapClient { $this->server->addFunction("f"); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { ob_start(); $this->server->handle($request); $response = ob_get_contents(); diff --git a/ext/soap/tests/classmap004.phpt b/ext/soap/tests/classmap004.phpt index 1fbf4c6ccad3d..172a6db7b4483 100644 --- a/ext/soap/tests/classmap004.phpt +++ b/ext/soap/tests/classmap004.phpt @@ -42,7 +42,7 @@ class LocalSoapClient extends SoapClient { $this->server->addFunction("f"); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { ob_start(); $this->server->handle($request); $response = ob_get_contents(); diff --git a/ext/soap/tests/classmap005.phpt b/ext/soap/tests/classmap005.phpt index ce4aa2b66bb85..a39adfa85033a 100644 --- a/ext/soap/tests/classmap005.phpt +++ b/ext/soap/tests/classmap005.phpt @@ -7,7 +7,7 @@ soap.wsdl_cache_enabled=0 --FILE-- diff --git a/ext/soap/tests/classmap006.phpt b/ext/soap/tests/classmap006.phpt index 817a3a883c7eb..c56f876148a1c 100644 --- a/ext/soap/tests/classmap006.phpt +++ b/ext/soap/tests/classmap006.phpt @@ -39,7 +39,7 @@ class LocalSoapClient extends SoapClient { $this->server->addFunction("f"); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { ob_start(); $this->server->handle($request); $response = ob_get_contents(); diff --git a/ext/soap/tests/classmap007.phpt b/ext/soap/tests/classmap007.phpt index b6fe394eaeecb..9a59e647bc96e 100644 --- a/ext/soap/tests/classmap007.phpt +++ b/ext/soap/tests/classmap007.phpt @@ -39,7 +39,7 @@ class LocalSoapClient extends SoapClient { $this->server->addFunction("f"); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { ob_start(); $this->server->handle($request); $response = ob_get_contents(); diff --git a/ext/soap/tests/gh15711.phpt b/ext/soap/tests/gh15711.phpt index b72251cc6f95b..17ff051698fdb 100644 --- a/ext/soap/tests/gh15711.phpt +++ b/ext/soap/tests/gh15711.phpt @@ -28,7 +28,7 @@ enum NonBackedEnum } class TestSoapClient extends SoapClient { - function __doRequest($request, $location, $action, $version, $one_way = 0): ?string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): ?string { echo $request; } } diff --git a/ext/soap/tests/gh16318.phpt b/ext/soap/tests/gh16318.phpt index a0a4c925df051..0c38b6fc8de30 100644 --- a/ext/soap/tests/gh16318.phpt +++ b/ext/soap/tests/gh16318.phpt @@ -15,7 +15,7 @@ $test2["a"] = "a"; $test2[] =& $test2; class TestSoapClient extends SoapClient { - public function __doRequest(string $request, string $location, string $action, int $version, bool $oneWay = false): ?string + public function __doRequest(string $request, string $location, string $action, int $version, bool $oneWay = false, ?string $uriParserClass = null): ?string { die($request); } diff --git a/ext/soap/tests/soap_qname_crash.phpt b/ext/soap/tests/soap_qname_crash.phpt index bcf01d574fab4..53d6904db1c95 100644 --- a/ext/soap/tests/soap_qname_crash.phpt +++ b/ext/soap/tests/soap_qname_crash.phpt @@ -18,6 +18,7 @@ class TestSoapClient extends SoapClient { $action, $version, $one_way = false, + ?string $uriParserClass = null, ): ?string { die($request); } diff --git a/ext/soap/tests/transport001.phpt b/ext/soap/tests/transport001.phpt index 297d0e1288e7e..c735b2e139d76 100644 --- a/ext/soap/tests/transport001.phpt +++ b/ext/soap/tests/transport001.phpt @@ -17,7 +17,7 @@ class LocalSoapClient extends SoapClient { $this->server->addFunction('Add'); } - function __doRequest($request, $location, $action, $version, $one_way = 0): string { + function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string { ob_start(); $this->server->handle($request); $response = ob_get_contents(); diff --git a/ext/soap/tests/typemap003.phpt b/ext/soap/tests/typemap003.phpt index a7b83b6348bba..3f4960f8d5d6b 100644 --- a/ext/soap/tests/typemap003.phpt +++ b/ext/soap/tests/typemap003.phpt @@ -8,7 +8,7 @@ soap.wsdl_cache_enabled=0 --FILE-- diff --git a/ext/soap/tests/typemap004.phpt b/ext/soap/tests/typemap004.phpt index 61b62867205fc..c0feb6b4ebbc8 100644 --- a/ext/soap/tests/typemap004.phpt +++ b/ext/soap/tests/typemap004.phpt @@ -7,7 +7,7 @@ soap.wsdl_cache_enabled=0 --FILE-- diff --git a/ext/soap/tests/typemap008.phpt b/ext/soap/tests/typemap008.phpt index 8abd8039f8d59..7e7012b6ad5ca 100644 --- a/ext/soap/tests/typemap008.phpt +++ b/ext/soap/tests/typemap008.phpt @@ -7,7 +7,7 @@ soap.wsdl_cache_enabled=0 --FILE-- diff --git a/ext/soap/tests/typemap012.phpt b/ext/soap/tests/typemap012.phpt index e31d3ffa0ac48..13bb0c8984796 100644 --- a/ext/soap/tests/typemap012.phpt +++ b/ext/soap/tests/typemap012.phpt @@ -7,7 +7,7 @@ soap.wsdl_cache_enabled=0 --FILE-- #ifdef HAVE_SYS_SOCKET_H @@ -124,16 +125,21 @@ static int php_stream_ftp_stream_close(php_stream_wrapper *wrapper, php_stream * /* {{{ php_ftp_fopen_connect */ static php_stream *php_ftp_fopen_connect(php_stream_wrapper *wrapper, const char *path, const char *mode, int options, zend_string **opened_path, php_stream_context *context, php_stream **preuseid, - php_url **presource, int *puse_ssl, int *puse_ssl_on_data) + php_uri **presource, int *puse_ssl, int *puse_ssl_on_data) { php_stream *stream = NULL, *reuseid = NULL; - php_url *resource = NULL; + php_uri *resource = NULL; int result, use_ssl, use_ssl_on_data = 0; char tmp_line[512]; char *transport; int transport_len; - resource = php_url_parse(path); + uri_handler_t *uri_handler = php_stream_context_get_uri_handler("ftp", context); + if (uri_handler == NULL) { + return NULL; + } + + resource = php_uri_parse_to_struct(uri_handler, path, strlen(path), URI_COMPONENT_READ_RAW, true); if (resource == NULL || resource->path == NULL) { if (resource && presource) { *presource = resource; @@ -254,12 +260,12 @@ static php_stream *php_ftp_fopen_connect(php_stream_wrapper *wrapper, const char if (result >= 300 && result <= 399) { php_stream_notify_info(context, PHP_STREAM_NOTIFY_AUTH_REQUIRED, tmp_line, 0); - if (resource->pass != NULL) { - ZSTR_LEN(resource->pass) = php_raw_url_decode(ZSTR_VAL(resource->pass), ZSTR_LEN(resource->pass)); + if (resource->password != NULL) { + ZSTR_LEN(resource->password) = php_raw_url_decode(ZSTR_VAL(resource->password), ZSTR_LEN(resource->password)); - PHP_FTP_CNTRL_CHK(ZSTR_VAL(resource->pass), ZSTR_LEN(resource->pass), "Invalid password %s") + PHP_FTP_CNTRL_CHK(ZSTR_VAL(resource->password), ZSTR_LEN(resource->password), "Invalid password %s") - php_stream_printf(stream, "PASS %s\r\n", ZSTR_VAL(resource->pass)); + php_stream_printf(stream, "PASS %s\r\n", ZSTR_VAL(resource->password)); } else { /* if the user has configured who they are, send that as the password */ @@ -299,7 +305,7 @@ static php_stream *php_ftp_fopen_connect(php_stream_wrapper *wrapper, const char return stream; connect_errexit: - php_url_free(resource); + php_uri_struct_free(resource); if (stream) { php_stream_close(stream); @@ -404,7 +410,7 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *pa int options, zend_string **opened_path, php_stream_context *context STREAMS_DC) { php_stream *stream = NULL, *datastream = NULL; - php_url *resource = NULL; + php_uri *resource = NULL; char tmp_line[512]; char ip[sizeof("123.123.123.123")]; unsigned short portno; @@ -579,12 +585,12 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *pa /* remember control stream */ datastream->wrapperthis = stream; - php_url_free(resource); + php_uri_struct_free(resource); return datastream; errexit: if (resource) { - php_url_free(resource); + php_uri_struct_free(resource); } if (stream) { php_stream_notify_error(context, PHP_STREAM_NOTIFY_FAILURE, tmp_line, result); @@ -683,7 +689,7 @@ static php_stream * php_stream_ftp_opendir(php_stream_wrapper *wrapper, const ch { php_stream *stream, *reuseid, *datastream = NULL; php_ftp_dirstream_data *dirsdata; - php_url *resource = NULL; + php_uri *resource = NULL; int result = 0, use_ssl, use_ssl_on_data = 0; char *hoststart = NULL, tmp_line[512]; char ip[sizeof("123.123.123.123")]; @@ -745,7 +751,7 @@ static php_stream * php_stream_ftp_opendir(php_stream_wrapper *wrapper, const ch goto opendir_errexit; } - php_url_free(resource); + php_uri_struct_free(resource); dirsdata = emalloc(sizeof *dirsdata); dirsdata->datastream = datastream; @@ -756,7 +762,7 @@ static php_stream * php_stream_ftp_opendir(php_stream_wrapper *wrapper, const ch opendir_errexit: if (resource) { - php_url_free(resource); + php_uri_struct_free(resource); } if (stream) { php_stream_notify_error(context, PHP_STREAM_NOTIFY_FAILURE, tmp_line, result); @@ -773,7 +779,7 @@ static php_stream * php_stream_ftp_opendir(php_stream_wrapper *wrapper, const ch static int php_stream_ftp_url_stat(php_stream_wrapper *wrapper, const char *url, int flags, php_stream_statbuf *ssb, php_stream_context *context) { php_stream *stream = NULL; - php_url *resource = NULL; + php_uri *resource = NULL; int result; char tmp_line[512]; @@ -877,12 +883,12 @@ static int php_stream_ftp_url_stat(php_stream_wrapper *wrapper, const char *url, #endif #endif php_stream_close(stream); - php_url_free(resource); + php_uri_struct_free(resource); return 0; stat_errexit: if (resource) { - php_url_free(resource); + php_uri_struct_free(resource); } if (stream) { php_stream_close(stream); @@ -895,7 +901,7 @@ static int php_stream_ftp_url_stat(php_stream_wrapper *wrapper, const char *url, static int php_stream_ftp_unlink(php_stream_wrapper *wrapper, const char *url, int options, php_stream_context *context) { php_stream *stream = NULL; - php_url *resource = NULL; + php_uri *resource = NULL; int result; char tmp_line[512]; @@ -925,13 +931,13 @@ static int php_stream_ftp_unlink(php_stream_wrapper *wrapper, const char *url, i goto unlink_errexit; } - php_url_free(resource); + php_uri_struct_free(resource); php_stream_close(stream); return 1; unlink_errexit: if (resource) { - php_url_free(resource); + php_uri_struct_free(resource); } if (stream) { php_stream_close(stream); @@ -944,18 +950,29 @@ static int php_stream_ftp_unlink(php_stream_wrapper *wrapper, const char *url, i static int php_stream_ftp_rename(php_stream_wrapper *wrapper, const char *url_from, const char *url_to, int options, php_stream_context *context) { php_stream *stream = NULL; - php_url *resource_from = NULL, *resource_to = NULL; + php_uri *resource_from = NULL, *resource_to = NULL; int result; char tmp_line[512]; - resource_from = php_url_parse(url_from); - resource_to = php_url_parse(url_to); + uri_handler_t *uri_handler = php_stream_context_get_uri_handler("ftp", context); + if (uri_handler == NULL) { + return 0; + } + + resource_from = php_uri_parse_to_struct(uri_handler, url_from, strlen(url_from), URI_COMPONENT_READ_RAW, true); + if (!resource_from) { + return 0; + } + + resource_to = php_uri_parse_to_struct(uri_handler, url_to, strlen(url_to), URI_COMPONENT_READ_RAW, true); + if (!resource_to) { + goto rename_errexit; + } + /* Must be same scheme (ftp/ftp or ftps/ftps), same host, and same port (or a 21/0 0/21 combination which is also "same") Also require paths to/from */ - if (!resource_from || - !resource_to || - !resource_from->scheme || + if (!resource_from->scheme || !resource_to->scheme || !zend_string_equals(resource_from->scheme, resource_to->scheme) || !resource_from->host || @@ -999,17 +1016,14 @@ static int php_stream_ftp_rename(php_stream_wrapper *wrapper, const char *url_fr goto rename_errexit; } - php_url_free(resource_from); - php_url_free(resource_to); + php_uri_struct_free(resource_from); + php_uri_struct_free(resource_to); php_stream_close(stream); return 1; rename_errexit: - if (resource_from) { - php_url_free(resource_from); - } if (resource_to) { - php_url_free(resource_to); + php_uri_struct_free(resource_to); } if (stream) { php_stream_close(stream); @@ -1022,7 +1036,7 @@ static int php_stream_ftp_rename(php_stream_wrapper *wrapper, const char *url_fr static int php_stream_ftp_mkdir(php_stream_wrapper *wrapper, const char *url, int mode, int options, php_stream_context *context) { php_stream *stream = NULL; - php_url *resource = NULL; + php_uri *resource = NULL; int result, recursive = options & PHP_STREAM_MKDIR_RECURSIVE; char tmp_line[512]; @@ -1089,7 +1103,7 @@ static int php_stream_ftp_mkdir(php_stream_wrapper *wrapper, const char *url, in efree(buf); } - php_url_free(resource); + php_uri_struct_free(resource); php_stream_close(stream); if (result < 200 || result > 299) { @@ -1101,7 +1115,7 @@ static int php_stream_ftp_mkdir(php_stream_wrapper *wrapper, const char *url, in mkdir_errexit: if (resource) { - php_url_free(resource); + php_uri_struct_free(resource); } if (stream) { php_stream_close(stream); @@ -1114,7 +1128,7 @@ static int php_stream_ftp_mkdir(php_stream_wrapper *wrapper, const char *url, in static int php_stream_ftp_rmdir(php_stream_wrapper *wrapper, const char *url, int options, php_stream_context *context) { php_stream *stream = NULL; - php_url *resource = NULL; + php_uri *resource = NULL; int result; char tmp_line[512]; @@ -1143,14 +1157,14 @@ static int php_stream_ftp_rmdir(php_stream_wrapper *wrapper, const char *url, in goto rmdir_errexit; } - php_url_free(resource); + php_uri_struct_free(resource); php_stream_close(stream); return 1; rmdir_errexit: if (resource) { - php_url_free(resource); + php_uri_struct_free(resource); } if (stream) { php_stream_close(stream); diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c index 9fefe153622fc..df0b89f894582 100644 --- a/ext/standard/http_fopen_wrapper.c +++ b/ext/standard/http_fopen_wrapper.c @@ -20,6 +20,7 @@ #include "php.h" #include "php_globals.h" +#include "ext/uri/php_uri.h" #include "php_streams.h" #include "php_network.h" #include "php_ini.h" @@ -358,7 +359,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, zval *response_header STREAMS_DC) /* {{{ */ { php_stream *stream = NULL; - php_url *resource = NULL; + php_uri *resource = NULL; int use_ssl; int use_proxy = 0; zend_string *tmp = NULL; @@ -391,7 +392,11 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, return NULL; } - resource = php_url_parse(path); + uri_handler_t *uri_handler = php_stream_context_get_uri_handler("http", context); + if (uri_handler == NULL) { + return NULL; + } + resource = php_uri_parse_to_struct(uri_handler, path, strlen(path), URI_COMPONENT_READ_RAW, true); if (resource == NULL) { return NULL; } @@ -403,7 +408,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, (tmpzval = php_stream_context_get_option(context, wrapper->wops->label, "proxy")) == NULL || Z_TYPE_P(tmpzval) != IS_STRING || Z_STRLEN_P(tmpzval) == 0) { - php_url_free(resource); + php_uri_struct_free(resource); return php_stream_open_wrapper_ex(path, mode, REPORT_ERRORS, NULL, context); } /* Called from a non-http wrapper with http proxying requested (i.e. ftp) */ @@ -416,7 +421,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, if (strpbrk(mode, "awx+")) { php_stream_wrapper_log_error(wrapper, options, "HTTP wrapper does not support writeable connections"); - php_url_free(resource); + php_uri_struct_free(resource); return NULL; } @@ -445,7 +450,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, if (request_fulluri && (strchr(path, '\n') != NULL || strchr(path, '\r') != NULL)) { php_stream_wrapper_log_error(wrapper, options, "HTTP wrapper full URI path does not allow CR or LF characters"); - php_url_free(resource); + php_uri_struct_free(resource); zend_string_release(transport_string); return NULL; } @@ -461,7 +466,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, if (d > timeoutmax) { php_stream_wrapper_log_error(wrapper, options, "timeout must be lower than " ZEND_ULONG_FMT, (zend_ulong)timeoutmax); zend_string_release(transport_string); - php_url_free(resource); + php_uri_struct_free(resource); return NULL; } #ifndef PHP_WIN32 @@ -758,9 +763,9 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, strcat(scratch, ":"); /* Note: password is optional! */ - if (resource->pass) { - php_url_decode(ZSTR_VAL(resource->pass), ZSTR_LEN(resource->pass)); - strcat(scratch, ZSTR_VAL(resource->pass)); + if (resource->password) { + php_url_decode(ZSTR_VAL(resource->password), ZSTR_LEN(resource->password)); + strcat(scratch, ZSTR_VAL(resource->password)); } stmp = php_base64_encode((unsigned char*)scratch, strlen(scratch)); @@ -1094,9 +1099,9 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, header_info.location = NULL; } - php_url_free(resource); + php_uri_struct_free(resource); /* check for invalid redirection URLs */ - if ((resource = php_url_parse(new_path)) == NULL) { + if ((resource = php_uri_parse_to_struct(uri_handler, new_path, strlen(new_path), URI_COMPONENT_READ_RAW, true)) == NULL) { php_stream_wrapper_log_error(wrapper, options, "Invalid redirect URL! %s", new_path); efree(new_path); goto out; @@ -1120,7 +1125,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, /* check for control characters in login, password & path */ if (strncasecmp(new_path, "http://", sizeof("http://") - 1) || strncasecmp(new_path, "https://", sizeof("https://") - 1)) { CHECK_FOR_CNTRL_CHARS(resource->user); - CHECK_FOR_CNTRL_CHARS(resource->pass); + CHECK_FOR_CNTRL_CHARS(resource->password); CHECK_FOR_CNTRL_CHARS(resource->path); } int new_flags = HTTP_WRAPPER_REDIRECTED; @@ -1151,7 +1156,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, } if (resource) { - php_url_free(resource); + php_uri_struct_free(resource); } if (stream) { diff --git a/ext/standard/tests/file/file_get_contents_with_custom_uri_parser.phpt b/ext/standard/tests/file/file_get_contents_with_custom_uri_parser.phpt new file mode 100644 index 0000000000000..7e1ca7327b291 --- /dev/null +++ b/ext/standard/tests/file/file_get_contents_with_custom_uri_parser.phpt @@ -0,0 +1,36 @@ +--TEST-- +Test file_get_contents() function when a custom URI parser is configured +--FILE-- + [ + "uri_parser_class" => null, + ], +]); +var_dump(file_get_contents("https:///example.com", context: $context)); // invalid for parse_url only, valid for the other handlers + +$context = stream_context_create([ + "http" => [ + "uri_parser_class" => \Uri\Rfc3986\Uri::class, + ], +]); +var_dump(file_get_contents("https://éxamplé.com", context: $context)); // invalid for RFC 3986 only, valid for the other handlers + +$context = stream_context_create([ + "http" => [ + "uri_parser_class" => \Uri\WhatWg\Url::class, + ], +]); +var_dump(file_get_contents("https://exa%23mple.org", context: $context)); // invalid for WHATWG only, valid for the other handlers + +?> +--EXPECTF-- +Warning: file_get_contents(https:///example.com): Failed to open stream: operation failed in %s on line %d +bool(false) + +Warning: file_get_contents(https://éxamplé.com): Failed to open stream: operation failed in %s on line %d +bool(false) + +Warning: file_get_contents(https://exa%23mple.org): Failed to open stream: operation failed in %s on line %d +bool(false) diff --git a/ext/standard/url.c b/ext/standard/url.c index 504805484ef2c..c9f73019df104 100644 --- a/ext/standard/url.c +++ b/ext/standard/url.c @@ -25,6 +25,8 @@ #include "file.h" #include "zend_simd.h" #include "Zend/zend_smart_str.h" +#include "Zend/zend_exceptions.h" +#include "ext/uri/php_uri.h" /* {{{ free_url */ PHPAPI void php_url_free(php_url *theurl) @@ -47,6 +49,13 @@ PHPAPI void php_url_free(php_url *theurl) } /* }}} */ +static void parse_url_free_uri(void *uri) +{ + php_url *parse_url_uri = (php_url *) uri; + + php_url_free(parse_url_uri); +} + static void php_replace_controlchars(char *str, size_t len) { unsigned char *s = (unsigned char *)str; @@ -311,7 +320,155 @@ PHPAPI php_url *php_url_parse_ex2(char const *str, size_t length, bool *has_port return ret; } -/* }}} */ + +static zend_result parse_url_read_scheme(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + php_url *parse_url_uri = internal_uri->uri; + + if (parse_url_uri->scheme) { + ZVAL_STR_COPY(retval, parse_url_uri->scheme); + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +static zend_result parse_url_read_username(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + php_url *parse_url_uri = internal_uri->uri; + + if (parse_url_uri->user) { + ZVAL_STR_COPY(retval, parse_url_uri->user); + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +static zend_result parse_url_read_password(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + php_url *parse_url_uri = internal_uri->uri; + + if (parse_url_uri->pass) { + ZVAL_STR_COPY(retval, parse_url_uri->pass); + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +static zend_result parse_url_read_host(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + php_url *parse_url_uri = internal_uri->uri; + + if (parse_url_uri->host) { + ZVAL_STR_COPY(retval, parse_url_uri->host); + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +static zend_result parse_url_read_port(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + php_url *parse_url_uri = internal_uri->uri; + + if (parse_url_uri->port) { + ZVAL_LONG(retval, parse_url_uri->port); + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +static zend_result parse_url_read_path(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + php_url *parse_url_uri = internal_uri->uri; + + if (parse_url_uri->path) { + ZVAL_STR_COPY(retval, parse_url_uri->path); + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +static zend_result parse_url_read_query(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + php_url *parse_url_uri = internal_uri->uri; + + if (parse_url_uri->query) { + ZVAL_STR_COPY(retval, parse_url_uri->query); + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +static zend_result parse_url_read_fragment(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + php_url *parse_url_uri = internal_uri->uri; + + if (parse_url_uri->fragment) { + ZVAL_STR_COPY(retval, parse_url_uri->fragment); + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +static void *parse_url_clone_uri(void *uri) +{ + ZEND_UNREACHABLE(); +} + +static void throw_invalid_uri_exception(void) +{ + zend_throw_exception(uri_invalid_uri_exception_ce, "The specified URI is malformed", 0); +} + +static void *parse_url_parse_uri(const char *uri_str, size_t uri_str_len, const void *base_url, zval *errors, bool silent) +{ + bool has_port; + + php_url *url = php_url_parse_ex2(uri_str, uri_str_len, &has_port); + if (url == NULL && !silent) { + throw_invalid_uri_exception(); + } + + return url; +} + +static zend_string *parse_url_uri_to_string(void *uri, uri_recomposition_mode_t recomposition_mode, bool exclude_fragment) +{ + ZEND_UNREACHABLE(); +} + +const uri_handler_t parse_url_uri_handler = { + .name = URI_PARSER_PHP, + .parse_uri = parse_url_parse_uri, + .clone_uri = parse_url_clone_uri, + .uri_to_string = parse_url_uri_to_string, + .free_uri = parse_url_free_uri, + { + .scheme = {.read_func = parse_url_read_scheme, .write_func = NULL}, + .username = {.read_func = parse_url_read_username, .write_func = NULL}, + .password = {.read_func = parse_url_read_password, .write_func = NULL}, + .host = {.read_func = parse_url_read_host, .write_func = NULL}, + .port = {.read_func = parse_url_read_port, .write_func = NULL}, + .path = {.read_func = parse_url_read_path, .write_func = NULL}, + .query = {.read_func = parse_url_read_query, .write_func = NULL}, + .fragment = {.read_func = parse_url_read_fragment, .write_func = NULL}, + } +}; /* {{{ Parse a URL and return its components */ PHP_FUNCTION(parse_url) @@ -753,3 +910,8 @@ PHP_FUNCTION(get_headers) php_stream_close(stream); } /* }}} */ + +PHP_MINIT_FUNCTION(url) +{ + return uri_handler_register(&parse_url_uri_handler); +} diff --git a/ext/standard/url.h b/ext/standard/url.h index 3885ecece5780..aefc362744cfd 100644 --- a/ext/standard/url.h +++ b/ext/standard/url.h @@ -17,6 +17,8 @@ #ifndef URL_H #define URL_H +PHP_MINIT_FUNCTION(url); + typedef struct php_url { zend_string *scheme; zend_string *user; diff --git a/ext/uri/php_lexbor.c b/ext/uri/php_lexbor.c index 5287bbcd9023d..b7ad297cd5b94 100644 --- a/ext/uri/php_lexbor.c +++ b/ext/uri/php_lexbor.c @@ -562,11 +562,11 @@ void lexbor_request_shutdown(void) lexbor_urls = 0; } -lxb_url_t *lexbor_parse_uri_ex(const zend_string *uri_str, const lxb_url_t *lexbor_base_url, zval *errors, bool silent) +lxb_url_t *lexbor_parse_uri_ex(const char *uri_str, size_t uri_str_len, const lxb_url_t *lexbor_base_url, zval *errors, bool silent) { lexbor_cleanup_parser(); - lxb_url_t *url = lxb_url_parse(&lexbor_parser, lexbor_base_url, (unsigned char *) ZSTR_VAL(uri_str), ZSTR_LEN(uri_str)); + lxb_url_t *url = lxb_url_parse(&lexbor_parser, lexbor_base_url, (unsigned char *) uri_str, uri_str_len); const char *reason = fill_errors(errors); if (url == NULL && !silent) { @@ -577,9 +577,9 @@ lxb_url_t *lexbor_parse_uri_ex(const zend_string *uri_str, const lxb_url_t *lexb return url; } -static void *lexbor_parse_uri(const zend_string *uri_str, const void *base_url, zval *errors, bool silent) +static void *lexbor_parse_uri(const char *uri_str, size_t uri_str_len, const void *base_url, zval *errors, bool silent) { - return lexbor_parse_uri_ex(uri_str, base_url, errors, silent); + return lexbor_parse_uri_ex(uri_str, uri_str_len, base_url, errors, silent); } static void *lexbor_clone_uri(void *uri) diff --git a/ext/uri/php_lexbor.h b/ext/uri/php_lexbor.h index 30d68b5cdf681..8420f7185094f 100644 --- a/ext/uri/php_lexbor.h +++ b/ext/uri/php_lexbor.h @@ -22,7 +22,7 @@ extern const uri_handler_t lexbor_uri_handler; -lxb_url_t *lexbor_parse_uri_ex(const zend_string *uri_str, const lxb_url_t *lexbor_base_url, zval *errors, bool silent); +lxb_url_t *lexbor_parse_uri_ex(const char *uri_str, size_t uri_str_len, const lxb_url_t *lexbor_base_url, zval *errors, bool silent); zend_result lexbor_request_init(void); void lexbor_request_shutdown(void); diff --git a/ext/uri/php_uri.c b/ext/uri/php_uri.c index f5a5b160bba06..2a9c948b8e55e 100644 --- a/ext/uri/php_uri.c +++ b/ext/uri/php_uri.c @@ -25,7 +25,7 @@ #include "Zend/zend_enum.h" #include "ext/standard/info.h" -#include "php_uri_common.h" +#include "php_uri.h" #include "php_lexbor.h" #include "php_uriparser.h" #include "php_uri_arginfo.h" @@ -106,6 +106,201 @@ static HashTable *uri_get_debug_properties(zend_object *object) return result; } +PHPAPI uri_handler_t *php_uri_get_handler(const zend_string *uri_handler_name) +{ + if (uri_handler_name == NULL) { + return uri_handler_by_name(URI_PARSER_PHP, sizeof(URI_PARSER_PHP) - 1); + } + + return uri_handler_by_name(ZSTR_VAL(uri_handler_name), ZSTR_LEN(uri_handler_name)); +} + +ZEND_ATTRIBUTE_NONNULL PHPAPI uri_internal_t *php_uri_parse(const uri_handler_t *uri_handler, const char *uri_str, size_t uri_str_len, bool silent) +{ + uri_internal_t *internal_uri = emalloc(sizeof(*internal_uri)); + internal_uri->handler = uri_handler; + internal_uri->uri = uri_handler->parse_uri(uri_str, uri_str_len, NULL, NULL, silent); + + if (UNEXPECTED(internal_uri->uri == NULL)) { + efree(internal_uri); + return NULL; + } + + return internal_uri; +} + +ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_get_property(const uri_internal_t *internal_uri, uri_property_name_t property_name, uri_component_read_mode_t read_mode, zval *zv) +{ + const uri_property_handler_t *property_handler = uri_property_handler_from_internal_uri(internal_uri, property_name); + if (property_handler == NULL) { + return FAILURE; + } + + return property_handler->read_func(internal_uri, read_mode, zv); +} + +ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_scheme(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv) +{ + return php_uri_get_property(internal_uri, URI_PROPERTY_NAME_SCHEME, read_mode, zv); +} + +ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_username(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv) +{ + return php_uri_get_property(internal_uri, URI_PROPERTY_NAME_USERNAME, read_mode, zv); +} + +ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_password(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv) +{ + return php_uri_get_property(internal_uri, URI_PROPERTY_NAME_PASSWORD, read_mode, zv); +} + +ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_host(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv) +{ + return php_uri_get_property(internal_uri, URI_PROPERTY_NAME_HOST, read_mode, zv); +} + +ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_port(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv) +{ + return php_uri_get_property(internal_uri, URI_PROPERTY_NAME_PORT, read_mode, zv); +} + +ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_path(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv) +{ + return php_uri_get_property(internal_uri, URI_PROPERTY_NAME_PATH, read_mode, zv); +} + +ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_query(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv) +{ + return php_uri_get_property(internal_uri, URI_PROPERTY_NAME_QUERY, read_mode, zv); +} + +ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_fragment(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv) +{ + return php_uri_get_property(internal_uri, URI_PROPERTY_NAME_FRAGMENT, read_mode, zv); +} + +ZEND_ATTRIBUTE_NONNULL PHPAPI void php_uri_free(uri_internal_t *internal_uri) +{ + internal_uri->handler->free_uri(internal_uri->uri); + internal_uri->uri = NULL; + internal_uri->handler = NULL; + efree(internal_uri); +} + +ZEND_ATTRIBUTE_NONNULL PHPAPI php_uri *php_uri_parse_to_struct( + const uri_handler_t *uri_handler, const char *uri_str, size_t uri_str_len, uri_component_read_mode_t read_mode, bool silent +) { + uri_internal_t *uri_internal = php_uri_parse(uri_handler, uri_str, uri_str_len, silent); + if (uri_internal == NULL) { + return NULL; + } + + php_uri *uri = ecalloc(1, sizeof(*uri)); + zval tmp; + zend_result result; + + result = php_uri_get_scheme(uri_internal, read_mode, &tmp); + if (result == FAILURE) { + goto error; + } + if (Z_TYPE(tmp) == IS_STRING) { + uri->scheme = Z_STR(tmp); + } + + result = php_uri_get_username(uri_internal, read_mode, &tmp); + if (result == FAILURE) { + goto error; + } + if (Z_TYPE(tmp) == IS_STRING) { + uri->user = Z_STR(tmp); + } + + result = php_uri_get_password(uri_internal, read_mode, &tmp); + if (result == FAILURE) { + goto error; + } + if (Z_TYPE(tmp) == IS_STRING) { + uri->password = Z_STR(tmp); + } + + result = php_uri_get_host(uri_internal, read_mode, &tmp); + if (result == FAILURE) { + goto error; + } + if (Z_TYPE(tmp) == IS_STRING) { + uri->host = Z_STR(tmp); + } + + result = php_uri_get_port(uri_internal, read_mode, &tmp); + if (result == FAILURE) { + goto error; + } + if (Z_TYPE(tmp) == IS_LONG) { + uri->port = Z_LVAL(tmp); + } + + result = php_uri_get_path(uri_internal, read_mode, &tmp); + if (result == FAILURE) { + goto error; + } + if (Z_TYPE(tmp) == IS_STRING) { + uri->path = Z_STR(tmp); + } + + result = php_uri_get_query(uri_internal, read_mode, &tmp); + if (result == FAILURE) { + goto error; + } + if (Z_TYPE(tmp) == IS_STRING) { + uri->query = Z_STR(tmp); + } + + result = php_uri_get_fragment(uri_internal, read_mode, &tmp); + if (result == FAILURE) { + goto error; + } + if (Z_TYPE(tmp) == IS_STRING) { + uri->fragment = Z_STR(tmp); + } + + php_uri_free(uri_internal); + + return uri; + +error: + php_uri_free(uri_internal); + php_uri_struct_free(uri); + + return NULL; +} + +ZEND_ATTRIBUTE_NONNULL PHPAPI void php_uri_struct_free(php_uri *uri) +{ + if (uri->scheme) { + zend_string_release(uri->scheme); + } + if (uri->user) { + zend_string_release(uri->user); + } + if (uri->password) { + zend_string_release(uri->password); + } + if (uri->host) { + zend_string_release(uri->host); + } + if (uri->path) { + zend_string_release(uri->path); + } + if (uri->query) { + zend_string_release(uri->query); + } + if (uri->fragment) { + zend_string_release(uri->fragment); + } + + efree(uri); +} + /** * Pass the errors parameter by ref to errors_zv for userland, and frees it if * it is not not needed anymore. @@ -136,7 +331,7 @@ static zend_result pass_errors_by_ref_and_free(zval *errors_zv, zval *errors) return SUCCESS; } -PHPAPI void php_uri_instantiate_uri( +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 2) PHPAPI void php_uri_instantiate_uri( INTERNAL_FUNCTION_PARAMETERS, const uri_handler_t *handler, const zend_string *uri_str, const zend_object *base_url_object, bool should_throw, bool should_update_this_object, zval *errors_zv ) { @@ -150,7 +345,7 @@ PHPAPI void php_uri_instantiate_uri( base_url = internal_base_url->uri; } - void *uri = handler->parse_uri(uri_str, base_url, should_throw || errors_zv != NULL ? &errors : NULL, !should_throw); + void *uri = handler->parse_uri(ZSTR_VAL(uri_str), ZSTR_LEN(uri_str), base_url, should_throw || errors_zv != NULL ? &errors : NULL, !should_throw); if (UNEXPECTED(uri == NULL)) { if (should_throw) { zval_ptr_dtor(&errors); @@ -573,7 +768,7 @@ static void uri_unserialize(INTERNAL_FUNCTION_PARAMETERS, const char *handler_na if (internal_uri->uri != NULL) { internal_uri->handler->free_uri(internal_uri->uri); } - internal_uri->uri = internal_uri->handler->parse_uri(Z_STR_P(uri_zv), NULL, NULL, true); + internal_uri->uri = internal_uri->handler->parse_uri(Z_STRVAL_P(uri_zv), Z_STRLEN_P(uri_zv), NULL, NULL, true); if (internal_uri->uri == NULL) { zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(object->ce->name)); RETURN_THROWS(); @@ -762,7 +957,7 @@ PHP_METHOD(Uri_WhatWg_Url, __debugInfo) static zend_object *uri_create_object_handler(zend_class_entry *class_type) { - uri_object_t *uri_object = zend_object_alloc(sizeof(uri_object_t), class_type); + uri_object_t *uri_object = zend_object_alloc(sizeof(*uri_object), class_type); zend_object_std_init(&uri_object->std, class_type); object_properties_init(&uri_object->std, class_type); @@ -806,7 +1001,7 @@ zend_object *uri_clone_obj_handler(zend_object *object) return &new_uri_object->std; } -PHPAPI void php_uri_implementation_set_object_handlers(zend_class_entry *ce, zend_object_handlers *object_handlers) +ZEND_ATTRIBUTE_NONNULL PHPAPI void php_uri_implementation_set_object_handlers(zend_class_entry *ce, zend_object_handlers *object_handlers) { ce->create_object = uri_create_object_handler; ce->default_object_handlers = object_handlers; diff --git a/ext/uri/php_uri.h b/ext/uri/php_uri.h index 9e22c227cbf83..7555be2752b6b 100644 --- a/ext/uri/php_uri.h +++ b/ext/uri/php_uri.h @@ -22,6 +22,37 @@ extern zend_module_entry uri_module_entry; #define phpext_uri_ptr &uri_module_entry -PHPAPI void php_uri_implementation_set_object_handlers(zend_class_entry *ce, zend_object_handlers *object_handlers); +typedef struct php_uri { + zend_string *scheme; + zend_string *user; + zend_string *password; + zend_string *host; + unsigned short port; + zend_string *path; + zend_string *query; + zend_string *fragment; +} php_uri; + +PHPAPI uri_handler_t *php_uri_get_handler(const zend_string *uri_handler_name); +ZEND_ATTRIBUTE_NONNULL PHPAPI uri_internal_t *php_uri_parse(const uri_handler_t *uri_handler, const char *uri_str, size_t uri_str_len, bool silent); +ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_scheme(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv); +ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_username(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv); +ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_password(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv); +ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_host(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv); +ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_port(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv); +ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_path(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv); +ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_query(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv); +ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_fragment(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv); +ZEND_ATTRIBUTE_NONNULL PHPAPI void php_uri_free(uri_internal_t *internal_uri); +ZEND_ATTRIBUTE_NONNULL PHPAPI php_uri *php_uri_parse_to_struct( + const uri_handler_t *uri_handler, const char *uri_str, size_t uri_str_len, uri_component_read_mode_t read_mode, bool silent +); +ZEND_ATTRIBUTE_NONNULL PHPAPI void php_uri_struct_free(php_uri *uri); + +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 2) PHPAPI void php_uri_instantiate_uri( + INTERNAL_FUNCTION_PARAMETERS, const uri_handler_t *handler, const zend_string *uri_str, const zend_object *base_url_object, + bool should_throw, bool should_update_this_object, zval *errors_zv +); +ZEND_ATTRIBUTE_NONNULL PHPAPI void php_uri_implementation_set_object_handlers(zend_class_entry *ce, zend_object_handlers *object_handlers); #endif diff --git a/ext/uri/php_uri_common.h b/ext/uri/php_uri_common.h index 8e5b0c2d2279f..f091f06c83915 100644 --- a/ext/uri/php_uri_common.h +++ b/ext/uri/php_uri_common.h @@ -94,7 +94,7 @@ typedef struct uri_handler_t { * If the silent parameter is true, a Uri\InvalidUriException instance must be thrown. * If the parameter is false, the possible errors should be handled by the caller. */ - void *(*parse_uri)(const zend_string *uri_str, const void *base_url, zval *errors, bool silent); + void *(*parse_uri)(const char *uri_str, size_t uri_str_len, const void *base_url, zval *errors, bool silent); void *(*clone_uri)(void *uri); zend_string *(*uri_to_string)(void *uri, uri_recomposition_mode_t recomposition_mode, bool exclude_fragment); void (*free_uri)(void *uri); @@ -125,6 +125,7 @@ static inline uri_internal_t *uri_internal_from_obj(const zend_object *object) { #define URI_PARSER_RFC3986 "Uri\\Rfc3986\\Uri" #define URI_PARSER_WHATWG "Uri\\WhatWg\\Url" +#define URI_PARSER_PHP "parse_url" #define URI_SERIALIZED_PROPERTY_NAME "uri" zend_result uri_handler_register(const uri_handler_t *uri_handler); diff --git a/ext/uri/php_uriparser.c b/ext/uri/php_uriparser.c index 337e453c6d4df..1744d4c38323e 100644 --- a/ext/uri/php_uriparser.c +++ b/ext/uri/php_uriparser.c @@ -292,12 +292,12 @@ static uriparser_uris_t *uriparser_create_uris(void) return uriparser_uris; } -void *uriparser_parse_uri_ex(const zend_string *uri_str, const uriparser_uris_t *uriparser_base_urls, bool silent) +void *uriparser_parse_uri_ex(const char *uri_str, size_t uri_str_len, const uriparser_uris_t *uriparser_base_urls, bool silent) { UriUriA uri = {0}; /* Parse the URI. */ - if (uriParseSingleUriExMmA(&uri, ZSTR_VAL(uri_str), ZSTR_VAL(uri_str) + ZSTR_LEN(uri_str), NULL, mm) != URI_SUCCESS) { + if (uriParseSingleUriExMmA(&uri, uri_str, uri_str + uri_str_len, NULL, mm) != URI_SUCCESS) { if (!silent) { zend_throw_exception(uri_invalid_uri_exception_ce, "The specified URI is malformed", 0); } @@ -347,9 +347,9 @@ void *uriparser_parse_uri_ex(const zend_string *uri_str, const uriparser_uris_t return NULL; } -void *uriparser_parse_uri(const zend_string *uri_str, const void *base_url, zval *errors, bool silent) +void *uriparser_parse_uri(const char *uri_str, size_t uri_str_len, const void *base_url, zval *errors, bool silent) { - return uriparser_parse_uri_ex(uri_str, base_url, silent); + return uriparser_parse_uri_ex(uri_str, uri_str_len, base_url, silent); } /* TODO make the clone handler accept a flag to distinguish between clone() calls and withers. diff --git a/ext/uri/php_uriparser.h b/ext/uri/php_uriparser.h index 1f35c7e69d7a0..19ba69f3444d0 100644 --- a/ext/uri/php_uriparser.h +++ b/ext/uri/php_uriparser.h @@ -32,6 +32,6 @@ PHP_MINIT_FUNCTION(uri_uriparser); zend_result uriparser_read_userinfo(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval); -void *uriparser_parse_uri_ex(const zend_string *uri_str, const uriparser_uris_t *uriparser_base_url, bool silent); +void *uriparser_parse_uri_ex(const char *uri_str, size_t uri_str_len, const uriparser_uris_t *uriparser_base_url, bool silent); #endif diff --git a/main/streams/php_stream_context.h b/main/streams/php_stream_context.h index b983bbb10efe2..6f0cc6f3d6af8 100644 --- a/main/streams/php_stream_context.h +++ b/main/streams/php_stream_context.h @@ -65,6 +65,10 @@ PHPAPI void php_stream_context_set_option(php_stream_context *context, const char *wrappername, const char *optionname, zval *optionvalue); void php_stream_context_unset_option(php_stream_context *context, const char *wrappername, const char *optionname); + +struct uri_handler_t; + +PHPAPI struct uri_handler_t *php_stream_context_get_uri_handler(const char *wrappername, php_stream_context *context); PHPAPI php_stream_notifier *php_stream_notification_alloc(void); PHPAPI void php_stream_notification_free(php_stream_notifier *notifier); END_EXTERN_C() diff --git a/main/streams/streams.c b/main/streams/streams.c index 2eef790863f61..8f838cdbf5cce 100644 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -28,6 +28,7 @@ #include "ext/standard/file.h" #include "ext/standard/basic_functions.h" /* for BG(CurrentStatFile) */ #include "ext/standard/php_string.h" /* for php_memnstr, used by php_stream_get_record() */ +#include "ext/uri/php_uri.h" #include #include #include "php_streams_int.h" @@ -2460,6 +2461,24 @@ void php_stream_context_unset_option(php_stream_context *context, } /* }}} */ +PHPAPI struct uri_handler_t *php_stream_context_get_uri_handler(const char *wrappername, php_stream_context *context) +{ + if (context == NULL) { + return php_uri_get_handler(NULL); + } + + zval *uri_handler_name = php_stream_context_get_option(context, wrappername, "uri_parser_class"); + if (uri_handler_name == NULL) { + return php_uri_get_handler(NULL); + } + + if (Z_TYPE_P(uri_handler_name) != IS_STRING) { + return NULL; + } + + return php_uri_get_handler(Z_STR_P(uri_handler_name)); +} + /* {{{ php_stream_dirent_alphasort */ PHPAPI int php_stream_dirent_alphasort(const zend_string **a, const zend_string **b) {