diff --git a/ext/uri/config.m4 b/ext/uri/config.m4 index 08dc044d8d29f..25e2f34b62eaf 100644 --- a/ext/uri/config.m4 +++ b/ext/uri/config.m4 @@ -5,6 +5,7 @@ PHP_INSTALL_HEADERS([ext/uri], m4_normalize([ php_lexbor.h php_uri.h php_uri_common.h + php_uriparser.h ])) AC_DEFINE([URI_ENABLE_ANSI], [1], [Define to 1 for enabling ANSI support of uriparser.]) @@ -17,6 +18,6 @@ $URIPARSER_DIR/src/UriMemory.c $URIPARSER_DIR/src/UriNormalize.c $URIPARSER_DIR/ $URIPARSER_DIR/src/UriParse.c $URIPARSER_DIR/src/UriParseBase.c $URIPARSER_DIR/src/UriQuery.c \ $URIPARSER_DIR/src/UriRecompose.c $URIPARSER_DIR/src/UriResolve.c $URIPARSER_DIR/src/UriShorten.c" -PHP_NEW_EXTENSION(uri, [php_lexbor.c php_uri.c php_uri_common.c $URIPARSER_SOURCES], [no],,[-I$ext_srcdir/$URIPARSER_DIR/include -DURI_STATIC_BUILD -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1]) +PHP_NEW_EXTENSION(uri, [php_lexbor.c php_uri.c php_uri_common.c php_uriparser.c $URIPARSER_SOURCES], [no],,[-I$ext_srcdir/$URIPARSER_DIR/include -DURI_STATIC_BUILD -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1]) PHP_ADD_EXTENSION_DEP(uri, lexbor) PHP_ADD_BUILD_DIR($ext_builddir/$URIPARSER_DIR/src $ext_builddir/$URIPARSER_DIR/include) diff --git a/ext/uri/config.w32 b/ext/uri/config.w32 index 9c6af0cc5fa7b..d0fc4fb89c98b 100644 --- a/ext/uri/config.w32 +++ b/ext/uri/config.w32 @@ -1,9 +1,9 @@ -EXTENSION("uri", "php_lexbor.c php_uri.c php_uri_common.c", false /* never shared */, "/I ext/lexbor /I ext/uri/uriparser/include /DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); +EXTENSION("uri", "php_lexbor.c php_uri.c php_uri_common.c php_uriparser.c", false /* never shared */, "/I ext/lexbor /I ext/uri/uriparser/include /DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); AC_DEFINE("URI_ENABLE_ANSI", 1, "Define to 1 for enabling ANSI support of uriparser.") AC_DEFINE("URI_NO_UNICODE", 1, "Define to 1 for disabling unicode support of uriparser.") ADD_FLAG("CFLAGS_URI", "/D URI_STATIC_BUILD"); ADD_EXTENSION_DEP('uri', 'lexbor'); -ADD_SOURCES("ext/uri/uriparser/src", "UriCommon.c UriCompare.c UriEscape.c UriFile.c UriIp4.c UriIp4Base.c UriMemory.c UriNormalize.c UriNormalizeBase.c UriParse.c UriParseBase.c UriQuery.c UriRecompose.c UriShorten.c", "uri"); -PHP_INSTALL_HEADERS("ext/uri", "php_lexbor.h php_uri.h php_uri_common.h uriparser/src uriparser/include"); +ADD_SOURCES("ext/uri/uriparser/src", "UriCommon.c UriCompare.c UriEscape.c UriFile.c UriIp4.c UriIp4Base.c UriMemory.c UriNormalize.c UriNormalizeBase.c UriParse.c UriParseBase.c UriQuery.c UriRecompose.c UriResolve.c UriShorten.c", "uri"); +PHP_INSTALL_HEADERS("ext/uri", "php_lexbor.h php_uri.h php_uri_common.h php_uriparser.h uriparser/src uriparser/include"); diff --git a/ext/uri/php_uri.c b/ext/uri/php_uri.c index 5b2e21b1625a3..f5a5b160bba06 100644 --- a/ext/uri/php_uri.c +++ b/ext/uri/php_uri.c @@ -25,12 +25,14 @@ #include "Zend/zend_enum.h" #include "ext/standard/info.h" -#include "php_uri.h" #include "php_uri_common.h" #include "php_lexbor.h" +#include "php_uriparser.h" #include "php_uri_arginfo.h" #include "uriparser/src/UriConfig.h" +zend_class_entry *uri_rfc3986_uri_ce; +zend_object_handlers uri_rfc3986_uri_object_handlers; zend_class_entry *uri_whatwg_url_ce; zend_object_handlers uri_whatwg_uri_object_handlers; zend_class_entry *uri_comparison_mode_ce; @@ -104,67 +106,6 @@ static HashTable *uri_get_debug_properties(zend_object *object) return result; } -PHP_METHOD(Uri_WhatWg_InvalidUrlException, __construct) -{ - zend_string *message = NULL; - zval *errors = NULL; - zend_long code = 0; - zval *previous = NULL; - - ZEND_PARSE_PARAMETERS_START(0, 4) - Z_PARAM_OPTIONAL - Z_PARAM_STR(message) - Z_PARAM_ARRAY(errors) - Z_PARAM_LONG(code) - Z_PARAM_OBJECT_OF_CLASS_OR_NULL(previous, zend_ce_throwable) - ZEND_PARSE_PARAMETERS_END(); - - if (zend_update_exception_properties(INTERNAL_FUNCTION_PARAM_PASSTHRU, message, code, previous) == FAILURE) { - RETURN_THROWS(); - } - - if (errors == NULL) { - zval tmp; - ZVAL_EMPTY_ARRAY(&tmp); - zend_update_property(uri_whatwg_invalid_url_exception_ce, Z_OBJ_P(ZEND_THIS), ZEND_STRL("errors"), &tmp); - } else { - zend_update_property(uri_whatwg_invalid_url_exception_ce, Z_OBJ_P(ZEND_THIS), ZEND_STRL("errors"), errors); - } - if (EG(exception)) { - RETURN_THROWS(); - } -} - -PHP_METHOD(Uri_WhatWg_UrlValidationError, __construct) -{ - zend_string *context; - zval *type; - bool failure; - - ZEND_PARSE_PARAMETERS_START(3, 3) - Z_PARAM_STR(context) - Z_PARAM_OBJECT_OF_CLASS(type, uri_whatwg_url_validation_error_type_ce) - Z_PARAM_BOOL(failure) - ZEND_PARSE_PARAMETERS_END(); - - zend_update_property_str(uri_whatwg_url_validation_error_ce, Z_OBJ_P(ZEND_THIS), ZEND_STRL("context"), context); - if (EG(exception)) { - RETURN_THROWS(); - } - - zend_update_property_ex(uri_whatwg_url_validation_error_ce, Z_OBJ_P(ZEND_THIS), ZSTR_KNOWN(ZEND_STR_TYPE), type); - if (EG(exception)) { - RETURN_THROWS(); - } - - zval failure_zv; - ZVAL_BOOL(&failure_zv, failure); - zend_update_property(uri_whatwg_url_validation_error_ce, Z_OBJ_P(ZEND_THIS), ZEND_STRL("failure"), &failure_zv); - if (EG(exception)) { - RETURN_THROWS(); - } -} - /** * Pass the errors parameter by ref to errors_zv for userland, and frees it if * it is not not needed anymore. @@ -242,6 +183,91 @@ PHPAPI void php_uri_instantiate_uri( uri_object->internal.uri = uri; } +static void create_rfc3986_uri(INTERNAL_FUNCTION_PARAMETERS, bool is_constructor) +{ + zend_string *uri_str; + zend_object *base_url_object = NULL; + + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_PATH_STR(uri_str) + Z_PARAM_OPTIONAL + Z_PARAM_OBJ_OF_CLASS_OR_NULL(base_url_object, uri_rfc3986_uri_ce) + ZEND_PARSE_PARAMETERS_END(); + + php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, &uriparser_uri_handler, uri_str, base_url_object, is_constructor, is_constructor, NULL); +} + +PHP_METHOD(Uri_Rfc3986_Uri, parse) +{ + create_rfc3986_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, false); +} + +PHP_METHOD(Uri_Rfc3986_Uri, __construct) +{ + create_rfc3986_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, true); +} + +PHP_METHOD(Uri_WhatWg_InvalidUrlException, __construct) +{ + zend_string *message = NULL; + zval *errors = NULL; + zend_long code = 0; + zval *previous = NULL; + + ZEND_PARSE_PARAMETERS_START(0, 4) + Z_PARAM_OPTIONAL + Z_PARAM_STR(message) + Z_PARAM_ARRAY(errors) + Z_PARAM_LONG(code) + Z_PARAM_OBJECT_OF_CLASS_OR_NULL(previous, zend_ce_throwable) + ZEND_PARSE_PARAMETERS_END(); + + if (zend_update_exception_properties(INTERNAL_FUNCTION_PARAM_PASSTHRU, message, code, previous) == FAILURE) { + RETURN_THROWS(); + } + + if (errors == NULL) { + zval tmp; + ZVAL_EMPTY_ARRAY(&tmp); + zend_update_property(uri_whatwg_invalid_url_exception_ce, Z_OBJ_P(ZEND_THIS), ZEND_STRL("errors"), &tmp); + } else { + zend_update_property(uri_whatwg_invalid_url_exception_ce, Z_OBJ_P(ZEND_THIS), ZEND_STRL("errors"), errors); + } + if (EG(exception)) { + RETURN_THROWS(); + } +} + +PHP_METHOD(Uri_WhatWg_UrlValidationError, __construct) +{ + zend_string *context; + zval *type; + bool failure; + + ZEND_PARSE_PARAMETERS_START(3, 3) + Z_PARAM_STR(context) + Z_PARAM_OBJECT_OF_CLASS(type, uri_whatwg_url_validation_error_type_ce) + Z_PARAM_BOOL(failure) + ZEND_PARSE_PARAMETERS_END(); + + zend_update_property_str(uri_whatwg_url_validation_error_ce, Z_OBJ_P(ZEND_THIS), ZEND_STRL("context"), context); + if (EG(exception)) { + RETURN_THROWS(); + } + + zend_update_property_ex(uri_whatwg_url_validation_error_ce, Z_OBJ_P(ZEND_THIS), ZSTR_KNOWN(ZEND_STR_TYPE), type); + if (EG(exception)) { + RETURN_THROWS(); + } + + zval failure_zv; + ZVAL_BOOL(&failure_zv, failure); + zend_update_property(uri_whatwg_url_validation_error_ce, Z_OBJ_P(ZEND_THIS), ZEND_STRL("failure"), &failure_zv); + if (EG(exception)) { + RETURN_THROWS(); + } +} + static void create_whatwg_uri(INTERNAL_FUNCTION_PARAMETERS, bool is_constructor) { zend_string *uri_str; @@ -268,6 +294,109 @@ PHP_METHOD(Uri_WhatWg_Url, __construct) create_whatwg_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, true); } +PHP_METHOD(Uri_Rfc3986_Uri, getScheme) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_SCHEME, URI_COMPONENT_READ_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getRawScheme) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_SCHEME, URI_COMPONENT_READ_RAW); +} + +static void read_uriparser_userinfo(INTERNAL_FUNCTION_PARAMETERS, uri_component_read_mode_t read_mode) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + uri_internal_t *internal_uri = Z_URI_INTERNAL_P(ZEND_THIS); + URI_ASSERT_INITIALIZATION(internal_uri); + + if (UNEXPECTED(uriparser_read_userinfo(internal_uri, read_mode, return_value) == FAILURE)) { + zend_throw_error(NULL, "The userinfo component cannot be retrieved"); + RETURN_THROWS(); + } +} + +PHP_METHOD(Uri_Rfc3986_Uri, getUserInfo) +{ + read_uriparser_userinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_COMPONENT_READ_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getRawUserInfo) +{ + read_uriparser_userinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_COMPONENT_READ_RAW); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getUsername) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_USERNAME, URI_COMPONENT_READ_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getRawUsername) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_USERNAME, URI_COMPONENT_READ_RAW); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getPassword) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PASSWORD, URI_COMPONENT_READ_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getRawPassword) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PASSWORD, URI_COMPONENT_READ_RAW); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getHost) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_HOST, URI_COMPONENT_READ_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getRawHost) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_HOST, URI_COMPONENT_READ_RAW); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getPort) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PORT, URI_COMPONENT_READ_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getPath) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PATH, URI_COMPONENT_READ_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getRawPath) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PATH, URI_COMPONENT_READ_RAW); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getQuery) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_QUERY, URI_COMPONENT_READ_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getRawQuery) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_QUERY, URI_COMPONENT_READ_RAW); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getFragment) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_FRAGMENT, URI_COMPONENT_READ_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getRawFragment) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_FRAGMENT, URI_COMPONENT_READ_RAW); +} + +static void throw_cannot_recompose_uri_to_string(zend_object *object) +{ + zend_throw_exception_ex(NULL, 0, "Cannot recompose %s to a string", ZSTR_VAL(object->ce->name)); +} + static void uri_equals(INTERNAL_FUNCTION_PARAMETERS, zend_object *that_object, zend_object *comparison_mode) { zend_object *this_object = Z_OBJ_P(ZEND_THIS); @@ -293,7 +422,7 @@ static void uri_equals(INTERNAL_FUNCTION_PARAMETERS, zend_object *that_object, z zend_string *this_str = this_internal_uri->handler->uri_to_string( this_internal_uri->uri, URI_RECOMPOSITION_NORMALIZED_ASCII, exclude_fragment); if (this_str == NULL) { - zend_throw_exception_ex(NULL, 0, "Cannot recompose %s to string", ZSTR_VAL(this_object->ce->name)); + throw_cannot_recompose_uri_to_string(this_object); RETURN_THROWS(); } @@ -301,7 +430,7 @@ static void uri_equals(INTERNAL_FUNCTION_PARAMETERS, zend_object *that_object, z that_internal_uri->uri, URI_RECOMPOSITION_NORMALIZED_ASCII, exclude_fragment); if (that_str == NULL) { zend_string_release(this_str); - zend_throw_exception_ex(NULL, 0, "Cannot recompose %s to string", ZSTR_VAL(that_object->ce->name)); + throw_cannot_recompose_uri_to_string(that_object); RETURN_THROWS(); } @@ -311,6 +440,99 @@ static void uri_equals(INTERNAL_FUNCTION_PARAMETERS, zend_object *that_object, z zend_string_release(that_str); } +PHP_METHOD(Uri_Rfc3986_Uri, equals) +{ + zend_object *that_object; + zend_object *comparison_mode = NULL; + + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_OBJ_OF_CLASS(that_object, uri_rfc3986_uri_ce) + Z_PARAM_OPTIONAL + Z_PARAM_OBJ_OF_CLASS(comparison_mode, uri_comparison_mode_ce) + ZEND_PARSE_PARAMETERS_END(); + + uri_equals(INTERNAL_FUNCTION_PARAM_PASSTHRU, that_object, comparison_mode); +} + +PHP_METHOD(Uri_Rfc3986_Uri, toRawString) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zend_object *this_object = Z_OBJ_P(ZEND_THIS); + uri_internal_t *internal_uri = uri_internal_from_obj(this_object); + URI_ASSERT_INITIALIZATION(internal_uri); + + zend_string *uri_str = internal_uri->handler->uri_to_string(internal_uri->uri, URI_RECOMPOSITION_RAW_ASCII, false); + if (uri_str == NULL) { + throw_cannot_recompose_uri_to_string(this_object); + RETURN_THROWS(); + } + + RETURN_STR(uri_str); +} + +PHP_METHOD(Uri_Rfc3986_Uri, toString) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zend_object *this_object = Z_OBJ_P(ZEND_THIS); + uri_internal_t *internal_uri = uri_internal_from_obj(this_object); + URI_ASSERT_INITIALIZATION(internal_uri); + + zend_string *uri_str = internal_uri->handler->uri_to_string(internal_uri->uri, URI_RECOMPOSITION_NORMALIZED_ASCII, false); + if (uri_str == NULL) { + throw_cannot_recompose_uri_to_string(this_object); + RETURN_THROWS(); + } + + RETURN_STR(uri_str); +} + +PHP_METHOD(Uri_Rfc3986_Uri, resolve) +{ + zend_string *uri_str; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_PATH_STR(uri_str) + ZEND_PARSE_PARAMETERS_END(); + + zend_object *this_object = Z_OBJ_P(ZEND_THIS); + uri_internal_t *internal_uri = uri_internal_from_obj(this_object); + URI_ASSERT_INITIALIZATION(internal_uri); + + php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, internal_uri->handler, uri_str, this_object, true, false, NULL); +} + +PHP_METHOD(Uri_Rfc3986_Uri, __serialize) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zend_object *this_object = Z_OBJ_P(ZEND_THIS); + uri_internal_t *internal_uri = uri_internal_from_obj(this_object); + URI_ASSERT_INITIALIZATION(internal_uri); + + /* Serialize state: "uri" key in the first array */ + zend_string *uri_str = internal_uri->handler->uri_to_string(internal_uri->uri, URI_RECOMPOSITION_RAW_ASCII, false); + if (uri_str == NULL) { + throw_cannot_recompose_uri_to_string(this_object); + RETURN_THROWS(); + } + zval tmp; + ZVAL_STR(&tmp, uri_str); + + array_init(return_value); + + zval arr; + array_init(&arr); + zend_hash_str_add_new(Z_ARRVAL(arr), URI_SERIALIZED_PROPERTY_NAME, sizeof(URI_SERIALIZED_PROPERTY_NAME) - 1, &tmp); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &arr); + + /* Serialize regular properties: second array */ + ZVAL_ARR(&arr, this_object->handlers->get_properties(this_object)); + Z_TRY_ADDREF(arr); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &arr); +} + static void uri_unserialize(INTERNAL_FUNCTION_PARAMETERS, const char *handler_name) { HashTable *data; @@ -371,29 +593,33 @@ static void uri_unserialize(INTERNAL_FUNCTION_PARAMETERS, const char *handler_na } } -PHP_METHOD(Uri_WhatWg_Url, getScheme) +PHP_METHOD(Uri_Rfc3986_Uri, __unserialize) { - uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_SCHEME, URI_COMPONENT_READ_NORMALIZED_ASCII); + uri_unserialize(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PARSER_RFC3986); } -PHP_METHOD(Uri_WhatWg_Url, withScheme) +PHP_METHOD(Uri_Rfc3986_Uri, __debugInfo) { - uri_write_component_str(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_SCHEME); + ZEND_PARSE_PARAMETERS_NONE(); + + zend_object *object = Z_OBJ_P(ZEND_THIS); + + RETURN_ARR(uri_get_debug_properties(object)); } -PHP_METHOD(Uri_WhatWg_Url, getUsername) +PHP_METHOD(Uri_WhatWg_Url, getScheme) { - uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_USERNAME, URI_COMPONENT_READ_NORMALIZED_ASCII); + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_SCHEME, URI_COMPONENT_READ_NORMALIZED_ASCII); } -PHP_METHOD(Uri_WhatWg_Url, withUsername) +PHP_METHOD(Uri_WhatWg_Url, withScheme) { - uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_USERNAME); + uri_write_component_str(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_SCHEME); } -PHP_METHOD(Uri_WhatWg_Url, getPassword) +PHP_METHOD(Uri_WhatWg_Url, withUsername) { - uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PASSWORD, URI_COMPONENT_READ_NORMALIZED_ASCII); + uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_USERNAME); } PHP_METHOD(Uri_WhatWg_Url, withPassword) @@ -416,41 +642,21 @@ PHP_METHOD(Uri_WhatWg_Url, withHost) uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_HOST); } -PHP_METHOD(Uri_WhatWg_Url, getPort) -{ - uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PORT, URI_COMPONENT_READ_NORMALIZED_ASCII); -} - PHP_METHOD(Uri_WhatWg_Url, withPort) { uri_write_component_long_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PORT); } -PHP_METHOD(Uri_WhatWg_Url, getPath) -{ - uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PATH, URI_COMPONENT_READ_NORMALIZED_ASCII); -} - PHP_METHOD(Uri_WhatWg_Url, withPath) { uri_write_component_str(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PATH); } -PHP_METHOD(Uri_WhatWg_Url, getQuery) -{ - uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_QUERY, URI_COMPONENT_READ_NORMALIZED_ASCII); -} - PHP_METHOD(Uri_WhatWg_Url, withQuery) { uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_QUERY); } -PHP_METHOD(Uri_WhatWg_Url, getFragment) -{ - uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_FRAGMENT, URI_COMPONENT_READ_NORMALIZED_ASCII); -} - PHP_METHOD(Uri_WhatWg_Url, withFragment) { uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_FRAGMENT); @@ -521,7 +727,7 @@ PHP_METHOD(Uri_WhatWg_Url, __serialize) /* Serialize state: "uri" key in the first array */ zend_string *uri_str = internal_uri->handler->uri_to_string(internal_uri->uri, URI_RECOMPOSITION_RAW_ASCII, false); if (uri_str == NULL) { - zend_throw_exception_ex(NULL, 0, "Cannot recompose %s to string", ZSTR_VAL(this_object->ce->name)); + throw_cannot_recompose_uri_to_string(this_object); RETURN_THROWS(); } zval tmp; @@ -629,6 +835,9 @@ zend_result uri_handler_register(const uri_handler_t *uri_handler) static PHP_MINIT_FUNCTION(uri) { + uri_rfc3986_uri_ce = register_class_Uri_Rfc3986_Uri(); + php_uri_implementation_set_object_handlers(uri_rfc3986_uri_ce, &uri_rfc3986_uri_object_handlers); + uri_whatwg_url_ce = register_class_Uri_WhatWg_Url(); php_uri_implementation_set_object_handlers(uri_whatwg_url_ce, &uri_whatwg_uri_object_handlers); @@ -641,6 +850,10 @@ static PHP_MINIT_FUNCTION(uri) zend_hash_init(&uri_handlers, 4, NULL, NULL, true); + if (PHP_MINIT(uri_uriparser)(INIT_FUNC_ARGS_PASSTHRU) == FAILURE) { + return FAILURE; + } + if (uri_handler_register(&lexbor_uri_handler) == FAILURE) { return FAILURE; } diff --git a/ext/uri/php_uri.stub.php b/ext/uri/php_uri.stub.php index ef49e4ba6f968..9fbd40d98e5e9 100644 --- a/ext/uri/php_uri.stub.php +++ b/ext/uri/php_uri.stub.php @@ -20,6 +20,64 @@ enum UriComparisonMode } } +namespace Uri\Rfc3986 { + /** @strict-properties */ + final readonly class Uri + { + public static function parse(string $uri, ?\Uri\Rfc3986\Uri $baseUrl = null): ?static {} + + public function __construct(string $uri, ?\Uri\Rfc3986\Uri $baseUrl = null) {} + + public function getScheme(): ?string {} + + public function getRawScheme(): ?string {} + + public function getUserInfo(): ?string {} + + public function getRawUserInfo(): ?string {} + + public function getUsername(): ?string {} + + public function getRawUsername(): ?string {} + + public function getPassword(): ?string {} + + public function getRawPassword(): ?string {} + + public function getHost(): ?string {} + + public function getRawHost(): ?string {} + + public function getPort(): ?int {} + + public function getPath(): string {} + + public function getRawPath(): string {} + + public function getQuery(): ?string {} + + public function getRawQuery(): ?string {} + + public function getFragment(): ?string {} + + public function getRawFragment(): ?string {} + + public function equals(\Uri\Rfc3986\Uri $uri, \Uri\UriComparisonMode $comparisonMode = \Uri\UriComparisonMode::ExcludeFragment): bool {} + + public function toString(): string {} + + public function toRawString(): string {} + + public function resolve(string $uri): static {} + + public function __serialize(): array {} + + public function __unserialize(array $data): void {} + + public function __debugInfo(): array {} + } +} + namespace Uri\WhatWg { /** @strict-properties */ class InvalidUrlException extends \Uri\InvalidUriException @@ -85,10 +143,12 @@ public function getScheme(): string {} public function withScheme(string $scheme): static {} + /** @implementation-alias Uri\Rfc3986\Uri::getUsername */ public function getUsername(): ?string {} public function withUsername(?string $username): static {} + /** @implementation-alias Uri\Rfc3986\Uri::getPassword */ public function getPassword(): ?string {} public function withPassword(#[\SensitiveParameter] ?string $password): static {} @@ -99,18 +159,22 @@ public function getUnicodeHost(): ?string {} public function withHost(?string $host): static {} + /** @implementation-alias Uri\Rfc3986\Uri::getPort */ public function getPort(): ?int {} public function withPort(?int $port): static {} + /** @implementation-alias Uri\Rfc3986\Uri::getPath */ public function getPath(): string {} public function withPath(string $path): static {} + /** @implementation-alias Uri\Rfc3986\Uri::getQuery */ public function getQuery(): ?string {} public function withQuery(?string $query): static {} + /** @implementation-alias Uri\Rfc3986\Uri::getFragment */ public function getFragment(): ?string {} public function withFragment(?string $fragment): static {} diff --git a/ext/uri/php_uri_arginfo.h b/ext/uri/php_uri_arginfo.h index 0ae755a9f70dc..65630f113a3d3 100644 --- a/ext/uri/php_uri_arginfo.h +++ b/ext/uri/php_uri_arginfo.h @@ -1,5 +1,74 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 1945c28deef13c2af552b18c2a5a6c7798d4aeec */ + * Stub hash: e2c448000b1e00485bc988f073ea61dfc984e953 */ + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_parse, 0, 1, IS_STATIC, 1) + ZEND_ARG_TYPE_INFO(0, uri, IS_STRING, 0) + ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, baseUrl, Uri\\Rfc3986\\\125ri, 1, "null") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Uri_Rfc3986_Uri___construct, 0, 0, 1) + ZEND_ARG_TYPE_INFO(0, uri, IS_STRING, 0) + ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, baseUrl, Uri\\Rfc3986\\\125ri, 1, "null") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_getScheme, 0, 0, IS_STRING, 1) +ZEND_END_ARG_INFO() + +#define arginfo_class_Uri_Rfc3986_Uri_getRawScheme arginfo_class_Uri_Rfc3986_Uri_getScheme + +#define arginfo_class_Uri_Rfc3986_Uri_getUserInfo arginfo_class_Uri_Rfc3986_Uri_getScheme + +#define arginfo_class_Uri_Rfc3986_Uri_getRawUserInfo arginfo_class_Uri_Rfc3986_Uri_getScheme + +#define arginfo_class_Uri_Rfc3986_Uri_getUsername arginfo_class_Uri_Rfc3986_Uri_getScheme + +#define arginfo_class_Uri_Rfc3986_Uri_getRawUsername arginfo_class_Uri_Rfc3986_Uri_getScheme + +#define arginfo_class_Uri_Rfc3986_Uri_getPassword arginfo_class_Uri_Rfc3986_Uri_getScheme + +#define arginfo_class_Uri_Rfc3986_Uri_getRawPassword arginfo_class_Uri_Rfc3986_Uri_getScheme + +#define arginfo_class_Uri_Rfc3986_Uri_getHost arginfo_class_Uri_Rfc3986_Uri_getScheme + +#define arginfo_class_Uri_Rfc3986_Uri_getRawHost arginfo_class_Uri_Rfc3986_Uri_getScheme + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_getPort, 0, 0, IS_LONG, 1) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_getPath, 0, 0, IS_STRING, 0) +ZEND_END_ARG_INFO() + +#define arginfo_class_Uri_Rfc3986_Uri_getRawPath arginfo_class_Uri_Rfc3986_Uri_getPath + +#define arginfo_class_Uri_Rfc3986_Uri_getQuery arginfo_class_Uri_Rfc3986_Uri_getScheme + +#define arginfo_class_Uri_Rfc3986_Uri_getRawQuery arginfo_class_Uri_Rfc3986_Uri_getScheme + +#define arginfo_class_Uri_Rfc3986_Uri_getFragment arginfo_class_Uri_Rfc3986_Uri_getScheme + +#define arginfo_class_Uri_Rfc3986_Uri_getRawFragment arginfo_class_Uri_Rfc3986_Uri_getScheme + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_equals, 0, 1, _IS_BOOL, 0) + ZEND_ARG_OBJ_INFO(0, uri, Uri\\Rfc3986\\\125ri, 0) + ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, comparisonMode, Uri\\\125riComparisonMode, 0, "Uri\\UriComparisonMode::ExcludeFragment") +ZEND_END_ARG_INFO() + +#define arginfo_class_Uri_Rfc3986_Uri_toString arginfo_class_Uri_Rfc3986_Uri_getPath + +#define arginfo_class_Uri_Rfc3986_Uri_toRawString arginfo_class_Uri_Rfc3986_Uri_getPath + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_resolve, 0, 1, IS_STATIC, 0) + ZEND_ARG_TYPE_INFO(0, uri, IS_STRING, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri___serialize, 0, 0, IS_ARRAY, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri___unserialize, 0, 1, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) +ZEND_END_ARG_INFO() + +#define arginfo_class_Uri_Rfc3986_Uri___debugInfo arginfo_class_Uri_Rfc3986_Uri___serialize ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Uri_WhatWg_InvalidUrlException___construct, 0, 0, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, message, IS_STRING, 0, "\"\"") @@ -26,54 +95,51 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Uri_WhatWg_Url___construct, 0, 0, 1) ZEND_ARG_INFO_WITH_DEFAULT_VALUE(1, softErrors, "null") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_getScheme, 0, 0, IS_STRING, 0) -ZEND_END_ARG_INFO() +#define arginfo_class_Uri_WhatWg_Url_getScheme arginfo_class_Uri_Rfc3986_Uri_getPath ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_withScheme, 0, 1, IS_STATIC, 0) ZEND_ARG_TYPE_INFO(0, scheme, IS_STRING, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_getUsername, 0, 0, IS_STRING, 1) -ZEND_END_ARG_INFO() +#define arginfo_class_Uri_WhatWg_Url_getUsername arginfo_class_Uri_Rfc3986_Uri_getScheme ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_withUsername, 0, 1, IS_STATIC, 0) ZEND_ARG_TYPE_INFO(0, username, IS_STRING, 1) ZEND_END_ARG_INFO() -#define arginfo_class_Uri_WhatWg_Url_getPassword arginfo_class_Uri_WhatWg_Url_getUsername +#define arginfo_class_Uri_WhatWg_Url_getPassword arginfo_class_Uri_Rfc3986_Uri_getScheme ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_withPassword, 0, 1, IS_STATIC, 0) ZEND_ARG_TYPE_INFO(0, password, IS_STRING, 1) ZEND_END_ARG_INFO() -#define arginfo_class_Uri_WhatWg_Url_getAsciiHost arginfo_class_Uri_WhatWg_Url_getUsername +#define arginfo_class_Uri_WhatWg_Url_getAsciiHost arginfo_class_Uri_Rfc3986_Uri_getScheme -#define arginfo_class_Uri_WhatWg_Url_getUnicodeHost arginfo_class_Uri_WhatWg_Url_getUsername +#define arginfo_class_Uri_WhatWg_Url_getUnicodeHost arginfo_class_Uri_Rfc3986_Uri_getScheme ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_withHost, 0, 1, IS_STATIC, 0) ZEND_ARG_TYPE_INFO(0, host, IS_STRING, 1) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_getPort, 0, 0, IS_LONG, 1) -ZEND_END_ARG_INFO() +#define arginfo_class_Uri_WhatWg_Url_getPort arginfo_class_Uri_Rfc3986_Uri_getPort ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_withPort, 0, 1, IS_STATIC, 0) ZEND_ARG_TYPE_INFO(0, port, IS_LONG, 1) ZEND_END_ARG_INFO() -#define arginfo_class_Uri_WhatWg_Url_getPath arginfo_class_Uri_WhatWg_Url_getScheme +#define arginfo_class_Uri_WhatWg_Url_getPath arginfo_class_Uri_Rfc3986_Uri_getPath ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_withPath, 0, 1, IS_STATIC, 0) ZEND_ARG_TYPE_INFO(0, path, IS_STRING, 0) ZEND_END_ARG_INFO() -#define arginfo_class_Uri_WhatWg_Url_getQuery arginfo_class_Uri_WhatWg_Url_getUsername +#define arginfo_class_Uri_WhatWg_Url_getQuery arginfo_class_Uri_Rfc3986_Uri_getScheme ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_withQuery, 0, 1, IS_STATIC, 0) ZEND_ARG_TYPE_INFO(0, query, IS_STRING, 1) ZEND_END_ARG_INFO() -#define arginfo_class_Uri_WhatWg_Url_getFragment arginfo_class_Uri_WhatWg_Url_getUsername +#define arginfo_class_Uri_WhatWg_Url_getFragment arginfo_class_Uri_Rfc3986_Uri_getScheme ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_withFragment, 0, 1, IS_STATIC, 0) ZEND_ARG_TYPE_INFO(0, fragment, IS_STRING, 1) @@ -84,44 +150,61 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_equals, 0, ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, comparisonMode, Uri\\\125riComparisonMode, 0, "Uri\\UriComparisonMode::ExcludeFragment") ZEND_END_ARG_INFO() -#define arginfo_class_Uri_WhatWg_Url_toAsciiString arginfo_class_Uri_WhatWg_Url_getScheme +#define arginfo_class_Uri_WhatWg_Url_toAsciiString arginfo_class_Uri_Rfc3986_Uri_getPath -#define arginfo_class_Uri_WhatWg_Url_toUnicodeString arginfo_class_Uri_WhatWg_Url_getScheme +#define arginfo_class_Uri_WhatWg_Url_toUnicodeString arginfo_class_Uri_Rfc3986_Uri_getPath ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_resolve, 0, 1, IS_STATIC, 0) ZEND_ARG_TYPE_INFO(0, uri, IS_STRING, 0) ZEND_ARG_INFO_WITH_DEFAULT_VALUE(1, softErrors, "null") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url___serialize, 0, 0, IS_ARRAY, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url___unserialize, 0, 1, IS_VOID, 0) - ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) -ZEND_END_ARG_INFO() - -#define arginfo_class_Uri_WhatWg_Url___debugInfo arginfo_class_Uri_WhatWg_Url___serialize - +#define arginfo_class_Uri_WhatWg_Url___serialize arginfo_class_Uri_Rfc3986_Uri___serialize + +#define arginfo_class_Uri_WhatWg_Url___unserialize arginfo_class_Uri_Rfc3986_Uri___unserialize + +#define arginfo_class_Uri_WhatWg_Url___debugInfo arginfo_class_Uri_Rfc3986_Uri___serialize + +ZEND_METHOD(Uri_Rfc3986_Uri, parse); +ZEND_METHOD(Uri_Rfc3986_Uri, __construct); +ZEND_METHOD(Uri_Rfc3986_Uri, getScheme); +ZEND_METHOD(Uri_Rfc3986_Uri, getRawScheme); +ZEND_METHOD(Uri_Rfc3986_Uri, getUserInfo); +ZEND_METHOD(Uri_Rfc3986_Uri, getRawUserInfo); +ZEND_METHOD(Uri_Rfc3986_Uri, getUsername); +ZEND_METHOD(Uri_Rfc3986_Uri, getRawUsername); +ZEND_METHOD(Uri_Rfc3986_Uri, getPassword); +ZEND_METHOD(Uri_Rfc3986_Uri, getRawPassword); +ZEND_METHOD(Uri_Rfc3986_Uri, getHost); +ZEND_METHOD(Uri_Rfc3986_Uri, getRawHost); +ZEND_METHOD(Uri_Rfc3986_Uri, getPort); +ZEND_METHOD(Uri_Rfc3986_Uri, getPath); +ZEND_METHOD(Uri_Rfc3986_Uri, getRawPath); +ZEND_METHOD(Uri_Rfc3986_Uri, getQuery); +ZEND_METHOD(Uri_Rfc3986_Uri, getRawQuery); +ZEND_METHOD(Uri_Rfc3986_Uri, getFragment); +ZEND_METHOD(Uri_Rfc3986_Uri, getRawFragment); +ZEND_METHOD(Uri_Rfc3986_Uri, equals); +ZEND_METHOD(Uri_Rfc3986_Uri, toString); +ZEND_METHOD(Uri_Rfc3986_Uri, toRawString); +ZEND_METHOD(Uri_Rfc3986_Uri, resolve); +ZEND_METHOD(Uri_Rfc3986_Uri, __serialize); +ZEND_METHOD(Uri_Rfc3986_Uri, __unserialize); +ZEND_METHOD(Uri_Rfc3986_Uri, __debugInfo); ZEND_METHOD(Uri_WhatWg_InvalidUrlException, __construct); ZEND_METHOD(Uri_WhatWg_UrlValidationError, __construct); ZEND_METHOD(Uri_WhatWg_Url, parse); ZEND_METHOD(Uri_WhatWg_Url, __construct); ZEND_METHOD(Uri_WhatWg_Url, getScheme); ZEND_METHOD(Uri_WhatWg_Url, withScheme); -ZEND_METHOD(Uri_WhatWg_Url, getUsername); ZEND_METHOD(Uri_WhatWg_Url, withUsername); -ZEND_METHOD(Uri_WhatWg_Url, getPassword); ZEND_METHOD(Uri_WhatWg_Url, withPassword); ZEND_METHOD(Uri_WhatWg_Url, getAsciiHost); ZEND_METHOD(Uri_WhatWg_Url, getUnicodeHost); ZEND_METHOD(Uri_WhatWg_Url, withHost); -ZEND_METHOD(Uri_WhatWg_Url, getPort); ZEND_METHOD(Uri_WhatWg_Url, withPort); -ZEND_METHOD(Uri_WhatWg_Url, getPath); ZEND_METHOD(Uri_WhatWg_Url, withPath); -ZEND_METHOD(Uri_WhatWg_Url, getQuery); ZEND_METHOD(Uri_WhatWg_Url, withQuery); -ZEND_METHOD(Uri_WhatWg_Url, getFragment); ZEND_METHOD(Uri_WhatWg_Url, withFragment); ZEND_METHOD(Uri_WhatWg_Url, equals); ZEND_METHOD(Uri_WhatWg_Url, toAsciiString); @@ -131,6 +214,36 @@ ZEND_METHOD(Uri_WhatWg_Url, __serialize); ZEND_METHOD(Uri_WhatWg_Url, __unserialize); ZEND_METHOD(Uri_WhatWg_Url, __debugInfo); +static const zend_function_entry class_Uri_Rfc3986_Uri_methods[] = { + ZEND_ME(Uri_Rfc3986_Uri, parse, arginfo_class_Uri_Rfc3986_Uri_parse, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + ZEND_ME(Uri_Rfc3986_Uri, __construct, arginfo_class_Uri_Rfc3986_Uri___construct, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, getScheme, arginfo_class_Uri_Rfc3986_Uri_getScheme, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, getRawScheme, arginfo_class_Uri_Rfc3986_Uri_getRawScheme, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, getUserInfo, arginfo_class_Uri_Rfc3986_Uri_getUserInfo, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, getRawUserInfo, arginfo_class_Uri_Rfc3986_Uri_getRawUserInfo, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, getUsername, arginfo_class_Uri_Rfc3986_Uri_getUsername, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, getRawUsername, arginfo_class_Uri_Rfc3986_Uri_getRawUsername, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, getPassword, arginfo_class_Uri_Rfc3986_Uri_getPassword, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, getRawPassword, arginfo_class_Uri_Rfc3986_Uri_getRawPassword, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, getHost, arginfo_class_Uri_Rfc3986_Uri_getHost, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, getRawHost, arginfo_class_Uri_Rfc3986_Uri_getRawHost, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, getPort, arginfo_class_Uri_Rfc3986_Uri_getPort, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, getPath, arginfo_class_Uri_Rfc3986_Uri_getPath, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, getRawPath, arginfo_class_Uri_Rfc3986_Uri_getRawPath, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, getQuery, arginfo_class_Uri_Rfc3986_Uri_getQuery, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, getRawQuery, arginfo_class_Uri_Rfc3986_Uri_getRawQuery, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, getFragment, arginfo_class_Uri_Rfc3986_Uri_getFragment, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, getRawFragment, arginfo_class_Uri_Rfc3986_Uri_getRawFragment, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, equals, arginfo_class_Uri_Rfc3986_Uri_equals, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, toString, arginfo_class_Uri_Rfc3986_Uri_toString, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, toRawString, arginfo_class_Uri_Rfc3986_Uri_toRawString, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, resolve, arginfo_class_Uri_Rfc3986_Uri_resolve, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, __serialize, arginfo_class_Uri_Rfc3986_Uri___serialize, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, __unserialize, arginfo_class_Uri_Rfc3986_Uri___unserialize, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, __debugInfo, arginfo_class_Uri_Rfc3986_Uri___debugInfo, ZEND_ACC_PUBLIC) + ZEND_FE_END +}; + static const zend_function_entry class_Uri_WhatWg_InvalidUrlException_methods[] = { ZEND_ME(Uri_WhatWg_InvalidUrlException, __construct, arginfo_class_Uri_WhatWg_InvalidUrlException___construct, ZEND_ACC_PUBLIC) ZEND_FE_END @@ -146,20 +259,20 @@ static const zend_function_entry class_Uri_WhatWg_Url_methods[] = { ZEND_ME(Uri_WhatWg_Url, __construct, arginfo_class_Uri_WhatWg_Url___construct, ZEND_ACC_PUBLIC) ZEND_ME(Uri_WhatWg_Url, getScheme, arginfo_class_Uri_WhatWg_Url_getScheme, ZEND_ACC_PUBLIC) ZEND_ME(Uri_WhatWg_Url, withScheme, arginfo_class_Uri_WhatWg_Url_withScheme, ZEND_ACC_PUBLIC) - ZEND_ME(Uri_WhatWg_Url, getUsername, arginfo_class_Uri_WhatWg_Url_getUsername, ZEND_ACC_PUBLIC) + ZEND_RAW_FENTRY("getUsername", zim_Uri_Rfc3986_Uri_getUsername, arginfo_class_Uri_WhatWg_Url_getUsername, ZEND_ACC_PUBLIC, NULL, NULL) ZEND_ME(Uri_WhatWg_Url, withUsername, arginfo_class_Uri_WhatWg_Url_withUsername, ZEND_ACC_PUBLIC) - ZEND_ME(Uri_WhatWg_Url, getPassword, arginfo_class_Uri_WhatWg_Url_getPassword, ZEND_ACC_PUBLIC) + ZEND_RAW_FENTRY("getPassword", zim_Uri_Rfc3986_Uri_getPassword, arginfo_class_Uri_WhatWg_Url_getPassword, ZEND_ACC_PUBLIC, NULL, NULL) ZEND_ME(Uri_WhatWg_Url, withPassword, arginfo_class_Uri_WhatWg_Url_withPassword, ZEND_ACC_PUBLIC) ZEND_ME(Uri_WhatWg_Url, getAsciiHost, arginfo_class_Uri_WhatWg_Url_getAsciiHost, ZEND_ACC_PUBLIC) ZEND_ME(Uri_WhatWg_Url, getUnicodeHost, arginfo_class_Uri_WhatWg_Url_getUnicodeHost, ZEND_ACC_PUBLIC) ZEND_ME(Uri_WhatWg_Url, withHost, arginfo_class_Uri_WhatWg_Url_withHost, ZEND_ACC_PUBLIC) - ZEND_ME(Uri_WhatWg_Url, getPort, arginfo_class_Uri_WhatWg_Url_getPort, ZEND_ACC_PUBLIC) + ZEND_RAW_FENTRY("getPort", zim_Uri_Rfc3986_Uri_getPort, arginfo_class_Uri_WhatWg_Url_getPort, ZEND_ACC_PUBLIC, NULL, NULL) ZEND_ME(Uri_WhatWg_Url, withPort, arginfo_class_Uri_WhatWg_Url_withPort, ZEND_ACC_PUBLIC) - ZEND_ME(Uri_WhatWg_Url, getPath, arginfo_class_Uri_WhatWg_Url_getPath, ZEND_ACC_PUBLIC) + ZEND_RAW_FENTRY("getPath", zim_Uri_Rfc3986_Uri_getPath, arginfo_class_Uri_WhatWg_Url_getPath, ZEND_ACC_PUBLIC, NULL, NULL) ZEND_ME(Uri_WhatWg_Url, withPath, arginfo_class_Uri_WhatWg_Url_withPath, ZEND_ACC_PUBLIC) - ZEND_ME(Uri_WhatWg_Url, getQuery, arginfo_class_Uri_WhatWg_Url_getQuery, ZEND_ACC_PUBLIC) + ZEND_RAW_FENTRY("getQuery", zim_Uri_Rfc3986_Uri_getQuery, arginfo_class_Uri_WhatWg_Url_getQuery, ZEND_ACC_PUBLIC, NULL, NULL) ZEND_ME(Uri_WhatWg_Url, withQuery, arginfo_class_Uri_WhatWg_Url_withQuery, ZEND_ACC_PUBLIC) - ZEND_ME(Uri_WhatWg_Url, getFragment, arginfo_class_Uri_WhatWg_Url_getFragment, ZEND_ACC_PUBLIC) + ZEND_RAW_FENTRY("getFragment", zim_Uri_Rfc3986_Uri_getFragment, arginfo_class_Uri_WhatWg_Url_getFragment, ZEND_ACC_PUBLIC, NULL, NULL) ZEND_ME(Uri_WhatWg_Url, withFragment, arginfo_class_Uri_WhatWg_Url_withFragment, ZEND_ACC_PUBLIC) ZEND_ME(Uri_WhatWg_Url, equals, arginfo_class_Uri_WhatWg_Url_equals, ZEND_ACC_PUBLIC) ZEND_ME(Uri_WhatWg_Url, toAsciiString, arginfo_class_Uri_WhatWg_Url_toAsciiString, ZEND_ACC_PUBLIC) @@ -202,6 +315,16 @@ static zend_class_entry *register_class_Uri_UriComparisonMode(void) return class_entry; } +static zend_class_entry *register_class_Uri_Rfc3986_Uri(void) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "Uri\\Rfc3986", "Uri", class_Uri_Rfc3986_Uri_methods); + class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_READONLY_CLASS); + + return class_entry; +} + static zend_class_entry *register_class_Uri_WhatWg_InvalidUrlException(zend_class_entry *class_entry_Uri_InvalidUriException) { zend_class_entry ce, *class_entry; diff --git a/ext/uri/php_uri_common.c b/ext/uri/php_uri_common.c index 9128b942e57b8..d4e4d6c2fc48c 100644 --- a/ext/uri/php_uri_common.c +++ b/ext/uri/php_uri_common.c @@ -76,8 +76,7 @@ void uri_read_component(INTERNAL_FUNCTION_PARAMETERS, uri_property_name_t proper ZEND_ASSERT(property_handler != NULL); if (UNEXPECTED(property_handler->read_func(internal_uri, component_read_mode, return_value) == FAILURE)) { - zend_throw_error(NULL, "%s::$%s property cannot be retrieved", ZSTR_VAL(Z_OBJ_P(ZEND_THIS)->ce->name), - ZSTR_VAL(get_known_string_by_property_name(property_name))); + zend_throw_error(NULL, "The %s component cannot be retrieved", ZSTR_VAL(get_known_string_by_property_name(property_name))); RETURN_THROWS(); } } diff --git a/ext/uri/php_uri_common.h b/ext/uri/php_uri_common.h index 1aee1cd512472..8e5b0c2d2279f 100644 --- a/ext/uri/php_uri_common.h +++ b/ext/uri/php_uri_common.h @@ -17,6 +17,8 @@ #ifndef PHP_URI_COMMON_H #define PHP_URI_COMMON_H +extern zend_class_entry *uri_rfc3986_uri_ce; +extern zend_object_handlers uri_rfc3986_uri_object_handlers; extern zend_class_entry *uri_whatwg_url_ce; extern zend_object_handlers uri_whatwg_uri_object_handlers; extern zend_class_entry *uri_comparison_mode_ce; @@ -121,6 +123,7 @@ static inline uri_internal_t *uri_internal_from_obj(const zend_object *object) { #define Z_URI_OBJECT_P(zv) uri_object_from_obj(Z_OBJ_P((zv))) #define Z_URI_INTERNAL_P(zv) uri_internal_from_obj(Z_OBJ_P((zv))) +#define URI_PARSER_RFC3986 "Uri\\Rfc3986\\Uri" #define URI_PARSER_WHATWG "Uri\\WhatWg\\Url" #define URI_SERIALIZED_PROPERTY_NAME "uri" diff --git a/ext/uri/php_uriparser.c b/ext/uri/php_uriparser.c new file mode 100644 index 0000000000000..51a38b07e068a --- /dev/null +++ b/ext/uri/php_uriparser.c @@ -0,0 +1,461 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Máté Kocsis | + +----------------------------------------------------------------------+ +*/ + +#include "php.h" +#include "php_uriparser.h" +#include "php_uri_common.h" +#include "Zend/zend_smart_str.h" +#include "Zend/zend_exceptions.h" + +static void uriparser_free_uri(void *uri); +static void throw_invalid_uri_exception(void); + +static inline size_t get_text_range_length(const UriTextRangeA *range) +{ + return range->afterLast - range->first; +} + +static UriUriA *uriparser_copy_uri(UriUriA *uriparser_uri) // TODO add to uriparser +{ + UriUriA *new_uriparser_uri = emalloc(sizeof(UriUriA)); + + if (uriCopyUriA(new_uriparser_uri, uriparser_uri) != URI_SUCCESS) { + efree(new_uriparser_uri); + return NULL; /* TODO check for null on call sites */ + } + + return new_uriparser_uri; +} + +static zend_result uriparser_normalize_uri(UriUriA *uriparser_uri) +{ + if (uriNormalizeSyntaxExA(uriparser_uri, (unsigned int)-1) != URI_SUCCESS) { + return FAILURE; + } + + return SUCCESS; +} + +static UriUriA *uriparser_read_uri(uriparser_uris_t *uriparser_uris, uri_component_read_mode_t read_mode) +{ + switch (read_mode) { + case URI_COMPONENT_READ_RAW: + return uriparser_uris->uri; + case URI_COMPONENT_READ_NORMALIZED_ASCII: + ZEND_FALLTHROUGH; + case URI_COMPONENT_READ_NORMALIZED_UNICODE: + if (uriparser_uris->normalized_uri == NULL) { + uriparser_uris->normalized_uri = uriparser_copy_uri(uriparser_uris->uri); + if (uriparser_normalize_uri(uriparser_uris->normalized_uri) == FAILURE) { + uriFreeUriMembersA(uriparser_uris->normalized_uri); + efree(uriparser_uris->normalized_uri); + uriparser_uris->normalized_uri = NULL; + + return NULL; + } + } + + return uriparser_uris->normalized_uri; + EMPTY_SWITCH_DEFAULT_CASE() + } +} + +static zend_result uriparser_read_scheme(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + if (UNEXPECTED(uriparser_uri == NULL)) { + return FAILURE; + } + + if (uriparser_uri->scheme.first != NULL && uriparser_uri->scheme.afterLast != NULL) { + zend_string *str = zend_string_init(uriparser_uri->scheme.first, get_text_range_length(&uriparser_uri->scheme), false); + ZVAL_NEW_STR(retval, str); + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +zend_result uriparser_read_userinfo(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + if (UNEXPECTED(uriparser_uri == NULL)) { + return FAILURE; + } + + if (uriparser_uri->userInfo.first != NULL && uriparser_uri->userInfo.afterLast != NULL) { + ZVAL_STRINGL(retval, uriparser_uri->userInfo.first, get_text_range_length(&uriparser_uri->userInfo)); + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +static zend_result uriparser_read_username(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + if (UNEXPECTED(uriparser_uri == NULL)) { + return FAILURE; + } + + if (uriparser_uri->userInfo.first != NULL && uriparser_uri->userInfo.afterLast != NULL) { + size_t length = get_text_range_length(&uriparser_uri->userInfo); + char *c = memchr(uriparser_uri->userInfo.first, ':', length); + + if (c == NULL && length > 0) { + ZVAL_STRINGL(retval, uriparser_uri->userInfo.first, length); + } else if (c != NULL && c - uriparser_uri->userInfo.first > 0) { + ZVAL_STRINGL(retval, uriparser_uri->userInfo.first, c - uriparser_uri->userInfo.first); + } else { + ZVAL_NULL(retval); + } + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +static zend_result uriparser_read_password(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + if (UNEXPECTED(uriparser_uri == NULL)) { + return FAILURE; + } + + if (uriparser_uri->userInfo.first != NULL && uriparser_uri->userInfo.afterLast != NULL) { + const char *c = memchr(uriparser_uri->userInfo.first, ':', get_text_range_length(&uriparser_uri->userInfo)); + + if (c != NULL && uriparser_uri->userInfo.afterLast - c - 1 > 0) { + ZVAL_STRINGL(retval, c + 1, uriparser_uri->userInfo.afterLast - c - 1); + } else { + ZVAL_NULL(retval); + } + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +static zend_result uriparser_read_host(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + if (UNEXPECTED(uriparser_uri == NULL)) { + return FAILURE; + } + + if (uriparser_uri->hostText.first != NULL && uriparser_uri->hostText.afterLast != NULL && get_text_range_length(&uriparser_uri->hostText) > 0) { + if (uriparser_uri->hostData.ip6 != NULL) { + smart_str host_str = {0}; + + smart_str_appendc(&host_str, '['); + smart_str_appendl(&host_str, uriparser_uri->hostText.first, get_text_range_length(&uriparser_uri->hostText)); + smart_str_appendc(&host_str, ']'); + + ZVAL_NEW_STR(retval, smart_str_extract(&host_str)); + } else { + ZVAL_STRINGL(retval, uriparser_uri->hostText.first, get_text_range_length(&uriparser_uri->hostText)); + } + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +static int str_to_int(const char *str, int len) +{ + int result = 0; + + for (int i = 0; i < len; ++i) { + result = result * 10 + (str[i] - '0'); + } + + return result; +} + +static zend_result uriparser_read_port(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + if (UNEXPECTED(uriparser_uri == NULL)) { + return FAILURE; + } + + if (uriparser_uri->portText.first != NULL && uriparser_uri->portText.afterLast != NULL) { + ZVAL_LONG(retval, str_to_int(uriparser_uri->portText.first, get_text_range_length(&uriparser_uri->portText))); + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +static zend_result uriparser_read_path(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + if (UNEXPECTED(uriparser_uri == NULL)) { + return FAILURE; + } + + if (uriparser_uri->pathHead != NULL) { + const UriPathSegmentA *p; + smart_str str = {0}; + + if (uriparser_uri->absolutePath || uriIsHostSetA(uriparser_uri)) { + smart_str_appendc(&str, '/'); + } + + smart_str_appendl(&str, uriparser_uri->pathHead->text.first, get_text_range_length(&uriparser_uri->pathHead->text)); + + for (p = uriparser_uri->pathHead->next; p != NULL; p = p->next) { + smart_str_appendc(&str, '/'); + smart_str_appendl(&str, p->text.first, get_text_range_length(&p->text)); + } + + ZVAL_NEW_STR(retval, smart_str_extract(&str)); + } else if (uriparser_uri->absolutePath) { + ZVAL_CHAR(retval, '/'); + } else { + ZVAL_EMPTY_STRING(retval); + } + + return SUCCESS; +} + +static zend_result uriparser_read_query(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + if (UNEXPECTED(uriparser_uri == NULL)) { + return FAILURE; + } + + if (uriparser_uri->query.first != NULL && uriparser_uri->query.afterLast != NULL) { + ZVAL_STRINGL(retval, uriparser_uri->query.first, get_text_range_length(&uriparser_uri->query)); + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +static zend_result uriparser_read_fragment(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + if (UNEXPECTED(uriparser_uri == NULL)) { + return FAILURE; + } + + if (uriparser_uri->fragment.first != NULL && uriparser_uri->fragment.afterLast != NULL) { + ZVAL_STRINGL(retval, uriparser_uri->fragment.first, get_text_range_length(&uriparser_uri->fragment)); + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +static void *uriparser_malloc(UriMemoryManager *memory_manager, size_t size) +{ + return emalloc(size); +} + +static void *uriparser_calloc(UriMemoryManager *memory_manager, size_t nmemb, size_t size) +{ + return ecalloc(nmemb, size); +} + +static void *uriparser_realloc(UriMemoryManager *memory_manager, void *ptr, size_t size) +{ + return erealloc(ptr, size); +} + +static void *uriparser_reallocarray(UriMemoryManager *memory_manager, void *ptr, size_t nmemb, size_t size) +{ + return safe_erealloc(ptr, nmemb, size, 0); +} + +static void uriparser_free(UriMemoryManager *memory_manager, void *ptr) +{ + efree(ptr); +} + +PHP_MINIT_FUNCTION(uri_uriparser) +{ + if (uri_handler_register(&uriparser_uri_handler) == FAILURE) { + return FAILURE; + } + + defaultMemoryManager.malloc = uriparser_malloc; + defaultMemoryManager.calloc = uriparser_calloc; + defaultMemoryManager.realloc = uriparser_realloc; + defaultMemoryManager.reallocarray = uriparser_reallocarray; + defaultMemoryManager.free = uriparser_free; + + return SUCCESS; +} + +static uriparser_uris_t *uriparser_create_uris( + UriUriA *uri, + UriUriA *normalized_uri +) { + uriparser_uris_t *uriparser_uris = emalloc(sizeof(uriparser_uris_t)); + + uriparser_uris->uri = uri; + uriparser_uris->normalized_uri = normalized_uri; + + return uriparser_uris; +} + +static void throw_invalid_uri_exception(void) +{ + zend_throw_exception(uri_invalid_uri_exception_ce, "URI parsing failed", 0); +} + +void *uriparser_parse_uri_ex(const zend_string *uri_str, const uriparser_uris_t *uriparser_base_urls, bool silent) +{ + UriUriA *uriparser_uri = emalloc(sizeof(UriUriA)); + + if (ZSTR_LEN(uri_str) == 0 || + uriParseSingleUriExA(uriparser_uri, ZSTR_VAL(uri_str), ZSTR_VAL(uri_str) + ZSTR_LEN(uri_str), NULL) != URI_SUCCESS + ) { + efree(uriparser_uri); + if (!silent) { + throw_invalid_uri_exception(); + } + + return NULL; + } + + uriMakeOwnerA(uriparser_uri); + if (uriparser_base_urls == NULL) { + return uriparser_create_uris(uriparser_uri, NULL); + } + + UriUriA *absolute_uri = emalloc(sizeof(UriUriA)); + + if (uriAddBaseUriA(absolute_uri, uriparser_uri, uriparser_base_urls->uri) != URI_SUCCESS) { + uriFreeUriMembersA(uriparser_uri); + efree(uriparser_uri); + efree(absolute_uri); + + if (!silent) { + throw_invalid_uri_exception(); + } + + return NULL; + } + + uriMakeOwnerA(absolute_uri); + uriFreeUriMembersA(uriparser_uri); + efree(uriparser_uri); + + return uriparser_create_uris(absolute_uri, NULL); +} + +void *uriparser_parse_uri(const zend_string *uri_str, const void *base_url, zval *errors, bool silent) +{ + return uriparser_parse_uri_ex(uri_str, base_url, silent); +} + +static void *uriparser_clone_uri(void *uri) +{ + uriparser_uris_t *uriparser_uris = (uriparser_uris_t *) uri; + + return uriparser_create_uris( + uriparser_copy_uri(uriparser_uris->uri), + uriparser_uris->normalized_uri != NULL ? uriparser_copy_uri(uriparser_uris->normalized_uri) : NULL + ); +} + +static zend_string *uriparser_uri_to_string(void *uri, uri_recomposition_mode_t recomposition_mode, bool exclude_fragment) +{ + uriparser_uris_t *uriparser_uris = (uriparser_uris_t *) uri; + UriUriA *uriparser_uri = uriparser_uris->uri; + + if ((recomposition_mode == URI_RECOMPOSITION_NORMALIZED_UNICODE || recomposition_mode == URI_RECOMPOSITION_NORMALIZED_ASCII) && + uriparser_uris->normalized_uri == NULL + ) { + uriparser_uris->normalized_uri = uriparser_copy_uri(uriparser_uris->uri); + if (uriparser_normalize_uri(uriparser_uris->normalized_uri) == FAILURE) { + return NULL; + } + uriparser_uri = uriparser_uris->normalized_uri; + } + + int charsRequired; + if (uriToStringCharsRequiredA(uriparser_uri, &charsRequired) != URI_SUCCESS) { + return NULL; + } + + charsRequired++; + + zend_string *uri_string = zend_string_alloc(charsRequired - 1, false); + if (uriToStringA(ZSTR_VAL(uri_string), uriparser_uri, charsRequired, NULL) != URI_SUCCESS) { + zend_string_efree(uri_string); + return NULL; + } + + if (exclude_fragment) { + const char *pos = zend_memrchr(ZSTR_VAL(uri_string), '#', ZSTR_LEN(uri_string)); + if (pos != NULL) { + uri_string = zend_string_truncate(uri_string, (pos - ZSTR_VAL(uri_string)), false); + } + } + + return uri_string; +} + +static void uriparser_free_uri(void *uri) +{ + uriparser_uris_t *uriparser_uris = (uriparser_uris_t *) uri; + + if (uriparser_uris->uri != NULL) { + uriFreeUriMembersA(uriparser_uris->uri); + efree(uriparser_uris->uri); + uriparser_uris->uri = NULL; + } + + if (uriparser_uris->normalized_uri != NULL) { + ZEND_ASSERT(uriparser_uris->normalized_uri->owner); + + uriFreeUriMembersA(uriparser_uris->normalized_uri); + efree(uriparser_uris->normalized_uri); + uriparser_uris->normalized_uri = NULL; + } + + efree(uriparser_uris); +} + +const uri_handler_t uriparser_uri_handler = { + .name = URI_PARSER_RFC3986, + .parse_uri = uriparser_parse_uri, + .clone_uri = uriparser_clone_uri, + .uri_to_string = uriparser_uri_to_string, + .free_uri = uriparser_free_uri, + { + .scheme = {.read_func = uriparser_read_scheme, .write_func = NULL}, + .username = {.read_func = uriparser_read_username, .write_func = NULL}, + .password = {.read_func = uriparser_read_password, .write_func = NULL}, + .host = {.read_func = uriparser_read_host, .write_func = NULL}, + .port = {.read_func = uriparser_read_port, .write_func = NULL}, + .path = {.read_func = uriparser_read_path, .write_func = NULL}, + .query = {.read_func = uriparser_read_query, .write_func = NULL}, + .fragment = {.read_func = uriparser_read_fragment, .write_func = NULL}, + } +}; diff --git a/ext/uri/php_uriparser.h b/ext/uri/php_uriparser.h new file mode 100644 index 0000000000000..78993d748e575 --- /dev/null +++ b/ext/uri/php_uriparser.h @@ -0,0 +1,37 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Máté Kocsis | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHP_URIPARSER_H +#define PHP_URIPARSER_H + +#include +#include "uriparser/src/UriMemory.h" +#include "php_uri_common.h" + +extern const uri_handler_t uriparser_uri_handler; + +typedef struct uriparser_uris_t { + UriUriA *uri; + UriUriA *normalized_uri; +} uriparser_uris_t; + +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); + +#endif diff --git a/ext/uri/tests/003.phpt b/ext/uri/tests/003.phpt index bcd6e417441c2..be607fd6cacef 100644 --- a/ext/uri/tests/003.phpt +++ b/ext/uri/tests/003.phpt @@ -5,12 +5,15 @@ uri --FILE-- --EXPECTF-- +NULL object(Uri\WhatWg\Url)#%d (%d) { ["scheme"]=> string(4) "http" @@ -29,4 +32,22 @@ object(Uri\WhatWg\Url)#%d (%d) { ["fragment"]=> string(6) "anchor" } +object(Uri\Rfc3986\Uri)#%d (%d) { + ["scheme"]=> + NULL + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + NULL + ["port"]=> + NULL + ["path"]=> + string(7) "/page:1" + ["query"]=> + NULL + ["fragment"]=> + NULL +} NULL diff --git a/ext/uri/tests/004.phpt b/ext/uri/tests/004.phpt index 04127a7ded0d3..ce6ccf760460f 100644 --- a/ext/uri/tests/004.phpt +++ b/ext/uri/tests/004.phpt @@ -5,6 +5,14 @@ uri --FILE-- getMessage() . "\n"; +} + +var_dump(Uri\Rfc3986\Uri::parse("")); + try { new Uri\WhatWg\Url(""); } catch (Uri\WhatWg\InvalidUrlException $e) { @@ -13,13 +21,36 @@ try { var_dump(Uri\WhatWg\Url::parse("")); +var_dump(Uri\Rfc3986\Uri::parse("192.168/contact.html")); var_dump(Uri\WhatWg\Url::parse("192.168/contact.html", null)); +var_dump(Uri\Rfc3986\Uri::parse("http://rupaul/'s Drag Race All Stars 7 Winners Cast on This Season's")); var_dump(Uri\WhatWg\Url::parse("http://rupaul/'s Drag Race All Stars 7 Winners Cast on This Season's", null)); ?> --EXPECTF-- +URI parsing failed +NULL URL parsing failed NULL +object(Uri\Rfc3986\Uri)#%d (%d) { + ["scheme"]=> + NULL + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + NULL + ["port"]=> + NULL + ["path"]=> + string(20) "192.168/contact.html" + ["query"]=> + NULL + ["fragment"]=> + NULL +} +NULL NULL NULL diff --git a/ext/uri/tests/005.phpt b/ext/uri/tests/005.phpt index 262d43a75406b..6db6c4a56ee5a 100644 --- a/ext/uri/tests/005.phpt +++ b/ext/uri/tests/005.phpt @@ -5,6 +5,8 @@ uri --FILE-- getAsciiHost()); @@ -14,6 +16,7 @@ var_dump($url->toUnicodeString()); ?> --EXPECTF-- +NULL object(Uri\WhatWg\Url)#%d (%d) { ["scheme"]=> string(4) "http" diff --git a/ext/uri/tests/006.phpt b/ext/uri/tests/006.phpt index 0aba3e9e46b5e..c4da9db905c82 100644 --- a/ext/uri/tests/006.phpt +++ b/ext/uri/tests/006.phpt @@ -5,11 +5,32 @@ uri --FILE-- --EXPECTF-- +object(Uri\Rfc3986\Uri)#%d (%d) { + ["scheme"]=> + string(5) "https" + ["username"]=> + string(8) "username" + ["password"]=> + string(8) "password" + ["host"]=> + string(11) "example.com" + ["port"]=> + int(8080) + ["path"]=> + string(5) "/path" + ["query"]=> + string(3) "q=r" + ["fragment"]=> + string(8) "fragment" +} object(Uri\WhatWg\Url)#%d (%d) { ["scheme"]=> string(5) "https" diff --git a/ext/uri/tests/007.phpt b/ext/uri/tests/007.phpt index e60e69fc113a3..7d465913fb908 100644 --- a/ext/uri/tests/007.phpt +++ b/ext/uri/tests/007.phpt @@ -5,6 +5,12 @@ uri --FILE-- getMessage() . "\n"; +} + try { new Uri\WhatWg\Url("https://example.com:8080@username:password/path?q=r#fragment"); } catch (Uri\WhatWg\InvalidUrlException $e) { @@ -19,6 +25,7 @@ var_dump($failures); ?> --EXPECTF-- +URI parsing failed URL parsing failed array(%d) { [0]=> diff --git a/ext/uri/tests/008.phpt b/ext/uri/tests/008.phpt index f4fddcd8eb777..e13130bb4c466 100644 --- a/ext/uri/tests/008.phpt +++ b/ext/uri/tests/008.phpt @@ -5,6 +5,27 @@ uri --FILE-- getScheme()); + var_dump($uri->getRawScheme()); + var_dump($uri->getUsername()); + var_dump($uri->getRawUsername()); + var_dump($uri->getPassword()); + var_dump($uri->getRawPassword()); + var_dump($uri->getUserInfo()); + var_dump($uri->getRawUserInfo()); + var_dump($uri->getHost()); + var_dump($uri->getRawHost()); + var_dump($uri->getPort()); + var_dump($uri->getPath()); + var_dump($uri->getRawPath()); + var_dump($uri->getQuery()); + var_dump($uri->getRawQuery()); + var_dump($uri->getFragment()); + var_dump($uri->getRawFragment()); +} + function callWhatWgGetters($url) { var_dump($url->getScheme()); @@ -18,11 +39,34 @@ function callWhatWgGetters($url) var_dump($url->getFragment()); } +$uri = Uri\Rfc3986\Uri::parse("https://username:password@www.google.com:8080/pathname1/pathname2/pathname3?query=true#hash-exists"); +callRfc3986Getters($uri); + +echo "\n"; + $url = Uri\WhatWg\Url::parse("https://username:password@www.google.com:8080/pathname1/pathname2/pathname3?query=true#hash-exists"); callWhatWgGetters($url); ?> --EXPECT-- +string(5) "https" +string(5) "https" +string(8) "username" +string(8) "username" +string(8) "password" +string(8) "password" +string(17) "username:password" +string(17) "username:password" +string(14) "www.google.com" +string(14) "www.google.com" +int(8080) +string(30) "/pathname1/pathname2/pathname3" +string(30) "/pathname1/pathname2/pathname3" +string(10) "query=true" +string(10) "query=true" +string(11) "hash-exists" +string(11) "hash-exists" + string(5) "https" string(8) "username" string(8) "password" diff --git a/ext/uri/tests/009.phpt b/ext/uri/tests/009.phpt index 1b279588c0167..05f2820bb3fcf 100644 --- a/ext/uri/tests/009.phpt +++ b/ext/uri/tests/009.phpt @@ -5,10 +5,29 @@ uri --FILE-- --EXPECTF-- +object(Uri\Rfc3986\Uri)#%d (%d) { + ["scheme"]=> + string(16) "chrome-extension" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(0) "" + ["query"]=> + NULL + ["fragment"]=> + NULL +} object(Uri\WhatWg\Url)#%d (%d) { ["scheme"]=> string(16) "chrome-extension" diff --git a/ext/uri/tests/010.phpt b/ext/uri/tests/010.phpt index 4ec13f652f60c..2ca071eb2ca33 100644 --- a/ext/uri/tests/010.phpt +++ b/ext/uri/tests/010.phpt @@ -5,11 +5,49 @@ uri --FILE-- --EXPECTF-- +object(Uri\Rfc3986\Uri)#%d (%d) { + ["scheme"]=> + string(4) "http" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(14) "/path/to/file2" + ["query"]=> + NULL + ["fragment"]=> + NULL +} +object(Uri\Rfc3986\Uri)#%d (%d) { + ["scheme"]=> + string(5) "https" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(8) "test.com" + ["port"]=> + NULL + ["path"]=> + string(14) "/path/to/file2" + ["query"]=> + NULL + ["fragment"]=> + NULL +} object(Uri\WhatWg\Url)#%d (%d) { ["scheme"]=> string(4) "http" diff --git a/ext/uri/tests/011.phpt b/ext/uri/tests/011.phpt index 283886fb34fbb..49b915fa22a31 100644 --- a/ext/uri/tests/011.phpt +++ b/ext/uri/tests/011.phpt @@ -5,6 +5,12 @@ uri --FILE-- toRawString()); +var_dump(Uri\Rfc3986\Uri::parse("https://www.example.com/dir2")->toRawString()); +var_dump(Uri\Rfc3986\Uri::parse("https://xn--6qqa088eba/")); +var_dump(Uri\Rfc3986\Uri::parse("https://192.168.0.1/")); +var_dump(Uri\Rfc3986\Uri::parse("HttPs://0300.0250.0000.0001/path?query=foo%20bar")->toRawString()); + var_dump(Uri\WhatWg\Url::parse("http://www.example.com/")->toAsciiString()); var_dump(Uri\WhatWg\Url::parse("https://www.example.com/dir2")->toAsciiString()); var_dump(Uri\WhatWg\Url::parse("https://xn--6qqa088eba/")->toAsciiString()); @@ -14,6 +20,11 @@ var_dump(Uri\WhatWg\Url::parse("HttPs://0300.0250.0000.0001/path?query=foo%20bar ?> --EXPECT-- +string(29) "http://www.example.com/" +string(36) "https://www.example.com/dir2" +NULL +NULL +string(48) "HttPs://0300.0250.0000.0001/path?query=foo%20bar" string(23) "http://www.example.com/" string(28) "https://www.example.com/dir2" string(23) "https://xn--6qqa088eba/" diff --git a/ext/uri/tests/012.phpt b/ext/uri/tests/012.phpt index 0784a74e625f0..7c14014fb3519 100644 --- a/ext/uri/tests/012.phpt +++ b/ext/uri/tests/012.phpt @@ -5,12 +5,32 @@ uri --FILE-- --EXPECTF-- +object(Uri\Rfc3986\Uri)#%d (%d) { + ["scheme"]=> + string(6) "mailto" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + NULL + ["port"]=> + NULL + ["path"]=> + string(15) "Joe@Example.COM" + ["query"]=> + NULL + ["fragment"]=> + NULL +} object(Uri\WhatWg\Url)#%d (%d) { ["scheme"]=> string(6) "mailto" @@ -29,6 +49,24 @@ object(Uri\WhatWg\Url)#%d (%d) { ["fragment"]=> NULL } +object(Uri\Rfc3986\Uri)#%d (%d) { + ["scheme"]=> + string(4) "file" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + NULL + ["port"]=> + NULL + ["path"]=> + string(30) "/E:/Documents%20and%20Settings" + ["query"]=> + NULL + ["fragment"]=> + NULL +} object(Uri\WhatWg\Url)#%d (%d) { ["scheme"]=> string(4) "file" diff --git a/ext/uri/tests/013.phpt b/ext/uri/tests/013.phpt index 016fe6632782c..6a5bb31870fb1 100644 --- a/ext/uri/tests/013.phpt +++ b/ext/uri/tests/013.phpt @@ -5,14 +5,39 @@ uri --FILE-- + @")); + var_dump(Uri\WhatWg\Url::parse("http://example.com/?foobar=%27%3Cscript%3E+%2B+%40")); var_dump(Uri\WhatWg\Url::parse("http://example.com/?foobar='