diff --git a/ext/dom/lexbor/lexbor/url/url.c b/ext/dom/lexbor/lexbor/url/url.c index 9dd8f4c7fbdb4..9627642f929a4 100644 --- a/ext/dom/lexbor/lexbor/url/url.c +++ b/ext/dom/lexbor/lexbor/url/url.c @@ -4398,3 +4398,63 @@ lxb_url_serialize_fragment(const lxb_url_t *url, return LXB_STATUS_OK; } + +lxb_url_t * +lxb_url_clone(lexbor_mraw_t *mraw, lxb_url_t *url) +{ + lxb_status_t status; + lxb_url_t *new_url; + + new_url = lexbor_mraw_calloc(mraw, sizeof(lxb_url_t)); + if (new_url == NULL) { + return NULL; + } + + new_url->mraw = mraw; + + status = lxb_url_scheme_copy(&url->scheme, &new_url->scheme, mraw); + if (status != LXB_STATUS_OK) { + goto failed; + } + + status = lxb_url_username_copy(&url->username, &new_url->username, mraw); + if (status != LXB_STATUS_OK) { + goto failed; + } + + status = lxb_url_password_copy(&url->password, &new_url->password, mraw); + if (status != LXB_STATUS_OK) { + goto failed; + } + + status = lxb_url_host_copy(&url->host, &new_url->host, mraw); + if (status != LXB_STATUS_OK) { + goto failed; + } + + new_url->port = url->port; + new_url->has_port = url->has_port; + + status = lxb_url_path_copy(url, new_url); + if (status != LXB_STATUS_OK) { + goto failed; + } + + status = lxb_url_query_copy(&url->query, &new_url->query, mraw); + if (status != LXB_STATUS_OK) { + goto failed; + } + + status = lxb_url_str_copy(&url->fragment, &new_url->fragment, mraw); + if (status != LXB_STATUS_OK) { + goto failed; + } + + return new_url; + + failed: + + lxb_url_destroy(new_url); + + return NULL; +} diff --git a/ext/dom/lexbor/lexbor/url/url.h b/ext/dom/lexbor/lexbor/url/url.h index 6cd8d71cf827d..940c09a18ba0e 100644 --- a/ext/dom/lexbor/lexbor/url/url.h +++ b/ext/dom/lexbor/lexbor/url/url.h @@ -371,6 +371,19 @@ LXB_API lxb_status_t lxb_url_serialize_fragment(const lxb_url_t *url, lexbor_serialize_cb_f cb, void *ctx); +/* + * Creates a clone of the object's URL. + * + * For lexbor_mraw_t *, use url->mraw or another lexbor_mraw_t * object. + * + * @param[in] lexbor_mraw_t *. + * @param[in] lxb_url_t *. + * + * @return a new URL object if successful, otherwise NULL value. + */ +LXB_API lxb_url_t * +lxb_url_clone(lexbor_mraw_t *mraw, lxb_url_t *url); + /* * Inline functions. diff --git a/ext/standard/url.c b/ext/standard/url.c index 8877093b3680b..aa5011a058c46 100644 --- a/ext/standard/url.c +++ b/ext/standard/url.c @@ -444,9 +444,18 @@ static zend_result parse_url_init_parser(void) return SUCCESS; } -static void parse_url_instantiate_uri(zval *zv) +static zend_class_entry *parse_url_get_uri_ce(void) { ZEND_UNREACHABLE(); + + return NULL; +} + +static void *parse_url_clone_uri(void *uri_object_internal) +{ + ZEND_UNREACHABLE(); + + return NULL; } static void *parse_url_parse_uri(const zend_string *uri_str, const zend_string *base_uri_str, zval *errors) @@ -472,7 +481,8 @@ const uri_handler_t parse_url_uri_handler = { "parse_url", parse_url_init_parser, parse_url_parse_uri, - parse_url_instantiate_uri, + parse_url_get_uri_ce, + parse_url_clone_uri, parse_url_uri_to_string, parse_url_free_uri, parse_url_destroy_parser, diff --git a/ext/uri/php_lexbor.c b/ext/uri/php_lexbor.c index a70aa47e088fb..fd7f171753b7c 100644 --- a/ext/uri/php_lexbor.c +++ b/ext/uri/php_lexbor.c @@ -23,6 +23,14 @@ #include #endif +static zend_result lexbor_init_parser(void); +static void *lexbor_parse_uri(const zend_string *url_str, const zend_string *base_url_str, zval *errors); +static zend_class_entry *lexbor_get_uri_ce(void); +static void *lexbor_clone_uri(void *uri_object_internal); +static zend_string *lexbor_to_string(void *uri_object_internal); +static void lexbor_free_uri(void *uri_object_internal); +static zend_result lexbor_destroy_parser(void); + HashTable lexbor_property_handlers; lxb_url_parser_t *lexbor_parser; @@ -32,7 +40,8 @@ const uri_handler_t lexbor_uri_handler = { "whatwg", lexbor_init_parser, lexbor_parse_uri, - lexbor_instantiate_uri, + lexbor_get_uri_ce, + lexbor_clone_uri, lexbor_to_string, lexbor_free_uri, lexbor_destroy_parser, @@ -61,6 +70,13 @@ static zend_result lexbor_read_scheme(void *uri_object_internal, zval *retval) return SUCCESS; } +static zend_result lexbor_write_scheme(void *uri_object_internal, zval *value) +{ + //lxb_url_t *lxb_url = (lxb_url_t *) uri_object_internal; + + return SUCCESS; +} + static zend_result lexbor_read_user(void *uri_object_internal, zval *retval) { lxb_url_t *lxb_url = (lxb_url_t *) uri_object_internal; @@ -133,16 +149,10 @@ static zend_result lexbor_read_path(void *uri_object_internal, zval *retval) { lxb_url_t *lxb_url = (lxb_url_t *) uri_object_internal; - if (lxb_url->path.length && (lxb_url->path.list[0]->length || lxb_url->path.length > 1)) { - smart_str str = {0}; - - smart_str_appendl(&str, (const char *) lxb_url->path.list[0]->data, lxb_url->path.list[0]->length); - for (int i = 1; i < lxb_url->path.length; i++) { - smart_str_appends(&str, "/"); - smart_str_appendl(&str, (const char *) lxb_url->path.list[i]->data, lxb_url->path.list[i]->length); - } - - ZVAL_STR(retval, smart_str_extract(&str)); + if (lxb_url->path.opaque) { + ZVAL_STRINGL(retval, (const char *) lxb_url->path.str.data, lxb_url->path.str.length); + } else if (lxb_url->path.str.length > 1) { + ZVAL_STRINGL(retval, (const char *) lxb_url->path.str.data + 1, lxb_url->path.str.length - 1); } else { ZVAL_NULL(retval); } @@ -176,7 +186,7 @@ static zend_result lexbor_read_fragment(void *uri_object_internal, zval *retval) return SUCCESS; } -zend_result lexbor_init_parser(void) +static zend_result lexbor_init_parser(void) { lexbor_mraw_t *mraw = lexbor_mraw_create(); lxb_status_t status = lexbor_mraw_init(mraw, 4096 * 2); @@ -197,7 +207,7 @@ zend_result lexbor_init_parser(void) zend_hash_init(&lexbor_property_handlers, 0, NULL, NULL, true); - URI_REGISTER_PROPERTY_READ_HANDLER(&lexbor_property_handlers, ZSTR_KNOWN(ZEND_STR_SCHEME), lexbor_read_scheme); + URI_REGISTER_PROPERTY_READ_WRITE_HANDLER(&lexbor_property_handlers, ZSTR_KNOWN(ZEND_STR_SCHEME), lexbor_read_scheme, lexbor_write_scheme); URI_REGISTER_PROPERTY_READ_HANDLER(&lexbor_property_handlers, ZSTR_KNOWN(ZEND_STR_USER), lexbor_read_user); URI_REGISTER_PROPERTY_READ_HANDLER(&lexbor_property_handlers, ZSTR_KNOWN(ZEND_STR_PASSWORD), lexbor_read_password); URI_REGISTER_PROPERTY_READ_HANDLER(&lexbor_property_handlers, ZSTR_KNOWN(ZEND_STR_HOST), lexbor_read_host); @@ -232,7 +242,7 @@ void fill_errors(zval *errors) zval_ptr_dtor(&errors_tmp); } -void *lexbor_parse_uri(const zend_string *url_str, const zend_string *base_url_str, zval *errors) +static void *lexbor_parse_uri(const zend_string *url_str, const zend_string *base_url_str, zval *errors) { lexbor_cleanup_parser(); @@ -255,12 +265,19 @@ void *lexbor_parse_uri(const zend_string *url_str, const zend_string *base_url_s return url; } -void lexbor_instantiate_uri(zval *zv) +static zend_class_entry *lexbor_get_uri_ce(void) { - object_init_ex(zv, whatwg_uri_ce); + return whatwg_uri_ce; +} + +static void *lexbor_clone_uri(void *uri_object_internal) +{ + lxb_url_t *lxb_url = (lxb_url_t *) uri_object_internal; + + return lxb_url_clone(lexbor_parser->mraw, lxb_url); } -lxb_status_t lexbor_serialize_callback(const lxb_char_t *data, size_t length, void *ctx) +static lxb_status_t lexbor_serialize_callback(const lxb_char_t *data, size_t length, void *ctx) { smart_str *uri_str = (smart_str *) ctx; @@ -269,7 +286,7 @@ lxb_status_t lexbor_serialize_callback(const lxb_char_t *data, size_t length, vo return LXB_STATUS_OK; } -zend_string *lexbor_to_string(void *uri_object_internal) +static zend_string *lexbor_to_string(void *uri_object_internal) { lxb_url_t *lxb_url = (lxb_url_t *) uri_object_internal; smart_str uri_str = {0}; @@ -279,12 +296,11 @@ zend_string *lexbor_to_string(void *uri_object_internal) return smart_str_extract(&uri_str); } -void lexbor_free_uri(void *uri_object_internal) +static void lexbor_free_uri(void *uri_object_internal) { - //lxb_url_t *url = (lxb_url_t *) uri_object_internal; } -zend_result lexbor_destroy_parser(void) +static zend_result lexbor_destroy_parser(void) { lxb_url_parser_memory_destroy(lexbor_parser); lxb_url_parser_destroy(lexbor_parser, true); diff --git a/ext/uri/php_lexbor.h b/ext/uri/php_lexbor.h index 463f0459f12ee..af6c094b46620 100644 --- a/ext/uri/php_lexbor.h +++ b/ext/uri/php_lexbor.h @@ -20,13 +20,6 @@ #include #include -zend_result lexbor_init_parser(void); -void *lexbor_parse_uri(const zend_string *url_str, const zend_string *base_url_str, zval *errors); -void lexbor_instantiate_uri(zval *zv); -zend_string *lexbor_to_string(void *uri_object_internal); -void lexbor_free_uri(void *uri_object_internal); -zend_result lexbor_destroy_parser(void); - extern const uri_handler_t lexbor_uri_handler; #endif diff --git a/ext/uri/php_uri.c b/ext/uri/php_uri.c index 888681a397475..28f9c4a1e81ca 100644 --- a/ext/uri/php_uri.c +++ b/ext/uri/php_uri.c @@ -36,6 +36,8 @@ zend_class_entry *whatwg_error_ce; static zend_array uri_handlers; +static zend_object *uri_clone_obj_handler(zend_object *obj); + ZEND_DECLARE_MODULE_GLOBALS(uri) static uri_handler_t *uri_handler_by_name(const zend_string *handler_name) @@ -55,17 +57,83 @@ static uri_property_handler_t *uri_property_handler_from_uri_object(const uri_ob return uri_property_handler_from_uri_handler(uri_object->handler, name); } +#define URI_CHECK_INITIALIZATION_RETURN_THROWS(uri_object, object) do { \ + ZEND_ASSERT(uri_object != NULL); \ + if (UNEXPECTED(uri_object->uri == NULL)) { \ + zend_throw_error(NULL, "%s object is not correctly initialized", ZSTR_VAL(object->ce->name)); \ + RETURN_THROWS(); \ + } \ +} while (0) + +#define URI_CHECK_INITIALIZATION_RETURN(uri_object, object, return_on_failure) do { \ + ZEND_ASSERT(uri_object != NULL); \ + if (UNEXPECTED(uri_object->uri == NULL)) { \ + zend_throw_error(NULL, "%s object is not correctly initialized", ZSTR_VAL(object->ce->name)); \ + return return_on_failure; \ + } \ +} while (0) + +#define URI_CHECK_INITIALIZATION_RETURN_VOID(uri_object, object) do { \ + ZEND_ASSERT(uri_object != NULL); \ + if (UNEXPECTED(uri_object->uri == NULL)) { \ + zend_throw_error(NULL, "%s object is not correctly initialized", ZSTR_VAL(object->ce->name)); \ + return; \ + } \ +} while (0) + #define URI_GETTER(property_name) do { \ ZEND_PARSE_PARAMETERS_NONE(); \ uri_object_t *uri_object = Z_URI_OBJECT_P(ZEND_THIS); \ - ZEND_ASSERT(uri_object != NULL); \ - if (uri_object->handler == NULL) { \ - zend_throw_error(NULL, "%s object is not correctly initialized", ZSTR_VAL(Z_OBJ_P(ZEND_THIS)->ce->name)); \ + URI_CHECK_INITIALIZATION_RETURN_THROWS(uri_object, Z_OBJ_P(ZEND_THIS)); \ + const uri_property_handler_t *property_handler = uri_property_handler_from_uri_object(uri_object, property_name); \ + ZEND_ASSERT(property_handler != NULL); \ + if (property_handler->read_func(uri_object->uri, return_value) == FAILURE) { \ + zend_throw_error(NULL, "%s::$%s property cannot be retrieved", ZSTR_VAL(Z_OBJ_P(ZEND_THIS)->ce->name), ZSTR_VAL(property_name)); \ RETURN_THROWS(); \ } \ +} while (0) + +#define URI_WITHER_COMMON(property_name, property_zv, return_value) \ + uri_object_t *uri_object = Z_URI_OBJECT_P(ZEND_THIS); \ + URI_CHECK_INITIALIZATION_RETURN_THROWS(uri_object, Z_OBJ_P(ZEND_THIS)); \ const uri_property_handler_t *property_handler = uri_property_handler_from_uri_object(uri_object, property_name); \ ZEND_ASSERT(property_handler != NULL); \ - property_handler->read_func(uri_object->uri, return_value); \ + zend_object *new_object = uri_clone_obj_handler(Z_OBJ_P(ZEND_THIS)); \ + uri_object_t *new_uri_object = uri_object_from_obj(new_object); \ + URI_CHECK_INITIALIZATION_RETURN_THROWS(new_uri_object, Z_OBJ_P(ZEND_THIS)); \ + if (property_handler->write_func == NULL || property_handler->write_func(new_uri_object->uri, property_zv) == FAILURE) { \ + zend_readonly_property_modification_error_ex(ZSTR_VAL(Z_OBJ_P(ZEND_THIS)->ce->name), ZSTR_VAL(property_name)); \ + RETURN_THROWS(); \ + } \ + ZVAL_OBJ(return_value, new_object); + +#define URI_WITHER_STR(property_name) do { \ + zend_string *value; \ + ZEND_PARSE_PARAMETERS_START(1, 1) \ + Z_PARAM_STR_OR_NULL(value) \ + ZEND_PARSE_PARAMETERS_END(); \ + zval zv; \ + if (value == NULL) { \ + ZVAL_NULL(&zv); \ + } else { \ + ZVAL_STR_COPY(&zv, value); \ + } \ + URI_WITHER_COMMON(property_name, &zv, return_value) \ +} while (0) + +#define URI_WITHER_LONG(property_name) do { \ + zend_long value; \ + bool value_is_null; \ + ZEND_PARSE_PARAMETERS_START(1, 1) \ + Z_PARAM_LONG_OR_NULL(value, value_is_null) \ + ZEND_PARSE_PARAMETERS_END(); \ + zval zv; \ + if (value_is_null) {\ + ZVAL_NULL(&zv); \ + } else { \ + ZVAL_LONG(&zv, value); \ + } \ + URI_WITHER_COMMON(property_name, &zv, return_value); \ } while (0) PHPAPI uri_handler_t *php_uri_get_handler(const zend_string *handler_name) @@ -189,7 +257,7 @@ static void instantiate_uri(INTERNAL_FUNCTION_PARAMETERS, const uri_handler_t *h } if (!is_constructor) { - handler->instantiate_uri(return_value); + object_init_ex(return_value, handler->get_uri_ce()); } uri_object_t *uri_object = Z_URI_OBJECT_P(is_constructor ? ZEND_THIS : return_value); @@ -260,52 +328,88 @@ PHP_METHOD(Uri_Uri, getScheme) URI_GETTER(ZSTR_KNOWN(ZEND_STR_SCHEME)); } +PHP_METHOD(Uri_Uri, withScheme) +{ + URI_WITHER_STR(ZSTR_KNOWN(ZEND_STR_SCHEME)); +} + PHP_METHOD(Uri_Uri, getUser) { URI_GETTER(ZSTR_KNOWN(ZEND_STR_USER)); } +PHP_METHOD(Uri_Uri, withUser) +{ + URI_WITHER_STR(ZSTR_KNOWN(ZEND_STR_USER)); +} + PHP_METHOD(Uri_Uri, getPassword) { URI_GETTER(ZSTR_KNOWN(ZEND_STR_PASSWORD)); } +PHP_METHOD(Uri_Uri, withPassword) +{ + URI_WITHER_STR(ZSTR_KNOWN(ZEND_STR_PASSWORD)); +} + PHP_METHOD(Uri_Uri, getHost) { URI_GETTER(ZSTR_KNOWN(ZEND_STR_HOST)); } +PHP_METHOD(Uri_Uri, withHost) +{ + URI_WITHER_STR(ZSTR_KNOWN(ZEND_STR_HOST)); +} + PHP_METHOD(Uri_Uri, getPort) { URI_GETTER(ZSTR_KNOWN(ZEND_STR_PORT)); } +PHP_METHOD(Uri_Uri, withPort) +{ + URI_WITHER_LONG(ZSTR_KNOWN(ZEND_STR_PORT)); +} + PHP_METHOD(Uri_Uri, getPath) { URI_GETTER(ZSTR_KNOWN(ZEND_STR_PATH)); } +PHP_METHOD(Uri_Uri, withPath) +{ + URI_WITHER_STR(ZSTR_KNOWN(ZEND_STR_PATH)); +} + PHP_METHOD(Uri_Uri, getQuery) { URI_GETTER(ZSTR_KNOWN(ZEND_STR_QUERY)); } +PHP_METHOD(Uri_Uri, withQuery) +{ + URI_WITHER_STR(ZSTR_KNOWN(ZEND_STR_QUERY)); +} + PHP_METHOD(Uri_Uri, getFragment) { URI_GETTER(ZSTR_KNOWN(ZEND_STR_FRAGMENT)); } +PHP_METHOD(Uri_Uri, withFragment) +{ + URI_WITHER_STR(ZSTR_KNOWN(ZEND_STR_FRAGMENT)); +} + PHP_METHOD(Uri_Uri, __toString) { ZEND_PARSE_PARAMETERS_NONE(); zend_object *this_obj = Z_OBJ_P(ZEND_THIS); uri_object_t *uri_object = uri_object_from_obj(this_obj); - ZEND_ASSERT(uri_object != NULL); - if (UNEXPECTED(uri_object->handler == NULL)) { - zend_throw_error(NULL, "%s object is not correctly initialized", ZSTR_VAL(this_obj->ce->name)); - RETURN_THROWS(); - } + URI_CHECK_INITIALIZATION_RETURN_THROWS(uri_object, this_obj); RETURN_STR(uri_object->handler->uri_to_string(uri_object->uri)); } @@ -337,7 +441,7 @@ static void uri_free_obj_handler(zend_object *object) { uri_object_t *uri_object = uri_object_from_obj(object); ZEND_ASSERT(uri_object != NULL); - if (UNEXPECTED(uri_object->handler != NULL)) { + if (UNEXPECTED(uri_object->uri != NULL)) { uri_object->handler->free_uri(uri_object->uri); uri_object->handler = NULL; uri_object->uri = NULL; @@ -350,71 +454,142 @@ static int uri_has_property_handler(zend_object *object, zend_string *name, int { uri_object_t *uri_object = uri_object_from_obj(object); ZEND_ASSERT(uri_object != NULL); - if (UNEXPECTED(uri_object->handler == NULL)) { - return 0; + if (UNEXPECTED(uri_object->uri == NULL)) { + if (check_empty == ZEND_PROPERTY_EXISTS) { + zend_throw_error(NULL, "%s object is not correctly initialized", ZSTR_VAL(object->ce->name)); + } + return false; } - bool retval = 0; - uri_property_handler_t *property_handler = zend_hash_find_ptr(uri_object->handler->property_handlers, name); - if (property_handler) { - zval tmp; - - if (check_empty == 2) { - retval = 1; - } else if (property_handler->read_func(uri_object->uri, &tmp) == SUCCESS) { - if (check_empty == 1) { - retval = zend_is_true(&tmp); - } else if (check_empty == 0) { - retval = (Z_TYPE(tmp) != IS_NULL); - } - zval_ptr_dtor(&tmp); - } + if (!property_handler) { + return zend_std_has_property(object, name, check_empty, cache_slot); + } + + if (check_empty == ZEND_PROPERTY_EXISTS) { + return true; + } + + zval tmp; + + if (property_handler->read_func(uri_object->uri, &tmp) == FAILURE) { + return false; + } + + bool retval; + + if (check_empty == ZEND_PROPERTY_NOT_EMPTY) { + retval = zend_is_true(&tmp); + } else if (check_empty == ZEND_PROPERTY_ISSET) { + retval = (Z_TYPE(tmp) != IS_NULL); } else { - retval = zend_std_has_property(object, name, check_empty, cache_slot); + ZEND_UNREACHABLE(); } + zval_ptr_dtor(&tmp); + return retval; } -static zval *uri_read_property_handler(zend_object *obj, zend_string *name, int type, void **cache_slot, zval *rv) +static zval *uri_read_property_handler(zend_object *object, zend_string *name, int type, void **cache_slot, zval *rv) { - zval *retval; - uri_object_t *uri_object = uri_object_from_obj(obj); - ZEND_ASSERT(uri_object != NULL); - if (UNEXPECTED(uri_object->handler == NULL)) { - zend_throw_error(NULL, "%s object is not correctly initialized", ZSTR_VAL(obj->ce->name)); - return &EG(uninitialized_zval); - } + uri_object_t *uri_object = uri_object_from_obj(object); + URI_CHECK_INITIALIZATION_RETURN(uri_object, object, &EG(uninitialized_zval)); uri_property_handler_t *property_handler = uri_property_handler_from_uri_object(uri_object, name); - if (property_handler != NULL) { - zend_result result = property_handler->read_func(uri_object->uri, rv); - if (result == SUCCESS) { - retval = rv; - } else { - retval = &EG(uninitialized_zval); - } + if (UNEXPECTED(property_handler == NULL)) { + return zend_std_read_property(object, name, type, cache_slot, rv); + } + + zval *retval; + zend_result result = property_handler->read_func(uri_object->uri, rv); + if (result == SUCCESS) { + retval = rv; } else { - retval = zend_std_read_property(obj, name, type, cache_slot, rv); + retval = &EG(uninitialized_zval); } return retval; } -static zval *uri_get_property_ptr_ptr_handler(zend_object *obj, zend_string *name, int type, void **cache_slot) +static zval *uri_write_property_handler(zend_object *object, zend_string *name, zval *value, void **cache_slot) { - const uri_object_t *uri_object = uri_object_from_obj(obj); - ZEND_ASSERT(uri_object != NULL); - if (UNEXPECTED(uri_object->handler == NULL)) { - return NULL; + uri_object_t *uri_object = uri_object_from_obj(object); + URI_CHECK_INITIALIZATION_RETURN(uri_object, object, &EG(uninitialized_zval)); + + uri_property_handler_t *property_handler = uri_property_handler_from_uri_object(uri_object, name); + if (UNEXPECTED(property_handler == NULL)) { + return zend_std_write_property(object, name, value, cache_slot); } - if (!zend_hash_exists(uri_object->handler->property_handlers, name)) { - return zend_std_get_property_ptr_ptr(obj, name, type, cache_slot); + if (UNEXPECTED(property_handler->write_func == NULL)) { + zend_readonly_property_modification_error_ex(ZSTR_VAL(object->ce->name), ZSTR_VAL(name)); + return &EG(uninitialized_zval); } - return NULL; + zval tmp; + ZVAL_COPY(&tmp, value); + + // TODO: Check type + + zend_result result = property_handler->write_func(uri_object->uri, &tmp); + zval_ptr_dtor(&tmp); + if (result == FAILURE) { + return &EG(uninitialized_zval); + } + + return value; +} + +static zval *uri_get_property_ptr_ptr_handler(zend_object *object, zend_string *name, int type, void **cache_slot) +{ + const uri_object_t *uri_object = uri_object_from_obj(object); + URI_CHECK_INITIALIZATION_RETURN(uri_object, object, NULL); + + if (zend_hash_exists(uri_object->handler->property_handlers, name)) { + zend_readonly_property_modification_error_ex(ZSTR_VAL(object->ce->name), ZSTR_VAL(name)); + return &EG(error_zval); + } + + return zend_std_get_property_ptr_ptr(object, name, type, cache_slot); +} + +static void uri_unset_property_handler(zend_object *object, zend_string *name, void **cache_slot) +{ + const uri_object_t *uri_object = uri_object_from_obj(object); + URI_CHECK_INITIALIZATION_RETURN_VOID(uri_object, object); + + if (zend_hash_exists(uri_object->handler->property_handlers, name)) { + zend_throw_error(NULL, "Cannot unset readonly property %s::$%s", ZSTR_VAL(object->ce->name), ZSTR_VAL(name)); + return; + } + + zend_std_unset_property(object, name, cache_slot); +} + +static zend_object *uri_clone_obj_handler(zend_object *object) +{ + uri_object_t *uri_object = uri_object_from_obj(object); + + zend_object *new_object = uri_create_object_handler(object->ce); + ZEND_ASSERT(new_object != NULL); + uri_object_t *new_uri_object = uri_object_from_obj(new_object); + + URI_CHECK_INITIALIZATION_RETURN(uri_object, object, &new_uri_object->std); + + new_uri_object->handler = uri_object->handler; + + void *uri = uri_object->handler->clone_uri(uri_object->uri); + if (uri == NULL) { + zend_throw_error(NULL, "Failed to clone %s", ZSTR_VAL(object->ce->name)); + return &new_uri_object->std; + } + + new_uri_object->uri = uri; + + zend_objects_clone_members(&new_uri_object->std, &uri_object->std); + + return &new_uri_object->std; } static HashTable *uri_get_debug_info_handler(zend_object *obj, int *is_temp) @@ -423,7 +598,7 @@ static HashTable *uri_get_debug_info_handler(zend_object *obj, int *is_temp) uri_object_t *uri_object = uri_object_from_obj(obj); ZEND_ASSERT(uri_object != NULL); - if (UNEXPECTED(uri_object->handler == NULL)) { + if (UNEXPECTED(uri_object->uri == NULL)) { return NULL; } @@ -481,6 +656,9 @@ void uri_register_symbols(void) uri_object_handlers.has_property = uri_has_property_handler; uri_object_handlers.get_property_ptr_ptr = uri_get_property_ptr_ptr_handler; uri_object_handlers.read_property = uri_read_property_handler; + uri_object_handlers.write_property = uri_write_property_handler; + uri_object_handlers.unset_property = uri_unset_property_handler; + uri_object_handlers.clone_obj = uri_clone_obj_handler; uri_object_handlers.get_debug_info = uri_get_debug_info_handler; uri_object_handlers.get_gc = uri_get_gc_handler; @@ -497,7 +675,8 @@ zend_result uri_handler_register(const uri_handler_t *uri_handler) ZEND_ASSERT(uri_handler->name != NULL); ZEND_ASSERT(uri_handler->init_parser != NULL); ZEND_ASSERT(uri_handler->parse_uri != NULL); - ZEND_ASSERT(uri_handler->instantiate_uri != NULL); + ZEND_ASSERT(uri_handler->get_uri_ce != NULL); + ZEND_ASSERT(uri_handler->clone_uri != NULL); ZEND_ASSERT(uri_handler->uri_to_string != NULL); ZEND_ASSERT(uri_handler->free_uri != NULL); ZEND_ASSERT(uri_handler->destroy_parser != NULL); diff --git a/ext/uri/php_uri.stub.php b/ext/uri/php_uri.stub.php index 73171ff46de69..bfd821015e459 100644 --- a/ext/uri/php_uri.stub.php +++ b/ext/uri/php_uri.stub.php @@ -99,20 +99,36 @@ public static function fromWhatWg(string $uri, ?string $baseUrl = null, &$errors public function getScheme(): ?string {} + public function withScheme(?string $scheme): static {} + public function getUser(): ?string {} + public function withUser(?string $user): static {} + public function getPassword(): ?string {} + public function withPassword(?string $password): static {} + public function getHost(): ?string {} + public function withHost(?string $host): static {} + public function getPort(): ?int {} + public function withPort(?int $port): static {} + public function getPath(): ?string {} + public function withPath(?string $path): static {} + public function getQuery(): ?string {} + public function withQuery(?string $query): static {} + public function getFragment(): ?string {} + public function withFragment(?string $fragment): static {} + public function __toString(): string {} } diff --git a/ext/uri/php_uri_arginfo.h b/ext/uri/php_uri_arginfo.h index 759a6d63cd140..668c9ad69b0b2 100644 --- a/ext/uri/php_uri_arginfo.h +++ b/ext/uri/php_uri_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: e98dcd894d79251d1413c05721ea68ad4989934b */ + * Stub hash: 20a7065d4fb21d878af78f4c21e36bdfd95b0656 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Uri_WhatWgError___construct, 0, 0, 2) ZEND_ARG_TYPE_INFO(0, position, IS_STRING, 0) @@ -20,21 +20,53 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Uri_getScheme, 0, 0, IS_STRING, 1) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Uri_withScheme, 0, 1, IS_STATIC, 0) + ZEND_ARG_TYPE_INFO(0, scheme, IS_STRING, 1) +ZEND_END_ARG_INFO() + #define arginfo_class_Uri_Uri_getUser arginfo_class_Uri_Uri_getScheme +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Uri_withUser, 0, 1, IS_STATIC, 0) + ZEND_ARG_TYPE_INFO(0, user, IS_STRING, 1) +ZEND_END_ARG_INFO() + #define arginfo_class_Uri_Uri_getPassword arginfo_class_Uri_Uri_getScheme +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Uri_withPassword, 0, 1, IS_STATIC, 0) + ZEND_ARG_TYPE_INFO(0, password, IS_STRING, 1) +ZEND_END_ARG_INFO() + #define arginfo_class_Uri_Uri_getHost arginfo_class_Uri_Uri_getScheme +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Uri_withHost, 0, 1, IS_STATIC, 0) + ZEND_ARG_TYPE_INFO(0, host, IS_STRING, 1) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Uri_getPort, 0, 0, IS_LONG, 1) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Uri_withPort, 0, 1, IS_STATIC, 0) + ZEND_ARG_TYPE_INFO(0, port, IS_LONG, 1) +ZEND_END_ARG_INFO() + #define arginfo_class_Uri_Uri_getPath arginfo_class_Uri_Uri_getScheme +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Uri_withPath, 0, 1, IS_STATIC, 0) + ZEND_ARG_TYPE_INFO(0, path, IS_STRING, 1) +ZEND_END_ARG_INFO() + #define arginfo_class_Uri_Uri_getQuery arginfo_class_Uri_Uri_getScheme +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Uri_withQuery, 0, 1, IS_STATIC, 0) + ZEND_ARG_TYPE_INFO(0, query, IS_STRING, 1) +ZEND_END_ARG_INFO() + #define arginfo_class_Uri_Uri_getFragment arginfo_class_Uri_Uri_getScheme +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Uri_withFragment, 0, 1, IS_STATIC, 0) + ZEND_ARG_TYPE_INFO(0, fragment, IS_STRING, 1) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Uri___toString, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() @@ -53,13 +85,21 @@ ZEND_METHOD(Uri_WhatWgError, __construct); ZEND_METHOD(Uri_Uri, fromRfc3986); ZEND_METHOD(Uri_Uri, fromWhatWg); ZEND_METHOD(Uri_Uri, getScheme); +ZEND_METHOD(Uri_Uri, withScheme); ZEND_METHOD(Uri_Uri, getUser); +ZEND_METHOD(Uri_Uri, withUser); ZEND_METHOD(Uri_Uri, getPassword); +ZEND_METHOD(Uri_Uri, withPassword); ZEND_METHOD(Uri_Uri, getHost); +ZEND_METHOD(Uri_Uri, withHost); ZEND_METHOD(Uri_Uri, getPort); +ZEND_METHOD(Uri_Uri, withPort); ZEND_METHOD(Uri_Uri, getPath); +ZEND_METHOD(Uri_Uri, withPath); ZEND_METHOD(Uri_Uri, getQuery); +ZEND_METHOD(Uri_Uri, withQuery); ZEND_METHOD(Uri_Uri, getFragment); +ZEND_METHOD(Uri_Uri, withFragment); ZEND_METHOD(Uri_Uri, __toString); ZEND_METHOD(Uri_Rfc3986Uri, __construct); ZEND_METHOD(Uri_WhatWgUri, __construct); @@ -73,13 +113,21 @@ static const zend_function_entry class_Uri_Uri_methods[] = { ZEND_ME(Uri_Uri, fromRfc3986, arginfo_class_Uri_Uri_fromRfc3986, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) ZEND_ME(Uri_Uri, fromWhatWg, arginfo_class_Uri_Uri_fromWhatWg, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) ZEND_ME(Uri_Uri, getScheme, arginfo_class_Uri_Uri_getScheme, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Uri, withScheme, arginfo_class_Uri_Uri_withScheme, ZEND_ACC_PUBLIC) ZEND_ME(Uri_Uri, getUser, arginfo_class_Uri_Uri_getUser, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Uri, withUser, arginfo_class_Uri_Uri_withUser, ZEND_ACC_PUBLIC) ZEND_ME(Uri_Uri, getPassword, arginfo_class_Uri_Uri_getPassword, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Uri, withPassword, arginfo_class_Uri_Uri_withPassword, ZEND_ACC_PUBLIC) ZEND_ME(Uri_Uri, getHost, arginfo_class_Uri_Uri_getHost, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Uri, withHost, arginfo_class_Uri_Uri_withHost, ZEND_ACC_PUBLIC) ZEND_ME(Uri_Uri, getPort, arginfo_class_Uri_Uri_getPort, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Uri, withPort, arginfo_class_Uri_Uri_withPort, ZEND_ACC_PUBLIC) ZEND_ME(Uri_Uri, getPath, arginfo_class_Uri_Uri_getPath, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Uri, withPath, arginfo_class_Uri_Uri_withPath, ZEND_ACC_PUBLIC) ZEND_ME(Uri_Uri, getQuery, arginfo_class_Uri_Uri_getQuery, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Uri, withQuery, arginfo_class_Uri_Uri_withQuery, ZEND_ACC_PUBLIC) ZEND_ME(Uri_Uri, getFragment, arginfo_class_Uri_Uri_getFragment, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Uri, withFragment, arginfo_class_Uri_Uri_withFragment, ZEND_ACC_PUBLIC) ZEND_ME(Uri_Uri, __toString, arginfo_class_Uri_Uri___toString, ZEND_ACC_PUBLIC) ZEND_FE_END }; @@ -300,15 +348,11 @@ static zend_class_entry *register_class_Uri_Uri(zend_class_entry *class_entry_Ur zval property_scheme_default_value; ZVAL_UNDEF(&property_scheme_default_value); - zend_string *property_scheme_name = zend_string_init("scheme", sizeof("scheme") - 1, 1); - zend_declare_typed_property(class_entry, property_scheme_name, &property_scheme_default_value, ZEND_ACC_PRIVATE|ZEND_ACC_READONLY|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); - zend_string_release(property_scheme_name); + zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_SCHEME), &property_scheme_default_value, ZEND_ACC_PRIVATE|ZEND_ACC_READONLY|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); zval property_user_default_value; ZVAL_UNDEF(&property_user_default_value); - zend_string *property_user_name = zend_string_init("user", sizeof("user") - 1, 1); - zend_declare_typed_property(class_entry, property_user_name, &property_user_default_value, ZEND_ACC_PRIVATE|ZEND_ACC_READONLY|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); - zend_string_release(property_user_name); + zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_USER), &property_user_default_value, ZEND_ACC_PRIVATE|ZEND_ACC_READONLY|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); zval property_password_default_value; ZVAL_UNDEF(&property_password_default_value); @@ -318,33 +362,23 @@ static zend_class_entry *register_class_Uri_Uri(zend_class_entry *class_entry_Ur zval property_host_default_value; ZVAL_UNDEF(&property_host_default_value); - zend_string *property_host_name = zend_string_init("host", sizeof("host") - 1, 1); - zend_declare_typed_property(class_entry, property_host_name, &property_host_default_value, ZEND_ACC_PRIVATE|ZEND_ACC_READONLY|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); - zend_string_release(property_host_name); + zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_HOST), &property_host_default_value, ZEND_ACC_PRIVATE|ZEND_ACC_READONLY|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); zval property_port_default_value; ZVAL_UNDEF(&property_port_default_value); - zend_string *property_port_name = zend_string_init("port", sizeof("port") - 1, 1); - zend_declare_typed_property(class_entry, property_port_name, &property_port_default_value, ZEND_ACC_PRIVATE|ZEND_ACC_READONLY|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG|MAY_BE_NULL)); - zend_string_release(property_port_name); + zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_PORT), &property_port_default_value, ZEND_ACC_PRIVATE|ZEND_ACC_READONLY|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG|MAY_BE_NULL)); zval property_path_default_value; ZVAL_UNDEF(&property_path_default_value); - zend_string *property_path_name = zend_string_init("path", sizeof("path") - 1, 1); - zend_declare_typed_property(class_entry, property_path_name, &property_path_default_value, ZEND_ACC_PRIVATE|ZEND_ACC_READONLY|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); - zend_string_release(property_path_name); + zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_PATH), &property_path_default_value, ZEND_ACC_PRIVATE|ZEND_ACC_READONLY|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); zval property_query_default_value; ZVAL_UNDEF(&property_query_default_value); - zend_string *property_query_name = zend_string_init("query", sizeof("query") - 1, 1); - zend_declare_typed_property(class_entry, property_query_name, &property_query_default_value, ZEND_ACC_PRIVATE|ZEND_ACC_READONLY|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); - zend_string_release(property_query_name); + zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_QUERY), &property_query_default_value, ZEND_ACC_PRIVATE|ZEND_ACC_READONLY|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); zval property_fragment_default_value; ZVAL_UNDEF(&property_fragment_default_value); - zend_string *property_fragment_name = zend_string_init("fragment", sizeof("fragment") - 1, 1); - zend_declare_typed_property(class_entry, property_fragment_name, &property_fragment_default_value, ZEND_ACC_PRIVATE|ZEND_ACC_READONLY|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); - zend_string_release(property_fragment_name); + zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_FRAGMENT), &property_fragment_default_value, ZEND_ACC_PRIVATE|ZEND_ACC_READONLY|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); return class_entry; } diff --git a/ext/uri/php_uri_common.h b/ext/uri/php_uri_common.h index 431f3910185d7..67fd31694df76 100644 --- a/ext/uri/php_uri_common.h +++ b/ext/uri/php_uri_common.h @@ -28,7 +28,8 @@ typedef struct uri_handler_t { zend_result (*init_parser)(void); void *(*parse_uri)(const zend_string *uri_str, const zend_string *base_url_str, zval *errors); - void (*instantiate_uri)(zval *zv); + zend_class_entry *(*get_uri_ce)(void); + void *(*clone_uri)(void *uri_object_internal); zend_string *(*uri_to_string)(void *uri_object_internal); void (*free_uri)(void *uri_object_internal); zend_result (*destroy_parser)(void); @@ -49,12 +50,20 @@ static inline uri_object_t *uri_object_from_obj(zend_object *obj) { typedef zend_result (*uri_read_t)(void *uri_object_internal, zval *retval); +typedef zend_result (*uri_write_t)(void *uri_object_internal, zval *value); + typedef struct uri_property_handler_t { uri_read_t read_func; + uri_write_t write_func; } uri_property_handler_t; #define URI_REGISTER_PROPERTY_READ_HANDLER(property_handlers, name, property_read_func) do { \ - static const uri_property_handler_t handler = {.read_func = property_read_func}; \ + static const uri_property_handler_t handler = {.read_func = property_read_func, .write_func = NULL}; \ + uri_register_property_handler(property_handlers, name, &handler); \ +} while (0) + +#define URI_REGISTER_PROPERTY_READ_WRITE_HANDLER(property_handlers, name, property_read_func, property_write_func) do { \ + static const uri_property_handler_t handler = {.read_func = property_read_func, .write_func = property_write_func}; \ uri_register_property_handler(property_handlers, name, &handler); \ } while (0) diff --git a/ext/uri/php_uriparser.c b/ext/uri/php_uriparser.c index d18c58a97add0..0f4b60e94981b 100644 --- a/ext/uri/php_uriparser.c +++ b/ext/uri/php_uriparser.c @@ -19,13 +19,22 @@ #include "php_uri_common.h" #include "Zend/zend_smart_str.h" +static zend_result uriparser_init_parser(void); +static void *uriparser_parse_uri(const zend_string *uri_str, const zend_string *base_uri_str, zval *errors); +static zend_class_entry *uriparser_get_uri_ce(void); +static void *uriparser_clone_uri(void *uri_object_internal); +static zend_string *uriparser_uri_to_string(void *uri_object_internal); +static void uriparser_free_uri(void *uri_object_internal); +static zend_result uriparser_destroy_parser(void); + HashTable uriparser_property_handlers; const uri_handler_t uriparser_uri_handler = { "rfc3986", uriparser_init_parser, uriparser_parse_uri, - uriparser_instantiate_uri, + uriparser_get_uri_ce, + uriparser_clone_uri, uriparser_uri_to_string, uriparser_free_uri, uriparser_destroy_parser, @@ -45,6 +54,14 @@ static zend_result uriparser_read_scheme(void *uri_object_internal, zval *retval return SUCCESS; } +static zend_result uriparser_write_scheme(void *uri_object_internal, zval *value) +{ + // UriUriA *uri = (UriUriA *) uri_object_internal; + // TODO + + return SUCCESS; +} + static zend_result uriparser_read_user(void *uri_object_internal, zval *retval) { UriUriA *uri = (UriUriA *) uri_object_internal; @@ -156,11 +173,11 @@ static zend_result uriparser_read_fragment(void *uri_object_internal, zval *retv return SUCCESS; } -zend_result uriparser_init_parser(void) +static zend_result uriparser_init_parser(void) { zend_hash_init(&uriparser_property_handlers, 0, NULL, NULL, true); - URI_REGISTER_PROPERTY_READ_HANDLER(&uriparser_property_handlers, ZSTR_KNOWN(ZEND_STR_SCHEME), uriparser_read_scheme); + URI_REGISTER_PROPERTY_READ_WRITE_HANDLER(&uriparser_property_handlers, ZSTR_KNOWN(ZEND_STR_SCHEME), uriparser_read_scheme, uriparser_write_scheme); URI_REGISTER_PROPERTY_READ_HANDLER(&uriparser_property_handlers, ZSTR_KNOWN(ZEND_STR_USER), uriparser_read_user); URI_REGISTER_PROPERTY_READ_HANDLER(&uriparser_property_handlers, ZSTR_KNOWN(ZEND_STR_PASSWORD), uriparser_read_password); URI_REGISTER_PROPERTY_READ_HANDLER(&uriparser_property_handlers, ZSTR_KNOWN(ZEND_STR_HOST), uriparser_read_host); @@ -172,7 +189,7 @@ zend_result uriparser_init_parser(void) return SUCCESS; } -void *uriparser_parse_uri(const zend_string *uri_str, const zend_string *base_uri_str, zval *errors) +static void *uriparser_parse_uri(const zend_string *uri_str, const zend_string *base_uri_str, zval *errors) { UriUriA *uri = emalloc(sizeof(UriUriA)); @@ -212,12 +229,22 @@ void *uriparser_parse_uri(const zend_string *uri_str, const zend_string *base_ur } } -void uriparser_instantiate_uri(zval *zv) +static zend_class_entry *uriparser_get_uri_ce(void) { - object_init_ex(zv, rfc3986_uri_ce); + return rfc3986_uri_ce; +} + +static void *uriparser_clone_uri(void *uri_object_internal) +{ + UriUriA *uri = (UriUriA *) uri_object_internal; + + UriUriA *new_uri = ecalloc(1, sizeof(UriUriA)); + memcpy(new_uri, uri, sizeof(UriUriA)); + + return new_uri; } -zend_string *uriparser_uri_to_string(void *uri_object_internal) +static zend_string *uriparser_uri_to_string(void *uri_object_internal) { UriUriA *uri = (UriUriA *) uri_object_internal; int charsRequired; @@ -236,7 +263,7 @@ zend_string *uriparser_uri_to_string(void *uri_object_internal) return uri_string; } -void uriparser_free_uri(void *uri_object_internal) +static void uriparser_free_uri(void *uri_object_internal) { UriUriA *uri = (UriUriA *) uri_object_internal; @@ -244,7 +271,7 @@ void uriparser_free_uri(void *uri_object_internal) efree(uri); } -zend_result uriparser_destroy_parser(void) +static zend_result uriparser_destroy_parser(void) { zend_hash_destroy(&uriparser_property_handlers); diff --git a/ext/uri/php_uriparser.h b/ext/uri/php_uriparser.h index 0a21772c763a5..8f10655b23380 100644 --- a/ext/uri/php_uriparser.h +++ b/ext/uri/php_uriparser.h @@ -20,13 +20,6 @@ #include #include -zend_result uriparser_init_parser(void); -void *uriparser_parse_uri(const zend_string *uri_str, const zend_string *base_url_str, zval *errors); -void uriparser_instantiate_uri(zval *zv); -zend_string *uriparser_uri_to_string(void *uri_object_internal); -void uriparser_free_uri(void *uri_object_internal); -zend_result uriparser_destroy_parser(void); - extern const uri_handler_t uriparser_uri_handler; #endif diff --git a/ext/uri/tests/001.phpt b/ext/uri/tests/001.phpt index d51af8406f148..453c925bc071e 100644 --- a/ext/uri/tests/001.phpt +++ b/ext/uri/tests/001.phpt @@ -13,7 +13,7 @@ $t2 = hrtime(true); $t3 = hrtime(true); for ($i = 0; $i < 1000; $i++) { - \Uri\Uri::fromWhatWg("https://example.com"); + \Uri\Uri::fromWhatWg("https://example.com/"); } $t4 = hrtime(true); diff --git a/ext/uri/tests/016.phpt b/ext/uri/tests/016.phpt new file mode 100644 index 0000000000000..0dc5a5299ee4e --- /dev/null +++ b/ext/uri/tests/016.phpt @@ -0,0 +1,56 @@ +--TEST-- +Test property mutation errors +--EXTENSIONS-- +reflection +uri +--FILE-- +setValue($value); + } catch (ReflectionException $e) { + echo $e->getMessage() . "\n"; + } +} + +$uri = \Uri\Uri::fromRfc3986("https://example.com"); +mutateProperty($uri, "scheme", ""); +mutateProperty($uri, "user", ""); +mutateProperty($uri, "password", ""); +mutateProperty($uri, "host", ""); +mutateProperty($uri, "port", 1); +mutateProperty($uri, "path", ""); +mutateProperty($uri, "query", ""); +mutateProperty($uri, "fragment", ""); + +$uri = \Uri\Uri::fromWhatWg("https://example.com"); +mutateProperty($uri, "scheme", ""); +mutateProperty($uri, "user", ""); +mutateProperty($uri, "password", ""); +mutateProperty($uri, "host", ""); +mutateProperty($uri, "port", 1); +mutateProperty($uri, "path", ""); +mutateProperty($uri, "query", ""); +mutateProperty($uri, "fragment", ""); + +?> +--EXPECTF-- +Property Uri\Rfc3986Uri::$scheme does not exist +Property Uri\Rfc3986Uri::$user does not exist +Property Uri\Rfc3986Uri::$password does not exist +Property Uri\Rfc3986Uri::$host does not exist +Property Uri\Rfc3986Uri::$port does not exist +Property Uri\Rfc3986Uri::$path does not exist +Property Uri\Rfc3986Uri::$query does not exist +Property Uri\Rfc3986Uri::$fragment does not exist +Property Uri\WhatWgUri::$scheme does not exist +Property Uri\WhatWgUri::$user does not exist +Property Uri\WhatWgUri::$password does not exist +Property Uri\WhatWgUri::$host does not exist +Property Uri\WhatWgUri::$port does not exist +Property Uri\WhatWgUri::$path does not exist +Property Uri\WhatWgUri::$query does not exist +Property Uri\WhatWgUri::$fragment does not exist diff --git a/ext/uri/tests/017.phpt b/ext/uri/tests/017.phpt new file mode 100644 index 0000000000000..a0e1a49d677d6 --- /dev/null +++ b/ext/uri/tests/017.phpt @@ -0,0 +1,132 @@ +--TEST-- +Test property mutation +--EXTENSIONS-- +uri +--FILE-- +withScheme("http"); +$uri3 = $uri2->withScheme(null); +var_dump($uri1); +var_dump($uri2); +var_dump($uri3); + +$uri4 = \Uri\Uri::fromWhatWg("https://example.com"); +$uri5 = $uri4->withScheme("http"); +$uri6 = $uri5->withScheme(null); + +var_dump($uri4); +var_dump($uri5); +var_dump($uri6); + +?> +--EXPECTF-- +object(Uri\Rfc3986Uri)#1 (%d) { + ["scheme"]=> + string(5) "https" + ["user"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + NULL + ["query"]=> + NULL + ["fragment"]=> + NULL +} +object(Uri\Rfc3986Uri)#2 (%d) { + ["scheme"]=> + string(5) "https" + ["user"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + NULL + ["query"]=> + NULL + ["fragment"]=> + NULL +} +object(Uri\Rfc3986Uri)#3 (%d) { + ["scheme"]=> + string(5) "https" + ["user"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + NULL + ["query"]=> + NULL + ["fragment"]=> + NULL +} +object(Uri\WhatWgUri)#4 (%d) { + ["scheme"]=> + string(5) "https" + ["user"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + NULL + ["query"]=> + NULL + ["fragment"]=> + NULL +} +object(Uri\WhatWgUri)#5 (%d) { + ["scheme"]=> + string(5) "https" + ["user"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + NULL + ["query"]=> + NULL + ["fragment"]=> + NULL +} +object(Uri\WhatWgUri)#6 (%d) { + ["scheme"]=> + string(5) "https" + ["user"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + NULL + ["query"]=> + NULL + ["fragment"]=> + NULL +} diff --git a/ext/uri/tests/018.phpt b/ext/uri/tests/018.phpt new file mode 100644 index 0000000000000..5fc1d19847c68 --- /dev/null +++ b/ext/uri/tests/018.phpt @@ -0,0 +1,91 @@ +--TEST-- +Test property mutation +--EXTENSIONS-- +uri +--FILE-- + +--EXPECTF-- +object(Uri\Rfc3986Uri)#1 (%d) { + ["scheme"]=> + string(5) "https" + ["user"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + NULL + ["query"]=> + NULL + ["fragment"]=> + NULL +} +object(Uri\Rfc3986Uri)#2 (%d) { + ["scheme"]=> + string(5) "https" + ["user"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + NULL + ["query"]=> + NULL + ["fragment"]=> + NULL +} +object(Uri\WhatWgUri)#3 (%d) { + ["scheme"]=> + string(5) "https" + ["user"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + NULL + ["query"]=> + NULL + ["fragment"]=> + NULL +} +object(Uri\WhatWgUri)#4 (%d) { + ["scheme"]=> + string(5) "https" + ["user"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + NULL + ["query"]=> + NULL + ["fragment"]=> + NULL +} diff --git a/ext/uri/tests/020.phpt b/ext/uri/tests/020.phpt new file mode 100644 index 0000000000000..6a180f7ada18f --- /dev/null +++ b/ext/uri/tests/020.phpt @@ -0,0 +1,62 @@ +--TEST-- +Test unsetting URI properties +--EXTENSIONS-- +uri +--FILE-- +getMessage() . "\n"; + } +} + +function unsetMembers(\Uri\Uri $uri) +{ + handleException($uri, function (\Uri\Uri $uri) {unset($uri->scheme);}); + handleException($uri, function (\Uri\Uri $uri) {unset($uri->user);}); + handleException($uri, function (\Uri\Uri $uri) {unset($uri->password);}); + handleException($uri, function (\Uri\Uri $uri) {unset($uri->host);}); + handleException($uri, function (\Uri\Uri $uri) {unset($uri->port);}); + handleException($uri, function (\Uri\Uri $uri) {unset($uri->path);}); + handleException($uri, function (\Uri\Uri $uri) {unset($uri->query);}); + handleException($uri, function (\Uri\Uri $uri) {unset($uri->fragment);}); + handleException($uri, function (\Uri\Uri $uri) {unset($uri->foo);}); +} + +unsetMembers(new MyRfc3986Uri("https://example.com")); +unsetMembers(new MyWhatWgUri("https://example.com")); + +?> +--EXPECT-- +Cannot unset readonly property MyRfc3986Uri::$scheme +Cannot unset readonly property MyRfc3986Uri::$user +Cannot unset readonly property MyRfc3986Uri::$password +Cannot unset readonly property MyRfc3986Uri::$host +Cannot unset readonly property MyRfc3986Uri::$port +Cannot unset readonly property MyRfc3986Uri::$path +Cannot unset readonly property MyRfc3986Uri::$query +Cannot unset readonly property MyRfc3986Uri::$fragment +Cannot unset protected(set) readonly property MyRfc3986Uri::$foo from global scope +Cannot unset readonly property MyWhatWgUri::$scheme +Cannot unset readonly property MyWhatWgUri::$user +Cannot unset readonly property MyWhatWgUri::$password +Cannot unset readonly property MyWhatWgUri::$host +Cannot unset readonly property MyWhatWgUri::$port +Cannot unset readonly property MyWhatWgUri::$path +Cannot unset readonly property MyWhatWgUri::$query +Cannot unset readonly property MyWhatWgUri::$fragment +Cannot unset protected(set) readonly property MyWhatWgUri::$foo from global scope diff --git a/ext/uri/tests/021.phpt b/ext/uri/tests/021.phpt new file mode 100644 index 0000000000000..a42e72cb2cb9a --- /dev/null +++ b/ext/uri/tests/021.phpt @@ -0,0 +1,131 @@ +--TEST-- +Test cloning userland properties +--EXTENSIONS-- +uri +--FILE-- +foo = 1; + } + + public function __clone(): void + { + $this->foo = 2; + } +} + +readonly class MyWhatWgUri extends Uri\WhatWgUri +{ + public int $foo; + + public function setFoo(): void + { + $this->foo = 1; + } + + public function __clone(): void + { + $this->foo = 2; + } +} + +$uri1 = new MyRfc3986Uri("https://example.com"); +$uri1->setFoo(); +$uri2 = clone $uri1; +var_dump($uri1); +var_dump($uri2); + +$uri3 = new MyWhatWgUri("https://example.com"); +$uri3->setFoo(); +$uri4 = clone $uri3; +var_dump($uri3); +var_dump($uri4); + +?> +--EXPECTF-- +object(MyRfc3986Uri)#1 (%d) { + ["foo"]=> + int(1) + ["scheme"]=> + string(5) "https" + ["user"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + NULL + ["query"]=> + NULL + ["fragment"]=> + NULL +} +object(MyRfc3986Uri)#2 (%d) { + ["foo"]=> + int(2) + ["scheme"]=> + string(5) "https" + ["user"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + NULL + ["query"]=> + NULL + ["fragment"]=> + NULL +} +object(MyWhatWgUri)#3 (%d) { + ["foo"]=> + int(1) + ["scheme"]=> + string(5) "https" + ["user"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + NULL + ["query"]=> + NULL + ["fragment"]=> + NULL +} +object(MyWhatWgUri)#4 (%d) { + ["foo"]=> + int(2) + ["scheme"]=> + string(5) "https" + ["user"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + NULL + ["query"]=> + NULL + ["fragment"]=> + NULL +} diff --git a/ext/uri/tests/022.phpt b/ext/uri/tests/022.phpt new file mode 100644 index 0000000000000..24e9c2f73850b --- /dev/null +++ b/ext/uri/tests/022.phpt @@ -0,0 +1,41 @@ +--TEST-- +Test cloning error +--EXTENSIONS-- +uri +--FILE-- +getMessage() . "\n"; +} +var_dump($uri1); + +$uri3 = new MyWhatWgUri("https://example.com"); +try { + $uri4 = clone $uri3; +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} +var_dump($uri3); + +?> +--EXPECTF-- +MyRfc3986Uri object is not correctly initialized +object(MyRfc3986Uri)#1 (%d) { +} +MyWhatWgUri object is not correctly initialized +object(MyWhatWgUri)#2 (%d) { +}