diff --git a/UPGRADING b/UPGRADING index 0e4a5288d680..d426f960abea 100644 --- a/UPGRADING +++ b/UPGRADING @@ -326,6 +326,10 @@ PHP 8.6 UPGRADE NOTES system. - URI: + . __construct(), parse(), and with*() of Uri\WhatWg\Url, and + Uri\WhatWg\UrlBuilder::build() now report validation errors in the order + in which they are detected. This reverses the order of multiple errors + compared to PHP 8.5. . Uri\WhatWg\Url::__construct() now sets $softErrors to an empty array when URL processing throws an exception, instead of preserving its value. URL validation errors remain available in the diff --git a/ext/uri/tests/whatwg/builder/build_error_soft_errors_reset_with_base.phpt b/ext/uri/tests/whatwg/builder/build_error_soft_errors_reset_with_base.phpt index b1a8b221849e..5ac520b2ebcf 100644 --- a/ext/uri/tests/whatwg/builder/build_error_soft_errors_reset_with_base.phpt +++ b/ext/uri/tests/whatwg/builder/build_error_soft_errors_reset_with_base.phpt @@ -21,7 +21,7 @@ var_dump($softErrors); ?> --EXPECT-- Uri\WhatWg\InvalidUrlException: The specified path is malformed (MissingSchemeNonRelativeUrl) -enum(Uri\WhatWg\UrlValidationErrorType::MissingSchemeNonRelativeUrl) enum(Uri\WhatWg\UrlValidationErrorType::InvalidUrlUnit) +enum(Uri\WhatWg\UrlValidationErrorType::MissingSchemeNonRelativeUrl) array(0) { } diff --git a/ext/uri/tests/whatwg/builder/build_error_soft_errors_reset_without_base.phpt b/ext/uri/tests/whatwg/builder/build_error_soft_errors_reset_without_base.phpt index f43ab31164bf..95f3d690afa0 100644 --- a/ext/uri/tests/whatwg/builder/build_error_soft_errors_reset_without_base.phpt +++ b/ext/uri/tests/whatwg/builder/build_error_soft_errors_reset_without_base.phpt @@ -3,6 +3,14 @@ Test Uri\WhatWg\UrlBuilder::build() - error - clears soft errors when an excepti --FILE-- errors; +} + $builder = new Uri\WhatWg\UrlBuilder(); $builder->setScheme("ht\ttps"); $builder->setHost(null); @@ -13,6 +21,10 @@ try { } catch (Throwable $e) { echo $e::class, ': ', $e->getMessage(), "\n"; var_dump($e->errors); + var_dump( + array_map(static fn($error) => $error->type, $e->errors) + === array_map(static fn($error) => $error->type, $referenceErrors) + ); } var_dump($softErrors); @@ -40,5 +52,6 @@ array(2) { bool(true) } } +bool(true) array(0) { } diff --git a/ext/uri/tests/whatwg/builder/build_success_validation_warning_order_without_base.phpt b/ext/uri/tests/whatwg/builder/build_success_validation_warning_order_without_base.phpt new file mode 100644 index 000000000000..815d48c422c5 --- /dev/null +++ b/ext/uri/tests/whatwg/builder/build_success_validation_warning_order_without_base.phpt @@ -0,0 +1,67 @@ +--TEST-- +Test Uri\WhatWg\UrlBuilder::build() - success - validation warning order without base URL +--FILE-- +setScheme('https') + ->setHost('127.0.0.1.') + ->setPath('\newPath') + ->build(null, $errors); + +var_dump($url->toAsciiString()); +var_dump($url); +var_dump($errors); +var_dump($errors == $referenceErrors); +var_dump($url->equals(new Uri\WhatWg\Url($url->toAsciiString()))); +var_dump($url->equals($reference, Uri\UriComparisonMode::IncludeFragment)); + +?> +--EXPECTF-- +string(25) "https://127.0.0.1/newPath" +object(Uri\WhatWg\Url)#%d (%d) { + ["scheme"]=> + string(5) "https" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(9) "127.0.0.1" + ["port"]=> + NULL + ["path"]=> + string(8) "/newPath" + ["query"]=> + NULL + ["fragment"]=> + NULL +} +array(2) { + [0]=> + object(Uri\WhatWg\UrlValidationError)#%d (%d) { + ["context"]=> + string(0) "" + ["type"]=> + enum(Uri\WhatWg\UrlValidationErrorType::Ipv4EmptyPart) + ["failure"]=> + bool(false) + } + [1]=> + object(Uri\WhatWg\UrlValidationError)#%d (%d) { + ["context"]=> + string(8) "\newPath" + ["type"]=> + enum(Uri\WhatWg\UrlValidationErrorType::InvalidReverseSoldius) + ["failure"]=> + bool(false) + } +} +bool(true) +bool(true) +bool(true) diff --git a/ext/uri/tests/whatwg/builder/path_success_opaque_spaces.phpt b/ext/uri/tests/whatwg/builder/path_success_opaque_spaces.phpt index c66d10f29f50..80c30d8a7b80 100644 --- a/ext/uri/tests/whatwg/builder/path_success_opaque_spaces.phpt +++ b/ext/uri/tests/whatwg/builder/path_success_opaque_spaces.phpt @@ -39,7 +39,7 @@ array(3) { [0]=> object(Uri\WhatWg\UrlValidationError)#%d (%d) { ["context"]=> - string(1) " " + string(6) " abc " ["type"]=> enum(Uri\WhatWg\UrlValidationErrorType::InvalidUrlUnit) ["failure"]=> @@ -57,7 +57,7 @@ array(3) { [2]=> object(Uri\WhatWg\UrlValidationError)#%d (%d) { ["context"]=> - string(6) " abc " + string(1) " " ["type"]=> enum(Uri\WhatWg\UrlValidationErrorType::InvalidUrlUnit) ["failure"]=> diff --git a/ext/uri/tests/whatwg/builder/path_success_opaque_spaces_with_fragment.phpt b/ext/uri/tests/whatwg/builder/path_success_opaque_spaces_with_fragment.phpt index b6d72abded4c..f1bd6860c96a 100644 --- a/ext/uri/tests/whatwg/builder/path_success_opaque_spaces_with_fragment.phpt +++ b/ext/uri/tests/whatwg/builder/path_success_opaque_spaces_with_fragment.phpt @@ -40,7 +40,7 @@ array(2) { [0]=> object(Uri\WhatWg\UrlValidationError)#%d (%d) { ["context"]=> - string(2) " #" + string(3) " #" ["type"]=> enum(Uri\WhatWg\UrlValidationErrorType::InvalidUrlUnit) ["failure"]=> @@ -49,7 +49,7 @@ array(2) { [1]=> object(Uri\WhatWg\UrlValidationError)#%d (%d) { ["context"]=> - string(3) " #" + string(2) " #" ["type"]=> enum(Uri\WhatWg\UrlValidationErrorType::InvalidUrlUnit) ["failure"]=> diff --git a/ext/uri/tests/whatwg/builder/path_success_opaque_spaces_with_query.phpt b/ext/uri/tests/whatwg/builder/path_success_opaque_spaces_with_query.phpt index d719feafc3d8..9a52a7c97651 100644 --- a/ext/uri/tests/whatwg/builder/path_success_opaque_spaces_with_query.phpt +++ b/ext/uri/tests/whatwg/builder/path_success_opaque_spaces_with_query.phpt @@ -40,7 +40,7 @@ array(2) { [0]=> object(Uri\WhatWg\UrlValidationError)#%d (%d) { ["context"]=> - string(2) " ?" + string(3) " ?" ["type"]=> enum(Uri\WhatWg\UrlValidationErrorType::InvalidUrlUnit) ["failure"]=> @@ -49,7 +49,7 @@ array(2) { [1]=> object(Uri\WhatWg\UrlValidationError)#%d (%d) { ["context"]=> - string(3) " ?" + string(2) " ?" ["type"]=> enum(Uri\WhatWg\UrlValidationErrorType::InvalidUrlUnit) ["failure"]=> diff --git a/ext/uri/tests/whatwg/modification/withPath_success_file_invalid_drive_letter.phpt b/ext/uri/tests/whatwg/modification/withPath_success_file_invalid_drive_letter.phpt index 39ed5d30a4fc..f57c8b0da2a7 100644 --- a/ext/uri/tests/whatwg/modification/withPath_success_file_invalid_drive_letter.phpt +++ b/ext/uri/tests/whatwg/modification/withPath_success_file_invalid_drive_letter.phpt @@ -14,8 +14,8 @@ var_dump($url->withPath("/zz")->getPath()); string(5) "/c:/x" array(2) { [0]=> - string(14) "InvalidUrlUnit" - [1]=> string(29) "FileInvalidWindowsDriveLetter" + [1]=> + string(14) "InvalidUrlUnit" } string(3) "/zz" diff --git a/ext/uri/tests/whatwg/parsing/basic_success_invalid_url_unit_warnings.phpt b/ext/uri/tests/whatwg/parsing/basic_success_invalid_url_unit_warnings.phpt index 4ee2a3d3b921..db989449071e 100644 --- a/ext/uri/tests/whatwg/parsing/basic_success_invalid_url_unit_warnings.phpt +++ b/ext/uri/tests/whatwg/parsing/basic_success_invalid_url_unit_warnings.phpt @@ -35,7 +35,7 @@ array(2) { [0]=> object(Uri\WhatWg\UrlValidationError)#%d (%d) { ["context"]=> - string(1) " " + string(21) " https://example.org " ["type"]=> enum(Uri\WhatWg\UrlValidationErrorType::InvalidUrlUnit) ["failure"]=> @@ -44,7 +44,7 @@ array(2) { [1]=> object(Uri\WhatWg\UrlValidationError)#%d (%d) { ["context"]=> - string(21) " https://example.org " + string(1) " " ["type"]=> enum(Uri\WhatWg\UrlValidationErrorType::InvalidUrlUnit) ["failure"]=> diff --git a/ext/uri/uri_parser_whatwg.c b/ext/uri/uri_parser_whatwg.c index 2c123cd238d2..2d2f4a81b8cd 100644 --- a/ext/uri/uri_parser_whatwg.c +++ b/ext/uri/uri_parser_whatwg.c @@ -173,14 +173,17 @@ ZEND_ATTRIBUTE_NONNULL static bool append_validation_error( ZEND_ATTRIBUTE_NONNULL static const char *fill_errors_inner(HashTable *errors) { const char *result = NULL; + lexbor_plog_t *log = lexbor_parser.log; + const size_t length = lexbor_plog_length(log); - lexbor_plog_entry_t *lxb_error; - while ((lxb_error = lexbor_array_obj_pop(&lexbor_parser.log->list)) != NULL) { + for (size_t i = 0; i < length; i++) { + const lexbor_plog_entry_t *lxb_error = lexbor_array_obj_get(&log->list, i); const char *reason; - if (append_validation_error(errors, lxb_error->id, (const char *) lxb_error->data, &reason)) { + if (append_validation_error(errors, lxb_error->id, (const char *) lxb_error->data, &reason) && result == NULL) { result = reason; } } + lexbor_plog_clean(log); return result; }