uri: Do not create new UrlValidationErrorType objects (#19009)

`zend_enum_new()` is not intended to be used “at runtime”, since it will create
a new object, breaking the singleton property. Instead
`zend_enum_get_case_cstr()` must be used.
This commit is contained in:
Tim Düsterhus 2025-07-02 13:57:50 +02:00 committed by GitHub
parent f906fad985
commit ec8b016d08
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 59 additions and 39 deletions

4
NEWS
View file

@ -2,6 +2,10 @@ PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? ????, PHP 8.5.0alpha2
- URI:
. Return the singleton UrlValidationErrorType instances from Uri\WhatWg\Url
instead of creating new objects that are different from the singleton.
(timwolla)
03 Jul 2025, PHP 8.5.0alpha1

View file

@ -73,7 +73,7 @@ static void lexbor_cleanup_parser(void)
* When errors is NULL, the caller is not interested in the additional error information,
* so the function does nothing.
*/
static zend_string *fill_errors(zval *errors)
static const char *fill_errors(zval *errors)
{
if (errors == NULL) {
return NULL;
@ -87,140 +87,138 @@ static zend_string *fill_errors(zval *errors)
return NULL;
}
zend_string *result = NULL;
const char *result = NULL;
lexbor_plog_entry_t *lxb_error;
while ((lxb_error = lexbor_array_obj_pop(&lexbor_parser.log->list)) != NULL) {
zval error;
object_init_ex(&error, uri_whatwg_url_validation_error_ce);
zend_update_property_string(uri_whatwg_url_validation_error_ce, Z_OBJ(error), ZEND_STRL("context"), (const char *) lxb_error->data);
zend_string *error_str;
const char *error_str;
zval failure;
switch (lxb_error->id) {
case LXB_URL_ERROR_TYPE_DOMAIN_TO_ASCII:
error_str = ZSTR_INIT_LITERAL("DomainToAscii", false);
error_str = "DomainToAscii";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_DOMAIN_TO_UNICODE:
error_str = ZSTR_INIT_LITERAL("DomainToUnicode", false);
error_str = "DomainToUnicode";
ZVAL_FALSE(&failure);
break;
case LXB_URL_ERROR_TYPE_DOMAIN_INVALID_CODE_POINT:
error_str = ZSTR_INIT_LITERAL("DomainInvalidCodePoint", false);
error_str = "DomainInvalidCodePoint";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_HOST_INVALID_CODE_POINT:
error_str = ZSTR_INIT_LITERAL("HostInvalidCodePoint", false);
error_str = "HostInvalidCodePoint";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV4_EMPTY_PART:
error_str = ZSTR_INIT_LITERAL("Ipv4EmptyPart", false);
error_str = "Ipv4EmptyPart";
ZVAL_FALSE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV4_TOO_MANY_PARTS:
error_str = ZSTR_INIT_LITERAL("Ipv4TooManyParts", false);
error_str = "Ipv4TooManyParts";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV4_NON_NUMERIC_PART:
error_str = ZSTR_INIT_LITERAL("Ipv4NonNumericPart", false);
error_str = "Ipv4NonNumericPart";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV4_NON_DECIMAL_PART:
error_str = ZSTR_INIT_LITERAL("Ipv4NonDecimalPart", false);
error_str = "Ipv4NonDecimalPart";
ZVAL_FALSE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV4_OUT_OF_RANGE_PART:
error_str = ZSTR_INIT_LITERAL("Ipv4OutOfRangePart", false);
error_str = "Ipv4OutOfRangePart";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV6_UNCLOSED:
error_str = ZSTR_INIT_LITERAL("Ipv6Unclosed", false);
error_str = "Ipv6Unclosed";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV6_INVALID_COMPRESSION:
error_str = ZSTR_INIT_LITERAL("Ipv6InvalidCompression", false);
error_str = "Ipv6InvalidCompression";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV6_TOO_MANY_PIECES:
error_str = ZSTR_INIT_LITERAL("Ipv6TooManyPieces", false);
error_str = "Ipv6TooManyPieces";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV6_MULTIPLE_COMPRESSION:
error_str = ZSTR_INIT_LITERAL("Ipv6MultipleCompression", false);
error_str = "Ipv6MultipleCompression";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV6_INVALID_CODE_POINT:
error_str = ZSTR_INIT_LITERAL("Ipv6InvalidCodePoint", false);
error_str = "Ipv6InvalidCodePoint";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV6_TOO_FEW_PIECES:
error_str = ZSTR_INIT_LITERAL("Ipv6TooFewPieces", false);
error_str = "Ipv6TooFewPieces";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV4_IN_IPV6_TOO_MANY_PIECES:
error_str = ZSTR_INIT_LITERAL("Ipv4InIpv6TooManyPieces", false);
error_str = "Ipv4InIpv6TooManyPieces";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV4_IN_IPV6_INVALID_CODE_POINT:
error_str = ZSTR_INIT_LITERAL("Ipv4InIpv6InvalidCodePoint", false);
error_str = "Ipv4InIpv6InvalidCodePoint";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV4_IN_IPV6_OUT_OF_RANGE_PART:
error_str = ZSTR_INIT_LITERAL("Ipv4InIpv6OutOfRangePart", false);
error_str = "Ipv4InIpv6OutOfRangePart";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV4_IN_IPV6_TOO_FEW_PARTS:
error_str = ZSTR_INIT_LITERAL("Ipv4InIpv6TooFewParts", false);
error_str = "Ipv4InIpv6TooFewParts";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_INVALID_URL_UNIT:
error_str = ZSTR_INIT_LITERAL("InvalidUrlUnit", false);
error_str = "InvalidUrlUnit";
ZVAL_FALSE(&failure);
break;
case LXB_URL_ERROR_TYPE_SPECIAL_SCHEME_MISSING_FOLLOWING_SOLIDUS:
error_str = ZSTR_INIT_LITERAL("SpecialSchemeMissingFollowingSolidus", false);
error_str = "SpecialSchemeMissingFollowingSolidus";
ZVAL_FALSE(&failure);
break;
case LXB_URL_ERROR_TYPE_MISSING_SCHEME_NON_RELATIVE_URL:
error_str = ZSTR_INIT_LITERAL("MissingSchemeNonRelativeUrl", false);
error_str = "MissingSchemeNonRelativeUrl";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_INVALID_REVERSE_SOLIDUS:
error_str = ZSTR_INIT_LITERAL("InvalidReverseSoldius", false);
error_str = "InvalidReverseSoldius";
ZVAL_FALSE(&failure);
break;
case LXB_URL_ERROR_TYPE_INVALID_CREDENTIALS:
error_str = ZSTR_INIT_LITERAL("InvalidCredentials", false);
error_str = "InvalidCredentials";
ZVAL_FALSE(&failure);
break;
case LXB_URL_ERROR_TYPE_HOST_MISSING:
error_str = ZSTR_INIT_LITERAL("HostMissing", false);
error_str = "HostMissing";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_PORT_OUT_OF_RANGE:
error_str = ZSTR_INIT_LITERAL("PortOutOfRange", false);
error_str = "PortOutOfRange";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_PORT_INVALID:
error_str = ZSTR_INIT_LITERAL("PortInvalid", false);
error_str = "PortInvalid";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_FILE_INVALID_WINDOWS_DRIVE_LETTER:
error_str = ZSTR_INIT_LITERAL("FileInvalidWindowsDriveLetter", false);
error_str = "FileInvalidWindowsDriveLetter";
ZVAL_FALSE(&failure);
break;
case LXB_URL_ERROR_TYPE_FILE_INVALID_WINDOWS_DRIVE_LETTER_HOST:
error_str = ZSTR_INIT_LITERAL("FileInvalidWindowsDriveLetterHost", false);
error_str = "FileInvalidWindowsDriveLetterHost";
ZVAL_FALSE(&failure);
break;
EMPTY_SWITCH_DEFAULT_CASE()
}
zval error_type;
zend_enum_new(&error_type, uri_whatwg_url_validation_error_type_ce, error_str, NULL);
ZVAL_OBJ(&error_type, zend_enum_get_case_cstr(uri_whatwg_url_validation_error_type_ce, error_str));
zend_update_property_ex(uri_whatwg_url_validation_error_ce, Z_OBJ(error), ZSTR_KNOWN(ZEND_STR_TYPE), &error_type);
zend_string_release_ex(error_str, false);
zval_ptr_dtor(&error_type);
zend_update_property(uri_whatwg_url_validation_error_ce, Z_OBJ(error), ZEND_STRL("failure"), &failure);
@ -236,14 +234,14 @@ static zend_string *fill_errors(zval *errors)
static void throw_invalid_url_exception_during_write(zval *errors, const char *component)
{
zend_string *reason = fill_errors(errors);
const char *reason = fill_errors(errors);
zend_object *exception = zend_throw_exception_ex(
uri_whatwg_invalid_url_exception_ce,
0,
"The specified %s is malformed%s%s%s",
component,
reason ? " (" : "",
reason ? ZSTR_VAL(reason) : "",
reason ? reason : "",
reason ? ")" : ""
);
zend_update_property(exception->ce, exception, ZEND_STRL("errors"), errors);
@ -567,10 +565,10 @@ lxb_url_t *lexbor_parse_uri_ex(const zend_string *uri_str, const lxb_url_t *lexb
lexbor_cleanup_parser();
lxb_url_t *url = lxb_url_parse(&lexbor_parser, lexbor_base_url, (unsigned char *) ZSTR_VAL(uri_str), ZSTR_LEN(uri_str));
zend_string *reason = fill_errors(errors);
const char *reason = fill_errors(errors);
if (url == NULL && !silent) {
zend_object *exception = zend_throw_exception_ex(uri_whatwg_invalid_url_exception_ce, 0, "The specified URI is malformed%s%s%s", reason ? " (" : "", reason ? ZSTR_VAL(reason) : "", reason ? ")" : "");
zend_object *exception = zend_throw_exception_ex(uri_whatwg_invalid_url_exception_ce, 0, "The specified URI is malformed%s%s%s", reason ? " (" : "", reason ? reason : "", reason ? ")" : "");
zend_update_property(exception->ce, exception, ZEND_STRL("errors"), errors);
}

18
ext/uri/tests/054.phpt Normal file
View file

@ -0,0 +1,18 @@
--TEST--
Test UrlValidationErrorType singleton
--EXTENSIONS--
uri
--FILE--
<?php
try {
new \Uri\WhatWg\Url('http://localhost:99999');
} catch (Uri\WhatWg\InvalidUrlException $e) {
echo $e->getMessage() . "\n";
var_dump($e->errors[0]->type === \Uri\WhatWg\UrlValidationErrorType::PortOutOfRange);
}
?>
--EXPECT--
The specified URI is malformed (PortOutOfRange)
bool(true)