diff --git a/ext/lexbor/lexbor/url/url.c b/ext/lexbor/lexbor/url/url.c index 7bfc007e622ce..c672a283ed184 100644 --- a/ext/lexbor/lexbor/url/url.c +++ b/ext/lexbor/lexbor/url/url.c @@ -860,12 +860,6 @@ lxb_url_is_url_codepoint(lxb_codepoint_t cp) return lxb_url_codepoint_alphanumeric[(lxb_char_t) cp] != 0xFF; } -lxb_inline bool -lxb_url_is_special(const lxb_url_t *url) -{ - return url->scheme.type != LXB_URL_SCHEMEL_TYPE__UNKNOWN; -} - lxb_inline const lxb_url_scheme_data_t * lxb_url_scheme_by_type(lxb_url_scheme_type_t type) { diff --git a/ext/lexbor/lexbor/url/url.h b/ext/lexbor/lexbor/url/url.h index 4ed3f32aa6467..1d705668628d7 100644 --- a/ext/lexbor/lexbor/url/url.h +++ b/ext/lexbor/lexbor/url/url.h @@ -773,6 +773,12 @@ lxb_url_scheme(const lxb_url_t *url) return &url->scheme.name; } +lxb_inline bool +lxb_url_is_special(const lxb_url_t *url) +{ + return url->scheme.type != LXB_URL_SCHEMEL_TYPE__UNKNOWN; +} + lxb_inline const lexbor_str_t * lxb_url_username(const lxb_url_t *url) { diff --git a/ext/uri/config.m4 b/ext/uri/config.m4 index 99e0d6b476779..c2df400777a51 100644 --- a/ext/uri/config.m4 +++ b/ext/uri/config.m4 @@ -11,6 +11,8 @@ PHP_ARG_WITH([external-uriparser], PHP_INSTALL_HEADERS([ext/uri], m4_normalize([ php_uri.h php_uri_common.h + php_uri_parser.h + php_uri_query.h uri_parser_rfc3986.h uri_parser_whatwg.h uri_parser_php_parse_url.h @@ -38,7 +40,7 @@ else PHP_EVAL_INCLINE([$LIBURIPARSER_CFLAGS]) fi -PHP_NEW_EXTENSION(uri, [php_uri.c php_uri_common.c uri_parser_rfc3986.c uri_parser_whatwg.c uri_parser_php_parse_url.c $URIPARSER_SOURCES], [no],,[$URI_CFLAGS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1]) +PHP_NEW_EXTENSION(uri, [php_uri.c php_uri_common.c php_uri_parser.c php_uri_query.c uri_parser_rfc3986.c uri_parser_whatwg.c uri_parser_php_parse_url.c $URIPARSER_SOURCES], [no],,[$URI_CFLAGS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1]) PHP_ADD_EXTENSION_DEP(uri, lexbor) if test "$PHP_EXTERNAL_URIPARSER" = "no"; then diff --git a/ext/uri/php_uri.c b/ext/uri/php_uri.c index eb0d105b52c7d..9f467ae974b92 100644 --- a/ext/uri/php_uri.c +++ b/ext/uri/php_uri.c @@ -26,78 +26,79 @@ #include "ext/standard/info.h" #include "php_uri.h" +#include "php_uri_query.h" #include "uri_parser_whatwg.h" #include "uri_parser_rfc3986.h" #include "uri_parser_php_parse_url.h" #include "php_uri_arginfo.h" #include "uriparser/UriBase.h" -zend_class_entry *php_uri_ce_rfc3986_uri; -zend_class_entry *php_uri_ce_whatwg_url; -zend_class_entry *php_uri_ce_comparison_mode; -zend_class_entry *php_uri_ce_exception; -zend_class_entry *php_uri_ce_error; -zend_class_entry *php_uri_ce_invalid_uri_exception; -zend_class_entry *php_uri_ce_whatwg_invalid_url_exception; -zend_class_entry *php_uri_ce_whatwg_url_validation_error_type; -zend_class_entry *php_uri_ce_whatwg_url_validation_error; - static zend_object_handlers object_handlers_rfc3986_uri; +static zend_object_handlers object_handlers_rfc3986_uri_query_params; static zend_object_handlers object_handlers_whatwg_uri; +static zend_object_handlers object_handlers_whatwg_url_query_params; static const zend_module_dep uri_deps[] = { ZEND_MOD_REQUIRED("lexbor") ZEND_MOD_END }; -static zend_array uri_parsers; -static HashTable *uri_get_debug_properties(php_uri_object *object) +PHPAPI zend_result php_uri_parser_register(const php_uri_parser *uri_parser) { - const HashTable *std_properties = zend_std_get_properties(&object->std); - HashTable *result = zend_array_dup(std_properties); + zend_string *key = zend_string_init_interned(uri_parser->name, strlen(uri_parser->name), true); - const php_uri_parser * const parser = object->parser; - void * const uri = object->uri; + ZEND_ASSERT(uri_parser->name != NULL); + ZEND_ASSERT(uri_parser->parse != NULL); + ZEND_ASSERT(uri_parser->clone != NULL || strcmp(uri_parser->name, PHP_URI_PARSER_PHP_PARSE_URL) == 0); + ZEND_ASSERT(uri_parser->to_string != NULL || strcmp(uri_parser->name, PHP_URI_PARSER_PHP_PARSE_URL) == 0); + ZEND_ASSERT(uri_parser->destroy != NULL); - if (UNEXPECTED(uri == NULL)) { - return result; - } + zend_result result = zend_hash_add_ptr(&uri_parsers, key, (void *) uri_parser) != NULL ? SUCCESS : FAILURE; - zval tmp; - if (parser->property_handler.scheme.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) { - zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_SCHEME), &tmp); - } + zend_string_release_ex(key, true); - if (parser->property_handler.username.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) { - zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_USERNAME), &tmp); - } + return result; +} - if (parser->property_handler.password.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) { - zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_PASSWORD), &tmp); - } +PHPAPI php_uri_object *php_uri_object_create(zend_class_entry *class_type, const php_uri_parser *parser) +{ + php_uri_object *uri_object = zend_object_alloc(sizeof(*uri_object), class_type); - if (parser->property_handler.host.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) { - zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_HOST), &tmp); - } + zend_object_std_init(&uri_object->std, class_type); + object_properties_init(&uri_object->std, class_type); - if (parser->property_handler.port.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) { - zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_PORT), &tmp); - } + uri_object->parser = parser; + uri_object->uri = NULL; - if (parser->property_handler.path.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) { - zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_PATH), &tmp); - } + return uri_object; +} - if (parser->property_handler.query.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) { - zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_QUERY), &tmp); - } +PHPAPI void php_uri_object_handler_free(zend_object *object) +{ + php_uri_object *uri_object = php_uri_object_from_obj(object); - if (parser->property_handler.fragment.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) { - zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_FRAGMENT), &tmp); - } + uri_object->parser->destroy(uri_object->uri); + zend_object_std_dtor(&uri_object->std); +} - return result; +PHPAPI zend_object *php_uri_object_handler_clone(zend_object *object) +{ + php_uri_object *uri_object = php_uri_object_from_obj(object); + + ZEND_ASSERT(uri_object->uri != NULL); + + php_uri_object *new_uri_object = php_uri_object_from_obj(object->ce->create_object(object->ce)); + ZEND_ASSERT(new_uri_object->parser == uri_object->parser); + + void *uri = uri_object->parser->clone(uri_object->uri); + ZEND_ASSERT(uri != NULL); + + new_uri_object->uri = uri; + + zend_objects_clone_members(&new_uri_object->std, &uri_object->std); + + return &new_uri_object->std; } PHPAPI const php_uri_parser *php_uri_get_parser(zend_string *uri_parser_name) @@ -286,742 +287,6 @@ ZEND_ATTRIBUTE_NONNULL PHPAPI void php_uri_struct_free(php_uri *uri) efree(uri); } -/** - * Pass the errors parameter by ref to errors_zv for userland, and frees it if - * it is not not needed anymore. - */ -static zend_result pass_errors_by_ref_and_free(zval *errors_zv, zval *errors) -{ - ZEND_ASSERT(Z_TYPE_P(errors) == IS_UNDEF || Z_TYPE_P(errors) == IS_ARRAY); - - /* There was no error during parsing */ - if (Z_ISUNDEF_P(errors)) { - return SUCCESS; - } - - /* The errors parameter is an array, but the pass-by ref argument stored by - * errors_zv was not passed - the URI implementation either doesn't support - * returning additional error information, or the caller is not interested in it */ - if (errors_zv == NULL) { - zval_ptr_dtor(errors); - return SUCCESS; - } - - ZEND_TRY_ASSIGN_REF_TMP(errors_zv, errors); - if (EG(exception)) { - return FAILURE; - } - - return SUCCESS; -} - -ZEND_ATTRIBUTE_NONNULL_ARGS(1, 2) PHPAPI void php_uri_instantiate_uri( - INTERNAL_FUNCTION_PARAMETERS, const zend_string *uri_str, const php_uri_object *base_url_object, - bool should_throw, bool should_update_this_object, zval *errors_zv -) { - - php_uri_object *uri_object; - if (should_update_this_object) { - uri_object = Z_URI_OBJECT_P(ZEND_THIS); - if (uri_object->uri != NULL) { - zend_throw_error(NULL, "Cannot modify readonly object of class %s", ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name)); - RETURN_THROWS(); - } - } else { - if (EX(func)->common.fn_flags & ZEND_ACC_STATIC) { - object_init_ex(return_value, Z_CE_P(ZEND_THIS)); - } else { - object_init_ex(return_value, Z_OBJCE_P(ZEND_THIS)); - } - uri_object = Z_URI_OBJECT_P(return_value); - } - - const php_uri_parser *uri_parser = uri_object->parser; - - zval errors; - ZVAL_UNDEF(&errors); - - void *base_url = NULL; - if (base_url_object != NULL) { - ZEND_ASSERT(base_url_object->std.ce == uri_object->std.ce); - ZEND_ASSERT(base_url_object->uri != NULL); - ZEND_ASSERT(base_url_object->parser == uri_parser); - base_url = base_url_object->uri; - } - - void *uri = uri_parser->parse(ZSTR_VAL(uri_str), ZSTR_LEN(uri_str), base_url, errors_zv != NULL ? &errors : NULL, !should_throw); - if (UNEXPECTED(uri == NULL)) { - if (should_throw) { - zval_ptr_dtor(&errors); - RETURN_THROWS(); - } else { - if (pass_errors_by_ref_and_free(errors_zv, &errors) == FAILURE) { - RETURN_THROWS(); - } - zval_ptr_dtor(return_value); - RETURN_NULL(); - } - } - - if (pass_errors_by_ref_and_free(errors_zv, &errors) == FAILURE) { - uri_parser->destroy(uri); - RETURN_THROWS(); - } - - uri_object->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, php_uri_ce_rfc3986_uri) - ZEND_PARSE_PARAMETERS_END(); - - php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, - uri_str, base_url_object ? php_uri_object_from_obj(base_url_object) : NULL, is_constructor, is_constructor, NULL); -} - -static bool is_list_of_whatwg_validation_errors(const HashTable *array) -{ - if (!zend_array_is_list(array)) { - return false; - } - - ZEND_HASH_FOREACH_VAL(array, zval *val) { - /* Do not allow references as they may change types after checking. */ - - if (Z_TYPE_P(val) != IS_OBJECT) { - return false; - } - - if (!instanceof_function(Z_OBJCE_P(val), php_uri_ce_whatwg_url_validation_error)) { - return false; - } - } ZEND_HASH_FOREACH_END(); - - return true; -} - -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(php_uri_ce_whatwg_invalid_url_exception, Z_OBJ_P(ZEND_THIS), ZEND_STRL("errors"), &tmp); - } else { - if (!is_list_of_whatwg_validation_errors(Z_ARR_P(errors))) { - zend_argument_value_error(2, "must be a list of %s", ZSTR_VAL(php_uri_ce_whatwg_url_validation_error->name)); - RETURN_THROWS(); - } - - zend_update_property(php_uri_ce_whatwg_invalid_url_exception, 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, php_uri_ce_whatwg_url_validation_error_type) - Z_PARAM_BOOL(failure) - ZEND_PARSE_PARAMETERS_END(); - - zend_update_property_str(php_uri_ce_whatwg_url_validation_error, Z_OBJ_P(ZEND_THIS), ZEND_STRL("context"), context); - if (EG(exception)) { - RETURN_THROWS(); - } - - zend_update_property_ex(php_uri_ce_whatwg_url_validation_error, 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(php_uri_ce_whatwg_url_validation_error, 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; - zend_object *base_url_object = NULL; - zval *errors = NULL; - - ZEND_PARSE_PARAMETERS_START(1, 3) - Z_PARAM_PATH_STR(uri_str) - Z_PARAM_OPTIONAL - Z_PARAM_OBJ_OF_CLASS_OR_NULL(base_url_object, php_uri_ce_whatwg_url) - Z_PARAM_ZVAL(errors) - ZEND_PARSE_PARAMETERS_END(); - - php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, - uri_str, base_url_object ? php_uri_object_from_obj(base_url_object) : NULL, is_constructor, is_constructor, errors); -} - -PHP_METHOD(Uri_WhatWg_Url, parse) -{ - create_whatwg_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, false); -} - -PHP_METHOD(Uri_WhatWg_Url, __construct) -{ - create_whatwg_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, true); -} - -PHP_METHOD(Uri_Rfc3986_Uri, getScheme) -{ - php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_SCHEME, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII); -} - -PHP_METHOD(Uri_Rfc3986_Uri, getRawScheme) -{ - php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_SCHEME, PHP_URI_COMPONENT_READ_MODE_RAW); -} - -PHP_METHOD(Uri_Rfc3986_Uri, withScheme) -{ - php_uri_property_write_str_or_null_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_SCHEME); -} - -static void rfc3986_userinfo_read(INTERNAL_FUNCTION_PARAMETERS, php_uri_component_read_mode read_mode) -{ - ZEND_PARSE_PARAMETERS_NONE(); - - php_uri_object *uri_object = Z_URI_OBJECT_P(ZEND_THIS); - ZEND_ASSERT(uri_object->uri != NULL); - - if (UNEXPECTED(php_uri_parser_rfc3986_userinfo_read(uri_object->uri, read_mode, return_value) == FAILURE)) { - zend_throw_error(NULL, "The userinfo component cannot be retrieved"); - RETURN_THROWS(); - } -} - -PHP_METHOD(Uri_Rfc3986_Uri, getUserInfo) -{ - rfc3986_userinfo_read(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII); -} - -PHP_METHOD(Uri_Rfc3986_Uri, getRawUserInfo) -{ - rfc3986_userinfo_read(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_COMPONENT_READ_MODE_RAW); -} - -PHP_METHOD(Uri_Rfc3986_Uri, withUserInfo) -{ - zend_string *value; - - ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_PATH_STR_OR_NULL(value) - ZEND_PARSE_PARAMETERS_END(); - - zval zv; - if (value == NULL) { - ZVAL_NULL(&zv); - } else { - ZVAL_STR(&zv, value); - } - - php_uri_object *old_uri_object = php_uri_object_from_obj(Z_OBJ_P(ZEND_THIS)); - ZEND_ASSERT(old_uri_object->uri != NULL); - - zend_object *new_object = old_uri_object->std.handlers->clone_obj(&old_uri_object->std); - if (new_object == NULL) { - RETURN_THROWS(); - } - - /* Assign the object early. The engine will take care of destruction in - * case of an exception being thrown. */ - RETVAL_OBJ(new_object); - - php_uri_object *new_uri_object = php_uri_object_from_obj(new_object); - ZEND_ASSERT(new_uri_object->uri != NULL); - - if (UNEXPECTED(php_uri_parser_rfc3986_userinfo_write(new_uri_object->uri, &zv, NULL) == FAILURE)) { - RETURN_THROWS(); - } -} - -PHP_METHOD(Uri_Rfc3986_Uri, getUsername) -{ - php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_USERNAME, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII); -} - -PHP_METHOD(Uri_Rfc3986_Uri, getRawUsername) -{ - php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_USERNAME, PHP_URI_COMPONENT_READ_MODE_RAW); -} - -PHP_METHOD(Uri_Rfc3986_Uri, getPassword) -{ - php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_PASSWORD, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII); -} - -PHP_METHOD(Uri_Rfc3986_Uri, getRawPassword) -{ - php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_PASSWORD, PHP_URI_COMPONENT_READ_MODE_RAW); -} - -PHP_METHOD(Uri_Rfc3986_Uri, getHost) -{ - php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_HOST, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII); -} - -PHP_METHOD(Uri_Rfc3986_Uri, getRawHost) -{ - php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_HOST, PHP_URI_COMPONENT_READ_MODE_RAW); -} - -PHP_METHOD(Uri_Rfc3986_Uri, withHost) -{ - php_uri_property_write_str_or_null_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_HOST); -} - -PHP_METHOD(Uri_Rfc3986_Uri, getPort) -{ - php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_PORT, PHP_URI_COMPONENT_READ_MODE_RAW); -} - -PHP_METHOD(Uri_Rfc3986_Uri, withPort) -{ - php_uri_property_write_long_or_null_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_PORT); -} - -PHP_METHOD(Uri_Rfc3986_Uri, getPath) -{ - php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_PATH, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII); -} - -PHP_METHOD(Uri_Rfc3986_Uri, getRawPath) -{ - php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_PATH, PHP_URI_COMPONENT_READ_MODE_RAW); -} - -PHP_METHOD(Uri_Rfc3986_Uri, withPath) -{ - php_uri_property_write_str_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_PATH); -} - -PHP_METHOD(Uri_Rfc3986_Uri, getQuery) -{ - php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_QUERY, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII); -} - -PHP_METHOD(Uri_Rfc3986_Uri, getRawQuery) -{ - php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_QUERY, PHP_URI_COMPONENT_READ_MODE_RAW); -} - -PHP_METHOD(Uri_Rfc3986_Uri, withQuery) -{ - php_uri_property_write_str_or_null_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_QUERY); -} - -PHP_METHOD(Uri_Rfc3986_Uri, getFragment) -{ - php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_FRAGMENT, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII); -} - -PHP_METHOD(Uri_Rfc3986_Uri, getRawFragment) -{ - php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_FRAGMENT, PHP_URI_COMPONENT_READ_MODE_RAW); -} - -PHP_METHOD(Uri_Rfc3986_Uri, withFragment) -{ - php_uri_property_write_str_or_null_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_FRAGMENT); -} - -static void throw_cannot_recompose_uri_to_string(php_uri_object *object) -{ - zend_throw_exception_ex(php_uri_ce_error, 0, "Cannot recompose %s to a string", ZSTR_VAL(object->std.ce->name)); -} - -static void uri_equals(INTERNAL_FUNCTION_PARAMETERS, php_uri_object *that_object, zend_object *comparison_mode) -{ - php_uri_object *this_object = Z_URI_OBJECT_P(ZEND_THIS); - ZEND_ASSERT(this_object->uri != NULL); - ZEND_ASSERT(that_object->uri != NULL); - - if (this_object->std.ce != that_object->std.ce && - !instanceof_function(this_object->std.ce, that_object->std.ce) && - !instanceof_function(that_object->std.ce, this_object->std.ce) - ) { - RETURN_FALSE; - } - - bool exclude_fragment = true; - if (comparison_mode) { - zval *case_name = zend_enum_fetch_case_name(comparison_mode); - exclude_fragment = zend_string_equals_literal(Z_STR_P(case_name), "ExcludeFragment"); - } - - zend_string *this_str = this_object->parser->to_string( - this_object->uri, PHP_URI_RECOMPOSITION_MODE_NORMALIZED_ASCII, exclude_fragment); - if (this_str == NULL) { - throw_cannot_recompose_uri_to_string(this_object); - RETURN_THROWS(); - } - - zend_string *that_str = that_object->parser->to_string( - that_object->uri, PHP_URI_RECOMPOSITION_MODE_NORMALIZED_ASCII, exclude_fragment); - if (that_str == NULL) { - zend_string_release(this_str); - throw_cannot_recompose_uri_to_string(that_object); - RETURN_THROWS(); - } - - RETVAL_BOOL(zend_string_equals(this_str, that_str)); - - zend_string_release(this_str); - 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, php_uri_ce_rfc3986_uri) - Z_PARAM_OPTIONAL - Z_PARAM_OBJ_OF_CLASS(comparison_mode, php_uri_ce_comparison_mode) - ZEND_PARSE_PARAMETERS_END(); - - uri_equals(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_uri_object_from_obj(that_object), comparison_mode); -} - -PHP_METHOD(Uri_Rfc3986_Uri, toRawString) -{ - ZEND_PARSE_PARAMETERS_NONE(); - - php_uri_object *uri_object = Z_URI_OBJECT_P(ZEND_THIS); - ZEND_ASSERT(uri_object->uri != NULL); - - zend_string *uri_str = uri_object->parser->to_string(uri_object->uri, PHP_URI_RECOMPOSITION_MODE_RAW_ASCII, false); - if (uri_str == NULL) { - throw_cannot_recompose_uri_to_string(uri_object); - RETURN_THROWS(); - } - - RETURN_STR(uri_str); -} - -PHP_METHOD(Uri_Rfc3986_Uri, toString) -{ - ZEND_PARSE_PARAMETERS_NONE(); - - php_uri_object *uri_object = Z_URI_OBJECT_P(ZEND_THIS); - ZEND_ASSERT(uri_object->uri != NULL); - - zend_string *uri_str = uri_object->parser->to_string(uri_object->uri, PHP_URI_RECOMPOSITION_MODE_NORMALIZED_ASCII, false); - if (uri_str == NULL) { - throw_cannot_recompose_uri_to_string(uri_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(); - - php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, - uri_str, Z_URI_OBJECT_P(ZEND_THIS), true, false, NULL); -} - -PHP_METHOD(Uri_Rfc3986_Uri, __serialize) -{ - ZEND_PARSE_PARAMETERS_NONE(); - - php_uri_object *uri_object = Z_URI_OBJECT_P(ZEND_THIS); - ZEND_ASSERT(uri_object->uri != NULL); - - /* Serialize state: "uri" key in the first array */ - zend_string *uri_str = uri_object->parser->to_string(uri_object->uri, PHP_URI_RECOMPOSITION_MODE_RAW_ASCII, false); - if (uri_str == NULL) { - throw_cannot_recompose_uri_to_string(uri_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), PHP_URI_SERIALIZE_URI_FIELD_NAME, sizeof(PHP_URI_SERIALIZE_URI_FIELD_NAME) - 1, &tmp); - zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &arr); - - /* Serialize regular properties: second array */ - ZVAL_ARR(&arr, uri_object->std.handlers->get_properties(&uri_object->std)); - Z_TRY_ADDREF(arr); - zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &arr); -} - -static void uri_unserialize(INTERNAL_FUNCTION_PARAMETERS) -{ - HashTable *data; - - ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ARRAY_HT(data) - ZEND_PARSE_PARAMETERS_END(); - - php_uri_object *uri_object = php_uri_object_from_obj(Z_OBJ_P(ZEND_THIS)); - if (uri_object->uri != NULL) { - /* Intentionally throw two exceptions for proper chaining. */ - zend_throw_error(NULL, "Cannot modify readonly object of class %s", ZSTR_VAL(uri_object->std.ce->name)); - zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_object->std.ce->name)); - RETURN_THROWS(); - } - - /* Verify the expected number of elements, this implicitly ensures that no additional elements are present. */ - if (zend_hash_num_elements(data) != 2) { - zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_object->std.ce->name)); - RETURN_THROWS(); - } - - /* Unserialize state: "uri" key in the first array */ - zval *arr = zend_hash_index_find(data, 0); - if (arr == NULL || Z_TYPE_P(arr) != IS_ARRAY) { - zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_object->std.ce->name)); - RETURN_THROWS(); - } - - /* Verify the expected number of elements inside the first array, this implicitly ensures that no additional elements are present. */ - if (zend_hash_num_elements(Z_ARRVAL_P(arr)) != 1) { - zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_object->std.ce->name)); - RETURN_THROWS(); - } - - zval *uri_zv = zend_hash_str_find_ind(Z_ARRVAL_P(arr), ZEND_STRL(PHP_URI_SERIALIZE_URI_FIELD_NAME)); - if (uri_zv == NULL || Z_TYPE_P(uri_zv) != IS_STRING) { - zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_object->std.ce->name)); - RETURN_THROWS(); - } - - uri_object->uri = uri_object->parser->parse(Z_STRVAL_P(uri_zv), Z_STRLEN_P(uri_zv), NULL, NULL, true); - if (uri_object->uri == NULL) { - zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_object->std.ce->name)); - RETURN_THROWS(); - } - - /* Unserialize regular properties: second array */ - arr = zend_hash_index_find(data, 1); - if (arr == NULL || Z_TYPE_P(arr) != IS_ARRAY) { - zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_object->std.ce->name)); - RETURN_THROWS(); - } - - /* Verify that there is no regular property in the second array, because the URI classes have no properties and they are final. */ - if (zend_hash_num_elements(Z_ARRVAL_P(arr)) > 0) { - zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_object->std.ce->name)); - RETURN_THROWS(); - } -} - -PHP_METHOD(Uri_Rfc3986_Uri, __unserialize) -{ - uri_unserialize(INTERNAL_FUNCTION_PARAM_PASSTHRU); -} - -PHP_METHOD(Uri_Rfc3986_Uri, __debugInfo) -{ - ZEND_PARSE_PARAMETERS_NONE(); - - php_uri_object *uri_object = Z_URI_OBJECT_P(ZEND_THIS); - - RETURN_ARR(uri_get_debug_properties(uri_object)); -} - -PHP_METHOD(Uri_WhatWg_Url, getScheme) -{ - php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_SCHEME, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII); -} - -PHP_METHOD(Uri_WhatWg_Url, withScheme) -{ - php_uri_property_write_str_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_SCHEME); -} - -PHP_METHOD(Uri_WhatWg_Url, withUsername) -{ - php_uri_property_write_str_or_null_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_USERNAME); -} - -PHP_METHOD(Uri_WhatWg_Url, withPassword) -{ - php_uri_property_write_str_or_null_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_PASSWORD); -} - -PHP_METHOD(Uri_WhatWg_Url, getAsciiHost) -{ - php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_HOST, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII); -} - -PHP_METHOD(Uri_WhatWg_Url, getUnicodeHost) -{ - php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_HOST, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_UNICODE); -} - -PHP_METHOD(Uri_WhatWg_Url, getFragment) -{ - php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_FRAGMENT, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_UNICODE); -} - -PHP_METHOD(Uri_WhatWg_Url, equals) -{ - zend_object *that_object; - zend_object *comparison_mode = NULL; - - ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_OBJ_OF_CLASS(that_object, php_uri_ce_whatwg_url) - Z_PARAM_OPTIONAL - Z_PARAM_OBJ_OF_CLASS(comparison_mode, php_uri_ce_comparison_mode) - ZEND_PARSE_PARAMETERS_END(); - - uri_equals(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_uri_object_from_obj(that_object), comparison_mode); -} - -PHP_METHOD(Uri_WhatWg_Url, toUnicodeString) -{ - ZEND_PARSE_PARAMETERS_NONE(); - - zend_object *this_object = Z_OBJ_P(ZEND_THIS); - php_uri_object *uri_object = php_uri_object_from_obj(this_object); - ZEND_ASSERT(uri_object->uri != NULL); - - RETURN_STR(uri_object->parser->to_string(uri_object->uri, PHP_URI_RECOMPOSITION_MODE_RAW_UNICODE, false)); -} - -PHP_METHOD(Uri_WhatWg_Url, toAsciiString) -{ - ZEND_PARSE_PARAMETERS_NONE(); - - zend_object *this_object = Z_OBJ_P(ZEND_THIS); - php_uri_object *uri_object = php_uri_object_from_obj(this_object); - ZEND_ASSERT(uri_object->uri != NULL); - - RETURN_STR(uri_object->parser->to_string(uri_object->uri, PHP_URI_RECOMPOSITION_MODE_RAW_ASCII, false)); -} - -PHP_METHOD(Uri_WhatWg_Url, resolve) -{ - zend_string *uri_str; - zval *errors = NULL; - - ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_PATH_STR(uri_str) - Z_PARAM_OPTIONAL - Z_PARAM_ZVAL(errors) - ZEND_PARSE_PARAMETERS_END(); - - php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, - uri_str, Z_URI_OBJECT_P(ZEND_THIS), true, false, errors); -} - -PHP_METHOD(Uri_WhatWg_Url, __serialize) -{ - ZEND_PARSE_PARAMETERS_NONE(); - - php_uri_object *this_object = Z_URI_OBJECT_P(ZEND_THIS); - ZEND_ASSERT(this_object->uri != NULL); - - /* Serialize state: "uri" key in the first array */ - zend_string *uri_str = this_object->parser->to_string(this_object->uri, PHP_URI_RECOMPOSITION_MODE_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), ZEND_STRL(PHP_URI_SERIALIZE_URI_FIELD_NAME), &tmp); - zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &arr); - - /* Serialize regular properties: second array */ - ZVAL_ARR(&arr, this_object->std.handlers->get_properties(&this_object->std)); - Z_ADDREF(arr); - zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &arr); -} - -PHP_METHOD(Uri_WhatWg_Url, __unserialize) -{ - uri_unserialize(INTERNAL_FUNCTION_PARAM_PASSTHRU); -} - -PHP_METHOD(Uri_WhatWg_Url, __debugInfo) -{ - ZEND_PARSE_PARAMETERS_NONE(); - - php_uri_object *uri_object = Z_URI_OBJECT_P(ZEND_THIS); - - RETURN_ARR(uri_get_debug_properties(uri_object)); -} - -PHPAPI php_uri_object *php_uri_object_create(zend_class_entry *class_type, const php_uri_parser *parser) -{ - php_uri_object *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); - - uri_object->parser = parser; - uri_object->uri = NULL; - - return uri_object; -} - static zend_object *php_uri_object_create_rfc3986(zend_class_entry *ce) { return &php_uri_object_create(ce, &php_uri_parser_rfc3986)->std; @@ -1032,52 +297,13 @@ static zend_object *php_uri_object_create_whatwg(zend_class_entry *ce) return &php_uri_object_create(ce, &php_uri_parser_whatwg)->std; } -PHPAPI void php_uri_object_handler_free(zend_object *object) -{ - php_uri_object *uri_object = php_uri_object_from_obj(object); - - uri_object->parser->destroy(uri_object->uri); - zend_object_std_dtor(&uri_object->std); -} - -PHPAPI zend_object *php_uri_object_handler_clone(zend_object *object) -{ - php_uri_object *uri_object = php_uri_object_from_obj(object); - - ZEND_ASSERT(uri_object->uri != NULL); - - php_uri_object *new_uri_object = php_uri_object_from_obj(object->ce->create_object(object->ce)); - ZEND_ASSERT(new_uri_object->parser == uri_object->parser); - - void *uri = uri_object->parser->clone(uri_object->uri); - ZEND_ASSERT(uri != NULL); - - new_uri_object->uri = uri; - - zend_objects_clone_members(&new_uri_object->std, &uri_object->std); - - return &new_uri_object->std; -} - -PHPAPI zend_result php_uri_parser_register(const php_uri_parser *uri_parser) -{ - zend_string *key = zend_string_init_interned(uri_parser->name, strlen(uri_parser->name), true); - - ZEND_ASSERT(uri_parser->name != NULL); - ZEND_ASSERT(uri_parser->parse != NULL); - ZEND_ASSERT(uri_parser->clone != NULL || strcmp(uri_parser->name, PHP_URI_PARSER_PHP_PARSE_URL) == 0); - ZEND_ASSERT(uri_parser->to_string != NULL || strcmp(uri_parser->name, PHP_URI_PARSER_PHP_PARSE_URL) == 0); - ZEND_ASSERT(uri_parser->destroy != NULL); - - zend_result result = zend_hash_add_ptr(&uri_parsers, key, (void *) uri_parser) != NULL ? SUCCESS : FAILURE; - - zend_string_release_ex(key, true); - - return result; -} - static PHP_MINIT_FUNCTION(uri) { + php_uri_ce_comparison_mode = register_class_Uri_UriComparisonMode(); + php_uri_ce_exception = register_class_Uri_UriException(zend_ce_exception); + php_uri_ce_error = register_class_Uri_UriError(zend_ce_error); + php_uri_ce_invalid_uri_exception = register_class_Uri_InvalidUriException(php_uri_ce_exception); + php_uri_ce_rfc3986_uri = register_class_Uri_Rfc3986_Uri(); php_uri_ce_rfc3986_uri->create_object = php_uri_object_create_rfc3986; php_uri_ce_rfc3986_uri->default_object_handlers = &object_handlers_rfc3986_uri; @@ -1086,6 +312,16 @@ static PHP_MINIT_FUNCTION(uri) object_handlers_rfc3986_uri.free_obj = php_uri_object_handler_free; object_handlers_rfc3986_uri.clone_obj = php_uri_object_handler_clone; + php_uri_ce_rfc3986_uri_host_type = register_class_Uri_Rfc3986_UriHostType(); + php_uri_ce_rfc3986_percent_encoding_mode = register_class_Uri_Rfc3986_PercentEncodingMode(); + php_uri_ce_rfc3986_uri_query_params = register_class_Uri_Rfc3986_UriQueryParams(); + php_uri_ce_rfc3986_uri_query_params->create_object = php_uri_object_create_rfc3986_uri_query_params; + php_uri_ce_rfc3986_uri_query_params->default_object_handlers = &object_handlers_rfc3986_uri_query_params; + memcpy(&object_handlers_rfc3986_uri_query_params, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + object_handlers_rfc3986_uri_query_params.offset = XtOffsetOf(php_uri_parser_rfc3986_uri_query_params_object, std); + object_handlers_rfc3986_uri_query_params.free_obj = php_uri_rfc3986_uri_query_params_object_handler_free; + object_handlers_rfc3986_uri_query_params.clone_obj = php_uri_rfc3986_uri_query_params_object_handler_clone; + php_uri_ce_whatwg_url = register_class_Uri_WhatWg_Url(); php_uri_ce_whatwg_url->create_object = php_uri_object_create_whatwg; php_uri_ce_whatwg_url->default_object_handlers = &object_handlers_whatwg_uri; @@ -1094,14 +330,20 @@ static PHP_MINIT_FUNCTION(uri) object_handlers_whatwg_uri.free_obj = php_uri_object_handler_free; object_handlers_whatwg_uri.clone_obj = php_uri_object_handler_clone; - php_uri_ce_comparison_mode = register_class_Uri_UriComparisonMode(); - php_uri_ce_exception = register_class_Uri_UriException(zend_ce_exception); - php_uri_ce_error = register_class_Uri_UriError(zend_ce_error); - php_uri_ce_invalid_uri_exception = register_class_Uri_InvalidUriException(php_uri_ce_exception); php_uri_ce_whatwg_invalid_url_exception = register_class_Uri_WhatWg_InvalidUrlException(php_uri_ce_invalid_uri_exception); php_uri_ce_whatwg_url_validation_error = register_class_Uri_WhatWg_UrlValidationError(); php_uri_ce_whatwg_url_validation_error_type = register_class_Uri_WhatWg_UrlValidationErrorType(); + php_uri_ce_whatwg_url_host_type = register_class_Uri_WhatWg_UrlHostType(); + php_uri_ce_whatwg_url_component = register_class_Uri_WhatWg_UrlComponent(); + php_uri_ce_whatwg_url_query_params = register_class_Uri_WhatWg_UrlQueryParams(); + php_uri_ce_whatwg_url_query_params->create_object = php_uri_object_create_rfc3986_uri_query_params; + php_uri_ce_whatwg_url_query_params->default_object_handlers = &object_handlers_whatwg_url_query_params; + memcpy(&object_handlers_whatwg_url_query_params, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + object_handlers_whatwg_url_query_params.offset = XtOffsetOf(php_uri_parser_whatwg_url_query_params_object, std); + object_handlers_whatwg_url_query_params.free_obj = php_uri_whatwg_url_query_params_object_handler_free; + object_handlers_whatwg_url_query_params.clone_obj = php_uri_whatwg_url_query_params_object_handler_clone; + zend_hash_init(&uri_parsers, 4, NULL, NULL, true); if (php_uri_parser_register(&php_uri_parser_rfc3986) == FAILURE) { diff --git a/ext/uri/php_uri.stub.php b/ext/uri/php_uri.stub.php index 9f12fbb1c0701..375921391829a 100644 --- a/ext/uri/php_uri.stub.php +++ b/ext/uri/php_uri.stub.php @@ -29,6 +29,10 @@ enum UriComparisonMode /** @strict-properties */ final readonly class Uri { + public static function percentEncode(string $input, \Uri\Rfc3986\PercentEncodingMode $mode): string {} + + public static function percentDecode(string $input, \Uri\Rfc3986\PercentEncodingMode $mode): string {} + public static function parse(string $uri, ?\Uri\Rfc3986\Uri $baseUrl = null): ?static {} public function __construct(string $uri, ?\Uri\Rfc3986\Uri $baseUrl = null) {} @@ -57,6 +61,8 @@ public function getHost(): ?string {} public function getRawHost(): ?string {} + public function getHostType(): ?\Uri\Rfc3986\UriHostType {} + public function withHost(?string $host): static {} public function getPort(): ?int {} @@ -67,14 +73,28 @@ public function getPath(): string {} public function getRawPath(): string {} + public function getRawPathSegments(): ?array {} + + public function getPathSegments(): ?array {} + public function withPath(string $path): static {} + #[\NoDiscard(message: "as Uri\Rfc3986\Uri::withPathSegments() does not modify the object itself")] + public function withPathSegments(array $segments): static {} + public function getQuery(): ?string {} public function getRawQuery(): ?string {} + public function getQueryParams(): ?\Uri\Rfc3986\UriQueryParams {} + + public function getRawQueryParams(): ?\Uri\Rfc3986\UriQueryParams {} + public function withQuery(?string $query): static {} + #[\NoDiscard(message: "as Uri\Rfc3986\Uri::withQueryParams() does not modify the object itself")] + public function withQueryParams(?\Uri\Rfc3986\UriQueryParams $queryParams): static {} + public function getFragment(): ?string {} public function getRawFragment(): ?string {} @@ -95,6 +115,87 @@ public function __unserialize(array $data): void {} public function __debugInfo(): array {} } + + final readonly class UriQueryParams + { + public static function parse(string $queryString): ?\Uri\Rfc3986\UriQueryParams {} + + public static function fromArray(array $queryParams): \Uri\Rfc3986\UriQueryParams {} + + public function append(string $name, mixed $value): void {} + + public function delete(string $name): void {} + + public function has(string $name): bool {} + + public function getFirst(string $name): mixed {} + + public function getLast(string $name): mixed {} + + public function getAll(): mixed {} + + public function set(string $name, mixed $value): mixed {} + + public function sort(): mixed {} + + public function toString(): string {} + + public function __serialize(): array {} + + public function __unserialize(array $data): void {} + + public function __debugInfo(): array {} + } + +/* + final class UriBuilder + { + public function __construct() {} + + public function setScheme(?string $scheme): \Uri\Rfc3986\UriBuilder {} + + public function setUsername(?string $username): \Uri\Rfc3986\UriBuilder {} + + public function setPassword(?string $password): \Uri\Rfc3986\UriBuilder {} + + public function setUserInfo(?string $userInfo): \Uri\Rfc3986\UriBuilder {} + + public function setHost(?string $host): \Uri\Rfc3986\UriBuilder {} + + public function setPath(string $path): \Uri\Rfc3986\UriBuilder {} + + public function setQuery(?string $query): \Uri\Rfc3986\UriBuilder {} + + public function setFragment(?string $fragment): \Uri\Rfc3986\UriBuilder {} + + public function buildRawUri(): \Uri\Rfc3986\Uri {} + + public function buildNormalizedUri(): \Uri\Rfc3986\Uri {} + } +*/ + + enum PercentEncodingMode + { + case UserInfo; + case Host; + case RelativeReferencePath; + case RelativeReferenceFirstPathSegment; + case Path; + case PathSegment; + case Query; + case FormQuery; + case Fragment; + case AllReservedCharacters; + case All; + } + + enum UriHostType + { + case IPv4; + case IPv6; + case IPvFuture; + case RegisteredName; + } } namespace Uri\WhatWg { @@ -152,6 +253,10 @@ public function __construct(string $context, \Uri\WhatWg\UrlValidationErrorType /** @strict-properties */ final readonly class Url { + public static function percentEncodeComponent(string $input, \Uri\WhatWg\UrlComponent $component): string {} + + public static function percentDecodeComponent(string $input, \Uri\WhatWg\UrlComponent $component): string {} + /** @param array $errors */ public static function parse(string $uri, ?\Uri\WhatWg\Url $baseUrl = null, &$errors = null): ?static {} @@ -162,6 +267,8 @@ public function getScheme(): string {} public function withScheme(string $scheme): static {} + public function isSpecial(): bool {} + /** @implementation-alias Uri\Rfc3986\Uri::getUsername */ public function getUsername(): ?string {} @@ -176,6 +283,8 @@ public function getAsciiHost(): ?string {} public function getUnicodeHost(): ?string {} + public function getHostType(): ?\Uri\WhatWg\UrlHostType {} + /** @implementation-alias Uri\Rfc3986\Uri::withHost */ public function withHost(?string $host): static {} @@ -188,15 +297,25 @@ public function withPort(?int $port): static {} /** @implementation-alias Uri\Rfc3986\Uri::getPath */ public function getPath(): string {} + public function getPathSegments(): array {} + /** @implementation-alias Uri\Rfc3986\Uri::withPath */ public function withPath(string $path): static {} + #[\NoDiscard(message: "as Uri\WhatWg\Url::withPathSegments() does not modify the object itself")] + public function withPathSegments(array $segments): static {} + /** @implementation-alias Uri\Rfc3986\Uri::getQuery */ public function getQuery(): ?string {} + public function getQueryParams(): ?\Uri\WhatWg\UrlQueryParams {} + /** @implementation-alias Uri\Rfc3986\Uri::withQuery */ public function withQuery(?string $query): static {} + #[\NoDiscard(message: "as Uri\WhatWg\Url::withQueryParams() does not modify the object itself")] + public function withQueryParams(?\Uri\WhatWg\UrlQueryParams $queryParams): static {} + /** @implementation-alias Uri\Rfc3986\Uri::getFragment */ public function getFragment(): ?string {} @@ -218,4 +337,86 @@ public function __unserialize(array $data): void {} public function __debugInfo(): array {} } + + final readonly class UrlQueryParams + { + public static function parse(string $queryString): ?\Uri\WhatWg\UrlQueryParams {} + + public static function fromArray(array $queryParams): ?\Uri\WhatWg\UrlQueryParams {} + + public function append(string $name, mixed $value): void {} + + public function delete(string $name): void {} + + public function deleteWithValue(string $name, string $value): void {} + + public function has(string $name): bool {} + + public function hasWithValue(string $name, string $value): bool {} + + public function getFirst(string $name): mixed {} + + public function getLast(string $name): mixed {} + + public function getAll(): mixed {} + + public function set(string $name, mixed $value): mixed {} + + public function sort(): mixed {} + + public function toString(): string {} + + public function __serialize(): array {} + + public function __unserialize(array $data): void {} + + public function __debugInfo(): array {} + } + + +/* + final class UrlBuilder + { + public function __construct() {} + + public function setScheme(?string $scheme): \Uri\Whatwg\UrlBuilder {} + + public function setUsername(?string $username): \Uri\Whatwg\UrlBuilder {} + + public function setPassword(?string $password): \Uri\Whatwg\UrlBuilder {} + + public function setUserInfo(?string $userInfo): \Uri\Whatwg\UrlBuilder {} + + public function setHost(?string $host): \Uri\Whatwg\UrlBuilder {} + + public function setPath(string $path): \Uri\Whatwg\UrlBuilder {} + + public function setQuery(?string $query): \Uri\Whatwg\UrlBuilder {} + + public function setFragment(?string $fragment): \Uri\Whatwg\UrlBuilder {} + + public function buildUrl(): \Uri\Whatwg\Url {} + } +*/ + + enum UrlComponent + { + case Scheme; + case Username; + case Password; + case Host; + case Port; + case Path; + case Query; + case Fragment; + } + + enum UrlHostType + { + case IPv4; + case IPv6; + case Domain; + case Opaque; + case Empty; + } } diff --git a/ext/uri/php_uri_arginfo.h b/ext/uri/php_uri_arginfo.h index d3a9c4fde7bca..83d2dac0d59d4 100644 --- a/ext/uri/php_uri_arginfo.h +++ b/ext/uri/php_uri_arginfo.h @@ -1,5 +1,12 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: f3c524798d1933a400cc9377cfbfdcbaf77b87f0 */ + * Stub hash: ddd64457340cd0d53c9ad92f0e18d2787446d4af */ + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_percentEncode, 0, 2, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, input, IS_STRING, 0) + ZEND_ARG_OBJ_INFO(0, mode, Uri\\Rfc3986\\PercentEncodingMode, 0) +ZEND_END_ARG_INFO() + +#define arginfo_class_Uri_Rfc3986_Uri_percentDecode arginfo_class_Uri_Rfc3986_Uri_percentEncode 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) @@ -40,6 +47,9 @@ ZEND_END_ARG_INFO() #define arginfo_class_Uri_Rfc3986_Uri_getRawHost arginfo_class_Uri_Rfc3986_Uri_getScheme +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_getHostType, 0, 0, Uri\\Rfc3986\\\125riHostType, 1) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_withHost, 0, 1, IS_STATIC, 0) ZEND_ARG_TYPE_INFO(0, host, IS_STRING, 1) ZEND_END_ARG_INFO() @@ -56,18 +66,36 @@ ZEND_END_ARG_INFO() #define arginfo_class_Uri_Rfc3986_Uri_getRawPath arginfo_class_Uri_Rfc3986_Uri_getPath +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_getRawPathSegments, 0, 0, IS_ARRAY, 1) +ZEND_END_ARG_INFO() + +#define arginfo_class_Uri_Rfc3986_Uri_getPathSegments arginfo_class_Uri_Rfc3986_Uri_getRawPathSegments + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_withPath, 0, 1, IS_STATIC, 0) ZEND_ARG_TYPE_INFO(0, path, IS_STRING, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_withPathSegments, 0, 1, IS_STATIC, 0) + ZEND_ARG_TYPE_INFO(0, segments, IS_ARRAY, 0) +ZEND_END_ARG_INFO() + #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 +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_getQueryParams, 0, 0, Uri\\Rfc3986\\\125riQueryParams, 1) +ZEND_END_ARG_INFO() + +#define arginfo_class_Uri_Rfc3986_Uri_getRawQueryParams arginfo_class_Uri_Rfc3986_Uri_getQueryParams + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_withQuery, 0, 1, IS_STATIC, 0) ZEND_ARG_TYPE_INFO(0, query, IS_STRING, 1) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_withQueryParams, 0, 1, IS_STATIC, 0) + ZEND_ARG_OBJ_INFO(0, queryParams, Uri\\Rfc3986\\\125riQueryParams, 1) +ZEND_END_ARG_INFO() + #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 @@ -98,6 +126,51 @@ ZEND_END_ARG_INFO() #define arginfo_class_Uri_Rfc3986_Uri___debugInfo arginfo_class_Uri_Rfc3986_Uri___serialize +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Uri_Rfc3986_UriQueryParams_parse, 0, 1, Uri\\Rfc3986\\\125riQueryParams, 1) + ZEND_ARG_TYPE_INFO(0, queryString, IS_STRING, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Uri_Rfc3986_UriQueryParams_fromArray, 0, 1, Uri\\Rfc3986\\\125riQueryParams, 0) + ZEND_ARG_TYPE_INFO(0, queryParams, IS_ARRAY, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_UriQueryParams_append, 0, 2, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_UriQueryParams_delete, 0, 1, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_UriQueryParams_has, 0, 1, _IS_BOOL, 0) + ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_UriQueryParams_getFirst, 0, 1, IS_MIXED, 0) + ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0) +ZEND_END_ARG_INFO() + +#define arginfo_class_Uri_Rfc3986_UriQueryParams_getLast arginfo_class_Uri_Rfc3986_UriQueryParams_getFirst + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_UriQueryParams_getAll, 0, 0, IS_MIXED, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_UriQueryParams_set, 0, 2, IS_MIXED, 0) + ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0) +ZEND_END_ARG_INFO() + +#define arginfo_class_Uri_Rfc3986_UriQueryParams_sort arginfo_class_Uri_Rfc3986_UriQueryParams_getAll + +#define arginfo_class_Uri_Rfc3986_UriQueryParams_toString arginfo_class_Uri_Rfc3986_Uri_getPath + +#define arginfo_class_Uri_Rfc3986_UriQueryParams___serialize arginfo_class_Uri_Rfc3986_Uri___serialize + +#define arginfo_class_Uri_Rfc3986_UriQueryParams___unserialize arginfo_class_Uri_Rfc3986_Uri___unserialize + +#define arginfo_class_Uri_Rfc3986_UriQueryParams___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, "\"\"") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, errors, IS_ARRAY, 0, "[]") @@ -111,6 +184,13 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Uri_WhatWg_UrlValidationError___construct, ZEND_ARG_TYPE_INFO(0, failure, _IS_BOOL, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_percentEncodeComponent, 0, 2, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, input, IS_STRING, 0) + ZEND_ARG_OBJ_INFO(0, component, Uri\\WhatWg\\\125rlComponent, 0) +ZEND_END_ARG_INFO() + +#define arginfo_class_Uri_WhatWg_Url_percentDecodeComponent arginfo_class_Uri_WhatWg_Url_percentEncodeComponent + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_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\\WhatWg\\\125rl, 1, "null") @@ -129,6 +209,9 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_withScheme, 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_isSpecial, 0, 0, _IS_BOOL, 0) +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) @@ -145,6 +228,9 @@ ZEND_END_ARG_INFO() #define arginfo_class_Uri_WhatWg_Url_getUnicodeHost arginfo_class_Uri_Rfc3986_Uri_getScheme +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Uri_WhatWg_Url_getHostType, 0, 0, Uri\\WhatWg\\\125rlHostType, 1) +ZEND_END_ARG_INFO() + #define arginfo_class_Uri_WhatWg_Url_withHost arginfo_class_Uri_Rfc3986_Uri_withHost #define arginfo_class_Uri_WhatWg_Url_getPort arginfo_class_Uri_Rfc3986_Uri_getPort @@ -153,12 +239,23 @@ ZEND_END_ARG_INFO() #define arginfo_class_Uri_WhatWg_Url_getPath arginfo_class_Uri_Rfc3986_Uri_getPath +#define arginfo_class_Uri_WhatWg_Url_getPathSegments arginfo_class_Uri_Rfc3986_Uri___serialize + #define arginfo_class_Uri_WhatWg_Url_withPath arginfo_class_Uri_Rfc3986_Uri_withPath +#define arginfo_class_Uri_WhatWg_Url_withPathSegments arginfo_class_Uri_Rfc3986_Uri_withPathSegments + #define arginfo_class_Uri_WhatWg_Url_getQuery arginfo_class_Uri_Rfc3986_Uri_getScheme +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Uri_WhatWg_Url_getQueryParams, 0, 0, Uri\\WhatWg\\\125rlQueryParams, 1) +ZEND_END_ARG_INFO() + #define arginfo_class_Uri_WhatWg_Url_withQuery arginfo_class_Uri_Rfc3986_Uri_withQuery +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_withQueryParams, 0, 1, IS_STATIC, 0) + ZEND_ARG_OBJ_INFO(0, queryParams, Uri\\WhatWg\\\125rlQueryParams, 1) +ZEND_END_ARG_INFO() + #define arginfo_class_Uri_WhatWg_Url_getFragment arginfo_class_Uri_Rfc3986_Uri_getScheme #define arginfo_class_Uri_WhatWg_Url_withFragment arginfo_class_Uri_Rfc3986_Uri_withFragment @@ -183,6 +280,50 @@ ZEND_END_ARG_INFO() #define arginfo_class_Uri_WhatWg_Url___debugInfo arginfo_class_Uri_Rfc3986_Uri___serialize +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Uri_WhatWg_UrlQueryParams_parse, 0, 1, Uri\\WhatWg\\\125rlQueryParams, 1) + ZEND_ARG_TYPE_INFO(0, queryString, IS_STRING, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Uri_WhatWg_UrlQueryParams_fromArray, 0, 1, Uri\\WhatWg\\\125rlQueryParams, 1) + ZEND_ARG_TYPE_INFO(0, queryParams, IS_ARRAY, 0) +ZEND_END_ARG_INFO() + +#define arginfo_class_Uri_WhatWg_UrlQueryParams_append arginfo_class_Uri_Rfc3986_UriQueryParams_append + +#define arginfo_class_Uri_WhatWg_UrlQueryParams_delete arginfo_class_Uri_Rfc3986_UriQueryParams_delete + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_UrlQueryParams_deleteWithValue, 0, 2, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, value, IS_STRING, 0) +ZEND_END_ARG_INFO() + +#define arginfo_class_Uri_WhatWg_UrlQueryParams_has arginfo_class_Uri_Rfc3986_UriQueryParams_has + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_UrlQueryParams_hasWithValue, 0, 2, _IS_BOOL, 0) + ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, value, IS_STRING, 0) +ZEND_END_ARG_INFO() + +#define arginfo_class_Uri_WhatWg_UrlQueryParams_getFirst arginfo_class_Uri_Rfc3986_UriQueryParams_getFirst + +#define arginfo_class_Uri_WhatWg_UrlQueryParams_getLast arginfo_class_Uri_Rfc3986_UriQueryParams_getFirst + +#define arginfo_class_Uri_WhatWg_UrlQueryParams_getAll arginfo_class_Uri_Rfc3986_UriQueryParams_getAll + +#define arginfo_class_Uri_WhatWg_UrlQueryParams_set arginfo_class_Uri_Rfc3986_UriQueryParams_set + +#define arginfo_class_Uri_WhatWg_UrlQueryParams_sort arginfo_class_Uri_Rfc3986_UriQueryParams_getAll + +#define arginfo_class_Uri_WhatWg_UrlQueryParams_toString arginfo_class_Uri_Rfc3986_Uri_getPath + +#define arginfo_class_Uri_WhatWg_UrlQueryParams___serialize arginfo_class_Uri_Rfc3986_Uri___serialize + +#define arginfo_class_Uri_WhatWg_UrlQueryParams___unserialize arginfo_class_Uri_Rfc3986_Uri___unserialize + +#define arginfo_class_Uri_WhatWg_UrlQueryParams___debugInfo arginfo_class_Uri_Rfc3986_Uri___serialize + +ZEND_METHOD(Uri_Rfc3986_Uri, percentEncode); +ZEND_METHOD(Uri_Rfc3986_Uri, percentDecode); ZEND_METHOD(Uri_Rfc3986_Uri, parse); ZEND_METHOD(Uri_Rfc3986_Uri, __construct); ZEND_METHOD(Uri_Rfc3986_Uri, getScheme); @@ -197,15 +338,22 @@ 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, getHostType); ZEND_METHOD(Uri_Rfc3986_Uri, withHost); ZEND_METHOD(Uri_Rfc3986_Uri, getPort); ZEND_METHOD(Uri_Rfc3986_Uri, withPort); ZEND_METHOD(Uri_Rfc3986_Uri, getPath); ZEND_METHOD(Uri_Rfc3986_Uri, getRawPath); +ZEND_METHOD(Uri_Rfc3986_Uri, getRawPathSegments); +ZEND_METHOD(Uri_Rfc3986_Uri, getPathSegments); ZEND_METHOD(Uri_Rfc3986_Uri, withPath); +ZEND_METHOD(Uri_Rfc3986_Uri, withPathSegments); ZEND_METHOD(Uri_Rfc3986_Uri, getQuery); ZEND_METHOD(Uri_Rfc3986_Uri, getRawQuery); +ZEND_METHOD(Uri_Rfc3986_Uri, getQueryParams); +ZEND_METHOD(Uri_Rfc3986_Uri, getRawQueryParams); ZEND_METHOD(Uri_Rfc3986_Uri, withQuery); +ZEND_METHOD(Uri_Rfc3986_Uri, withQueryParams); ZEND_METHOD(Uri_Rfc3986_Uri, getFragment); ZEND_METHOD(Uri_Rfc3986_Uri, getRawFragment); ZEND_METHOD(Uri_Rfc3986_Uri, withFragment); @@ -216,16 +364,38 @@ 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_Rfc3986_UriQueryParams, parse); +ZEND_METHOD(Uri_Rfc3986_UriQueryParams, fromArray); +ZEND_METHOD(Uri_Rfc3986_UriQueryParams, append); +ZEND_METHOD(Uri_Rfc3986_UriQueryParams, delete); +ZEND_METHOD(Uri_Rfc3986_UriQueryParams, has); +ZEND_METHOD(Uri_Rfc3986_UriQueryParams, getFirst); +ZEND_METHOD(Uri_Rfc3986_UriQueryParams, getLast); +ZEND_METHOD(Uri_Rfc3986_UriQueryParams, getAll); +ZEND_METHOD(Uri_Rfc3986_UriQueryParams, set); +ZEND_METHOD(Uri_Rfc3986_UriQueryParams, sort); +ZEND_METHOD(Uri_Rfc3986_UriQueryParams, toString); +ZEND_METHOD(Uri_Rfc3986_UriQueryParams, __serialize); +ZEND_METHOD(Uri_Rfc3986_UriQueryParams, __unserialize); +ZEND_METHOD(Uri_Rfc3986_UriQueryParams, __debugInfo); ZEND_METHOD(Uri_WhatWg_InvalidUrlException, __construct); ZEND_METHOD(Uri_WhatWg_UrlValidationError, __construct); +ZEND_METHOD(Uri_WhatWg_Url, percentEncodeComponent); +ZEND_METHOD(Uri_WhatWg_Url, percentDecodeComponent); 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, isSpecial); ZEND_METHOD(Uri_WhatWg_Url, withUsername); ZEND_METHOD(Uri_WhatWg_Url, withPassword); ZEND_METHOD(Uri_WhatWg_Url, getAsciiHost); ZEND_METHOD(Uri_WhatWg_Url, getUnicodeHost); +ZEND_METHOD(Uri_WhatWg_Url, getHostType); +ZEND_METHOD(Uri_WhatWg_Url, getPathSegments); +ZEND_METHOD(Uri_WhatWg_Url, withPathSegments); +ZEND_METHOD(Uri_WhatWg_Url, getQueryParams); +ZEND_METHOD(Uri_WhatWg_Url, withQueryParams); ZEND_METHOD(Uri_WhatWg_Url, equals); ZEND_METHOD(Uri_WhatWg_Url, toAsciiString); ZEND_METHOD(Uri_WhatWg_Url, toUnicodeString); @@ -233,8 +403,26 @@ ZEND_METHOD(Uri_WhatWg_Url, resolve); ZEND_METHOD(Uri_WhatWg_Url, __serialize); ZEND_METHOD(Uri_WhatWg_Url, __unserialize); ZEND_METHOD(Uri_WhatWg_Url, __debugInfo); +ZEND_METHOD(Uri_WhatWg_UrlQueryParams, parse); +ZEND_METHOD(Uri_WhatWg_UrlQueryParams, fromArray); +ZEND_METHOD(Uri_WhatWg_UrlQueryParams, append); +ZEND_METHOD(Uri_WhatWg_UrlQueryParams, delete); +ZEND_METHOD(Uri_WhatWg_UrlQueryParams, deleteWithValue); +ZEND_METHOD(Uri_WhatWg_UrlQueryParams, has); +ZEND_METHOD(Uri_WhatWg_UrlQueryParams, hasWithValue); +ZEND_METHOD(Uri_WhatWg_UrlQueryParams, getFirst); +ZEND_METHOD(Uri_WhatWg_UrlQueryParams, getLast); +ZEND_METHOD(Uri_WhatWg_UrlQueryParams, getAll); +ZEND_METHOD(Uri_WhatWg_UrlQueryParams, set); +ZEND_METHOD(Uri_WhatWg_UrlQueryParams, sort); +ZEND_METHOD(Uri_WhatWg_UrlQueryParams, toString); +ZEND_METHOD(Uri_WhatWg_UrlQueryParams, __serialize); +ZEND_METHOD(Uri_WhatWg_UrlQueryParams, __unserialize); +ZEND_METHOD(Uri_WhatWg_UrlQueryParams, __debugInfo); static const zend_function_entry class_Uri_Rfc3986_Uri_methods[] = { + ZEND_ME(Uri_Rfc3986_Uri, percentEncode, arginfo_class_Uri_Rfc3986_Uri_percentEncode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + ZEND_ME(Uri_Rfc3986_Uri, percentDecode, arginfo_class_Uri_Rfc3986_Uri_percentDecode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) 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) @@ -249,15 +437,22 @@ static const zend_function_entry class_Uri_Rfc3986_Uri_methods[] = { 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, getHostType, arginfo_class_Uri_Rfc3986_Uri_getHostType, ZEND_ACC_PUBLIC) ZEND_ME(Uri_Rfc3986_Uri, withHost, arginfo_class_Uri_Rfc3986_Uri_withHost, ZEND_ACC_PUBLIC) ZEND_ME(Uri_Rfc3986_Uri, getPort, arginfo_class_Uri_Rfc3986_Uri_getPort, ZEND_ACC_PUBLIC) ZEND_ME(Uri_Rfc3986_Uri, withPort, arginfo_class_Uri_Rfc3986_Uri_withPort, 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, getRawPathSegments, arginfo_class_Uri_Rfc3986_Uri_getRawPathSegments, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, getPathSegments, arginfo_class_Uri_Rfc3986_Uri_getPathSegments, ZEND_ACC_PUBLIC) ZEND_ME(Uri_Rfc3986_Uri, withPath, arginfo_class_Uri_Rfc3986_Uri_withPath, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, withPathSegments, arginfo_class_Uri_Rfc3986_Uri_withPathSegments, ZEND_ACC_PUBLIC|ZEND_ACC_NODISCARD) 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, getQueryParams, arginfo_class_Uri_Rfc3986_Uri_getQueryParams, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, getRawQueryParams, arginfo_class_Uri_Rfc3986_Uri_getRawQueryParams, ZEND_ACC_PUBLIC) ZEND_ME(Uri_Rfc3986_Uri, withQuery, arginfo_class_Uri_Rfc3986_Uri_withQuery, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, withQueryParams, arginfo_class_Uri_Rfc3986_Uri_withQueryParams, ZEND_ACC_PUBLIC|ZEND_ACC_NODISCARD) 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, withFragment, arginfo_class_Uri_Rfc3986_Uri_withFragment, ZEND_ACC_PUBLIC) @@ -271,6 +466,24 @@ static const zend_function_entry class_Uri_Rfc3986_Uri_methods[] = { ZEND_FE_END }; +static const zend_function_entry class_Uri_Rfc3986_UriQueryParams_methods[] = { + ZEND_ME(Uri_Rfc3986_UriQueryParams, parse, arginfo_class_Uri_Rfc3986_UriQueryParams_parse, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + ZEND_ME(Uri_Rfc3986_UriQueryParams, fromArray, arginfo_class_Uri_Rfc3986_UriQueryParams_fromArray, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + ZEND_ME(Uri_Rfc3986_UriQueryParams, append, arginfo_class_Uri_Rfc3986_UriQueryParams_append, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_UriQueryParams, delete, arginfo_class_Uri_Rfc3986_UriQueryParams_delete, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_UriQueryParams, has, arginfo_class_Uri_Rfc3986_UriQueryParams_has, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_UriQueryParams, getFirst, arginfo_class_Uri_Rfc3986_UriQueryParams_getFirst, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_UriQueryParams, getLast, arginfo_class_Uri_Rfc3986_UriQueryParams_getLast, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_UriQueryParams, getAll, arginfo_class_Uri_Rfc3986_UriQueryParams_getAll, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_UriQueryParams, set, arginfo_class_Uri_Rfc3986_UriQueryParams_set, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_UriQueryParams, sort, arginfo_class_Uri_Rfc3986_UriQueryParams_sort, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_UriQueryParams, toString, arginfo_class_Uri_Rfc3986_UriQueryParams_toString, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_UriQueryParams, __serialize, arginfo_class_Uri_Rfc3986_UriQueryParams___serialize, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_UriQueryParams, __unserialize, arginfo_class_Uri_Rfc3986_UriQueryParams___unserialize, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_UriQueryParams, __debugInfo, arginfo_class_Uri_Rfc3986_UriQueryParams___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 @@ -282,23 +495,31 @@ static const zend_function_entry class_Uri_WhatWg_UrlValidationError_methods[] = }; static const zend_function_entry class_Uri_WhatWg_Url_methods[] = { + ZEND_ME(Uri_WhatWg_Url, percentEncodeComponent, arginfo_class_Uri_WhatWg_Url_percentEncodeComponent, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + ZEND_ME(Uri_WhatWg_Url, percentDecodeComponent, arginfo_class_Uri_WhatWg_Url_percentDecodeComponent, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) ZEND_ME(Uri_WhatWg_Url, parse, arginfo_class_Uri_WhatWg_Url_parse, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) 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, isSpecial, arginfo_class_Uri_WhatWg_Url_isSpecial, 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_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, getHostType, arginfo_class_Uri_WhatWg_Url_getHostType, ZEND_ACC_PUBLIC) ZEND_RAW_FENTRY("withHost", zim_Uri_Rfc3986_Uri_withHost, arginfo_class_Uri_WhatWg_Url_withHost, ZEND_ACC_PUBLIC, NULL, NULL) ZEND_RAW_FENTRY("getPort", zim_Uri_Rfc3986_Uri_getPort, arginfo_class_Uri_WhatWg_Url_getPort, ZEND_ACC_PUBLIC, NULL, NULL) ZEND_RAW_FENTRY("withPort", zim_Uri_Rfc3986_Uri_withPort, arginfo_class_Uri_WhatWg_Url_withPort, ZEND_ACC_PUBLIC, NULL, NULL) 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, getPathSegments, arginfo_class_Uri_WhatWg_Url_getPathSegments, ZEND_ACC_PUBLIC) ZEND_RAW_FENTRY("withPath", zim_Uri_Rfc3986_Uri_withPath, arginfo_class_Uri_WhatWg_Url_withPath, ZEND_ACC_PUBLIC, NULL, NULL) + ZEND_ME(Uri_WhatWg_Url, withPathSegments, arginfo_class_Uri_WhatWg_Url_withPathSegments, ZEND_ACC_PUBLIC|ZEND_ACC_NODISCARD) 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, getQueryParams, arginfo_class_Uri_WhatWg_Url_getQueryParams, ZEND_ACC_PUBLIC) ZEND_RAW_FENTRY("withQuery", zim_Uri_Rfc3986_Uri_withQuery, arginfo_class_Uri_WhatWg_Url_withQuery, ZEND_ACC_PUBLIC, NULL, NULL) + ZEND_ME(Uri_WhatWg_Url, withQueryParams, arginfo_class_Uri_WhatWg_Url_withQueryParams, ZEND_ACC_PUBLIC|ZEND_ACC_NODISCARD) ZEND_RAW_FENTRY("getFragment", zim_Uri_Rfc3986_Uri_getFragment, arginfo_class_Uri_WhatWg_Url_getFragment, ZEND_ACC_PUBLIC, NULL, NULL) ZEND_RAW_FENTRY("withFragment", zim_Uri_Rfc3986_Uri_withFragment, arginfo_class_Uri_WhatWg_Url_withFragment, ZEND_ACC_PUBLIC, NULL, NULL) ZEND_ME(Uri_WhatWg_Url, equals, arginfo_class_Uri_WhatWg_Url_equals, ZEND_ACC_PUBLIC) @@ -311,6 +532,26 @@ static const zend_function_entry class_Uri_WhatWg_Url_methods[] = { ZEND_FE_END }; +static const zend_function_entry class_Uri_WhatWg_UrlQueryParams_methods[] = { + ZEND_ME(Uri_WhatWg_UrlQueryParams, parse, arginfo_class_Uri_WhatWg_UrlQueryParams_parse, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + ZEND_ME(Uri_WhatWg_UrlQueryParams, fromArray, arginfo_class_Uri_WhatWg_UrlQueryParams_fromArray, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + ZEND_ME(Uri_WhatWg_UrlQueryParams, append, arginfo_class_Uri_WhatWg_UrlQueryParams_append, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_UrlQueryParams, delete, arginfo_class_Uri_WhatWg_UrlQueryParams_delete, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_UrlQueryParams, deleteWithValue, arginfo_class_Uri_WhatWg_UrlQueryParams_deleteWithValue, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_UrlQueryParams, has, arginfo_class_Uri_WhatWg_UrlQueryParams_has, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_UrlQueryParams, hasWithValue, arginfo_class_Uri_WhatWg_UrlQueryParams_hasWithValue, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_UrlQueryParams, getFirst, arginfo_class_Uri_WhatWg_UrlQueryParams_getFirst, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_UrlQueryParams, getLast, arginfo_class_Uri_WhatWg_UrlQueryParams_getLast, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_UrlQueryParams, getAll, arginfo_class_Uri_WhatWg_UrlQueryParams_getAll, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_UrlQueryParams, set, arginfo_class_Uri_WhatWg_UrlQueryParams_set, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_UrlQueryParams, sort, arginfo_class_Uri_WhatWg_UrlQueryParams_sort, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_UrlQueryParams, toString, arginfo_class_Uri_WhatWg_UrlQueryParams_toString, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_UrlQueryParams, __serialize, arginfo_class_Uri_WhatWg_UrlQueryParams___serialize, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_UrlQueryParams, __unserialize, arginfo_class_Uri_WhatWg_UrlQueryParams___unserialize, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_UrlQueryParams, __debugInfo, arginfo_class_Uri_WhatWg_UrlQueryParams___debugInfo, ZEND_ACC_PUBLIC) + ZEND_FE_END +}; + static zend_class_entry *register_class_Uri_UriException(zend_class_entry *class_entry_Exception) { zend_class_entry ce, *class_entry; @@ -362,6 +603,74 @@ static zend_class_entry *register_class_Uri_Rfc3986_Uri(void) zend_add_parameter_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "withuserinfo", sizeof("withuserinfo") - 1), 0, ZSTR_KNOWN(ZEND_STR_SENSITIVEPARAMETER), 0); + zend_string *attribute_name_NoDiscard_func_withpathsegments_0 = zend_string_init_interned("NoDiscard", sizeof("NoDiscard") - 1, true); + zend_attribute *attribute_NoDiscard_func_withpathsegments_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "withpathsegments", sizeof("withpathsegments") - 1), attribute_name_NoDiscard_func_withpathsegments_0, 1); + zend_string_release_ex(attribute_name_NoDiscard_func_withpathsegments_0, true); + zend_string *attribute_NoDiscard_func_withpathsegments_0_arg0_str = zend_string_init("as Uri\\Rfc3986\\Uri::withPathSegments() does not modify the object itself", strlen("as Uri\\Rfc3986\\Uri::withPathSegments() does not modify the object itself"), 1); + ZVAL_STR(&attribute_NoDiscard_func_withpathsegments_0->args[0].value, attribute_NoDiscard_func_withpathsegments_0_arg0_str); + attribute_NoDiscard_func_withpathsegments_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE); + + zend_string *attribute_name_NoDiscard_func_withqueryparams_0 = zend_string_init_interned("NoDiscard", sizeof("NoDiscard") - 1, true); + zend_attribute *attribute_NoDiscard_func_withqueryparams_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "withqueryparams", sizeof("withqueryparams") - 1), attribute_name_NoDiscard_func_withqueryparams_0, 1); + zend_string_release_ex(attribute_name_NoDiscard_func_withqueryparams_0, true); + zend_string *attribute_NoDiscard_func_withqueryparams_0_arg0_str = zend_string_init("as Uri\\Rfc3986\\Uri::withQueryParams() does not modify the object itself", strlen("as Uri\\Rfc3986\\Uri::withQueryParams() does not modify the object itself"), 1); + ZVAL_STR(&attribute_NoDiscard_func_withqueryparams_0->args[0].value, attribute_NoDiscard_func_withqueryparams_0_arg0_str); + attribute_NoDiscard_func_withqueryparams_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE); + + return class_entry; +} + +static zend_class_entry *register_class_Uri_Rfc3986_UriQueryParams(void) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "Uri\\Rfc3986", "UriQueryParams", class_Uri_Rfc3986_UriQueryParams_methods); + class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_READONLY_CLASS); + + return class_entry; +} + +static zend_class_entry *register_class_Uri_Rfc3986_PercentEncodingMode(void) +{ + zend_class_entry *class_entry = zend_register_internal_enum("Uri\\Rfc3986\\PercentEncodingMode", IS_UNDEF, NULL); + + zend_enum_add_case_cstr(class_entry, "UserInfo", NULL); + + zend_enum_add_case_cstr(class_entry, "Host", NULL); + + zend_enum_add_case_cstr(class_entry, "RelativeReferencePath", NULL); + + zend_enum_add_case_cstr(class_entry, "RelativeReferenceFirstPathSegment", NULL); + + zend_enum_add_case_cstr(class_entry, "Path", NULL); + + zend_enum_add_case_cstr(class_entry, "PathSegment", NULL); + + zend_enum_add_case_cstr(class_entry, "Query", NULL); + + zend_enum_add_case_cstr(class_entry, "FormQuery", NULL); + + zend_enum_add_case_cstr(class_entry, "Fragment", NULL); + + zend_enum_add_case_cstr(class_entry, "AllReservedCharacters", NULL); + + zend_enum_add_case_cstr(class_entry, "All", NULL); + + return class_entry; +} + +static zend_class_entry *register_class_Uri_Rfc3986_UriHostType(void) +{ + zend_class_entry *class_entry = zend_register_internal_enum("Uri\\Rfc3986\\UriHostType", IS_UNDEF, NULL); + + zend_enum_add_case_cstr(class_entry, "IPv4", NULL); + + zend_enum_add_case_cstr(class_entry, "IPv6", NULL); + + zend_enum_add_case_cstr(class_entry, "IPvFuture", NULL); + + zend_enum_add_case_cstr(class_entry, "RegisteredName", NULL); + return class_entry; } @@ -483,5 +792,69 @@ static zend_class_entry *register_class_Uri_WhatWg_Url(void) zend_add_parameter_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "withpassword", sizeof("withpassword") - 1), 0, ZSTR_KNOWN(ZEND_STR_SENSITIVEPARAMETER), 0); + zend_string *attribute_name_NoDiscard_func_withpathsegments_0 = zend_string_init_interned("NoDiscard", sizeof("NoDiscard") - 1, true); + zend_attribute *attribute_NoDiscard_func_withpathsegments_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "withpathsegments", sizeof("withpathsegments") - 1), attribute_name_NoDiscard_func_withpathsegments_0, 1); + zend_string_release_ex(attribute_name_NoDiscard_func_withpathsegments_0, true); + zend_string *attribute_NoDiscard_func_withpathsegments_0_arg0_str = zend_string_init("as Uri\\WhatWg\\Url::withPathSegments() does not modify the object itself", strlen("as Uri\\WhatWg\\Url::withPathSegments() does not modify the object itself"), 1); + ZVAL_STR(&attribute_NoDiscard_func_withpathsegments_0->args[0].value, attribute_NoDiscard_func_withpathsegments_0_arg0_str); + attribute_NoDiscard_func_withpathsegments_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE); + + zend_string *attribute_name_NoDiscard_func_withqueryparams_0 = zend_string_init_interned("NoDiscard", sizeof("NoDiscard") - 1, true); + zend_attribute *attribute_NoDiscard_func_withqueryparams_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "withqueryparams", sizeof("withqueryparams") - 1), attribute_name_NoDiscard_func_withqueryparams_0, 1); + zend_string_release_ex(attribute_name_NoDiscard_func_withqueryparams_0, true); + zend_string *attribute_NoDiscard_func_withqueryparams_0_arg0_str = zend_string_init("as Uri\\WhatWg\\Url::withQueryParams() does not modify the object itself", strlen("as Uri\\WhatWg\\Url::withQueryParams() does not modify the object itself"), 1); + ZVAL_STR(&attribute_NoDiscard_func_withqueryparams_0->args[0].value, attribute_NoDiscard_func_withqueryparams_0_arg0_str); + attribute_NoDiscard_func_withqueryparams_0->args[0].name = ZSTR_KNOWN(ZEND_STR_MESSAGE); + + return class_entry; +} + +static zend_class_entry *register_class_Uri_WhatWg_UrlQueryParams(void) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "Uri\\WhatWg", "UrlQueryParams", class_Uri_WhatWg_UrlQueryParams_methods); + class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_READONLY_CLASS); + + return class_entry; +} + +static zend_class_entry *register_class_Uri_WhatWg_UrlComponent(void) +{ + zend_class_entry *class_entry = zend_register_internal_enum("Uri\\WhatWg\\UrlComponent", IS_UNDEF, NULL); + + zend_enum_add_case_cstr(class_entry, "Scheme", NULL); + + zend_enum_add_case_cstr(class_entry, "Username", NULL); + + zend_enum_add_case_cstr(class_entry, "Password", NULL); + + zend_enum_add_case_cstr(class_entry, "Host", NULL); + + zend_enum_add_case_cstr(class_entry, "Port", NULL); + + zend_enum_add_case_cstr(class_entry, "Path", NULL); + + zend_enum_add_case_cstr(class_entry, "Query", NULL); + + zend_enum_add_case_cstr(class_entry, "Fragment", NULL); + + return class_entry; +} + +static zend_class_entry *register_class_Uri_WhatWg_UrlHostType(void) +{ + zend_class_entry *class_entry = zend_register_internal_enum("Uri\\WhatWg\\UrlHostType", IS_UNDEF, NULL); + + zend_enum_add_case_cstr(class_entry, "IPv4", NULL); + + zend_enum_add_case_cstr(class_entry, "IPv6", NULL); + + zend_enum_add_case_cstr(class_entry, "Domain", NULL); + + zend_enum_add_case_cstr(class_entry, "Opaque", NULL); + + zend_enum_add_case_cstr(class_entry, "Empty", NULL); + return class_entry; } diff --git a/ext/uri/php_uri_common.c b/ext/uri/php_uri_common.c index 780cc95074159..1c9f4b4c7f856 100644 --- a/ext/uri/php_uri_common.c +++ b/ext/uri/php_uri_common.c @@ -19,6 +19,24 @@ #include "Zend/zend_exceptions.h" #include "php_uri_common.h" +zend_class_entry *php_uri_ce_rfc3986_uri; +zend_class_entry *php_uri_ce_whatwg_url; +zend_class_entry *php_uri_ce_comparison_mode; +zend_class_entry *php_uri_ce_exception; +zend_class_entry *php_uri_ce_error; +zend_class_entry *php_uri_ce_invalid_uri_exception; +zend_class_entry *php_uri_ce_rfc3986_uri_query_params; +zend_class_entry *php_uri_ce_rfc3986_uri_host_type; +zend_class_entry *php_uri_ce_rfc3986_percent_encoding_mode; +zend_class_entry *php_uri_ce_whatwg_invalid_url_exception; +zend_class_entry *php_uri_ce_whatwg_url_validation_error_type; +zend_class_entry *php_uri_ce_whatwg_url_validation_error; +zend_class_entry *php_uri_ce_whatwg_url_query_params; +zend_class_entry *php_uri_ce_whatwg_url_host_type; +zend_class_entry *php_uri_ce_whatwg_url_component; + +zend_array uri_parsers; + static zend_string *get_known_string_by_property_name(php_uri_property_name property_name) { switch (property_name) { diff --git a/ext/uri/php_uri_common.h b/ext/uri/php_uri_common.h index 109236879ae7f..bc36c80c90f10 100644 --- a/ext/uri/php_uri_common.h +++ b/ext/uri/php_uri_common.h @@ -23,9 +23,17 @@ extern zend_class_entry *php_uri_ce_comparison_mode; extern zend_class_entry *php_uri_ce_exception; extern zend_class_entry *php_uri_ce_error; extern zend_class_entry *php_uri_ce_invalid_uri_exception; +extern zend_class_entry *php_uri_ce_rfc3986_uri_query_params; +extern zend_class_entry *php_uri_ce_rfc3986_uri_host_type; +extern zend_class_entry *php_uri_ce_rfc3986_percent_encoding_mode; extern zend_class_entry *php_uri_ce_whatwg_invalid_url_exception; extern zend_class_entry *php_uri_ce_whatwg_url_validation_error_type; extern zend_class_entry *php_uri_ce_whatwg_url_validation_error; +extern zend_class_entry *php_uri_ce_whatwg_url_query_params; +extern zend_class_entry *php_uri_ce_whatwg_url_host_type; +extern zend_class_entry *php_uri_ce_whatwg_url_component; + +extern zend_array uri_parsers; typedef enum php_uri_recomposition_mode { PHP_URI_RECOMPOSITION_MODE_RAW_ASCII, @@ -160,6 +168,7 @@ PHPAPI zend_object *php_uri_object_handler_clone(zend_object *object); #define PHP_URI_PARSER_WHATWG "Uri\\WhatWg\\Url" #define PHP_URI_PARSER_PHP_PARSE_URL "parse_url" #define PHP_URI_SERIALIZE_URI_FIELD_NAME "uri" +#define PHP_URI_SERIALIZE_URI_QUERY_PARAM_FIELD_NAME "query" static inline const php_uri_property_handler *php_uri_parser_property_handler_by_name(const php_uri_parser *parser, php_uri_property_name property_name) { diff --git a/ext/uri/php_uri_parser.c b/ext/uri/php_uri_parser.c new file mode 100644 index 0000000000000..5b16b2b1aa08d --- /dev/null +++ b/ext/uri/php_uri_parser.c @@ -0,0 +1,1101 @@ +/* + +----------------------------------------------------------------------+ + | 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 | + +----------------------------------------------------------------------+ +*/ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "php.h" +#include "Zend/zend_interfaces.h" +#include "Zend/zend_exceptions.h" +#include "Zend/zend_attributes.h" +#include "Zend/zend_enum.h" + +#include "php_uri.h" +#include "uri_parser_whatwg.h" +#include "uri_parser_rfc3986.h" +#include "uriparser/UriBase.h" + +PHP_METHOD(Uri_Rfc3986_Uri, percentEncode) +{ + zend_string *str; + zend_object *mode_object; + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_PATH_STR(str) + Z_PARAM_OBJ_OF_CLASS(mode_object, php_uri_ce_rfc3986_percent_encoding_mode) + ZEND_PARSE_PARAMETERS_END(); + + zval *case_name = zend_enum_fetch_case_name(mode_object); + zend_string *result; + + if (zend_string_equals_literal(Z_STR_P(case_name), "UserInfo")) { + result = php_uri_parser_rfc3986_percent_encode_user_info(str); + } else if (zend_string_equals_literal(Z_STR_P(case_name), "Host")) { + result = php_uri_parser_rfc3986_percent_encode_host(str); + } else if (zend_string_equals_literal(Z_STR_P(case_name), "Path")) { + result = php_uri_parser_rfc3986_percent_encode_path(str); + } else if (zend_string_equals_literal(Z_STR_P(case_name), "PathSegment")) { + result = php_uri_parser_rfc3986_percent_encode_path_segment(str); + } else if (zend_string_equals_literal(Z_STR_P(case_name), "RelativeReferencePath")) { + result = php_uri_parser_rfc3986_percent_encode_relative_reference_path(str); + } else if (zend_string_equals_literal(Z_STR_P(case_name), "RelativeReferenceFirstPathSegment")) { + result = php_uri_parser_rfc3986_percent_encode_relative_reference_first_path_segment(str); + } else if (zend_string_equals_literal(Z_STR_P(case_name), "Query")) { + result = php_uri_parser_rfc3986_percent_encode_query_or_fragment(str); + } else if (zend_string_equals_literal(Z_STR_P(case_name), "FormQuery")) { + result = php_uri_parser_rfc3986_percent_encode_query_or_fragment(str); + } else if (zend_string_equals_literal(Z_STR_P(case_name), "Fragment")) { + result = php_uri_parser_rfc3986_percent_encode_query_or_fragment(str); + } else if (zend_string_equals_literal(Z_STR_P(case_name), "AllReservedCharacters")) { + result = php_uri_parser_rfc3986_percent_encode_reserved_characters(str); + } else if (zend_string_equals_literal(Z_STR_P(case_name), "All")) { + result = php_uri_parser_rfc3986_percent_encode_all(str); + } else { + ZEND_UNREACHABLE(); + } + + RETVAL_NEW_STR(result); +} + +PHP_METHOD(Uri_Rfc3986_Uri, percentDecode) +{ + zend_string *str; + zend_object *mode_object; + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_PATH_STR(str) + Z_PARAM_OBJ_OF_CLASS(mode_object, php_uri_ce_rfc3986_percent_encoding_mode) + ZEND_PARSE_PARAMETERS_END(); + + zval *case_name = zend_enum_fetch_case_name(mode_object); + zend_string *result; + + if (zend_string_equals_literal(Z_STR_P(case_name), "UserInfo")) { + result = php_uri_parser_rfc3986_percent_encode_user_info(str); + } else if (zend_string_equals_literal(Z_STR_P(case_name), "Host")) { + result = php_uri_parser_rfc3986_percent_encode_host(str); + } else if (zend_string_equals_literal(Z_STR_P(case_name), "Path")) { + result = php_uri_parser_rfc3986_percent_encode_path(str); + } else if (zend_string_equals_literal(Z_STR_P(case_name), "PathSegment")) { + result = php_uri_parser_rfc3986_percent_encode_path_segment(str); + } else if (zend_string_equals_literal(Z_STR_P(case_name), "RelativeReferencePath")) { + result = php_uri_parser_rfc3986_percent_encode_relative_reference_path(str); + } else if (zend_string_equals_literal(Z_STR_P(case_name), "RelativeReferenceFirstPathSegment")) { + result = php_uri_parser_rfc3986_percent_encode_relative_reference_first_path_segment(str); + } else if (zend_string_equals_literal(Z_STR_P(case_name), "Query")) { + result = php_uri_parser_rfc3986_percent_encode_query_or_fragment(str); + } else if (zend_string_equals_literal(Z_STR_P(case_name), "FormQuery")) { + result = php_uri_parser_rfc3986_percent_encode_query_or_fragment(str); + } else if (zend_string_equals_literal(Z_STR_P(case_name), "Fragment")) { + result = php_uri_parser_rfc3986_percent_encode_query_or_fragment(str); + } else if (zend_string_equals_literal(Z_STR_P(case_name), "AllReservedCharacters")) { + result = php_uri_parser_rfc3986_percent_decode_reserved_characters(str); + } else if (zend_string_equals_literal(Z_STR_P(case_name), "All")) { + result = php_uri_parser_rfc3986_percent_decode(str); + } else { + ZEND_UNREACHABLE(); + } + + if (result == NULL) { + RETURN_NULL(); + } + + RETVAL_NEW_STR(result); +} + +/** + * Pass the errors parameter by ref to errors_zv for userland, and frees it if + * it is not not needed anymore. + */ +static zend_result pass_errors_by_ref_and_free(zval *errors_zv, zval *errors) +{ + ZEND_ASSERT(Z_TYPE_P(errors) == IS_UNDEF || Z_TYPE_P(errors) == IS_ARRAY); + + /* There was no error during parsing */ + if (Z_ISUNDEF_P(errors)) { + return SUCCESS; + } + + /* The errors parameter is an array, but the pass-by ref argument stored by + * errors_zv was not passed - the URI implementation either doesn't support + * returning additional error information, or the caller is not interested in it */ + if (errors_zv == NULL) { + zval_ptr_dtor(errors); + return SUCCESS; + } + + ZEND_TRY_ASSIGN_REF_TMP(errors_zv, errors); + if (EG(exception)) { + return FAILURE; + } + + return SUCCESS; +} + +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 2) PHPAPI void php_uri_instantiate_uri( + INTERNAL_FUNCTION_PARAMETERS, const zend_string *uri_str, const php_uri_object *base_url_object, + bool should_throw, bool should_update_this_object, zval *errors_zv +) { + php_uri_object *uri_object; + if (should_update_this_object) { + uri_object = Z_URI_OBJECT_P(ZEND_THIS); + if (uri_object->uri != NULL) { + zend_throw_error(NULL, "Cannot modify readonly object of class %s", ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name)); + RETURN_THROWS(); + } + } else { + if (EX(func)->common.fn_flags & ZEND_ACC_STATIC) { + object_init_ex(return_value, Z_CE_P(ZEND_THIS)); + } else { + object_init_ex(return_value, Z_OBJCE_P(ZEND_THIS)); + } + uri_object = Z_URI_OBJECT_P(return_value); + } + + const php_uri_parser *uri_parser = uri_object->parser; + + zval errors; + ZVAL_UNDEF(&errors); + + void *base_url = NULL; + if (base_url_object != NULL) { + ZEND_ASSERT(base_url_object->std.ce == uri_object->std.ce); + ZEND_ASSERT(base_url_object->uri != NULL); + ZEND_ASSERT(base_url_object->parser == uri_parser); + base_url = base_url_object->uri; + } + + void *uri = uri_parser->parse(ZSTR_VAL(uri_str), ZSTR_LEN(uri_str), base_url, errors_zv != NULL ? &errors : NULL, !should_throw); + if (UNEXPECTED(uri == NULL)) { + if (should_throw) { + zval_ptr_dtor(&errors); + RETURN_THROWS(); + } else { + if (pass_errors_by_ref_and_free(errors_zv, &errors) == FAILURE) { + RETURN_THROWS(); + } + zval_ptr_dtor(return_value); + RETURN_NULL(); + } + } + + if (pass_errors_by_ref_and_free(errors_zv, &errors) == FAILURE) { + uri_parser->destroy(uri); + RETURN_THROWS(); + } + + uri_object->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, php_uri_ce_rfc3986_uri) + ZEND_PARSE_PARAMETERS_END(); + + php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, + uri_str, base_url_object ? php_uri_object_from_obj(base_url_object) : NULL, is_constructor, is_constructor, NULL); +} + +PHP_METHOD(Uri_Rfc3986_Uri, __construct) +{ + create_rfc3986_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, true); +} + +PHP_METHOD(Uri_Rfc3986_Uri, parse) +{ + create_rfc3986_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, false); +} + +static bool is_list_of_whatwg_validation_errors(const HashTable *array) +{ + if (!zend_array_is_list(array)) { + return false; + } + + ZEND_HASH_FOREACH_VAL(array, zval *val) { + /* Do not allow references as they may change types after checking. */ + + if (Z_TYPE_P(val) != IS_OBJECT) { + return false; + } + + if (!instanceof_function(Z_OBJCE_P(val), php_uri_ce_whatwg_url_validation_error)) { + return false; + } + } ZEND_HASH_FOREACH_END(); + + return 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(php_uri_ce_whatwg_invalid_url_exception, Z_OBJ_P(ZEND_THIS), ZEND_STRL("errors"), &tmp); + } else { + if (!is_list_of_whatwg_validation_errors(Z_ARR_P(errors))) { + zend_argument_value_error(2, "must be a list of %s", ZSTR_VAL(php_uri_ce_whatwg_url_validation_error->name)); + RETURN_THROWS(); + } + + zend_update_property(php_uri_ce_whatwg_invalid_url_exception, 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, php_uri_ce_whatwg_url_validation_error_type) + Z_PARAM_BOOL(failure) + ZEND_PARSE_PARAMETERS_END(); + + zend_update_property_str(php_uri_ce_whatwg_url_validation_error, Z_OBJ_P(ZEND_THIS), ZEND_STRL("context"), context); + if (EG(exception)) { + RETURN_THROWS(); + } + + zend_update_property_ex(php_uri_ce_whatwg_url_validation_error, 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(php_uri_ce_whatwg_url_validation_error, 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; + zend_object *base_url_object = NULL; + zval *errors = NULL; + + ZEND_PARSE_PARAMETERS_START(1, 3) + Z_PARAM_PATH_STR(uri_str) + Z_PARAM_OPTIONAL + Z_PARAM_OBJ_OF_CLASS_OR_NULL(base_url_object, php_uri_ce_whatwg_url) + Z_PARAM_ZVAL(errors) + ZEND_PARSE_PARAMETERS_END(); + + php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, + uri_str, base_url_object ? php_uri_object_from_obj(base_url_object) : NULL, is_constructor, is_constructor, errors); +} + +PHP_METHOD(Uri_WhatWg_Url, __construct) +{ + create_whatwg_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, true); +} + +PHP_METHOD(Uri_WhatWg_Url, parse) +{ + create_whatwg_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, false); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getScheme) +{ + php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_SCHEME, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getRawScheme) +{ + php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_SCHEME, PHP_URI_COMPONENT_READ_MODE_RAW); +} + +PHP_METHOD(Uri_Rfc3986_Uri, withScheme) +{ + php_uri_property_write_str_or_null_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_SCHEME); +} + +static void rfc3986_userinfo_read(INTERNAL_FUNCTION_PARAMETERS, php_uri_component_read_mode read_mode) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + php_uri_object *uri_object = Z_URI_OBJECT_P(ZEND_THIS); + ZEND_ASSERT(uri_object->uri != NULL); + + if (UNEXPECTED(php_uri_parser_rfc3986_userinfo_read(uri_object->uri, read_mode, return_value) == FAILURE)) { + zend_throw_error(NULL, "The userinfo component cannot be retrieved"); + RETURN_THROWS(); + } +} + +PHP_METHOD(Uri_Rfc3986_Uri, getUserInfo) +{ + rfc3986_userinfo_read(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getRawUserInfo) +{ + rfc3986_userinfo_read(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_COMPONENT_READ_MODE_RAW); +} + +PHP_METHOD(Uri_Rfc3986_Uri, withUserInfo) +{ + zend_string *value; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_PATH_STR_OR_NULL(value) + ZEND_PARSE_PARAMETERS_END(); + + zval zv; + if (value == NULL) { + ZVAL_NULL(&zv); + } else { + ZVAL_STR(&zv, value); + } + + php_uri_object *old_uri_object = php_uri_object_from_obj(Z_OBJ_P(ZEND_THIS)); + ZEND_ASSERT(old_uri_object->uri != NULL); + + zend_object *new_object = old_uri_object->std.handlers->clone_obj(&old_uri_object->std); + if (new_object == NULL) { + RETURN_THROWS(); + } + + /* Assign the object early. The engine will take care of destruction in + * case of an exception being thrown. */ + RETVAL_OBJ(new_object); + + php_uri_object *new_uri_object = php_uri_object_from_obj(new_object); + ZEND_ASSERT(new_uri_object->uri != NULL); + + if (UNEXPECTED(php_uri_parser_rfc3986_userinfo_write(new_uri_object->uri, &zv, NULL) == FAILURE)) { + RETURN_THROWS(); + } +} + +PHP_METHOD(Uri_Rfc3986_Uri, getUsername) +{ + php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_USERNAME, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getRawUsername) +{ + php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_USERNAME, PHP_URI_COMPONENT_READ_MODE_RAW); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getPassword) +{ + php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_PASSWORD, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getRawPassword) +{ + php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_PASSWORD, PHP_URI_COMPONENT_READ_MODE_RAW); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getHost) +{ + php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_HOST, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getRawHost) +{ + php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_HOST, PHP_URI_COMPONENT_READ_MODE_RAW); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getHostType) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + php_uri_object *uri_object = Z_URI_OBJECT_P(ZEND_THIS); + ZEND_ASSERT(uri_object->uri != NULL); + + php_uri_parser_rfc3986_host_type_read(uri_object->uri, PHP_URI_COMPONENT_READ_MODE_RAW, return_value); +} + +PHP_METHOD(Uri_Rfc3986_Uri, withHost) +{ + php_uri_property_write_str_or_null_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_HOST); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getPort) +{ + php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_PORT, PHP_URI_COMPONENT_READ_MODE_RAW); +} + +PHP_METHOD(Uri_Rfc3986_Uri, withPort) +{ + php_uri_property_write_long_or_null_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_PORT); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getPath) +{ + php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_PATH, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getRawPath) +{ + php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_PATH, PHP_URI_COMPONENT_READ_MODE_RAW); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getPathSegments) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + php_uri_object *uri_object = Z_URI_OBJECT_P(ZEND_THIS); + ZEND_ASSERT(uri_object->uri != NULL); + + if (php_uri_parser_rfc3986_path_segments_read(uri_object->uri, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII, return_value) == FAILURE) { + zend_throw_exception_ex(php_uri_ce_error, 0, "The path component cannot be retrieved"); + RETURN_THROWS(); + } +} + +PHP_METHOD(Uri_Rfc3986_Uri, getRawPathSegments) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + php_uri_object *uri_object = Z_URI_OBJECT_P(ZEND_THIS); + ZEND_ASSERT(uri_object->uri != NULL); + + if (php_uri_parser_rfc3986_path_segments_read(uri_object->uri, PHP_URI_COMPONENT_READ_MODE_RAW, return_value) == FAILURE) { + zend_throw_exception_ex(php_uri_ce_error, 0, "The path component cannot be retrieved"); + RETURN_THROWS(); + } +} + +PHP_METHOD(Uri_Rfc3986_Uri, withPath) +{ + php_uri_property_write_str_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_PATH); +} + +PHP_METHOD(Uri_Rfc3986_Uri, withPathSegments) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + php_uri_object *uri_object = Z_URI_OBJECT_P(ZEND_THIS); + ZEND_ASSERT(uri_object->uri != NULL); + + zend_throw_exception(NULL, "Not implemented", 0); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getQuery) +{ + php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_QUERY, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getRawQuery) +{ + php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_QUERY, PHP_URI_COMPONENT_READ_MODE_RAW); +} + +PHP_METHOD(Uri_Rfc3986_Uri, withQuery) +{ + php_uri_property_write_str_or_null_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_QUERY); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getRawQueryParams) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + php_uri_object *uri_object = Z_URI_OBJECT_P(ZEND_THIS); + ZEND_ASSERT(uri_object->uri != NULL); + + if (UNEXPECTED(php_uri_parser_rfc3986_query_params_read(uri_object->uri, PHP_URI_COMPONENT_READ_MODE_RAW, return_value) == FAILURE)) { + RETURN_THROWS(); + } +} + +PHP_METHOD(Uri_Rfc3986_Uri, getQueryParams) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + php_uri_object *uri_object = Z_URI_OBJECT_P(ZEND_THIS); + ZEND_ASSERT(uri_object->uri != NULL); + + if (UNEXPECTED(php_uri_parser_rfc3986_query_params_read(uri_object->uri, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII, return_value) == FAILURE)) { + RETURN_THROWS(); + } +} + +PHP_METHOD(Uri_Rfc3986_Uri, withQueryParams) +{ + zval *zv; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_OBJECT_OF_CLASS_OR_NULL(zv, php_uri_ce_rfc3986_uri_query_params) + ZEND_PARSE_PARAMETERS_END(); + + php_uri_object *old_uri_object = php_uri_object_from_obj(Z_OBJ_P(ZEND_THIS)); + ZEND_ASSERT(old_uri_object->uri != NULL); + + zend_object *new_object = old_uri_object->std.handlers->clone_obj(&old_uri_object->std); + if (new_object == NULL) { + RETURN_THROWS(); + } + + /* Assign the object early. The engine will take care of destruction in + * case of an exception being thrown. */ + RETVAL_OBJ(new_object); + + php_uri_object *new_uri_object = php_uri_object_from_obj(new_object); + ZEND_ASSERT(new_uri_object->uri != NULL); + + if (UNEXPECTED(php_uri_parser_rfc3986_query_params_write(new_uri_object->uri, zv) == FAILURE)) { + RETURN_THROWS(); + } +} + +PHP_METHOD(Uri_Rfc3986_Uri, getFragment) +{ + php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_FRAGMENT, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getRawFragment) +{ + php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_FRAGMENT, PHP_URI_COMPONENT_READ_MODE_RAW); +} + +PHP_METHOD(Uri_Rfc3986_Uri, withFragment) +{ + php_uri_property_write_str_or_null_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_FRAGMENT); +} + +static void throw_cannot_recompose_uri_to_string(zend_object *object) +{ + zend_throw_exception_ex(php_uri_ce_error, 0, "Cannot recompose %s to a string", ZSTR_VAL(object->ce->name)); +} + +static void uri_equals(INTERNAL_FUNCTION_PARAMETERS, php_uri_object *that_object, zend_object *comparison_mode) +{ + php_uri_object *this_object = Z_URI_OBJECT_P(ZEND_THIS); + ZEND_ASSERT(this_object->uri != NULL); + ZEND_ASSERT(that_object->uri != NULL); + + if (this_object->std.ce != that_object->std.ce && + !instanceof_function(this_object->std.ce, that_object->std.ce) && + !instanceof_function(that_object->std.ce, this_object->std.ce) + ) { + RETURN_FALSE; + } + + bool exclude_fragment = true; + if (comparison_mode) { + zval *case_name = zend_enum_fetch_case_name(comparison_mode); + exclude_fragment = zend_string_equals_literal(Z_STR_P(case_name), "ExcludeFragment"); + } + + zend_string *this_str = this_object->parser->to_string( + this_object->uri, PHP_URI_RECOMPOSITION_MODE_NORMALIZED_ASCII, exclude_fragment); + if (this_str == NULL) { + throw_cannot_recompose_uri_to_string(&this_object->std); + RETURN_THROWS(); + } + + zend_string *that_str = that_object->parser->to_string( + that_object->uri, PHP_URI_RECOMPOSITION_MODE_NORMALIZED_ASCII, exclude_fragment); + if (that_str == NULL) { + zend_string_release(this_str); + throw_cannot_recompose_uri_to_string(&that_object->std); + RETURN_THROWS(); + } + + RETVAL_BOOL(zend_string_equals(this_str, that_str)); + + zend_string_release(this_str); + 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, php_uri_ce_rfc3986_uri) + Z_PARAM_OPTIONAL + Z_PARAM_OBJ_OF_CLASS(comparison_mode, php_uri_ce_comparison_mode) + ZEND_PARSE_PARAMETERS_END(); + + uri_equals(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_uri_object_from_obj(that_object), comparison_mode); +} + +PHP_METHOD(Uri_Rfc3986_Uri, toRawString) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + php_uri_object *uri_object = Z_URI_OBJECT_P(ZEND_THIS); + ZEND_ASSERT(uri_object->uri != NULL); + + zend_string *uri_str = uri_object->parser->to_string(uri_object->uri, PHP_URI_RECOMPOSITION_MODE_RAW_ASCII, false); + if (uri_str == NULL) { + throw_cannot_recompose_uri_to_string(&uri_object->std); + RETURN_THROWS(); + } + + RETURN_STR(uri_str); +} + +PHP_METHOD(Uri_Rfc3986_Uri, toString) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + php_uri_object *uri_object = Z_URI_OBJECT_P(ZEND_THIS); + ZEND_ASSERT(uri_object->uri != NULL); + + zend_string *uri_str = uri_object->parser->to_string(uri_object->uri, PHP_URI_RECOMPOSITION_MODE_NORMALIZED_ASCII, false); + if (uri_str == NULL) { + throw_cannot_recompose_uri_to_string(&uri_object->std); + 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(); + + php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, + uri_str, Z_URI_OBJECT_P(ZEND_THIS), true, false, NULL); +} + +PHP_METHOD(Uri_Rfc3986_Uri, __serialize) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + php_uri_object *uri_object = Z_URI_OBJECT_P(ZEND_THIS); + ZEND_ASSERT(uri_object->uri != NULL); + + /* Serialize state: "uri" key in the first array */ + zend_string *uri_str = uri_object->parser->to_string(uri_object->uri, PHP_URI_RECOMPOSITION_MODE_RAW_ASCII, false); + if (uri_str == NULL) { + throw_cannot_recompose_uri_to_string(&uri_object->std); + 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), PHP_URI_SERIALIZE_URI_FIELD_NAME, sizeof(PHP_URI_SERIALIZE_URI_FIELD_NAME) - 1, &tmp); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &arr); + + /* Serialize regular properties: second array */ + ZVAL_ARR(&arr, uri_object->std.handlers->get_properties(&uri_object->std)); + Z_TRY_ADDREF(arr); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &arr); +} + +static void uri_unserialize(INTERNAL_FUNCTION_PARAMETERS) +{ + HashTable *data; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ARRAY_HT(data) + ZEND_PARSE_PARAMETERS_END(); + + php_uri_object *uri_object = php_uri_object_from_obj(Z_OBJ_P(ZEND_THIS)); + if (uri_object->uri != NULL) { + /* Intentionally throw two exceptions for proper chaining. */ + zend_throw_error(NULL, "Cannot modify readonly object of class %s", ZSTR_VAL(uri_object->std.ce->name)); + zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_object->std.ce->name)); + RETURN_THROWS(); + } + + /* Verify the expected number of elements, this implicitly ensures that no additional elements are present. */ + if (zend_hash_num_elements(data) != 2) { + zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_object->std.ce->name)); + RETURN_THROWS(); + } + + /* Unserialize state: "uri" key in the first array */ + zval *arr = zend_hash_index_find(data, 0); + if (arr == NULL || Z_TYPE_P(arr) != IS_ARRAY) { + zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_object->std.ce->name)); + RETURN_THROWS(); + } + + /* Verify the expected number of elements inside the first array, this implicitly ensures that no additional elements are present. */ + if (zend_hash_num_elements(Z_ARRVAL_P(arr)) != 1) { + zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_object->std.ce->name)); + RETURN_THROWS(); + } + + zval *uri_zv = zend_hash_str_find_ind(Z_ARRVAL_P(arr), ZEND_STRL(PHP_URI_SERIALIZE_URI_FIELD_NAME)); + if (uri_zv == NULL || Z_TYPE_P(uri_zv) != IS_STRING) { + zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_object->std.ce->name)); + RETURN_THROWS(); + } + + uri_object->uri = uri_object->parser->parse(Z_STRVAL_P(uri_zv), Z_STRLEN_P(uri_zv), NULL, NULL, true); + if (uri_object->uri == NULL) { + zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_object->std.ce->name)); + RETURN_THROWS(); + } + + /* Unserialize regular properties: second array */ + arr = zend_hash_index_find(data, 1); + if (arr == NULL || Z_TYPE_P(arr) != IS_ARRAY) { + zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_object->std.ce->name)); + RETURN_THROWS(); + } + + /* Verify that there is no regular property in the second array, because the URI classes have no properties and they are final. */ + if (zend_hash_num_elements(Z_ARRVAL_P(arr)) > 0) { + zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_object->std.ce->name)); + RETURN_THROWS(); + } +} + +PHP_METHOD(Uri_Rfc3986_Uri, __unserialize) +{ + uri_unserialize(INTERNAL_FUNCTION_PARAM_PASSTHRU); +} + +static HashTable *uri_get_debug_properties(php_uri_object *object) +{ + const HashTable *std_properties = zend_std_get_properties(&object->std); + HashTable *result = zend_array_dup(std_properties); + + const php_uri_parser * const parser = object->parser; + void * const uri = object->uri; + + if (UNEXPECTED(uri == NULL)) { + return result; + } + + zval tmp; + if (parser->property_handler.scheme.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) { + zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_SCHEME), &tmp); + } + + if (parser->property_handler.username.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) { + zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_USERNAME), &tmp); + } + + if (parser->property_handler.password.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) { + zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_PASSWORD), &tmp); + } + + if (parser->property_handler.host.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) { + zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_HOST), &tmp); + } + + if (parser->property_handler.port.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) { + zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_PORT), &tmp); + } + + if (parser->property_handler.path.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) { + zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_PATH), &tmp); + } + + if (parser->property_handler.query.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) { + zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_QUERY), &tmp); + } + + if (parser->property_handler.fragment.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) { + zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_FRAGMENT), &tmp); + } + + return result; +} + +PHP_METHOD(Uri_Rfc3986_Uri, __debugInfo) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + php_uri_object *uri_object = Z_URI_OBJECT_P(ZEND_THIS); + + RETURN_ARR(uri_get_debug_properties(uri_object)); +} + +PHP_METHOD(Uri_WhatWg_Url, percentEncodeComponent) +{ + zend_string *str; + zend_object *component_object; + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_PATH_STR(str) + Z_PARAM_OBJ_OF_CLASS(component_object, php_uri_ce_whatwg_url_host_type) + ZEND_PARSE_PARAMETERS_END(); + + zend_throw_exception(NULL, "Not implemented", 0); +} + +PHP_METHOD(Uri_WhatWg_Url, percentDecodeComponent) +{ + zend_string *str; + zend_object *component_object; + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_PATH_STR(str) + Z_PARAM_OBJ_OF_CLASS(component_object, php_uri_ce_whatwg_url_host_type) + ZEND_PARSE_PARAMETERS_END(); + + zend_throw_exception(NULL, "Not implemented", 0); +} + +PHP_METHOD(Uri_WhatWg_Url, getScheme) +{ + php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_SCHEME, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_WhatWg_Url, withScheme) +{ + php_uri_property_write_str_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_SCHEME); +} + +PHP_METHOD(Uri_WhatWg_Url, isSpecial) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + php_uri_object *uri_object = Z_URI_OBJECT_P(ZEND_THIS); + ZEND_ASSERT(uri_object->uri != NULL); + + RETVAL_BOOL(php_uri_parser_whatwg_is_special(uri_object->uri)); +} + +PHP_METHOD(Uri_WhatWg_Url, withUsername) +{ + php_uri_property_write_str_or_null_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_USERNAME); +} + +PHP_METHOD(Uri_WhatWg_Url, withPassword) +{ + php_uri_property_write_str_or_null_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_PASSWORD); +} + +PHP_METHOD(Uri_WhatWg_Url, getAsciiHost) +{ + php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_HOST, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_WhatWg_Url, getUnicodeHost) +{ + php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_HOST, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_UNICODE); +} + +PHP_METHOD(Uri_WhatWg_Url, getHostType) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + php_uri_object *uri_object = Z_URI_OBJECT_P(ZEND_THIS); + ZEND_ASSERT(uri_object->uri != NULL); + + php_uri_parser_whatwg_host_type_read(uri_object->uri, PHP_URI_COMPONENT_READ_MODE_RAW, return_value); +} + +PHP_METHOD(Uri_WhatWg_Url, getPathSegments) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + php_uri_object *uri_object = Z_URI_OBJECT_P(ZEND_THIS); + ZEND_ASSERT(uri_object->uri != NULL); + + if (php_uri_parser_whatwg_path_segments_read(uri_object->uri, PHP_URI_COMPONENT_READ_MODE_RAW, return_value) == FAILURE) { + zend_throw_exception_ex(php_uri_ce_error, 0, "The path component cannot be retrieved"); + RETURN_THROWS(); + } +} + +PHP_METHOD(Uri_WhatWg_Url, withPathSegments) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + php_uri_object *uri_object = Z_URI_OBJECT_P(ZEND_THIS); + ZEND_ASSERT(uri_object->uri != NULL); + + zend_throw_exception(NULL, "Not implemented", 0); +} + +PHP_METHOD(Uri_WhatWg_Url, getQueryParams) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + php_uri_object *uri_object = Z_URI_OBJECT_P(ZEND_THIS); + ZEND_ASSERT(uri_object->uri != NULL); + + if (UNEXPECTED(php_uri_parser_whatwg_query_params_read(uri_object->uri, PHP_URI_COMPONENT_READ_MODE_RAW, return_value) == FAILURE)) { + RETURN_THROWS(); + } +} + +PHP_METHOD(Uri_WhatWg_Url, withQueryParams) +{ + zval *zv; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_OBJECT_OF_CLASS_OR_NULL(zv, php_uri_ce_whatwg_url_query_params) + ZEND_PARSE_PARAMETERS_END(); + + php_uri_object *old_uri_object = php_uri_object_from_obj(Z_OBJ_P(ZEND_THIS)); + ZEND_ASSERT(old_uri_object->uri != NULL); + + zend_object *new_object = old_uri_object->std.handlers->clone_obj(&old_uri_object->std); + if (new_object == NULL) { + RETURN_THROWS(); + } + + /* Assign the object early. The engine will take care of destruction in + * case of an exception being thrown. */ + RETVAL_OBJ(new_object); + + php_uri_object *new_uri_object = php_uri_object_from_obj(new_object); + ZEND_ASSERT(new_uri_object->uri != NULL); + + zval errors; + ZVAL_UNDEF(&errors); + + if (UNEXPECTED(php_uri_parser_whatwg_query_params_write(new_uri_object->uri, zv, &errors) == FAILURE)) { + zval_ptr_dtor(&errors); + RETURN_THROWS(); + } + + ZEND_ASSERT(Z_ISUNDEF(errors)); +} + +PHP_METHOD(Uri_WhatWg_Url, getFragment) +{ + php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_FRAGMENT, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_UNICODE); +} + +PHP_METHOD(Uri_WhatWg_Url, equals) +{ + zend_object *that_object; + zend_object *comparison_mode = NULL; + + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_OBJ_OF_CLASS(that_object, php_uri_ce_whatwg_url) + Z_PARAM_OPTIONAL + Z_PARAM_OBJ_OF_CLASS(comparison_mode, php_uri_ce_comparison_mode) + ZEND_PARSE_PARAMETERS_END(); + + uri_equals(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_uri_object_from_obj(that_object), comparison_mode); +} + +PHP_METHOD(Uri_WhatWg_Url, toUnicodeString) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zend_object *this_object = Z_OBJ_P(ZEND_THIS); + php_uri_object *uri_object = php_uri_object_from_obj(this_object); + ZEND_ASSERT(uri_object->uri != NULL); + + RETURN_STR(uri_object->parser->to_string(uri_object->uri, PHP_URI_RECOMPOSITION_MODE_RAW_UNICODE, false)); +} + +PHP_METHOD(Uri_WhatWg_Url, toAsciiString) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zend_object *this_object = Z_OBJ_P(ZEND_THIS); + php_uri_object *uri_object = php_uri_object_from_obj(this_object); + ZEND_ASSERT(uri_object->uri != NULL); + + RETURN_STR(uri_object->parser->to_string(uri_object->uri, PHP_URI_RECOMPOSITION_MODE_RAW_ASCII, false)); +} + +PHP_METHOD(Uri_WhatWg_Url, resolve) +{ + zend_string *uri_str; + zval *errors = NULL; + + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_PATH_STR(uri_str) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(errors) + ZEND_PARSE_PARAMETERS_END(); + + php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, + uri_str, Z_URI_OBJECT_P(ZEND_THIS), true, false, errors); +} + +PHP_METHOD(Uri_WhatWg_Url, __serialize) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + php_uri_object *this_object = Z_URI_OBJECT_P(ZEND_THIS); + ZEND_ASSERT(this_object->uri != NULL); + + /* Serialize state: "uri" key in the first array */ + zend_string *uri_str = this_object->parser->to_string(this_object->uri, PHP_URI_RECOMPOSITION_MODE_RAW_ASCII, false); + if (uri_str == NULL) { + throw_cannot_recompose_uri_to_string(&this_object->std); + 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), ZEND_STRL(PHP_URI_SERIALIZE_URI_FIELD_NAME), &tmp); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &arr); + + /* Serialize regular properties: second array */ + ZVAL_ARR(&arr, this_object->std.handlers->get_properties(&this_object->std)); + Z_ADDREF(arr); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &arr); +} + +PHP_METHOD(Uri_WhatWg_Url, __unserialize) +{ + uri_unserialize(INTERNAL_FUNCTION_PARAM_PASSTHRU); +} + +PHP_METHOD(Uri_WhatWg_Url, __debugInfo) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + php_uri_object *uri_object = Z_URI_OBJECT_P(ZEND_THIS); + + RETURN_ARR(uri_get_debug_properties(uri_object)); +} diff --git a/ext/uri/php_uri_parser.h b/ext/uri/php_uri_parser.h new file mode 100644 index 0000000000000..13211a8bb9d05 --- /dev/null +++ b/ext/uri/php_uri_parser.h @@ -0,0 +1,85 @@ +/* + +----------------------------------------------------------------------+ + | 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_URI_PARSER_H +#define PHP_URI_PARSER_H + +extern PHP_METHOD(Uri_Rfc3986_Uri, __construct); +extern PHP_METHOD(Uri_Rfc3986_Uri, parse); +extern PHP_METHOD(Uri_Rfc3986_Uri, withPassword); +extern PHP_METHOD(Uri_Rfc3986_Uri, getRawScheme); +extern PHP_METHOD(Uri_Rfc3986_Uri, getScheme); +extern PHP_METHOD(Uri_Rfc3986_Uri, getRawUserInfo); +extern PHP_METHOD(Uri_Rfc3986_Uri, getUserInfo); +extern PHP_METHOD(Uri_Rfc3986_Uri, withUserInfo); +extern PHP_METHOD(Uri_Rfc3986_Uri, getRawUsername); +extern PHP_METHOD(Uri_Rfc3986_Uri, getUsername); +extern PHP_METHOD(Uri_Rfc3986_Uri, withUsername); +extern PHP_METHOD(Uri_Rfc3986_Uri, getRawPassword); +extern PHP_METHOD(Uri_Rfc3986_Uri, getPassword); +extern PHP_METHOD(Uri_Rfc3986_Uri, getRawHost); +extern PHP_METHOD(Uri_Rfc3986_Uri, getHost); +extern PHP_METHOD(Uri_Rfc3986_Uri, getHostType); +extern PHP_METHOD(Uri_Rfc3986_Uri, withHost); +extern PHP_METHOD(Uri_Rfc3986_Uri, getPort); +extern PHP_METHOD(Uri_Rfc3986_Uri, withPort); +extern PHP_METHOD(Uri_Rfc3986_Uri, getRawPath); +extern PHP_METHOD(Uri_Rfc3986_Uri, getPath); +extern PHP_METHOD(Uri_Rfc3986_Uri, getRawPathSegments); +extern PHP_METHOD(Uri_Rfc3986_Uri, getPathSegments); +extern PHP_METHOD(Uri_Rfc3986_Uri, withPath); +extern PHP_METHOD(Uri_Rfc3986_Uri, getRawQuery); +extern PHP_METHOD(Uri_Rfc3986_Uri, getQuery); +extern PHP_METHOD(Uri_Rfc3986_Uri, withQuery); +extern PHP_METHOD(Uri_Rfc3986_Uri, getRawQueryParams); +extern PHP_METHOD(Uri_Rfc3986_Uri, getQueryParams); +extern PHP_METHOD(Uri_Rfc3986_Uri, withQueryParams); +extern PHP_METHOD(Uri_Rfc3986_Uri, getRawFragment); +extern PHP_METHOD(Uri_Rfc3986_Uri, getFragment); +extern PHP_METHOD(Uri_Rfc3986_Uri, withFragment); +extern PHP_METHOD(Uri_Rfc3986_Uri, equals); +extern PHP_METHOD(Uri_Rfc3986_Uri, toRawString); +extern PHP_METHOD(Uri_Rfc3986_Uri, toString); +extern PHP_METHOD(Uri_Rfc3986_Uri, resolve); +extern PHP_METHOD(Uri_Rfc3986_Uri, __serialize); +extern PHP_METHOD(Uri_Rfc3986_Uri, __unserialize); +extern PHP_METHOD(Uri_Rfc3986_Uri, __debugInfo); + +extern PHP_METHOD(Uri_WhatWg_InvalidUrlException, withPassword); +extern PHP_METHOD(Uri_WhatWg_UrlValidationError, withPassword); + +extern PHP_METHOD(Uri_WhatWg_Url, __construct); +extern PHP_METHOD(Uri_WhatWg_Url, parse); +extern PHP_METHOD(Uri_WhatWg_Url, getScheme); +extern PHP_METHOD(Uri_WhatWg_Url, withScheme); +extern PHP_METHOD(Uri_WhatWg_Url, withUsername); +extern PHP_METHOD(Uri_WhatWg_Url, withPassword); +extern PHP_METHOD(Uri_WhatWg_Url, getAsciiHost); +extern PHP_METHOD(Uri_WhatWg_Url, getUnicodeHost); +extern PHP_METHOD(Uri_WhatWg_Url, getHostType); +extern PHP_METHOD(Uri_WhatWg_Url, getPathSegments); +extern PHP_METHOD(Uri_WhatWg_Url, getQueryParams); +extern PHP_METHOD(Uri_WhatWg_Url, withQueryParams); +extern PHP_METHOD(Uri_WhatWg_Url, getFragment); +extern PHP_METHOD(Uri_WhatWg_Url, equals); +extern PHP_METHOD(Uri_WhatWg_Url, toAsciiString); +extern PHP_METHOD(Uri_WhatWg_Url, toUnicodeString); +extern PHP_METHOD(Uri_WhatWg_Url, resolve); +extern PHP_METHOD(Uri_WhatWg_Url, __serialize); +extern PHP_METHOD(Uri_WhatWg_Url, __unserialize); +extern PHP_METHOD(Uri_WhatWg_Url, __debugInfo); + +#endif diff --git a/ext/uri/php_uri_query.c b/ext/uri/php_uri_query.c new file mode 100644 index 0000000000000..56ab82066009e --- /dev/null +++ b/ext/uri/php_uri_query.c @@ -0,0 +1,690 @@ +/* + +----------------------------------------------------------------------+ + | 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 "zend_enum.h" +#include "zend_smart_str.h" +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "php.h" +#include "Zend/zend_exceptions.h" + +#include "php_uri_common.h" +#include "uri_parser_whatwg.h" +#include "uri_parser_rfc3986.h" + +static void throw_cannot_recompose_uri_to_string(zend_object *object) +{ + zend_throw_exception_ex(php_uri_ce_error, 0, "Cannot recompose %s to a string", ZSTR_VAL(object->ce->name)); +} + +PHP_METHOD(Uri_Rfc3986_UriQueryParams, parse) +{ + zend_string *query_str; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_PATH_STR(query_str) + ZEND_PARSE_PARAMETERS_END(); + + object_init_ex(return_value, Z_CE_P(ZEND_THIS)); + php_uri_parser_rfc3986_uri_query_params_object *uri_query_params_object = Z_URI_QUERY_PARAMS_OBJECT_P(return_value); + + if (php_uri_rfc3986_uri_query_params_from_str(ZSTR_VAL(query_str), ZSTR_LEN(query_str), &uri_query_params_object->query_list, false, true) == FAILURE) { + php_uri_rfc3986_uri_query_params_free(Z_URI_QUERY_PARAMS_OBJECT_P(return_value)); + RETURN_NULL(); + } + + uri_query_params_object->is_initialized = true; +} + +PHP_METHOD(Uri_Rfc3986_UriQueryParams, fromArray) +{ + HashTable *query_params_arr; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ARRAY_HT(query_params_arr) + ZEND_PARSE_PARAMETERS_END(); + + zend_throw_exception(NULL, "Not implemented", 0); +} + +ZEND_ATTRIBUTE_NONNULL_ARGS(2) static const zend_string *php_uri_build_name(const zend_string *name_array_prefix, const zend_string *name) +{ + if (EXPECTED(name_array_prefix == NULL)) { + return name; + } + + smart_str result = {0}; + smart_str_append(&result, name_array_prefix); + smart_str_appendl(&result, "%5B", strlen("%5B")); + smart_str_append(&result, name); + smart_str_appendl(&result, "%5D", strlen("%5D")); + + return smart_str_extract(&result); +} + +static zend_result uri_query_params_append(php_uri_parser_rfc3986_uri_query_params_object *query_params_object, + const zend_string *name, const zval *value, const zend_string *name_array_prefix) +{ + zend_result result = FAILURE; + const zend_string *tmp; + const zend_string *final_name = php_uri_build_name(name_array_prefix, name); + + switch (Z_TYPE_P(value)) { + case IS_STRING: + result = php_uri_rfc3986_uri_query_params_append(&query_params_object->query_list, + ZSTR_VAL(final_name), ZSTR_LEN(final_name), Z_STRVAL_P(value), Z_STRLEN_P(value) + ); + break; + case IS_FALSE: + ZEND_FALLTHROUGH; + case IS_TRUE: { + zend_string *bool_tmp = zend_string_init(Z_TYPE_P(value) == IS_FALSE ? "0" : "1", 1, false); + result = php_uri_rfc3986_uri_query_params_append(&query_params_object->query_list, + ZSTR_VAL(final_name), ZSTR_LEN(final_name), ZSTR_VAL(bool_tmp), ZSTR_LEN(bool_tmp) + ); + zend_string_release_ex(bool_tmp, false); + break; + } + case IS_LONG: { + zend_string *long_tmp = zend_long_to_str(Z_LVAL_P(value)); + result = php_uri_rfc3986_uri_query_params_append(&query_params_object->query_list, + ZSTR_VAL(final_name), ZSTR_LEN(final_name), ZSTR_VAL(long_tmp), ZSTR_LEN(long_tmp) + ); + zend_string_release_ex(long_tmp, false); + break; + } + case IS_NULL: + tmp = zend_empty_string; + + result = php_uri_rfc3986_uri_query_params_append(&query_params_object->query_list, + ZSTR_VAL(final_name), ZSTR_LEN(final_name), ZSTR_VAL(tmp), ZSTR_LEN(tmp) + ); + break; + case IS_ARRAY: { + zend_string *key; + zval *data; + zend_ulong index; + + if (zend_array_count(Z_ARR_P(value)) == 0) { + // TODO what to do here? + result = php_uri_rfc3986_uri_query_params_append(&query_params_object->query_list, + ZSTR_VAL(final_name), ZSTR_LEN(final_name), "", 0 + ); + break; + } + + ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARR_P(value), index, key, data) { + if (key == NULL) { + key = zend_ulong_to_str(index); + } + + result = uri_query_params_append(query_params_object, key, data, name_array_prefix); + if (result == FAILURE) { + return FAILURE; + } + } ZEND_HASH_FOREACH_END(); + break; + } + case IS_OBJECT: + if (Z_OBJCE_P(value)->ce_flags & ZEND_ACC_ENUM && Z_OBJCE_P(value)->enum_backing_type != IS_UNDEF) { + result = uri_query_params_append(query_params_object, final_name, zend_enum_fetch_case_value(Z_OBJ_P(value)), NULL); + } + break; + } + + return result; +} + +PHP_METHOD(Uri_Rfc3986_UriQueryParams, append) +{ + zend_string *name; + zval *value; + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_PATH_STR(name) + Z_PARAM_ZVAL(value) + ZEND_PARSE_PARAMETERS_END(); + + php_uri_parser_rfc3986_uri_query_params_object *uri_query_params_object = Z_URI_QUERY_PARAMS_OBJECT_P(ZEND_THIS); + + if (uri_query_params_append(uri_query_params_object, name, value, NULL) == FAILURE) { + throw_cannot_recompose_uri_to_string(Z_OBJ_P(ZEND_THIS)); + RETURN_THROWS(); + } +} + +PHP_METHOD(Uri_Rfc3986_UriQueryParams, delete) +{ + zend_string *name; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_PATH_STR(name) + ZEND_PARSE_PARAMETERS_END(); + + zend_throw_exception(NULL, "Not implemented", 0); +} + +PHP_METHOD(Uri_Rfc3986_UriQueryParams, has) +{ + zend_string *name; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_PATH_STR(name) + ZEND_PARSE_PARAMETERS_END(); + + zend_throw_exception(NULL, "Not implemented", 0); +} + +PHP_METHOD(Uri_Rfc3986_UriQueryParams, getFirst) +{ + zend_string *name; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_PATH_STR(name) + ZEND_PARSE_PARAMETERS_END(); + + zend_throw_exception(NULL, "Not implemented", 0); +} + +PHP_METHOD(Uri_Rfc3986_UriQueryParams, getLast) +{ + zend_string *name; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_PATH_STR(name) + ZEND_PARSE_PARAMETERS_END(); + + zend_throw_exception(NULL, "Not implemented", 0); +} + +PHP_METHOD(Uri_Rfc3986_UriQueryParams, getAll) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zend_throw_exception(NULL, "Not implemented", 0); +} + +PHP_METHOD(Uri_Rfc3986_UriQueryParams, set) +{ + zend_string *name; + zval *value; + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_PATH_STR(name) + Z_PARAM_ZVAL(value) + ZEND_PARSE_PARAMETERS_END(); + + zend_throw_exception(NULL, "Not implemented", 0); +} + +PHP_METHOD(Uri_Rfc3986_UriQueryParams, sort) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zend_throw_exception(NULL, "Not implemented", 0); +} + +PHP_METHOD(Uri_Rfc3986_UriQueryParams, toString) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + const php_uri_parser_rfc3986_uri_query_params_object *uri_query_params_object = Z_URI_QUERY_PARAMS_OBJECT_P(ZEND_THIS); + + zend_string *result = php_uri_rfc3986_uri_query_params_to_string(uri_query_params_object->query_list, false); + if (result == NULL) { + throw_cannot_recompose_uri_to_string(Z_OBJ_P(ZEND_THIS)); + RETURN_THROWS(); + } + + ZVAL_STR(return_value, result); +} + +PHP_METHOD(Uri_Rfc3986_UriQueryParams, __serialize) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + php_uri_parser_rfc3986_uri_query_params_object *uri_query_params_object = Z_URI_QUERY_PARAMS_OBJECT_P(ZEND_THIS); + + /* Serialize state: "query" key in the first array */ + zend_string *uri_query_param_str = php_uri_rfc3986_uri_query_params_to_string(uri_query_params_object->query_list, false); + if (uri_query_param_str == NULL) { + throw_cannot_recompose_uri_to_string(Z_OBJ_P(ZEND_THIS)); + RETURN_THROWS(); + } + zval tmp; + ZVAL_STR(&tmp, uri_query_param_str); + + array_init(return_value); + + zval arr; + array_init(&arr); + zend_hash_str_add_new(Z_ARRVAL(arr), PHP_URI_SERIALIZE_URI_QUERY_PARAM_FIELD_NAME, sizeof(PHP_URI_SERIALIZE_URI_QUERY_PARAM_FIELD_NAME) - 1, &tmp); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &arr); + + /* Serialize regular properties: second array */ + ZVAL_ARR(&arr, uri_query_params_object->std.handlers->get_properties(&uri_query_params_object->std)); + Z_TRY_ADDREF(arr); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &arr); +} + +static void uri_query_params_unserialize(INTERNAL_FUNCTION_PARAMETERS) +{ + HashTable *data; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ARRAY_HT(data) + ZEND_PARSE_PARAMETERS_END(); + + php_uri_parser_rfc3986_uri_query_params_object *uri_query_params_object = Z_URI_QUERY_PARAMS_OBJECT_P(ZEND_THIS); + if (uri_query_params_object->query_list != NULL) { + /* Intentionally throw two exceptions for proper chaining. */ + zend_throw_error(NULL, "Cannot modify readonly object of class %s", ZSTR_VAL(uri_query_params_object->std.ce->name)); + zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_query_params_object->std.ce->name)); + RETURN_THROWS(); + } + + /* Verify the expected number of elements, this implicitly ensures that no additional elements are present. */ + if (zend_hash_num_elements(data) != 2) { + zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_query_params_object->std.ce->name)); + RETURN_THROWS(); + } + + /* Unserialize state: "query" key in the first array */ + zval *arr = zend_hash_index_find(data, 0); + if (arr == NULL || Z_TYPE_P(arr) != IS_ARRAY) { + zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_query_params_object->std.ce->name)); + RETURN_THROWS(); + } + + /* Verify the expected number of elements inside the first array, this implicitly ensures that no additional elements are present. */ + if (zend_hash_num_elements(Z_ARRVAL_P(arr)) != 1) { + zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_query_params_object->std.ce->name)); + RETURN_THROWS(); + } + + const zval *uri_query_param_zv = zend_hash_str_find_ind(Z_ARRVAL_P(arr), ZEND_STRL(PHP_URI_SERIALIZE_URI_QUERY_PARAM_FIELD_NAME)); + if (uri_query_param_zv == NULL || Z_TYPE_P(uri_query_param_zv) != IS_STRING) { + zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_query_params_object->std.ce->name)); + RETURN_THROWS(); + } + + const zend_result result = php_uri_rfc3986_uri_query_params_from_str( + Z_STRVAL_P(uri_query_param_zv), + Z_STRLEN_P(uri_query_param_zv), + &uri_query_params_object->query_list, + false, + false + ); + + if (result == FAILURE) { + RETURN_THROWS(); + } + + uri_query_params_object->is_initialized = true; + + /* Unserialize regular properties: second array */ + arr = zend_hash_index_find(data, 1); + if (arr == NULL || Z_TYPE_P(arr) != IS_ARRAY) { + zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_query_params_object->std.ce->name)); + RETURN_THROWS(); + } + + /* Verify that there is no regular property in the second array, because the query param classes have no properties and they are final. */ + if (zend_hash_num_elements(Z_ARRVAL_P(arr)) > 0) { + zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_query_params_object->std.ce->name)); + RETURN_THROWS(); + } +} + +PHP_METHOD(Uri_Rfc3986_UriQueryParams, __unserialize) +{ + uri_query_params_unserialize(INTERNAL_FUNCTION_PARAM_PASSTHRU); +} + +PHP_METHOD(Uri_Rfc3986_UriQueryParams, __debugInfo) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + php_uri_parser_rfc3986_uri_query_params_object *uri_query_params_object = Z_URI_QUERY_PARAMS_OBJECT_P(ZEND_THIS); + + RETURN_ARR(php_uri_rfc3986_uri_query_params_get_debug_properties(uri_query_params_object)); +} + +PHP_METHOD(Uri_WhatWg_UrlQueryParams, parse) +{ + zend_string *query_str; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_PATH_STR(query_str) + ZEND_PARSE_PARAMETERS_END(); + + object_init_ex(return_value, Z_CE_P(ZEND_THIS)); + php_uri_parser_whatwg_url_query_params_object *url_query_params_object = Z_URL_QUERY_PARAMS_OBJECT_P(return_value); + + url_query_params_object->query_params = php_uri_whatwg_url_query_params_from_str( + ZSTR_VAL(query_str), + ZSTR_LEN(query_str), + true + ); + + if (url_query_params_object->query_params == NULL) { + RETURN_NULL(); + } + + url_query_params_object->is_initialized = true; +} + +PHP_METHOD(Uri_WhatWg_UrlQueryParams, fromArray) +{ + HashTable *query_params_arr; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ARRAY_HT(query_params_arr) + ZEND_PARSE_PARAMETERS_END(); + + zend_throw_exception(NULL, "Not implemented", 0); +} + +static zend_result php_uri_whatwg_query_params_append(const php_uri_parser_whatwg_url_query_params_object *query_params_object, + const zend_string *name, const zval *value, const zend_string *name_array_prefix) +{ + zend_result result = FAILURE; + const zend_string *tmp; + const zend_string *final_name = php_uri_build_name(name_array_prefix, name); + + switch (Z_TYPE_P(value)) { + case IS_STRING: + result = php_uri_whatwg_url_query_params_append(query_params_object->query_params, + ZSTR_VAL(final_name), ZSTR_LEN(final_name), Z_STRVAL_P(value), Z_STRLEN_P(value) + ); + break; + case IS_FALSE: + ZEND_FALLTHROUGH; + case IS_TRUE: { + zend_string *bool_tmp = zend_string_init(Z_TYPE_P(value) == IS_FALSE ? "0" : "1", 1, false); + result = php_uri_whatwg_url_query_params_append(query_params_object->query_params, + ZSTR_VAL(final_name), ZSTR_LEN(final_name), ZSTR_VAL(bool_tmp), ZSTR_LEN(bool_tmp) + ); + zend_string_release_ex(bool_tmp, false); + break; + } + case IS_LONG: { + zend_string *long_tmp = zend_long_to_str(Z_LVAL_P(value)); + result = php_uri_whatwg_url_query_params_append(query_params_object->query_params, + ZSTR_VAL(final_name), ZSTR_LEN(final_name), ZSTR_VAL(long_tmp), ZSTR_LEN(long_tmp) + ); + zend_string_release_ex(long_tmp, false); + break; + } + case IS_NULL: + tmp = zend_empty_string; + + result = php_uri_whatwg_url_query_params_append(query_params_object->query_params, + ZSTR_VAL(final_name), ZSTR_LEN(final_name), ZSTR_VAL(tmp), ZSTR_LEN(tmp) + ); + break; + case IS_ARRAY: { + zend_string *key; + zval *data; + zend_ulong index; + + if (zend_array_count(Z_ARR_P(value)) == 0) { + // TODO what to do here? + result = php_uri_whatwg_url_query_params_append(query_params_object->query_params, + ZSTR_VAL(final_name), ZSTR_LEN(final_name), "", 0 + ); + break; + } + + ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARR_P(value), index, key, data) { + if (key == NULL) { + key = zend_ulong_to_str(index); + } + + result = php_uri_whatwg_query_params_append(query_params_object, key, data, name_array_prefix); + if (result == FAILURE) { + return FAILURE; + } + } ZEND_HASH_FOREACH_END(); + break; + } + case IS_OBJECT: + if (Z_OBJCE_P(value)->ce_flags & ZEND_ACC_ENUM && Z_OBJCE_P(value)->enum_backing_type != IS_UNDEF) { + result = php_uri_whatwg_query_params_append(query_params_object, final_name, zend_enum_fetch_case_value(Z_OBJ_P(value)), NULL); + } + break; + } + + return result; +} + +PHP_METHOD(Uri_WhatWg_UrlQueryParams, append) +{ + zend_string *name; + zval *value; + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_PATH_STR(name) + Z_PARAM_ZVAL(value) + ZEND_PARSE_PARAMETERS_END(); + + const php_uri_parser_whatwg_url_query_params_object *uri_query_params_object = Z_URL_QUERY_PARAMS_OBJECT_P(ZEND_THIS); + + if (php_uri_whatwg_query_params_append(uri_query_params_object, name, value, NULL) == FAILURE) { + throw_cannot_recompose_uri_to_string(Z_OBJ_P(ZEND_THIS)); + RETURN_THROWS(); + } +} + +PHP_METHOD(Uri_WhatWg_UrlQueryParams, delete) +{ + zend_string *name; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_PATH_STR(name) + ZEND_PARSE_PARAMETERS_END(); + + const php_uri_parser_whatwg_url_query_params_object *uri_query_params_object = Z_URL_QUERY_PARAMS_OBJECT_P(ZEND_THIS); + + php_uri_whatwg_url_query_params_delete(uri_query_params_object->query_params, ZSTR_VAL(name), ZSTR_LEN(name), NULL, 0); +} + +PHP_METHOD(Uri_WhatWg_UrlQueryParams, deleteWithValue) +{ + zend_string *name, *value; + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_PATH_STR(name) + Z_PARAM_PATH_STR(value) + ZEND_PARSE_PARAMETERS_END(); + + const php_uri_parser_whatwg_url_query_params_object *uri_query_params_object = Z_URL_QUERY_PARAMS_OBJECT_P(ZEND_THIS); + + php_uri_whatwg_url_query_params_delete(uri_query_params_object->query_params, + ZSTR_VAL(name), ZSTR_LEN(name), ZSTR_VAL(value), ZSTR_LEN(value) + ); +} + +PHP_METHOD(Uri_WhatWg_UrlQueryParams, has) +{ + zend_string *name; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_PATH_STR(name) + ZEND_PARSE_PARAMETERS_END(); + + const php_uri_parser_whatwg_url_query_params_object *uri_query_params_object = Z_URL_QUERY_PARAMS_OBJECT_P(ZEND_THIS); + + RETURN_BOOL(php_uri_whatwg_url_query_params_exists(uri_query_params_object->query_params, + ZSTR_VAL(name), ZSTR_LEN(name), NULL, 0 + )); +} + +PHP_METHOD(Uri_WhatWg_UrlQueryParams, hasWithValue) +{ + zend_string *name, *value; + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_PATH_STR(name) + Z_PARAM_PATH_STR(value) + ZEND_PARSE_PARAMETERS_END(); + + const php_uri_parser_whatwg_url_query_params_object *uri_query_params_object = Z_URL_QUERY_PARAMS_OBJECT_P(ZEND_THIS); + + RETURN_BOOL(php_uri_whatwg_url_query_params_exists(uri_query_params_object->query_params, + ZSTR_VAL(name), ZSTR_LEN(name), ZSTR_VAL(value), ZSTR_LEN(value) + )); +} + +PHP_METHOD(Uri_WhatWg_UrlQueryParams, getFirst) +{ + zend_string *name; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_PATH_STR(name) + ZEND_PARSE_PARAMETERS_END(); + + zend_throw_exception(NULL, "Not implemented", 0); +} + +PHP_METHOD(Uri_WhatWg_UrlQueryParams, getLast) +{ + zend_string *name; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_PATH_STR(name) + ZEND_PARSE_PARAMETERS_END(); + + zend_throw_exception(NULL, "Not implemented", 0); +} + +PHP_METHOD(Uri_WhatWg_UrlQueryParams, getAll) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zend_throw_exception(NULL, "Not implemented", 0); +} + +PHP_METHOD(Uri_WhatWg_UrlQueryParams, set) +{ + zend_string *name; + zval *value; + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_PATH_STR(name) + Z_PARAM_ZVAL(value) + ZEND_PARSE_PARAMETERS_END(); + + zend_throw_exception(NULL, "Not implemented", 0); +} + +PHP_METHOD(Uri_WhatWg_UrlQueryParams, sort) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zend_throw_exception(NULL, "Not implemented", 0); +} + +PHP_METHOD(Uri_WhatWg_UrlQueryParams, toString) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + const php_uri_parser_whatwg_url_query_params_object *uri_query_params_object = Z_URL_QUERY_PARAMS_OBJECT_P(ZEND_THIS); + + zend_string *result = php_uri_whatwg_url_query_params_to_string(uri_query_params_object->query_params); + if (result == NULL) { + throw_cannot_recompose_uri_to_string(Z_OBJ_P(ZEND_THIS)); + RETURN_THROWS(); + } + + ZVAL_STR(return_value, result); +} + +PHP_METHOD(Uri_WhatWg_UrlQueryParams, __serialize) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + php_uri_parser_whatwg_url_query_params_object *uri_query_params_object = Z_URL_QUERY_PARAMS_OBJECT_P(ZEND_THIS); + + /* Serialize state: "query" key in the first array */ + zend_string *url_query_param_str = php_uri_whatwg_url_query_params_to_string(uri_query_params_object->query_params); + if (url_query_param_str == NULL) { + throw_cannot_recompose_uri_to_string(Z_OBJ_P(ZEND_THIS)); + RETURN_THROWS(); + } + zval tmp; + ZVAL_STR(&tmp, url_query_param_str); + + array_init(return_value); + + zval arr; + array_init(&arr); + zend_hash_str_add_new(Z_ARRVAL(arr), PHP_URI_SERIALIZE_URI_QUERY_PARAM_FIELD_NAME, sizeof(PHP_URI_SERIALIZE_URI_QUERY_PARAM_FIELD_NAME) - 1, &tmp); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &arr); + + /* Serialize regular properties: second array */ + ZVAL_ARR(&arr, uri_query_params_object->std.handlers->get_properties(&uri_query_params_object->std)); + Z_TRY_ADDREF(arr); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &arr); +} + +PHP_METHOD(Uri_WhatWg_UrlQueryParams, __unserialize) +{ + HashTable *data; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ARRAY_HT(data) + ZEND_PARSE_PARAMETERS_END(); + + zend_throw_exception(NULL, "Not implemented", 0); +} + +PHP_METHOD(Uri_WhatWg_UrlQueryParams, __debugInfo) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + php_uri_parser_whatwg_url_query_params_object *url_query_params_object = Z_URL_QUERY_PARAMS_OBJECT_P(ZEND_THIS); + + RETURN_ARR(php_uri_whatwg_url_query_params_get_debug_properties(url_query_params_object)); +} + +zend_object *php_uri_object_create_rfc3986_uri_query_params(zend_class_entry *ce) +{ + php_uri_parser_rfc3986_uri_query_params_object *uri_query_params_object = zend_object_alloc(sizeof(*php_uri_ce_rfc3986_uri_query_params), ce); + + zend_object_std_init(&uri_query_params_object->std, ce); + object_properties_init(&uri_query_params_object->std, ce); + + uri_query_params_object->query_list = NULL; + uri_query_params_object->is_initialized = false; + + return &uri_query_params_object->std; +} + +zend_object *php_uri_object_create_whatwg_url_query_params(zend_class_entry *ce) +{ + php_uri_parser_whatwg_url_query_params_object *url_query_params_object = zend_object_alloc(sizeof(*url_query_params_object), ce); + + zend_object_std_init(&url_query_params_object->std, ce); + object_properties_init(&url_query_params_object->std, ce); + + url_query_params_object->query_params = NULL; + url_query_params_object->is_initialized = false; + + return &url_query_params_object->std; +} diff --git a/ext/uri/php_uri_query.h b/ext/uri/php_uri_query.h new file mode 100644 index 0000000000000..d2580c5415c13 --- /dev/null +++ b/ext/uri/php_uri_query.h @@ -0,0 +1,52 @@ +/* + +----------------------------------------------------------------------+ + | 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_URI_QUERY_H +#define PHP_URI_QUERY_H + +extern PHP_METHOD(Uri_Rfc3986_UriQueryParams, fromQueryString); +extern PHP_METHOD(Uri_Rfc3986_UriQueryParams, fromArray); +extern PHP_METHOD(Uri_Rfc3986_UriQueryParams, append); +extern PHP_METHOD(Uri_Rfc3986_UriQueryParams, delete); +extern PHP_METHOD(Uri_Rfc3986_UriQueryParams, has); +extern PHP_METHOD(Uri_Rfc3986_UriQueryParams, getFirst); +extern PHP_METHOD(Uri_Rfc3986_UriQueryParams, getLast); +extern PHP_METHOD(Uri_Rfc3986_UriQueryParams, getAll); +extern PHP_METHOD(Uri_Rfc3986_UriQueryParams, set); +extern PHP_METHOD(Uri_Rfc3986_UriQueryParams, sort); +extern PHP_METHOD(Uri_Rfc3986_UriQueryParams, toString); +extern PHP_METHOD(Uri_Rfc3986_UriQueryParams, __serialize); +extern PHP_METHOD(Uri_Rfc3986_UriQueryParams, __unserialize); +extern PHP_METHOD(Uri_Rfc3986_UriQueryParams, __debugInfo); + +extern PHP_METHOD(Uri_WhatWg_UrlQueryParams, fromQueryString); +extern PHP_METHOD(Uri_WhatWg_UrlQueryParams, fromArray); +extern PHP_METHOD(Uri_WhatWg_UrlQueryParams, append); +extern PHP_METHOD(Uri_WhatWg_UrlQueryParams, delete); +extern PHP_METHOD(Uri_WhatWg_UrlQueryParams, has); +extern PHP_METHOD(Uri_WhatWg_UrlQueryParams, getFirst); +extern PHP_METHOD(Uri_WhatWg_UrlQueryParams, getLast); +extern PHP_METHOD(Uri_WhatWg_UrlQueryParams, getAll); +extern PHP_METHOD(Uri_WhatWg_UrlQueryParams, set); +extern PHP_METHOD(Uri_WhatWg_UrlQueryParams, sort); +extern PHP_METHOD(Uri_WhatWg_UrlQueryParams, toString); +extern PHP_METHOD(Uri_WhatWg_UrlQueryParams, __serialize); +extern PHP_METHOD(Uri_WhatWg_UrlQueryParams, __unserialize); +extern PHP_METHOD(Uri_WhatWg_UrlQueryParams, __debugInfo); + +zend_object *php_uri_object_create_rfc3986_uri_query_params(zend_class_entry *ce); + +#endif diff --git a/ext/uri/tests/rfc3986/getters/host_type_success_ip_future.phpt b/ext/uri/tests/rfc3986/getters/host_type_success_ip_future.phpt new file mode 100644 index 0000000000000..d3f719c312e4d --- /dev/null +++ b/ext/uri/tests/rfc3986/getters/host_type_success_ip_future.phpt @@ -0,0 +1,13 @@ +--TEST-- +Test Uri\Rfc3986\Uri component retrieval - host type - IP future +--FILE-- +getHostType()); + +?> +--EXPECT-- +enum(Uri\Rfc3986\UriHostType::IPvFuture) + diff --git a/ext/uri/tests/rfc3986/getters/host_type_success_ipv4.phpt b/ext/uri/tests/rfc3986/getters/host_type_success_ipv4.phpt new file mode 100644 index 0000000000000..1c0c4448b953b --- /dev/null +++ b/ext/uri/tests/rfc3986/getters/host_type_success_ipv4.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test Uri\Rfc3986\Uri component retrieval - host type - IPv4 +--FILE-- +getHostType()); + +?> +--EXPECT-- +enum(Uri\Rfc3986\UriHostType::IPv4) diff --git a/ext/uri/tests/rfc3986/getters/host_type_success_ipv6.phpt b/ext/uri/tests/rfc3986/getters/host_type_success_ipv6.phpt new file mode 100644 index 0000000000000..5f3d826b412ab --- /dev/null +++ b/ext/uri/tests/rfc3986/getters/host_type_success_ipv6.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test Uri\Rfc3986\Uri component retrieval - host type - IPv6 +--FILE-- +getHostType()); + +?> +--EXPECT-- +enum(Uri\Rfc3986\UriHostType::IPv6) diff --git a/ext/uri/tests/rfc3986/getters/host_type_success_none.phpt b/ext/uri/tests/rfc3986/getters/host_type_success_none.phpt new file mode 100644 index 0000000000000..963e3cc0e95db --- /dev/null +++ b/ext/uri/tests/rfc3986/getters/host_type_success_none.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test Uri\Rfc3986\Uri component retrieval - host type - registered name +--FILE-- +getHostType()); + +?> +--EXPECT-- +NULL diff --git a/ext/uri/tests/rfc3986/getters/host_type_success_registered_name.phpt b/ext/uri/tests/rfc3986/getters/host_type_success_registered_name.phpt new file mode 100644 index 0000000000000..31d4aca36c826 --- /dev/null +++ b/ext/uri/tests/rfc3986/getters/host_type_success_registered_name.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test Uri\Rfc3986\Uri component retrieval - host type - registered name +--FILE-- +getHostType()); + +?> +--EXPECT-- +enum(Uri\Rfc3986\UriHostType::RegisteredName) diff --git a/ext/uri/tests/rfc3986/getters/path_segments_success_multiple.phpt b/ext/uri/tests/rfc3986/getters/path_segments_success_multiple.phpt new file mode 100644 index 0000000000000..f819c80b52426 --- /dev/null +++ b/ext/uri/tests/rfc3986/getters/path_segments_success_multiple.phpt @@ -0,0 +1,28 @@ +--TEST-- +Test Uri\Rfc3986\Uri component retrieval - path segments - multiple +--FILE-- +getRawPathSegments()); +var_dump($uri->getPathSegments()); + +?> +--EXPECT-- +array(3) { + [0]=> + string(3) "foo" + [1]=> + string(3) "bar" + [2]=> + string(3) "baz" +} +array(3) { + [0]=> + string(3) "foo" + [1]=> + string(3) "bar" + [2]=> + string(3) "baz" +} diff --git a/ext/uri/tests/rfc3986/getters/path_segments_success_one.phpt b/ext/uri/tests/rfc3986/getters/path_segments_success_one.phpt new file mode 100644 index 0000000000000..7ada26133fef5 --- /dev/null +++ b/ext/uri/tests/rfc3986/getters/path_segments_success_one.phpt @@ -0,0 +1,20 @@ +--TEST-- +Test Uri\Rfc3986\Uri component retrieval - path segments - one +--FILE-- +getRawPathSegments()); +var_dump($uri->getPathSegments()); + +?> +--EXPECT-- +array(1) { + [0]=> + string(0) "" +} +array(1) { + [0]=> + string(0) "" +} diff --git a/ext/uri/tests/rfc3986/getters/path_segments_success_zero.phpt b/ext/uri/tests/rfc3986/getters/path_segments_success_zero.phpt new file mode 100644 index 0000000000000..c7f82c2096798 --- /dev/null +++ b/ext/uri/tests/rfc3986/getters/path_segments_success_zero.phpt @@ -0,0 +1,14 @@ +--TEST-- +Test Uri\Rfc3986\Uri component retrieval - path segments - zero +--FILE-- +getRawPathSegments()); +var_dump($uri->getPathSegments()); + +?> +--EXPECT-- +NULL +NULL diff --git a/ext/uri/tests/rfc3986/getters/query_params_success_basic.phpt b/ext/uri/tests/rfc3986/getters/query_params_success_basic.phpt new file mode 100644 index 0000000000000..feaae580714a1 --- /dev/null +++ b/ext/uri/tests/rfc3986/getters/query_params_success_basic.phpt @@ -0,0 +1,24 @@ +--TEST-- +Test Uri\Rfc3986\Uri::getQueryParams() - success - basic +--FILE-- +getRawQueryParams()); +var_dump($uri->getQueryParams()); + +?> +--EXPECTF-- +object(Uri\Rfc3986\UriQueryParams)#%d (%d) { + ["abc"]=> + string(3) "123" + ["foo"]=> + string(3) "bar" +} +object(Uri\Rfc3986\UriQueryParams)#%d (%d) { + ["abc"]=> + string(3) "123" + ["foo"]=> + string(3) "bar" +} diff --git a/ext/uri/tests/rfc3986/getters/query_params_success_empty.phpt b/ext/uri/tests/rfc3986/getters/query_params_success_empty.phpt new file mode 100644 index 0000000000000..fcd30b1ec0204 --- /dev/null +++ b/ext/uri/tests/rfc3986/getters/query_params_success_empty.phpt @@ -0,0 +1,16 @@ +--TEST-- +Test Uri\Rfc3986\Uri::getQueryParams() - success - empty query string +--FILE-- +getRawQueryParams()); +var_dump($uri->getQueryParams()); + +?> +--EXPECTF-- +object(Uri\Rfc3986\UriQueryParams)#%d (%d) { +} +object(Uri\Rfc3986\UriQueryParams)#%d (%d) { +} diff --git a/ext/uri/tests/rfc3986/getters/query_params_success_non_existent.phpt b/ext/uri/tests/rfc3986/getters/query_params_success_non_existent.phpt new file mode 100644 index 0000000000000..44e06fe4fbf98 --- /dev/null +++ b/ext/uri/tests/rfc3986/getters/query_params_success_non_existent.phpt @@ -0,0 +1,14 @@ +--TEST-- +Test Uri\Rfc3986\Uri::getQueryParams() - success - non-existent query string +--FILE-- +getRawQueryParams()); +var_dump($uri->getQueryParams()); + +?> +--EXPECT-- +NULL +NULL diff --git a/ext/uri/tests/rfc3986/modification/query_params_success_basic.phpt b/ext/uri/tests/rfc3986/modification/query_params_success_basic.phpt new file mode 100644 index 0000000000000..c464c7f21a1ef --- /dev/null +++ b/ext/uri/tests/rfc3986/modification/query_params_success_basic.phpt @@ -0,0 +1,34 @@ +--TEST-- +Test Uri\Rfc3986\Uri::withQueryParams() - success - basic +--FILE-- +withQueryParams($queryParams); + +var_dump($uri1->getRawQuery()); +var_dump($uri2->getRawQuery()); +var_dump($uri2->getQuery()); +var_dump($uri2->getRawQueryParams()); +var_dump($uri2->getQueryParams()); +var_dump($uri2->toString()); + +?> +--EXPECTF-- +NULL +string(15) "abc=123&foo=bar" +string(15) "abc=123&foo=bar" +object(Uri\Rfc3986\UriQueryParams)#%d (%d) { + ["abc"]=> + string(3) "123" + ["foo"]=> + string(3) "bar" +} +object(Uri\Rfc3986\UriQueryParams)#%d (%d) { + ["abc"]=> + string(3) "123" + ["foo"]=> + string(3) "bar" +} +string(36) "https://example.com/?abc=123&foo=bar" diff --git a/ext/uri/tests/rfc3986/percent_encoding/percent_decode_reserved_characters_success_basic.phpt b/ext/uri/tests/rfc3986/percent_encoding/percent_decode_reserved_characters_success_basic.phpt new file mode 100644 index 0000000000000..624006b2ae846 --- /dev/null +++ b/ext/uri/tests/rfc3986/percent_encoding/percent_decode_reserved_characters_success_basic.phpt @@ -0,0 +1,14 @@ +--TEST-- +Test Uri\Rfc3986\Uri::percentDecode() - success - reserved characters basic +--FILE-- + +--EXPECT-- +string(35) ": / ? # [ ] @ ! $ & ' ( ) * + , ; =" + diff --git a/ext/uri/tests/rfc3986/percent_encoding/percent_decode_reserved_characters_success_none.phpt b/ext/uri/tests/rfc3986/percent_encoding/percent_decode_reserved_characters_success_none.phpt new file mode 100644 index 0000000000000..80e81a52cbf23 --- /dev/null +++ b/ext/uri/tests/rfc3986/percent_encoding/percent_decode_reserved_characters_success_none.phpt @@ -0,0 +1,10 @@ +--TEST-- +Test Uri\Rfc3986\Uri::percentDecode() - success - reserved characters none +--FILE-- + +--EXPECT-- +string(11) "foo 123 _ -" diff --git a/ext/uri/tests/rfc3986/percent_encoding/percent_encode_reserved_characters_success_basic.phpt b/ext/uri/tests/rfc3986/percent_encoding/percent_encode_reserved_characters_success_basic.phpt new file mode 100644 index 0000000000000..9bef30711e510 --- /dev/null +++ b/ext/uri/tests/rfc3986/percent_encoding/percent_encode_reserved_characters_success_basic.phpt @@ -0,0 +1,10 @@ +--TEST-- +Test Uri\Rfc3986\Uri::percentEncode() - success - reserved characters basic +--FILE-- + +--EXPECT-- +string(71) "%3A %2F %3F %23 %5B %5D %40 %21 %24 %26 %27 %28 %29 %2A %2B %2C %3B %3D" diff --git a/ext/uri/tests/rfc3986/percent_encoding/percent_encode_reserved_characters_success_none.phpt b/ext/uri/tests/rfc3986/percent_encoding/percent_encode_reserved_characters_success_none.phpt new file mode 100644 index 0000000000000..889fd762429bd --- /dev/null +++ b/ext/uri/tests/rfc3986/percent_encoding/percent_encode_reserved_characters_success_none.phpt @@ -0,0 +1,10 @@ +--TEST-- +Test Uri\Rfc3986\Uri::percentEncode() - success - no reserved characters +--FILE-- + +--EXPECT-- +string(11) "foo 123 _ -" diff --git a/ext/uri/tests/rfc3986/percent_encoding/percent_encode_user_info_success_basic.phpt b/ext/uri/tests/rfc3986/percent_encoding/percent_encode_user_info_success_basic.phpt new file mode 100644 index 0000000000000..6517eeae4ed52 --- /dev/null +++ b/ext/uri/tests/rfc3986/percent_encoding/percent_encode_user_info_success_basic.phpt @@ -0,0 +1,10 @@ +--TEST-- +Test Uri\Rfc3986\Uri::percentEncode() - success - user info +--FILE-- + +--EXPECT-- +string(21) "us%25rname:p%40ssword" diff --git a/ext/uri/tests/rfc3986/query_params/append_success_array_value.phpt b/ext/uri/tests/rfc3986/query_params/append_success_array_value.phpt new file mode 100644 index 0000000000000..301381d09ab7c --- /dev/null +++ b/ext/uri/tests/rfc3986/query_params/append_success_array_value.phpt @@ -0,0 +1,30 @@ +--TEST-- +Test Uri\Rfc3986\UriQueryParams::append() - success - array value +--FILE-- +append("baz", [null, false, "key2" => true, 123, "", ["bla"]]); + +var_dump($params); +var_dump($params->toString()); + +?> +--EXPECTF-- +object(Uri\Rfc3986\UriQueryParams)#%d (%d) { + ["abc"]=> + string(3) "123" + ["foo"]=> + string(3) "bar" + ["0"]=> + string(3) "bla" + ["1"]=> + string(1) "0" + ["key2"]=> + string(1) "1" + ["2"]=> + string(3) "123" + ["3"]=> + string(0) "" +} +string(44) "abc=123&foo=bar&0=&1=0&key2=1&2=123&3=&0=bla" diff --git a/ext/uri/tests/rfc3986/query_params/append_success_basic.phpt b/ext/uri/tests/rfc3986/query_params/append_success_basic.phpt new file mode 100644 index 0000000000000..8a95383f53139 --- /dev/null +++ b/ext/uri/tests/rfc3986/query_params/append_success_basic.phpt @@ -0,0 +1,22 @@ +--TEST-- +Test Uri\Rfc3986\UriQueryParams::append() - success - basic +--FILE-- +append("baz", "qux"); + +var_dump($params); +var_dump($params->toString()); + +?> +--EXPECTF-- +object(Uri\Rfc3986\UriQueryParams)#%d (%d) { + ["abc"]=> + string(3) "123" + ["foo"]=> + string(3) "bar" + ["baz"]=> + string(3) "qux" +} +string(23) "abc=123&foo=bar&baz=qux" diff --git a/ext/uri/tests/rfc3986/query_params/append_success_bool_value.phpt b/ext/uri/tests/rfc3986/query_params/append_success_bool_value.phpt new file mode 100644 index 0000000000000..015720ca736ac --- /dev/null +++ b/ext/uri/tests/rfc3986/query_params/append_success_bool_value.phpt @@ -0,0 +1,25 @@ +--TEST-- +Test Uri\Rfc3986\UriQueryParams::append() - success - bool value +--FILE-- +append("baz", false); +$params->append("qux", true); + +var_dump($params); +var_dump($params->toString()); + +?> +--EXPECTF-- +object(Uri\Rfc3986\UriQueryParams)#%d (%d) { + ["abc"]=> + string(3) "123" + ["foo"]=> + string(3) "bar" + ["baz"]=> + string(1) "0" + ["qux"]=> + string(1) "1" +} +string(27) "abc=123&foo=bar&baz=0&qux=1" diff --git a/ext/uri/tests/rfc3986/query_params/append_success_empty_array_value.phpt b/ext/uri/tests/rfc3986/query_params/append_success_empty_array_value.phpt new file mode 100644 index 0000000000000..8f0d7235157df --- /dev/null +++ b/ext/uri/tests/rfc3986/query_params/append_success_empty_array_value.phpt @@ -0,0 +1,22 @@ +--TEST-- +Test Uri\Rfc3986\UriQueryParams::append() - success - empty array value +--FILE-- +append("baz", []); + +var_dump($params); +var_dump($params->toString()); + +?> +--EXPECTF-- +object(Uri\Rfc3986\UriQueryParams)#%d (%d) { + ["abc"]=> + string(3) "123" + ["foo"]=> + string(3) "bar" + ["baz"]=> + string(0) "" +} +string(20) "abc=123&foo=bar&baz=" diff --git a/ext/uri/tests/rfc3986/query_params/append_success_existing.phpt b/ext/uri/tests/rfc3986/query_params/append_success_existing.phpt new file mode 100644 index 0000000000000..b6370a370efc3 --- /dev/null +++ b/ext/uri/tests/rfc3986/query_params/append_success_existing.phpt @@ -0,0 +1,20 @@ +--TEST-- +Test Uri\Rfc3986\UriQueryParams::append() - success - existing parameter +--FILE-- +append("foo", "bar"); + +var_dump($params); +var_dump($params->toString()); + +?> +--EXPECTF-- +object(Uri\Rfc3986\UriQueryParams)#%d (%d) { + ["abc"]=> + string(3) "123" + ["foo"]=> + string(3) "bar" +} +string(23) "abc=123&foo=bar&foo=bar" diff --git a/ext/uri/tests/rfc3986/query_params/append_success_int_value.phpt b/ext/uri/tests/rfc3986/query_params/append_success_int_value.phpt new file mode 100644 index 0000000000000..8be8cc2f78ac4 --- /dev/null +++ b/ext/uri/tests/rfc3986/query_params/append_success_int_value.phpt @@ -0,0 +1,23 @@ +--TEST-- +Test Uri\Rfc3986\UriQueryParams::append() - success - integer value + +--FILE-- +append("baz", 0); + +var_dump($params); +var_dump($params->toString()); + +?> +--EXPECTF-- +object(Uri\Rfc3986\UriQueryParams)#%d (%d) { + ["abc"]=> + string(3) "123" + ["foo"]=> + string(3) "bar" + ["baz"]=> + string(1) "0" +} +string(21) "abc=123&foo=bar&baz=0" diff --git a/ext/uri/tests/rfc3986/query_params/parse_success_basic.phpt b/ext/uri/tests/rfc3986/query_params/parse_success_basic.phpt new file mode 100644 index 0000000000000..e4658842bbec5 --- /dev/null +++ b/ext/uri/tests/rfc3986/query_params/parse_success_basic.phpt @@ -0,0 +1,17 @@ +--TEST-- +Test Uri\Rfc3986\UriQueryParams::parse() - success +--FILE-- + +--EXPECTF-- +object(Uri\Rfc3986\UriQueryParams)#%d (%d) { + ["abc"]=> + string(3) "123" + ["foo"]=> + string(3) "bar" +} diff --git a/ext/uri/tests/rfc3986/query_params/parse_success_empty.phpt b/ext/uri/tests/rfc3986/query_params/parse_success_empty.phpt new file mode 100644 index 0000000000000..249303fc688e8 --- /dev/null +++ b/ext/uri/tests/rfc3986/query_params/parse_success_empty.phpt @@ -0,0 +1,13 @@ +--TEST-- +Test Uri\Rfc3986\UriQueryParams::parse() - success - empty string +--FILE-- + +--EXPECTF-- +object(Uri\Rfc3986\UriQueryParams)#%d (%d) { +} diff --git a/ext/uri/tests/rfc3986/query_params/parse_success_reserved.phpt b/ext/uri/tests/rfc3986/query_params/parse_success_reserved.phpt new file mode 100644 index 0000000000000..93e2852f82868 --- /dev/null +++ b/ext/uri/tests/rfc3986/query_params/parse_success_reserved.phpt @@ -0,0 +1,19 @@ +--TEST-- +Test Uri\Rfc3986\UriQueryParams::parse() - success - reserved characters are not validated +--FILE-- +=b@r"); + +var_dump($params); +var_dump($params->toString()); + +?> +--EXPECTF-- +object(Uri\Rfc3986\UriQueryParams)#%d (%d) { + ["ab:c"]=> + string(4) "#123" + [""]=> + string(3) "b@r" +} +string(14) "abc=123&foo=br" diff --git a/ext/uri/tests/rfc3986/query_params/parse_success_space.phpt b/ext/uri/tests/rfc3986/query_params/parse_success_space.phpt new file mode 100644 index 0000000000000..74d9d8de9aa5b --- /dev/null +++ b/ext/uri/tests/rfc3986/query_params/parse_success_space.phpt @@ -0,0 +1,19 @@ +--TEST-- +Test Uri\Rfc3986\UriQueryParams::parse() - success - space character +--FILE-- +toString()); + +?> +--EXPECTF-- +object(Uri\Rfc3986\UriQueryParams)#%d (%d) { + ["a c"]=> + string(3) "123" + ["foo"]=> + string(3) "b r" +} +string(15) "a+c=123&foo=b+r" diff --git a/ext/uri/tests/rfc3986/query_params/to_string_success_basic.phpt b/ext/uri/tests/rfc3986/query_params/to_string_success_basic.phpt new file mode 100644 index 0000000000000..c66b0b9dfea7e --- /dev/null +++ b/ext/uri/tests/rfc3986/query_params/to_string_success_basic.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test Uri\Rfc3986\UriQueryParams::toString() - success - basic +--FILE-- +toString()); + +?> +--EXPECT-- +string(15) "abc=123&foo=bar" diff --git a/ext/uri/tests/rfc3986/query_params/to_string_success_empty.phpt b/ext/uri/tests/rfc3986/query_params/to_string_success_empty.phpt new file mode 100644 index 0000000000000..34f01058ceacc --- /dev/null +++ b/ext/uri/tests/rfc3986/query_params/to_string_success_empty.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test Uri\Rfc3986\UriQueryParams::toString() - success - empty query string +--FILE-- +toString()); + +?> +--EXPECT-- +string(0) "" diff --git a/ext/uri/tests/rfc3986/query_params/to_string_success_value_empty.phpt b/ext/uri/tests/rfc3986/query_params/to_string_success_value_empty.phpt new file mode 100644 index 0000000000000..dd89da77ac582 --- /dev/null +++ b/ext/uri/tests/rfc3986/query_params/to_string_success_value_empty.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test Uri\Rfc3986\UriQueryParams::toString() - success - empty values +--FILE-- +toString()); + +?> +--EXPECT-- +string(8) "foo=&bar" diff --git a/ext/uri/tests/whatwg/getters/host_type_success_domain.phpt b/ext/uri/tests/whatwg/getters/host_type_success_domain.phpt new file mode 100644 index 0000000000000..21fc961e55411 --- /dev/null +++ b/ext/uri/tests/whatwg/getters/host_type_success_domain.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test Uri\WhatWg\Url component retrieval - host type - registered name +--FILE-- +getHostType()); + +?> +--EXPECT-- +enum(Uri\WhatWg\UrlHostType::Domain) diff --git a/ext/uri/tests/whatwg/getters/host_type_success_empty.phpt b/ext/uri/tests/whatwg/getters/host_type_success_empty.phpt new file mode 100644 index 0000000000000..41351350fb610 --- /dev/null +++ b/ext/uri/tests/whatwg/getters/host_type_success_empty.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test Uri\WhatWg\Url component retrieval - host type - empty +--FILE-- +getHostType()); + +?> +--EXPECT-- +enum(Uri\WhatWg\UrlHostType::Empty) diff --git a/ext/uri/tests/whatwg/getters/host_type_success_ipv4.phpt b/ext/uri/tests/whatwg/getters/host_type_success_ipv4.phpt new file mode 100644 index 0000000000000..f2f63caabb5e3 --- /dev/null +++ b/ext/uri/tests/whatwg/getters/host_type_success_ipv4.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test Uri\WhatWg\Url component retrieval - host type - IPv4 +--FILE-- +getHostType()); + +?> +--EXPECT-- +enum(Uri\WhatWg\UrlHostType::IPv4) diff --git a/ext/uri/tests/whatwg/getters/host_type_success_ipv6.phpt b/ext/uri/tests/whatwg/getters/host_type_success_ipv6.phpt new file mode 100644 index 0000000000000..ce5bb00b93d5e --- /dev/null +++ b/ext/uri/tests/whatwg/getters/host_type_success_ipv6.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test Uri\WhatWg\Url component retrieval - host type - IPv6 +--FILE-- +getHostType()); + +?> +--EXPECT-- +enum(Uri\WhatWg\UrlHostType::IPv6) diff --git a/ext/uri/tests/whatwg/getters/host_type_success_none.phpt b/ext/uri/tests/whatwg/getters/host_type_success_none.phpt new file mode 100644 index 0000000000000..07d54412a23c3 --- /dev/null +++ b/ext/uri/tests/whatwg/getters/host_type_success_none.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test Uri\WhatWg\Url component retrieval - host type - none +--FILE-- +getHostType()); + +?> +--EXPECT-- +NULL diff --git a/ext/uri/tests/whatwg/getters/host_type_success_opaque.phpt b/ext/uri/tests/whatwg/getters/host_type_success_opaque.phpt new file mode 100644 index 0000000000000..844cba82d512d --- /dev/null +++ b/ext/uri/tests/whatwg/getters/host_type_success_opaque.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test Uri\WhatWg\Url component retrieval - host type - opaque +--FILE-- +getHostType()); + +?> +--EXPECT-- +enum(Uri\WhatWg\UrlHostType::Opaque) diff --git a/ext/uri/tests/whatwg/getters/is_special_success_false.phpt b/ext/uri/tests/whatwg/getters/is_special_success_false.phpt new file mode 100644 index 0000000000000..320923c59e0fa --- /dev/null +++ b/ext/uri/tests/whatwg/getters/is_special_success_false.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test Uri\WhatWg\Url::isSpecial() - success - not special +--FILE-- +isSpecial()); + +?> +--EXPECT-- +bool(false) diff --git a/ext/uri/tests/whatwg/getters/is_special_success_true.phpt b/ext/uri/tests/whatwg/getters/is_special_success_true.phpt new file mode 100644 index 0000000000000..9f499af436554 --- /dev/null +++ b/ext/uri/tests/whatwg/getters/is_special_success_true.phpt @@ -0,0 +1,31 @@ +--TEST-- +Test Uri\WhatWg\Url::isSpecial() - success - https +--FILE-- +isSpecial()); + +$url = Uri\WhatWg\Url::parse("https://example.com"); +var_dump($url->isSpecial()); + +$url = Uri\WhatWg\Url::parse("ws://example.com"); +var_dump($url->isSpecial()); + +$url = Uri\WhatWg\Url::parse("wss://example.com"); +var_dump($url->isSpecial()); + +$url = Uri\WhatWg\Url::parse("ftp://example.com"); +var_dump($url->isSpecial()); + +$url = Uri\WhatWg\Url::parse("file://example.com"); +var_dump($url->isSpecial()); + +?> +--EXPECT-- +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) diff --git a/ext/uri/tests/whatwg/getters/path_segments_success_multiple.phpt b/ext/uri/tests/whatwg/getters/path_segments_success_multiple.phpt new file mode 100644 index 0000000000000..14cc057362f6e --- /dev/null +++ b/ext/uri/tests/whatwg/getters/path_segments_success_multiple.phpt @@ -0,0 +1,19 @@ +--TEST-- +Test Uri\WhatWg\Url component retrieval - path segments - multiple +--FILE-- +getPathSegments()); + +?> +--EXPECT-- +array(3) { + [0]=> + string(3) "foo" + [1]=> + string(3) "bar" + [2]=> + string(3) "baz" +} diff --git a/ext/uri/tests/whatwg/getters/path_segments_success_one.phpt b/ext/uri/tests/whatwg/getters/path_segments_success_one.phpt new file mode 100644 index 0000000000000..75f5c35c50099 --- /dev/null +++ b/ext/uri/tests/whatwg/getters/path_segments_success_one.phpt @@ -0,0 +1,13 @@ +--TEST-- +Test Uri\WhatWg\Url component retrieval - path segments - one +--FILE-- +getPathSegments()); + +?> +--EXPECT-- +array(0) { +} diff --git a/ext/uri/tests/whatwg/getters/path_segments_success_zero.phpt b/ext/uri/tests/whatwg/getters/path_segments_success_zero.phpt new file mode 100644 index 0000000000000..8f194e8b2140e --- /dev/null +++ b/ext/uri/tests/whatwg/getters/path_segments_success_zero.phpt @@ -0,0 +1,13 @@ +--TEST-- +Test Uri\WhatWg\Url component retrieval - path segments - zero +--FILE-- +getPathSegments()); + +?> +--EXPECT-- +array(0) { +} diff --git a/ext/uri/tests/whatwg/getters/query_params_success_basic.phpt b/ext/uri/tests/whatwg/getters/query_params_success_basic.phpt new file mode 100644 index 0000000000000..c92ca56af395d --- /dev/null +++ b/ext/uri/tests/whatwg/getters/query_params_success_basic.phpt @@ -0,0 +1,17 @@ +--TEST-- +Test Uri\WhatWg\Url::getQueryParams() - success - basic +--FILE-- +getQueryParams()); + +?> +--EXPECTF-- +object(Uri\WhatWg\UrlQueryParams)#%d (%d) { + ["abc"]=> + string(3) "123" + ["foo"]=> + string(3) "bar" +} diff --git a/ext/uri/tests/whatwg/getters/query_params_success_empty.phpt b/ext/uri/tests/whatwg/getters/query_params_success_empty.phpt new file mode 100644 index 0000000000000..c9dc4ba9c173c --- /dev/null +++ b/ext/uri/tests/whatwg/getters/query_params_success_empty.phpt @@ -0,0 +1,13 @@ +--TEST-- +Test Uri\WhatWg\Url::getQueryParams() - success - empty query string +--FILE-- +getQueryParams()); + +?> +--EXPECTF-- +object(Uri\WhatWg\UrlQueryParams)#%d (%d) { +} diff --git a/ext/uri/tests/whatwg/getters/query_params_success_non_existent.phpt b/ext/uri/tests/whatwg/getters/query_params_success_non_existent.phpt new file mode 100644 index 0000000000000..85af71915a3e9 --- /dev/null +++ b/ext/uri/tests/whatwg/getters/query_params_success_non_existent.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test Uri\WhatWg\Url::getQueryParams() - success - non-existent query string +--FILE-- +getQueryParams()); + +?> +--EXPECT-- +NULL diff --git a/ext/uri/tests/whatwg/modification/query_params_success_basic.phpt b/ext/uri/tests/whatwg/modification/query_params_success_basic.phpt new file mode 100644 index 0000000000000..dc53f3ba44845 --- /dev/null +++ b/ext/uri/tests/whatwg/modification/query_params_success_basic.phpt @@ -0,0 +1,25 @@ +--TEST-- +Test Uri\WhatWg\Url::withQueryParams() - success - basic +--FILE-- +withQueryParams($queryParams); + +var_dump($uri1->getQuery()); +var_dump($uri2->getQuery()); +var_dump($uri2->getQueryParams()); +var_dump($uri2->toAsciiString()); + +?> +--EXPECTF-- +NULL +string(15) "abc=123&foo=bar" +object(Uri\WhatWg\UrlQueryParams)#%d (%d) { + ["abc"]=> + string(3) "123" + ["foo"]=> + string(3) "bar" +} +string(36) "https://example.com/?abc=123&foo=bar" diff --git a/ext/uri/tests/whatwg/query_params/append_success_array_value.phpt b/ext/uri/tests/whatwg/query_params/append_success_array_value.phpt new file mode 100644 index 0000000000000..49dfcf1db88c7 --- /dev/null +++ b/ext/uri/tests/whatwg/query_params/append_success_array_value.phpt @@ -0,0 +1,30 @@ +--TEST-- +Test Uri\WhatWg\UrlQueryParams::append() - success - array value +--FILE-- +append("baz", [null, false, "key2" => true, 123, "", ["bla"]]); + +var_dump($params); +var_dump($params->toString()); + +?> +--EXPECTF-- +object(Uri\WhatWg\UrlQueryParams)#%d (%d) { + ["abc"]=> + string(3) "123" + ["foo"]=> + string(3) "bar" + ["0"]=> + string(3) "bla" + ["1"]=> + string(1) "0" + ["key2"]=> + string(1) "1" + ["2"]=> + string(3) "123" + ["3"]=> + string(0) "" +} +string(44) "abc=123&foo=bar&0=&1=0&key2=1&2=123&3=&0=bla" diff --git a/ext/uri/tests/whatwg/query_params/append_success_basic.phpt b/ext/uri/tests/whatwg/query_params/append_success_basic.phpt new file mode 100644 index 0000000000000..317e1b3890081 --- /dev/null +++ b/ext/uri/tests/whatwg/query_params/append_success_basic.phpt @@ -0,0 +1,22 @@ +--TEST-- +Test Uri\WhatWg\UrlQueryParams::append() - success - basic +--FILE-- +append("baz", "qux"); + +var_dump($params); +var_dump($params->toString()); + +?> +--EXPECTF-- +object(Uri\WhatWg\UrlQueryParams)#%d (%d) { + ["abc"]=> + string(3) "123" + ["foo"]=> + string(3) "bar" + ["baz"]=> + string(3) "qux" +} +string(23) "abc=123&foo=bar&baz=qux" diff --git a/ext/uri/tests/whatwg/query_params/append_success_bool_value.phpt b/ext/uri/tests/whatwg/query_params/append_success_bool_value.phpt new file mode 100644 index 0000000000000..970f36dc48db4 --- /dev/null +++ b/ext/uri/tests/whatwg/query_params/append_success_bool_value.phpt @@ -0,0 +1,25 @@ +--TEST-- +Test Uri\WhatWg\UrlQueryParams::append() - success - bool value +--FILE-- +append("baz", false); +$params->append("qux", true); + +var_dump($params); +var_dump($params->toString()); + +?> +--EXPECTF-- +object(Uri\WhatWg\UrlQueryParams)#%d (%d) { + ["abc"]=> + string(3) "123" + ["foo"]=> + string(3) "bar" + ["baz"]=> + string(1) "0" + ["qux"]=> + string(1) "1" +} +string(27) "abc=123&foo=bar&baz=0&qux=1" diff --git a/ext/uri/tests/whatwg/query_params/append_success_empty_array_value.phpt b/ext/uri/tests/whatwg/query_params/append_success_empty_array_value.phpt new file mode 100644 index 0000000000000..79e1cbc9e4cad --- /dev/null +++ b/ext/uri/tests/whatwg/query_params/append_success_empty_array_value.phpt @@ -0,0 +1,22 @@ +--TEST-- +Test Uri\WhatWg\UrlQueryParams::append() - success - empty array value +--FILE-- +append("baz", []); + +var_dump($params); +var_dump($params->toString()); + +?> +--EXPECTF-- +object(Uri\WhatWg\UrlQueryParams)#%d (%d) { + ["abc"]=> + string(3) "123" + ["foo"]=> + string(3) "bar" + ["baz"]=> + string(0) "" +} +string(20) "abc=123&foo=bar&baz=" diff --git a/ext/uri/tests/whatwg/query_params/append_success_existing.phpt b/ext/uri/tests/whatwg/query_params/append_success_existing.phpt new file mode 100644 index 0000000000000..916144ac03d7c --- /dev/null +++ b/ext/uri/tests/whatwg/query_params/append_success_existing.phpt @@ -0,0 +1,20 @@ +--TEST-- +Test Uri\WhatWg\UrlQueryParams::append() - success - existing parameter +--FILE-- +append("foo", "bar"); + +var_dump($params); +var_dump($params->toString()); + +?> +--EXPECTF-- +object(Uri\WhatWg\UrlQueryParams)#%d (%d) { + ["abc"]=> + string(3) "123" + ["foo"]=> + string(3) "bar" +} +string(23) "abc=123&foo=bar&foo=bar" diff --git a/ext/uri/tests/whatwg/query_params/append_success_int_value.phpt b/ext/uri/tests/whatwg/query_params/append_success_int_value.phpt new file mode 100644 index 0000000000000..22e2198dfea67 --- /dev/null +++ b/ext/uri/tests/whatwg/query_params/append_success_int_value.phpt @@ -0,0 +1,23 @@ +--TEST-- +Test Uri\WhatWg\UrlQueryParams::append() - success - integer value + +--FILE-- +append("baz", 0); + +var_dump($params); +var_dump($params->toString()); + +?> +--EXPECTF-- +object(Uri\WhatWg\UrlQueryParams)#%d (%d) { + ["abc"]=> + string(3) "123" + ["foo"]=> + string(3) "bar" + ["baz"]=> + string(1) "0" +} +string(21) "abc=123&foo=bar&baz=0" diff --git a/ext/uri/tests/whatwg/query_params/delete_success_basic.phpt b/ext/uri/tests/whatwg/query_params/delete_success_basic.phpt new file mode 100644 index 0000000000000..71162a89ab187 --- /dev/null +++ b/ext/uri/tests/whatwg/query_params/delete_success_basic.phpt @@ -0,0 +1,18 @@ +--TEST-- +Test Uri\WhatWg\UrlQueryParams::delete() - success - basic +--FILE-- +delete("abc"); + +var_dump($params); +var_dump($params->toString()); + +?> +--EXPECTF-- +object(Uri\WhatWg\UrlQueryParams)#%d (%d) { + ["foo"]=> + string(3) "bar" +} +string(7) "foo=bar" diff --git a/ext/uri/tests/whatwg/query_params/delete_success_multiple.phpt b/ext/uri/tests/whatwg/query_params/delete_success_multiple.phpt new file mode 100644 index 0000000000000..0e7a9ccaf7f03 --- /dev/null +++ b/ext/uri/tests/whatwg/query_params/delete_success_multiple.phpt @@ -0,0 +1,18 @@ +--TEST-- +Test Uri\WhatWg\UrlQueryParams::delete() - success - basic +--FILE-- +delete("foo"); + +var_dump($params); +var_dump($params->toString()); + +?> +--EXPECTF-- +object(Uri\WhatWg\UrlQueryParams)#%d (%d) { + ["abc"]=> + string(3) "123" +} +string(7) "abc=123" diff --git a/ext/uri/tests/whatwg/query_params/delete_success_nonexistent.phpt b/ext/uri/tests/whatwg/query_params/delete_success_nonexistent.phpt new file mode 100644 index 0000000000000..344fbb50517b0 --- /dev/null +++ b/ext/uri/tests/whatwg/query_params/delete_success_nonexistent.phpt @@ -0,0 +1,20 @@ +--TEST-- +Test Uri\WhatWg\UrlQueryParams::delete() - success - nonexistent key +--FILE-- +delete("baz"); + +var_dump($params); +var_dump($params->toString()); + +?> +--EXPECTF-- +object(Uri\WhatWg\UrlQueryParams)#%d (%d) { + ["abc"]=> + string(3) "123" + ["foo"]=> + string(3) "bar" +} +string(15) "abc=123&foo=bar" diff --git a/ext/uri/tests/whatwg/query_params/has_success_false.phpt b/ext/uri/tests/whatwg/query_params/has_success_false.phpt new file mode 100644 index 0000000000000..d540620df305d --- /dev/null +++ b/ext/uri/tests/whatwg/query_params/has_success_false.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test Uri\WhatWg\UrlQueryParams::has() - success - basic +--FILE-- +has("baz")); + +?> +--EXPECT-- +bool(false) diff --git a/ext/uri/tests/whatwg/query_params/has_success_true.phpt b/ext/uri/tests/whatwg/query_params/has_success_true.phpt new file mode 100644 index 0000000000000..a1cf92f818306 --- /dev/null +++ b/ext/uri/tests/whatwg/query_params/has_success_true.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test Uri\WhatWg\UrlQueryParams::has() - success - basic +--FILE-- +has("abc")); + +?> +--EXPECT-- +bool(true) diff --git a/ext/uri/tests/whatwg/query_params/parse_success_basic.phpt b/ext/uri/tests/whatwg/query_params/parse_success_basic.phpt new file mode 100644 index 0000000000000..86c63cd447565 --- /dev/null +++ b/ext/uri/tests/whatwg/query_params/parse_success_basic.phpt @@ -0,0 +1,19 @@ +--TEST-- +Test Uri\WhatWg\UrlQueryParams::parse() - success +--FILE-- +toString()); + +?> +--EXPECTF-- +object(Uri\WhatWg\UrlQueryParams)#%d (%d) { + ["abc"]=> + string(3) "123" + ["foo"]=> + string(3) "bar" +} +string(15) "abc=123&foo=bar" diff --git a/ext/uri/tests/whatwg/query_params/parse_success_empty.phpt b/ext/uri/tests/whatwg/query_params/parse_success_empty.phpt new file mode 100644 index 0000000000000..a35966ca871eb --- /dev/null +++ b/ext/uri/tests/whatwg/query_params/parse_success_empty.phpt @@ -0,0 +1,15 @@ +--TEST-- +Test Uri\WhatWg\UrlQueryParams::parse() - success - empty string +--FILE-- +toString()); + +?> +--EXPECTF-- +object(Uri\WhatWg\UrlQueryParams)#%d (%d) { +} +string(0) "" diff --git a/ext/uri/tests/whatwg/query_params/parse_success_encoding_set1.phpt b/ext/uri/tests/whatwg/query_params/parse_success_encoding_set1.phpt new file mode 100644 index 0000000000000..b84a19f6f109a --- /dev/null +++ b/ext/uri/tests/whatwg/query_params/parse_success_encoding_set1.phpt @@ -0,0 +1,19 @@ +--TEST-- +Test Uri\WhatWg\UrlQueryParams::parse() - success - characters in the query string percent-encode set +--FILE-- +=b@r"); + +var_dump($params); +var_dump($params->toString()); + +?> +--EXPECTF-- +object(Uri\WhatWg\UrlQueryParams)#%d (%d) { + ["ab:c"]=> + string(4) "#123" + [""]=> + string(3) "b@r" +} +string(29) "ab%3Ac=%23123&%3Cfoo%3E=b%40r" diff --git a/ext/uri/tests/whatwg/query_params/parse_success_encoding_set2.phpt b/ext/uri/tests/whatwg/query_params/parse_success_encoding_set2.phpt new file mode 100644 index 0000000000000..e01b2496dddc9 --- /dev/null +++ b/ext/uri/tests/whatwg/query_params/parse_success_encoding_set2.phpt @@ -0,0 +1,19 @@ +--TEST-- +Test Uri\WhatWg\UrlQueryParams::parse() - success - characters in the application/x-www-form-urlencoded percent-encode set +--FILE-- +toString()); + +?> +--EXPECTF-- +object(Uri\WhatWg\UrlQueryParams)#%d (%d) { + ["abc!"]=> + string(3) "123" + ["foo'"]=> + string(4) "bar)" +} +string(24) "abc%21=123&foo%27=bar%29" diff --git a/ext/uri/tests/whatwg/query_params/parse_success_space.phpt b/ext/uri/tests/whatwg/query_params/parse_success_space.phpt new file mode 100644 index 0000000000000..4edf97a0c54df --- /dev/null +++ b/ext/uri/tests/whatwg/query_params/parse_success_space.phpt @@ -0,0 +1,19 @@ +--TEST-- +Test Uri\WhatWg\UrlQueryParams::parse() - success - space character +--FILE-- +toString()); + +?> +--EXPECTF-- +object(Uri\WhatWg\UrlQueryParams)#%d (%d) { + ["a c"]=> + string(3) "123" + ["foo"]=> + string(3) "b r" +} +string(15) "a+c=123&foo=b+r" diff --git a/ext/uri/tests/whatwg/query_params/query_params_success_basic.phpt b/ext/uri/tests/whatwg/query_params/query_params_success_basic.phpt new file mode 100644 index 0000000000000..4b8ca33c8acc4 --- /dev/null +++ b/ext/uri/tests/whatwg/query_params/query_params_success_basic.phpt @@ -0,0 +1,17 @@ +--TEST-- +Test Uri\WhatWg\Url::getQueryParams() - success - basic +--FILE-- +getQueryParams()); + +?> +--EXPECTF-- +object(Uri\WhatWg\UrlQueryParams)#%d (%d) { + ["abc"]=> + string(3) "123" + ["foo"]=> + string(3) "bar" +} diff --git a/ext/uri/tests/whatwg/query_params/query_params_success_empty.phpt b/ext/uri/tests/whatwg/query_params/query_params_success_empty.phpt new file mode 100644 index 0000000000000..cc6e5845396d5 --- /dev/null +++ b/ext/uri/tests/whatwg/query_params/query_params_success_empty.phpt @@ -0,0 +1,13 @@ +--TEST-- +Test Uri\WhatWg\Url::getQueryParams() - success - empty query string +--FILE-- +getQueryParams()); + +?> +--EXPECTF-- +object(Uri\WhatWg\UrlQueryParams)#%d (%d) { +} diff --git a/ext/uri/tests/whatwg/query_params/query_params_success_non_existent.phpt b/ext/uri/tests/whatwg/query_params/query_params_success_non_existent.phpt new file mode 100644 index 0000000000000..c3f088bb8e444 --- /dev/null +++ b/ext/uri/tests/whatwg/query_params/query_params_success_non_existent.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test Uri\WhatWg\Url::getQueryParams() - success - non-existent query string +--FILE-- +getQueryParams()); + +?> +--EXPECT-- +NULL diff --git a/ext/uri/tests/whatwg/query_params/to_string_success_basic.phpt b/ext/uri/tests/whatwg/query_params/to_string_success_basic.phpt new file mode 100644 index 0000000000000..74a1146821643 --- /dev/null +++ b/ext/uri/tests/whatwg/query_params/to_string_success_basic.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test Uri\WhatWg\UrlQueryParams::toString() - success - basic +--FILE-- +toString()); + +?> +--EXPECT-- +string(15) "abc=123&foo=bar" diff --git a/ext/uri/tests/whatwg/query_params/to_string_success_empty.phpt b/ext/uri/tests/whatwg/query_params/to_string_success_empty.phpt new file mode 100644 index 0000000000000..1cefce7715a29 --- /dev/null +++ b/ext/uri/tests/whatwg/query_params/to_string_success_empty.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test Uri\WhatWg\UrlQueryParams::toString() - success - empty query string +--FILE-- +toString()); + +?> +--EXPECT-- +string(0) "" diff --git a/ext/uri/tests/whatwg/query_params/to_string_success_value_empty.phpt b/ext/uri/tests/whatwg/query_params/to_string_success_value_empty.phpt new file mode 100644 index 0000000000000..a2c63633eee4a --- /dev/null +++ b/ext/uri/tests/whatwg/query_params/to_string_success_value_empty.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test Uri\WhatWg\UrlQueryParams::toString() - success - empty values +--FILE-- +toString()); + +?> +--EXPECT-- +string(9) "foo=&bar=" diff --git a/ext/uri/uri_parser_rfc3986.c b/ext/uri/uri_parser_rfc3986.c index 24dd4e1947b2b..b00579e4de593 100644 --- a/ext/uri/uri_parser_rfc3986.c +++ b/ext/uri/uri_parser_rfc3986.c @@ -17,6 +17,7 @@ #include "php.h" #include "uri_parser_rfc3986.h" #include "php_uri_common.h" +#include "Zend/zend_enum.h" #include "Zend/zend_smart_str.h" #include "Zend/zend_exceptions.h" @@ -59,6 +60,541 @@ static const UriMemoryManager php_uri_parser_rfc3986_memory_manager = { * const struct with a non-const pointer for convenience. */ static UriMemoryManager* const mm = (UriMemoryManager*)&php_uri_parser_rfc3986_memory_manager; +#define PERCENT_ENCODE_COLON_CASE(retval) \ + case ':': \ + smart_str_appends(&retval, "%3A"); \ + break; + +#define PERCENT_ENCODE_SLASH_CASE(retval) \ + case '/': \ + smart_str_appends(&retval, "%2F"); \ + break; + +#define PERCENT_ENCODE_AT_CASE(retval) \ + case '@': \ + smart_str_appends(&retval, "%40"); \ + break; + +#define PERCENT_ENCODE_QUESTION_MARK_CASE(retval) \ + case '?': \ + smart_str_appends(&retval, "%3F"); \ + break; + +#define PERCENT_ENCODE_REST_OF_GEN_DELIMS_CASES(retval) \ + case '#': \ + smart_str_appends(&retval, "%23"); \ + break; \ + case '[': \ + smart_str_appends(&retval, "%5B"); \ + break; \ + case ']': \ + smart_str_appends(&retval, "%5D"); \ + break; + +#define PERCENT_ENCODE_PERCENT_CASE(retval) \ + case '%': \ + smart_str_appends(&retval, "%25"); \ + break; + +#define PERCENT_ENCODE_PERCENT_AS_PLUS_CASE(retval) \ + case '%': \ + smart_str_appends(&retval, "+"); \ + break; + +#define PERCENT_ENCODE_OTHER_CHARACTERS_CASES(retval) \ + case ' ': \ + smart_str_appends(&retval, "%20"); \ + break; \ + case '"': \ + smart_str_appends(&retval, "%22"); \ + break; \ + case '<': \ + smart_str_appends(&retval, "%3C"); \ + break; \ + case '>': \ + smart_str_appends(&retval, "%3E"); \ + break; \ + case '\\': \ + smart_str_appends(&retval, "%5C"); \ + break; \ + case '^': \ + smart_str_appends(&retval, "%5E"); \ + break; \ + case '`': \ + smart_str_appends(&retval, "%60"); \ + break; \ + case '{': \ + smart_str_appends(&retval, "%7B"); \ + break; \ + case '|': \ + smart_str_appends(&retval, "%7C"); \ + break; \ + case '}': \ + smart_str_appends(&retval, "%7D"); \ + break; + +#define PERCENT_ENCODE_GEN_DELIMS_CASES(retval) \ + PERCENT_ENCODE_COLON_CASE(retval) \ + PERCENT_ENCODE_SLASH_CASE(retval) \ + PERCENT_ENCODE_QUESTION_MARK_CASE(retval) \ + PERCENT_ENCODE_AT_CASE(retval) \ + PERCENT_ENCODE_REST_OF_GEN_DELIMS_CASES(retval) + +#define PERCENT_ENCODE_SUB_DELIMS_CASES(retval) \ + case '!': \ + smart_str_appends(&retval, "%21"); \ + break; \ + case '$': \ + smart_str_appends(&retval, "%24"); \ + break; \ + case '&': \ + smart_str_appends(&retval, "%26"); \ + break; \ + case '\'': \ + smart_str_appends(&retval, "%27"); \ + break; \ + case '(': \ + smart_str_appends(&retval, "%28"); \ + break; \ + case ')': \ + smart_str_appends(&retval, "%29"); \ + break; \ + case '*': \ + smart_str_appends(&retval, "%2A"); \ + break; \ + case '+': \ + smart_str_appends(&retval, "%2B"); \ + break; \ + case ',': \ + smart_str_appends(&retval, "%2C"); \ + break; \ + case ';': \ + smart_str_appends(&retval, "%3B"); \ + break; \ + case '=': \ + smart_str_appends(&retval, "%3D"); \ + break; + +ZEND_ATTRIBUTE_NONNULL zend_string *php_uri_parser_rfc3986_percent_encode_reserved_characters(const zend_string *str) +{ + smart_str retval = {0}; + + // gen-delims ":" / "/" / "?" / "#" / "[" / "]" / "@" + // sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + // / "*" / "+" / "," / ";" / "=" + + for (int i = 0; i < ZSTR_LEN(str); i++) { + switch (ZSTR_VAL(str)[i]) { + PERCENT_ENCODE_GEN_DELIMS_CASES(retval) + PERCENT_ENCODE_SUB_DELIMS_CASES(retval) + default: + smart_str_appendc(&retval, ZSTR_VAL(str)[i]); + break; + } + } + + return smart_str_extract(&retval); +} + +ZEND_ATTRIBUTE_NONNULL zend_string *php_uri_parser_rfc3986_percent_encode_all(const zend_string *str) +{ + smart_str retval = {0}; + + // gen-delims ":" / "/" / "?" / "#" / "[" / "]" / "@" + // sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + // / "*" / "+" / "," / ";" / "=" + + for (int i = 0; i < ZSTR_LEN(str); i++) { + switch (ZSTR_VAL(str)[i]) { + PERCENT_ENCODE_GEN_DELIMS_CASES(retval) + PERCENT_ENCODE_SUB_DELIMS_CASES(retval) + PERCENT_ENCODE_PERCENT_CASE(retval) + PERCENT_ENCODE_OTHER_CHARACTERS_CASES(retval) + default: + smart_str_appendc(&retval, ZSTR_VAL(str)[i]); + break; + } + } + + return smart_str_extract(&retval); +} + +ZEND_ATTRIBUTE_NONNULL zend_string *php_uri_parser_rfc3986_percent_decode_reserved_characters(const zend_string *str) +{ + smart_str retval = {0}; + + // gen-delims ":" / "/" / "?" / "#" / "[" / "]" / "@" + // sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + // / "*" / "+" / "," / ";" / "=" + + for (int i = 0; i < ZSTR_LEN(str); i++) { + switch (ZSTR_VAL(str)[i]) { + case '%': + if (i + 2 >= ZSTR_LEN(str)) { + return NULL; + } + + switch (ZSTR_VAL(str)[i + 1]) { + case '2': + switch (ZSTR_VAL(str)[i + 2]) { + case 'F': + smart_str_appendc(&retval, '/'); + i+= 2; + break; + case '3': + smart_str_appendc(&retval, '#'); + i+= 2; + break; + case '1': + smart_str_appendc(&retval, '!'); + i+= 2; + break; + case '4': + smart_str_appendc(&retval, '$'); + i+= 2; + break; + case '6': + smart_str_appendc(&retval, '&'); + i+= 2; + break; + case '7': + smart_str_appendc(&retval, '\''); + i+= 2; + break; + case '8': + smart_str_appendc(&retval, '('); + i+= 2; + break; + case '9': + smart_str_appendc(&retval, ')'); + i+= 2; + break; + case 'A': + smart_str_appendc(&retval, '*'); + i+= 2; + break; + case 'B': + smart_str_appendc(&retval, '+'); + i+= 2; + break; + case 'C': + smart_str_appendc(&retval, ','); + i+= 2; + break; + default: + smart_str_appendc(&retval, ZSTR_VAL(str)[i + 2]); + i+= 2; + break; + } + break; + case '3': + switch (ZSTR_VAL(str)[i + 2]) { + case 'A': + smart_str_appendc(&retval, ':'); + i+= 2; + break; + case 'F': + smart_str_appendc(&retval, '?'); + i+= 2; + break; + case 'B': + smart_str_appendc(&retval, ';'); + i+= 2; + break; + case 'D': + smart_str_appendc(&retval, '='); + i+= 2; + break; + default: + smart_str_appendc(&retval, ZSTR_VAL(str)[i + 2]); + i+= 2; + break; + } + break; + case '4': + switch (ZSTR_VAL(str)[i + 2]) { + case '0': + smart_str_appendc(&retval, '@'); + i+= 2; + break; + default: + smart_str_appendc(&retval, ZSTR_VAL(str)[i + 2]); + i+= 2; + break; + } + break; + case '5': + switch (ZSTR_VAL(str)[i + 2]) { + case 'B': + smart_str_appendc(&retval, '['); + i+= 2; + break; + case 'D': + smart_str_appendc(&retval, ']'); + i+= 2; + break; + default: + smart_str_appendc(&retval, ZSTR_VAL(str)[i + 2]); + i+= 2; + break; + } + break; + default: + i+= 1; + smart_str_appendc(&retval, ZSTR_VAL(str)[i + 1]); + break; + } + break; + default: + smart_str_appendc(&retval, ZSTR_VAL(str)[i]); + break; + } + } + + return smart_str_extract(&retval); +} + +ZEND_ATTRIBUTE_NONNULL zend_string *php_uri_parser_rfc3986_percent_encode_user_info(const zend_string *str) +{ + /* userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) */ + smart_str retval = {0}; + + for (int i = 0; i < ZSTR_LEN(str); i++) { + switch (ZSTR_VAL(str)[i]) { + /* PERCENT_ENCODE_COLON_CASE(retval) */ + PERCENT_ENCODE_SLASH_CASE(retval) + PERCENT_ENCODE_QUESTION_MARK_CASE(retval) + PERCENT_ENCODE_AT_CASE(retval) + PERCENT_ENCODE_REST_OF_GEN_DELIMS_CASES(retval) + PERCENT_ENCODE_PERCENT_CASE(retval) + PERCENT_ENCODE_OTHER_CHARACTERS_CASES(retval) + default: + smart_str_appendc(&retval, ZSTR_VAL(str)[i]); + break; + } + } + + return smart_str_extract(&retval); +} + +ZEND_ATTRIBUTE_NONNULL zend_string *php_uri_parser_rfc3986_percent_encode_host(const zend_string *str) +{ + /* host = IP-literal / IPv4address / reg-name + * IP-literal = "[" ( IPv6address / IPvFuture ) "]" + * IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) + * IPv6address = 6( h16 ":" ) ls32 + * / "::" 5( h16 ":" ) ls32 + * / [ h16 ] "::" 4( h16 ":" ) ls32 + * / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32 + * / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32 + * / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32 + * / [ *4( h16 ":" ) h16 ] "::" ls32 + * / [ *5( h16 ":" ) h16 ] "::" h16 + * / [ *6( h16 ":" ) h16 ] "::" + * h16 = 1*4HEXDIG + * ls32 = ( h16 ":" h16 ) / IPv4address + * IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet + * dec-octet = DIGIT ; 0-9 + * / %x31-39 DIGIT ; 10-99 + * / "1" 2DIGIT ; 100-199 + * / "2" %x30-34 DIGIT ; 200-249 + * / "25" %x30-35 ; 250-255 + * reg-name = *( unreserved / pct-encoded / sub-delims ) + */ + smart_str retval = {0}; + + /* Is IP-literal */ + if (ZSTR_LEN(str) > 0 && ZSTR_VAL(str)[0] == '[') { + smart_str_append(&retval, str); + } else { /* reg-name or IPv4address -> only reg-name supports percent-encoding */ + for (int i = 0; i < ZSTR_LEN(str); i++) { + switch (ZSTR_VAL(str)[i]) { + PERCENT_ENCODE_GEN_DELIMS_CASES(retval) + PERCENT_ENCODE_PERCENT_CASE(retval) + PERCENT_ENCODE_OTHER_CHARACTERS_CASES(retval) + default: + smart_str_appendc(&retval, ZSTR_VAL(str)[i]); + break; + } + } + } + + return smart_str_extract(&retval); +} + +ZEND_ATTRIBUTE_NONNULL zend_string *php_uri_parser_rfc3986_percent_encode_path(const zend_string *str) +{ + /* path-abempty = *( "/" segment ) + * path-absolute = "/" [ segment-nz *( "/" segment ) ] + * path-rootless = segment-nz *( "/" segment ) + * path-empty = 0 + * segment = *pchar + * segment-nz = 1*pchar + * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + */ + smart_str retval = {0}; + + for (int i = 0; i < ZSTR_LEN(str); i++) { + switch (ZSTR_VAL(str)[i]) { + /* PERCENT_ENCODE_COLON_CASE(retval) */ + /* PERCENT_ENCODE_SLASH_CASE(retval) */ + PERCENT_ENCODE_QUESTION_MARK_CASE(retval) + /* PERCENT_ENCODE_AT_CASE(retval) */ + PERCENT_ENCODE_REST_OF_GEN_DELIMS_CASES(retval) + PERCENT_ENCODE_PERCENT_CASE(retval) + PERCENT_ENCODE_OTHER_CHARACTERS_CASES(retval) + default: + smart_str_appendc(&retval, ZSTR_VAL(str)[i]); + break; + } + } + + return smart_str_extract(&retval); +} + +ZEND_ATTRIBUTE_NONNULL zend_string *php_uri_parser_rfc3986_percent_encode_path_segment(const zend_string *str) +{ + /* segment = *pchar + * segment-nz = 1*pchar + * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + */ + smart_str retval = {0}; + + for (int i = 0; i < ZSTR_LEN(str); i++) { + switch (ZSTR_VAL(str)[i]) { + /* PERCENT_ENCODE_COLON_CASE(retval) */ + PERCENT_ENCODE_SLASH_CASE(retval) + PERCENT_ENCODE_QUESTION_MARK_CASE(retval) + /* PERCENT_ENCODE_AT_CASE(retval) */ + PERCENT_ENCODE_REST_OF_GEN_DELIMS_CASES(retval) + PERCENT_ENCODE_PERCENT_CASE(retval) + PERCENT_ENCODE_OTHER_CHARACTERS_CASES(retval) + default: + smart_str_appendc(&retval, ZSTR_VAL(str)[i]); + break; + } + } + + return smart_str_extract(&retval); +} + +ZEND_ATTRIBUTE_NONNULL zend_string *php_uri_parser_rfc3986_percent_encode_relative_reference_path(const zend_string *str) +{ + /* path-noscheme = segment-nz-nc *( "/" segment ) + * segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" ) + * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + */ + smart_str retval = {0}; + bool first_segment = true; + + for (int i = 0; i < ZSTR_LEN(str); i++) { + switch (ZSTR_VAL(str)[i]) { + case '/': + first_segment = false; + break; + case ':': + if (first_segment) { + smart_str_appends(&retval, "%3A"); + } else { + smart_str_appendc(&retval, ZSTR_VAL(str)[i]); + } + break; + /* PERCENT_ENCODE_SLASH_CASE(retval) */ + PERCENT_ENCODE_QUESTION_MARK_CASE(retval) + /* PERCENT_ENCODE_AT_CASE(retval) */ + PERCENT_ENCODE_REST_OF_GEN_DELIMS_CASES(retval) + PERCENT_ENCODE_PERCENT_CASE(retval) + PERCENT_ENCODE_OTHER_CHARACTERS_CASES(retval) + default: + smart_str_appendc(&retval, ZSTR_VAL(str)[i]); + break; + } + } + + return smart_str_extract(&retval); +} + +ZEND_ATTRIBUTE_NONNULL zend_string *php_uri_parser_rfc3986_percent_encode_relative_reference_first_path_segment(const zend_string *str) +{ + /* segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" ) */ + smart_str retval = {0}; + + for (int i = 0; i < ZSTR_LEN(str); i++) { + switch (ZSTR_VAL(str)[i]) { + PERCENT_ENCODE_COLON_CASE(retval) + PERCENT_ENCODE_SLASH_CASE(retval) + PERCENT_ENCODE_QUESTION_MARK_CASE(retval) + /* PERCENT_ENCODE_AT_CASE(retval) */ + PERCENT_ENCODE_REST_OF_GEN_DELIMS_CASES(retval) + PERCENT_ENCODE_PERCENT_CASE(retval) + PERCENT_ENCODE_OTHER_CHARACTERS_CASES(retval) + default: + smart_str_appendc(&retval, ZSTR_VAL(str)[i]); + break; + } + } + + return smart_str_extract(&retval); +} + +ZEND_ATTRIBUTE_NONNULL zend_string *php_uri_parser_rfc3986_percent_encode_query_or_fragment(const zend_string *str) +{ + /* query = *( pchar / "/" / "?" ) */ + /* fragment = *( pchar / "/" / "?" ) */ + /* pchar = unreserved / pct-encoded / sub-delims / ":" / "@" */ + smart_str retval = {0}; + + for (int i = 0; i < ZSTR_LEN(str); i++) { + switch (ZSTR_VAL(str)[i]) { + /* PERCENT_ENCODE_COLON_CASE(retval) */ + /* PERCENT_ENCODE_SLASH_CASE(retval) */ + /* PERCENT_ENCODE_QUESTION_MARK_CASE(retval) */ + /* PERCENT_ENCODE_AT_CASE(retval) */ + PERCENT_ENCODE_REST_OF_GEN_DELIMS_CASES(retval) + PERCENT_ENCODE_PERCENT_CASE(retval) + PERCENT_ENCODE_OTHER_CHARACTERS_CASES(retval) + default: + smart_str_appendc(&retval, ZSTR_VAL(str)[i]); + break; + } + } + + return smart_str_extract(&retval); +} + +ZEND_ATTRIBUTE_NONNULL zend_string *php_uri_parser_rfc3986_percent_encode_form_query(const zend_string *str) +{ + /* query = *( pchar / "/" / "?" ) */ + /* pchar = unreserved / pct-encoded / sub-delims / ":" / "@" */ + smart_str retval = {0}; + + for (int i = 0; i < ZSTR_LEN(str); i++) { + switch (ZSTR_VAL(str)[i]) { + /* PERCENT_ENCODE_COLON_CASE(retval) */ + /* PERCENT_ENCODE_SLASH_CASE(retval) */ + /* PERCENT_ENCODE_QUESTION_MARK_CASE(retval) */ + /* PERCENT_ENCODE_AT_CASE(retval) */ + PERCENT_ENCODE_REST_OF_GEN_DELIMS_CASES(retval) + PERCENT_ENCODE_PERCENT_AS_PLUS_CASE(retval) + PERCENT_ENCODE_OTHER_CHARACTERS_CASES(retval) + default: + smart_str_appendc(&retval, ZSTR_VAL(str)[i]); + break; + } + } + + return smart_str_extract(&retval); +} + +ZEND_ATTRIBUTE_NONNULL zend_string *php_uri_parser_rfc3986_percent_decode(const zend_string *str) +{ + smart_str retval = {0}; + + smart_str_append(&retval, str); + + return smart_str_extract(&retval); +} + static inline size_t get_text_range_length(const UriTextRangeA *range) { return range->afterLast - range->first; @@ -246,6 +782,26 @@ ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_host_read(void return SUCCESS; } +ZEND_ATTRIBUTE_NONNULL void php_uri_parser_rfc3986_host_type_read(void *uri, php_uri_component_read_mode read_mode, zval *retval) +{ + const UriUriA *uriparser_uri = get_uri_for_reading(uri, read_mode); + + if (!has_text_range(&uriparser_uri->hostText)) { + ZVAL_NULL(retval); + return; + } + + if (uriparser_uri->hostData.ip4 != NULL) { + ZVAL_OBJ_COPY(retval, zend_enum_get_case_cstr(php_uri_ce_rfc3986_uri_host_type, "IPv4")); + } else if (uriparser_uri->hostData.ip6 != NULL) { + ZVAL_OBJ_COPY(retval, zend_enum_get_case_cstr(php_uri_ce_rfc3986_uri_host_type, "IPv6")); + } else if (has_text_range(&uriparser_uri->hostData.ipFuture)) { + ZVAL_OBJ_COPY(retval, zend_enum_get_case_cstr(php_uri_ce_rfc3986_uri_host_type, "IPvFuture")); + } else { + ZVAL_OBJ_COPY(retval, zend_enum_get_case_cstr(php_uri_ce_rfc3986_uri_host_type, "RegisteredName")); + } +} + static zend_result php_uri_parser_rfc3986_host_write(void *uri, zval *value, zval *errors) { UriUriA *uriparser_uri = get_uri_for_writing(uri); @@ -364,6 +920,27 @@ ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_path_read(void return SUCCESS; } +zend_result php_uri_parser_rfc3986_path_segments_read(void *uri, php_uri_component_read_mode read_mode, zval *retval) +{ + const UriUriA *uriparser_uri = get_uri_for_reading(uri, read_mode); + + if (uriparser_uri->pathHead != NULL) { + array_init(retval); + zval tmp; + + for (const UriPathSegmentA *p = uriparser_uri->pathHead; p; p = p->next) { + ZVAL_STRINGL(&tmp,p->text.first, get_text_range_length(&p->text)); + zend_hash_next_index_insert_new(Z_ARRVAL_P(retval), &tmp); + } + } else if (uriparser_uri->absolutePath) { + ZVAL_EMPTY_ARRAY(retval); + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + static zend_result php_uri_parser_rfc3986_path_write(void *uri, zval *value, zval *errors) { UriUriA *uriparser_uri = get_uri_for_writing(uri); @@ -401,6 +978,29 @@ ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_query_read(void return SUCCESS; } +ZEND_ATTRIBUTE_NONNULL zend_result php_uri_parser_rfc3986_query_params_read(void *uri, php_uri_component_read_mode read_mode, zval *retval) +{ + const UriUriA *uriparser_uri = get_uri_for_reading(uri, read_mode); + + if (has_text_range(&uriparser_uri->query)) { + object_init_ex(retval, php_uri_ce_rfc3986_uri_query_params); + php_uri_parser_rfc3986_uri_query_params_object *uri_query_params_object = Z_URI_QUERY_PARAMS_OBJECT_P(retval); + + if (php_uri_rfc3986_uri_query_params_from_str(uriparser_uri->query.first, get_text_range_length(&uriparser_uri->query), + &uri_query_params_object->query_list, PHP_URI_RECOMPOSITION_MODE_RAW_ASCII ? false : true, false + ) == FAILURE) { + php_uri_rfc3986_uri_query_params_free(Z_URI_QUERY_PARAMS_OBJECT_P(retval)); + return FAILURE; + } + + uri_query_params_object->is_initialized = true; + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + static zend_result php_uri_parser_rfc3986_query_write(void *uri, zval *value, zval *errors) { UriUriA *uriparser_uri = get_uri_for_writing(uri); @@ -425,6 +1025,36 @@ static zend_result php_uri_parser_rfc3986_query_write(void *uri, zval *value, zv } } +ZEND_ATTRIBUTE_NONNULL zend_result php_uri_parser_rfc3986_query_params_write(void *uri, zval *value) +{ + UriUriA *uriparser_uri = get_uri_for_writing(uri); + int result; + + if (Z_TYPE_P(value) == IS_NULL) { + result = uriSetQueryMmA(uriparser_uri, NULL, NULL, mm); + } else { + ZEND_ASSERT(Z_TYPE_P(value) == IS_OBJECT && instanceof_function(Z_OBJCE_P(value), php_uri_ce_rfc3986_uri_query_params)); + php_uri_parser_rfc3986_uri_query_params_object *uri_query_params_object = Z_URI_QUERY_PARAMS_OBJECT_P(value); + zend_string *query_string = php_uri_rfc3986_uri_query_params_to_string(uri_query_params_object->query_list, false); + + result = uriSetQueryMmA(uriparser_uri, ZSTR_VAL(query_string), ZSTR_VAL(query_string) + ZSTR_LEN(query_string), mm); + + zend_string_release(query_string); + } + + switch (result) { + case URI_SUCCESS: + return SUCCESS; + case URI_ERROR_SYNTAX: + zend_throw_exception(php_uri_ce_invalid_uri_exception, "The specified query is malformed", 0); + return FAILURE; + default: + /* This should be unreachable in practice. */ + zend_throw_exception(php_uri_ce_error, "Failed to update the query", 0); + return FAILURE; + } +} + ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_fragment_read(void *uri, php_uri_component_read_mode read_mode, zval *retval) { const UriUriA *uriparser_uri = get_uri_for_reading(uri, read_mode); @@ -607,6 +1237,150 @@ static void php_uri_parser_rfc3986_destroy(void *uri) efree(uriparser_uris); } +ZEND_ATTRIBUTE_NONNULL PHPAPI void php_uri_rfc3986_uri_query_params_free(php_uri_parser_rfc3986_uri_query_params_object *uri_query_params_object) +{ + if (uri_query_params_object->query_list != NULL) { + uriFreeQueryListMmA(uri_query_params_object->query_list, mm); + uri_query_params_object->query_list = NULL; + uri_query_params_object->is_initialized = false; + } +} + +ZEND_ATTRIBUTE_NONNULL PHPAPI void php_uri_rfc3986_uri_query_params_object_handler_free(zend_object *object) +{ + php_uri_parser_rfc3986_uri_query_params_object *uri_query_params_object = php_uri_rfc3986_uri_query_params_object_from_obj(object); + + php_uri_rfc3986_uri_query_params_free(uri_query_params_object); + + zend_object_std_dtor(&uri_query_params_object->std); +} + +ZEND_ATTRIBUTE_NONNULL PHPAPI zend_object *php_uri_rfc3986_uri_query_params_object_handler_clone(zend_object *object) +{ + php_uri_parser_rfc3986_uri_query_params_object *uri_query_params_object = php_uri_rfc3986_uri_query_params_object_from_obj(object); + + php_uri_parser_rfc3986_uri_query_params_object *new_uri_query_params_object = php_uri_rfc3986_uri_query_params_object_from_obj( + object->ce->create_object(object->ce) + ); + + new_uri_query_params_object->query_list = uri_query_params_object->query_list; // TODO Fix + + zend_objects_clone_members(&new_uri_query_params_object->std, &uri_query_params_object->std); + + return &new_uri_query_params_object->std; +} + +ZEND_ATTRIBUTE_NONNULL zend_result php_uri_rfc3986_uri_query_params_from_str(const char *query_str_first, + size_t query_str_length, UriQueryListA **query_list, bool normalize, bool silent +) { + int item_count; + + if (uriDissectQueryMallocExMmA( + query_list, &item_count, query_str_first, query_str_first + query_str_length, + URI_TRUE, URI_BR_DONT_TOUCH, normalize, mm + ) != URI_SUCCESS) { + if (!silent) { + zend_throw_exception(php_uri_ce_exception, "Failed to parse the specified query string", 0); + } + + return FAILURE; + } + + return SUCCESS; +} + +static UriQueryListA *php_uri_rfc3986_uri_query_params_search_last_item(UriQueryListA *query_list) +{ + if (query_list == NULL) { + return NULL; + } + + UriQueryListA *p = query_list; + + while (p->next != NULL) { + p = p->next; + } + + return p; +} + +ZEND_ATTRIBUTE_NONNULL_ARGS(2) UriQueryListA *php_uri_rfc3986_uri_query_params_search_first(UriQueryListA *query_list, + const char *name, size_t name_len, const char *value, size_t value_len +) { + for (UriQueryListA *p = query_list; p != NULL; p = p->next) { + if (zend_binary_strcmp(name, name_len, p->key, strlen(p->key)) != 0) { + continue; + } + + if (EXPECTED(value == NULL)) { + return p; + } + + if (zend_binary_strcmp(value, value_len, p->value, strlen(p->value))) { // TODO check null values + return p; + } + } + + return NULL; +} + +ZEND_ATTRIBUTE_NONNULL zend_result php_uri_rfc3986_uri_query_params_append(UriQueryListA **query_list, + const char *name, size_t name_len, const char *value, size_t value_len +) { + int item_count; + + UriQueryListA *last_item = php_uri_rfc3986_uri_query_params_search_last_item(*query_list); + if (UNEXPECTED(last_item == NULL)) { + // TODO create new list + } + + bool result = uriAppendQueryItemA(&last_item->next, &item_count, + name, name + name_len, value, value + value_len, + URI_TRUE, URI_BR_DONT_TOUCH, URI_FALSE, mm + ); + + return result == URI_TRUE ? SUCCESS : FAILURE; +} + +zend_string *php_uri_rfc3986_uri_query_params_to_string(const UriQueryListA *query_list, bool normalize) +{ + if (query_list == NULL) { + return zend_empty_string; + } + + int chars_required = 0; + if (uriComposeQueryCharsRequiredExA(query_list, &chars_required, true, URI_BR_DONT_TOUCH, normalize) != URI_SUCCESS) { + return NULL; + } + + zend_string *query_string = zend_string_alloc(chars_required, false); + int chars_written; + if (uriComposeQueryExA(ZSTR_VAL(query_string), query_list, chars_required + 1, &chars_written, URI_TRUE, URI_FALSE, normalize) != URI_SUCCESS) { + zend_string_efree(query_string); + return NULL; + } + + if (chars_written == chars_required) { + return query_string; + } + + return zend_string_truncate(query_string, chars_written - 1, false); +} + +ZEND_ATTRIBUTE_NONNULL HashTable *php_uri_rfc3986_uri_query_params_get_debug_properties(php_uri_parser_rfc3986_uri_query_params_object *object) +{ + const HashTable *std_properties = zend_std_get_properties(&object->std); + HashTable *result = zend_array_dup(std_properties); + + for (UriQueryListA *param = object->query_list; param != NULL; param = param->next) { + zval tmp; + ZVAL_STRING(&tmp, param->value); + zend_hash_str_update(result, param->key, strlen(param->key), &tmp); + } + + return result; +} + const php_uri_parser php_uri_parser_rfc3986 = { .name = PHP_URI_PARSER_RFC3986, .parse = php_uri_parser_rfc3986_parse, diff --git a/ext/uri/uri_parser_rfc3986.h b/ext/uri/uri_parser_rfc3986.h index bdf792816c29f..4af0b6e4c133d 100644 --- a/ext/uri/uri_parser_rfc3986.h +++ b/ext/uri/uri_parser_rfc3986.h @@ -28,9 +28,49 @@ typedef struct php_uri_parser_rfc3986_uris { bool normalized_uri_initialized; } php_uri_parser_rfc3986_uris; +typedef struct php_uri_parser_rfc3986_uri_query_params_object { + UriQueryListA *query_list; + bool is_initialized; + zend_object std; +} php_uri_parser_rfc3986_uri_query_params_object; + +#define Z_URI_QUERY_PARAMS_OBJECT_P(zv) php_uri_rfc3986_uri_query_params_object_from_obj(Z_OBJ_P((zv))) + +static inline php_uri_parser_rfc3986_uri_query_params_object *php_uri_rfc3986_uri_query_params_object_from_obj(zend_object *object) { + return (php_uri_parser_rfc3986_uri_query_params_object*)((char*)(object) - XtOffsetOf(php_uri_parser_rfc3986_uri_query_params_object, std)); +} + +ZEND_ATTRIBUTE_NONNULL zend_string *php_uri_parser_rfc3986_percent_encode_user_info(const zend_string *str); +ZEND_ATTRIBUTE_NONNULL zend_string *php_uri_parser_rfc3986_percent_encode_host(const zend_string *str); +ZEND_ATTRIBUTE_NONNULL zend_string *php_uri_parser_rfc3986_percent_encode_path(const zend_string *str); +ZEND_ATTRIBUTE_NONNULL zend_string *php_uri_parser_rfc3986_percent_encode_path_segment(const zend_string *str); +ZEND_ATTRIBUTE_NONNULL zend_string *php_uri_parser_rfc3986_percent_encode_relative_reference_path(const zend_string *str); +ZEND_ATTRIBUTE_NONNULL zend_string *php_uri_parser_rfc3986_percent_encode_relative_reference_first_path_segment(const zend_string *str); +ZEND_ATTRIBUTE_NONNULL zend_string *php_uri_parser_rfc3986_percent_encode_query_or_fragment(const zend_string *str); +ZEND_ATTRIBUTE_NONNULL zend_string *php_uri_parser_rfc3986_percent_encode_reserved_characters(const zend_string *str); +ZEND_ATTRIBUTE_NONNULL zend_string *php_uri_parser_rfc3986_percent_encode_all(const zend_string *str); + +ZEND_ATTRIBUTE_NONNULL zend_string *php_uri_parser_rfc3986_percent_decode(const zend_string *str); +ZEND_ATTRIBUTE_NONNULL zend_string *php_uri_parser_rfc3986_percent_decode_reserved_characters(const zend_string *str); + zend_result php_uri_parser_rfc3986_userinfo_read(void *uri, php_uri_component_read_mode read_mode, zval *retval); zend_result php_uri_parser_rfc3986_userinfo_write(void *uri, zval *value, zval *errors); +void php_uri_parser_rfc3986_host_type_read(void *uri, php_uri_component_read_mode read_mode, zval *retval); +zend_result php_uri_parser_rfc3986_path_segments_read(void *uri, php_uri_component_read_mode read_mode, zval *retval); +zend_result php_uri_parser_rfc3986_path_query_params_read(void *uri, php_uri_component_read_mode read_mode, zval *retval); +ZEND_ATTRIBUTE_NONNULL zend_result php_uri_parser_rfc3986_query_params_read(void *uri, php_uri_component_read_mode read_mode, zval *retval); +ZEND_ATTRIBUTE_NONNULL zend_result php_uri_parser_rfc3986_query_params_write(void *uri, zval *value); php_uri_parser_rfc3986_uris *php_uri_parser_rfc3986_parse_ex(const char *uri_str, size_t uri_str_len, const php_uri_parser_rfc3986_uris *uriparser_base_url, bool silent); +PHPAPI void php_uri_rfc3986_uri_query_params_free(php_uri_parser_rfc3986_uri_query_params_object *uri_query_params_object); +PHPAPI void php_uri_rfc3986_uri_query_params_object_handler_free(zend_object *object); +zend_object *php_uri_rfc3986_uri_query_params_object_handler_clone(zend_object *object); +zend_result php_uri_rfc3986_uri_query_params_from_str(const char *query_str_first, size_t query_str_length, UriQueryListA **query_list, bool normalize, bool silent); +ZEND_ATTRIBUTE_NONNULL zend_result php_uri_rfc3986_uri_query_params_append(UriQueryListA **query_list, + const char *name, size_t name_len, const char *value, size_t value_len +); +zend_string *php_uri_rfc3986_uri_query_params_to_string(const UriQueryListA *query_list, bool normalize); +HashTable *php_uri_rfc3986_uri_query_params_get_debug_properties(php_uri_parser_rfc3986_uri_query_params_object *object); + #endif diff --git a/ext/uri/uri_parser_whatwg.c b/ext/uri/uri_parser_whatwg.c index fab228a2d70cf..ee1a308f457fd 100644 --- a/ext/uri/uri_parser_whatwg.c +++ b/ext/uri/uri_parser_whatwg.c @@ -274,6 +274,11 @@ static zend_result php_uri_parser_whatwg_scheme_write(void *uri, zval *value, zv return SUCCESS; } +ZEND_ATTRIBUTE_NONNULL bool php_uri_parser_whatwg_is_special(lxb_url_t *lexbor_uri) +{ + return lxb_url_is_special(lexbor_uri); +} + static zend_result php_uri_parser_whatwg_username_read(void *uri, php_uri_component_read_mode read_mode, zval *retval) { const lxb_url_t *lexbor_uri = uri; @@ -376,6 +381,33 @@ static zend_result php_uri_parser_whatwg_host_read(void *uri, php_uri_component_ return SUCCESS; } +ZEND_ATTRIBUTE_NONNULL void php_uri_parser_whatwg_host_type_read(void *uri, php_uri_component_read_mode read_mode, zval *retval) +{ + const lxb_url_t *lexbor_uri = uri; + + switch (lexbor_uri->host.type) { + case LXB_URL_HOST_TYPE_IPV4: + ZVAL_OBJ_COPY(retval, zend_enum_get_case_cstr(php_uri_ce_whatwg_url_host_type, "IPv4")); + return; + case LXB_URL_HOST_TYPE_IPV6: + ZVAL_OBJ_COPY(retval, zend_enum_get_case_cstr(php_uri_ce_whatwg_url_host_type, "IPv6")); + return; + case LXB_URL_HOST_TYPE_DOMAIN: + ZVAL_OBJ_COPY(retval, zend_enum_get_case_cstr(php_uri_ce_whatwg_url_host_type, "Domain")); + return; + case LXB_URL_HOST_TYPE_EMPTY: + ZVAL_OBJ_COPY(retval, zend_enum_get_case_cstr(php_uri_ce_whatwg_url_host_type, "Empty")); + return; + case LXB_URL_HOST_TYPE_OPAQUE: + ZVAL_OBJ_COPY(retval, zend_enum_get_case_cstr(php_uri_ce_whatwg_url_host_type, "Opaque")); + return; + case LXB_URL_HOST_TYPE__UNDEF: + ZVAL_NULL(retval); + return; + EMPTY_SWITCH_DEFAULT_CASE() + } +} + static zend_result php_uri_parser_whatwg_host_write(void *uri, zval *value, zval *errors) { lxb_url_t *lexbor_uri = uri; @@ -434,6 +466,19 @@ static zend_result php_uri_parser_whatwg_path_read(void *uri, php_uri_component_ return SUCCESS; } +ZEND_ATTRIBUTE_NONNULL zend_result php_uri_parser_whatwg_path_segments_read(void *uri, php_uri_component_read_mode read_mode, zval *retval) +{ + const lxb_url_t *lexbor_uri = uri; + + if (lexbor_uri->path.str.length) { + ZVAL_EMPTY_ARRAY(retval); + } else { + ZVAL_EMPTY_ARRAY(retval); + } + + return SUCCESS; +} + static zend_result php_uri_parser_whatwg_path_write(void *uri, zval *value, zval *errors) { lxb_url_t *lexbor_uri = uri; @@ -463,6 +508,34 @@ static zend_result php_uri_parser_whatwg_query_read(void *uri, php_uri_component return SUCCESS; } +ZEND_ATTRIBUTE_NONNULL zend_result php_uri_parser_whatwg_query_params_read(void *uri, php_uri_component_read_mode read_mode, zval *retval) +{ + const lxb_url_t *lexbor_uri = uri; + + if (lexbor_uri->query.data != NULL) { + lxb_url_search_params_t *query_params = php_uri_whatwg_url_query_params_from_str( + (const char *) lexbor_uri->query.data, + lexbor_uri->query.length, + false + ); + + if (query_params == NULL) { + lxb_url_search_params_destroy(query_params); + return FAILURE; + } + + object_init_ex(retval, php_uri_ce_whatwg_url_query_params); + php_uri_parser_whatwg_url_query_params_object *url_query_params_object = Z_URL_QUERY_PARAMS_OBJECT_P(retval); + + url_query_params_object->query_params = query_params; + url_query_params_object->is_initialized = true; + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + static zend_result php_uri_parser_whatwg_query_write(void *uri, zval *value, zval *errors) { lxb_url_t *lexbor_uri = uri; @@ -479,6 +552,31 @@ static zend_result php_uri_parser_whatwg_query_write(void *uri, zval *value, zva return SUCCESS; } +ZEND_ATTRIBUTE_NONNULL zend_result php_uri_parser_whatwg_query_params_write(void *uri, zval *value, zval *errors) +{ + lxb_url_t *lexbor_uri = uri; + lexbor_str_t str = {0}; + + if (Z_TYPE_P(value) == IS_NULL) { + zval_string_or_null_to_lexbor_str(value, &str); + } else { + ZEND_ASSERT(Z_TYPE_P(value) == IS_OBJECT && instanceof_function(Z_OBJCE_P(value), php_uri_ce_whatwg_url_query_params)); + php_uri_parser_whatwg_url_query_params_object *url_query_params_object = Z_URL_QUERY_PARAMS_OBJECT_P(value); + zend_string *query_string = php_uri_whatwg_url_query_params_to_string(url_query_params_object->query_params); + + str.data = (lxb_char_t *) ZSTR_VAL(query_string); + str.length = ZSTR_LEN(query_string); + } + + if (lxb_url_api_search_set(lexbor_uri, &lexbor_parser, str.data, str.length) != LXB_STATUS_OK) { + throw_invalid_url_exception_during_write(errors, "query string"); + + return FAILURE; + } + + return SUCCESS; +} + static zend_result php_uri_parser_whatwg_fragment_read(void *uri, php_uri_component_read_mode read_mode, zval *retval) { const lxb_url_t *lexbor_uri = uri; @@ -621,6 +719,96 @@ static void php_uri_parser_whatwg_destroy(void *uri) lxb_url_destroy(lexbor_uri); } +PHPAPI ZEND_ATTRIBUTE_NONNULL void php_uri_whatwg_url_query_params_free(php_uri_parser_whatwg_url_query_params_object *url_query_params_object) +{ + if (url_query_params_object->query_params != NULL) { + lxb_url_search_params_destroy(url_query_params_object->query_params); + url_query_params_object->query_params = NULL; + url_query_params_object->is_initialized = false; + } +} + +PHPAPI ZEND_ATTRIBUTE_NONNULL void php_uri_whatwg_url_query_params_object_handler_free(zend_object *object) +{ + php_uri_parser_whatwg_url_query_params_object *url_query_params_object = php_uri_whatwg_url_query_params_object_from_obj(object); + + php_uri_whatwg_url_query_params_free(url_query_params_object); + + zend_object_std_dtor(&url_query_params_object->std); +} + +PHPAPI ZEND_ATTRIBUTE_NONNULL zend_object *php_uri_whatwg_url_query_params_object_handler_clone(zend_object *object) +{ + php_uri_parser_whatwg_url_query_params_object *url_query_params_object = php_uri_whatwg_url_query_params_object_from_obj(object); + + php_uri_parser_whatwg_url_query_params_object *new_url_query_params_object = php_uri_whatwg_url_query_params_object_from_obj( + object->ce->create_object(object->ce) + ); + + new_url_query_params_object->query_params = url_query_params_object->query_params; // TODO Fix + + zend_objects_clone_members(&new_url_query_params_object->std, &url_query_params_object->std); + + return &new_url_query_params_object->std; +} + +ZEND_ATTRIBUTE_NONNULL lxb_url_search_params_t *php_uri_whatwg_url_query_params_from_str(const char *query_str, size_t query_str_len, bool silent) +{ + lxb_url_search_params_t *query_params = lxb_url_search_params_init(&lexbor_mraw, (const lxb_char_t *) query_str, query_str_len); + + if (query_params == NULL) { + if (!silent) { + zend_throw_exception(php_uri_ce_exception, "Failed to parse the specified query string", 0); + } + } + + return query_params; +} + +ZEND_ATTRIBUTE_NONNULL zend_result php_uri_whatwg_url_query_params_append(lxb_url_search_params_t *query_params, + const char *name, size_t name_len, const char *value, size_t value_len +) { + lxb_url_search_entry_t * entry = lxb_url_search_params_append(query_params, (lxb_char_t *) name, name_len, + (lxb_char_t *) value, value_len); + + return entry == NULL ? FAILURE : SUCCESS; +} + +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 2) void php_uri_whatwg_url_query_params_delete(lxb_url_search_params_t *query_params, + const char *name, size_t name_len, const char *value, size_t value_len +) { + lxb_url_search_params_delete(query_params, (lxb_char_t *) name, name_len, (lxb_char_t *) value, value_len); +} + +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 2) bool php_uri_whatwg_url_query_params_exists(lxb_url_search_params_t *query_params, + const char *name, size_t name_len, const char *value, size_t value_len +) { + return lxb_url_search_params_has(query_params, (lxb_char_t *) name, name_len, (lxb_char_t *) value, value_len); +} + +ZEND_ATTRIBUTE_NONNULL zend_string *php_uri_whatwg_url_query_params_to_string(lxb_url_search_params_t *query_params) +{ + smart_str query_str = {0}; + + lxb_url_search_params_serialize(query_params, serialize_to_smart_str_callback, &query_str); + + return smart_str_extract(&query_str); +} + +HashTable *php_uri_whatwg_url_query_params_get_debug_properties(php_uri_parser_whatwg_url_query_params_object *object) +{ + const HashTable *std_properties = zend_std_get_properties(&object->std); + HashTable *result = zend_array_dup(std_properties); + + for (lxb_url_search_entry_t *param = object->query_params->first; param != NULL; param = param->next) { + zval tmp; + ZVAL_STRINGL(&tmp, (const char *) param->value.data, param->value.length); + zend_hash_str_update(result, (const char *) param->name.data, param->name.length, &tmp); + } + + return result; +} + const php_uri_parser php_uri_parser_whatwg = { .name = PHP_URI_PARSER_WHATWG, .parse = php_uri_parser_whatwg_parse, diff --git a/ext/uri/uri_parser_whatwg.h b/ext/uri/uri_parser_whatwg.h index 71d6ee3903bfa..e28a6b777c33e 100644 --- a/ext/uri/uri_parser_whatwg.h +++ b/ext/uri/uri_parser_whatwg.h @@ -22,8 +22,41 @@ extern const php_uri_parser php_uri_parser_whatwg; +typedef struct php_uri_parser_whatwg_url_query_params_object { + lxb_url_search_params_t *query_params; + bool is_initialized; + zend_object std; +} php_uri_parser_whatwg_url_query_params_object; + +#define Z_URL_QUERY_PARAMS_OBJECT_P(zv) php_uri_whatwg_url_query_params_object_from_obj(Z_OBJ_P((zv))) + +static inline php_uri_parser_whatwg_url_query_params_object *php_uri_whatwg_url_query_params_object_from_obj(zend_object *object) { + return (php_uri_parser_whatwg_url_query_params_object*)((char*)(object) - XtOffsetOf(php_uri_parser_whatwg_url_query_params_object, std)); +} +ZEND_ATTRIBUTE_NONNULL bool php_uri_parser_whatwg_is_special(lxb_url_t *lexbor_uri); +ZEND_ATTRIBUTE_NONNULL void php_uri_parser_whatwg_host_type_read(void *uri, php_uri_component_read_mode read_mode, zval *retval); +ZEND_ATTRIBUTE_NONNULL zend_result php_uri_parser_whatwg_path_segments_read(void *uri, php_uri_component_read_mode read_mode, zval *retval); +ZEND_ATTRIBUTE_NONNULL zend_result php_uri_parser_whatwg_query_params_read(void *uri, php_uri_component_read_mode read_mode, zval *retval); +ZEND_ATTRIBUTE_NONNULL zend_result php_uri_parser_whatwg_query_params_write(void *uri, zval *value, zval *errors); + lxb_url_t *php_uri_parser_whatwg_parse_ex(const char *uri_str, size_t uri_str_len, const lxb_url_t *lexbor_base_url, zval *errors, bool silent); +PHPAPI ZEND_ATTRIBUTE_NONNULL void php_uri_whatwg_url_query_params_free(php_uri_parser_whatwg_url_query_params_object *url_query_params_object); +PHPAPI ZEND_ATTRIBUTE_NONNULL void php_uri_whatwg_url_query_params_object_handler_free(zend_object *object); +ZEND_ATTRIBUTE_NONNULL zend_object *php_uri_whatwg_url_query_params_object_handler_clone(zend_object *object); +ZEND_ATTRIBUTE_NONNULL lxb_url_search_params_t *php_uri_whatwg_url_query_params_from_str(const char *query_str, size_t query_str_len, bool silent); +ZEND_ATTRIBUTE_NONNULL zend_result php_uri_whatwg_url_query_params_append(lxb_url_search_params_t *query_params, + const char *name, size_t name_len, const char *value, size_t value_len +); +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 2) void php_uri_whatwg_url_query_params_delete(lxb_url_search_params_t *query_params, + const char *name, size_t name_len, const char *value, size_t value_len +); +ZEND_ATTRIBUTE_NONNULL_ARGS(1, 2) bool php_uri_whatwg_url_query_params_exists(lxb_url_search_params_t *query_params, + const char *name, size_t name_len, const char *value, size_t value_len +); +zend_string *php_uri_whatwg_url_query_params_to_string(lxb_url_search_params_t *query_list); +HashTable *php_uri_whatwg_url_query_params_get_debug_properties(php_uri_parser_whatwg_url_query_params_object *object); + PHP_RINIT_FUNCTION(uri_parser_whatwg); ZEND_MODULE_POST_ZEND_DEACTIVATE_D(uri_parser_whatwg); diff --git a/ext/uri/uriparser/include/uriparser/Uri.h b/ext/uri/uriparser/include/uriparser/Uri.h index fbdb3d9a3798e..4c0bf23e7ce18 100644 --- a/ext/uri/uriparser/include/uriparser/Uri.h +++ b/ext/uri/uriparser/include/uriparser/Uri.h @@ -444,7 +444,7 @@ URI_PUBLIC int URI_FUNC(FreeUriMembersMm)(URI_TYPE(Uri) * uri, */ URI_PUBLIC URI_CHAR * URI_FUNC(EscapeEx)(const URI_CHAR * inFirst, const URI_CHAR * inAfterLast, URI_CHAR * out, - UriBool spaceToPlus, UriBool normalizeBreaks); + UriBool spaceToPlus, UriBool normalizeBreaks, UriBool normalizePercentEncoding); @@ -476,7 +476,7 @@ URI_PUBLIC URI_CHAR * URI_FUNC(EscapeEx)(const URI_CHAR * inFirst, * @since 0.5.0 */ URI_PUBLIC URI_CHAR * URI_FUNC(Escape)(const URI_CHAR * in, URI_CHAR * out, - UriBool spaceToPlus, UriBool normalizeBreaks); + UriBool spaceToPlus, UriBool normalizeBreaks, UriBool normalizePercentEncoding); @@ -958,7 +958,7 @@ URI_PUBLIC int URI_FUNC(ComposeQueryCharsRequired)( */ URI_PUBLIC int URI_FUNC(ComposeQueryCharsRequiredEx)( const URI_TYPE(QueryList) * queryList, - int * charsRequired, UriBool spaceToPlus, UriBool normalizeBreaks); + int * charsRequired, UriBool spaceToPlus, UriBool normalizeBreaks, UriBool normalizePercentEncoding); @@ -1013,7 +1013,7 @@ URI_PUBLIC int URI_FUNC(ComposeQuery)(URI_CHAR * dest, */ URI_PUBLIC int URI_FUNC(ComposeQueryEx)(URI_CHAR * dest, const URI_TYPE(QueryList) * queryList, int maxChars, int * charsWritten, - UriBool spaceToPlus, UriBool normalizeBreaks); + UriBool spaceToPlus, UriBool normalizeBreaks, UriBool normalizePercentEncoding); @@ -1064,7 +1064,7 @@ URI_PUBLIC int URI_FUNC(ComposeQueryMalloc)(URI_CHAR ** dest, */ URI_PUBLIC int URI_FUNC(ComposeQueryMallocEx)(URI_CHAR ** dest, const URI_TYPE(QueryList) * queryList, - UriBool spaceToPlus, UriBool normalizeBreaks); + UriBool spaceToPlus, UriBool normalizeBreaks, UriBool normalizePercentEncoding); @@ -1090,7 +1090,7 @@ URI_PUBLIC int URI_FUNC(ComposeQueryMallocEx)(URI_CHAR ** dest, */ URI_PUBLIC int URI_FUNC(ComposeQueryMallocExMm)(URI_CHAR ** dest, const URI_TYPE(QueryList) * queryList, - UriBool spaceToPlus, UriBool normalizeBreaks, + UriBool spaceToPlus, UriBool normalizeBreaks, UriBool normalizePercentEncoding, UriMemoryManager * memory); @@ -1138,7 +1138,7 @@ URI_PUBLIC int URI_FUNC(DissectQueryMalloc)(URI_TYPE(QueryList) ** dest, */ URI_PUBLIC int URI_FUNC(DissectQueryMallocEx)(URI_TYPE(QueryList) ** dest, int * itemCount, const URI_CHAR * first, const URI_CHAR * afterLast, - UriBool plusToSpace, UriBreakConversion breakConversion); + UriBool plusToSpace, UriBreakConversion breakConversion, UriBool normalizePercentEncoding); @@ -1163,7 +1163,7 @@ URI_PUBLIC int URI_FUNC(DissectQueryMallocEx)(URI_TYPE(QueryList) ** dest, */ URI_PUBLIC int URI_FUNC(DissectQueryMallocExMm)(URI_TYPE(QueryList) ** dest, int * itemCount, const URI_CHAR * first, const URI_CHAR * afterLast, - UriBool plusToSpace, UriBreakConversion breakConversion, + UriBool plusToSpace, UriBreakConversion breakConversion, UriBool normalizePercentEncoding, UriMemoryManager * memory); @@ -1196,6 +1196,14 @@ URI_PUBLIC int URI_FUNC(FreeQueryListMm)(URI_TYPE(QueryList) * queryList, UriMemoryManager * memory); +/* TODO custom modification */ +UriBool URI_FUNC(AppendQueryItem)(URI_TYPE(QueryList) ** prevNext, + int * itemCount, const URI_CHAR * keyFirst, const URI_CHAR * keyAfter, + const URI_CHAR * valueFirst, const URI_CHAR * valueAfter, + UriBool plusToSpace, UriBreakConversion breakConversion, UriBool normalizePercentEncoding, + UriMemoryManager * memory); + + /** * Makes the %URI hold copies of strings so that it no longer depends diff --git a/ext/uri/uriparser/src/UriEscape.c b/ext/uri/uriparser/src/UriEscape.c index 366955f4adad4..73a3d5b567ed2 100644 --- a/ext/uri/uriparser/src/UriEscape.c +++ b/ext/uri/uriparser/src/UriEscape.c @@ -69,15 +69,15 @@ URI_CHAR * URI_FUNC(Escape)(const URI_CHAR * in, URI_CHAR * out, - UriBool spaceToPlus, UriBool normalizeBreaks) { - return URI_FUNC(EscapeEx)(in, NULL, out, spaceToPlus, normalizeBreaks); + UriBool spaceToPlus, UriBool normalizeBreaks, UriBool normalizePercentEncoding) { + return URI_FUNC(EscapeEx)(in, NULL, out, spaceToPlus, normalizeBreaks, normalizePercentEncoding); } URI_CHAR * URI_FUNC(EscapeEx)(const URI_CHAR * inFirst, const URI_CHAR * inAfterLast, URI_CHAR * out, - UriBool spaceToPlus, UriBool normalizeBreaks) { + UriBool spaceToPlus, UriBool normalizeBreaks, UriBool normalizePercentEncoding) { const URI_CHAR * read = inFirst; URI_CHAR * write = out; UriBool prevWasCr = URI_FALSE; @@ -227,7 +227,7 @@ URI_CHAR * URI_FUNC(EscapeEx)(const URI_CHAR * inFirst, default: /* Percent encode */ - { + if (normalizePercentEncoding) { const unsigned char code = (unsigned char)read[0]; /* Uppercase recommended in (last sentence of) section 2.1 * * of RFC 3986: * @@ -236,6 +236,8 @@ URI_CHAR * URI_FUNC(EscapeEx)(const URI_CHAR * inFirst, write[1] = URI_FUNC(HexToLetterEx)(code >> 4, URI_TRUE); write[2] = URI_FUNC(HexToLetterEx)(code & 0x0f, URI_TRUE); write += 3; + } else { + write[0] = (unsigned char)read[0]; } prevWasCr = URI_FALSE; break; diff --git a/ext/uri/uriparser/src/UriFile.c b/ext/uri/uriparser/src/UriFile.c index 232957d3c8079..de451127816fd 100644 --- a/ext/uri/uriparser/src/UriFile.c +++ b/ext/uri/uriparser/src/UriFile.c @@ -117,7 +117,7 @@ static URI_INLINE int URI_FUNC(FilenameToUriString)(const URI_CHAR * filename, output += charsToCopy; } else { output = URI_FUNC(EscapeEx)(lastSep + 1, input, output, - URI_FALSE, URI_FALSE); + URI_FALSE, URI_FALSE, URI_FALSE); } } firstSegment = URI_FALSE; diff --git a/ext/uri/uriparser/src/UriQuery.c b/ext/uri/uriparser/src/UriQuery.c index bbc15488773c6..79f6a15413144 100644 --- a/ext/uri/uriparser/src/UriQuery.c +++ b/ext/uri/uriparser/src/UriQuery.c @@ -77,12 +77,12 @@ static int URI_FUNC(ComposeQueryEngine)(URI_CHAR * dest, const URI_TYPE(QueryList) * queryList, int maxChars, int * charsWritten, int * charsRequired, - UriBool spaceToPlus, UriBool normalizeBreaks); + UriBool spaceToPlus, UriBool normalizeBreaks, UriBool normalizePercentEncoding); -static UriBool URI_FUNC(AppendQueryItem)(URI_TYPE(QueryList) ** prevNext, +UriBool URI_FUNC(AppendQueryItem)(URI_TYPE(QueryList) ** prevNext, int * itemCount, const URI_CHAR * keyFirst, const URI_CHAR * keyAfter, const URI_CHAR * valueFirst, const URI_CHAR * valueAfter, - UriBool plusToSpace, UriBreakConversion breakConversion, + UriBool plusToSpace, UriBreakConversion breakConversion, UriBool normalizePercentEncoding, UriMemoryManager * memory); @@ -91,21 +91,23 @@ int URI_FUNC(ComposeQueryCharsRequired)(const URI_TYPE(QueryList) * queryList, int * charsRequired) { const UriBool spaceToPlus = URI_TRUE; const UriBool normalizeBreaks = URI_TRUE; + const UriBool normalizePercentEncoding = URI_TRUE; return URI_FUNC(ComposeQueryCharsRequiredEx)(queryList, charsRequired, - spaceToPlus, normalizeBreaks); + spaceToPlus, normalizeBreaks, normalizePercentEncoding); } int URI_FUNC(ComposeQueryCharsRequiredEx)(const URI_TYPE(QueryList) * queryList, - int * charsRequired, UriBool spaceToPlus, UriBool normalizeBreaks) { + int * charsRequired, UriBool spaceToPlus, UriBool normalizeBreaks, + UriBool normalizePercentEncoding) { if ((queryList == NULL) || (charsRequired == NULL)) { return URI_ERROR_NULL; } return URI_FUNC(ComposeQueryEngine)(NULL, queryList, 0, NULL, - charsRequired, spaceToPlus, normalizeBreaks); + charsRequired, spaceToPlus, normalizeBreaks, normalizePercentEncoding); } @@ -114,16 +116,17 @@ int URI_FUNC(ComposeQuery)(URI_CHAR * dest, const URI_TYPE(QueryList) * queryList, int maxChars, int * charsWritten) { const UriBool spaceToPlus = URI_TRUE; const UriBool normalizeBreaks = URI_TRUE; + const UriBool normalizePercentEncoding = URI_TRUE; return URI_FUNC(ComposeQueryEx)(dest, queryList, maxChars, charsWritten, - spaceToPlus, normalizeBreaks); + spaceToPlus, normalizeBreaks, normalizePercentEncoding); } int URI_FUNC(ComposeQueryEx)(URI_CHAR * dest, const URI_TYPE(QueryList) * queryList, int maxChars, int * charsWritten, - UriBool spaceToPlus, UriBool normalizeBreaks) { + UriBool spaceToPlus, UriBool normalizeBreaks, UriBool normalizePercentEncoding) { if ((dest == NULL) || (queryList == NULL)) { return URI_ERROR_NULL; } @@ -133,7 +136,7 @@ int URI_FUNC(ComposeQueryEx)(URI_CHAR * dest, } return URI_FUNC(ComposeQueryEngine)(dest, queryList, maxChars, - charsWritten, NULL, spaceToPlus, normalizeBreaks); + charsWritten, NULL, spaceToPlus, normalizeBreaks, normalizePercentEncoding); } @@ -142,18 +145,19 @@ int URI_FUNC(ComposeQueryMalloc)(URI_CHAR ** dest, const URI_TYPE(QueryList) * queryList) { const UriBool spaceToPlus = URI_TRUE; const UriBool normalizeBreaks = URI_TRUE; + const UriBool normalizePercentEncoding = URI_TRUE; return URI_FUNC(ComposeQueryMallocEx)(dest, queryList, - spaceToPlus, normalizeBreaks); + spaceToPlus, normalizeBreaks, normalizePercentEncoding); } int URI_FUNC(ComposeQueryMallocEx)(URI_CHAR ** dest, const URI_TYPE(QueryList) * queryList, - UriBool spaceToPlus, UriBool normalizeBreaks) { + UriBool spaceToPlus, UriBool normalizeBreaks, UriBool normalizePercentEncoding) { return URI_FUNC(ComposeQueryMallocExMm)(dest, queryList, spaceToPlus, - normalizeBreaks, NULL); + normalizeBreaks, normalizePercentEncoding, NULL); } @@ -161,6 +165,7 @@ int URI_FUNC(ComposeQueryMallocEx)(URI_CHAR ** dest, int URI_FUNC(ComposeQueryMallocExMm)(URI_CHAR ** dest, const URI_TYPE(QueryList) * queryList, UriBool spaceToPlus, UriBool normalizeBreaks, + UriBool normalizePercentEncoding, UriMemoryManager * memory) { int charsRequired; int res; @@ -174,7 +179,7 @@ int URI_FUNC(ComposeQueryMallocExMm)(URI_CHAR ** dest, /* Calculate space */ res = URI_FUNC(ComposeQueryCharsRequiredEx)(queryList, &charsRequired, - spaceToPlus, normalizeBreaks); + spaceToPlus, normalizeBreaks, normalizePercentEncoding); if (res != URI_SUCCESS) { return res; } @@ -191,7 +196,7 @@ int URI_FUNC(ComposeQueryMallocExMm)(URI_CHAR ** dest, /* Put query in */ res = URI_FUNC(ComposeQueryEx)(queryString, queryList, charsRequired, - NULL, spaceToPlus, normalizeBreaks); + NULL, spaceToPlus, normalizeBreaks, normalizePercentEncoding); if (res != URI_SUCCESS) { memory->free(memory, queryString); return res; @@ -206,7 +211,7 @@ int URI_FUNC(ComposeQueryMallocExMm)(URI_CHAR ** dest, int URI_FUNC(ComposeQueryEngine)(URI_CHAR * dest, const URI_TYPE(QueryList) * queryList, int maxChars, int * charsWritten, int * charsRequired, - UriBool spaceToPlus, UriBool normalizeBreaks) { + UriBool spaceToPlus, UriBool normalizeBreaks, UriBool normalizePercentEncoding) { UriBool firstItem = URI_TRUE; int ampersandLen = 0; /* increased to 1 from second item on */ URI_CHAR * write = dest; @@ -221,7 +226,7 @@ int URI_FUNC(ComposeQueryEngine)(URI_CHAR * dest, while (queryList != NULL) { const URI_CHAR * const key = queryList->key; const URI_CHAR * const value = queryList->value; - const int worstCase = (normalizeBreaks == URI_TRUE ? 6 : 3); + const int worstCase = (normalizePercentEncoding == URI_TRUE && normalizeBreaks == URI_TRUE ? 6 : (normalizePercentEncoding == URI_TRUE ? 3 : 1)); const size_t keyLen = (key == NULL) ? 0 : URI_STRLEN(key); int keyRequiredChars; const size_t valueLen = (value == NULL) ? 0 : URI_STRLEN(value); @@ -256,7 +261,7 @@ int URI_FUNC(ComposeQueryEngine)(URI_CHAR * dest, write++; } write = URI_FUNC(EscapeEx)(key, key + keyLen, - write, spaceToPlus, normalizeBreaks); + write, spaceToPlus, normalizeBreaks, normalizePercentEncoding); if (value != NULL) { if ((write - dest) + 1 + valueRequiredChars > maxChars) { @@ -267,7 +272,7 @@ int URI_FUNC(ComposeQueryEngine)(URI_CHAR * dest, write[0] = _UT('='); write++; write = URI_FUNC(EscapeEx)(value, value + valueLen, - write, spaceToPlus, normalizeBreaks); + write, spaceToPlus, normalizeBreaks, normalizePercentEncoding); } } @@ -289,7 +294,7 @@ int URI_FUNC(ComposeQueryEngine)(URI_CHAR * dest, UriBool URI_FUNC(AppendQueryItem)(URI_TYPE(QueryList) ** prevNext, int * itemCount, const URI_CHAR * keyFirst, const URI_CHAR * keyAfter, const URI_CHAR * valueFirst, const URI_CHAR * valueAfter, - UriBool plusToSpace, UriBreakConversion breakConversion, + UriBool plusToSpace, UriBreakConversion breakConversion, UriBool normalizePercentEncoding, UriMemoryManager * memory) { const int keyLen = (int)(keyAfter - keyFirst); const int valueLen = (int)(valueAfter - valueFirst); @@ -326,7 +331,9 @@ UriBool URI_FUNC(AppendQueryItem)(URI_TYPE(QueryList) ** prevNext, memcpy(key, keyFirst, keyLen * sizeof(URI_CHAR)); /* Unescape */ - URI_FUNC(UnescapeInPlaceEx)(key, plusToSpace, breakConversion); + if (normalizePercentEncoding) { + URI_FUNC(UnescapeInPlaceEx)(key, plusToSpace, breakConversion); + } } (*prevNext)->key = key; @@ -347,7 +354,9 @@ UriBool URI_FUNC(AppendQueryItem)(URI_TYPE(QueryList) ** prevNext, memcpy(value, valueFirst, valueLen * sizeof(URI_CHAR)); /* Unescape */ - URI_FUNC(UnescapeInPlaceEx)(value, plusToSpace, breakConversion); + if (normalizePercentEncoding) { + URI_FUNC(UnescapeInPlaceEx)(value, plusToSpace, breakConversion); + } } (*prevNext)->value = value; } else { @@ -386,25 +395,26 @@ int URI_FUNC(DissectQueryMalloc)(URI_TYPE(QueryList) ** dest, int * itemCount, const URI_CHAR * first, const URI_CHAR * afterLast) { const UriBool plusToSpace = URI_TRUE; const UriBreakConversion breakConversion = URI_BR_DONT_TOUCH; + const UriBool normalizePercentEncoding = URI_TRUE; return URI_FUNC(DissectQueryMallocEx)(dest, itemCount, first, afterLast, - plusToSpace, breakConversion); + plusToSpace, breakConversion, normalizePercentEncoding); } int URI_FUNC(DissectQueryMallocEx)(URI_TYPE(QueryList) ** dest, int * itemCount, const URI_CHAR * first, const URI_CHAR * afterLast, - UriBool plusToSpace, UriBreakConversion breakConversion) { + UriBool plusToSpace, UriBreakConversion breakConversion, UriBool normalizePercentEncoding) { return URI_FUNC(DissectQueryMallocExMm)(dest, itemCount, first, afterLast, - plusToSpace, breakConversion, NULL); + plusToSpace, breakConversion, normalizePercentEncoding, NULL); } int URI_FUNC(DissectQueryMallocExMm)(URI_TYPE(QueryList) ** dest, int * itemCount, const URI_CHAR * first, const URI_CHAR * afterLast, - UriBool plusToSpace, UriBreakConversion breakConversion, + UriBool plusToSpace, UriBreakConversion breakConversion, UriBool normalizePercentEncoding, UriMemoryManager * memory) { const URI_CHAR * walk = first; const URI_CHAR * keyFirst = first; @@ -440,7 +450,7 @@ int URI_FUNC(DissectQueryMallocExMm)(URI_TYPE(QueryList) ** dest, int * itemCoun if (URI_FUNC(AppendQueryItem)(prevNext, itemsAppended, keyFirst, keyAfter, valueFirst, valueAfter, - plusToSpace, breakConversion, memory) + plusToSpace, breakConversion, normalizePercentEncoding, memory) == URI_FALSE) { /* Free list we built */ *itemsAppended = 0; @@ -489,7 +499,7 @@ int URI_FUNC(DissectQueryMallocExMm)(URI_TYPE(QueryList) ** dest, int * itemCoun } if (URI_FUNC(AppendQueryItem)(prevNext, itemsAppended, keyFirst, keyAfter, - valueFirst, valueAfter, plusToSpace, breakConversion, memory) + valueFirst, valueAfter, plusToSpace, breakConversion, normalizePercentEncoding, memory) == URI_FALSE) { /* Free list we built */ *itemsAppended = 0;