php-src/ext/uri/php_uri_common.c
Máté Kocsis 5a9f5a6514
Add the Uri\Rfc3986\Uri class to ext/uri without wither support (#18836)
Relates to #14461 and https://wiki.php.net/rfc/url_parsing_api

Co-authored-by: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
Co-authored-by: Tim Düsterhus <tim@tideways-gmbh.com>
2025-07-05 10:00:20 +02:00

165 lines
5.6 KiB
C

/*
+----------------------------------------------------------------------+
| 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 <kocsismate@php.net> |
+----------------------------------------------------------------------+
*/
#include "php.h"
#include "Zend/zend_interfaces.h"
#include "Zend/zend_exceptions.h"
#include "php_uri_common.h"
const uri_property_handler_t *uri_property_handler_from_internal_uri(const uri_internal_t *internal_uri, uri_property_name_t property_name)
{
switch (property_name) {
case URI_PROPERTY_NAME_SCHEME:
return &internal_uri->handler->property_handlers.scheme;
case URI_PROPERTY_NAME_USERNAME:
return &internal_uri->handler->property_handlers.username;
case URI_PROPERTY_NAME_PASSWORD:
return &internal_uri->handler->property_handlers.password;
case URI_PROPERTY_NAME_HOST:
return &internal_uri->handler->property_handlers.host;
case URI_PROPERTY_NAME_PORT:
return &internal_uri->handler->property_handlers.port;
case URI_PROPERTY_NAME_PATH:
return &internal_uri->handler->property_handlers.path;
case URI_PROPERTY_NAME_QUERY:
return &internal_uri->handler->property_handlers.query;
case URI_PROPERTY_NAME_FRAGMENT:
return &internal_uri->handler->property_handlers.fragment;
EMPTY_SWITCH_DEFAULT_CASE()
}
}
static zend_string *get_known_string_by_property_name(uri_property_name_t property_name)
{
switch (property_name) {
case URI_PROPERTY_NAME_SCHEME:
return ZSTR_KNOWN(ZEND_STR_SCHEME);
case URI_PROPERTY_NAME_USERNAME:
return ZSTR_KNOWN(ZEND_STR_USERNAME);
case URI_PROPERTY_NAME_PASSWORD:
return ZSTR_KNOWN(ZEND_STR_PASSWORD);
case URI_PROPERTY_NAME_HOST:
return ZSTR_KNOWN(ZEND_STR_HOST);
case URI_PROPERTY_NAME_PORT:
return ZSTR_KNOWN(ZEND_STR_PORT);
case URI_PROPERTY_NAME_PATH:
return ZSTR_KNOWN(ZEND_STR_PATH);
case URI_PROPERTY_NAME_QUERY:
return ZSTR_KNOWN(ZEND_STR_QUERY);
case URI_PROPERTY_NAME_FRAGMENT:
return ZSTR_KNOWN(ZEND_STR_FRAGMENT);
EMPTY_SWITCH_DEFAULT_CASE()
}
}
void uri_read_component(INTERNAL_FUNCTION_PARAMETERS, uri_property_name_t property_name, uri_component_read_mode_t component_read_mode)
{
ZEND_PARSE_PARAMETERS_NONE();
uri_internal_t *internal_uri = Z_URI_INTERNAL_P(ZEND_THIS);
URI_ASSERT_INITIALIZATION(internal_uri);
const uri_property_handler_t *property_handler = uri_property_handler_from_internal_uri(internal_uri, property_name);
ZEND_ASSERT(property_handler != NULL);
if (UNEXPECTED(property_handler->read_func(internal_uri, component_read_mode, return_value) == FAILURE)) {
zend_throw_error(NULL, "The %s component cannot be retrieved", ZSTR_VAL(get_known_string_by_property_name(property_name)));
RETURN_THROWS();
}
}
static void uri_write_component_ex(INTERNAL_FUNCTION_PARAMETERS, uri_property_name_t property_name, zval *property_zv)
{
uri_internal_t *internal_uri = Z_URI_INTERNAL_P(ZEND_THIS);
URI_ASSERT_INITIALIZATION(internal_uri);
const uri_property_handler_t *property_handler = uri_property_handler_from_internal_uri(internal_uri, property_name);
ZEND_ASSERT(property_handler != NULL);
zend_object *new_object = uri_clone_obj_handler(Z_OBJ_P(ZEND_THIS));
ZEND_ASSERT(new_object != NULL);
uri_internal_t *new_internal_uri = uri_internal_from_obj(new_object);
URI_ASSERT_INITIALIZATION(new_internal_uri);
if (UNEXPECTED(property_handler->write_func == NULL)) {
zend_readonly_property_modification_error_ex(ZSTR_VAL(Z_OBJ_P(ZEND_THIS)->ce->name),
ZSTR_VAL(get_known_string_by_property_name(property_name)));
zend_object_release(new_object);
RETURN_THROWS();
}
zval errors;
ZVAL_UNDEF(&errors);
if (UNEXPECTED(property_handler->write_func(new_internal_uri, property_zv, &errors) == FAILURE)) {
zval_ptr_dtor(&errors);
zend_object_release(new_object);
RETURN_THROWS();
}
ZEND_ASSERT(Z_ISUNDEF(errors));
RETVAL_OBJ(new_object);
}
void uri_write_component_str(INTERNAL_FUNCTION_PARAMETERS, uri_property_name_t property_name)
{
zend_string *value;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_PATH_STR(value)
ZEND_PARSE_PARAMETERS_END();
zval zv;
ZVAL_STR(&zv, value);
uri_write_component_ex(INTERNAL_FUNCTION_PARAM_PASSTHRU, property_name, &zv);
}
void uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAMETERS, uri_property_name_t property_name)
{
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);
}
uri_write_component_ex(INTERNAL_FUNCTION_PARAM_PASSTHRU, property_name, &zv);
}
void uri_write_component_long_or_null(INTERNAL_FUNCTION_PARAMETERS, uri_property_name_t property_name)
{
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_write_component_ex(INTERNAL_FUNCTION_PARAM_PASSTHRU, property_name, &zv);
}