From 3399235bec275516f6b87714087526d36d6f6976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Tue, 10 Jun 2025 10:18:22 +0200 Subject: [PATCH 001/120] Add Uri\WhatWg classes to ext/uri (#18672) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- UPGRADING.INTERNALS | 3 + Zend/zend_exceptions.c | 61 ++-- Zend/zend_exceptions.h | 2 + Zend/zend_string.h | 2 + build/gen_stub.php | 2 + ext/uri/config.m4 | 4 +- ext/uri/config.w32 | 4 +- ext/uri/php_lexbor.c | 639 ++++++++++++++++++++++++++++++++++++++ ext/uri/php_lexbor.h | 30 ++ ext/uri/php_uri.c | 614 +++++++++++++++++++++++++++++++++++- ext/uri/php_uri.h | 3 + ext/uri/php_uri.stub.php | 110 +++++++ ext/uri/php_uri_arginfo.h | 290 ++++++++++++++++- ext/uri/php_uri_common.c | 169 ++++++++++ ext/uri/php_uri_common.h | 138 ++++++++ ext/uri/tests/003.phpt | 32 ++ ext/uri/tests/004.phpt | 25 ++ ext/uri/tests/005.phpt | 38 +++ ext/uri/tests/006.phpt | 30 ++ ext/uri/tests/007.phpt | 63 ++++ ext/uri/tests/008.phpt | 34 ++ ext/uri/tests/009.phpt | 29 ++ ext/uri/tests/010.phpt | 48 +++ ext/uri/tests/011.phpt | 22 ++ ext/uri/tests/012.phpt | 49 +++ ext/uri/tests/013.phpt | 87 ++++++ ext/uri/tests/014.phpt | 12 + ext/uri/tests/015.phpt | 18 ++ ext/uri/tests/018.phpt | 50 +++ ext/uri/tests/019.phpt | 55 ++++ ext/uri/tests/022.phpt | 14 + ext/uri/tests/023.phpt | 31 ++ ext/uri/tests/024.phpt | 29 ++ ext/uri/tests/025.phpt | 29 ++ ext/uri/tests/026.phpt | 67 ++++ ext/uri/tests/027.phpt | 36 +++ ext/uri/tests/028.phpt | 37 +++ ext/uri/tests/029.phpt | 40 +++ ext/uri/tests/030.phpt | 31 ++ ext/uri/tests/031.phpt | 98 ++++++ ext/uri/tests/032.phpt | 13 + ext/uri/tests/033.phpt | 15 + ext/uri/tests/034.phpt | 14 + ext/uri/tests/035.phpt | 24 ++ ext/uri/tests/036.phpt | 24 ++ ext/uri/tests/038.phpt | 26 ++ ext/uri/tests/039.phpt | 34 ++ ext/uri/tests/040.phpt | 32 ++ ext/uri/tests/041.phpt | 26 ++ ext/uri/tests/042.phpt | 29 ++ ext/uri/tests/043.phpt | 71 +++++ ext/uri/tests/045.phpt | 16 + ext/uri/tests/046.phpt | 30 ++ ext/uri/tests/047.phpt | 27 ++ ext/uri/tests/049.phpt | 13 + ext/uri/tests/050.phpt | 16 + ext/uri/tests/051.phpt | 35 +++ ext/uri/tests/052.phpt | 28 ++ ext/uri/tests/053.phpt | 63 ++++ 59 files changed, 3565 insertions(+), 46 deletions(-) create mode 100644 ext/uri/php_lexbor.c create mode 100644 ext/uri/php_lexbor.h create mode 100644 ext/uri/php_uri_common.c create mode 100644 ext/uri/php_uri_common.h create mode 100644 ext/uri/tests/003.phpt create mode 100644 ext/uri/tests/004.phpt create mode 100644 ext/uri/tests/005.phpt create mode 100644 ext/uri/tests/006.phpt create mode 100644 ext/uri/tests/007.phpt create mode 100644 ext/uri/tests/008.phpt create mode 100644 ext/uri/tests/009.phpt create mode 100644 ext/uri/tests/010.phpt create mode 100644 ext/uri/tests/011.phpt create mode 100644 ext/uri/tests/012.phpt create mode 100644 ext/uri/tests/013.phpt create mode 100644 ext/uri/tests/014.phpt create mode 100644 ext/uri/tests/015.phpt create mode 100644 ext/uri/tests/018.phpt create mode 100644 ext/uri/tests/019.phpt create mode 100644 ext/uri/tests/022.phpt create mode 100644 ext/uri/tests/023.phpt create mode 100644 ext/uri/tests/024.phpt create mode 100644 ext/uri/tests/025.phpt create mode 100644 ext/uri/tests/026.phpt create mode 100644 ext/uri/tests/027.phpt create mode 100644 ext/uri/tests/028.phpt create mode 100644 ext/uri/tests/029.phpt create mode 100644 ext/uri/tests/030.phpt create mode 100644 ext/uri/tests/031.phpt create mode 100644 ext/uri/tests/032.phpt create mode 100644 ext/uri/tests/033.phpt create mode 100644 ext/uri/tests/034.phpt create mode 100644 ext/uri/tests/035.phpt create mode 100644 ext/uri/tests/036.phpt create mode 100644 ext/uri/tests/038.phpt create mode 100644 ext/uri/tests/039.phpt create mode 100644 ext/uri/tests/040.phpt create mode 100644 ext/uri/tests/041.phpt create mode 100644 ext/uri/tests/042.phpt create mode 100644 ext/uri/tests/043.phpt create mode 100644 ext/uri/tests/045.phpt create mode 100644 ext/uri/tests/046.phpt create mode 100644 ext/uri/tests/047.phpt create mode 100644 ext/uri/tests/049.phpt create mode 100644 ext/uri/tests/050.phpt create mode 100644 ext/uri/tests/051.phpt create mode 100644 ext/uri/tests/052.phpt create mode 100644 ext/uri/tests/053.phpt diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 574d5f0827ff7..e4cf9e9c94b0d 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -34,6 +34,9 @@ PHP 8.5 INTERNALS UPGRADE NOTES . Added ZEND_NONSTRING attribute macro for character arrays that do not represent strings. This allows to silence the GCC 15.x `-Wunterminated-string-initialization` warning. + . Added the zend_update_exception_properties() function for instantiating + Exception child classes. It updates the $message, $code, and $previous + properties. ======================== 2. Build system changes diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index 7777c5fa62e48..ab9c815718a0d 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -329,24 +329,15 @@ ZEND_COLD ZEND_METHOD(Exception, __clone) } /* }}} */ -/* {{{ Exception constructor */ -ZEND_METHOD(Exception, __construct) +ZEND_API zend_result zend_update_exception_properties(INTERNAL_FUNCTION_PARAMETERS, zend_string *message, zend_long code, zval *previous) { - zend_string *message = NULL; - zend_long code = 0; - zval tmp, *object, *previous = NULL; - - object = ZEND_THIS; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|SlO!", &message, &code, &previous, zend_ce_throwable) == FAILURE) { - RETURN_THROWS(); - } + zval tmp, *object = ZEND_THIS; if (message) { ZVAL_STR_COPY(&tmp, message); zend_update_property_num_checked(NULL, Z_OBJ_P(object), ZEND_EXCEPTION_MESSAGE_OFF, ZSTR_KNOWN(ZEND_STR_MESSAGE), &tmp); if (UNEXPECTED(EG(exception))) { - RETURN_THROWS(); + return FAILURE; } } @@ -354,7 +345,7 @@ ZEND_METHOD(Exception, __construct) ZVAL_LONG(&tmp, code); zend_update_property_num_checked(NULL, Z_OBJ_P(object), ZEND_EXCEPTION_CODE_OFF, ZSTR_KNOWN(ZEND_STR_CODE), &tmp); if (UNEXPECTED(EG(exception))) { - RETURN_THROWS(); + return FAILURE; } } @@ -362,9 +353,27 @@ ZEND_METHOD(Exception, __construct) Z_ADDREF_P(previous); zend_update_property_num_checked(zend_ce_exception, Z_OBJ_P(object), ZEND_EXCEPTION_PREVIOUS_OFF, ZSTR_KNOWN(ZEND_STR_PREVIOUS), previous); if (UNEXPECTED(EG(exception))) { - RETURN_THROWS(); + return FAILURE; } } + + return SUCCESS; +} + +/* {{{ Exception constructor */ +ZEND_METHOD(Exception, __construct) +{ + zend_string *message = NULL; + zend_long code = 0; + zval *previous = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|SlO!", &message, &code, &previous, zend_ce_throwable) == FAILURE) { + RETURN_THROWS(); + } + + if (zend_update_exception_properties(INTERNAL_FUNCTION_PARAM_PASSTHRU, message, code, previous) == FAILURE) { + RETURN_THROWS(); + } } /* }}} */ @@ -401,28 +410,8 @@ ZEND_METHOD(ErrorException, __construct) object = ZEND_THIS; - if (message) { - ZVAL_STR_COPY(&tmp, message); - zend_update_property_num_checked(NULL, Z_OBJ_P(object), ZEND_EXCEPTION_MESSAGE_OFF, ZSTR_KNOWN(ZEND_STR_MESSAGE), &tmp); - if (UNEXPECTED(EG(exception))) { - RETURN_THROWS(); - } - } - - if (code) { - ZVAL_LONG(&tmp, code); - zend_update_property_num_checked(NULL, Z_OBJ_P(object), ZEND_EXCEPTION_CODE_OFF, ZSTR_KNOWN(ZEND_STR_CODE), &tmp); - if (UNEXPECTED(EG(exception))) { - RETURN_THROWS(); - } - } - - if (previous) { - Z_ADDREF_P(previous); - zend_update_property_num_checked(zend_ce_exception, Z_OBJ_P(object), ZEND_EXCEPTION_PREVIOUS_OFF, ZSTR_KNOWN(ZEND_STR_PREVIOUS), previous); - if (UNEXPECTED(EG(exception))) { - RETURN_THROWS(); - } + if (zend_update_exception_properties(INTERNAL_FUNCTION_PARAM_PASSTHRU, message, code, previous) == FAILURE) { + RETURN_THROWS(); } ZVAL_LONG(&tmp, severity); diff --git a/Zend/zend_exceptions.h b/Zend/zend_exceptions.h index d0138021d1ea3..86dc379cce871 100644 --- a/Zend/zend_exceptions.h +++ b/Zend/zend_exceptions.h @@ -69,6 +69,8 @@ ZEND_API zend_object *zend_throw_error_exception(zend_class_entry *exception_ce, extern ZEND_API void (*zend_throw_exception_hook)(zend_object *ex); +ZEND_API zend_result zend_update_exception_properties(INTERNAL_FUNCTION_PARAMETERS, zend_string *message, zend_long code, zval *previous); + /* show an exception using zend_error(severity,...), severity should be E_ERROR */ ZEND_API ZEND_COLD zend_result zend_exception_error(zend_object *exception, int severity); ZEND_NORETURN void zend_exception_uncaught_error(const char *prefix, ...) ZEND_ATTRIBUTE_FORMAT(printf, 1, 2); diff --git a/Zend/zend_string.h b/Zend/zend_string.h index e9e2b947a6c91..0b2a484016ec3 100644 --- a/Zend/zend_string.h +++ b/Zend/zend_string.h @@ -597,7 +597,9 @@ EMPTY_SWITCH_DEFAULT_CASE() _(ZEND_STR_HOST, "host") \ _(ZEND_STR_PORT, "port") \ _(ZEND_STR_USER, "user") \ + _(ZEND_STR_USERNAME, "username") \ _(ZEND_STR_PASS, "pass") \ + _(ZEND_STR_PASSWORD, "password") \ _(ZEND_STR_PATH, "path") \ _(ZEND_STR_QUERY, "query") \ _(ZEND_STR_FRAGMENT, "fragment") \ diff --git a/build/gen_stub.php b/build/gen_stub.php index 13ef9e60f334d..0e87cdd9a0b40 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -3055,6 +3055,8 @@ class PropertyInfo extends VariableLike private const PHP_85_KNOWN = [ "self" => "ZEND_STR_SELF", "parent" => "ZEND_STR_PARENT", + "username" => "ZEND_STR_USERNAME", + "password" => "ZEND_STR_PASSWORD", ]; /** diff --git a/ext/uri/config.m4 b/ext/uri/config.m4 index f29bbe58bd32e..08dc044d8d29f 100644 --- a/ext/uri/config.m4 +++ b/ext/uri/config.m4 @@ -2,7 +2,9 @@ dnl Configure options dnl PHP_INSTALL_HEADERS([ext/uri], m4_normalize([ + php_lexbor.h php_uri.h + php_uri_common.h ])) AC_DEFINE([URI_ENABLE_ANSI], [1], [Define to 1 for enabling ANSI support of uriparser.]) @@ -15,6 +17,6 @@ $URIPARSER_DIR/src/UriMemory.c $URIPARSER_DIR/src/UriNormalize.c $URIPARSER_DIR/ $URIPARSER_DIR/src/UriParse.c $URIPARSER_DIR/src/UriParseBase.c $URIPARSER_DIR/src/UriQuery.c \ $URIPARSER_DIR/src/UriRecompose.c $URIPARSER_DIR/src/UriResolve.c $URIPARSER_DIR/src/UriShorten.c" -PHP_NEW_EXTENSION(uri, [php_uri.c $URIPARSER_SOURCES], [no],,[-I$ext_srcdir/$URIPARSER_DIR/include -DURI_STATIC_BUILD -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1]) +PHP_NEW_EXTENSION(uri, [php_lexbor.c php_uri.c php_uri_common.c $URIPARSER_SOURCES], [no],,[-I$ext_srcdir/$URIPARSER_DIR/include -DURI_STATIC_BUILD -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1]) PHP_ADD_EXTENSION_DEP(uri, lexbor) PHP_ADD_BUILD_DIR($ext_builddir/$URIPARSER_DIR/src $ext_builddir/$URIPARSER_DIR/include) diff --git a/ext/uri/config.w32 b/ext/uri/config.w32 index 962f7bee0660e..9c6af0cc5fa7b 100644 --- a/ext/uri/config.w32 +++ b/ext/uri/config.w32 @@ -1,4 +1,4 @@ -EXTENSION("uri", "php_uri.c", false /* never shared */, "/I ext/lexbor /I ext/uri/uriparser/include /DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); +EXTENSION("uri", "php_lexbor.c php_uri.c php_uri_common.c", false /* never shared */, "/I ext/lexbor /I ext/uri/uriparser/include /DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); AC_DEFINE("URI_ENABLE_ANSI", 1, "Define to 1 for enabling ANSI support of uriparser.") AC_DEFINE("URI_NO_UNICODE", 1, "Define to 1 for disabling unicode support of uriparser.") @@ -6,4 +6,4 @@ ADD_FLAG("CFLAGS_URI", "/D URI_STATIC_BUILD"); ADD_EXTENSION_DEP('uri', 'lexbor'); ADD_SOURCES("ext/uri/uriparser/src", "UriCommon.c UriCompare.c UriEscape.c UriFile.c UriIp4.c UriIp4Base.c UriMemory.c UriNormalize.c UriNormalizeBase.c UriParse.c UriParseBase.c UriQuery.c UriRecompose.c UriShorten.c", "uri"); -PHP_INSTALL_HEADERS("ext/uri", "php_uri.h uriparser/src uriparser/include"); +PHP_INSTALL_HEADERS("ext/uri", "php_lexbor.h php_uri.h php_uri_common.h uriparser/src uriparser/include"); diff --git a/ext/uri/php_lexbor.c b/ext/uri/php_lexbor.c new file mode 100644 index 0000000000000..82f3919bb6a97 --- /dev/null +++ b/ext/uri/php_lexbor.c @@ -0,0 +1,639 @@ +/* + +----------------------------------------------------------------------+ + | 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 "php.h" +#include "php_lexbor.h" +#include "php_uri_common.h" +#include "Zend/zend_enum.h" +#include "Zend/zend_smart_str.h" +#include "Zend/zend_exceptions.h" +#ifdef HAVE_ARPA_INET_H +#include +#endif + +ZEND_TLS lxb_url_parser_t lexbor_parser; +ZEND_TLS unsigned short int lexbor_urls; + +#define LEXBOR_MAX_URL_COUNT 500 +#define LEXBOR_MRAW_BYTE_SIZE 8192 + +static zend_always_inline void zval_string_or_null_to_lexbor_str(zval *value, lexbor_str_t *lexbor_str) +{ + if (Z_TYPE_P(value) == IS_STRING && Z_STRLEN_P(value) > 0) { + lexbor_str->data = (lxb_char_t *) Z_STRVAL_P(value); + lexbor_str->length = Z_STRLEN_P(value); + } else { + ZEND_ASSERT(Z_ISNULL_P(value) || (Z_TYPE_P(value) == IS_STRING && Z_STRLEN_P(value) == 0)); + lexbor_str->data = (lxb_char_t *) ""; + lexbor_str->length = 0; + } +} + +static zend_always_inline void zval_long_or_null_to_lexbor_str(zval *value, lexbor_str_t *lexbor_str) +{ + if (Z_TYPE_P(value) == IS_LONG) { + ZVAL_STR(value, zend_long_to_str(Z_LVAL_P(value))); + lexbor_str_init_append(lexbor_str, lexbor_parser.mraw, (const lxb_char_t *) Z_STRVAL_P(value), Z_STRLEN_P(value)); + zval_ptr_dtor_str(value); + } else { + ZEND_ASSERT(Z_ISNULL_P(value)); + lexbor_str->data = (lxb_char_t *) ""; + lexbor_str->length = 0; + } +} + +static void lexbor_cleanup_parser(void) +{ + if (++lexbor_urls % LEXBOR_MAX_URL_COUNT == 0) { + lexbor_mraw_clean(lexbor_parser.mraw); + lexbor_urls = 0; + } + + lxb_url_parser_clean(&lexbor_parser); +} + +/** + * Creates a Uri\WhatWg\UrlValidationError class by mapping error codes listed in + * https://url.spec.whatwg.org/#writing to a Uri\WhatWg\UrlValidationErrorType enum. + * The result is passed by reference to the errors parameter. + * + * When errors is NULL, the caller is not interested in the additional error information, + * so the function does nothing. + */ +static void fill_errors(zval *errors) +{ + if (errors == NULL) { + return; + } + + ZEND_ASSERT(Z_ISUNDEF_P(errors)); + + array_init(errors); + + if (lexbor_parser.log == NULL) { + return; + } + + 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; + zval failure; + switch (lxb_error->id) { + case LXB_URL_ERROR_TYPE_DOMAIN_TO_ASCII: + error_str = ZSTR_INIT_LITERAL("DomainToAscii", false); + ZVAL_TRUE(&failure); + break; + case LXB_URL_ERROR_TYPE_DOMAIN_TO_UNICODE: + error_str = ZSTR_INIT_LITERAL("DomainToUnicode", false); + ZVAL_FALSE(&failure); + break; + case LXB_URL_ERROR_TYPE_DOMAIN_INVALID_CODE_POINT: + error_str = ZSTR_INIT_LITERAL("DomainInvalidCodePoint", false); + ZVAL_TRUE(&failure); + break; + case LXB_URL_ERROR_TYPE_HOST_INVALID_CODE_POINT: + error_str = ZSTR_INIT_LITERAL("HostInvalidCodePoint", false); + ZVAL_TRUE(&failure); + break; + case LXB_URL_ERROR_TYPE_IPV4_EMPTY_PART: + error_str = ZSTR_INIT_LITERAL("Ipv4EmptyPart", false); + ZVAL_FALSE(&failure); + break; + case LXB_URL_ERROR_TYPE_IPV4_TOO_MANY_PARTS: + error_str = ZSTR_INIT_LITERAL("Ipv4TooManyParts", false); + ZVAL_TRUE(&failure); + break; + case LXB_URL_ERROR_TYPE_IPV4_NON_NUMERIC_PART: + error_str = ZSTR_INIT_LITERAL("Ipv4NonNumericPart", false); + ZVAL_TRUE(&failure); + break; + case LXB_URL_ERROR_TYPE_IPV4_NON_DECIMAL_PART: + error_str = ZSTR_INIT_LITERAL("Ipv4NonDecimalPart", false); + ZVAL_FALSE(&failure); + break; + case LXB_URL_ERROR_TYPE_IPV4_OUT_OF_RANGE_PART: + error_str = ZSTR_INIT_LITERAL("Ipv4OutOfRangePart", false); + ZVAL_TRUE(&failure); + break; + case LXB_URL_ERROR_TYPE_IPV6_UNCLOSED: + error_str = ZSTR_INIT_LITERAL("Ipv6Unclosed", false); + ZVAL_TRUE(&failure); + break; + case LXB_URL_ERROR_TYPE_IPV6_INVALID_COMPRESSION: + error_str = ZSTR_INIT_LITERAL("Ipv6InvalidCompression", false); + ZVAL_TRUE(&failure); + break; + case LXB_URL_ERROR_TYPE_IPV6_TOO_MANY_PIECES: + error_str = ZSTR_INIT_LITERAL("Ipv6TooManyPieces", false); + ZVAL_TRUE(&failure); + break; + case LXB_URL_ERROR_TYPE_IPV6_MULTIPLE_COMPRESSION: + error_str = ZSTR_INIT_LITERAL("Ipv6MultipleCompression", false); + ZVAL_TRUE(&failure); + break; + case LXB_URL_ERROR_TYPE_IPV6_INVALID_CODE_POINT: + error_str = ZSTR_INIT_LITERAL("Ipv6InvalidCodePoint", false); + ZVAL_TRUE(&failure); + break; + case LXB_URL_ERROR_TYPE_IPV6_TOO_FEW_PIECES: + error_str = ZSTR_INIT_LITERAL("Ipv6TooFewPieces", false); + ZVAL_TRUE(&failure); + break; + case LXB_URL_ERROR_TYPE_IPV4_IN_IPV6_TOO_MANY_PIECES: + error_str = ZSTR_INIT_LITERAL("Ipv4InIpv6TooManyPieces", false); + ZVAL_TRUE(&failure); + break; + case LXB_URL_ERROR_TYPE_IPV4_IN_IPV6_INVALID_CODE_POINT: + error_str = ZSTR_INIT_LITERAL("Ipv4InIpv6InvalidCodePoint", false); + ZVAL_TRUE(&failure); + break; + case LXB_URL_ERROR_TYPE_IPV4_IN_IPV6_OUT_OF_RANGE_PART: + error_str = ZSTR_INIT_LITERAL("Ipv4InIpv6OutOfRangePart", false); + ZVAL_TRUE(&failure); + break; + case LXB_URL_ERROR_TYPE_IPV4_IN_IPV6_TOO_FEW_PARTS: + error_str = ZSTR_INIT_LITERAL("Ipv4InIpv6TooFewParts", false); + ZVAL_TRUE(&failure); + break; + case LXB_URL_ERROR_TYPE_INVALID_URL_UNIT: + error_str = ZSTR_INIT_LITERAL("InvalidUrlUnit", false); + ZVAL_FALSE(&failure); + break; + case LXB_URL_ERROR_TYPE_SPECIAL_SCHEME_MISSING_FOLLOWING_SOLIDUS: + error_str = ZSTR_INIT_LITERAL("SpecialSchemeMissingFollowingSolidus", false); + ZVAL_FALSE(&failure); + break; + case LXB_URL_ERROR_TYPE_MISSING_SCHEME_NON_RELATIVE_URL: + error_str = ZSTR_INIT_LITERAL("MissingSchemeNonRelativeUrl", false); + ZVAL_TRUE(&failure); + break; + case LXB_URL_ERROR_TYPE_INVALID_REVERSE_SOLIDUS: + error_str = ZSTR_INIT_LITERAL("InvalidReverseSoldius", false); + ZVAL_FALSE(&failure); + break; + case LXB_URL_ERROR_TYPE_INVALID_CREDENTIALS: + error_str = ZSTR_INIT_LITERAL("InvalidCredentials", false); + ZVAL_FALSE(&failure); + break; + case LXB_URL_ERROR_TYPE_HOST_MISSING: + error_str = ZSTR_INIT_LITERAL("HostMissing", false); + ZVAL_TRUE(&failure); + break; + case LXB_URL_ERROR_TYPE_PORT_OUT_OF_RANGE: + error_str = ZSTR_INIT_LITERAL("PortOutOfRange", false); + ZVAL_TRUE(&failure); + break; + case LXB_URL_ERROR_TYPE_PORT_INVALID: + error_str = ZSTR_INIT_LITERAL("PortInvalid", false); + ZVAL_TRUE(&failure); + break; + case LXB_URL_ERROR_TYPE_FILE_INVALID_WINDOWS_DRIVE_LETTER: + error_str = ZSTR_INIT_LITERAL("FileInvalidWindowsDriveLetter", false); + ZVAL_FALSE(&failure); + break; + case LXB_URL_ERROR_TYPE_FILE_INVALID_WINDOWS_DRIVE_LETTER_HOST: + error_str = ZSTR_INIT_LITERAL("FileInvalidWindowsDriveLetterHost", false); + 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); + 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); + + add_next_index_zval(errors, &error); + } +} + +static void throw_invalid_url_exception(zval *errors) +{ + ZEND_ASSERT(errors != NULL && Z_TYPE_P(errors) == IS_ARRAY); + + zval exception; + + object_init_ex(&exception, uri_whatwg_invalid_url_exception_ce); + + zval value; + ZVAL_STRING(&value, "URL parsing failed"); + zend_update_property_ex(uri_whatwg_invalid_url_exception_ce, Z_OBJ(exception), ZSTR_KNOWN(ZEND_STR_MESSAGE), &value); + zval_ptr_dtor_str(&value); + + zend_update_property(uri_whatwg_invalid_url_exception_ce, Z_OBJ(exception), ZEND_STRL("errors"), errors); + + zend_throw_exception_object(&exception); +} + +static void throw_invalid_url_exception_during_write(zval *errors) +{ + fill_errors(errors); + throw_invalid_url_exception(errors); +} + +static lxb_status_t lexbor_serialize_callback(const lxb_char_t *data, size_t length, void *ctx) +{ + smart_str *uri_str = ctx; + + if (data != NULL && length > 0) { + smart_str_appendl(uri_str, (const char *) data, length); + } + + return LXB_STATUS_OK; +} + +static zend_result lexbor_read_scheme(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + lxb_url_t *lexbor_uri = internal_uri->uri; + + ZEND_ASSERT(lexbor_uri->scheme.type != LXB_URL_SCHEMEL_TYPE__UNDEF); + + ZVAL_STRINGL(retval, (const char *) lexbor_uri->scheme.name.data, lexbor_uri->scheme.name.length); + + return SUCCESS; +} + +static zend_result lexbor_write_scheme(struct uri_internal_t *internal_uri, zval *value, zval *errors) +{ + lxb_url_t *lexbor_uri = internal_uri->uri; + lexbor_str_t str = {0}; + + zval_string_or_null_to_lexbor_str(value, &str); + + if (lxb_url_api_protocol_set(lexbor_uri, &lexbor_parser, str.data, str.length) != LXB_STATUS_OK) { + throw_invalid_url_exception_during_write(errors); + + return FAILURE; + } + + return SUCCESS; +} + +static zend_result lexbor_read_username(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + lxb_url_t *lexbor_uri = internal_uri->uri; + + if (lexbor_uri->username.length) { + ZVAL_STRINGL(retval, (const char *) lexbor_uri->username.data, lexbor_uri->username.length); + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +static zend_result lexbor_write_username(uri_internal_t *internal_uri, zval *value, zval *errors) +{ + lxb_url_t *lexbor_uri = internal_uri->uri; + lexbor_str_t str = {0}; + + zval_string_or_null_to_lexbor_str(value, &str); + + if (lxb_url_api_username_set(lexbor_uri, str.data, str.length) != LXB_STATUS_OK) { + throw_invalid_url_exception_during_write(errors); + + return FAILURE; + } + + return SUCCESS; +} + +static zend_result lexbor_read_password(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + lxb_url_t *lexbor_uri = internal_uri->uri; + + if (lexbor_uri->password.length > 0) { + ZVAL_STRINGL(retval, (const char *) lexbor_uri->password.data, lexbor_uri->password.length); + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +static zend_result lexbor_write_password(struct uri_internal_t *internal_uri, zval *value, zval *errors) +{ + lxb_url_t *lexbor_uri = internal_uri->uri; + lexbor_str_t str = {0}; + + zval_string_or_null_to_lexbor_str(value, &str); + + if (lxb_url_api_password_set(lexbor_uri, str.data, str.length) != LXB_STATUS_OK) { + throw_invalid_url_exception_during_write(errors); + + return FAILURE; + } + + return SUCCESS; +} + +static zend_result init_idna(void) +{ + if (lexbor_parser.idna != NULL) { + return SUCCESS; + } + + lexbor_parser.idna = lxb_unicode_idna_create(); + + return lxb_unicode_idna_init(lexbor_parser.idna) == LXB_STATUS_OK ? SUCCESS : FAILURE; +} + +static zend_result lexbor_read_host(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + lxb_url_t *lexbor_uri = internal_uri->uri; + + if (lexbor_uri->host.type == LXB_URL_HOST_TYPE_IPV4) { + smart_str host_str = {0}; + + lxb_url_serialize_host_ipv4(lexbor_uri->host.u.ipv4, lexbor_serialize_callback, &host_str); + + ZVAL_NEW_STR(retval, smart_str_extract(&host_str)); + } else if (lexbor_uri->host.type == LXB_URL_HOST_TYPE_IPV6) { + smart_str host_str = {0}; + + smart_str_appendc(&host_str, '['); + lxb_url_serialize_host_ipv6(lexbor_uri->host.u.ipv6, lexbor_serialize_callback, &host_str); + smart_str_appendc(&host_str, ']'); + + ZVAL_NEW_STR(retval, smart_str_extract(&host_str)); + } else if (lexbor_uri->host.type != LXB_URL_HOST_TYPE_EMPTY && lexbor_uri->host.type != LXB_URL_HOST_TYPE__UNDEF) { + switch (read_mode) { + case URI_COMPONENT_READ_NORMALIZED_UNICODE: { + smart_str host_str = {0}; + if (init_idna() == FAILURE) { + return FAILURE; + } + lxb_url_serialize_host_unicode(lexbor_parser.idna, &lexbor_uri->host, lexbor_serialize_callback, &host_str); + lxb_unicode_idna_clean(lexbor_parser.idna); + + ZVAL_NEW_STR(retval, smart_str_extract(&host_str)); + break; + } + case URI_COMPONENT_READ_NORMALIZED_ASCII: + ZEND_FALLTHROUGH; + case URI_COMPONENT_READ_RAW: + ZVAL_STRINGL(retval, (const char *) lexbor_uri->host.u.domain.data, lexbor_uri->host.u.domain.length); + break; + EMPTY_SWITCH_DEFAULT_CASE() + } + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +static zend_result lexbor_write_host(struct uri_internal_t *internal_uri, zval *value, zval *errors) +{ + lxb_url_t *lexbor_uri = internal_uri->uri; + lexbor_str_t str = {0}; + + zval_string_or_null_to_lexbor_str(value, &str); + + if (lxb_url_api_hostname_set(lexbor_uri, &lexbor_parser, str.data, str.length) != LXB_STATUS_OK) { + throw_invalid_url_exception_during_write(errors); + + return FAILURE; + } + + return SUCCESS; +} + +static zend_result lexbor_read_port(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + lxb_url_t *lexbor_uri = internal_uri->uri; + + if (lexbor_uri->has_port) { + ZVAL_LONG(retval, lexbor_uri->port); + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +static zend_result lexbor_write_port(struct uri_internal_t *internal_uri, zval *value, zval *errors) +{ + lxb_url_t *lexbor_uri = internal_uri->uri; + lexbor_str_t str = {0}; + + zval_long_or_null_to_lexbor_str(value, &str); + + if (lxb_url_api_port_set(lexbor_uri, &lexbor_parser, str.data, str.length) != LXB_STATUS_OK) { + throw_invalid_url_exception_during_write(errors); + + return FAILURE; + } + + return SUCCESS; +} + +static zend_result lexbor_read_path(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + lxb_url_t *lexbor_uri = internal_uri->uri; + + if (lexbor_uri->path.str.length) { + ZVAL_STRINGL(retval, (const char *) lexbor_uri->path.str.data, lexbor_uri->path.str.length); + } else { + ZVAL_EMPTY_STRING(retval); + } + + return SUCCESS; +} + +static zend_result lexbor_write_path(struct uri_internal_t *internal_uri, zval *value, zval *errors) +{ + lxb_url_t *lexbor_uri = internal_uri->uri; + lexbor_str_t str = {0}; + + zval_string_or_null_to_lexbor_str(value, &str); + + if (lxb_url_api_pathname_set(lexbor_uri, &lexbor_parser, str.data, str.length) != LXB_STATUS_OK) { + throw_invalid_url_exception_during_write(errors); + + return FAILURE; + } + + return SUCCESS; +} + +static zend_result lexbor_read_query(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + lxb_url_t *lexbor_uri = internal_uri->uri; + + if (lexbor_uri->query.length) { + ZVAL_STRINGL(retval, (const char *) lexbor_uri->query.data, lexbor_uri->query.length); + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +static zend_result lexbor_write_query(struct uri_internal_t *internal_uri, zval *value, zval *errors) +{ + lxb_url_t *lexbor_uri = internal_uri->uri; + lexbor_str_t str = {0}; + + zval_string_or_null_to_lexbor_str(value, &str); + + if (lxb_url_api_search_set(lexbor_uri, &lexbor_parser, str.data, str.length) != LXB_STATUS_OK) { + throw_invalid_url_exception_during_write(errors); + + return FAILURE; + } + + return SUCCESS; +} + +static zend_result lexbor_read_fragment(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + lxb_url_t *lexbor_uri = internal_uri->uri; + + if (lexbor_uri->fragment.length) { + ZVAL_STRINGL(retval, (const char *) lexbor_uri->fragment.data, lexbor_uri->fragment.length); + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +static zend_result lexbor_write_fragment(struct uri_internal_t *internal_uri, zval *value, zval *errors) +{ + lxb_url_t *lexbor_uri = internal_uri->uri; + lexbor_str_t str = {0}; + + zval_string_or_null_to_lexbor_str(value, &str); + + if (lxb_url_api_hash_set(lexbor_uri, &lexbor_parser, str.data, str.length) != LXB_STATUS_OK) { + throw_invalid_url_exception_during_write(errors); + + return FAILURE; + } + + return SUCCESS; +} + +zend_result lexbor_request_init(void) +{ + lexbor_mraw_t *mraw = lexbor_mraw_create(); + lxb_status_t status = lexbor_mraw_init(mraw, LEXBOR_MRAW_BYTE_SIZE); + if (status != LXB_STATUS_OK) { + lexbor_mraw_destroy(mraw, true); + return FAILURE; + } + + status = lxb_url_parser_init(&lexbor_parser, mraw); + if (status != LXB_STATUS_OK) { + lxb_url_parser_destroy(&lexbor_parser, false); + lexbor_mraw_destroy(mraw, true); + return FAILURE; + } + + lexbor_urls = 0; + + return SUCCESS; +} + +void lexbor_request_shutdown(void) +{ + lxb_url_parser_memory_destroy(&lexbor_parser); + lxb_url_parser_destroy(&lexbor_parser, false); + + lexbor_urls = 0; +} + +lxb_url_t *lexbor_parse_uri_ex(const zend_string *uri_str, const lxb_url_t *lexbor_base_url, zval *errors, bool silent) +{ + 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)); + fill_errors(errors); + + if (url == NULL && !silent) { + throw_invalid_url_exception(errors); + } + + return url; +} + +static void *lexbor_parse_uri(const zend_string *uri_str, const void *base_url, zval *errors, bool silent) +{ + return lexbor_parse_uri_ex(uri_str, base_url, errors, silent); +} + +static void *lexbor_clone_uri(void *uri) +{ + lxb_url_t *lexbor_uri = (lxb_url_t *) uri; + + return lxb_url_clone(lexbor_parser.mraw, lexbor_uri); +} + +static zend_string *lexbor_uri_to_string(void *uri, uri_recomposition_mode_t recomposition_mode, bool exclude_fragment) +{ + lxb_url_t *lexbor_uri = (lxb_url_t *) uri; + smart_str uri_str = {0}; + + switch (recomposition_mode) { + case URI_RECOMPOSITION_RAW_UNICODE: + ZEND_FALLTHROUGH; + case URI_RECOMPOSITION_NORMALIZED_UNICODE: + if (init_idna() == FAILURE) { + return NULL; + } + lxb_url_serialize_idna(lexbor_parser.idna, lexbor_uri, lexbor_serialize_callback, &uri_str, exclude_fragment); + lxb_unicode_idna_clean(lexbor_parser.idna); + break; + case URI_RECOMPOSITION_RAW_ASCII: + ZEND_FALLTHROUGH; + case URI_RECOMPOSITION_NORMALIZED_ASCII: + lxb_url_serialize(lexbor_uri, lexbor_serialize_callback, &uri_str, exclude_fragment); + break; + EMPTY_SWITCH_DEFAULT_CASE() + } + + return smart_str_extract(&uri_str); +} + +static void lexbor_free_uri(void *uri) +{ +} + +const uri_handler_t lexbor_uri_handler = { + .name = URI_PARSER_WHATWG, + .parse_uri = lexbor_parse_uri, + .clone_uri = lexbor_clone_uri, + .uri_to_string = lexbor_uri_to_string, + .free_uri = lexbor_free_uri, + { + .scheme = {.read_func = lexbor_read_scheme, .write_func = lexbor_write_scheme}, + .username = {.read_func = lexbor_read_username, .write_func = lexbor_write_username}, + .password = {.read_func = lexbor_read_password, .write_func = lexbor_write_password}, + .host = {.read_func = lexbor_read_host, .write_func = lexbor_write_host}, + .port = {.read_func = lexbor_read_port, .write_func = lexbor_write_port}, + .path = {.read_func = lexbor_read_path, .write_func = lexbor_write_path}, + .query = {.read_func = lexbor_read_query, .write_func = lexbor_write_query}, + .fragment = {.read_func = lexbor_read_fragment, .write_func = lexbor_write_fragment}, + } +}; diff --git a/ext/uri/php_lexbor.h b/ext/uri/php_lexbor.h new file mode 100644 index 0000000000000..30d68b5cdf681 --- /dev/null +++ b/ext/uri/php_lexbor.h @@ -0,0 +1,30 @@ +/* + +----------------------------------------------------------------------+ + | 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_LEXBOR_H +#define PHP_LEXBOR_H + +#include "php_uri_common.h" +#include "lexbor/url/url.h" + +extern const uri_handler_t lexbor_uri_handler; + +lxb_url_t *lexbor_parse_uri_ex(const zend_string *uri_str, const lxb_url_t *lexbor_base_url, zval *errors, bool silent); + +zend_result lexbor_request_init(void); +void lexbor_request_shutdown(void); + +#endif diff --git a/ext/uri/php_uri.c b/ext/uri/php_uri.c index bd5c622ed3765..5b2e21b1625a3 100644 --- a/ext/uri/php_uri.c +++ b/ext/uri/php_uri.c @@ -22,16 +22,23 @@ #include "Zend/zend_interfaces.h" #include "Zend/zend_exceptions.h" #include "Zend/zend_attributes.h" -#include "main/php_ini.h" +#include "Zend/zend_enum.h" #include "ext/standard/info.h" #include "php_uri.h" +#include "php_uri_common.h" +#include "php_lexbor.h" #include "php_uri_arginfo.h" #include "uriparser/src/UriConfig.h" +zend_class_entry *uri_whatwg_url_ce; +zend_object_handlers uri_whatwg_uri_object_handlers; +zend_class_entry *uri_comparison_mode_ce; zend_class_entry *uri_exception_ce; -zend_class_entry *invalid_uri_exception_ce; -zend_class_entry *whatwg_invalid_url_exception_ce; +zend_class_entry *uri_invalid_uri_exception_ce; +zend_class_entry *uri_whatwg_invalid_url_exception_ce; +zend_class_entry *uri_whatwg_url_validation_error_type_ce; +zend_class_entry *uri_whatwg_url_validation_error_ce; #define URIPARSER_VERSION PACKAGE_VERSION @@ -40,12 +47,603 @@ static const zend_module_dep uri_deps[] = { ZEND_MOD_END }; +static zend_array uri_handlers; + +static uri_handler_t *uri_handler_by_name(const char *handler_name, size_t handler_name_len) +{ + return zend_hash_str_find_ptr(&uri_handlers, handler_name, handler_name_len); +} + +static HashTable *uri_get_debug_properties(zend_object *object) +{ + uri_internal_t *internal_uri = uri_internal_from_obj(object); + ZEND_ASSERT(internal_uri != NULL); + + HashTable *std_properties = zend_std_get_properties(object); + HashTable *result = zend_array_dup(std_properties); + + if (UNEXPECTED(internal_uri->uri == NULL)) { + return result; + } + + const uri_property_handlers_t property_handlers = internal_uri->handler->property_handlers; + + zval tmp; + if (property_handlers.scheme.read_func(internal_uri, URI_COMPONENT_READ_RAW, &tmp) == SUCCESS) { + zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_SCHEME), &tmp); + } + + if (property_handlers.username.read_func(internal_uri, URI_COMPONENT_READ_RAW, &tmp) == SUCCESS) { + zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_USERNAME), &tmp); + } + + if (property_handlers.password.read_func(internal_uri, URI_COMPONENT_READ_RAW, &tmp) == SUCCESS) { + zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_PASSWORD), &tmp); + } + + if (property_handlers.host.read_func(internal_uri, URI_COMPONENT_READ_RAW, &tmp) == SUCCESS) { + zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_HOST), &tmp); + } + + if (property_handlers.port.read_func(internal_uri, URI_COMPONENT_READ_RAW, &tmp) == SUCCESS) { + zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_PORT), &tmp); + } + + if (property_handlers.path.read_func(internal_uri, URI_COMPONENT_READ_RAW, &tmp) == SUCCESS) { + zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_PATH), &tmp); + } + + if (property_handlers.query.read_func(internal_uri, URI_COMPONENT_READ_RAW, &tmp) == SUCCESS) { + zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_QUERY), &tmp); + } + + if (property_handlers.fragment.read_func(internal_uri, URI_COMPONENT_READ_RAW, &tmp) == SUCCESS) { + zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_FRAGMENT), &tmp); + } + + return result; +} + +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(uri_whatwg_invalid_url_exception_ce, Z_OBJ_P(ZEND_THIS), ZEND_STRL("errors"), &tmp); + } else { + zend_update_property(uri_whatwg_invalid_url_exception_ce, 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, uri_whatwg_url_validation_error_type_ce) + Z_PARAM_BOOL(failure) + ZEND_PARSE_PARAMETERS_END(); + + zend_update_property_str(uri_whatwg_url_validation_error_ce, Z_OBJ_P(ZEND_THIS), ZEND_STRL("context"), context); + if (EG(exception)) { + RETURN_THROWS(); + } + + zend_update_property_ex(uri_whatwg_url_validation_error_ce, 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(uri_whatwg_url_validation_error_ce, Z_OBJ_P(ZEND_THIS), ZEND_STRL("failure"), &failure_zv); + if (EG(exception)) { + RETURN_THROWS(); + } +} + +/** + * 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_ARR(errors_zv, Z_ARRVAL_P(errors)); + if (EG(exception)) { + zval_ptr_dtor(errors); + return FAILURE; + } + + return SUCCESS; +} + +PHPAPI void php_uri_instantiate_uri( + INTERNAL_FUNCTION_PARAMETERS, const uri_handler_t *handler, const zend_string *uri_str, const zend_object *base_url_object, + bool should_throw, bool should_update_this_object, zval *errors_zv +) { + zval errors; + ZVAL_UNDEF(&errors); + + void *base_url = NULL; + if (base_url_object != NULL) { + uri_internal_t *internal_base_url = uri_internal_from_obj(base_url_object); + URI_ASSERT_INITIALIZATION(internal_base_url); + base_url = internal_base_url->uri; + } + + void *uri = handler->parse_uri(uri_str, base_url, should_throw || 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(); + } + RETURN_NULL(); + } + } + + if (pass_errors_by_ref_and_free(errors_zv, &errors) == FAILURE) { + RETURN_THROWS(); + } + + uri_object_t *uri_object; + if (should_update_this_object) { + uri_object = Z_URI_OBJECT_P(ZEND_THIS); + } 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); + } + + uri_object->internal.handler = handler; + uri_object->internal.uri = uri; +} + +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, uri_whatwg_url_ce) + Z_PARAM_ZVAL(errors) + ZEND_PARSE_PARAMETERS_END(); + + php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, &lexbor_uri_handler, uri_str, base_url_object, 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); +} + +static void uri_equals(INTERNAL_FUNCTION_PARAMETERS, zend_object *that_object, zend_object *comparison_mode) +{ + zend_object *this_object = Z_OBJ_P(ZEND_THIS); + uri_internal_t *this_internal_uri = uri_internal_from_obj(this_object); + URI_ASSERT_INITIALIZATION(this_internal_uri); + + uri_internal_t *that_internal_uri = uri_internal_from_obj(that_object); + URI_ASSERT_INITIALIZATION(that_internal_uri); + + if (this_object->ce != that_object->ce && + !instanceof_function(this_object->ce, that_object->ce) && + !instanceof_function(that_object->ce, this_object->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_internal_uri->handler->uri_to_string( + this_internal_uri->uri, URI_RECOMPOSITION_NORMALIZED_ASCII, exclude_fragment); + if (this_str == NULL) { + zend_throw_exception_ex(NULL, 0, "Cannot recompose %s to string", ZSTR_VAL(this_object->ce->name)); + RETURN_THROWS(); + } + + zend_string *that_str = that_internal_uri->handler->uri_to_string( + that_internal_uri->uri, URI_RECOMPOSITION_NORMALIZED_ASCII, exclude_fragment); + if (that_str == NULL) { + zend_string_release(this_str); + zend_throw_exception_ex(NULL, 0, "Cannot recompose %s to string", ZSTR_VAL(that_object->ce->name)); + RETURN_THROWS(); + } + + RETVAL_BOOL(zend_string_equals(this_str, that_str)); + + zend_string_release(this_str); + zend_string_release(that_str); +} + +static void uri_unserialize(INTERNAL_FUNCTION_PARAMETERS, const char *handler_name) +{ + HashTable *data; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ARRAY_HT(data) + ZEND_PARSE_PARAMETERS_END(); + + zend_object *object = Z_OBJ_P(ZEND_THIS); + + /* 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(object->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(object->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(object->ce->name)); + RETURN_THROWS(); + } + + zval *uri_zv = zend_hash_str_find_ind(Z_ARRVAL_P(arr), ZEND_STRL(URI_SERIALIZED_PROPERTY_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(object->ce->name)); + RETURN_THROWS(); + } + + uri_internal_t *internal_uri = uri_internal_from_obj(object); + internal_uri->handler = uri_handler_by_name(handler_name, strlen(handler_name)); + if (internal_uri->uri != NULL) { + internal_uri->handler->free_uri(internal_uri->uri); + } + internal_uri->uri = internal_uri->handler->parse_uri(Z_STR_P(uri_zv), NULL, NULL, true); + if (internal_uri->uri == NULL) { + zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(object->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(object->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(object->ce->name)); + RETURN_THROWS(); + } +} + +PHP_METHOD(Uri_WhatWg_Url, getScheme) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_SCHEME, URI_COMPONENT_READ_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_WhatWg_Url, withScheme) +{ + uri_write_component_str(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_SCHEME); +} + +PHP_METHOD(Uri_WhatWg_Url, getUsername) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_USERNAME, URI_COMPONENT_READ_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_WhatWg_Url, withUsername) +{ + uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_USERNAME); +} + +PHP_METHOD(Uri_WhatWg_Url, getPassword) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PASSWORD, URI_COMPONENT_READ_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_WhatWg_Url, withPassword) +{ + uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PASSWORD); +} + +PHP_METHOD(Uri_WhatWg_Url, getAsciiHost) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_HOST, URI_COMPONENT_READ_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_WhatWg_Url, getUnicodeHost) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_HOST, URI_COMPONENT_READ_NORMALIZED_UNICODE); +} + +PHP_METHOD(Uri_WhatWg_Url, withHost) +{ + uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_HOST); +} + +PHP_METHOD(Uri_WhatWg_Url, getPort) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PORT, URI_COMPONENT_READ_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_WhatWg_Url, withPort) +{ + uri_write_component_long_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PORT); +} + +PHP_METHOD(Uri_WhatWg_Url, getPath) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PATH, URI_COMPONENT_READ_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_WhatWg_Url, withPath) +{ + uri_write_component_str(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PATH); +} + +PHP_METHOD(Uri_WhatWg_Url, getQuery) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_QUERY, URI_COMPONENT_READ_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_WhatWg_Url, withQuery) +{ + uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_QUERY); +} + +PHP_METHOD(Uri_WhatWg_Url, getFragment) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_FRAGMENT, URI_COMPONENT_READ_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_WhatWg_Url, withFragment) +{ + uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_FRAGMENT); +} + +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, uri_whatwg_url_ce) + Z_PARAM_OPTIONAL + Z_PARAM_OBJ_OF_CLASS(comparison_mode, uri_comparison_mode_ce) + ZEND_PARSE_PARAMETERS_END(); + + uri_equals(INTERNAL_FUNCTION_PARAM_PASSTHRU, that_object, comparison_mode); +} + +PHP_METHOD(Uri_WhatWg_Url, toUnicodeString) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zend_object *this_object = Z_OBJ_P(ZEND_THIS); + uri_internal_t *internal_uri = uri_internal_from_obj(this_object); + URI_ASSERT_INITIALIZATION(internal_uri); + + RETURN_STR(internal_uri->handler->uri_to_string(internal_uri->uri, URI_RECOMPOSITION_RAW_UNICODE, false)); +} + +PHP_METHOD(Uri_WhatWg_Url, toAsciiString) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zend_object *this_object = Z_OBJ_P(ZEND_THIS); + uri_internal_t *internal_uri = uri_internal_from_obj(this_object); + URI_ASSERT_INITIALIZATION(internal_uri); + + RETURN_STR(internal_uri->handler->uri_to_string(internal_uri->uri, URI_RECOMPOSITION_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(); + + zend_object *this_object = Z_OBJ_P(ZEND_THIS); + uri_internal_t *internal_uri = uri_internal_from_obj(this_object); + URI_ASSERT_INITIALIZATION(internal_uri); + + php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, internal_uri->handler, uri_str, this_object, true, false, errors); +} + +PHP_METHOD(Uri_WhatWg_Url, __serialize) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zend_object *this_object = Z_OBJ_P(ZEND_THIS); + uri_internal_t *internal_uri = uri_internal_from_obj(this_object); + URI_ASSERT_INITIALIZATION(internal_uri); + + /* Serialize state: "uri" key in the first array */ + zend_string *uri_str = internal_uri->handler->uri_to_string(internal_uri->uri, URI_RECOMPOSITION_RAW_ASCII, false); + if (uri_str == NULL) { + zend_throw_exception_ex(NULL, 0, "Cannot recompose %s to string", ZSTR_VAL(this_object->ce->name)); + 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(URI_SERIALIZED_PROPERTY_NAME), &tmp); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &arr); + + /* Serialize regular properties: second array */ + ZVAL_ARR(&arr, this_object->handlers->get_properties(this_object)); + 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, URI_PARSER_WHATWG); +} + +PHP_METHOD(Uri_WhatWg_Url, __debugInfo) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zend_object *object = Z_OBJ_P(ZEND_THIS); + + RETURN_ARR(uri_get_debug_properties(object)); +} + +static zend_object *uri_create_object_handler(zend_class_entry *class_type) +{ + uri_object_t *uri_object = zend_object_alloc(sizeof(uri_object_t), class_type); + + zend_object_std_init(&uri_object->std, class_type); + object_properties_init(&uri_object->std, class_type); + + return &uri_object->std; +} + +static void uri_free_obj_handler(zend_object *object) +{ + uri_object_t *uri_object = uri_object_from_obj(object); + + if (UNEXPECTED(uri_object->internal.uri != NULL)) { + uri_object->internal.handler->free_uri(uri_object->internal.uri); + uri_object->internal.handler = NULL; + uri_object->internal.uri = NULL; + } + + zend_object_std_dtor(&uri_object->std); +} + +zend_object *uri_clone_obj_handler(zend_object *object) +{ + uri_object_t *uri_object = uri_object_from_obj(object); + uri_internal_t *internal_uri = uri_internal_from_obj(object); + + URI_ASSERT_INITIALIZATION(internal_uri); + + 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); + + new_uri_object->internal.handler = internal_uri->handler; + + void *uri = internal_uri->handler->clone_uri(internal_uri->uri); + ZEND_ASSERT(uri != NULL); + + new_uri_object->internal.uri = uri; + + zend_objects_clone_members(&new_uri_object->std, &uri_object->std); + + return &new_uri_object->std; +} + +PHPAPI void php_uri_implementation_set_object_handlers(zend_class_entry *ce, zend_object_handlers *object_handlers) +{ + ce->create_object = uri_create_object_handler; + ce->default_object_handlers = object_handlers; + memcpy(object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); + object_handlers->offset = XtOffsetOf(uri_object_t, std); + object_handlers->free_obj = uri_free_obj_handler; + object_handlers->clone_obj = uri_clone_obj_handler; +} + +zend_result uri_handler_register(const uri_handler_t *uri_handler) +{ + zend_string *key = zend_string_init_interned(uri_handler->name, strlen(uri_handler->name), 1); + + ZEND_ASSERT(uri_handler->name != NULL); + ZEND_ASSERT(uri_handler->parse_uri != NULL); + ZEND_ASSERT(uri_handler->clone_uri != NULL); + ZEND_ASSERT(uri_handler->uri_to_string != NULL); + ZEND_ASSERT(uri_handler->free_uri != NULL); + + zend_result result = zend_hash_add_ptr(&uri_handlers, key, (void *) uri_handler) != NULL ? SUCCESS : FAILURE; + + zend_string_release_ex(key, true); + + return result; +} static PHP_MINIT_FUNCTION(uri) { + uri_whatwg_url_ce = register_class_Uri_WhatWg_Url(); + php_uri_implementation_set_object_handlers(uri_whatwg_url_ce, &uri_whatwg_uri_object_handlers); + + uri_comparison_mode_ce = register_class_Uri_UriComparisonMode(); uri_exception_ce = register_class_Uri_UriException(zend_ce_exception); - invalid_uri_exception_ce = register_class_Uri_InvalidUriException(uri_exception_ce); - whatwg_invalid_url_exception_ce = register_class_Uri_WhatWg_InvalidUrlException(invalid_uri_exception_ce); + uri_invalid_uri_exception_ce = register_class_Uri_InvalidUriException(uri_exception_ce); + uri_whatwg_invalid_url_exception_ce = register_class_Uri_WhatWg_InvalidUrlException(uri_invalid_uri_exception_ce); + uri_whatwg_url_validation_error_ce = register_class_Uri_WhatWg_UrlValidationError(); + uri_whatwg_url_validation_error_type_ce = register_class_Uri_WhatWg_UrlValidationErrorType(); + + zend_hash_init(&uri_handlers, 4, NULL, NULL, true); + + if (uri_handler_register(&lexbor_uri_handler) == FAILURE) { + return FAILURE; + } return SUCCESS; } @@ -60,18 +658,24 @@ static PHP_MINFO_FUNCTION(uri) static PHP_MSHUTDOWN_FUNCTION(uri) { + zend_hash_destroy(&uri_handlers); return SUCCESS; } PHP_RINIT_FUNCTION(uri) { + if (lexbor_request_init() == FAILURE) { + return FAILURE; + } return SUCCESS; } PHP_RSHUTDOWN_FUNCTION(uri) { + lexbor_request_shutdown(); + return SUCCESS; } diff --git a/ext/uri/php_uri.h b/ext/uri/php_uri.h index 79dfced4a721a..9e22c227cbf83 100644 --- a/ext/uri/php_uri.h +++ b/ext/uri/php_uri.h @@ -17,8 +17,11 @@ #ifndef PHP_URI_H #define PHP_URI_H +#include "php_uri_common.h" + extern zend_module_entry uri_module_entry; #define phpext_uri_ptr &uri_module_entry +PHPAPI void php_uri_implementation_set_object_handlers(zend_class_entry *ce, zend_object_handlers *object_handlers); #endif diff --git a/ext/uri/php_uri.stub.php b/ext/uri/php_uri.stub.php index 926be1fbb8267..ef49e4ba6f968 100644 --- a/ext/uri/php_uri.stub.php +++ b/ext/uri/php_uri.stub.php @@ -12,6 +12,12 @@ class UriException extends \Exception class InvalidUriException extends \Uri\UriException { } + + enum UriComparisonMode + { + case IncludeFragment; + case ExcludeFragment; + } } namespace Uri\WhatWg { @@ -19,5 +25,109 @@ class InvalidUriException extends \Uri\UriException class InvalidUrlException extends \Uri\InvalidUriException { public readonly array $errors; + + public function __construct(string $message = "", array $errors = [], int $code = 0, ?\Throwable $previous = null) {} + } + + enum UrlValidationErrorType + { + case DomainToAscii; + case DomainToUnicode; + case DomainInvalidCodePoint; + case HostInvalidCodePoint; + case Ipv4EmptyPart; + case Ipv4TooManyParts; + case Ipv4NonNumericPart; + case Ipv4NonDecimalPart; + case Ipv4OutOfRangePart; + case Ipv6Unclosed; + case Ipv6InvalidCompression; + case Ipv6TooManyPieces; + case Ipv6MultipleCompression; + case Ipv6InvalidCodePoint; + case Ipv6TooFewPieces; + case Ipv4InIpv6TooManyPieces; + case Ipv4InIpv6InvalidCodePoint; + case Ipv4InIpv6OutOfRangePart; + case Ipv4InIpv6TooFewParts; + case InvalidUrlUnit; + case SpecialSchemeMissingFollowingSolidus; + case MissingSchemeNonRelativeUrl; + case InvalidReverseSoldius; + case InvalidCredentials; + case HostMissing; + case PortOutOfRange; + case PortInvalid; + case FileInvalidWindowsDriveLetter; + case FileInvalidWindowsDriveLetterHost; + } + + /** @strict-properties */ + final readonly class UrlValidationError + { + public string $context; + public \Uri\WhatWg\UrlValidationErrorType $type; + public bool $failure; + + public function __construct(string $context, \Uri\WhatWg\UrlValidationErrorType $type, bool $failure) {} + } + + /** @strict-properties */ + final readonly class Url + { + /** @param array $errors */ + public static function parse(string $uri, ?\Uri\WhatWg\Url $baseUrl = null, &$errors = null): ?static {} + + /** @param array $softErrors */ + public function __construct(string $uri, ?\Uri\WhatWg\Url $baseUrl = null, &$softErrors = null) {} + + public function getScheme(): string {} + + public function withScheme(string $scheme): static {} + + public function getUsername(): ?string {} + + public function withUsername(?string $username): static {} + + public function getPassword(): ?string {} + + public function withPassword(#[\SensitiveParameter] ?string $password): static {} + + public function getAsciiHost(): ?string {} + + public function getUnicodeHost(): ?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 equals(\Uri\WhatWg\Url $url, \Uri\UriComparisonMode $comparisonMode = \Uri\UriComparisonMode::ExcludeFragment): bool {} + + public function toAsciiString(): string {} + + public function toUnicodeString(): string {} + + /** @param array $softErrors */ + public function resolve(string $uri, &$softErrors = null): static {} + + public function __serialize(): array {} + + public function __unserialize(array $data): void {} + + public function __debugInfo(): array {} } } diff --git a/ext/uri/php_uri_arginfo.h b/ext/uri/php_uri_arginfo.h index 124a6b3719849..0ae755a9f70dc 100644 --- a/ext/uri/php_uri_arginfo.h +++ b/ext/uri/php_uri_arginfo.h @@ -1,5 +1,175 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 35460b24cf237585dabdc9813212c343034cf591 */ + * Stub hash: 1945c28deef13c2af552b18c2a5a6c7798d4aeec */ + +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, "[]") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, code, IS_LONG, 0, "0") + ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, previous, Throwable, 1, "null") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Uri_WhatWg_UrlValidationError___construct, 0, 0, 3) + ZEND_ARG_TYPE_INFO(0, context, IS_STRING, 0) + ZEND_ARG_OBJ_INFO(0, type, Uri\\WhatWg\\\125rlValidationErrorType, 0) + 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_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") + ZEND_ARG_INFO_WITH_DEFAULT_VALUE(1, errors, "null") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Uri_WhatWg_Url___construct, 0, 0, 1) + ZEND_ARG_TYPE_INFO(0, uri, IS_STRING, 0) + ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, baseUrl, Uri\\WhatWg\\\125rl, 1, "null") + ZEND_ARG_INFO_WITH_DEFAULT_VALUE(1, softErrors, "null") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_getScheme, 0, 0, IS_STRING, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_withScheme, 0, 1, IS_STATIC, 0) + 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_getUsername, 0, 0, IS_STRING, 1) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_withUsername, 0, 1, IS_STATIC, 0) + ZEND_ARG_TYPE_INFO(0, username, IS_STRING, 1) +ZEND_END_ARG_INFO() + +#define arginfo_class_Uri_WhatWg_Url_getPassword arginfo_class_Uri_WhatWg_Url_getUsername + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_withPassword, 0, 1, IS_STATIC, 0) + ZEND_ARG_TYPE_INFO(0, password, IS_STRING, 1) +ZEND_END_ARG_INFO() + +#define arginfo_class_Uri_WhatWg_Url_getAsciiHost arginfo_class_Uri_WhatWg_Url_getUsername + +#define arginfo_class_Uri_WhatWg_Url_getUnicodeHost arginfo_class_Uri_WhatWg_Url_getUsername + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_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_WhatWg_Url_getPort, 0, 0, IS_LONG, 1) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_withPort, 0, 1, IS_STATIC, 0) + ZEND_ARG_TYPE_INFO(0, port, IS_LONG, 1) +ZEND_END_ARG_INFO() + +#define arginfo_class_Uri_WhatWg_Url_getPath arginfo_class_Uri_WhatWg_Url_getScheme + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_withPath, 0, 1, IS_STATIC, 0) + ZEND_ARG_TYPE_INFO(0, path, IS_STRING, 0) +ZEND_END_ARG_INFO() + +#define arginfo_class_Uri_WhatWg_Url_getQuery arginfo_class_Uri_WhatWg_Url_getUsername + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_withQuery, 0, 1, IS_STATIC, 0) + ZEND_ARG_TYPE_INFO(0, query, IS_STRING, 1) +ZEND_END_ARG_INFO() + +#define arginfo_class_Uri_WhatWg_Url_getFragment arginfo_class_Uri_WhatWg_Url_getUsername + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_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_WhatWg_Url_equals, 0, 1, _IS_BOOL, 0) + ZEND_ARG_OBJ_INFO(0, url, Uri\\WhatWg\\\125rl, 0) + ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, comparisonMode, Uri\\\125riComparisonMode, 0, "Uri\\UriComparisonMode::ExcludeFragment") +ZEND_END_ARG_INFO() + +#define arginfo_class_Uri_WhatWg_Url_toAsciiString arginfo_class_Uri_WhatWg_Url_getScheme + +#define arginfo_class_Uri_WhatWg_Url_toUnicodeString arginfo_class_Uri_WhatWg_Url_getScheme + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_resolve, 0, 1, IS_STATIC, 0) + ZEND_ARG_TYPE_INFO(0, uri, IS_STRING, 0) + ZEND_ARG_INFO_WITH_DEFAULT_VALUE(1, softErrors, "null") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url___serialize, 0, 0, IS_ARRAY, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url___unserialize, 0, 1, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) +ZEND_END_ARG_INFO() + +#define arginfo_class_Uri_WhatWg_Url___debugInfo arginfo_class_Uri_WhatWg_Url___serialize + +ZEND_METHOD(Uri_WhatWg_InvalidUrlException, __construct); +ZEND_METHOD(Uri_WhatWg_UrlValidationError, __construct); +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, getUsername); +ZEND_METHOD(Uri_WhatWg_Url, withUsername); +ZEND_METHOD(Uri_WhatWg_Url, getPassword); +ZEND_METHOD(Uri_WhatWg_Url, withPassword); +ZEND_METHOD(Uri_WhatWg_Url, getAsciiHost); +ZEND_METHOD(Uri_WhatWg_Url, getUnicodeHost); +ZEND_METHOD(Uri_WhatWg_Url, withHost); +ZEND_METHOD(Uri_WhatWg_Url, getPort); +ZEND_METHOD(Uri_WhatWg_Url, withPort); +ZEND_METHOD(Uri_WhatWg_Url, getPath); +ZEND_METHOD(Uri_WhatWg_Url, withPath); +ZEND_METHOD(Uri_WhatWg_Url, getQuery); +ZEND_METHOD(Uri_WhatWg_Url, withQuery); +ZEND_METHOD(Uri_WhatWg_Url, getFragment); +ZEND_METHOD(Uri_WhatWg_Url, withFragment); +ZEND_METHOD(Uri_WhatWg_Url, equals); +ZEND_METHOD(Uri_WhatWg_Url, toAsciiString); +ZEND_METHOD(Uri_WhatWg_Url, toUnicodeString); +ZEND_METHOD(Uri_WhatWg_Url, resolve); +ZEND_METHOD(Uri_WhatWg_Url, __serialize); +ZEND_METHOD(Uri_WhatWg_Url, __unserialize); +ZEND_METHOD(Uri_WhatWg_Url, __debugInfo); + +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 +}; + +static const zend_function_entry class_Uri_WhatWg_UrlValidationError_methods[] = { + ZEND_ME(Uri_WhatWg_UrlValidationError, __construct, arginfo_class_Uri_WhatWg_UrlValidationError___construct, ZEND_ACC_PUBLIC) + ZEND_FE_END +}; + +static const zend_function_entry class_Uri_WhatWg_Url_methods[] = { + 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, getUsername, arginfo_class_Uri_WhatWg_Url_getUsername, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_Url, withUsername, arginfo_class_Uri_WhatWg_Url_withUsername, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_Url, getPassword, arginfo_class_Uri_WhatWg_Url_getPassword, ZEND_ACC_PUBLIC) + 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, withHost, arginfo_class_Uri_WhatWg_Url_withHost, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_Url, getPort, arginfo_class_Uri_WhatWg_Url_getPort, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_Url, withPort, arginfo_class_Uri_WhatWg_Url_withPort, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_Url, getPath, arginfo_class_Uri_WhatWg_Url_getPath, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_Url, withPath, arginfo_class_Uri_WhatWg_Url_withPath, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_Url, getQuery, arginfo_class_Uri_WhatWg_Url_getQuery, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_Url, withQuery, arginfo_class_Uri_WhatWg_Url_withQuery, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_Url, getFragment, arginfo_class_Uri_WhatWg_Url_getFragment, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_Url, withFragment, arginfo_class_Uri_WhatWg_Url_withFragment, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_Url, equals, arginfo_class_Uri_WhatWg_Url_equals, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_Url, toAsciiString, arginfo_class_Uri_WhatWg_Url_toAsciiString, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_Url, toUnicodeString, arginfo_class_Uri_WhatWg_Url_toUnicodeString, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_Url, resolve, arginfo_class_Uri_WhatWg_Url_resolve, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_Url, __serialize, arginfo_class_Uri_WhatWg_Url___serialize, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_Url, __unserialize, arginfo_class_Uri_WhatWg_Url___unserialize, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_WhatWg_Url, __debugInfo, arginfo_class_Uri_WhatWg_Url___debugInfo, ZEND_ACC_PUBLIC) + ZEND_FE_END +}; static zend_class_entry *register_class_Uri_UriException(zend_class_entry *class_entry_Exception) { @@ -21,11 +191,22 @@ static zend_class_entry *register_class_Uri_InvalidUriException(zend_class_entry return class_entry; } +static zend_class_entry *register_class_Uri_UriComparisonMode(void) +{ + zend_class_entry *class_entry = zend_register_internal_enum("Uri\\UriComparisonMode", IS_UNDEF, NULL); + + zend_enum_add_case_cstr(class_entry, "IncludeFragment", NULL); + + zend_enum_add_case_cstr(class_entry, "ExcludeFragment", NULL); + + return class_entry; +} + static zend_class_entry *register_class_Uri_WhatWg_InvalidUrlException(zend_class_entry *class_entry_Uri_InvalidUriException) { zend_class_entry ce, *class_entry; - INIT_NS_CLASS_ENTRY(ce, "Uri\\WhatWg", "InvalidUrlException", NULL); + INIT_NS_CLASS_ENTRY(ce, "Uri\\WhatWg", "InvalidUrlException", class_Uri_WhatWg_InvalidUrlException_methods); class_entry = zend_register_internal_class_with_flags(&ce, class_entry_Uri_InvalidUriException, ZEND_ACC_NO_DYNAMIC_PROPERTIES); zval property_errors_default_value; @@ -36,3 +217,108 @@ static zend_class_entry *register_class_Uri_WhatWg_InvalidUrlException(zend_clas return class_entry; } + +static zend_class_entry *register_class_Uri_WhatWg_UrlValidationErrorType(void) +{ + zend_class_entry *class_entry = zend_register_internal_enum("Uri\\WhatWg\\UrlValidationErrorType", IS_UNDEF, NULL); + + zend_enum_add_case_cstr(class_entry, "DomainToAscii", NULL); + + zend_enum_add_case_cstr(class_entry, "DomainToUnicode", NULL); + + zend_enum_add_case_cstr(class_entry, "DomainInvalidCodePoint", NULL); + + zend_enum_add_case_cstr(class_entry, "HostInvalidCodePoint", NULL); + + zend_enum_add_case_cstr(class_entry, "Ipv4EmptyPart", NULL); + + zend_enum_add_case_cstr(class_entry, "Ipv4TooManyParts", NULL); + + zend_enum_add_case_cstr(class_entry, "Ipv4NonNumericPart", NULL); + + zend_enum_add_case_cstr(class_entry, "Ipv4NonDecimalPart", NULL); + + zend_enum_add_case_cstr(class_entry, "Ipv4OutOfRangePart", NULL); + + zend_enum_add_case_cstr(class_entry, "Ipv6Unclosed", NULL); + + zend_enum_add_case_cstr(class_entry, "Ipv6InvalidCompression", NULL); + + zend_enum_add_case_cstr(class_entry, "Ipv6TooManyPieces", NULL); + + zend_enum_add_case_cstr(class_entry, "Ipv6MultipleCompression", NULL); + + zend_enum_add_case_cstr(class_entry, "Ipv6InvalidCodePoint", NULL); + + zend_enum_add_case_cstr(class_entry, "Ipv6TooFewPieces", NULL); + + zend_enum_add_case_cstr(class_entry, "Ipv4InIpv6TooManyPieces", NULL); + + zend_enum_add_case_cstr(class_entry, "Ipv4InIpv6InvalidCodePoint", NULL); + + zend_enum_add_case_cstr(class_entry, "Ipv4InIpv6OutOfRangePart", NULL); + + zend_enum_add_case_cstr(class_entry, "Ipv4InIpv6TooFewParts", NULL); + + zend_enum_add_case_cstr(class_entry, "InvalidUrlUnit", NULL); + + zend_enum_add_case_cstr(class_entry, "SpecialSchemeMissingFollowingSolidus", NULL); + + zend_enum_add_case_cstr(class_entry, "MissingSchemeNonRelativeUrl", NULL); + + zend_enum_add_case_cstr(class_entry, "InvalidReverseSoldius", NULL); + + zend_enum_add_case_cstr(class_entry, "InvalidCredentials", NULL); + + zend_enum_add_case_cstr(class_entry, "HostMissing", NULL); + + zend_enum_add_case_cstr(class_entry, "PortOutOfRange", NULL); + + zend_enum_add_case_cstr(class_entry, "PortInvalid", NULL); + + zend_enum_add_case_cstr(class_entry, "FileInvalidWindowsDriveLetter", NULL); + + zend_enum_add_case_cstr(class_entry, "FileInvalidWindowsDriveLetterHost", NULL); + + return class_entry; +} + +static zend_class_entry *register_class_Uri_WhatWg_UrlValidationError(void) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "Uri\\WhatWg", "UrlValidationError", class_Uri_WhatWg_UrlValidationError_methods); + class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_READONLY_CLASS); + + zval property_context_default_value; + ZVAL_UNDEF(&property_context_default_value); + zend_string *property_context_name = zend_string_init("context", sizeof("context") - 1, 1); + zend_declare_typed_property(class_entry, property_context_name, &property_context_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); + zend_string_release(property_context_name); + + zval property_type_default_value; + ZVAL_UNDEF(&property_type_default_value); + zend_string *property_type_class_Uri_WhatWg_UrlValidationErrorType = zend_string_init("Uri\\WhatWg\\\125rlValidationErrorType", sizeof("Uri\\WhatWg\\\125rlValidationErrorType")-1, 1); + zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_TYPE), &property_type_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_type_class_Uri_WhatWg_UrlValidationErrorType, 0, 0)); + + zval property_failure_default_value; + ZVAL_UNDEF(&property_failure_default_value); + zend_string *property_failure_name = zend_string_init("failure", sizeof("failure") - 1, 1); + zend_declare_typed_property(class_entry, property_failure_name, &property_failure_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); + zend_string_release(property_failure_name); + + return class_entry; +} + +static zend_class_entry *register_class_Uri_WhatWg_Url(void) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "Uri\\WhatWg", "Url", class_Uri_WhatWg_Url_methods); + class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_READONLY_CLASS); + + + zend_add_parameter_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "withpassword", sizeof("withpassword") - 1), 0, ZSTR_KNOWN(ZEND_STR_SENSITIVEPARAMETER), 0); + + return class_entry; +} diff --git a/ext/uri/php_uri_common.c b/ext/uri/php_uri_common.c new file mode 100644 index 0000000000000..9128b942e57b8 --- /dev/null +++ b/ext/uri/php_uri_common.c @@ -0,0 +1,169 @@ +/* + +----------------------------------------------------------------------+ + | 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 "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, "%s::$%s property cannot be retrieved", ZSTR_VAL(Z_OBJ_P(ZEND_THIS)->ce->name), + 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)); + if (UNEXPECTED(EG(exception) != NULL)) { + zend_object_release(new_object); + RETURN_THROWS(); + } + + uri_internal_t *new_internal_uri = uri_internal_from_obj(new_object); + URI_ASSERT_INITIALIZATION(new_internal_uri); + if (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 (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); +} diff --git a/ext/uri/php_uri_common.h b/ext/uri/php_uri_common.h new file mode 100644 index 0000000000000..1aee1cd512472 --- /dev/null +++ b/ext/uri/php_uri_common.h @@ -0,0 +1,138 @@ +/* + +----------------------------------------------------------------------+ + | 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_COMMON_H +#define PHP_URI_COMMON_H + +extern zend_class_entry *uri_whatwg_url_ce; +extern zend_object_handlers uri_whatwg_uri_object_handlers; +extern zend_class_entry *uri_comparison_mode_ce; +extern zend_class_entry *uri_exception_ce; +extern zend_class_entry *uri_invalid_uri_exception_ce; +extern zend_class_entry *uri_whatwg_invalid_url_exception_ce; +extern zend_class_entry *uri_whatwg_url_validation_error_type_ce; +extern zend_class_entry *uri_whatwg_url_validation_error_ce; +extern zend_object *uri_clone_obj_handler(zend_object *object); + +typedef enum { + URI_RECOMPOSITION_RAW_ASCII, + URI_RECOMPOSITION_RAW_UNICODE, + URI_RECOMPOSITION_NORMALIZED_ASCII, + URI_RECOMPOSITION_NORMALIZED_UNICODE, +} uri_recomposition_mode_t; + +typedef enum { + URI_COMPONENT_READ_RAW, + URI_COMPONENT_READ_NORMALIZED_ASCII, + URI_COMPONENT_READ_NORMALIZED_UNICODE, +} uri_component_read_mode_t; + +struct uri_internal_t; + +typedef zend_result (*uri_read_t)(const struct uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval); + +typedef zend_result (*uri_write_t)(struct uri_internal_t *internal_uri, zval *value, zval *errors); + +typedef enum { + URI_PROPERTY_NAME_SCHEME, + URI_PROPERTY_NAME_USERNAME, + URI_PROPERTY_NAME_PASSWORD, + URI_PROPERTY_NAME_HOST, + URI_PROPERTY_NAME_PORT, + URI_PROPERTY_NAME_PATH, + URI_PROPERTY_NAME_QUERY, + URI_PROPERTY_NAME_FRAGMENT, +} uri_property_name_t; + +typedef struct uri_property_handler_t { + uri_read_t read_func; + uri_write_t write_func; +} uri_property_handler_t; + +typedef struct uri_property_handlers_t { + uri_property_handler_t scheme; + uri_property_handler_t username; + uri_property_handler_t password; + uri_property_handler_t host; + uri_property_handler_t port; + uri_property_handler_t path; + uri_property_handler_t query; + uri_property_handler_t fragment; +} uri_property_handlers_t; + +typedef struct uri_handler_t { + const char *name; + + /** + * Parse a URI string into a URI. + * + * If the URI string is valid, a URI is returned. In case of failure, NULL is + * returned. + * + * The errors by-ref parameter can contain errors that occurred during parsing. + * If the input value is NULL, or there were no errors, the errors parameter should + * not be modified. + * + * If the URI string is valid and the base_url URI is not NULL, the URI object + * is resolved against the base_url. + * + * If the silent parameter is true, a Uri\InvalidUriException instance must be thrown. + * If the parameter is false, the possible errors should be handled by the caller. + */ + void *(*parse_uri)(const zend_string *uri_str, const void *base_url, zval *errors, bool silent); + void *(*clone_uri)(void *uri); + zend_string *(*uri_to_string)(void *uri, uri_recomposition_mode_t recomposition_mode, bool exclude_fragment); + void (*free_uri)(void *uri); + + const uri_property_handlers_t property_handlers; +} uri_handler_t; + +typedef struct uri_internal_t { + const uri_handler_t *handler; + void *uri; +} uri_internal_t; + +typedef struct uri_object_t { + uri_internal_t internal; + zend_object std; +} uri_object_t; + +static inline uri_object_t *uri_object_from_obj(const zend_object *object) { + return (uri_object_t*)((char*)(object) - XtOffsetOf(uri_object_t, std)); +} + +static inline uri_internal_t *uri_internal_from_obj(const zend_object *object) { + return &(uri_object_from_obj(object)->internal); +} + +#define Z_URI_OBJECT_P(zv) uri_object_from_obj(Z_OBJ_P((zv))) +#define Z_URI_INTERNAL_P(zv) uri_internal_from_obj(Z_OBJ_P((zv))) + +#define URI_PARSER_WHATWG "Uri\\WhatWg\\Url" +#define URI_SERIALIZED_PROPERTY_NAME "uri" + +zend_result uri_handler_register(const uri_handler_t *uri_handler); +const uri_property_handler_t *uri_property_handler_from_internal_uri(const uri_internal_t *internal_uri, uri_property_name_t property_name); +void uri_read_component(INTERNAL_FUNCTION_PARAMETERS, uri_property_name_t property_name, uri_component_read_mode_t component_read_mode); +void uri_write_component_str(INTERNAL_FUNCTION_PARAMETERS, uri_property_name_t property_name); +void uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAMETERS, uri_property_name_t property_name); +void uri_write_component_long_or_null(INTERNAL_FUNCTION_PARAMETERS, uri_property_name_t property_name); + +#define URI_ASSERT_INITIALIZATION(internal_uri) do { \ + ZEND_ASSERT(internal_uri != NULL && internal_uri->uri != NULL); \ +} while (0) + +#endif diff --git a/ext/uri/tests/003.phpt b/ext/uri/tests/003.phpt new file mode 100644 index 0000000000000..bcd6e417441c2 --- /dev/null +++ b/ext/uri/tests/003.phpt @@ -0,0 +1,32 @@ +--TEST-- +Parse URL exotic URLs +--EXTENSIONS-- +uri +--FILE-- + +--EXPECTF-- +object(Uri\WhatWg\Url)#%d (%d) { + ["scheme"]=> + string(4) "http" + ["username"]=> + string(8) "username" + ["password"]=> + string(8) "password" + ["host"]=> + string(18) "xn--hostname-b1aaa" + ["port"]=> + int(9090) + ["path"]=> + string(5) "/path" + ["query"]=> + string(14) "arg=va%C3%A9ue" + ["fragment"]=> + string(6) "anchor" +} +NULL diff --git a/ext/uri/tests/004.phpt b/ext/uri/tests/004.phpt new file mode 100644 index 0000000000000..04127a7ded0d3 --- /dev/null +++ b/ext/uri/tests/004.phpt @@ -0,0 +1,25 @@ +--TEST-- +Parse invalid URLs +--EXTENSIONS-- +uri +--FILE-- +getMessage() . "\n"; +} + +var_dump(Uri\WhatWg\Url::parse("")); + +var_dump(Uri\WhatWg\Url::parse("192.168/contact.html", null)); + +var_dump(Uri\WhatWg\Url::parse("http://RuPaul's Drag Race All Stars 7 Winners Cast on This Season's", null)); + +?> +--EXPECTF-- +URL parsing failed +NULL +NULL +NULL diff --git a/ext/uri/tests/005.phpt b/ext/uri/tests/005.phpt new file mode 100644 index 0000000000000..262d43a75406b --- /dev/null +++ b/ext/uri/tests/005.phpt @@ -0,0 +1,38 @@ +--TEST-- +Parse multibyte URLs +--EXTENSIONS-- +uri +--FILE-- +getAsciiHost()); +var_dump($url->getUnicodeHost()); +var_dump($url->toAsciiString()); +var_dump($url->toUnicodeString()); + +?> +--EXPECTF-- +object(Uri\WhatWg\Url)#%d (%d) { + ["scheme"]=> + string(4) "http" + ["username"]=> + string(8) "username" + ["password"]=> + string(8) "password" + ["host"]=> + string(18) "xn--hostname-b1aaa" + ["port"]=> + int(9090) + ["path"]=> + string(5) "/path" + ["query"]=> + string(14) "arg=va%C3%A9ue" + ["fragment"]=> + string(6) "anchor" +} +string(18) "xn--hostname-b1aaa" +string(14) "héééostname" +string(75) "http://username:password@xn--hostname-b1aaa:9090/path?arg=va%C3%A9ue#anchor" +string(71) "http://username:password@héééostname:9090/path?arg=va%C3%A9ue#anchor" diff --git a/ext/uri/tests/006.phpt b/ext/uri/tests/006.phpt new file mode 100644 index 0000000000000..0aba3e9e46b5e --- /dev/null +++ b/ext/uri/tests/006.phpt @@ -0,0 +1,30 @@ +--TEST-- +Test successful manual Uri child instance creation +--EXTENSIONS-- +uri +--FILE-- + +--EXPECTF-- +object(Uri\WhatWg\Url)#%d (%d) { + ["scheme"]=> + string(5) "https" + ["username"]=> + string(8) "username" + ["password"]=> + string(8) "password" + ["host"]=> + string(11) "example.com" + ["port"]=> + int(8080) + ["path"]=> + string(5) "/path" + ["query"]=> + string(3) "q=r" + ["fragment"]=> + string(8) "fragment" +} diff --git a/ext/uri/tests/007.phpt b/ext/uri/tests/007.phpt new file mode 100644 index 0000000000000..e60e69fc113a3 --- /dev/null +++ b/ext/uri/tests/007.phpt @@ -0,0 +1,63 @@ +--TEST-- +Test URI creation errors +--EXTENSIONS-- +uri +--FILE-- +getMessage() . "\n"; + var_dump($e->errors); +} + +$failures = []; +$url = new Uri\WhatWg\Url(" https://example.org ", null, $failures); +var_dump($url->toAsciiString()); +var_dump($failures); + +?> +--EXPECTF-- +URL parsing failed +array(%d) { + [0]=> + object(Uri\WhatWg\UrlValidationError)#%d (%d) { + ["context"]=> + string(26) "password/path?q=r#fragment" + ["type"]=> + enum(Uri\WhatWg\UrlValidationErrorType::PortInvalid) + ["failure"]=> + bool(true) + } + [1]=> + object(Uri\WhatWg\UrlValidationError)#%d (%d) { + ["context"]=> + string(36) "@username:password/path?q=r#fragment" + ["type"]=> + enum(Uri\WhatWg\UrlValidationErrorType::InvalidCredentials) + ["failure"]=> + bool(false) + } +} +string(20) "https://example.org/" +array(2) { + [0]=> + object(Uri\WhatWg\UrlValidationError)#%d (%d) { + ["context"]=> + string(1) " " + ["type"]=> + enum(Uri\WhatWg\UrlValidationErrorType::InvalidUrlUnit) + ["failure"]=> + bool(false) + } + [1]=> + object(Uri\WhatWg\UrlValidationError)#%d (%d) { + ["context"]=> + string(21) " https://example.org " + ["type"]=> + enum(Uri\WhatWg\UrlValidationErrorType::InvalidUrlUnit) + ["failure"]=> + bool(false) + } +} diff --git a/ext/uri/tests/008.phpt b/ext/uri/tests/008.phpt new file mode 100644 index 0000000000000..f4fddcd8eb777 --- /dev/null +++ b/ext/uri/tests/008.phpt @@ -0,0 +1,34 @@ +--TEST-- +Test Uri getters +--EXTENSIONS-- +uri +--FILE-- +getScheme()); + var_dump($url->getUsername()); + var_dump($url->getPassword()); + var_dump($url->getAsciiHost()); + var_dump($url->getUnicodeHost()); + var_dump($url->getPort()); + var_dump($url->getPath()); + var_dump($url->getQuery()); + var_dump($url->getFragment()); +} + +$url = Uri\WhatWg\Url::parse("https://username:password@www.google.com:8080/pathname1/pathname2/pathname3?query=true#hash-exists"); +callWhatWgGetters($url); + +?> +--EXPECT-- +string(5) "https" +string(8) "username" +string(8) "password" +string(14) "www.google.com" +string(14) "www.google.com" +int(8080) +string(30) "/pathname1/pathname2/pathname3" +string(10) "query=true" +string(11) "hash-exists" diff --git a/ext/uri/tests/009.phpt b/ext/uri/tests/009.phpt new file mode 100644 index 0000000000000..1b279588c0167 --- /dev/null +++ b/ext/uri/tests/009.phpt @@ -0,0 +1,29 @@ +--TEST-- +Test parsing with IANA schemes +--EXTENSIONS-- +uri +--FILE-- + +--EXPECTF-- +object(Uri\WhatWg\Url)#%d (%d) { + ["scheme"]=> + string(16) "chrome-extension" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(0) "" + ["query"]=> + NULL + ["fragment"]=> + NULL +} diff --git a/ext/uri/tests/010.phpt b/ext/uri/tests/010.phpt new file mode 100644 index 0000000000000..4ec13f652f60c --- /dev/null +++ b/ext/uri/tests/010.phpt @@ -0,0 +1,48 @@ +--TEST-- +Test parsing URIs when a base URI is present +--EXTENSIONS-- +uri +--FILE-- + +--EXPECTF-- +object(Uri\WhatWg\Url)#%d (%d) { + ["scheme"]=> + string(4) "http" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(14) "/path/to/file1" + ["query"]=> + NULL + ["fragment"]=> + NULL +} +object(Uri\WhatWg\Url)#%d (%d) { + ["scheme"]=> + string(5) "https" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(8) "test.com" + ["port"]=> + NULL + ["path"]=> + string(14) "/path/to/file1" + ["query"]=> + NULL + ["fragment"]=> + NULL +} diff --git a/ext/uri/tests/011.phpt b/ext/uri/tests/011.phpt new file mode 100644 index 0000000000000..283886fb34fbb --- /dev/null +++ b/ext/uri/tests/011.phpt @@ -0,0 +1,22 @@ +--TEST-- +Test encoding and normalization +--EXTENSIONS-- +uri +--FILE-- +toAsciiString()); +var_dump(Uri\WhatWg\Url::parse("https://www.example.com:443/dir1/../dir2")->toAsciiString()); +var_dump(Uri\WhatWg\Url::parse("https://你好你好")->toAsciiString()); +var_dump(Uri\WhatWg\Url::parse("https://你好你好")->toUnicodeString()); +var_dump(Uri\WhatWg\Url::parse("https://0Xc0.0250.01")->toAsciiString()); +var_dump(Uri\WhatWg\Url::parse("HttPs://0300.0250.0000.0001/path?query=foo%20bar")->toAsciiString()); + +?> +--EXPECT-- +string(23) "http://www.example.com/" +string(28) "https://www.example.com/dir2" +string(23) "https://xn--6qqa088eba/" +string(21) "https://你好你好/" +string(20) "https://192.168.0.1/" +string(40) "https://192.168.0.1/path?query=foo%20bar" diff --git a/ext/uri/tests/012.phpt b/ext/uri/tests/012.phpt new file mode 100644 index 0000000000000..0784a74e625f0 --- /dev/null +++ b/ext/uri/tests/012.phpt @@ -0,0 +1,49 @@ +--TEST-- +Test parsing of various schemes +--EXTENSIONS-- +uri +--FILE-- + +--EXPECTF-- +object(Uri\WhatWg\Url)#%d (%d) { + ["scheme"]=> + string(6) "mailto" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + NULL + ["port"]=> + NULL + ["path"]=> + string(15) "Joe@Example.COM" + ["query"]=> + NULL + ["fragment"]=> + NULL +} +object(Uri\WhatWg\Url)#%d (%d) { + ["scheme"]=> + string(4) "file" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + NULL + ["port"]=> + NULL + ["path"]=> + string(30) "/E:/Documents%20and%20Settings" + ["query"]=> + NULL + ["fragment"]=> + NULL +} diff --git a/ext/uri/tests/013.phpt b/ext/uri/tests/013.phpt new file mode 100644 index 0000000000000..016fe6632782c --- /dev/null +++ b/ext/uri/tests/013.phpt @@ -0,0 +1,87 @@ +--TEST-- +Test parsing of query strings +--EXTENSIONS-- +uri +--FILE-- + + @")); + +?> +--EXPECTF-- +object(Uri\WhatWg\Url)#%d (%d) { + ["scheme"]=> + string(4) "http" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(1) "/" + ["query"]=> + string(25) "foo=Hell%C3%B3+W%C3%B6rld" + ["fragment"]=> + NULL +} +object(Uri\WhatWg\Url)#%d (%d) { + ["scheme"]=> + string(4) "http" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(1) "/" + ["query"]=> + string(27) "foo=Hell%C3%B3%20W%C3%B6rld" + ["fragment"]=> + NULL +} +object(Uri\WhatWg\Url)#%d (%d) { + ["scheme"]=> + string(4) "http" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(1) "/" + ["query"]=> + string(30) "foobar=%27%3Cscript%3E+%2B+%40" + ["fragment"]=> + NULL +} +object(Uri\WhatWg\Url)#%d (%d) { + ["scheme"]=> + string(4) "http" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(1) "/" + ["query"]=> + string(30) "foobar=%27%3Cscript%3E%20+%20@" + ["fragment"]=> + NULL +} diff --git a/ext/uri/tests/014.phpt b/ext/uri/tests/014.phpt new file mode 100644 index 0000000000000..224b0c9b64fb4 --- /dev/null +++ b/ext/uri/tests/014.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test recomposition of URIs +--EXTENSIONS-- +uri +--FILE-- +toAsciiString()); + +?> +--EXPECT-- +string(45) "http://example.com/?foo=Hell%C3%B3+W%C3%B6rld" diff --git a/ext/uri/tests/015.phpt b/ext/uri/tests/015.phpt new file mode 100644 index 0000000000000..4df353e942186 --- /dev/null +++ b/ext/uri/tests/015.phpt @@ -0,0 +1,18 @@ +--TEST-- +Test instantiation without calling constructor +--EXTENSIONS-- +reflection +uri +--FILE-- +newInstanceWithoutConstructor(); +} catch (ReflectionException $e) { + echo $e->getMessage() . "\n"; +} + +?> +--EXPECT-- +Class Uri\WhatWg\Url is an internal class marked as final that cannot be instantiated without invoking its constructor diff --git a/ext/uri/tests/018.phpt b/ext/uri/tests/018.phpt new file mode 100644 index 0000000000000..bf8caffb5e7ec --- /dev/null +++ b/ext/uri/tests/018.phpt @@ -0,0 +1,50 @@ +--TEST-- +Test property mutation +--EXTENSIONS-- +uri +--FILE-- + +--EXPECTF-- +object(Uri\WhatWg\Url)#1 (%d) { + ["scheme"]=> + string(5) "https" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(1) "/" + ["query"]=> + NULL + ["fragment"]=> + NULL +} +object(Uri\WhatWg\Url)#2 (%d) { + ["scheme"]=> + string(5) "https" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(1) "/" + ["query"]=> + NULL + ["fragment"]=> + NULL +} diff --git a/ext/uri/tests/019.phpt b/ext/uri/tests/019.phpt new file mode 100644 index 0000000000000..df19fb14196ac --- /dev/null +++ b/ext/uri/tests/019.phpt @@ -0,0 +1,55 @@ +--TEST-- +Test IDNA support +--EXTENSIONS-- +uri +--FILE-- +getAsciiHost()); +var_dump($url->getUnicodeHost()); +var_dump($url->toAsciiString()); +var_dump($url->toUnicodeString()); + +?> +--EXPECTF-- +NULL +array(1) { + [0]=> + object(Uri\WhatWg\UrlValidationError)#%d (%d) { + ["context"]=> + string(4) "🐘" + ["type"]=> + enum(Uri\WhatWg\UrlValidationErrorType::MissingSchemeNonRelativeUrl) + ["failure"]=> + bool(true) + } +} +object(Uri\WhatWg\Url)#%d (%d) { + ["scheme"]=> + string(5) "https" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(12) "xn--go8h.com" + ["port"]=> + NULL + ["path"]=> + string(13) "/%F0%9F%90%98" + ["query"]=> + string(25) "%F0%9F%90%98=%F0%9F%90%98" + ["fragment"]=> + NULL +} +string(12) "xn--go8h.com" +string(8) "🐘.com" +string(59) "https://xn--go8h.com/%F0%9F%90%98?%F0%9F%90%98=%F0%9F%90%98" +string(55) "https://🐘.com/%F0%9F%90%98?%F0%9F%90%98=%F0%9F%90%98" diff --git a/ext/uri/tests/022.phpt b/ext/uri/tests/022.phpt new file mode 100644 index 0000000000000..1e920c5055f81 --- /dev/null +++ b/ext/uri/tests/022.phpt @@ -0,0 +1,14 @@ +--TEST-- +Test extension of Uri\WhatWg\Url +--EXTENSIONS-- +uri +--FILE-- + +--EXPECTF-- +Fatal error: Class MyWhatWgUri cannot extend final class Uri\WhatWg\Url in %s on line %d diff --git a/ext/uri/tests/023.phpt b/ext/uri/tests/023.phpt new file mode 100644 index 0000000000000..b48e2df838eef --- /dev/null +++ b/ext/uri/tests/023.phpt @@ -0,0 +1,31 @@ +--TEST-- +Test property mutation - scheme +--EXTENSIONS-- +uri +--FILE-- +withScheme("http"); + +var_dump($url1->getScheme()); +var_dump($url2->getScheme()); + +try { + $url2->withScheme(""); +} catch (Uri\WhatWg\InvalidUrlException $e) { + echo $e->getMessage() . "\n"; +} + +try { + $url2->withScheme("http%73"); +} catch (Uri\WhatWg\InvalidUrlException $e) { + echo $e->getMessage() . "\n"; +} + +?> +--EXPECT-- +string(5) "https" +string(4) "http" +URL parsing failed +URL parsing failed diff --git a/ext/uri/tests/024.phpt b/ext/uri/tests/024.phpt new file mode 100644 index 0000000000000..907be0091d7c7 --- /dev/null +++ b/ext/uri/tests/024.phpt @@ -0,0 +1,29 @@ +--TEST-- +Test property mutation - username +--EXTENSIONS-- +uri +--FILE-- +withUsername("user"); +$url3 = $url2->withUsername(null); +$url4 = $url3->withUsername("%75s%2Fr"); // us/r +$url5 = $url4->withUsername("u:s/r"); + +$url6 = Uri\WhatWg\Url::parse("file:///foo/bar/"); +$url6 = $url6->withUsername("user"); + +var_dump($url2->getUsername()); +var_dump($url3->getUsername()); +var_dump($url4->getUsername()); +var_dump($url5->getUsername()); +var_dump($url6->getUsername()); + +?> +--EXPECT-- +string(4) "user" +NULL +string(8) "%75s%2Fr" +string(9) "u%3As%2Fr" +NULL diff --git a/ext/uri/tests/025.phpt b/ext/uri/tests/025.phpt new file mode 100644 index 0000000000000..dafc36043bcbc --- /dev/null +++ b/ext/uri/tests/025.phpt @@ -0,0 +1,29 @@ +--TEST-- +Test property mutation - password +--EXTENSIONS-- +uri +--FILE-- +withPassword("pass"); +$url3 = $url2->withPassword(null); +$url4 = $url3->withPassword("p%61ss"); +$url5 = $url4->withPassword("p:s/"); + +$url6 = Uri\WhatWg\Url::parse("file:///foo/bar/"); +$url6 = $url6->withUsername("pass"); + +var_dump($url2->getPassword()); +var_dump($url3->getPassword()); +var_dump($url4->getPassword()); +var_dump($url5->getPassword()); +var_dump($url6->getPassword()); + +?> +--EXPECT-- +string(4) "pass" +NULL +string(6) "p%61ss" +string(8) "p%3As%2F" +NULL diff --git a/ext/uri/tests/026.phpt b/ext/uri/tests/026.phpt new file mode 100644 index 0000000000000..4640ebebae52d --- /dev/null +++ b/ext/uri/tests/026.phpt @@ -0,0 +1,67 @@ +--TEST-- +Test property mutation - host +--EXTENSIONS-- +uri +--FILE-- +withHost("test.com"); +$url3 = $url2->withHost("t%65st.com"); // test.com +$url4 = $url3->withHost("test.com:8080"); + +var_dump($url1->getAsciiHost()); +var_dump($url2->getAsciiHost()); +var_dump($url3->getAsciiHost()); +var_dump($url4->getAsciiHost()); +var_dump($url4->getPort()); + +try { + $url4->withHost("t%3As%2Ft.com"); // t:s/t.com +} catch (Uri\WhatWg\InvalidUrlException $e) { + echo $e->getMessage() . "\n"; +} + +var_dump($url4->withHost("t:s/t.com")); + +try { + $url2->withHost(null); +} catch (Uri\WhatWg\InvalidUrlException $e) { + echo $e->getMessage() . "\n"; +} + +$url1 = Uri\WhatWg\Url::parse("ftp://foo.com?query=abc#foo"); +$url2 = $url1->withHost("test.com"); + +var_dump($url1->getAsciiHost()); +var_dump($url2->getAsciiHost()); + +?> +--EXPECTF-- +string(11) "example.com" +string(8) "test.com" +string(8) "test.com" +string(8) "test.com" +NULL +URL parsing failed +object(Uri\WhatWg\Url)#%d (%d) { + ["scheme"]=> + string(5) "https" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(8) "test.com" + ["port"]=> + NULL + ["path"]=> + string(1) "/" + ["query"]=> + NULL + ["fragment"]=> + NULL +} +URL parsing failed +string(7) "foo.com" +string(8) "test.com" diff --git a/ext/uri/tests/027.phpt b/ext/uri/tests/027.phpt new file mode 100644 index 0000000000000..79c121dd7f383 --- /dev/null +++ b/ext/uri/tests/027.phpt @@ -0,0 +1,36 @@ +--TEST-- +Test property mutation - port +--EXTENSIONS-- +uri +--FILE-- +withPort(22); +$url3 = $url2->withPort(null); + +var_dump($url1->getPort()); +var_dump($url2->getPort()); +var_dump($url3->getPort()); + +$url1 = Uri\WhatWg\Url::parse("ftp://foo.com:443?query=abc#foo"); +$url2 = $url1->withPort(8080); + +var_dump($url1->getPort()); +var_dump($url2->getPort()); + +$url1 = Uri\WhatWg\Url::parse("file:///foo/bar"); +$url2 = $url1->withPort(80); + +var_dump($url1->getPort()); +var_dump($url2->getPort()); + +?> +--EXPECT-- +int(8080) +int(22) +NULL +int(443) +int(8080) +NULL +NULL diff --git a/ext/uri/tests/028.phpt b/ext/uri/tests/028.phpt new file mode 100644 index 0000000000000..fd565c900e02f --- /dev/null +++ b/ext/uri/tests/028.phpt @@ -0,0 +1,37 @@ +--TEST-- +Test property mutation - path +--EXTENSIONS-- +uri +--FILE-- +withPath("/foo"); +$url3 = $url2->withPath(""); +$url4 = $url3->withPath("t%65st"); +$url5 = $url4->withPath("/foo%2Fbar"); +$url6 = $url5->withPath("/#"); + +var_dump($url1->getPath()); +var_dump($url2->getPath()); +var_dump($url3->getPath()); +var_dump($url4->getPath()); +var_dump($url5->getPath()); +var_dump($url6->getPath()); + +$url1 = Uri\WhatWg\Url::parse("https://example.com/"); +$uri2 = $url1->withPath("/foo"); + +var_dump($url1->getPath()); +var_dump($url2->getPath()); + +?> +--EXPECT-- +string(9) "/foo/bar/" +string(4) "/foo" +string(1) "/" +string(7) "/t%65st" +string(10) "/foo%2Fbar" +string(4) "/%23" +string(1) "/" +string(4) "/foo" diff --git a/ext/uri/tests/029.phpt b/ext/uri/tests/029.phpt new file mode 100644 index 0000000000000..e23008a65ad6a --- /dev/null +++ b/ext/uri/tests/029.phpt @@ -0,0 +1,40 @@ +--TEST-- +Test property mutation - query +--EXTENSIONS-- +uri +--FILE-- +withQuery("?foo=baz"); +$url3 = $url2->withQuery(null); + +var_dump($url1->getQuery()); +var_dump($url2->getQuery()); +var_dump($url3->getQuery()); + +$url1 = Uri\WhatWg\Url::parse("https://example.com"); +$url2 = $url1->withQuery("?foo=bar&foo=baz"); +$url3 = $url1->withQuery("foo=bar&foo=baz"); +$url4 = $url3->withQuery("t%65st"); +$url5 = $url4->withQuery("foo=foo%26bar&baz=/qux%3D"); +$url6 = $url5->withQuery("#"); + +var_dump($url1->getQuery()); +var_dump($url2->getQuery()); +var_dump($url3->getQuery()); +var_dump($url4->getQuery()); +var_dump($url5->getQuery()); +var_dump($url6->getQuery()); + +?> +--EXPECT-- +string(7) "foo=bar" +string(7) "foo=baz" +NULL +NULL +string(15) "foo=bar&foo=baz" +string(15) "foo=bar&foo=baz" +string(6) "t%65st" +string(25) "foo=foo%26bar&baz=/qux%3D" +string(3) "%23" diff --git a/ext/uri/tests/030.phpt b/ext/uri/tests/030.phpt new file mode 100644 index 0000000000000..6bb85e6720c95 --- /dev/null +++ b/ext/uri/tests/030.phpt @@ -0,0 +1,31 @@ +--TEST-- +Test property mutation - fragment +--EXTENSIONS-- +uri +--FILE-- +withFragment("#fragment2"); +$url3 = $url2->withFragment(null); +$url4 = $url3->withFragment(" "); + +var_dump($url1->getFragment()); +var_dump($url2->getFragment()); +var_dump($url3->getFragment()); +var_dump($url4->getFragment()); + +$url1 = Uri\WhatWg\Url::parse("https://example.com?abc=def"); +$url2 = $url1->withFragment("#fragment"); + +var_dump($url1->getFragment()); +var_dump($url2->getFragment()); + +?> +--EXPECT-- +string(9) "fragment1" +string(9) "fragment2" +NULL +string(3) "%20" +NULL +string(8) "fragment" diff --git a/ext/uri/tests/031.phpt b/ext/uri/tests/031.phpt new file mode 100644 index 0000000000000..0572a4ec11fe6 --- /dev/null +++ b/ext/uri/tests/031.phpt @@ -0,0 +1,98 @@ +--TEST-- +Test serialization and unserialization +--EXTENSIONS-- +uri +--FILE-- +getMessage() . "\n"; +} + +try { + unserialize('O:14:"Uri\WhatWg\Url":3:{i:0;a:0:{}i:1;a:0:{}i:2;a:0:{}}'); // more than 2 items +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} + +try { + unserialize('O:14:"Uri\WhatWg\Url":2:{i:0;N;i:1;a:0:{}}'); // first item is not an array +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} + +try { + unserialize('O:14:"Uri\WhatWg\Url":2:{i:0;a:0:{}i:1;a:0:{}}'); // first array is empty +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} + +try { + unserialize('O:14:"Uri\WhatWg\Url":2:{i:0;a:2:{s:3:"uri";s:19:"https://example.com";s:1:"a";i:1;}i:1;a:0:{}}'); // "uri" key in first array contains more than 1 item +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} + +try { + unserialize('O:14:"Uri\WhatWg\Url":2:{i:0;a:1:{s:3:"uri";i:1;}i:1;a:0:{}}'); // "uri" key in first array is not a string +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} + +try { + unserialize('O:14:"Uri\WhatWg\Url":2:{i:0;a:1:{s:3:"uri";s:11:"invalid-url";}i:1;a:0:{}}'); // "uri" key in first array contains invalid URL +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} + +try { + unserialize('O:14:"Uri\WhatWg\Url":2:{i:0;a:1:{s:3:"uri";s:19:"https://example.com";}i:1;s:0:"";}'); // second item in not an array +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} + +try { + unserialize('O:14:"Uri\WhatWg\Url":2:{i:0;a:1:{s:3:"uri";s:19:"https://example.com";}i:1;a:1:{s:5:"prop1";i:123;}}'); // second array contains property +} catch (Exception $e) { + echo $e->getMessage() . "\n"; +} + +?> +--EXPECTF-- +string(162) "O:14:"Uri\WhatWg\Url":2:{i:0;a:1:{s:3:"uri";s:98:"https://username:password@www.google.com:8080/pathname1/pathname2/pathname3?query=true#hash-exists";}i:1;a:0:{}}" +object(Uri\WhatWg\Url)#%d (%d) { + ["scheme"]=> + string(5) "https" + ["username"]=> + string(8) "username" + ["password"]=> + string(8) "password" + ["host"]=> + string(14) "www.google.com" + ["port"]=> + int(8080) + ["path"]=> + string(30) "/pathname1/pathname2/pathname3" + ["query"]=> + string(10) "query=true" + ["fragment"]=> + string(11) "hash-exists" +} +Invalid serialization data for Uri\WhatWg\Url object +Invalid serialization data for Uri\WhatWg\Url object +Invalid serialization data for Uri\WhatWg\Url object +Invalid serialization data for Uri\WhatWg\Url object +Invalid serialization data for Uri\WhatWg\Url object +Invalid serialization data for Uri\WhatWg\Url object +Invalid serialization data for Uri\WhatWg\Url object +Invalid serialization data for Uri\WhatWg\Url object +Invalid serialization data for Uri\WhatWg\Url object diff --git a/ext/uri/tests/032.phpt b/ext/uri/tests/032.phpt new file mode 100644 index 0000000000000..93bb80bcdb72a --- /dev/null +++ b/ext/uri/tests/032.phpt @@ -0,0 +1,13 @@ +--TEST-- +Test JSON encoding +--EXTENSIONS-- +uri +--FILE-- + +--EXPECT-- +string(2) "{}" diff --git a/ext/uri/tests/033.phpt b/ext/uri/tests/033.phpt new file mode 100644 index 0000000000000..5b74af9b74f74 --- /dev/null +++ b/ext/uri/tests/033.phpt @@ -0,0 +1,15 @@ +--TEST-- +Test var_export +--EXTENSIONS-- +uri +--FILE-- + +--EXPECT-- +\Uri\WhatWg\Url::__set_state(array( +)) diff --git a/ext/uri/tests/034.phpt b/ext/uri/tests/034.phpt new file mode 100644 index 0000000000000..ccb0d9f6e5347 --- /dev/null +++ b/ext/uri/tests/034.phpt @@ -0,0 +1,14 @@ +--TEST-- +Test array cast +--EXTENSIONS-- +uri +--FILE-- + +--EXPECTF-- +array(%d) { +} diff --git a/ext/uri/tests/035.phpt b/ext/uri/tests/035.phpt new file mode 100644 index 0000000000000..6760e5dc0fb7a --- /dev/null +++ b/ext/uri/tests/035.phpt @@ -0,0 +1,24 @@ +--TEST-- +Test URI parsing containing null bytes +--EXTENSIONS-- +uri +--FILE-- +getMessage() . "\n"; +} + +$url = new Uri\WhatWg\Url("https://example.com"); +try { + $url->withHost("exam\0ple.com"); +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +?> +--EXPECT-- +Uri\WhatWg\Url::__construct(): Argument #1 ($uri) must not contain any null bytes +Uri\WhatWg\Url::withHost(): Argument #1 ($host) must not contain any null bytes diff --git a/ext/uri/tests/036.phpt b/ext/uri/tests/036.phpt new file mode 100644 index 0000000000000..adc4041db5506 --- /dev/null +++ b/ext/uri/tests/036.phpt @@ -0,0 +1,24 @@ +--TEST-- +Test URI equality checks +--EXTENSIONS-- +uri +--FILE-- +equals(new Uri\WhatWg\Url("https://example.com"))); // true: identical URIs +var_dump(new Uri\WhatWg\Url("https://example.com#foo")->equals(new Uri\WhatWg\Url("https://example.com#bar"), Uri\UriComparisonMode::ExcludeFragment)); // true: fragment differs, but fragment is excluded +var_dump(new Uri\WhatWg\Url("https://example.com#foo")->equals(new Uri\WhatWg\Url("https://example.com#bar"), Uri\UriComparisonMode::IncludeFragment)); // false: fragment differs and fragment is included +var_dump(new Uri\WhatWg\Url("https://example.com/foo/..")->equals(new Uri\WhatWg\Url("https://example.com"))); // true: both URIs are https://example.com/ after normalization +var_dump(new Uri\WhatWg\Url("https://example.com/foo/..")->equals(new Uri\WhatWg\Url("https://example.com/"))); // true: both URIs are https://example.com/ after normalization +var_dump(new Uri\WhatWg\Url("http://example%2ecom/foo%2fb%61r")->equals(new Uri\WhatWg\Url("http://example%2ecom/foo/bar"))); // false: WHATWG doesn't percent-decode the path during normalization +var_dump(new Uri\WhatWg\Url("http://example%2ecom/foo/b%61r")->equals(new Uri\WhatWg\Url("http://example.com/foo/b%61r"))); // true: WHATWG percent-decodes the host during normalization + +?> +--EXPECT-- +bool(true) +bool(true) +bool(false) +bool(true) +bool(true) +bool(false) +bool(true) diff --git a/ext/uri/tests/038.phpt b/ext/uri/tests/038.phpt new file mode 100644 index 0000000000000..06171b258d6f8 --- /dev/null +++ b/ext/uri/tests/038.phpt @@ -0,0 +1,26 @@ +--TEST-- +Test toString() +--EXTENSIONS-- +uri +--FILE-- +toUnicodeString()); +var_dump($url1->toAsciiString()); +var_dump($url2->toUnicodeString()); +var_dump($url2->toAsciiString()); +var_dump($url3->toUnicodeString()); +var_dump($url3->toAsciiString()); + +?> +--EXPECT-- +string(20) "https://example.com/" +string(20) "https://example.com/" +string(20) "https://example.com/" +string(20) "https://example.com/" +string(20) "https://example.com/" +string(20) "https://example.com/" diff --git a/ext/uri/tests/039.phpt b/ext/uri/tests/039.phpt new file mode 100644 index 0000000000000..6bf57cde97d95 --- /dev/null +++ b/ext/uri/tests/039.phpt @@ -0,0 +1,34 @@ +--TEST-- +Test percent-encoding of different URI components +--EXTENSIONS-- +uri +--FILE-- +getScheme()); + var_dump($url->getUsername()); + var_dump($url->getPassword()); + var_dump($url->getAsciiHost()); + var_dump($url->getUnicodeHost()); + var_dump($url->getPort()); + var_dump($url->getPath()); + var_dump($url->getQuery()); + var_dump($url->getFragment()); +} + +$url = Uri\WhatWg\Url::parse("http://%61pple:p%61ss@ex%61mple.com/foob%61r?%61bc=%61bc#%61bc"); +callWhatWgGetters($url); + +?> +--EXPECT-- +string(4) "http" +string(7) "%61pple" +string(6) "p%61ss" +string(11) "example.com" +string(11) "example.com" +NULL +string(9) "/foob%61r" +string(11) "%61bc=%61bc" +string(5) "%61bc" diff --git a/ext/uri/tests/040.phpt b/ext/uri/tests/040.phpt new file mode 100644 index 0000000000000..6bd66fd396f21 --- /dev/null +++ b/ext/uri/tests/040.phpt @@ -0,0 +1,32 @@ +--TEST-- +Test HTTP URL validation +--EXTENSIONS-- +uri +--FILE-- +toAsciiString()); + +?> +--EXPECTF-- +object(Uri\WhatWg\Url)#%d (%d) { + ["scheme"]=> + string(5) "https" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(1) "/" + ["query"]=> + NULL + ["fragment"]=> + NULL +} +string(20) "https://example.com/" diff --git a/ext/uri/tests/041.phpt b/ext/uri/tests/041.phpt new file mode 100644 index 0000000000000..5cfcec2628dab --- /dev/null +++ b/ext/uri/tests/041.phpt @@ -0,0 +1,26 @@ +--TEST-- +Test relative URI parsing +--EXTENSIONS-- +uri +--FILE-- + +--EXPECTF-- +NULL +array(%d) { + [0]=> + object(Uri\WhatWg\UrlValidationError)#%d (%d) { + ["context"]=> + string(15) "?query#fragment" + ["type"]=> + enum(Uri\WhatWg\UrlValidationErrorType::MissingSchemeNonRelativeUrl) + ["failure"]=> + bool(true) + } +} diff --git a/ext/uri/tests/042.phpt b/ext/uri/tests/042.phpt new file mode 100644 index 0000000000000..caf63366e2b19 --- /dev/null +++ b/ext/uri/tests/042.phpt @@ -0,0 +1,29 @@ +--TEST-- +Test URN parsing +--EXTENSIONS-- +uri +--FILE-- + +--EXPECTF-- +object(Uri\WhatWg\Url)#%d (%d) { + ["scheme"]=> + string(3) "urn" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + NULL + ["port"]=> + NULL + ["path"]=> + string(41) "uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66" + ["query"]=> + NULL + ["fragment"]=> + NULL +} diff --git a/ext/uri/tests/043.phpt b/ext/uri/tests/043.phpt new file mode 100644 index 0000000000000..d9f17d45024c9 --- /dev/null +++ b/ext/uri/tests/043.phpt @@ -0,0 +1,71 @@ +--TEST-- +Test reference resolution +--EXTENSIONS-- +uri +--FILE-- + +--EXPECTF-- +object(Uri\WhatWg\Url)#%d (%d) { + ["scheme"]=> + string(5) "https" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(14) "/without-base/" + ["query"]=> + NULL + ["fragment"]=> + NULL +} +object(Uri\WhatWg\Url)#%d (%d) { + ["scheme"]=> + string(5) "https" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(10) "/with-base" + ["query"]=> + NULL + ["fragment"]=> + NULL +} +object(Uri\WhatWg\Url)#%d (%d) { + ["scheme"]=> + string(5) "https" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(8) "test.com" + ["port"]=> + NULL + ["path"]=> + string(18) "/with-base-in-vain" + ["query"]=> + NULL + ["fragment"]=> + NULL +} diff --git a/ext/uri/tests/045.phpt b/ext/uri/tests/045.phpt new file mode 100644 index 0000000000000..13137d6a42b69 --- /dev/null +++ b/ext/uri/tests/045.phpt @@ -0,0 +1,16 @@ +--TEST-- +Test percent-decoding of reserved characters in the path +--EXTENSIONS-- +uri +--FILE-- +toAsciiString()); +var_dump($url->getPath()); + +?> +--EXPECT-- +string(33) "https://example.com/foo/bar%2Fbaz" +string(14) "/foo/bar%2Fbaz" diff --git a/ext/uri/tests/046.phpt b/ext/uri/tests/046.phpt new file mode 100644 index 0000000000000..cf283ad5297e5 --- /dev/null +++ b/ext/uri/tests/046.phpt @@ -0,0 +1,30 @@ +--TEST-- +Test special path variants +--EXTENSIONS-- +uri +--FILE-- +toAsciiString()); +var_dump($url->getPath()); + +$url = new Uri\Whatwg\Url("https://example.com"); + +var_dump($url->toAsciiString()); +var_dump($url->getPath()); + +$url = new Uri\Whatwg\Url("https://example.com/"); + +var_dump($url->toAsciiString()); +var_dump($url->getPath()); + +?> +--EXPECT-- +string(26) "mailto:johndoe@example.com" +string(19) "johndoe@example.com" +string(20) "https://example.com/" +string(1) "/" +string(20) "https://example.com/" +string(1) "/" diff --git a/ext/uri/tests/047.phpt b/ext/uri/tests/047.phpt new file mode 100644 index 0000000000000..4ab3a0584de79 --- /dev/null +++ b/ext/uri/tests/047.phpt @@ -0,0 +1,27 @@ +--TEST-- +Test IP addresses +--EXTENSIONS-- +uri +--FILE-- +getAsciiHost()); +var_dump($url->toAsciiString()); + +$url = new Uri\WhatWg\Url("https://[2001:0db8:0001:0000:0000:0ab9:C0A8:0102]"); +var_dump($url->getAsciiHost()); +var_dump($url->toAsciiString()); + +$url = new Uri\WhatWg\Url("https://[0:0::1]"); +var_dump($url->getAsciiHost()); +var_dump($url->toAsciiString()); + +?> +--EXPECT-- +string(11) "192.168.0.1" +string(20) "https://192.168.0.1/" +string(26) "[2001:db8:1::ab9:c0a8:102]" +string(35) "https://[2001:db8:1::ab9:c0a8:102]/" +string(5) "[::1]" +string(14) "https://[::1]/" diff --git a/ext/uri/tests/049.phpt b/ext/uri/tests/049.phpt new file mode 100644 index 0000000000000..41e6eaeea3cf9 --- /dev/null +++ b/ext/uri/tests/049.phpt @@ -0,0 +1,13 @@ +--TEST-- +Test percent-encoding normalization - special case +--EXTENSIONS-- +uri +--FILE-- +getPath()); + +?> +--EXPECT-- +string(14) "/foo/bar%2Fbaz" diff --git a/ext/uri/tests/050.phpt b/ext/uri/tests/050.phpt new file mode 100644 index 0000000000000..12af66721cf65 --- /dev/null +++ b/ext/uri/tests/050.phpt @@ -0,0 +1,16 @@ +--TEST-- +Test resolve() method - success cases +--EXTENSIONS-- +uri +--FILE-- +resolve("/foo/")->toAsciiString()); +var_dump($url->resolve("https://test.com/foo")->toAsciiString()); + +?> +--EXPECTF-- +string(24) "https://example.com/foo/" +string(20) "https://test.com/foo" diff --git a/ext/uri/tests/051.phpt b/ext/uri/tests/051.phpt new file mode 100644 index 0000000000000..5911f8767567c --- /dev/null +++ b/ext/uri/tests/051.phpt @@ -0,0 +1,35 @@ +--TEST-- +Test resolve() method - error cases +--EXTENSIONS-- +uri +--FILE-- +resolve("https://1.2.3.4.5"); +} catch (Uri\WhatWg\InvalidUrlException $e) { + echo $e->getMessage() . "\n"; +} + +$softErrors = []; + +var_dump($url->resolve(" /foo", $softErrors)->toAsciiString()); +var_dump($softErrors); + +?> +--EXPECTF-- +URL parsing failed +string(23) "https://example.com/foo" +array(%d) { + [0]=> + object(Uri\WhatWg\UrlValidationError)#%d (%d) { + ["context"]=> + string(5) " /foo" + ["type"]=> + enum(Uri\WhatWg\UrlValidationErrorType::InvalidUrlUnit) + ["failure"]=> + bool(false) + } +} diff --git a/ext/uri/tests/052.phpt b/ext/uri/tests/052.phpt new file mode 100644 index 0000000000000..af7d05b893ea5 --- /dev/null +++ b/ext/uri/tests/052.phpt @@ -0,0 +1,28 @@ +--TEST-- +Test UrlValidationError constructor error handling +--EXTENSIONS-- +uri +--FILE-- +__construct('bar', Uri\WhatWg\UrlValidationErrorType::HostMissing, false); +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +var_dump($r); + +?> +--EXPECTF-- +Cannot modify readonly property Uri\WhatWg\UrlValidationError::$context +object(Uri\WhatWg\UrlValidationError)#%d (%d) { + ["context"]=> + string(3) "foo" + ["type"]=> + enum(Uri\WhatWg\UrlValidationErrorType::DomainInvalidCodePoint) + ["failure"]=> + bool(true) +} diff --git a/ext/uri/tests/053.phpt b/ext/uri/tests/053.phpt new file mode 100644 index 0000000000000..93ff77b15c0a5 --- /dev/null +++ b/ext/uri/tests/053.phpt @@ -0,0 +1,63 @@ +--TEST-- +Test InvalidUrlException constructor error handling +--EXTENSIONS-- +uri +--FILE-- +__construct("foo"); +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + $r->__construct("bar", []); +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + $r->__construct("baz", [], false); +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + $r->__construct("qax", [], false, null); +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +var_dump($r->getMessage()); +var_dump($r->errors); +var_dump($r->getCode()); +var_dump($r->getPrevious()::class); + +?> +--EXPECTF-- +Cannot modify readonly property Uri\WhatWg\InvalidUrlException::$errors +Cannot modify readonly property Uri\WhatWg\InvalidUrlException::$errors +Cannot modify readonly property Uri\WhatWg\InvalidUrlException::$errors +Cannot modify readonly property Uri\WhatWg\InvalidUrlException::$errors +string(3) "qax" +array(%d) { + [%d]=> + object(Uri\WhatWg\UrlValidationError)#%d (%d) { + ["context"]=> + string(3) "abc" + ["type"]=> + enum(Uri\WhatWg\UrlValidationErrorType::DomainInvalidCodePoint) + ["failure"]=> + bool(true) + } +} +int(1) +string(9) "Exception" From 5f9a0b568b18d74391807d56afaee69e9e4f8aea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Tue, 10 Jun 2025 15:28:34 +0200 Subject: [PATCH 002/120] gen_stub: Fix undefined variable warning (#18821) > PHP Warning: Undefined variable $code in build/gen_stub.php on line 5322 Introduced in php/php-src#18735. --- build/gen_stub.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/gen_stub.php b/build/gen_stub.php index 0e87cdd9a0b40..ff86106e8a2a4 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -5313,6 +5313,8 @@ function generateGlobalConstantAttributeInitialization( $constInfos, "", static function (ConstInfo $constInfo) use ($allConstInfos, $phpVersionIdMinimumCompatibility) { + $code = ""; + if ($constInfo->attributes === []) { return null; } From 8f3e5553f386b66ad77fb562d641a8fd8c2fcefb Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Tue, 10 Jun 2025 17:33:42 +0200 Subject: [PATCH 003/120] Use zval_try_get_string_func() in concat_function() (#18815) This allows a cheaper exception check and also does not need a release call. This shrinks concat_function() on x86-64 with GCC 15.1.1 from 3443 bytes to 3332 bytes. --- Zend/zend_operators.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index 140734d1b9602..7e456ff68246a 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -1989,9 +1989,8 @@ ZEND_API zend_result ZEND_FASTCALL concat_function(zval *result, zval *op1, zval } } ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_CONCAT); - op1_string = zval_get_string_func(op1); - if (UNEXPECTED(EG(exception))) { - zend_string_release(op1_string); + op1_string = zval_try_get_string_func(op1); + if (UNEXPECTED(!op1_string)) { if (orig_op1 != result) { ZVAL_UNDEF(result); } @@ -2023,10 +2022,9 @@ ZEND_API zend_result ZEND_FASTCALL concat_function(zval *result, zval *op1, zval free_op1_string = true; } ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_CONCAT); - op2_string = zval_get_string_func(op2); - if (UNEXPECTED(EG(exception))) { + op2_string = zval_try_get_string_func(op2); + if (UNEXPECTED(!op2_string)) { zend_string_release(op1_string); - zend_string_release(op2_string); if (orig_op1 != result) { ZVAL_UNDEF(result); } From 594221fff2d635528c58bd6273e923e56ff53c14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Tue, 10 Jun 2025 19:15:35 +0200 Subject: [PATCH 004/120] cli: Fix tests/bug80092.phpt expectation for `PHP_BUILD_PROVIDER` (#18824) see afc5738154b8e0e7f8bcb5d6a521514bb495a0c0 see 40d88cacc1db11787aa2fde6d0ee4b6064746d94 --- sapi/cli/tests/bug80092.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapi/cli/tests/bug80092.phpt b/sapi/cli/tests/bug80092.phpt index 350b46b3f57a6..1fb2e8664cc1e 100644 --- a/sapi/cli/tests/bug80092.phpt +++ b/sapi/cli/tests/bug80092.phpt @@ -43,5 +43,5 @@ foreach (explode("\n", $output) as $line) { preloaded PHP %s Copyright (c) The PHP Group -Zend Engine %s +%AZend Engine %s %A with Zend OPcache %a From eb151e39b029ced2e40e013718d305a67b81d205 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Mon, 9 Jun 2025 14:47:02 +0200 Subject: [PATCH 005/120] Properly handle reference return value from __toString() It's possible to return a reference from __toString(), but this is not handled and results in a (confusing) error telling that the return value must be a string. Properly handle this by unwrapping the reference. Closes GH-18810. --- NEWS | 1 + ...tal_uncaught_error_reference_tostring.phpt | 19 +++++++++++++++++++ .../string_cast_reference_tostring.phpt | 17 +++++++++++++++++ Zend/zend_exceptions.c | 3 +++ Zend/zend_object_handlers.c | 4 ++++ sapi/phpdbg/phpdbg_prompt.c | 4 ++++ 6 files changed, 48 insertions(+) create mode 100644 Zend/tests/exceptions/exception_fatal_uncaught_error_reference_tostring.phpt create mode 100644 Zend/tests/type_casts/string_cast_reference_tostring.phpt diff --git a/NEWS b/NEWS index b1100f7672226..bf2b1937d7945 100644 --- a/NEWS +++ b/NEWS @@ -54,6 +54,7 @@ PHP NEWS released on bailout). (DanielEScherzer and ilutov) . Fixed AST printing for immediately invoked Closure. (Dmitrii Derepko) . Properly handle __debugInfo() returning an array reference. (nielsdos) + . Properly handle reference return value from __toString(). (nielsdos) . Added the pipe (|>) operator. (crell) - Curl: diff --git a/Zend/tests/exceptions/exception_fatal_uncaught_error_reference_tostring.phpt b/Zend/tests/exceptions/exception_fatal_uncaught_error_reference_tostring.phpt new file mode 100644 index 0000000000000..6222a0895baf2 --- /dev/null +++ b/Zend/tests/exceptions/exception_fatal_uncaught_error_reference_tostring.phpt @@ -0,0 +1,19 @@ +--TEST-- +Exception fatal uncaught error with reference __toString +--FILE-- +field; + } +} + +// Must not be caught to trigger the issue! +throw new MyException; + +?> +--EXPECTF-- +Fatal error: Uncaught my string + thrown in %s on line %d diff --git a/Zend/tests/type_casts/string_cast_reference_tostring.phpt b/Zend/tests/type_casts/string_cast_reference_tostring.phpt new file mode 100644 index 0000000000000..96b47a4fba9bc --- /dev/null +++ b/Zend/tests/type_casts/string_cast_reference_tostring.phpt @@ -0,0 +1,17 @@ +--TEST-- +String cast with reference __toString +--FILE-- +field; + } +} + +echo new MyClass; + +?> +--EXPECT-- +my string diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index ab9c815718a0d..212fe3cb7ab66 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -969,6 +969,9 @@ ZEND_API ZEND_COLD zend_result zend_exception_error(zend_object *ex, int severit zend_call_known_instance_method_with_0_params(ex->ce->__tostring, ex, &tmp); if (!EG(exception)) { + if (UNEXPECTED(Z_ISREF(tmp))) { + zend_unwrap_reference(&tmp); + } if (Z_TYPE(tmp) != IS_STRING) { zend_error(E_WARNING, "%s::__toString() must return a string", ZSTR_VAL(ce_exception->name)); } else { diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index f79023ade1c25..7b804e7afe95a 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -2440,8 +2440,12 @@ ZEND_API zend_result zend_std_cast_object_tostring(zend_object *readobj, zval *w zend_call_known_instance_method_with_0_params(ce->__tostring, readobj, &retval); zend_object_release(readobj); if (EXPECTED(Z_TYPE(retval) == IS_STRING)) { +is_string: ZVAL_COPY_VALUE(writeobj, &retval); return SUCCESS; + } else if (Z_ISREF(retval)) { + zend_unwrap_reference(&retval); + goto is_string; } zval_ptr_dtor(&retval); if (!EG(exception)) { diff --git a/sapi/phpdbg/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c index 92c139fa52abe..84bd7a076acec 100644 --- a/sapi/phpdbg/phpdbg_prompt.c +++ b/sapi/phpdbg/phpdbg_prompt.c @@ -702,6 +702,10 @@ static inline void phpdbg_handle_exception(void) /* {{{ */ EG(exception) = NULL; msg = ZSTR_EMPTY_ALLOC(); } else { + if (UNEXPECTED(Z_ISREF(tmp))) { + zend_unwrap_reference(&tmp); + } + ZEND_ASSERT(Z_TYPE(tmp) == IS_STRING); zend_update_property_string(zend_get_exception_base(ex), ex, ZEND_STRL("string"), Z_STRVAL(tmp)); zval_ptr_dtor(&tmp); msg = zval_get_string(zend_read_property_ex(zend_get_exception_base(ex), ex, ZSTR_KNOWN(ZEND_STR_STRING), /* silent */ true, &rv)); From 0cd3ebfc40c6f4aa90fad8bab05b09f274465385 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Mon, 9 Jun 2025 17:49:27 +0200 Subject: [PATCH 006/120] Fix 'phpdbg --help' segfault on shutdown with USE_ZEND_ALLOC=0 This hack not only breaks the handling of custom allocators, but also breaks if zend_alloc is compiled with USE_CUSTOM_MM. This hack is just no good, if you want leak information then use ASAN. Closes GH-18813. --- NEWS | 3 +++ sapi/phpdbg/phpdbg.c | 6 ------ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index 11fb787662c4a..a665633283d0c 100644 --- a/NEWS +++ b/NEWS @@ -39,6 +39,9 @@ PHP NEWS . Add missing filter cleanups on phar failure. (nielsdos) . Fixed bug GH-18642 (Signed integer overflow in ext/phar fseek). (nielsdos) +- PHPDBG: + . Fix 'phpdbg --help' segfault on shutdown with USE_ZEND_ALLOC=0. (nielsdos) + - PDO ODBC: . Fix memory leak if WideCharToMultiByte() fails. (nielsdos) diff --git a/sapi/phpdbg/phpdbg.c b/sapi/phpdbg/phpdbg.c index 5a4dd6acdbe2f..f27d87de84187 100644 --- a/sapi/phpdbg/phpdbg.c +++ b/sapi/phpdbg/phpdbg.c @@ -179,12 +179,6 @@ static PHP_MSHUTDOWN_FUNCTION(phpdbg) /* {{{ */ phpdbg_notice("Script ended normally"); } - /* hack to restore mm_heap->use_custom_heap in order to receive memory leak info */ - if (use_mm_wrappers) { - /* ASSUMING that mm_heap->use_custom_heap is the first element of the struct ... */ - *(int *) zend_mm_get_heap() = 0; - } - if (PHPDBG_G(buffer)) { free(PHPDBG_G(buffer)); PHPDBG_G(buffer) = NULL; From 0a95b2f30caa26cf540d48b47c623995acd1183c Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Tue, 10 Jun 2025 21:54:29 +0200 Subject: [PATCH 007/120] Fix GH-18820: Windows compilation issue: php-src\Zend\zend_exceptions.h(75): error C2122: 'message': prototype parameter in name list illegal INTERNAL_FUNCTION_PARAMETERS is defined in zend.h, but not included in zend_exceptions.h (and it shouldn't). Expand the macro to fix the compile issue. --- Zend/zend_exceptions.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/zend_exceptions.h b/Zend/zend_exceptions.h index 86dc379cce871..35f6699559421 100644 --- a/Zend/zend_exceptions.h +++ b/Zend/zend_exceptions.h @@ -69,7 +69,7 @@ ZEND_API zend_object *zend_throw_error_exception(zend_class_entry *exception_ce, extern ZEND_API void (*zend_throw_exception_hook)(zend_object *ex); -ZEND_API zend_result zend_update_exception_properties(INTERNAL_FUNCTION_PARAMETERS, zend_string *message, zend_long code, zval *previous); +ZEND_API zend_result zend_update_exception_properties(zend_execute_data *execute_data, zval *return_value, zend_string *message, zend_long code, zval *previous); /* show an exception using zend_error(severity,...), severity should be E_ERROR */ ZEND_API ZEND_COLD zend_result zend_exception_error(zend_object *exception, int severity); From 559858c82249155db5c362cf6a7efcc2665414a8 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Tue, 10 Jun 2025 22:33:33 +0200 Subject: [PATCH 008/120] Improve performance of unpack() with nameless repetitions (#18803) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can avoid creating temporary strings, and then reparsing them into numbers with zend_symtable_update() by using zend_hash_index_update() directly. For the following benchmark on an i7-4790: ```php $file = str_repeat('A', 100000); for ($i=0;$i<100;$i++) unpack('C*',$file); ``` I get: ``` Benchmark 1: ./sapi/cli/php y.php Time (mean ± σ): 85.8 ms ± 1.8 ms [User: 74.5 ms, System: 10.4 ms] Range (min … max): 83.8 ms … 92.4 ms 33 runs Benchmark 2: ./sapi/cli/php_old y.php Time (mean ± σ): 318.3 ms ± 2.7 ms [User: 306.7 ms, System: 9.9 ms] Range (min … max): 314.9 ms … 321.6 ms 10 runs Summary ./sapi/cli/php y.php ran 3.71 ± 0.08 times faster than ./sapi/cli/php_old y.php ``` On an i7-1185G7 I get: ``` Benchmark 1: ./sapi/cli/php test.php Time (mean ± σ): 60.1 ms ± 0.7 ms [User: 47.8 ms, System: 12.0 ms] Range (min … max): 59.2 ms … 63.8 ms 48 runs Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options. Benchmark 2: ./sapi/cli/php_old test.php Time (mean ± σ): 220.8 ms ± 2.2 ms [User: 209.6 ms, System: 10.7 ms] Range (min … max): 218.5 ms … 224.5 ms 13 runs Summary ./sapi/cli/php test.php ran 3.67 ± 0.06 times faster than ./sapi/cli/php_old test.php ``` --- UPGRADING | 2 ++ ext/standard/pack.c | 40 +++++++++++++++++++++------------------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/UPGRADING b/UPGRADING index 7025c9778e7ac..26c87d7aeb795 100644 --- a/UPGRADING +++ b/UPGRADING @@ -582,6 +582,8 @@ PHP 8.5 UPGRADE NOTES . Improved performance of array functions with callbacks (array_find, array_filter, array_map, usort, ...). . Improved performance of urlencode() and rawurlencode(). + . Improved unpack() performance with nameless repetitions by avoiding + creating temporary strings and reparsing them. - XMLReader: . Improved property access performance. diff --git a/ext/standard/pack.c b/ext/standard/pack.c index ec30be436741d..1dc04dab86c1a 100644 --- a/ext/standard/pack.c +++ b/ext/standard/pack.c @@ -885,12 +885,15 @@ PHP_FUNCTION(unpack) if ((inputpos + size) <= inputlen) { zend_string* real_name; + zend_long long_key = 0; zval val; - if (repetitions == 1 && namelen > 0) { + if (namelen == 0) { + real_name = NULL; + long_key = i + 1; + } else if (repetitions == 1) { /* Use a part of the formatarg argument directly as the name. */ real_name = zend_string_init_fast(name, namelen); - } else { /* Need to add the 1-based element number to the name */ char buf[MAX_LENGTH_OF_LONG + 1]; @@ -912,7 +915,6 @@ PHP_FUNCTION(unpack) size = len; ZVAL_STRINGL(&val, &input[inputpos], len); - zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); break; } case 'A': { @@ -939,7 +941,6 @@ PHP_FUNCTION(unpack) } ZVAL_STRINGL(&val, &input[inputpos], len + 1); - zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); break; } /* New option added for Z to remain in-line with the Perl implementation */ @@ -964,7 +965,6 @@ PHP_FUNCTION(unpack) len = s; ZVAL_STRINGL(&val, &input[inputpos], len); - zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); break; } @@ -979,7 +979,9 @@ PHP_FUNCTION(unpack) if (size > INT_MAX / 2) { - zend_string_release(real_name); + if (real_name) { + zend_string_release_ex(real_name, false); + } zend_argument_value_error(1, "repeater must be less than or equal to %d", INT_MAX / 2); RETURN_THROWS(); } @@ -1016,7 +1018,6 @@ PHP_FUNCTION(unpack) ZSTR_VAL(buf)[len] = '\0'; ZVAL_STR(&val, buf); - zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); break; } @@ -1026,7 +1027,6 @@ PHP_FUNCTION(unpack) zend_long v = (type == 'c') ? (int8_t) x : x; ZVAL_LONG(&val, v); - zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); break; } @@ -1046,7 +1046,6 @@ PHP_FUNCTION(unpack) } ZVAL_LONG(&val, v); - zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); break; } @@ -1062,7 +1061,6 @@ PHP_FUNCTION(unpack) } ZVAL_LONG(&val, v); - zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); break; } @@ -1082,8 +1080,6 @@ PHP_FUNCTION(unpack) } ZVAL_LONG(&val, v); - zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); - break; } @@ -1104,7 +1100,6 @@ PHP_FUNCTION(unpack) } ZVAL_LONG(&val, v); - zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); break; } #endif @@ -1124,7 +1119,6 @@ PHP_FUNCTION(unpack) } ZVAL_DOUBLE(&val, v); - zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); break; } @@ -1143,13 +1137,12 @@ PHP_FUNCTION(unpack) } ZVAL_DOUBLE(&val, v); - zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); break; } case 'x': /* Do nothing with input, just skip it */ - break; + goto no_output; case 'X': if (inputpos < size) { @@ -1160,7 +1153,7 @@ PHP_FUNCTION(unpack) php_error_docref(NULL, E_WARNING, "Type %c: outside of string", type); } } - break; + goto no_output; case '@': if (repetitions <= inputlen) { @@ -1170,10 +1163,19 @@ PHP_FUNCTION(unpack) } i = repetitions - 1; /* Done, break out of for loop */ - break; + goto no_output; } - zend_string_release(real_name); + if (real_name) { + zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); + } else { + zend_hash_index_update(Z_ARRVAL_P(return_value), long_key, &val); + } + +no_output: + if (real_name) { + zend_string_release_ex(real_name, false); + } inputpos += size; if (inputpos < 0) { From dbabbe180b157eeaac5002276667f1f56f0b4def Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Tue, 10 Jun 2025 22:35:56 +0200 Subject: [PATCH 009/120] Remove dead code from openssl_spki_new() implementation (#18752) If s is not NULL, the length can't be <= 0 because we at least append `spkac` in the string, which is non-empty. I noticed this condition because if it were actually possible to execute, then it would leak memory. --- ext/openssl/openssl.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index 6518a719314fd..4d1567f56d8c2 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -652,10 +652,6 @@ PHP_FUNCTION(openssl_spki_new) if (spki != NULL) { NETSCAPE_SPKI_free(spki); } - - if (s && ZSTR_LEN(s) <= 0) { - RETVAL_FALSE; - } } /* }}} */ From 2a77e282f86f3f2ecfcd68a83e7dcddf92165995 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Tue, 10 Jun 2025 13:09:49 +0100 Subject: [PATCH 010/120] ext/standard/pack: Inline constant single use variables They serve no purpose and are just confusing --- ext/standard/pack.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/ext/standard/pack.c b/ext/standard/pack.c index 1dc04dab86c1a..b0ed378b49ec0 100644 --- a/ext/standard/pack.c +++ b/ext/standard/pack.c @@ -919,7 +919,6 @@ PHP_FUNCTION(unpack) } case 'A': { /* A will strip any trailing whitespace */ - char padn = '\0'; char pads = ' '; char padt = '\t'; char padc = '\r'; char padl = '\n'; zend_long len = inputlen - inputpos; /* Remaining string */ /* If size was given take minimum of len and size */ @@ -931,11 +930,11 @@ PHP_FUNCTION(unpack) /* Remove trailing white space and nulls chars from unpacked data */ while (--len >= 0) { - if (input[inputpos + len] != padn - && input[inputpos + len] != pads - && input[inputpos + len] != padt - && input[inputpos + len] != padc - && input[inputpos + len] != padl + if (input[inputpos + len] != '\0' + && input[inputpos + len] != ' ' + && input[inputpos + len] != '\t' + && input[inputpos + len] != '\r' + && input[inputpos + len] != '\n' ) break; } @@ -946,7 +945,6 @@ PHP_FUNCTION(unpack) /* New option added for Z to remain in-line with the Perl implementation */ case 'Z': { /* Z will strip everything after the first null character */ - char pad = '\0'; zend_long s, len = inputlen - inputpos; /* Remaining string */ @@ -959,7 +957,7 @@ PHP_FUNCTION(unpack) /* Remove everything after the first null */ for (s=0 ; s < len ; s++) { - if (input[inputpos + s] == pad) + if (input[inputpos + s] == '\0') break; } len = s; From e96a7f0dfb50aaab94a04276d2bf06e37ecfc62d Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Tue, 10 Jun 2025 13:14:22 +0100 Subject: [PATCH 011/120] ext/standard/pack: Remove useless casts And use char instead of widening to int for no reason --- ext/standard/pack.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ext/standard/pack.c b/ext/standard/pack.c index b0ed378b49ec0..e6ca60d456d42 100644 --- a/ext/standard/pack.c +++ b/ext/standard/pack.c @@ -274,7 +274,7 @@ PHP_FUNCTION(pack) } /* Handle special arg '*' for all codes and check argv overflows */ - switch ((int) code) { + switch (code) { /* Never uses any args */ case 'x': case 'X': @@ -380,10 +380,10 @@ PHP_FUNCTION(pack) /* Calculate output length and upper bound while processing*/ for (i = 0; i < formatcount; i++) { - int code = (int) formatcodes[i]; + char code = formatcodes[i]; int arg = formatargs[i]; - switch ((int) code) { + switch (code) { case 'h': case 'H': INC_OUTPUTPOS((arg + (arg % 2)) / 2,1) /* 4 bit per arg */ @@ -463,10 +463,10 @@ PHP_FUNCTION(pack) /* Do actual packing */ for (i = 0; i < formatcount; i++) { - int code = (int) formatcodes[i]; + char code = formatcodes[i]; int arg = formatargs[i]; - switch ((int) code) { + switch (code) { case 'a': case 'A': case 'Z': { @@ -632,7 +632,7 @@ PHP_FUNCTION(pack) case 'd': { while (arg-- > 0) { - double v = (double) zval_get_double(&argv[currentarg++]); + double v = zval_get_double(&argv[currentarg++]); memcpy(&ZSTR_VAL(output)[outputpos], &v, sizeof(v)); outputpos += sizeof(v); } @@ -642,7 +642,7 @@ PHP_FUNCTION(pack) case 'e': { /* pack little endian double */ while (arg-- > 0) { - double v = (double) zval_get_double(&argv[currentarg++]); + double v = zval_get_double(&argv[currentarg++]); php_pack_copy_double(1, &ZSTR_VAL(output)[outputpos], v); outputpos += sizeof(v); } @@ -652,7 +652,7 @@ PHP_FUNCTION(pack) case 'E': { /* pack big endian double */ while (arg-- > 0) { - double v = (double) zval_get_double(&argv[currentarg++]); + double v = zval_get_double(&argv[currentarg++]); php_pack_copy_double(0, &ZSTR_VAL(output)[outputpos], v); outputpos += sizeof(v); } @@ -784,7 +784,7 @@ PHP_FUNCTION(unpack) if (namelen > 200) namelen = 200; - switch ((int) type) { + switch (type) { /* Never use any input */ case 'X': size = -1; @@ -902,7 +902,7 @@ PHP_FUNCTION(unpack) real_name = zend_string_concat2(name, namelen, res, digits); } - switch ((int) type) { + switch (type) { case 'a': { /* a will not strip any trailing whitespace or null padding */ zend_long len = inputlen - inputpos; /* Remaining string */ From 34e22c54bc75b7bbb1c3a2daa01e0a3d300cb6cb Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Tue, 10 Jun 2025 13:20:04 +0100 Subject: [PATCH 012/120] ext/standard/pack: Reduce scope of variable --- ext/standard/pack.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ext/standard/pack.c b/ext/standard/pack.c index e6ca60d456d42..7db7724cdb2ed 100644 --- a/ext/standard/pack.c +++ b/ext/standard/pack.c @@ -737,7 +737,6 @@ PHP_FUNCTION(unpack) while (formatlen-- > 0) { char type = *(format++); - char c; int repetitions = 1, argb; char *name; int namelen; @@ -745,7 +744,7 @@ PHP_FUNCTION(unpack) /* Handle format arguments if any */ if (formatlen > 0) { - c = *format; + char c = *format; if (c >= '0' && c <= '9') { errno = 0; From a297a44d2fbd9a32148c2373111131dce685f9bb Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Tue, 10 Jun 2025 13:24:51 +0100 Subject: [PATCH 013/120] ext/standard/pack: Remove unused header includes --- ext/standard/pack.c | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/ext/standard/pack.c b/ext/standard/pack.c index 7db7724cdb2ed..a7568544be021 100644 --- a/ext/standard/pack.c +++ b/ext/standard/pack.c @@ -16,30 +16,10 @@ #include "php.h" -#include #include #include #include -#include -#include -#ifdef PHP_WIN32 -#define O_RDONLY _O_RDONLY -#include "win32/param.h" -#else -#include -#endif #include "pack.h" -#ifdef HAVE_PWD_H -#ifdef PHP_WIN32 -#include "win32/pwd.h" -#else -#include -#endif -#endif -#include "fsock.h" -#ifdef HAVE_NETINET_IN_H -#include -#endif #define INC_OUTPUTPOS(a,b) \ if ((a) < 0 || ((INT_MAX - outputpos)/((int)b)) < (a)) { \ From def3a95b14618774e63f42829edcc2ffe026bf63 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Tue, 10 Jun 2025 15:14:07 +0100 Subject: [PATCH 014/120] [skip ci] ext/standard/pack: Fix indentation to use tabs --- ext/standard/pack.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/standard/pack.c b/ext/standard/pack.c index a7568544be021..d4c5cc1f04cfa 100644 --- a/ext/standard/pack.c +++ b/ext/standard/pack.c @@ -360,7 +360,7 @@ PHP_FUNCTION(pack) /* Calculate output length and upper bound while processing*/ for (i = 0; i < formatcount; i++) { - char code = formatcodes[i]; + char code = formatcodes[i]; int arg = formatargs[i]; switch (code) { @@ -443,7 +443,7 @@ PHP_FUNCTION(pack) /* Do actual packing */ for (i = 0; i < formatcount; i++) { - char code = formatcodes[i]; + char code = formatcodes[i]; int arg = formatargs[i]; switch (code) { From 029a78813dd57929934976ad032743155f28503e Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Thu, 12 Jun 2025 17:49:22 +0200 Subject: [PATCH 015/120] Simplify callers of zval_try_get_long() (#18830) Since 2b383848 references are handled properly by the Zend API, so we can simplify the callers by removing reference handling from there. --- ext/curl/share.c | 4 +--- ext/zip/php_zip.c | 8 +++----- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/ext/curl/share.c b/ext/curl/share.c index e5f9e3d807dc2..ba23faa46bf54 100644 --- a/ext/curl/share.c +++ b/ext/curl/share.c @@ -160,9 +160,7 @@ PHP_FUNCTION(curl_share_init_persistent) } ZEND_HASH_FOREACH_VAL(share_opts, zval *entry) { - ZVAL_DEREF(entry); - - bool failed = false; + bool failed; zend_ulong option = zval_try_get_long(entry, &failed); if (failed) { diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c index 5272a161ae292..450c297762b87 100644 --- a/ext/zip/php_zip.c +++ b/ext/zip/php_zip.c @@ -3037,13 +3037,11 @@ static int php_zip_cancel_callback(zip_t *arch, void *ptr) /* Cancel if an exception has been thrown */ return -1; } - bool failed = false; - zval *cb_retval_ptr = &cb_retval; - ZVAL_DEREF(cb_retval_ptr); - zend_long retval = zval_try_get_long(cb_retval_ptr, &failed); + bool failed; + zend_long retval = zval_try_get_long(&cb_retval, &failed); if (failed) { zend_type_error("Return value of callback provided to ZipArchive::registerCancelCallback()" - " must be of type int, %s returned", zend_zval_value_name(cb_retval_ptr)); + " must be of type int, %s returned", zend_zval_value_name(&cb_retval)); zval_ptr_dtor(&cb_retval); return -1; } From 28a083bddcacdad9ec2b846c2b87b2a6f3204bd5 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Thu, 12 Jun 2025 17:49:38 +0200 Subject: [PATCH 016/120] Use zend_string_release_ex() in concat_function() (#18827) The strings we encounter are either interned in which case the persistent bool doesn't matter; or they're temporary as the code already assumes that anyway. This patch shrinks the function from 3332 bytes to 3173 bytes on x86-64 with GCC 15.1.1. --- Zend/zend_operators.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index 7e456ff68246a..712a6039dfb14 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -2024,7 +2024,7 @@ ZEND_API zend_result ZEND_FASTCALL concat_function(zval *result, zval *op1, zval ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_CONCAT); op2_string = zval_try_get_string_func(op2); if (UNEXPECTED(!op2_string)) { - zend_string_release(op1_string); + zend_string_release_ex(op1_string, false); if (orig_op1 != result) { ZVAL_UNDEF(result); } @@ -2069,8 +2069,8 @@ has_op2_string:; uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(op1_string, op2_string); if (UNEXPECTED(op1_len > ZSTR_MAX_LEN - op2_len)) { - if (free_op1_string) zend_string_release(op1_string); - if (free_op2_string) zend_string_release(op2_string); + if (free_op1_string) zend_string_release_ex(op1_string, false); + if (free_op2_string) zend_string_release_ex(op2_string, false); zend_throw_error(NULL, "String size overflow"); if (orig_op1 != result) { ZVAL_UNDEF(result); @@ -2093,7 +2093,7 @@ has_op2_string:; /* account for the case where result_str == op1_string == op2_string and the realloc is done */ if (op1_string == op2_string) { if (free_op2_string) { - zend_string_release(op2_string); + zend_string_release_ex(op2_string, false); free_op2_string = false; } op2_string = result_str; @@ -2112,8 +2112,8 @@ has_op2_string:; ZSTR_VAL(result_str)[result_len] = '\0'; } - if (free_op1_string) zend_string_release(op1_string); - if (free_op2_string) zend_string_release(op2_string); + if (free_op1_string) zend_string_release_ex(op1_string, false); + if (free_op2_string) zend_string_release_ex(op2_string, false); return SUCCESS; } From 42b9b2f5b36200f8675bbf2eae623d12d478f9b8 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Thu, 12 Jun 2025 18:48:43 +0200 Subject: [PATCH 017/120] [ci skip] Fix pipe optimization test wrt temps for observers --- Zend/tests/pipe_operator/optimizations.phpt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Zend/tests/pipe_operator/optimizations.phpt b/Zend/tests/pipe_operator/optimizations.phpt index afdc528337c13..5a8750845ddc8 100644 --- a/Zend/tests/pipe_operator/optimizations.phpt +++ b/Zend/tests/pipe_operator/optimizations.phpt @@ -35,7 +35,7 @@ var_dump($res1); ?> --EXPECTF-- $_main: - ; (lines=18, args=0, vars=2, tmps=2) + ; (lines=18, args=0, vars=2, tmps=%d) ; (after optimizer) ; %s:1-27 0000 V2 = NEW 0 string("Other") @@ -61,7 +61,7 @@ LIVE RANGES: 2: 0010 - 0011 (tmp/var) _test1: - ; (lines=4, args=1, vars=1, tmps=1) + ; (lines=4, args=1, vars=1, tmps=%d) ; (after optimizer) ; %s:3-5 0000 CV0($a) = RECV 1 @@ -70,7 +70,7 @@ _test1: 0003 RETURN T1 Other::foo: - ; (lines=4, args=1, vars=1, tmps=1) + ; (lines=4, args=1, vars=1, tmps=%d) ; (after optimizer) ; %s:8-10 0000 CV0($a) = RECV 1 @@ -79,7 +79,7 @@ Other::foo: 0003 RETURN T1 Other::bar: - ; (lines=4, args=1, vars=1, tmps=1) + ; (lines=4, args=1, vars=1, tmps=%d) ; (after optimizer) ; %s:12-14 0000 CV0($a) = RECV 1 From afb1c574700e035ba20a3b8ddd203471a31ba6c6 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Mon, 9 Jun 2025 17:52:21 +0200 Subject: [PATCH 018/120] Fix GH-14551: PGO build fails with xxhash Turns out that the instrumentation added for gcov can change inlining decisions of the compiler, which results in a mismatch between the profile data CFG and the actual generated CFG between compiles. There are two functions that suffer from this issue: 1. _PHP_XXH3_Init: Removing the inline hint fixes this one. In fact, always inlining this makes no sense as there's no real opportunity for specialising. It just bloats the binary and increases I$ pressure. So besides fixing this issue it's beneficial on its own to drop the attribute. 2. PHP_XXH3_128_Final: Sometimes XXH128_canonicalFromHash gets inlined and sometimes not. Make sure it gets always inlined. Closes GH-18814. --- NEWS | 3 +++ ext/hash/hash_xxhash.c | 2 +- ext/hash/xxhash/xxhash.h | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index a665633283d0c..d32c60625ed23 100644 --- a/NEWS +++ b/NEWS @@ -18,6 +18,9 @@ PHP NEWS - FPM: . Fixed GH-18662 (fpm_get_status segfault). (txuna) +- Hash: + . Fixed bug GH-14551 (PGO build fails with xxhash). (nielsdos) + - Intl: . Fix memory leak in intl_datetime_decompose() on failure. (nielsdos) . Fix memory leak in locale lookup on failure. (nielsdos) diff --git a/ext/hash/hash_xxhash.c b/ext/hash/hash_xxhash.c index 24da754d8835a..070bd06bff070 100644 --- a/ext/hash/hash_xxhash.c +++ b/ext/hash/hash_xxhash.c @@ -154,7 +154,7 @@ const php_hash_ops php_hash_xxh3_64_ops = { typedef XXH_errorcode (*xxh3_reset_with_secret_func_t)(XXH3_state_t*, const void*, size_t); typedef XXH_errorcode (*xxh3_reset_with_seed_func_t)(XXH3_state_t*, XXH64_hash_t); -zend_always_inline static void _PHP_XXH3_Init(PHP_XXH3_64_CTX *ctx, HashTable *args, +static void _PHP_XXH3_Init(PHP_XXH3_64_CTX *ctx, HashTable *args, xxh3_reset_with_seed_func_t func_init_seed, xxh3_reset_with_secret_func_t func_init_secret, const char* algo_name) { memset(&ctx->s, 0, sizeof ctx->s); diff --git a/ext/hash/xxhash/xxhash.h b/ext/hash/xxhash/xxhash.h index 8e816c0584ebd..5874c9a1f97b5 100644 --- a/ext/hash/xxhash/xxhash.h +++ b/ext/hash/xxhash/xxhash.h @@ -931,7 +931,7 @@ XXH_PUBLIC_API int XXH128_cmp(const void* h128_1, const void* h128_2); /******* Canonical representation *******/ typedef struct { unsigned char digest[sizeof(XXH128_hash_t)]; } XXH128_canonical_t; -XXH_PUBLIC_API void XXH128_canonicalFromHash(XXH128_canonical_t* dst, XXH128_hash_t hash); +static zend_always_inline void XXH128_canonicalFromHash(XXH128_canonical_t* dst, XXH128_hash_t hash); XXH_PUBLIC_API XXH128_hash_t XXH128_hashFromCanonical(const XXH128_canonical_t* src); @@ -5503,7 +5503,7 @@ XXH_PUBLIC_API int XXH128_cmp(const void* h128_1, const void* h128_2) /*====== Canonical representation ======*/ /*! @ingroup xxh3_family */ -XXH_PUBLIC_API void +static zend_always_inline void XXH128_canonicalFromHash(XXH128_canonical_t* dst, XXH128_hash_t hash) { XXH_STATIC_ASSERT(sizeof(XXH128_canonical_t) == sizeof(XXH128_hash_t)); From 71a254489c9c4e3f92bd4893bbf591ac4c8d67c6 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 10 Jun 2025 19:24:35 +0100 Subject: [PATCH 019/120] ext/pdo_sqlite: EXPLAIN mode support for SQL statements. available since 3.41.0 we can reprepare a statement in either explain, explain query plan or the usual prepared mode. close GH-18829 --- NEWS | 3 + UPGRADING | 3 + ext/pdo_sqlite/pdo_sqlite.stub.php | 9 + ext/pdo_sqlite/pdo_sqlite_arginfo.h | 32 +- ext/pdo_sqlite/php_pdo_sqlite_int.h | 3 +- ext/pdo_sqlite/sqlite_statement.c | 64 ++- .../pdo_sqlite_getsetattr_explain.phpt | 400 ++++++++++++++++++ 7 files changed, 511 insertions(+), 3 deletions(-) create mode 100644 ext/pdo_sqlite/tests/subclasses/pdo_sqlite_getsetattr_explain.phpt diff --git a/NEWS b/NEWS index bf2b1937d7945..4e9aa8f483b2f 100644 --- a/NEWS +++ b/NEWS @@ -148,6 +148,9 @@ PHP NEWS has a wrong return type. (David Carlier) . Added Pdo_Sqlite::ATTR_BUSY_STATEMENT constant to check if a statement is currently executing. (David Carlier) + . Added Pdo_Sqlite::ATTR_EXPLAIN_STATEMENT constant to set a statement + in either EXPLAIN_MODE_PREPARED, EXPLAIN_MODE_EXPLAIN, + EXPLAIN_MODE_EXPLAIN_QUERY_PLAN modes. (David Carlier) - PGSQL: . Added pg_close_stmt to close a prepared statement while allowing diff --git a/UPGRADING b/UPGRADING index 26c87d7aeb795..98a7ec41c3a01 100644 --- a/UPGRADING +++ b/UPGRADING @@ -198,6 +198,9 @@ PHP 8.5 UPGRADE NOTES - PDO_Sqlite: . Added class constant Pdo_Sqlite::ATTR_BUSY_STATEMENT. + . Added class constants Pdo_Sqlite::ATTR_EXPLAIN_STATEMENT, + Pdo_Sqlite::EXPLAIN_MODE_PREPARED, Pdo_Sqlite::EXPLAIN_MODE_EXPLAIN, + Pdo_Sqlite::EXPLAIN_MODE_EXPLAIN_QUERY_PLAN. - SOAP: . Enumeration cases are now dumped in __getTypes(). diff --git a/ext/pdo_sqlite/pdo_sqlite.stub.php b/ext/pdo_sqlite/pdo_sqlite.stub.php index 4cb6c14eae0a4..596029524dea0 100644 --- a/ext/pdo_sqlite/pdo_sqlite.stub.php +++ b/ext/pdo_sqlite/pdo_sqlite.stub.php @@ -36,6 +36,15 @@ class Sqlite extends \PDO /** @cvalue PDO_SQLITE_ATTR_BUSY_STATEMENT */ public const int ATTR_BUSY_STATEMENT = UNKNOWN; + /** @cvalue PDO_SQLITE_ATTR_EXPLAIN_STATEMENT */ + public const int ATTR_EXPLAIN_STATEMENT = UNKNOWN; + +#if SQLITE_VERSION_NUMBER >= 3041000 + public const int EXPLAIN_MODE_PREPARED = 0; + public const int EXPLAIN_MODE_EXPLAIN = 1; + public const int EXPLAIN_MODE_EXPLAIN_QUERY_PLAN = 2; +#endif + /** @cvalue SQLITE_OK */ public const int OK = UNKNOWN; diff --git a/ext/pdo_sqlite/pdo_sqlite_arginfo.h b/ext/pdo_sqlite/pdo_sqlite_arginfo.h index ec826bc4bbc5a..b81790fa1df1d 100644 --- a/ext/pdo_sqlite/pdo_sqlite_arginfo.h +++ b/ext/pdo_sqlite/pdo_sqlite_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: ae1e62d72c3c8290c9f39f21b583e980ea9b8eb2 */ + * Stub hash: fa489a46c586ae935036f76a992163aeb67246d3 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Pdo_Sqlite_createAggregate, 0, 3, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0) @@ -116,6 +116,36 @@ static zend_class_entry *register_class_Pdo_Sqlite(zend_class_entry *class_entry zend_declare_typed_class_constant(class_entry, const_ATTR_BUSY_STATEMENT_name, &const_ATTR_BUSY_STATEMENT_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_ATTR_BUSY_STATEMENT_name); + zval const_ATTR_EXPLAIN_STATEMENT_value; + ZVAL_LONG(&const_ATTR_EXPLAIN_STATEMENT_value, PDO_SQLITE_ATTR_EXPLAIN_STATEMENT); + zend_string *const_ATTR_EXPLAIN_STATEMENT_name = zend_string_init_interned("ATTR_EXPLAIN_STATEMENT", sizeof("ATTR_EXPLAIN_STATEMENT") - 1, 1); + zend_declare_typed_class_constant(class_entry, const_ATTR_EXPLAIN_STATEMENT_name, &const_ATTR_EXPLAIN_STATEMENT_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(const_ATTR_EXPLAIN_STATEMENT_name); +#if SQLITE_VERSION_NUMBER >= 3041000 + + zval const_EXPLAIN_MODE_PREPARED_value; + ZVAL_LONG(&const_EXPLAIN_MODE_PREPARED_value, 0); + zend_string *const_EXPLAIN_MODE_PREPARED_name = zend_string_init_interned("EXPLAIN_MODE_PREPARED", sizeof("EXPLAIN_MODE_PREPARED") - 1, 1); + zend_declare_typed_class_constant(class_entry, const_EXPLAIN_MODE_PREPARED_name, &const_EXPLAIN_MODE_PREPARED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(const_EXPLAIN_MODE_PREPARED_name); +#endif +#if SQLITE_VERSION_NUMBER >= 3041000 + + zval const_EXPLAIN_MODE_EXPLAIN_value; + ZVAL_LONG(&const_EXPLAIN_MODE_EXPLAIN_value, 1); + zend_string *const_EXPLAIN_MODE_EXPLAIN_name = zend_string_init_interned("EXPLAIN_MODE_EXPLAIN", sizeof("EXPLAIN_MODE_EXPLAIN") - 1, 1); + zend_declare_typed_class_constant(class_entry, const_EXPLAIN_MODE_EXPLAIN_name, &const_EXPLAIN_MODE_EXPLAIN_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(const_EXPLAIN_MODE_EXPLAIN_name); +#endif +#if SQLITE_VERSION_NUMBER >= 3041000 + + zval const_EXPLAIN_MODE_EXPLAIN_QUERY_PLAN_value; + ZVAL_LONG(&const_EXPLAIN_MODE_EXPLAIN_QUERY_PLAN_value, 2); + zend_string *const_EXPLAIN_MODE_EXPLAIN_QUERY_PLAN_name = zend_string_init_interned("EXPLAIN_MODE_EXPLAIN_QUERY_PLAN", sizeof("EXPLAIN_MODE_EXPLAIN_QUERY_PLAN") - 1, 1); + zend_declare_typed_class_constant(class_entry, const_EXPLAIN_MODE_EXPLAIN_QUERY_PLAN_name, &const_EXPLAIN_MODE_EXPLAIN_QUERY_PLAN_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(const_EXPLAIN_MODE_EXPLAIN_QUERY_PLAN_name); +#endif + zval const_OK_value; ZVAL_LONG(&const_OK_value, SQLITE_OK); zend_string *const_OK_name = zend_string_init_interned("OK", sizeof("OK") - 1, 1); diff --git a/ext/pdo_sqlite/php_pdo_sqlite_int.h b/ext/pdo_sqlite/php_pdo_sqlite_int.h index 8acb95015e79a..69ac003356b87 100644 --- a/ext/pdo_sqlite/php_pdo_sqlite_int.h +++ b/ext/pdo_sqlite/php_pdo_sqlite_int.h @@ -74,7 +74,8 @@ enum { PDO_SQLITE_ATTR_OPEN_FLAGS = PDO_ATTR_DRIVER_SPECIFIC, PDO_SQLITE_ATTR_READONLY_STATEMENT, PDO_SQLITE_ATTR_EXTENDED_RESULT_CODES, - PDO_SQLITE_ATTR_BUSY_STATEMENT + PDO_SQLITE_ATTR_BUSY_STATEMENT, + PDO_SQLITE_ATTR_EXPLAIN_STATEMENT }; typedef int pdo_sqlite_create_collation_callback(void*, int, const void*, int, const void*); diff --git a/ext/pdo_sqlite/sqlite_statement.c b/ext/pdo_sqlite/sqlite_statement.c index 64c8c8a86dd9a..e683cc5ed51bf 100644 --- a/ext/pdo_sqlite/sqlite_statement.c +++ b/ext/pdo_sqlite/sqlite_statement.c @@ -26,6 +26,11 @@ #include "php_pdo_sqlite.h" #include "php_pdo_sqlite_int.h" +#if defined(__APPLE__) +// If more than one usage, a Zend macro could be created +// around this runtime check +#include +#endif static int pdo_sqlite_stmt_dtor(pdo_stmt_t *stmt) { @@ -387,6 +392,23 @@ static int pdo_sqlite_stmt_get_attribute(pdo_stmt_t *stmt, zend_long attr, zval ZVAL_TRUE(val); } break; + case PDO_SQLITE_ATTR_EXPLAIN_STATEMENT: +#if SQLITE_VERSION_NUMBER >= 3041000 +#if defined(__APPLE__) + if (__builtin_available(macOS 14.2, *)) { +#endif + ZVAL_LONG(val, (zend_long)sqlite3_stmt_isexplain(S->stmt)); + return 1; +#if defined(__APPLE__) + } else { + zend_value_error("explain statement unsupported"); + return 0; + } +#endif +#else + zend_value_error("explain statement unsupported"); + return 0; +#endif default: return 0; } @@ -394,6 +416,46 @@ static int pdo_sqlite_stmt_get_attribute(pdo_stmt_t *stmt, zend_long attr, zval return 1; } +static int pdo_sqlite_stmt_set_attribute(pdo_stmt_t *stmt, zend_long attr, zval *zval) +{ + pdo_sqlite_stmt *S = (pdo_sqlite_stmt*)stmt->driver_data; + + switch (attr) { + case PDO_SQLITE_ATTR_EXPLAIN_STATEMENT: +#if SQLITE_VERSION_NUMBER >= 3041000 +#if defined(__APPLE__) + if (__builtin_available(macOS 14.2, *)) { +#endif + if (Z_TYPE_P(zval) != IS_LONG) { + zend_type_error("explain mode must be of type int, %s given", zend_zval_value_name(zval)); + return 0; + } + if (Z_LVAL_P(zval) < 0 || Z_LVAL_P(zval) > 2) { + zend_value_error("explain mode must be one of the EXPLAIN_MODE_* constants"); + return 0; + } + if (sqlite3_stmt_explain(S->stmt, (int)Z_LVAL_P(zval)) != SQLITE_OK) { + return 0; + } + + return 1; +#if defined(__APPLE__) + } else { + zend_value_error("explain statement unsupported"); + return 0; + } +#endif +#else + zend_value_error("explain statement unsupported"); + return 0; +#endif + default: + return 0; + } + + return 1; +} + const struct pdo_stmt_methods sqlite_stmt_methods = { pdo_sqlite_stmt_dtor, pdo_sqlite_stmt_execute, @@ -401,7 +463,7 @@ const struct pdo_stmt_methods sqlite_stmt_methods = { pdo_sqlite_stmt_describe, pdo_sqlite_stmt_get_col, pdo_sqlite_stmt_param_hook, - NULL, /* set_attr */ + pdo_sqlite_stmt_set_attribute, /* set_attr */ pdo_sqlite_stmt_get_attribute, /* get_attr */ pdo_sqlite_stmt_col_meta, NULL, /* next_rowset */ diff --git a/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_getsetattr_explain.phpt b/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_getsetattr_explain.phpt new file mode 100644 index 0000000000000..c91fb892477b3 --- /dev/null +++ b/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_getsetattr_explain.phpt @@ -0,0 +1,400 @@ +--TEST-- +Pdo\Sqlite::ATTR_EXPLAIN_STATEMENT usage +--EXTENSIONS-- +pdo_sqlite +--SKIPIF-- + +--FILE-- +query('CREATE TABLE test_explain (a string);'); +$stmt = $db->prepare('INSERT INTO test_explain VALUES ("first insert"), ("second_insert")'); +$stmt->setAttribute(Pdo\Sqlite::ATTR_EXPLAIN_STATEMENT, Pdo\Sqlite::EXPLAIN_MODE_EXPLAIN); +var_dump($stmt->getAttribute(Pdo\Sqlite::ATTR_EXPLAIN_STATEMENT) == Pdo\Sqlite::EXPLAIN_MODE_EXPLAIN); +$r = $stmt->execute(); +var_dump($stmt->fetchAll(PDO::FETCH_ASSOC)); +$stmts = $db->prepare('SELECT * FROM test_explain'); +$stmts->setAttribute(Pdo\Sqlite::ATTR_EXPLAIN_STATEMENT, Pdo\Sqlite::EXPLAIN_MODE_EXPLAIN_QUERY_PLAN); +var_dump($stmt->getAttribute(Pdo\Sqlite::ATTR_EXPLAIN_STATEMENT) == Pdo\Sqlite::EXPLAIN_MODE_EXPLAIN_QUERY_PLAN); +$r = $stmts->execute(); +var_dump($stmts->fetchAll(PDO::FETCH_ASSOC)); + +$stmt = $db->prepare('INSERT INTO test_explain VALUES ("first insert"), ("second_insert")'); +$stmt->setAttribute(Pdo\Sqlite::ATTR_EXPLAIN_STATEMENT, Pdo\Sqlite::EXPLAIN_MODE_PREPARED); +$stmt->execute(); +$stmts->setAttribute(Pdo\Sqlite::ATTR_EXPLAIN_STATEMENT, Pdo\Sqlite::EXPLAIN_MODE_PREPARED); +$r = $stmts->execute(); +var_dump($stmts->fetchAll(PDO::FETCH_ASSOC)); + +class Duh {} + +try { + $stmts->setAttribute(Pdo\Sqlite::ATTR_EXPLAIN_STATEMENT, "EXPLAIN"); +} catch (\TypeError $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + $stmts->setAttribute(Pdo\Sqlite::ATTR_EXPLAIN_STATEMENT, new Duh()); +} catch (\TypeError $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + $stmts->setAttribute(Pdo\Sqlite::ATTR_EXPLAIN_STATEMENT, -1); +} catch (\ValueError $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + $stmts->setAttribute(Pdo\Sqlite::ATTR_EXPLAIN_STATEMENT, 256); +} catch (\ValueError $e) { + echo $e->getMessage(), PHP_EOL; +} + +var_dump($stmts->getAttribute(Pdo\Sqlite::ATTR_EXPLAIN_STATEMENT) == Pdo\Sqlite::EXPLAIN_MODE_PREPARED); +?> +--EXPECT-- +bool(true) +array(16) { + [0]=> + array(8) { + ["addr"]=> + int(0) + ["opcode"]=> + string(4) "Init" + ["p1"]=> + int(0) + ["p2"]=> + int(14) + ["p3"]=> + int(0) + ["p4"]=> + NULL + ["p5"]=> + int(0) + ["comment"]=> + NULL + } + [1]=> + array(8) { + ["addr"]=> + int(1) + ["opcode"]=> + string(13) "InitCoroutine" + ["p1"]=> + int(3) + ["p2"]=> + int(7) + ["p3"]=> + int(2) + ["p4"]=> + NULL + ["p5"]=> + int(0) + ["comment"]=> + NULL + } + [2]=> + array(8) { + ["addr"]=> + int(2) + ["opcode"]=> + string(7) "String8" + ["p1"]=> + int(0) + ["p2"]=> + int(2) + ["p3"]=> + int(0) + ["p4"]=> + string(12) "first insert" + ["p5"]=> + int(0) + ["comment"]=> + NULL + } + [3]=> + array(8) { + ["addr"]=> + int(3) + ["opcode"]=> + string(5) "Yield" + ["p1"]=> + int(3) + ["p2"]=> + int(0) + ["p3"]=> + int(0) + ["p4"]=> + NULL + ["p5"]=> + int(0) + ["comment"]=> + NULL + } + [4]=> + array(8) { + ["addr"]=> + int(4) + ["opcode"]=> + string(7) "String8" + ["p1"]=> + int(0) + ["p2"]=> + int(2) + ["p3"]=> + int(0) + ["p4"]=> + string(13) "second_insert" + ["p5"]=> + int(0) + ["comment"]=> + NULL + } + [5]=> + array(8) { + ["addr"]=> + int(5) + ["opcode"]=> + string(5) "Yield" + ["p1"]=> + int(3) + ["p2"]=> + int(0) + ["p3"]=> + int(0) + ["p4"]=> + NULL + ["p5"]=> + int(0) + ["comment"]=> + NULL + } + [6]=> + array(8) { + ["addr"]=> + int(6) + ["opcode"]=> + string(12) "EndCoroutine" + ["p1"]=> + int(3) + ["p2"]=> + int(0) + ["p3"]=> + int(0) + ["p4"]=> + NULL + ["p5"]=> + int(0) + ["comment"]=> + NULL + } + [7]=> + array(8) { + ["addr"]=> + int(7) + ["opcode"]=> + string(9) "OpenWrite" + ["p1"]=> + int(0) + ["p2"]=> + int(2) + ["p3"]=> + int(0) + ["p4"]=> + string(1) "1" + ["p5"]=> + int(0) + ["comment"]=> + NULL + } + [8]=> + array(8) { + ["addr"]=> + int(8) + ["opcode"]=> + string(5) "Yield" + ["p1"]=> + int(3) + ["p2"]=> + int(13) + ["p3"]=> + int(0) + ["p4"]=> + NULL + ["p5"]=> + int(0) + ["comment"]=> + NULL + } + [9]=> + array(8) { + ["addr"]=> + int(9) + ["opcode"]=> + string(8) "NewRowid" + ["p1"]=> + int(0) + ["p2"]=> + int(1) + ["p3"]=> + int(0) + ["p4"]=> + NULL + ["p5"]=> + int(0) + ["comment"]=> + NULL + } + [10]=> + array(8) { + ["addr"]=> + int(10) + ["opcode"]=> + string(10) "MakeRecord" + ["p1"]=> + int(2) + ["p2"]=> + int(1) + ["p3"]=> + int(4) + ["p4"]=> + string(1) "C" + ["p5"]=> + int(0) + ["comment"]=> + NULL + } + [11]=> + array(8) { + ["addr"]=> + int(11) + ["opcode"]=> + string(6) "Insert" + ["p1"]=> + int(0) + ["p2"]=> + int(4) + ["p3"]=> + int(1) + ["p4"]=> + string(12) "test_explain" + ["p5"]=> + int(57) + ["comment"]=> + NULL + } + [12]=> + array(8) { + ["addr"]=> + int(12) + ["opcode"]=> + string(4) "Goto" + ["p1"]=> + int(0) + ["p2"]=> + int(8) + ["p3"]=> + int(0) + ["p4"]=> + NULL + ["p5"]=> + int(0) + ["comment"]=> + NULL + } + [13]=> + array(8) { + ["addr"]=> + int(13) + ["opcode"]=> + string(4) "Halt" + ["p1"]=> + int(0) + ["p2"]=> + int(0) + ["p3"]=> + int(0) + ["p4"]=> + NULL + ["p5"]=> + int(0) + ["comment"]=> + NULL + } + [14]=> + array(8) { + ["addr"]=> + int(14) + ["opcode"]=> + string(11) "Transaction" + ["p1"]=> + int(0) + ["p2"]=> + int(1) + ["p3"]=> + int(1) + ["p4"]=> + string(1) "0" + ["p5"]=> + int(1) + ["comment"]=> + NULL + } + [15]=> + array(8) { + ["addr"]=> + int(15) + ["opcode"]=> + string(4) "Goto" + ["p1"]=> + int(0) + ["p2"]=> + int(1) + ["p3"]=> + int(0) + ["p4"]=> + NULL + ["p5"]=> + int(0) + ["comment"]=> + NULL + } +} +bool(false) +array(1) { + [0]=> + array(4) { + ["id"]=> + int(2) + ["parent"]=> + int(0) + ["notused"]=> + int(0) + ["detail"]=> + string(17) "SCAN test_explain" + } +} +array(2) { + [0]=> + array(1) { + ["a"]=> + string(12) "first insert" + } + [1]=> + array(1) { + ["a"]=> + string(13) "second_insert" + } +} +explain mode must be of type int, string given +explain mode must be of type int, Duh given +explain mode must be one of the EXPLAIN_MODE_* constants +explain mode must be one of the EXPLAIN_MODE_* constants +bool(true) From 058c0348fdd9599d16a49f292613e9ba91c59fe0 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Thu, 12 Jun 2025 21:23:15 +0100 Subject: [PATCH 020/120] ext/sqlite3: adding busy() call. checks if the prepared statement had been fetched but did not complete yet. close GH-18843 --- NEWS | 4 ++++ UPGRADING | 4 ++++ ext/sqlite3/sqlite3.c | 17 +++++++++++++++++ ext/sqlite3/sqlite3.stub.php | 2 ++ ext/sqlite3/sqlite3_arginfo.h | 7 ++++++- ext/sqlite3/tests/sqlite3_stmt_busy.phpt | 24 ++++++++++++++++++++++++ 6 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 ext/sqlite3/tests/sqlite3_stmt_busy.phpt diff --git a/NEWS b/NEWS index 4e9aa8f483b2f..01978f7e89e43 100644 --- a/NEWS +++ b/NEWS @@ -240,6 +240,10 @@ PHP NEWS . Fix overall theorical overflows on zend_string buffer allocations. (David Carlier/nielsdos) +- Sqlite: + . Added Sqlite3Stmt::busy to check if a statement is still being executed. + (David Carlier) + - Standard: . Fixed crypt() tests on musl when using --with-external-libcrypt (Michael Orlitzky). diff --git a/UPGRADING b/UPGRADING index 98a7ec41c3a01..a9bb61fddd86c 100644 --- a/UPGRADING +++ b/UPGRADING @@ -393,6 +393,10 @@ PHP 8.5 UPGRADE NOTES . ReflectionConstant::getAttributes() was introduced. RFC: https://wiki.php.net/rfc/attributes-on-constants +- Sqlite: + . Sqlite3Stmt::busy to check if a statement had been fetched + but not completely. + - Standard: . Added array_first() and array_last(). RFC: https://wiki.php.net/rfc/array_first_last diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c index 1396e693d9955..3b0811ccd7d2c 100644 --- a/ext/sqlite3/sqlite3.c +++ b/ext/sqlite3/sqlite3.c @@ -1479,6 +1479,23 @@ PHP_METHOD(SQLite3Stmt, readOnly) } /* }}} */ +PHP_METHOD(SQLite3Stmt, busy) +{ + php_sqlite3_stmt *stmt_obj; + zval *object = ZEND_THIS; + stmt_obj = Z_SQLITE3_STMT_P(object); + + ZEND_PARSE_PARAMETERS_NONE(); + + SQLITE3_CHECK_INITIALIZED(stmt_obj->db_obj, stmt_obj->initialised, SQLite3); + SQLITE3_CHECK_INITIALIZED_STMT(stmt_obj->stmt, SQLite3Stmt); + + if (sqlite3_stmt_busy(stmt_obj->stmt)) { + RETURN_TRUE; + } + RETURN_FALSE; +} + /* bind parameters to a statement before execution */ static int php_sqlite3_bind_params(php_sqlite3_stmt *stmt_obj) /* {{{ */ { diff --git a/ext/sqlite3/sqlite3.stub.php b/ext/sqlite3/sqlite3.stub.php index 3545da36acfcd..8a3d90470767a 100644 --- a/ext/sqlite3/sqlite3.stub.php +++ b/ext/sqlite3/sqlite3.stub.php @@ -272,6 +272,8 @@ public function readOnly(): bool {} /** @tentative-return-type */ public function reset(): bool {} + + public function busy(): bool {} } /** @not-serializable */ diff --git a/ext/sqlite3/sqlite3_arginfo.h b/ext/sqlite3/sqlite3_arginfo.h index 654e25edead6c..f83188841b43f 100644 --- a/ext/sqlite3/sqlite3_arginfo.h +++ b/ext/sqlite3/sqlite3_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: edf910997672a2b8d8b5c25e8a7a4ff1c135e7b1 */ + * Stub hash: 28132e0e4df61f19dc4b23a7c9f79be6b3e40a8e */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_SQLite3___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) @@ -144,6 +144,9 @@ ZEND_END_ARG_INFO() #define arginfo_class_SQLite3Stmt_reset arginfo_class_SQLite3_close +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_SQLite3Stmt_busy, 0, 0, _IS_BOOL, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(arginfo_class_SQLite3Result___construct, 0, 0, 0) ZEND_END_ARG_INFO() @@ -202,6 +205,7 @@ ZEND_METHOD(SQLite3Stmt, getSQL); ZEND_METHOD(SQLite3Stmt, paramCount); ZEND_METHOD(SQLite3Stmt, readOnly); ZEND_METHOD(SQLite3Stmt, reset); +ZEND_METHOD(SQLite3Stmt, busy); ZEND_METHOD(SQLite3Result, __construct); ZEND_METHOD(SQLite3Result, numColumns); ZEND_METHOD(SQLite3Result, columnName); @@ -253,6 +257,7 @@ static const zend_function_entry class_SQLite3Stmt_methods[] = { ZEND_ME(SQLite3Stmt, paramCount, arginfo_class_SQLite3Stmt_paramCount, ZEND_ACC_PUBLIC) ZEND_ME(SQLite3Stmt, readOnly, arginfo_class_SQLite3Stmt_readOnly, ZEND_ACC_PUBLIC) ZEND_ME(SQLite3Stmt, reset, arginfo_class_SQLite3Stmt_reset, ZEND_ACC_PUBLIC) + ZEND_ME(SQLite3Stmt, busy, arginfo_class_SQLite3Stmt_busy, ZEND_ACC_PUBLIC) ZEND_FE_END }; diff --git a/ext/sqlite3/tests/sqlite3_stmt_busy.phpt b/ext/sqlite3/tests/sqlite3_stmt_busy.phpt new file mode 100644 index 0000000000000..8110d374afe68 --- /dev/null +++ b/ext/sqlite3/tests/sqlite3_stmt_busy.phpt @@ -0,0 +1,24 @@ +--TEST-- +SQLite3_stmt::busy +--EXTENSIONS-- +sqlite3 +--SKIPIF-- + +--FILE-- +exec('CREATE TABLE test_busy (a string);'); +$db->exec('INSERT INTO test_busy VALUES ("interleaved"), ("statements")'); +$st = $db->prepare('SELECT a FROM test_busy'); +var_dump($st->busy()); +$r = $st->execute(); +$r->fetchArray(); +var_dump($st->busy()); +?> +--EXPECT-- +bool(false) +bool(true) From 43c18f3cfe33d5e06711a5b4a4464c7601527af6 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Tue, 10 Jun 2025 20:14:49 +0200 Subject: [PATCH 021/120] Fix GH-18823: setlocale's 2nd and 3rd argument ignores strict_types Closes GH-18828. --- NEWS | 2 ++ ext/standard/string.c | 29 +++++++++++++---- .../tests/strings/gh18823_strict.phpt | 19 +++++++++++ ext/standard/tests/strings/gh18823_weak.phpt | 32 +++++++++++++++++++ .../tests/strings/setlocale_variation4.phpt | 2 +- 5 files changed, 76 insertions(+), 8 deletions(-) create mode 100644 ext/standard/tests/strings/gh18823_strict.phpt create mode 100644 ext/standard/tests/strings/gh18823_weak.phpt diff --git a/NEWS b/NEWS index 01978f7e89e43..6c2d75d8a3070 100644 --- a/NEWS +++ b/NEWS @@ -250,6 +250,8 @@ PHP NEWS . Fixed bug GH-18062 (is_callable(func(...), callable_name: $name) for first class callables returns wrong name). (timwolla) . Added array_first() and array_last(). (nielsdos) + . Fixed bug GH-18823 (setlocale's 2nd and 3rd argument ignores strict_types). + (nielsdos) - Streams: . Fixed bug GH-16889 (stream_select() timeout useless for pipes on Windows). diff --git a/ext/standard/string.c b/ext/standard/string.c index f21c9be8a7bd2..36903b3c5c7b9 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -4926,37 +4926,52 @@ PHP_FUNCTION(setlocale) { zend_long cat; zval *args = NULL; - int num_args; + uint32_t num_args; + ALLOCA_FLAG(use_heap); ZEND_PARSE_PARAMETERS_START(2, -1) Z_PARAM_LONG(cat) Z_PARAM_VARIADIC('+', args, num_args) ZEND_PARSE_PARAMETERS_END(); + zend_string **strings = do_alloca(sizeof(zend_string *) * num_args, use_heap); + + for (uint32_t i = 0; i < num_args; i++) { + if (UNEXPECTED(Z_TYPE(args[i]) != IS_ARRAY && !zend_parse_arg_str(&args[i], &strings[i], false, i + 2))) { + zend_wrong_parameter_type_error(i + 2, Z_EXPECTED_ARRAY_OR_STRING, &args[i]); + goto out; + } + } + for (uint32_t i = 0; i < num_args; i++) { if (Z_TYPE(args[i]) == IS_ARRAY) { zval *elem; ZEND_HASH_FOREACH_VAL(Z_ARRVAL(args[i]), elem) { zend_string *result = try_setlocale_zval(cat, elem); if (EG(exception)) { - RETURN_THROWS(); + goto out; } if (result) { - RETURN_STR(result); + RETVAL_STR(result); + goto out; } } ZEND_HASH_FOREACH_END(); } else { - zend_string *result = try_setlocale_zval(cat, &args[i]); + zend_string *result = try_setlocale_str(cat, strings[i]); if (EG(exception)) { - RETURN_THROWS(); + goto out; } if (result) { - RETURN_STR(result); + RETVAL_STR(result); + goto out; } } } - RETURN_FALSE; + RETVAL_FALSE; + +out: + free_alloca(strings, use_heap); } /* }}} */ diff --git a/ext/standard/tests/strings/gh18823_strict.phpt b/ext/standard/tests/strings/gh18823_strict.phpt new file mode 100644 index 0000000000000..80b21d2093172 --- /dev/null +++ b/ext/standard/tests/strings/gh18823_strict.phpt @@ -0,0 +1,19 @@ +--TEST-- +GH-18823 (setlocale's 2nd and 3rd argument ignores strict_types) - strict mode +--FILE-- +getMessage(), "\n"; +} +try { + setlocale(LC_ALL, "0", 0); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +setlocale(): Argument #2 ($locales) must be of type array|string, int given +setlocale(): Argument #3 must be of type array|string, int given diff --git a/ext/standard/tests/strings/gh18823_weak.phpt b/ext/standard/tests/strings/gh18823_weak.phpt new file mode 100644 index 0000000000000..bc9611098a8db --- /dev/null +++ b/ext/standard/tests/strings/gh18823_weak.phpt @@ -0,0 +1,32 @@ +--TEST-- +GH-18823 (setlocale's 2nd and 3rd argument ignores strict_types) - weak mode +--INI-- +error_reporting=E_ALL +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECTF-- +Deprecated: setlocale(): Passing null to parameter #2 ($locales) of type string is deprecated in %s on line %d +no diff --git a/ext/standard/tests/strings/setlocale_variation4.phpt b/ext/standard/tests/strings/setlocale_variation4.phpt index ca469759dbd15..a2b236c146c8c 100644 --- a/ext/standard/tests/strings/setlocale_variation4.phpt +++ b/ext/standard/tests/strings/setlocale_variation4.phpt @@ -28,7 +28,7 @@ var_dump($locale_info_before); //Testing setlocale() by giving locale = null echo "Setting system locale, category = LC_ALL and locale = null\n"; -setlocale(LC_ALL, null); +@setlocale(LC_ALL, null); echo "Locale info, after setting the locale\n"; //Returns Current locale,after executing setlocale(). From 7361a1206d28810800d9ecf191d11b08dce7d03f Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Fri, 13 Jun 2025 19:19:13 +0100 Subject: [PATCH 022/120] ext/pdo_sqlite: explain statement prefixing with its class for errors. (#18846) --- ext/pdo_sqlite/sqlite_statement.c | 2 +- .../tests/subclasses/pdo_sqlite_getsetattr_explain.phpt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/pdo_sqlite/sqlite_statement.c b/ext/pdo_sqlite/sqlite_statement.c index e683cc5ed51bf..31fb98f887e04 100644 --- a/ext/pdo_sqlite/sqlite_statement.c +++ b/ext/pdo_sqlite/sqlite_statement.c @@ -431,7 +431,7 @@ static int pdo_sqlite_stmt_set_attribute(pdo_stmt_t *stmt, zend_long attr, zval return 0; } if (Z_LVAL_P(zval) < 0 || Z_LVAL_P(zval) > 2) { - zend_value_error("explain mode must be one of the EXPLAIN_MODE_* constants"); + zend_value_error("explain mode must be one of the Pdo\\Sqlite::EXPLAIN_MODE_* constants"); return 0; } if (sqlite3_stmt_explain(S->stmt, (int)Z_LVAL_P(zval)) != SQLITE_OK) { diff --git a/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_getsetattr_explain.phpt b/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_getsetattr_explain.phpt index c91fb892477b3..73a160e1d8134 100644 --- a/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_getsetattr_explain.phpt +++ b/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_getsetattr_explain.phpt @@ -395,6 +395,6 @@ array(2) { } explain mode must be of type int, string given explain mode must be of type int, Duh given -explain mode must be one of the EXPLAIN_MODE_* constants -explain mode must be one of the EXPLAIN_MODE_* constants +explain mode must be one of the Pdo\Sqlite::EXPLAIN_MODE_* constants +explain mode must be one of the Pdo\Sqlite::EXPLAIN_MODE_* constants bool(true) From 7e59769b1fb34335401033cac11e49ba95692c6c Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sat, 14 Jun 2025 15:00:49 +0200 Subject: [PATCH 023/120] Move pipe test with opcache dump to ext/opcache This test breaks under file cache (because the opcodes are not dumped when ran with a primed cache). run-tests.php --file-cache-* automatically skips all ext/opcache tests, so move it there. --- .../opcache/tests/pipe_optimizations.phpt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Zend/tests/pipe_operator/optimizations.phpt => ext/opcache/tests/pipe_optimizations.phpt (100%) diff --git a/Zend/tests/pipe_operator/optimizations.phpt b/ext/opcache/tests/pipe_optimizations.phpt similarity index 100% rename from Zend/tests/pipe_operator/optimizations.phpt rename to ext/opcache/tests/pipe_optimizations.phpt From 0a9697f5e1361825696f11ee72557640b172b838 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sat, 14 Jun 2025 15:51:18 +0200 Subject: [PATCH 024/120] Fix unused variable in pdo_sqlite_stmt_set_attribute() (GH-18851) The indentation is also wrong (using spaces instead of tabs), but this should be fixed in a separate commit. --- ext/pdo_sqlite/sqlite_statement.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/pdo_sqlite/sqlite_statement.c b/ext/pdo_sqlite/sqlite_statement.c index 31fb98f887e04..24d3f280a97a3 100644 --- a/ext/pdo_sqlite/sqlite_statement.c +++ b/ext/pdo_sqlite/sqlite_statement.c @@ -418,8 +418,6 @@ static int pdo_sqlite_stmt_get_attribute(pdo_stmt_t *stmt, zend_long attr, zval static int pdo_sqlite_stmt_set_attribute(pdo_stmt_t *stmt, zend_long attr, zval *zval) { - pdo_sqlite_stmt *S = (pdo_sqlite_stmt*)stmt->driver_data; - switch (attr) { case PDO_SQLITE_ATTR_EXPLAIN_STATEMENT: #if SQLITE_VERSION_NUMBER >= 3041000 @@ -434,6 +432,8 @@ static int pdo_sqlite_stmt_set_attribute(pdo_stmt_t *stmt, zend_long attr, zval zend_value_error("explain mode must be one of the Pdo\\Sqlite::EXPLAIN_MODE_* constants"); return 0; } + + pdo_sqlite_stmt *S = (pdo_sqlite_stmt*)stmt->driver_data; if (sqlite3_stmt_explain(S->stmt, (int)Z_LVAL_P(zval)) != SQLITE_OK) { return 0; } From 2e2494fbef842171257b0ae2b6d4392ba303f43f Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sat, 14 Jun 2025 16:00:13 +0200 Subject: [PATCH 025/120] [skip ci] Fix whitespace in ext/pdo_sqlite/sqlite_statement.c --- ext/pdo_sqlite/sqlite_statement.c | 70 +++++++++++++++---------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/ext/pdo_sqlite/sqlite_statement.c b/ext/pdo_sqlite/sqlite_statement.c index 24d3f280a97a3..381dab82af62f 100644 --- a/ext/pdo_sqlite/sqlite_statement.c +++ b/ext/pdo_sqlite/sqlite_statement.c @@ -392,22 +392,22 @@ static int pdo_sqlite_stmt_get_attribute(pdo_stmt_t *stmt, zend_long attr, zval ZVAL_TRUE(val); } break; - case PDO_SQLITE_ATTR_EXPLAIN_STATEMENT: + case PDO_SQLITE_ATTR_EXPLAIN_STATEMENT: #if SQLITE_VERSION_NUMBER >= 3041000 #if defined(__APPLE__) - if (__builtin_available(macOS 14.2, *)) { + if (__builtin_available(macOS 14.2, *)) { #endif - ZVAL_LONG(val, (zend_long)sqlite3_stmt_isexplain(S->stmt)); - return 1; + ZVAL_LONG(val, (zend_long)sqlite3_stmt_isexplain(S->stmt)); + return 1; #if defined(__APPLE__) - } else { - zend_value_error("explain statement unsupported"); - return 0; - } + } else { + zend_value_error("explain statement unsupported"); + return 0; + } #endif #else - zend_value_error("explain statement unsupported"); - return 0; + zend_value_error("explain statement unsupported"); + return 0; #endif default: return 0; @@ -419,41 +419,41 @@ static int pdo_sqlite_stmt_get_attribute(pdo_stmt_t *stmt, zend_long attr, zval static int pdo_sqlite_stmt_set_attribute(pdo_stmt_t *stmt, zend_long attr, zval *zval) { switch (attr) { - case PDO_SQLITE_ATTR_EXPLAIN_STATEMENT: + case PDO_SQLITE_ATTR_EXPLAIN_STATEMENT: #if SQLITE_VERSION_NUMBER >= 3041000 #if defined(__APPLE__) - if (__builtin_available(macOS 14.2, *)) { + if (__builtin_available(macOS 14.2, *)) { #endif - if (Z_TYPE_P(zval) != IS_LONG) { - zend_type_error("explain mode must be of type int, %s given", zend_zval_value_name(zval)); - return 0; - } - if (Z_LVAL_P(zval) < 0 || Z_LVAL_P(zval) > 2) { - zend_value_error("explain mode must be one of the Pdo\\Sqlite::EXPLAIN_MODE_* constants"); - return 0; - } - - pdo_sqlite_stmt *S = (pdo_sqlite_stmt*)stmt->driver_data; - if (sqlite3_stmt_explain(S->stmt, (int)Z_LVAL_P(zval)) != SQLITE_OK) { - return 0; - } - - return 1; + if (Z_TYPE_P(zval) != IS_LONG) { + zend_type_error("explain mode must be of type int, %s given", zend_zval_value_name(zval)); + return 0; + } + if (Z_LVAL_P(zval) < 0 || Z_LVAL_P(zval) > 2) { + zend_value_error("explain mode must be one of the Pdo\\Sqlite::EXPLAIN_MODE_* constants"); + return 0; + } + + pdo_sqlite_stmt *S = (pdo_sqlite_stmt*)stmt->driver_data; + if (sqlite3_stmt_explain(S->stmt, (int)Z_LVAL_P(zval)) != SQLITE_OK) { + return 0; + } + + return 1; #if defined(__APPLE__) - } else { - zend_value_error("explain statement unsupported"); - return 0; - } + } else { + zend_value_error("explain statement unsupported"); + return 0; + } #endif #else - zend_value_error("explain statement unsupported"); - return 0; + zend_value_error("explain statement unsupported"); + return 0; #endif default: return 0; - } + } - return 1; + return 1; } const struct pdo_stmt_methods sqlite_stmt_methods = { From a6749046f6c5fd043919cb9090452165542ab612 Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Tue, 17 Jun 2025 21:05:02 +0900 Subject: [PATCH 026/120] PHP-8.4 is now for PHP 8.4.10-dev --- NEWS | 5 ++++- Zend/zend.h | 2 +- configure.ac | 2 +- main/php_version.h | 6 +++--- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index c8a8197d1417e..5d8334fdf78fc 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,9 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -?? ??? ????, PHP 8.4.9 +?? ??? ????, PHP 8.4.10 + + +03 Jul 2025, PHP 8.4.9 - BcMath: . Fixed bug GH-18641 (Accessing a BcMath\Number property by ref crashes). diff --git a/Zend/zend.h b/Zend/zend.h index 34a6a0258a261..15a9b3d8189aa 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -20,7 +20,7 @@ #ifndef ZEND_H #define ZEND_H -#define ZEND_VERSION "4.4.9-dev" +#define ZEND_VERSION "4.4.10-dev" #define ZEND_ENGINE_3 diff --git a/configure.ac b/configure.ac index 3662d3e985b02..c94038e6ca5db 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ dnl Basic autoconf initialization, generation of config.nice. dnl ---------------------------------------------------------------------------- AC_PREREQ([2.68]) -AC_INIT([PHP],[8.4.9-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) +AC_INIT([PHP],[8.4.10-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) AC_CONFIG_SRCDIR([main/php_version.h]) AC_CONFIG_AUX_DIR([build]) AC_PRESERVE_HELP_ORDER diff --git a/main/php_version.h b/main/php_version.h index 7bd5e8c37f895..da01e82826df1 100644 --- a/main/php_version.h +++ b/main/php_version.h @@ -2,7 +2,7 @@ /* edit configure.ac to change version number */ #define PHP_MAJOR_VERSION 8 #define PHP_MINOR_VERSION 4 -#define PHP_RELEASE_VERSION 9 +#define PHP_RELEASE_VERSION 10 #define PHP_EXTRA_VERSION "-dev" -#define PHP_VERSION "8.4.9-dev" -#define PHP_VERSION_ID 80409 +#define PHP_VERSION "8.4.10-dev" +#define PHP_VERSION_ID 80410 From 50606f85696053f886ebd48e1b543bd09d3be3d8 Mon Sep 17 00:00:00 2001 From: Eric Mann Date: Tue, 17 Jun 2025 08:06:35 -0700 Subject: [PATCH 027/120] PHP 8.3 is now for PHP 8.3.24-dev --- NEWS | 5 ++++- Zend/zend.h | 2 +- configure.ac | 2 +- main/php_version.h | 6 +++--- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index d32c60625ed23..c29118397857d 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,9 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -?? ??? ????, PHP 8.3.23 +?? ??? ????, PHP 8.3.24 + + +03 Jul 2025, PHP 8.3.23 - Core: . Fixed GH-18695 (zend_ast_export() - float number is not preserved). diff --git a/Zend/zend.h b/Zend/zend.h index 704df32e9c145..0d2c52e2505e2 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -20,7 +20,7 @@ #ifndef ZEND_H #define ZEND_H -#define ZEND_VERSION "4.3.23-dev" +#define ZEND_VERSION "4.3.24-dev" #define ZEND_ENGINE_3 diff --git a/configure.ac b/configure.ac index 965c0bdd853ee..e96c12486fa2c 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ dnl Basic autoconf initialization, generation of config.nice. dnl ---------------------------------------------------------------------------- AC_PREREQ([2.68]) -AC_INIT([PHP],[8.3.23-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) +AC_INIT([PHP],[8.3.24-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) AC_CONFIG_SRCDIR([main/php_version.h]) AC_CONFIG_AUX_DIR([build]) AC_PRESERVE_HELP_ORDER diff --git a/main/php_version.h b/main/php_version.h index 28e4162421ded..cf74940556ddc 100644 --- a/main/php_version.h +++ b/main/php_version.h @@ -2,7 +2,7 @@ /* edit configure.ac to change version number */ #define PHP_MAJOR_VERSION 8 #define PHP_MINOR_VERSION 3 -#define PHP_RELEASE_VERSION 23 +#define PHP_RELEASE_VERSION 24 #define PHP_EXTRA_VERSION "-dev" -#define PHP_VERSION "8.3.23-dev" -#define PHP_VERSION_ID 80323 +#define PHP_VERSION "8.3.24-dev" +#define PHP_VERSION_ID 80324 From 5f67bace1b915ca45cabb12bf0c1dc35a58ae8bc Mon Sep 17 00:00:00 2001 From: Bogdan Ungureanu Date: Wed, 18 Jun 2025 11:21:31 +0300 Subject: [PATCH 028/120] ext/intl: Fix compile issues with ICU versions lower than 67 (#18868) --- ext/intl/listformatter/listformatter.stub.php | 10 +++++++++ .../listformatter/listformatter_arginfo.h | 22 ++++++++++++++++++- ext/intl/listformatter/listformatter_class.c | 15 ++++++++----- ext/intl/listformatter/listformatter_class.h | 3 +++ 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/ext/intl/listformatter/listformatter.stub.php b/ext/intl/listformatter/listformatter.stub.php index b16ad5c270091..c97127240b43c 100644 --- a/ext/intl/listformatter/listformatter.stub.php +++ b/ext/intl/listformatter/listformatter.stub.php @@ -8,8 +8,13 @@ */ final class IntlListFormatter { +#if U_ICU_VERSION_MAJOR_NUM >= 67 /** @cvalue ULISTFMT_TYPE_AND */ public const int TYPE_AND = UNKNOWN; +#else + /** @cvalue INTL_LISTFORMATTER_FALLBACK_TYPE_AND */ + public const int TYPE_AND = UNKNOWN; +#endif #if U_ICU_VERSION_MAJOR_NUM >= 67 /** @cvalue ULISTFMT_TYPE_OR */ @@ -19,8 +24,13 @@ final class IntlListFormatter { public const int TYPE_UNITS = UNKNOWN; #endif +#if U_ICU_VERSION_MAJOR_NUM >= 67 /** @cvalue ULISTFMT_WIDTH_WIDE */ public const int WIDTH_WIDE = UNKNOWN; +#else + /** @cvalue INTL_LISTFORMATTER_FALLBACK_WIDTH_WIDE */ + public const int WIDTH_WIDE = UNKNOWN; +#endif #if U_ICU_VERSION_MAJOR_NUM >= 67 /** @cvalue ULISTFMT_WIDTH_SHORT */ diff --git a/ext/intl/listformatter/listformatter_arginfo.h b/ext/intl/listformatter/listformatter_arginfo.h index 3e18c1154ae76..d9a4c3fb84ddc 100644 --- a/ext/intl/listformatter/listformatter_arginfo.h +++ b/ext/intl/listformatter/listformatter_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: f64f4171cfe4f66f976b9350b0a0e22269301ce5 */ + * Stub hash: cdbbdb55d1e53f422c5854460c3c6cc3d01360d7 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_IntlListFormatter___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, locale, IS_STRING, 0) @@ -36,12 +36,22 @@ static zend_class_entry *register_class_IntlListFormatter(void) INIT_CLASS_ENTRY(ce, "IntlListFormatter", class_IntlListFormatter_methods); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); +#if U_ICU_VERSION_MAJOR_NUM >= 67 zval const_TYPE_AND_value; ZVAL_LONG(&const_TYPE_AND_value, ULISTFMT_TYPE_AND); zend_string *const_TYPE_AND_name = zend_string_init_interned("TYPE_AND", sizeof("TYPE_AND") - 1, 1); zend_declare_typed_class_constant(class_entry, const_TYPE_AND_name, &const_TYPE_AND_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_TYPE_AND_name); +#endif +#if !(U_ICU_VERSION_MAJOR_NUM >= 67) + + zval const_TYPE_AND_value; + ZVAL_LONG(&const_TYPE_AND_value, INTL_LISTFORMATTER_FALLBACK_TYPE_AND); + zend_string *const_TYPE_AND_name = zend_string_init_interned("TYPE_AND", sizeof("TYPE_AND") - 1, 1); + zend_declare_typed_class_constant(class_entry, const_TYPE_AND_name, &const_TYPE_AND_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(const_TYPE_AND_name); +#endif #if U_ICU_VERSION_MAJOR_NUM >= 67 zval const_TYPE_OR_value; @@ -58,12 +68,22 @@ static zend_class_entry *register_class_IntlListFormatter(void) zend_declare_typed_class_constant(class_entry, const_TYPE_UNITS_name, &const_TYPE_UNITS_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_TYPE_UNITS_name); #endif +#if U_ICU_VERSION_MAJOR_NUM >= 67 zval const_WIDTH_WIDE_value; ZVAL_LONG(&const_WIDTH_WIDE_value, ULISTFMT_WIDTH_WIDE); zend_string *const_WIDTH_WIDE_name = zend_string_init_interned("WIDTH_WIDE", sizeof("WIDTH_WIDE") - 1, 1); zend_declare_typed_class_constant(class_entry, const_WIDTH_WIDE_name, &const_WIDTH_WIDE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_WIDTH_WIDE_name); +#endif +#if !(U_ICU_VERSION_MAJOR_NUM >= 67) + + zval const_WIDTH_WIDE_value; + ZVAL_LONG(&const_WIDTH_WIDE_value, INTL_LISTFORMATTER_FALLBACK_WIDTH_WIDE); + zend_string *const_WIDTH_WIDE_name = zend_string_init_interned("WIDTH_WIDE", sizeof("WIDTH_WIDE") - 1, 1); + zend_declare_typed_class_constant(class_entry, const_WIDTH_WIDE_name, &const_WIDTH_WIDE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(const_WIDTH_WIDE_name); +#endif #if U_ICU_VERSION_MAJOR_NUM >= 67 zval const_WIDTH_SHORT_value; diff --git a/ext/intl/listformatter/listformatter_class.c b/ext/intl/listformatter/listformatter_class.c index 522ecdd371357..1fe8da554a1ca 100644 --- a/ext/intl/listformatter/listformatter_class.c +++ b/ext/intl/listformatter/listformatter_class.c @@ -15,8 +15,8 @@ #include "php.h" #include "php_intl.h" #include -#include "listformatter_arginfo.h" #include "listformatter_class.h" +#include "listformatter_arginfo.h" #include "intl_convert.h" static zend_object_handlers listformatter_handlers; @@ -53,8 +53,13 @@ PHP_METHOD(IntlListFormatter, __construct) ListFormatter_object *obj = Z_INTL_LISTFORMATTER_P(ZEND_THIS); char* locale; size_t locale_len = 0; - zend_long type = ULISTFMT_TYPE_AND; - zend_long width = ULISTFMT_WIDTH_WIDE; + #if U_ICU_VERSION_MAJOR_NUM >= 67 + zend_long type = ULISTFMT_TYPE_AND; + zend_long width = ULISTFMT_WIDTH_WIDE; + #else + zend_long type = INTL_LISTFORMATTER_FALLBACK_TYPE_AND; + zend_long width = INTL_LISTFORMATTER_FALLBACK_WIDTH_WIDE; + #endif ZEND_PARSE_PARAMETERS_START(1, 3) Z_PARAM_STRING(locale, locale_len) Z_PARAM_OPTIONAL @@ -90,12 +95,12 @@ PHP_METHOD(IntlListFormatter, __construct) LISTFORMATTER_OBJECT(obj) = ulistfmt_openForType(locale, type, width, &status); #else - if (type != ULISTFMT_TYPE_AND) { + if (type != INTL_LISTFORMATTER_FALLBACK_TYPE_AND) { zend_argument_value_error(2, "contains an unsupported type. ICU 66 and below only support IntlListFormatter::TYPE_AND"); RETURN_THROWS(); } - if (width != ULISTFMT_WIDTH_WIDE) { + if (width != INTL_LISTFORMATTER_FALLBACK_WIDTH_WIDE) { zend_argument_value_error(3, "contains an unsupported width. ICU 66 and below only support IntlListFormatter::WIDTH_WIDE"); RETURN_THROWS(); } diff --git a/ext/intl/listformatter/listformatter_class.h b/ext/intl/listformatter/listformatter_class.h index 9dd708ca3dfbc..8fe8137796bfb 100644 --- a/ext/intl/listformatter/listformatter_class.h +++ b/ext/intl/listformatter/listformatter_class.h @@ -49,4 +49,7 @@ static inline ListFormatter_object *php_intl_listformatter_fetch_object(zend_obj void listformatter_register_class( void ); extern zend_class_entry *ListFormatter_ce_ptr; +#define INTL_LISTFORMATTER_FALLBACK_TYPE_AND 0 +#define INTL_LISTFORMATTER_FALLBACK_WIDTH_WIDE 0 + #endif // LISTFORMATTER_CLASS_H From 5ff5ee0698f47e87f65ca7daa3b338e804cd108f Mon Sep 17 00:00:00 2001 From: Demon Date: Sun, 8 Jun 2025 18:25:25 +0800 Subject: [PATCH 029/120] Fix iconv tests skipped on windows Closes GH-18802. --- ext/iconv/tests/translit-failure.phpt | 2 +- ext/iconv/tests/translit-utf8.phpt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/iconv/tests/translit-failure.phpt b/ext/iconv/tests/translit-failure.phpt index b639c26b4eb32..33f992300a184 100644 --- a/ext/iconv/tests/translit-failure.phpt +++ b/ext/iconv/tests/translit-failure.phpt @@ -4,7 +4,7 @@ Translit failure iconv --SKIPIF-- --INI-- error_reporting=2039 diff --git a/ext/iconv/tests/translit-utf8.phpt b/ext/iconv/tests/translit-utf8.phpt index 14b5d7a05e1b6..5a308820ca2be 100644 --- a/ext/iconv/tests/translit-utf8.phpt +++ b/ext/iconv/tests/translit-utf8.phpt @@ -4,7 +4,7 @@ Translit UTF-8 quotes iconv --SKIPIF-- --INI-- error_reporting=2047 From 5cf3c2663ba53049fc6326c0b401542429992215 Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Wed, 11 Jun 2025 13:22:02 +0200 Subject: [PATCH 030/120] Fix use after free during shutdown destruction Closes GH-18834. --- NEWS | 3 +++ Zend/tests/gh18833.phpt | 24 ++++++++++++++++++++++++ Zend/zend_objects_API.c | 4 +++- 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/gh18833.phpt diff --git a/NEWS b/NEWS index c29118397857d..af154569e2843 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,9 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.3.24 +- Core: + . Fixed bug GH-18833 (Use after free with weakmaps dependent on destruction + order). (Daniil Gentili) 03 Jul 2025, PHP 8.3.23 diff --git a/Zend/tests/gh18833.phpt b/Zend/tests/gh18833.phpt new file mode 100644 index 0000000000000..d00f860ee43aa --- /dev/null +++ b/Zend/tests/gh18833.phpt @@ -0,0 +1,24 @@ +--TEST-- +GH-18833 (Use after free with weakmaps dependent on destruction order) +--FILE-- +current(); + +echo "ok\n"; +?> +--EXPECT-- +ok diff --git a/Zend/zend_objects_API.c b/Zend/zend_objects_API.c index 80f5b747db710..ec4c88d6aa513 100644 --- a/Zend/zend_objects_API.c +++ b/Zend/zend_objects_API.c @@ -104,7 +104,9 @@ ZEND_API void ZEND_FASTCALL zend_objects_store_free_object_storage(zend_objects_ if (IS_OBJ_VALID(obj)) { if (!(OBJ_FLAGS(obj) & IS_OBJ_FREE_CALLED)) { GC_ADD_FLAGS(obj, IS_OBJ_FREE_CALLED); - if (obj->handlers->free_obj != zend_object_std_dtor) { + if (obj->handlers->free_obj != zend_object_std_dtor + || (OBJ_FLAGS(obj) & IS_OBJ_WEAKLY_REFERENCED) + ) { GC_ADDREF(obj); obj->handlers->free_obj(obj); } From f1295864597a2e46ee2694c5bcdc0132427e9c3f Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Wed, 18 Jun 2025 21:06:03 +0100 Subject: [PATCH 031/120] ext/pdo_sqlite: fix minimal version for EXPLAIN feature support. (#18854) --- ext/pdo_sqlite/pdo_sqlite.stub.php | 2 +- ext/pdo_sqlite/pdo_sqlite_arginfo.h | 8 +- ext/pdo_sqlite/sqlite_statement.c | 4 +- .../pdo_sqlite_getsetattr_explain.phpt | 102 +++++++++--------- 4 files changed, 58 insertions(+), 58 deletions(-) diff --git a/ext/pdo_sqlite/pdo_sqlite.stub.php b/ext/pdo_sqlite/pdo_sqlite.stub.php index 596029524dea0..4af2d8c55260b 100644 --- a/ext/pdo_sqlite/pdo_sqlite.stub.php +++ b/ext/pdo_sqlite/pdo_sqlite.stub.php @@ -39,7 +39,7 @@ class Sqlite extends \PDO /** @cvalue PDO_SQLITE_ATTR_EXPLAIN_STATEMENT */ public const int ATTR_EXPLAIN_STATEMENT = UNKNOWN; -#if SQLITE_VERSION_NUMBER >= 3041000 +#if SQLITE_VERSION_NUMBER >= 3043000 public const int EXPLAIN_MODE_PREPARED = 0; public const int EXPLAIN_MODE_EXPLAIN = 1; public const int EXPLAIN_MODE_EXPLAIN_QUERY_PLAN = 2; diff --git a/ext/pdo_sqlite/pdo_sqlite_arginfo.h b/ext/pdo_sqlite/pdo_sqlite_arginfo.h index b81790fa1df1d..02cf12673ce53 100644 --- a/ext/pdo_sqlite/pdo_sqlite_arginfo.h +++ b/ext/pdo_sqlite/pdo_sqlite_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: fa489a46c586ae935036f76a992163aeb67246d3 */ + * Stub hash: c1d4ef325ecb8c8cb312910e8091ca003dc2603a */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Pdo_Sqlite_createAggregate, 0, 3, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0) @@ -121,7 +121,7 @@ static zend_class_entry *register_class_Pdo_Sqlite(zend_class_entry *class_entry zend_string *const_ATTR_EXPLAIN_STATEMENT_name = zend_string_init_interned("ATTR_EXPLAIN_STATEMENT", sizeof("ATTR_EXPLAIN_STATEMENT") - 1, 1); zend_declare_typed_class_constant(class_entry, const_ATTR_EXPLAIN_STATEMENT_name, &const_ATTR_EXPLAIN_STATEMENT_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_ATTR_EXPLAIN_STATEMENT_name); -#if SQLITE_VERSION_NUMBER >= 3041000 +#if SQLITE_VERSION_NUMBER >= 3043000 zval const_EXPLAIN_MODE_PREPARED_value; ZVAL_LONG(&const_EXPLAIN_MODE_PREPARED_value, 0); @@ -129,7 +129,7 @@ static zend_class_entry *register_class_Pdo_Sqlite(zend_class_entry *class_entry zend_declare_typed_class_constant(class_entry, const_EXPLAIN_MODE_PREPARED_name, &const_EXPLAIN_MODE_PREPARED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_EXPLAIN_MODE_PREPARED_name); #endif -#if SQLITE_VERSION_NUMBER >= 3041000 +#if SQLITE_VERSION_NUMBER >= 3043000 zval const_EXPLAIN_MODE_EXPLAIN_value; ZVAL_LONG(&const_EXPLAIN_MODE_EXPLAIN_value, 1); @@ -137,7 +137,7 @@ static zend_class_entry *register_class_Pdo_Sqlite(zend_class_entry *class_entry zend_declare_typed_class_constant(class_entry, const_EXPLAIN_MODE_EXPLAIN_name, &const_EXPLAIN_MODE_EXPLAIN_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_EXPLAIN_MODE_EXPLAIN_name); #endif -#if SQLITE_VERSION_NUMBER >= 3041000 +#if SQLITE_VERSION_NUMBER >= 3043000 zval const_EXPLAIN_MODE_EXPLAIN_QUERY_PLAN_value; ZVAL_LONG(&const_EXPLAIN_MODE_EXPLAIN_QUERY_PLAN_value, 2); diff --git a/ext/pdo_sqlite/sqlite_statement.c b/ext/pdo_sqlite/sqlite_statement.c index 381dab82af62f..e9e7a0cc78609 100644 --- a/ext/pdo_sqlite/sqlite_statement.c +++ b/ext/pdo_sqlite/sqlite_statement.c @@ -393,7 +393,7 @@ static int pdo_sqlite_stmt_get_attribute(pdo_stmt_t *stmt, zend_long attr, zval } break; case PDO_SQLITE_ATTR_EXPLAIN_STATEMENT: -#if SQLITE_VERSION_NUMBER >= 3041000 +#if SQLITE_VERSION_NUMBER >= 3043000 #if defined(__APPLE__) if (__builtin_available(macOS 14.2, *)) { #endif @@ -420,7 +420,7 @@ static int pdo_sqlite_stmt_set_attribute(pdo_stmt_t *stmt, zend_long attr, zval { switch (attr) { case PDO_SQLITE_ATTR_EXPLAIN_STATEMENT: -#if SQLITE_VERSION_NUMBER >= 3041000 +#if SQLITE_VERSION_NUMBER >= 3043000 #if defined(__APPLE__) if (__builtin_available(macOS 14.2, *)) { #endif diff --git a/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_getsetattr_explain.phpt b/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_getsetattr_explain.phpt index 73a160e1d8134..383457f3a79e8 100644 --- a/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_getsetattr_explain.phpt +++ b/ext/pdo_sqlite/tests/subclasses/pdo_sqlite_getsetattr_explain.phpt @@ -59,9 +59,9 @@ try { var_dump($stmts->getAttribute(Pdo\Sqlite::ATTR_EXPLAIN_STATEMENT) == Pdo\Sqlite::EXPLAIN_MODE_PREPARED); ?> ---EXPECT-- +--EXPECTF-- bool(true) -array(16) { +array(%d) { [0]=> array(8) { ["addr"]=> @@ -71,7 +71,7 @@ array(16) { ["p1"]=> int(0) ["p2"]=> - int(14) + int(%d) ["p3"]=> int(0) ["p4"]=> @@ -79,7 +79,7 @@ array(16) { ["p5"]=> int(0) ["comment"]=> - NULL + %a } [1]=> array(8) { @@ -90,7 +90,7 @@ array(16) { ["p1"]=> int(3) ["p2"]=> - int(7) + int(%d) ["p3"]=> int(2) ["p4"]=> @@ -98,12 +98,12 @@ array(16) { ["p5"]=> int(0) ["comment"]=> - NULL + %a } - [2]=> + %A array(8) { ["addr"]=> - int(2) + int(%d) ["opcode"]=> string(7) "String8" ["p1"]=> @@ -117,12 +117,12 @@ array(16) { ["p5"]=> int(0) ["comment"]=> - NULL + %a } - [3]=> + %A array(8) { ["addr"]=> - int(3) + int(%d) ["opcode"]=> string(5) "Yield" ["p1"]=> @@ -136,12 +136,12 @@ array(16) { ["p5"]=> int(0) ["comment"]=> - NULL + %a } - [4]=> + %A array(8) { ["addr"]=> - int(4) + int(%d) ["opcode"]=> string(7) "String8" ["p1"]=> @@ -155,12 +155,12 @@ array(16) { ["p5"]=> int(0) ["comment"]=> - NULL + %a } - [5]=> + [%d]=> array(8) { ["addr"]=> - int(5) + int(%d) ["opcode"]=> string(5) "Yield" ["p1"]=> @@ -174,12 +174,12 @@ array(16) { ["p5"]=> int(0) ["comment"]=> - NULL + %a } - [6]=> + [%d]=> array(8) { ["addr"]=> - int(6) + int(%d) ["opcode"]=> string(12) "EndCoroutine" ["p1"]=> @@ -193,12 +193,12 @@ array(16) { ["p5"]=> int(0) ["comment"]=> - NULL + %a } - [7]=> + [%d]=> array(8) { ["addr"]=> - int(7) + int(%d) ["opcode"]=> string(9) "OpenWrite" ["p1"]=> @@ -212,18 +212,18 @@ array(16) { ["p5"]=> int(0) ["comment"]=> - NULL + %a } - [8]=> + [%d]=> array(8) { ["addr"]=> - int(8) + int(%d) ["opcode"]=> string(5) "Yield" ["p1"]=> int(3) ["p2"]=> - int(13) + int(%d) ["p3"]=> int(0) ["p4"]=> @@ -231,12 +231,12 @@ array(16) { ["p5"]=> int(0) ["comment"]=> - NULL + %a } - [9]=> + [%d]=> array(8) { ["addr"]=> - int(9) + int(%d) ["opcode"]=> string(8) "NewRowid" ["p1"]=> @@ -250,12 +250,12 @@ array(16) { ["p5"]=> int(0) ["comment"]=> - NULL + %a } - [10]=> + [%d]=> array(8) { ["addr"]=> - int(10) + int(%d) ["opcode"]=> string(10) "MakeRecord" ["p1"]=> @@ -269,12 +269,12 @@ array(16) { ["p5"]=> int(0) ["comment"]=> - NULL + %a } - [11]=> + [%d]=> array(8) { ["addr"]=> - int(11) + int(%d) ["opcode"]=> string(6) "Insert" ["p1"]=> @@ -288,18 +288,18 @@ array(16) { ["p5"]=> int(57) ["comment"]=> - NULL + %a } - [12]=> + [%d]=> array(8) { ["addr"]=> - int(12) + int(%d) ["opcode"]=> string(4) "Goto" ["p1"]=> int(0) ["p2"]=> - int(8) + int(%d) ["p3"]=> int(0) ["p4"]=> @@ -307,12 +307,12 @@ array(16) { ["p5"]=> int(0) ["comment"]=> - NULL + %a } - [13]=> + [%d]=> array(8) { ["addr"]=> - int(13) + int(%d) ["opcode"]=> string(4) "Halt" ["p1"]=> @@ -326,12 +326,12 @@ array(16) { ["p5"]=> int(0) ["comment"]=> - NULL + %a } - [14]=> + [%d]=> array(8) { ["addr"]=> - int(14) + int(%d) ["opcode"]=> string(11) "Transaction" ["p1"]=> @@ -345,12 +345,12 @@ array(16) { ["p5"]=> int(1) ["comment"]=> - NULL + %a } - [15]=> + [%d]=> array(8) { ["addr"]=> - int(15) + int(%d) ["opcode"]=> string(4) "Goto" ["p1"]=> @@ -364,7 +364,7 @@ array(16) { ["p5"]=> int(0) ["comment"]=> - NULL + %a } } bool(false) @@ -376,7 +376,7 @@ array(1) { ["parent"]=> int(0) ["notused"]=> - int(0) + int(%d) ["detail"]=> string(17) "SCAN test_explain" } From 3ff6874658231669e1f1659ad7b6edbbe81eb90e Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Thu, 19 Jun 2025 14:07:40 +0200 Subject: [PATCH 032/120] Remove HAVE_GETLOGIN from win32/config.w32.h.in template (#18865) PHP once had getlogin() emulation implemented on Windows. This isn't the case anymore since 2006 (dc34d34230ec152abfe27bf492d206a294359320), neither Windows has getlogin() function. --- win32/build/config.w32.h.in | 1 - 1 file changed, 1 deletion(-) diff --git a/win32/build/config.w32.h.in b/win32/build/config.w32.h.in index 40a4264cf396f..df69e4622f90d 100644 --- a/win32/build/config.w32.h.in +++ b/win32/build/config.w32.h.in @@ -59,7 +59,6 @@ #undef HAVE_STRUCT_STAT_ST_BLKSIZE #undef HAVE_STRUCT_STAT_ST_BLOCKS #define HAVE_STRUCT_STAT_ST_RDEV 1 -#define HAVE_GETLOGIN 1 #define HAVE_SHUTDOWN 1 #define HAVE_STRCASECMP 1 #define HAVE_UTIME 1 From 49dd61906a009a687988b9e25002359ca0a3282a Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Thu, 19 Jun 2025 17:19:23 +0200 Subject: [PATCH 033/120] Autotools: Move PHP_ODBC_* defines to configuration header (#15708) The PHP_ODBC_* defines are remains of the PHP 2 and 3 era where the ODBC functionality was part of the PHP core and was later moved to an extension. This moves these defines to a regular PHP configuration header (php_config.h) as done in other extensions. --- UPGRADING.INTERNALS | 3 +++ ext/odbc/config.m4 | 13 +++++++++---- main/build-defs.h.in | 4 ---- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index e4cf9e9c94b0d..432754528f09a 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -52,6 +52,9 @@ PHP 8.5 INTERNALS UPGRADE NOTES - Linux build system changes . libdir is properly set when --libdir (ex: /usr/lib64) and --with-libdir (ex lib64) configure options are used to ${libdir}/php (ex: /usr/lib64/php) + . PHP_ODBC_CFLAGS, PHP_ODBC_LFLAGS, PHP_ODBC_LIBS, PHP_ODBC_TYPE preprocessor + macros defined by ext/odbc are now defined in php_config.h instead of the + build-defs.h header. ======================== 3. Module changes diff --git a/ext/odbc/config.m4 b/ext/odbc/config.m4 index eb6572c2c5c2d..9baa8dbd8e646 100644 --- a/ext/odbc/config.m4 +++ b/ext/odbc/config.m4 @@ -428,11 +428,16 @@ if test -n "$ODBC_TYPE"; then AC_DEFINE([HAVE_UODBC], [1], [Define to 1 if the PHP extension 'odbc' is available.]) + AC_DEFINE_UNQUOTED([PHP_ODBC_CFLAGS], ["$ODBC_CFLAGS"], + [The compile options that PHP odbc extension was built with.]) + AC_DEFINE_UNQUOTED([PHP_ODBC_LIBS], ["$ODBC_LIBS"], + [The libraries linker flags that PHP odbc extension was built with.]) + AC_DEFINE_UNQUOTED([PHP_ODBC_LFLAGS], ["$ODBC_LFLAGS"], + [The linker flags that PHP odbc extension was built with.]) + AC_DEFINE_UNQUOTED([PHP_ODBC_TYPE], ["$ODBC_TYPE"], + [The ODBC library used in the PHP odbc extension.]) + PHP_SUBST([ODBC_SHARED_LIBADD]) - AC_SUBST([ODBC_CFLAGS]) - AC_SUBST([ODBC_LIBS]) - AC_SUBST([ODBC_LFLAGS]) - AC_SUBST([ODBC_TYPE]) PHP_NEW_EXTENSION([odbc], [php_odbc.c odbc_utils.c], diff --git a/main/build-defs.h.in b/main/build-defs.h.in index f0cbdb631c0d5..72cd9c30fb743 100644 --- a/main/build-defs.h.in +++ b/main/build-defs.h.in @@ -15,10 +15,6 @@ */ #define CONFIGURE_COMMAND "@CONFIGURE_COMMAND@" -#define PHP_ODBC_CFLAGS "@ODBC_CFLAGS@" -#define PHP_ODBC_LFLAGS "@ODBC_LFLAGS@" -#define PHP_ODBC_LIBS "@ODBC_LIBS@" -#define PHP_ODBC_TYPE "@ODBC_TYPE@" #define PHP_PROG_SENDMAIL "@PROG_SENDMAIL@" #define PEAR_INSTALLDIR "@EXPANDED_PEAR_INSTALLDIR@" #define PHP_INCLUDE_PATH "@INCLUDE_PATH@" From 2f55291cebcee390507a4762c8ca1f4333076713 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Thu, 19 Jun 2025 21:18:18 +0200 Subject: [PATCH 034/120] Sync to lexbor/lexbor@0eac579f (#18882) --- ext/lexbor/lexbor/core/sbst.h | 1 - ext/lexbor/lexbor/css/syntax/state.c | 158 ++++++++++----------------- ext/lexbor/lexbor/css/unit.h | 2 +- ext/lexbor/lexbor/css/unit/const.h | 6 +- ext/lexbor/lexbor/css/unit/res.h | 2 +- ext/lexbor/lexbor/css/value.h | 2 +- 6 files changed, 66 insertions(+), 105 deletions(-) diff --git a/ext/lexbor/lexbor/core/sbst.h b/ext/lexbor/lexbor/core/sbst.h index 03444afdc747d..15a1d4053ce56 100644 --- a/ext/lexbor/lexbor/core/sbst.h +++ b/ext/lexbor/lexbor/core/sbst.h @@ -25,7 +25,6 @@ extern "C" { # define LXB_NONSTRING #endif - typedef struct { lxb_char_t key; diff --git a/ext/lexbor/lexbor/css/syntax/state.c b/ext/lexbor/lexbor/css/syntax/state.c index 81c88e8c093f1..99cd30c1868f3 100644 --- a/ext/lexbor/lexbor/css/syntax/state.c +++ b/ext/lexbor/lexbor/css/syntax/state.c @@ -99,13 +99,6 @@ lxb_css_syntax_state_consume_numeric(lxb_css_syntax_tokenizer_t *tkz, const lxb_char_t *data, const lxb_char_t *end); -static const lxb_char_t * -lxb_css_syntax_state_decimal(lxb_css_syntax_tokenizer_t *tkz, - lxb_css_syntax_token_t *token, - const lxb_char_t *data, const lxb_char_t *end, - lxb_char_t *buf, lxb_char_t *buf_p, - const lxb_char_t *buf_end); - static const lxb_char_t * lxb_css_syntax_state_consume_numeric_name_start(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, @@ -706,8 +699,6 @@ lxb_css_syntax_state_plus(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, const lxb_char_t *data, const lxb_char_t *end) { - lxb_char_t buf[128]; - /* Skip U+002B PLUS SIGN (+). */ data += 1; @@ -732,8 +723,8 @@ lxb_css_syntax_state_plus(lxb_css_syntax_tokenizer_t *tkz, /* U+0030 DIGIT ZERO (0) and U+0039 DIGIT NINE (9) */ if (*data >= 0x30 && *data <= 0x39) { lxb_css_syntax_token_number(token)->have_sign = true; - return lxb_css_syntax_state_decimal(tkz, token, data, end, - buf, buf, buf + sizeof(buf)); + return lxb_css_syntax_state_consume_numeric(tkz, token, + data - 1, end); } data -= 1; @@ -804,6 +795,7 @@ lxb_css_syntax_state_full_stop(lxb_css_syntax_tokenizer_t *tkz, const lxb_char_t *data, const lxb_char_t *end) { if (lxb_css_syntax_state_start_number(data, end)) { + lxb_css_syntax_token_number(token)->have_sign = false; return lxb_css_syntax_state_consume_numeric(tkz, token, data, end); } @@ -935,37 +927,26 @@ lxb_css_syntax_state_rc_bracket(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_ * Numeric */ lxb_inline void -lxb_css_syntax_consume_numeric_set_int(lxb_css_syntax_tokenizer_t *tkz, - lxb_css_syntax_token_t *token, - const lxb_char_t *start, const lxb_char_t *end) -{ - double num = lexbor_strtod_internal(start, (end - start), 0); - - token->type = LXB_CSS_SYNTAX_TOKEN_NUMBER; - - lxb_css_syntax_token_number(token)->is_float = false; - lxb_css_syntax_token_number(token)->num = num; -} - -lxb_inline void -lxb_css_syntax_consume_numeric_set_float(lxb_css_syntax_tokenizer_t *tkz, - lxb_css_syntax_token_t *token, - const lxb_char_t *start, const lxb_char_t *end, - bool e_is_negative, int exponent, int e_digit) +lxb_css_syntax_consume_numeric_set(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *start, const lxb_char_t *end, + bool is_float, bool e_is_negative, + int exponent, int e_digit) { if (e_is_negative) { - exponent -= e_digit; + exponent = e_digit - exponent; + exponent = -exponent; } else { - exponent += e_digit; + exponent = e_digit + exponent; } double num = lexbor_strtod_internal(start, (end - start), exponent); token->type = LXB_CSS_SYNTAX_TOKEN_NUMBER; + lxb_css_syntax_token_number(token)->is_float = is_float; lxb_css_syntax_token_number(token)->num = num; - lxb_css_syntax_token_number(token)->is_float = true; } const lxb_char_t * @@ -985,19 +966,22 @@ lxb_css_syntax_state_consume_numeric(lxb_css_syntax_tokenizer_t *tkz, const lxb_char_t *data, const lxb_char_t *end) { - lxb_char_t *buf_p; - const lxb_char_t *buf_end; + bool e_is_negative, is_float; + int exponent, e_digit; + lxb_char_t ch, *buf_p; + const lxb_char_t *begin, *buf_end; + lxb_css_syntax_token_t *t_str; + lxb_css_syntax_token_string_t *str; lxb_char_t buf[128]; buf_p = buf; buf_end = buf + sizeof(buf); - do { - /* U+0030 DIGIT ZERO (0) and U+0039 DIGIT NINE (9) */ - if (*data < 0x30 || *data > 0x39) { - break; - } + str = lxb_css_syntax_token_dimension_string(token); + t_str = (lxb_css_syntax_token_t *) (void *) str; + /* U+0030 DIGIT ZERO (0) and U+0039 DIGIT NINE (9) */ + while (*data >= 0x30 && *data <= 0x39) { if (buf_p != buf_end) { *buf_p++ = *data; } @@ -1005,75 +989,54 @@ lxb_css_syntax_state_consume_numeric(lxb_css_syntax_tokenizer_t *tkz, data += 1; if (data >= end) { - lxb_css_syntax_consume_numeric_set_int(tkz, token, buf, buf_p); + lxb_css_syntax_consume_numeric_set(tkz, token, buf, buf_p, + false, false, 0, 0); return data; } } - while (true); - - /* U+002E FULL STOP (.) */ - if (*data != 0x2E) { - lxb_css_syntax_consume_numeric_set_int(tkz, token, buf, buf_p); - - return lxb_css_syntax_state_consume_numeric_name_start(tkz, token, - data, end); - } - data += 1; + exponent = 0; + is_float = false; - if (data >= end || *data < 0x30 || *data > 0x39) { - lxb_css_syntax_consume_numeric_set_int(tkz, token, buf, buf_p); - return data - 1; - } - - return lxb_css_syntax_state_decimal(tkz, token, data, end, - buf, buf_p, buf_end); -} + /* U+002E FULL STOP (.) */ + if (*data == 0x2E) { + data += 1; -static const lxb_char_t * -lxb_css_syntax_state_decimal(lxb_css_syntax_tokenizer_t *tkz, - lxb_css_syntax_token_t *token, - const lxb_char_t *data, const lxb_char_t *end, - lxb_char_t *buf, lxb_char_t *buf_p, - const lxb_char_t *buf_end) -{ - bool e_is_negative; - int exponent, e_digit; - lxb_char_t ch; - const lxb_char_t *begin; - lxb_css_syntax_token_t *t_str; - lxb_css_syntax_token_string_t *str; + /* U+0030 DIGIT ZERO (0) and U+0039 DIGIT NINE (9) */ + if (data >= end || *data < 0x30 || *data > 0x39) { + lxb_css_syntax_consume_numeric_set(tkz, token, buf, buf_p, + false, false, 0, 0); + return data - 1; + } - begin = data; + begin = buf_p; - str = lxb_css_syntax_token_dimension_string(token); - t_str = (lxb_css_syntax_token_t *) (void *) str; + /* U+0030 DIGIT ZERO (0) and U+0039 DIGIT NINE (9) */ + do { + if (buf_p != buf_end) { + *buf_p++ = *data; + } - /* U+0030 DIGIT ZERO (0) and U+0039 DIGIT NINE (9) */ - do { - if (buf_p != buf_end) { - *buf_p++ = *data; + data += 1; } + while (data < end && *data >= 0x30 && *data <= 0x39); - data += 1; + exponent = -(int) (buf_p - begin); + is_float = true; if (data >= end) { - exponent = 0 - (int) (data - begin); - - lxb_css_syntax_consume_numeric_set_float(tkz, token, buf, - buf_p, 0, exponent, 0); + lxb_css_syntax_consume_numeric_set(tkz, token, buf, buf_p, + true, false, exponent, 0); return data; } } - while (*data >= 0x30 && *data <= 0x39); ch = *data; - exponent = 0 - (int) (data - begin); /* U+0045 Latin Capital Letter (E) or U+0065 Latin Small Letter (e) */ if (ch != 0x45 && ch != 0x65) { - lxb_css_syntax_consume_numeric_set_float(tkz, token, buf, - buf_p, 0, exponent, 0); + lxb_css_syntax_consume_numeric_set(tkz, token, buf, buf_p, + is_float, false, exponent, 0); return lxb_css_syntax_state_consume_numeric_name_start(tkz, token, data, end); @@ -1087,11 +1050,10 @@ lxb_css_syntax_state_decimal(lxb_css_syntax_tokenizer_t *tkz, data -= 1; lxb_css_syntax_token_base(t_str)->length = 1; - lxb_css_syntax_buffer_append_m(tkz, data, 1); - lxb_css_syntax_consume_numeric_set_float(tkz, token, buf, - buf_p, 0, exponent, 0); + lxb_css_syntax_consume_numeric_set(tkz, token, buf, buf_p, + is_float, false, exponent, 0); token->type = LXB_CSS_SYNTAX_TOKEN_DIMENSION; @@ -1122,8 +1084,8 @@ lxb_css_syntax_state_decimal(lxb_css_syntax_tokenizer_t *tkz, data -= 1; } - lxb_css_syntax_consume_numeric_set_float(tkz, token, buf, - buf_p, 0, exponent, 0); + lxb_css_syntax_consume_numeric_set(tkz, token, buf, buf_p, + is_float, false, exponent, 0); token->type = LXB_CSS_SYNTAX_TOKEN_DIMENSION; @@ -1135,7 +1097,6 @@ lxb_css_syntax_state_decimal(lxb_css_syntax_tokenizer_t *tkz, return begin; } - begin = data; e_digit = 0; /* U+0030 DIGIT ZERO (0) and U+0039 DIGIT NINE (9) */ @@ -1145,16 +1106,17 @@ lxb_css_syntax_state_decimal(lxb_css_syntax_tokenizer_t *tkz, data += 1; if (data >= end) { - lxb_css_syntax_consume_numeric_set_float(tkz, token, buf, buf_p, - e_is_negative, exponent, - e_digit); - return data; + lxb_css_syntax_consume_numeric_set(tkz, token, buf, buf_p, + true, e_is_negative, + exponent, e_digit); + return data; } } while(*data >= 0x30 && *data <= 0x39); - lxb_css_syntax_consume_numeric_set_float(tkz, token, buf, buf_p, - e_is_negative, exponent, e_digit); + lxb_css_syntax_consume_numeric_set(tkz, token, buf, buf_p, + true, e_is_negative, + exponent, e_digit); return lxb_css_syntax_state_consume_numeric_name_start(tkz, token, data, end); diff --git a/ext/lexbor/lexbor/css/unit.h b/ext/lexbor/lexbor/css/unit.h index dbaa08d1c6d28..06dba0dbca5de 100644 --- a/ext/lexbor/lexbor/css/unit.h +++ b/ext/lexbor/lexbor/css/unit.h @@ -24,7 +24,7 @@ LXB_API const lxb_css_data_t * lxb_css_unit_relative_by_name(const lxb_char_t *name, size_t length); LXB_API const lxb_css_data_t * -lxb_css_unit_angel_by_name(const lxb_char_t *name, size_t length); +lxb_css_unit_angle_by_name(const lxb_char_t *name, size_t length); LXB_API const lxb_css_data_t * lxb_css_unit_frequency_by_name(const lxb_char_t *name, size_t length); diff --git a/ext/lexbor/lexbor/css/unit/const.h b/ext/lexbor/lexbor/css/unit/const.h index 686ce37f94ffc..9b7ba1c311b17 100644 --- a/ext/lexbor/lexbor/css/unit/const.h +++ b/ext/lexbor/lexbor/css/unit/const.h @@ -58,14 +58,14 @@ typedef enum { lxb_css_unit_relative_t; typedef enum { - LXB_CSS_UNIT_ANGEL__BEGIN = 0x0016, + LXB_CSS_UNIT_ANGLE__BEGIN = 0x0016, LXB_CSS_UNIT_DEG = 0x0016, LXB_CSS_UNIT_GRAD = 0x0017, LXB_CSS_UNIT_RAD = 0x0018, LXB_CSS_UNIT_TURN = 0x0019, - LXB_CSS_UNIT_ANGEL__LAST_ENTRY = 0x001a + LXB_CSS_UNIT_ANGLE__LAST_ENTRY = 0x001a } -lxb_css_unit_angel_t; +lxb_css_unit_angle_t; typedef enum { LXB_CSS_UNIT_FREQUENCY__BEGIN = 0x001a, diff --git a/ext/lexbor/lexbor/css/unit/res.h b/ext/lexbor/lexbor/css/unit/res.h index e4b867983894a..4cca189b6f459 100644 --- a/ext/lexbor/lexbor/css/unit/res.h +++ b/ext/lexbor/lexbor/css/unit/res.h @@ -246,7 +246,7 @@ static const lexbor_shs_entry_t lxb_css_unit_relative_shs[64] = {NULL, NULL, 0, 0} }; -static const lexbor_shs_entry_t lxb_css_unit_angel_shs[7] = +static const lexbor_shs_entry_t lxb_css_unit_angle_shs[7] = { {NULL, NULL, 6, 0}, {"turn", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_TURN], 4, 0}, diff --git a/ext/lexbor/lexbor/css/value.h b/ext/lexbor/lexbor/css/value.h index 7f74b6a6b458d..eb26aa8f8b95b 100644 --- a/ext/lexbor/lexbor/css/value.h +++ b/ext/lexbor/lexbor/css/value.h @@ -109,7 +109,7 @@ lxb_css_value_length_percentage_type_t; typedef struct { double num; bool is_float; - lxb_css_unit_angel_t unit; + lxb_css_unit_angle_t unit; } lxb_css_value_angle_t; From be70f42de7c9ec0e6158ce9ec9d21f0dac24897f Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Thu, 19 Jun 2025 21:49:36 +0200 Subject: [PATCH 035/120] Add HAVE_MEMMOVE to ext/pcre (#18862) The pcre2 library still needs HAVE_MEMMOVE defined to use the system (C99 standard) memmove() function, otherwise emulation is used. On Windows, this is already enabled. --- ext/pcre/config0.m4 | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ext/pcre/config0.m4 b/ext/pcre/config0.m4 index bf48aa53130c5..d049cc538c0f5 100644 --- a/ext/pcre/config0.m4 +++ b/ext/pcre/config0.m4 @@ -99,7 +99,14 @@ else [PHP_PCRE_CFLAGS="$PHP_PCRE_CFLAGS -Wno-implicit-fallthrough"],, [-Werror]) - PHP_PCRE_CFLAGS="$PHP_PCRE_CFLAGS -DHAVE_CONFIG_H -I@ext_srcdir@/pcre2lib -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1" + PHP_PCRE_CFLAGS=m4_normalize([" + $PHP_PCRE_CFLAGS + -DHAVE_CONFIG_H + -DHAVE_MEMMOVE + -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 + -I@ext_srcdir@/pcre2lib + "]) + AC_DEFINE([HAVE_BUNDLED_PCRE], [1], [Define to 1 if PHP uses the bundled PCRE library.]) AC_DEFINE([PCRE2_CODE_UNIT_WIDTH], [8]) From 9cacc57350e1bb2f070b4a7bda6803da1d71e140 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Thu, 19 Jun 2025 16:28:45 +0200 Subject: [PATCH 036/120] Track heap->real_size for USE_TRACKED_ALLOC real_size is returned by memory_get_usage(true), which previously returned 0. Discovered in Symfony ConsumeMessagesCommandTest::testRunWithMemoryLimit() through nightly. Closes GH-18880 --- Zend/zend_alloc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c index c41f6118607e2..61792b37c9c50 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -2256,6 +2256,7 @@ void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent) heap->custom_heap.std._free = free; } heap->size = 0; + heap->real_size = 0; } if (full) { @@ -2799,6 +2800,7 @@ static void *tracked_malloc(size_t size) void *ptr = __zend_malloc(size); tracked_add(heap, ptr, size); heap->size += size; + heap->real_size = heap->size; return ptr; } @@ -2810,6 +2812,7 @@ static void tracked_free(void *ptr) { zend_mm_heap *heap = AG(mm_heap); zval *size_zv = tracked_get_size_zv(heap, ptr); heap->size -= Z_LVAL_P(size_zv); + heap->real_size = heap->size; zend_hash_del_bucket(heap->tracked_allocs, (Bucket *) size_zv); free(ptr); } @@ -2835,6 +2838,7 @@ static void *tracked_realloc(void *ptr, size_t new_size) { ptr = __zend_realloc(ptr, new_size); tracked_add(heap, ptr, new_size); heap->size += new_size - old_size; + heap->real_size = heap->size; return ptr; } From edfd55c1970413b8513ebaab03a6169f67c4cf4c Mon Sep 17 00:00:00 2001 From: Saki Takamachi <34942839+SakiTakamachi@users.noreply.github.com> Date: Sat, 21 Jun 2025 01:34:42 +0900 Subject: [PATCH 037/120] ext/bcmath: use vector in compare (#18859) --- ext/bcmath/libbcmath/src/compare.c | 69 +++++++++++++++++------------- 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/ext/bcmath/libbcmath/src/compare.c b/ext/bcmath/libbcmath/src/compare.c index 06ef246782089..76ab794dc874c 100644 --- a/ext/bcmath/libbcmath/src/compare.c +++ b/ext/bcmath/libbcmath/src/compare.c @@ -39,6 +39,25 @@ than N2 and +1 if N1 is greater than N2. If USE_SIGN is false, just compare the magnitudes. */ +static inline bcmath_compare_result bc_compare_get_result_val(bool left_abs_greater, bool use_sign, sign left_sign) +{ + if (left_abs_greater) { + /* Magnitude of left > right. */ + if (!use_sign || left_sign == PLUS) { + return BCMATH_LEFT_GREATER; + } else { + return BCMATH_RIGHT_GREATER; + } + } else { + /* Magnitude of left < right. */ + if (!use_sign || left_sign == PLUS) { + return BCMATH_RIGHT_GREATER; + } else { + return BCMATH_LEFT_GREATER; + } + } +} + bcmath_compare_result _bc_do_compare(bc_num n1, bc_num n2, size_t scale, bool use_sign) { /* First, compare signs. */ @@ -66,21 +85,7 @@ bcmath_compare_result _bc_do_compare(bc_num n1, bc_num n2, size_t scale, bool us /* Now compare the magnitude. */ if (n1->n_len != n2->n_len) { - if (n1->n_len > n2->n_len) { - /* Magnitude of n1 > n2. */ - if (!use_sign || n1->n_sign == PLUS) { - return BCMATH_LEFT_GREATER; - } else { - return BCMATH_RIGHT_GREATER; - } - } else { - /* Magnitude of n1 < n2. */ - if (!use_sign || n1->n_sign == PLUS) { - return BCMATH_RIGHT_GREATER; - } else { - return BCMATH_LEFT_GREATER; - } - } + return bc_compare_get_result_val(n1->n_len > n2->n_len, use_sign, n1->n_sign); } size_t n1_scale = MIN(n1->n_scale, scale); @@ -92,6 +97,24 @@ bcmath_compare_result _bc_do_compare(bc_num n1, bc_num n2, size_t scale, bool us const char *n1ptr = n1->n_value; const char *n2ptr = n2->n_value; + while (count >= sizeof(BC_VECTOR)) { + BC_VECTOR n1bytes; + BC_VECTOR n2bytes; + memcpy(&n1bytes, n1ptr, sizeof(BC_VECTOR)); + memcpy(&n2bytes, n2ptr, sizeof(BC_VECTOR)); + + if (n1bytes != n2bytes) { +#if BC_LITTLE_ENDIAN + n1bytes = BC_BSWAP(n1bytes); + n2bytes = BC_BSWAP(n2bytes); +#endif + return bc_compare_get_result_val(n1bytes > n2bytes, use_sign, n1->n_sign); + } + count -= sizeof(BC_VECTOR); + n1ptr += sizeof(BC_VECTOR); + n2ptr += sizeof(BC_VECTOR); + } + while ((count > 0) && (*n1ptr == *n2ptr)) { n1ptr++; n2ptr++; @@ -99,21 +122,7 @@ bcmath_compare_result _bc_do_compare(bc_num n1, bc_num n2, size_t scale, bool us } if (count != 0) { - if (*n1ptr > *n2ptr) { - /* Magnitude of n1 > n2. */ - if (!use_sign || n1->n_sign == PLUS) { - return BCMATH_LEFT_GREATER; - } else { - return BCMATH_RIGHT_GREATER; - } - } else { - /* Magnitude of n1 < n2. */ - if (!use_sign || n1->n_sign == PLUS) { - return BCMATH_RIGHT_GREATER; - } else { - return BCMATH_LEFT_GREATER; - } - } + return bc_compare_get_result_val(*n1ptr > *n2ptr, use_sign, n1->n_sign); } /* They are equal up to the last part of the equal part of the fraction. */ From 940441106dda47a644510731cd4193704f70651a Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Fri, 20 Jun 2025 15:11:31 +0200 Subject: [PATCH 038/120] ext/dom: Fix new MSVC compiler warning Closes GH-18889 --- ext/dom/html_document.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/dom/html_document.c b/ext/dom/html_document.c index 1ba39870d39b9..248e85c74c396 100644 --- a/ext/dom/html_document.c +++ b/ext/dom/html_document.c @@ -752,7 +752,7 @@ static bool dom_parse_decode_encode_finish( static bool check_options_validity(uint32_t arg_num, zend_long options) { - const zend_long VALID_OPTIONS = XML_PARSE_NOERROR | XML_PARSE_COMPACT | HTML_PARSE_NOIMPLIED | DOM_HTML_NO_DEFAULT_NS; + const zend_long VALID_OPTIONS = HTML_PARSE_NOERROR | HTML_PARSE_COMPACT | HTML_PARSE_NOIMPLIED | DOM_HTML_NO_DEFAULT_NS; if ((options & ~VALID_OPTIONS) != 0) { zend_argument_value_error(arg_num, "contains invalid flags (allowed flags: " "LIBXML_NOERROR, " From 391bd2a48fb1e256ec7108166857997eea5da93a Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Fri, 20 Jun 2025 22:39:51 +0200 Subject: [PATCH 039/120] Remove bug61371 test These tests attempt to test that no memory is leaked for stream calls. However, it is incorrect to assume the memory will not increase for other reasons, e.g. when growing resource buffers, for the output buffer, etc. This was discovered through 9cacc57350e1bb2f070b4a7bda6803da1d71e140 with USE_TRACKED_ALLOC=1, but this can also fail with USE_ZEND_ALLOC=1 when increasing loop iterations. --- ext/standard/tests/streams/bug61371-unix.phpt | 45 ------------------- ext/standard/tests/streams/bug61371.phpt | 40 ----------------- 2 files changed, 85 deletions(-) delete mode 100644 ext/standard/tests/streams/bug61371-unix.phpt delete mode 100644 ext/standard/tests/streams/bug61371.phpt diff --git a/ext/standard/tests/streams/bug61371-unix.phpt b/ext/standard/tests/streams/bug61371-unix.phpt deleted file mode 100644 index e196c028cc941..0000000000000 --- a/ext/standard/tests/streams/bug61371-unix.phpt +++ /dev/null @@ -1,45 +0,0 @@ ---TEST-- -Bug #61371: stream_context_create() causes memory leaks on use streams_socket_create ---SKIPIF-- - ---EXPECTF-- -memory: %dkb -bool(true) -memory: %dkb -bool(true) -memory: %dkb -memory: %dkb -bool(true) -memory: %dkb -bool(true) -memory: %dkb diff --git a/ext/standard/tests/streams/bug61371.phpt b/ext/standard/tests/streams/bug61371.phpt deleted file mode 100644 index 00e6372e85a4f..0000000000000 --- a/ext/standard/tests/streams/bug61371.phpt +++ /dev/null @@ -1,40 +0,0 @@ ---TEST-- -Bug #61371: stream_context_create() causes memory leaks on use streams_socket_create ---FILE-- - ---EXPECTF-- -memory: %dkb -bool(true) -memory: %dkb -bool(true) -memory: %dkb -memory: %dkb -bool(true) -memory: %dkb -bool(true) -memory: %dkb From 9859d837caa4dd3baf055b27de069bc9b9cc7f49 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Thu, 29 May 2025 19:15:02 +0200 Subject: [PATCH 040/120] Implement request #61105: Support Soap 1.2 SoapFault Reason Text lang attribute This is on the border line of a bugfix and a new feature. Anyway, this is necessary to fix compatibility with .NET clients. Closes GH-18701. --- NEWS | 2 + UPGRADING | 5 + ext/soap/php_http.c | 24 ++--- ext/soap/php_packet_soap.c | 42 +++++---- ext/soap/php_soap.h | 3 +- ext/soap/soap.c | 146 ++++++++++++++++++----------- ext/soap/soap.stub.php | 5 +- ext/soap/soap_arginfo.h | 10 +- ext/soap/tests/bugs/bug38005.phpt | 2 +- ext/soap/tests/bugs/bug68996.phpt | 2 +- ext/soap/tests/bugs/bug73037.phpt | 5 +- ext/soap/tests/fault_language.phpt | 29 ++++++ ext/soap/tests/soap12/T12.phpt | 2 +- ext/soap/tests/soap12/T13.phpt | 2 +- ext/soap/tests/soap12/T14.phpt | 2 +- ext/soap/tests/soap12/T23.phpt | 2 +- ext/soap/tests/soap12/T24.phpt | 2 +- ext/soap/tests/soap12/T25.phpt | 2 +- ext/soap/tests/soap12/T27.phpt | 2 +- ext/soap/tests/soap12/T28.phpt | 2 +- ext/soap/tests/soap12/T33.phpt | 2 +- ext/soap/tests/soap12/T35.phpt | 2 +- ext/soap/tests/soap12/T36.phpt | 2 +- ext/soap/tests/soap12/T39.phpt | 2 +- ext/soap/tests/soap12/T56.phpt | 2 +- ext/soap/tests/soap12/T58.phpt | 2 +- ext/soap/tests/soap12/T59.phpt | 2 +- ext/soap/tests/soap12/T61.phpt | 2 +- ext/soap/tests/soap12/T63.phpt | 2 +- ext/soap/tests/soap12/T64.phpt | 2 +- ext/soap/tests/soap12/T65.phpt | 2 +- ext/soap/tests/soap12/T69.phpt | 2 +- ext/soap/tests/soap12/T70.phpt | 2 +- ext/soap/tests/soap12/T71.phpt | 2 +- ext/soap/tests/soap12/T72.phpt | 2 +- ext/soap/tests/soap12/T80.phpt | 2 +- 36 files changed, 205 insertions(+), 118 deletions(-) create mode 100644 ext/soap/tests/fault_language.phpt diff --git a/NEWS b/NEWS index 6c2d75d8a3070..fb117a221a37a 100644 --- a/NEWS +++ b/NEWS @@ -202,6 +202,8 @@ PHP NEWS . Fixed bug #70951 (Segmentation fault on invalid WSDL cache). (nielsdos) . Implement request #55503 (Extend __getTypes to support enumerations). (nielsdos, datibbaw) + . Implement request #61105 (Support Soap 1.2 SoapFault Reason Text lang + attribute). (nielsdos) - Sockets: . Added IPPROTO_ICMP/IPPROTO_ICMPV6 to create raw socket for ICMP usage. diff --git a/UPGRADING b/UPGRADING index a9bb61fddd86c..72bb5d76da936 100644 --- a/UPGRADING +++ b/UPGRADING @@ -204,6 +204,11 @@ PHP 8.5 UPGRADE NOTES - SOAP: . Enumeration cases are now dumped in __getTypes(). + . Implemented request #61105: + support for Soap 1.2 Reason Text xml:lang attribute. + The signature of SoapFault::__construct() and SoapServer::fault() therefore + now have an optional $lang parameter. + This support solves compatibility with .NET SOAP clients. - XSL: . The $namespace argument of XSLTProcessor::getParameter(), diff --git a/ext/soap/php_http.c b/ext/soap/php_http.c index a1bd7dff0c8a5..84a10368d22fe 100644 --- a/ext/soap/php_http.c +++ b/ext/soap/php_http.c @@ -455,7 +455,7 @@ int make_http_soap_request(zval *this_ptr, if (request != buf) { zend_string_release_ex(request, 0); } - add_soap_fault(this_ptr, "HTTP", "Unable to parse URL", NULL, NULL); + add_soap_fault(this_ptr, "HTTP", "Unable to parse URL", NULL, NULL, SOAP_GLOBAL(lang_en)); smart_str_free(&soap_headers_z); efree(http_msg); return FALSE; @@ -469,7 +469,7 @@ int make_http_soap_request(zval *this_ptr, if (request != buf) { zend_string_release_ex(request, 0); } - add_soap_fault(this_ptr, "HTTP", "Unknown protocol. Only http and https are allowed.", NULL, NULL); + add_soap_fault(this_ptr, "HTTP", "Unknown protocol. Only http and https are allowed.", NULL, NULL, SOAP_GLOBAL(lang_en)); smart_str_free(&soap_headers_z); efree(http_msg); return FALSE; @@ -482,7 +482,7 @@ int make_http_soap_request(zval *this_ptr, if (request != buf) { zend_string_release_ex(request, 0); } - add_soap_fault(this_ptr, "HTTP", "SSL support is not available in this build", NULL, NULL); + add_soap_fault(this_ptr, "HTTP", "SSL support is not available in this build", NULL, NULL, SOAP_GLOBAL(lang_en)); PG(allow_url_fopen) = old_allow_url_fopen; smart_str_free(&soap_headers_z); efree(http_msg); @@ -537,7 +537,7 @@ int make_http_soap_request(zval *this_ptr, if (request != buf) { zend_string_release_ex(request, 0); } - add_soap_fault(this_ptr, "HTTP", "Could not connect to host", NULL, NULL); + add_soap_fault(this_ptr, "HTTP", "Could not connect to host", NULL, NULL, SOAP_GLOBAL(lang_en)); PG(allow_url_fopen) = old_allow_url_fopen; smart_str_free(&soap_headers_z); efree(http_msg); @@ -908,14 +908,14 @@ int make_http_soap_request(zval *this_ptr, convert_to_null(Z_CLIENT_HTTPURL_P(this_ptr)); convert_to_null(Z_CLIENT_HTTPSOCKET_P(this_ptr)); convert_to_null(Z_CLIENT_USE_PROXY_P(this_ptr)); - add_soap_fault(this_ptr, "HTTP", "Failed Sending HTTP SOAP request", NULL, NULL); + add_soap_fault(this_ptr, "HTTP", "Failed Sending HTTP SOAP request", NULL, NULL, SOAP_GLOBAL(lang_en)); smart_str_free(&soap_headers_z); efree(http_msg); return FALSE; } smart_str_free(&soap_headers); } else { - add_soap_fault(this_ptr, "HTTP", "Failed to create stream??", NULL, NULL); + add_soap_fault(this_ptr, "HTTP", "Failed to create stream??", NULL, NULL, SOAP_GLOBAL(lang_en)); smart_str_free(&soap_headers_z); efree(http_msg); return FALSE; @@ -932,7 +932,7 @@ int make_http_soap_request(zval *this_ptr, php_stream_close(stream); convert_to_null(Z_CLIENT_HTTPSOCKET_P(this_ptr)); convert_to_null(Z_CLIENT_USE_PROXY_P(this_ptr)); - add_soap_fault(this_ptr, "HTTP", "Error Fetching http headers", NULL, NULL); + add_soap_fault(this_ptr, "HTTP", "Error Fetching http headers", NULL, NULL, SOAP_GLOBAL(lang_en)); smart_str_free(&soap_headers_z); efree(http_msg); return FALSE; @@ -1121,7 +1121,7 @@ int make_http_soap_request(zval *this_ptr, zend_string_release_ex(http_headers, 0); convert_to_null(Z_CLIENT_HTTPSOCKET_P(this_ptr)); convert_to_null(Z_CLIENT_USE_PROXY_P(this_ptr)); - add_soap_fault(this_ptr, "HTTP", "Error Fetching http body, No Content-Length, connection closed or chunked data", NULL, NULL); + add_soap_fault(this_ptr, "HTTP", "Error Fetching http body, No Content-Length, connection closed or chunked data", NULL, NULL, SOAP_GLOBAL(lang_en)); if (http_msg) { efree(http_msg); } @@ -1180,7 +1180,7 @@ int make_http_soap_request(zval *this_ptr, phpurl = new_url; if (--redirect_max < 1) { - add_soap_fault(this_ptr, "HTTP", "Redirection limit reached, aborting", NULL, NULL); + add_soap_fault(this_ptr, "HTTP", "Redirection limit reached, aborting", NULL, NULL, SOAP_GLOBAL(lang_en)); smart_str_free(&soap_headers_z); efree(http_msg); return FALSE; @@ -1318,7 +1318,7 @@ int make_http_soap_request(zval *this_ptr, if (http_msg) { efree(http_msg); } - add_soap_fault(this_ptr, "HTTP", "Unknown Content-Encoding", NULL, NULL); + add_soap_fault(this_ptr, "HTTP", "Unknown Content-Encoding", NULL, NULL, SOAP_GLOBAL(lang_en)); return FALSE; } if (call_user_function(CG(function_table), (zval*)NULL, &func, &retval, 1, params) == SUCCESS && @@ -1334,7 +1334,7 @@ int make_http_soap_request(zval *this_ptr, efree(content_encoding); zend_string_release_ex(http_headers, 0); zend_string_release_ex(http_body, 0); - add_soap_fault(this_ptr, "HTTP", "Can't uncompress compressed response", NULL, NULL); + add_soap_fault(this_ptr, "HTTP", "Can't uncompress compressed response", NULL, NULL, SOAP_GLOBAL(lang_en)); if (http_msg) { efree(http_msg); } @@ -1368,7 +1368,7 @@ int make_http_soap_request(zval *this_ptr, if (error) { zval_ptr_dtor(return_value); ZVAL_UNDEF(return_value); - add_soap_fault(this_ptr, "HTTP", http_msg, NULL, NULL); + add_soap_fault(this_ptr, "HTTP", http_msg, NULL, NULL, SOAP_GLOBAL(lang_en)); efree(http_msg); return FALSE; } diff --git a/ext/soap/php_packet_soap.c b/ext/soap/php_packet_soap.c index fddb6b63874d9..31ed094ef2fc7 100644 --- a/ext/soap/php_packet_soap.c +++ b/ext/soap/php_packet_soap.c @@ -40,11 +40,11 @@ bool parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctio response = soap_xmlParseMemory(buffer, buffer_size); if (!response) { - add_soap_fault(this_ptr, "Client", "looks like we got no XML document", NULL, NULL); + add_soap_fault(this_ptr, "Client", "looks like we got no XML document", NULL, NULL, SOAP_GLOBAL(lang_en)); return false; } if (xmlGetIntSubset(response) != NULL) { - add_soap_fault(this_ptr, "Client", "DTD are not supported by SOAP", NULL, NULL); + add_soap_fault(this_ptr, "Client", "DTD are not supported by SOAP", NULL, NULL, SOAP_GLOBAL(lang_en)); xmlFreeDoc(response); return false; } @@ -63,7 +63,7 @@ bool parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctio envelope_ns = SOAP_1_2_ENV_NAMESPACE; soap_version = SOAP_1_2; } else { - add_soap_fault(this_ptr, "VersionMismatch", "Wrong Version", NULL, NULL); + add_soap_fault(this_ptr, "VersionMismatch", "Wrong Version", NULL, NULL, SOAP_GLOBAL(lang_en)); xmlFreeDoc(response); return false; } @@ -71,7 +71,7 @@ bool parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctio trav = trav->next; } if (env == NULL) { - add_soap_fault(this_ptr, "Client", "looks like we got XML without \"Envelope\" element", NULL, NULL); + add_soap_fault(this_ptr, "Client", "looks like we got XML without \"Envelope\" element", NULL, NULL, SOAP_GLOBAL(lang_en)); xmlFreeDoc(response); return false; } @@ -79,16 +79,16 @@ bool parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctio attr = env->properties; while (attr != NULL) { if (attr->ns == NULL) { - add_soap_fault(this_ptr, "Client", "A SOAP Envelope element cannot have non Namespace qualified attributes", NULL, NULL); + add_soap_fault(this_ptr, "Client", "A SOAP Envelope element cannot have non Namespace qualified attributes", NULL, NULL, SOAP_GLOBAL(lang_en)); xmlFreeDoc(response); return false; } else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) { if (soap_version == SOAP_1_2) { - add_soap_fault(this_ptr, "Client", "encodingStyle cannot be specified on the Envelope", NULL, NULL); + add_soap_fault(this_ptr, "Client", "encodingStyle cannot be specified on the Envelope", NULL, NULL, SOAP_GLOBAL(lang_en)); xmlFreeDoc(response); return false; } else if (strcmp((char*)attr->children->content, SOAP_1_1_ENC_NAMESPACE) != 0) { - add_soap_fault(this_ptr, "Client", "Unknown data encoding style", NULL, NULL); + add_soap_fault(this_ptr, "Client", "Unknown data encoding style", NULL, NULL, SOAP_GLOBAL(lang_en)); xmlFreeDoc(response); return false; } @@ -120,7 +120,7 @@ bool parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctio trav = trav->next; } if (body == NULL) { - add_soap_fault(this_ptr, "Client", "Body must be present in a SOAP envelope", NULL, NULL); + add_soap_fault(this_ptr, "Client", "Body must be present in a SOAP envelope", NULL, NULL, SOAP_GLOBAL(lang_en)); xmlFreeDoc(response); return false; } @@ -128,17 +128,17 @@ bool parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctio while (attr != NULL) { if (attr->ns == NULL) { if (soap_version == SOAP_1_2) { - add_soap_fault(this_ptr, "Client", "A SOAP Body element cannot have non Namespace qualified attributes", NULL, NULL); + add_soap_fault(this_ptr, "Client", "A SOAP Body element cannot have non Namespace qualified attributes", NULL, NULL, SOAP_GLOBAL(lang_en)); xmlFreeDoc(response); return false; } } else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) { if (soap_version == SOAP_1_2) { - add_soap_fault(this_ptr, "Client", "encodingStyle cannot be specified on the Body", NULL, NULL); + add_soap_fault(this_ptr, "Client", "encodingStyle cannot be specified on the Body", NULL, NULL, SOAP_GLOBAL(lang_en)); xmlFreeDoc(response); return false; } else if (strcmp((char*)attr->children->content, SOAP_1_1_ENC_NAMESPACE) != 0) { - add_soap_fault(this_ptr, "Client", "Unknown data encoding style", NULL, NULL); + add_soap_fault(this_ptr, "Client", "Unknown data encoding style", NULL, NULL, SOAP_GLOBAL(lang_en)); xmlFreeDoc(response); return false; } @@ -146,7 +146,7 @@ bool parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctio attr = attr->next; } if (trav != NULL && soap_version == SOAP_1_2) { - add_soap_fault(this_ptr, "Client", "A SOAP 1.2 envelope can contain only Header and Body", NULL, NULL); + add_soap_fault(this_ptr, "Client", "A SOAP 1.2 envelope can contain only Header and Body", NULL, NULL, SOAP_GLOBAL(lang_en)); xmlFreeDoc(response); return false; } @@ -155,16 +155,16 @@ bool parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctio attr = head->properties; while (attr != NULL) { if (attr->ns == NULL) { - add_soap_fault(this_ptr, "Client", "A SOAP Header element cannot have non Namespace qualified attributes", NULL, NULL); + add_soap_fault(this_ptr, "Client", "A SOAP Header element cannot have non Namespace qualified attributes", NULL, NULL, SOAP_GLOBAL(lang_en)); xmlFreeDoc(response); return false; } else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) { if (soap_version == SOAP_1_2) { - add_soap_fault(this_ptr, "Client", "encodingStyle cannot be specified on the Header", NULL, NULL); + add_soap_fault(this_ptr, "Client", "encodingStyle cannot be specified on the Header", NULL, NULL, SOAP_GLOBAL(lang_en)); xmlFreeDoc(response); return false; } else if (strcmp((char*)attr->children->content, SOAP_1_1_ENC_NAMESPACE) != 0) { - add_soap_fault(this_ptr, "Client", "Unknown data encoding style", NULL, NULL); + add_soap_fault(this_ptr, "Client", "Unknown data encoding style", NULL, NULL, SOAP_GLOBAL(lang_en)); xmlFreeDoc(response); return false; } @@ -177,6 +177,7 @@ bool parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctio fault = get_node_ex(body->children,"Fault",envelope_ns); if (fault != NULL) { char *faultcode = NULL; + zend_string *lang = ZSTR_EMPTY_ALLOC(); zend_string *faultstring = NULL, *faultactor = NULL; zval details; xmlNodePtr tmp; @@ -219,13 +220,19 @@ bool parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctio tmp = get_node(fault->children,"Reason"); if (tmp != NULL && tmp->children != NULL) { - /* TODO: lang attribute */ tmp = get_node(tmp->children,"Text"); if (tmp != NULL && tmp->children != NULL) { zval zv; master_to_zval(&zv, get_conversion(IS_STRING), tmp); convert_to_string(&zv) faultstring = Z_STR(zv); + + /* xml:lang is required by SOAP 1.2, but for BC reasons we allow it to be missing */ + xmlAttrPtr lang_attr = get_attribute_ex(tmp->properties, "lang", (const char *) XML_XML_NAMESPACE); + if (lang_attr != NULL && lang_attr->children != NULL) { + const char *lang_str = (const char *) lang_attr->children->content; + lang = zend_string_init(lang_str, strlen(lang_str), false); + } } } @@ -234,13 +241,14 @@ bool parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctio master_to_zval(&details, NULL, tmp); } } - add_soap_fault(this_ptr, faultcode, faultstring ? ZSTR_VAL(faultstring) : NULL, faultactor ? ZSTR_VAL(faultactor) : NULL, &details); + add_soap_fault(this_ptr, faultcode, faultstring ? ZSTR_VAL(faultstring) : NULL, faultactor ? ZSTR_VAL(faultactor) : NULL, &details, lang); if (faultstring) { zend_string_release_ex(faultstring, 0); } if (faultactor) { zend_string_release_ex(faultactor, 0); } + zend_string_release_ex(lang, false); if (Z_REFCOUNTED(details)) { Z_DELREF(details); } diff --git a/ext/soap/php_soap.h b/ext/soap/php_soap.h index 89dbf4408be2f..98e3d4af6f19d 100644 --- a/ext/soap/php_soap.h +++ b/ext/soap/php_soap.h @@ -170,6 +170,7 @@ ZEND_BEGIN_MODULE_GLOBALS(soap) HashTable wsdl_cache; int cur_uniq_ref; HashTable *ref_map; + zend_string *lang_en; ZEND_END_MODULE_GLOBALS(soap) #ifdef ZTS @@ -194,7 +195,7 @@ extern zend_class_entry* soap_sdl_class_entry; extern HashTable php_soap_defEncNs, php_soap_defEnc, php_soap_defEncIndex; -void add_soap_fault(zval *obj, char *fault_code, char *fault_string, char *fault_actor, zval *fault_detail); +void add_soap_fault(zval *obj, char *fault_code, char *fault_string, char *fault_actor, zval *fault_detail, zend_string *lang); #define soap_error0(severity, format) \ php_error(severity, "SOAP-ERROR: " format) diff --git a/ext/soap/soap.c b/ext/soap/soap.c index e0577ac648cae..cdb0216ebcf83 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -49,10 +49,13 @@ static void function_to_string(sdlFunctionPtr function, smart_str *buf); static void type_to_string(sdlTypePtr type, smart_str *buf, int level); static void clear_soap_fault(zval *obj); -static void set_soap_fault(zval *obj, const char *fault_code_ns, const char *fault_code, const char *fault_string, const char *fault_actor, zval *fault_detail, zend_string *name); -static void add_soap_fault_ex(zval *fault, zval *obj, char *fault_code, char *fault_string, char *fault_actor, zval *fault_detail); -static ZEND_NORETURN void soap_server_fault(char* code, char* string, char *actor, zval* details, zend_string *name); +static void set_soap_fault(zval *obj, const char *fault_code_ns, const char *fault_code, const char *fault_string, const char *fault_actor, zval *fault_detail, zend_string *name, zend_string *lang); +static void add_soap_fault_en(zval *obj, char *fault_code, char *fault_string, char *fault_actor, zval *fault_detail); +static void add_soap_fault_ex(zval *fault, zval *obj, char *fault_code, char *fault_string, char *fault_actor, zval *fault_detail, zend_string *lang); +static void add_soap_fault_ex_en(zval *fault, zval *obj, char *fault_code, char *fault_string, char *fault_actor, zval *fault_detail); +static ZEND_NORETURN void soap_server_fault(char* code, char* string, char *actor, zval* details, zend_string *name, zend_string *lang); static void soap_server_fault_ex(sdlFunctionPtr function, zval* fault, soapHeader* hdr); +static ZEND_NORETURN void soap_server_fault_en(char* code, char* string, char *actor, zval* details, zend_string *name); static sdlParamPtr get_param(sdlFunctionPtr function, const char *param_name, zend_ulong index, int); static sdlFunctionPtr get_function(sdlPtr sdl, const char *function_name, size_t function_name_length); @@ -156,6 +159,7 @@ static void soap_error_handler(int error_num, zend_string *error_filename, uint3 #define Z_FAULT_DETAIL_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), FAULT_PROP_START_OFFSET + 4)) #define Z_FAULT_NAME_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), FAULT_PROP_START_OFFSET + 5)) #define Z_FAULT_HEADERFAULT_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), FAULT_PROP_START_OFFSET + 6)) +#define Z_FAULT_LANG_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), FAULT_PROP_START_OFFSET + 7)) #define FETCH_THIS_SERVICE_NO_BAILOUT(ss) \ { \ @@ -448,6 +452,7 @@ static void php_soap_init_globals(zend_soap_globals *soap_globals) soap_globals->soap_version = SOAP_1_1; soap_globals->mem_cache = NULL; soap_globals->ref_map = NULL; + soap_globals->lang_en = zend_string_init_interned(ZEND_STRL("en"), true); } PHP_MSHUTDOWN_FUNCTION(soap) @@ -467,6 +472,7 @@ PHP_MSHUTDOWN_FUNCTION(soap) zend_hash_destroy(SOAP_GLOBAL(mem_cache)); free(SOAP_GLOBAL(mem_cache)); } + zend_string_release_ex(SOAP_GLOBAL(lang_en), true); UNREGISTER_INI_ENTRIES(); return SUCCESS; } @@ -645,6 +651,7 @@ static void soap_fault_dtor_properties(zval *obj) zval_ptr_dtor(Z_FAULT_DETAIL_P(obj)); zval_ptr_dtor(Z_FAULT_NAME_P(obj)); zval_ptr_dtor(Z_FAULT_HEADERFAULT_P(obj)); + zval_ptr_dtor(Z_FAULT_LANG_P(obj)); ZVAL_EMPTY_STRING(Z_FAULT_STRING_P(obj)); ZVAL_NULL(Z_FAULT_CODE_P(obj)); ZVAL_NULL(Z_FAULT_CODENS_P(obj)); @@ -652,6 +659,7 @@ static void soap_fault_dtor_properties(zval *obj) ZVAL_NULL(Z_FAULT_DETAIL_P(obj)); ZVAL_NULL(Z_FAULT_NAME_P(obj)); ZVAL_NULL(Z_FAULT_HEADERFAULT_P(obj)); + ZVAL_EMPTY_STRING(Z_FAULT_LANG_P(obj)); } /* {{{ SoapFault constructor */ @@ -660,11 +668,12 @@ PHP_METHOD(SoapFault, __construct) char *fault_string = NULL, *fault_code = NULL, *fault_actor = NULL, *fault_code_ns = NULL; size_t fault_string_len, fault_actor_len = 0, fault_code_len = 0; zend_string *name = NULL; + zend_string *lang = ZSTR_EMPTY_ALLOC(); zval *details = NULL, *headerfault = NULL, *this_ptr; zend_string *code_str; HashTable *code_ht; - ZEND_PARSE_PARAMETERS_START(2, 6) + ZEND_PARSE_PARAMETERS_START(2, 7) Z_PARAM_ARRAY_HT_OR_STR_OR_NULL(code_ht, code_str) Z_PARAM_STRING(fault_string, fault_string_len) Z_PARAM_OPTIONAL @@ -672,6 +681,7 @@ PHP_METHOD(SoapFault, __construct) Z_PARAM_ZVAL_OR_NULL(details) Z_PARAM_STR_OR_NULL(name) Z_PARAM_ZVAL_OR_NULL(headerfault) + Z_PARAM_PATH_STR(lang) ZEND_PARSE_PARAMETERS_END(); if (code_str) { @@ -700,7 +710,7 @@ PHP_METHOD(SoapFault, __construct) } this_ptr = ZEND_THIS; - set_soap_fault(this_ptr, fault_code_ns, fault_code, fault_string, fault_actor, details, name); + set_soap_fault(this_ptr, fault_code_ns, fault_code, fault_string, fault_actor, details, name, lang); if (headerfault != NULL) { ZVAL_COPY(Z_FAULT_HEADERFAULT_P(this_ptr), headerfault); } @@ -1245,10 +1255,10 @@ static void _soap_server_exception(soapServicePtr service, sdlFunctionPtr functi if (service->send_errors) { zval rv; zend_string *msg = zval_get_string(zend_read_property_ex(zend_ce_error, Z_OBJ(exception_object), ZSTR_KNOWN(ZEND_STR_MESSAGE), /* silent */ false, &rv)); - add_soap_fault_ex(&exception_object, this_ptr, "Server", ZSTR_VAL(msg), NULL, NULL); + add_soap_fault_ex_en(&exception_object, this_ptr, "Server", ZSTR_VAL(msg), NULL, NULL); zend_string_release_ex(msg, 0); } else { - add_soap_fault_ex(&exception_object, this_ptr, "Server", "Internal Error", NULL, NULL); + add_soap_fault_ex_en(&exception_object, this_ptr, "Server", "Internal Error", NULL, NULL); } soap_server_fault_ex(function, &exception_object, NULL); } @@ -1288,7 +1298,7 @@ PHP_METHOD(SoapServer, handle) SOAP_GLOBAL(soap_version) = service->version; if (arg && ZEND_SIZE_T_INT_OVFL(arg_len)) { - soap_server_fault("Server", "Input string is too long", NULL, NULL, NULL); + soap_server_fault_en("Server", "Input string is too long", NULL, NULL, NULL); SOAP_SERVER_END_CODE(); return; } @@ -1314,13 +1324,13 @@ PHP_METHOD(SoapServer, handle) php_stream_passthru(stream); php_stream_close(stream); } else { - soap_server_fault("Server", "Couldn't find WSDL", NULL, NULL, NULL); + soap_server_fault_en("Server", "Couldn't find WSDL", NULL, NULL, NULL); } SOAP_SERVER_END_CODE(); return; } else { - soap_server_fault("Server", "WSDL generation is not supported yet", NULL, NULL, NULL); + soap_server_fault_en("Server", "WSDL generation is not supported yet", NULL, NULL, NULL); /* sapi_add_header("Content-Type: text/xml; charset=utf-8", sizeof("Content-Type: text/xml; charset=utf-8"), 1); PUTS("\nchildren,"Envelope"); @@ -1405,7 +1415,7 @@ PHP_METHOD(SoapServer, handle) } } xmlFreeDoc(doc_request); - soap_server_fault("Server", "DTD are not supported by SOAP", NULL, NULL, NULL); + soap_server_fault_en("Server", "DTD are not supported by SOAP", NULL, NULL, NULL); } old_sdl = SOAP_GLOBAL(sdl); @@ -1463,7 +1473,7 @@ PHP_METHOD(SoapServer, handle) soap_obj = tmp_soap_p; } else if (Z_OBJCE_P(tmp_soap_p) == php_ce_incomplete_class) { /* See #51561, communicate limitation to user */ - soap_server_fault("Server", "SoapServer class was deserialized from the session prior to loading the class passed to SoapServer::setClass(). Start the session after loading all classes to resolve this issue.", NULL, NULL, NULL); + soap_server_fault_en("Server", "SoapServer class was deserialized from the session prior to loading the class passed to SoapServer::setClass(). Start the session after loading all classes to resolve this issue.", NULL, NULL, NULL); } } } @@ -1522,7 +1532,7 @@ PHP_METHOD(SoapServer, handle) #if 0 if (service->sdl && !h->function && !h->hdr) { if (h->mustUnderstand) { - soap_server_fault("MustUnderstand","Header not understood", NULL, NULL, NULL); + soap_server_fault_en("MustUnderstand","Header not understood", NULL, NULL, NULL); } else { continue; } @@ -1553,7 +1563,7 @@ PHP_METHOD(SoapServer, handle) goto fail; } } else if (h->mustUnderstand) { - soap_server_fault("MustUnderstand","Header not understood", NULL, NULL, NULL); + soap_server_fault_en("MustUnderstand","Header not understood", NULL, NULL, NULL); } } } @@ -1716,12 +1726,13 @@ PHP_METHOD(SoapServer, fault) size_t code_len, string_len, actor_len = 0; zval* details = NULL; zend_string *name = NULL; + zend_string *lang = ZSTR_EMPTY_ALLOC(); soapServicePtr service; xmlCharEncodingHandlerPtr old_encoding; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|szS", + if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|szSP", &code, &code_len, &string, &string_len, &actor, &actor_len, &details, - &name) == FAILURE) { + &name, &lang) == FAILURE) { RETURN_THROWS(); } @@ -1730,7 +1741,7 @@ PHP_METHOD(SoapServer, fault) old_encoding = SOAP_GLOBAL(encoding); SOAP_GLOBAL(encoding) = service->encoding; - soap_server_fault(code, string, actor, details, name); + soap_server_fault(code, string, actor, details, name, lang); SOAP_GLOBAL(encoding) = old_encoding; SOAP_SERVER_END_CODE(); @@ -1826,18 +1837,23 @@ static void soap_server_fault_ex(sdlFunctionPtr function, zval* fault, soapHeade } /* }}} */ -static ZEND_NORETURN void soap_server_fault(char* code, char* string, char *actor, zval* details, zend_string* name) /* {{{ */ +static ZEND_NORETURN void soap_server_fault(char* code, char* string, char *actor, zval* details, zend_string* name, zend_string *lang) /* {{{ */ { zval ret; ZVAL_NULL(&ret); - set_soap_fault(&ret, NULL, code, string, actor, details, name); + set_soap_fault(&ret, NULL, code, string, actor, details, name, lang); /* TODO: Which function */ soap_server_fault_ex(NULL, &ret, NULL); zend_bailout(); } /* }}} */ +static ZEND_NORETURN void soap_server_fault_en(char* code, char* string, char *actor, zval* details, zend_string* name) +{ + soap_server_fault(code, string, actor, details, name, SOAP_GLOBAL(lang_en)); +} + static zend_never_inline ZEND_COLD void soap_real_error_handler(int error_num, zend_string *error_filename, const uint32_t error_lineno, zend_string *message) /* {{{ */ { bool _old_in_compilation; @@ -1861,7 +1877,7 @@ static zend_never_inline ZEND_COLD void soap_real_error_handler(int error_num, z code = "Client"; } - add_soap_fault_ex(&fault, &SOAP_GLOBAL(error_object), code, ZSTR_VAL(message), NULL, NULL); + add_soap_fault_ex_en(&fault, &SOAP_GLOBAL(error_object), code, ZSTR_VAL(message), NULL, NULL); Z_ADDREF(fault); zend_throw_exception_object(&fault); zend_bailout(); @@ -1904,7 +1920,7 @@ static zend_never_inline ZEND_COLD void soap_real_error_handler(int error_num, z } ZVAL_NULL(&fault_obj); - set_soap_fault(&fault_obj, NULL, code, ZSTR_VAL(buffer), NULL, &outbuf, NULL); + set_soap_fault(&fault_obj, NULL, code, ZSTR_VAL(buffer), NULL, &outbuf, NULL, SOAP_GLOBAL(lang_en)); zend_string_release(buffer); fault = 1; } @@ -2215,7 +2231,7 @@ static bool do_request(zval *this_ptr, xmlDoc *request, const char *location, co xmlDocDumpMemory(request, (xmlChar**)&buf, &buf_size); if (!buf) { - add_soap_fault(this_ptr, "HTTP", "Error build soap request", NULL, NULL); + add_soap_fault_en(this_ptr, "HTTP", "Error build soap request", NULL, NULL); return false; } @@ -2245,7 +2261,7 @@ static bool do_request(zval *this_ptr, xmlDoc *request, const char *location, co if (EG(exception) && instanceof_function(EG(exception)->ce, zend_ce_error)) { /* Programmer error in __doRequest() implementation, let it bubble up. */ } else if (Z_TYPE_P(Z_CLIENT_SOAP_FAULT_P(this_ptr)) != IS_OBJECT) { - add_soap_fault(this_ptr, "Client", "SoapClient::__doRequest() returned non string value", NULL, NULL); + add_soap_fault_en(this_ptr, "Client", "SoapClient::__doRequest() returned non string value", NULL, NULL); } ret = false; } else if (Z_TYPE_P(trace) == IS_TRUE) { @@ -2405,15 +2421,15 @@ static void do_soap_call(zend_execute_data *execute_data, smart_str_append(&error,function); smart_str_appends(&error,"\") is not a valid method for this service"); smart_str_0(&error); - add_soap_fault(this_ptr, "Client", ZSTR_VAL(error.s), NULL, NULL); + add_soap_fault_en(this_ptr, "Client", ZSTR_VAL(error.s), NULL, NULL); smart_str_free(&error); } } else { zval *uri = Z_CLIENT_URI_P(this_ptr); if (Z_TYPE_P(uri) != IS_STRING) { - add_soap_fault(this_ptr, "Client", "Error finding \"uri\" property", NULL, NULL); + add_soap_fault_en(this_ptr, "Client", "Error finding \"uri\" property", NULL, NULL); } else if (location == NULL) { - add_soap_fault(this_ptr, "Client", "Error could not find \"location\" property", NULL, NULL); + add_soap_fault_en(this_ptr, "Client", "Error could not find \"location\" property", NULL, NULL); } else { if (call_uri == NULL) { call_uri = Z_STR_P(uri); @@ -2450,7 +2466,7 @@ static void do_soap_call(zend_execute_data *execute_data, if (Z_TYPE_P(fault) == IS_OBJECT) { ZVAL_COPY(return_value, fault); } else { - add_soap_fault_ex(return_value, this_ptr, "Client", "Unknown Error", NULL, NULL); + add_soap_fault_ex_en(return_value, this_ptr, "Client", "Unknown Error", NULL, NULL); Z_ADDREF_P(return_value); } } else { @@ -2898,10 +2914,10 @@ static void clear_soap_fault(zval *obj) /* {{{ */ } /* }}} */ -static void add_soap_fault_ex(zval *fault, zval *obj, char *fault_code, char *fault_string, char *fault_actor, zval *fault_detail) /* {{{ */ +static void add_soap_fault_ex(zval *fault, zval *obj, char *fault_code, char *fault_string, char *fault_actor, zval *fault_detail, zend_string *lang) /* {{{ */ { ZVAL_NULL(fault); - set_soap_fault(fault, NULL, fault_code, fault_string, fault_actor, fault_detail, NULL); + set_soap_fault(fault, NULL, fault_code, fault_string, fault_actor, fault_detail, NULL, lang); zval *target; if (instanceof_function(Z_OBJCE_P(obj), soap_class_entry)) { target = Z_CLIENT_SOAP_FAULT_P(obj); @@ -2915,14 +2931,24 @@ static void add_soap_fault_ex(zval *fault, zval *obj, char *fault_code, char *fa } /* }}} */ -void add_soap_fault(zval *obj, char *fault_code, char *fault_string, char *fault_actor, zval *fault_detail) /* {{{ */ +static void add_soap_fault_ex_en(zval *fault, zval *obj, char *fault_code, char *fault_string, char *fault_actor, zval *fault_detail) +{ + add_soap_fault_ex(fault, obj, fault_code, fault_string, fault_actor, fault_detail, SOAP_GLOBAL(lang_en)); +} + +void add_soap_fault(zval *obj, char *fault_code, char *fault_string, char *fault_actor, zval *fault_detail, zend_string *lang) /* {{{ */ { zval fault; - add_soap_fault_ex(&fault, obj, fault_code, fault_string, fault_actor, fault_detail); + add_soap_fault_ex(&fault, obj, fault_code, fault_string, fault_actor, fault_detail, lang); } /* }}} */ -static void set_soap_fault(zval *obj, const char *fault_code_ns, const char *fault_code, const char *fault_string, const char *fault_actor, zval *fault_detail, zend_string *name) /* {{{ */ +static void add_soap_fault_en(zval *obj, char *fault_code, char *fault_string, char *fault_actor, zval *fault_detail) +{ + add_soap_fault(obj, fault_code, fault_string, fault_actor, fault_detail, SOAP_GLOBAL(lang_en)); +} + +static void set_soap_fault(zval *obj, const char *fault_code_ns, const char *fault_code, const char *fault_string, const char *fault_actor, zval *fault_detail, zend_string *name, zend_string *lang) /* {{{ */ { if (Z_TYPE_P(obj) != IS_OBJECT) { object_init_ex(obj, soap_fault_class_entry); @@ -2973,6 +2999,7 @@ static void set_soap_fault(zval *obj, const char *fault_code_ns, const char *fau if (name != NULL) { ZVAL_STR_COPY(Z_FAULT_NAME_P(obj), name); } + ZVAL_STR_COPY(Z_FAULT_LANG_P(obj), lang); } /* }}} */ @@ -3043,7 +3070,7 @@ static void deserialize_parameters(xmlNodePtr params, sdlFunctionPtr function, u sdlParamPtr param = NULL; if (function != NULL && (param = zend_hash_index_find_ptr(function->requestParameters, cur_param)) == NULL) { - soap_server_fault("Client", "Error cannot find parameter", NULL, NULL, NULL); + soap_server_fault_en("Client", "Error cannot find parameter", NULL, NULL, NULL); } if (param == NULL) { enc = NULL; @@ -3058,7 +3085,7 @@ static void deserialize_parameters(xmlNodePtr params, sdlFunctionPtr function, u } } if (num_of_params > cur_param) { - soap_server_fault("Client","Missing parameter", NULL, NULL, NULL); + soap_server_fault_en("Client","Missing parameter", NULL, NULL, NULL); } (*parameters) = tmp_parameters; (*num_params) = num_of_params; @@ -3145,7 +3172,7 @@ static xmlNodePtr get_envelope(xmlNodePtr trav, int *version, char **envelope_ns return trav; } - soap_server_fault("VersionMismatch", "Wrong Version", NULL, NULL, NULL); + soap_server_fault_en("VersionMismatch", "Wrong Version", NULL, NULL, NULL); } trav = trav->next; } @@ -3165,18 +3192,18 @@ static sdlFunctionPtr deserialize_function_call(sdlPtr sdl, xmlDocPtr request, c /* Get element */ env = get_envelope(request->children, version, &envelope_ns); if (!env) { - soap_server_fault("Client", "looks like we got XML without \"Envelope\" element", NULL, NULL, NULL); + soap_server_fault_en("Client", "looks like we got XML without \"Envelope\" element", NULL, NULL, NULL); } attr = env->properties; while (attr != NULL) { if (attr->ns == NULL) { - soap_server_fault("Client", "A SOAP Envelope element cannot have non Namespace qualified attributes", NULL, NULL, NULL); + soap_server_fault_en("Client", "A SOAP Envelope element cannot have non Namespace qualified attributes", NULL, NULL, NULL); } else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) { if (*version == SOAP_1_2) { - soap_server_fault("Client", "encodingStyle cannot be specified on the Envelope", NULL, NULL, NULL); + soap_server_fault_en("Client", "encodingStyle cannot be specified on the Envelope", NULL, NULL, NULL); } else if (strcmp((char*)attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) { - soap_server_fault("Client", "Unknown data encoding style", NULL, NULL, NULL); + soap_server_fault_en("Client", "Unknown data encoding style", NULL, NULL, NULL); } } attr = attr->next; @@ -3206,26 +3233,26 @@ static sdlFunctionPtr deserialize_function_call(sdlPtr sdl, xmlDocPtr request, c trav = trav->next; } if (body == NULL) { - soap_server_fault("Client", "Body must be present in a SOAP envelope", NULL, NULL, NULL); + soap_server_fault_en("Client", "Body must be present in a SOAP envelope", NULL, NULL, NULL); } attr = body->properties; while (attr != NULL) { if (attr->ns == NULL) { if (*version == SOAP_1_2) { - soap_server_fault("Client", "A SOAP Body element cannot have non Namespace qualified attributes", NULL, NULL, NULL); + soap_server_fault_en("Client", "A SOAP Body element cannot have non Namespace qualified attributes", NULL, NULL, NULL); } } else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) { if (*version == SOAP_1_2) { - soap_server_fault("Client", "encodingStyle cannot be specified on the Body", NULL, NULL, NULL); + soap_server_fault_en("Client", "encodingStyle cannot be specified on the Body", NULL, NULL, NULL); } else if (strcmp((char*)attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) { - soap_server_fault("Client", "Unknown data encoding style", NULL, NULL, NULL); + soap_server_fault_en("Client", "Unknown data encoding style", NULL, NULL, NULL); } } attr = attr->next; } if (trav != NULL && *version == SOAP_1_2) { - soap_server_fault("Client", "A SOAP 1.2 envelope can contain only Header and Body", NULL, NULL, NULL); + soap_server_fault_en("Client", "A SOAP 1.2 envelope can contain only Header and Body", NULL, NULL, NULL); } func = NULL; @@ -3234,7 +3261,7 @@ static sdlFunctionPtr deserialize_function_call(sdlPtr sdl, xmlDocPtr request, c if (trav->type == XML_ELEMENT_NODE) { /* if (func != NULL) { - soap_server_fault("Client", "looks like we got \"Body\" with several functions call", NULL, NULL, NULL); + soap_server_fault_en("Client", "looks like we got \"Body\" with several functions call", NULL, NULL, NULL); } */ func = trav; @@ -3251,19 +3278,19 @@ static sdlFunctionPtr deserialize_function_call(sdlPtr sdl, xmlDocPtr request, c if (function) { ZVAL_STRING(function_name, (char *)function->functionName); } else { - soap_server_fault("Client", "looks like we got \"Body\" without function call", NULL, NULL, NULL); + soap_server_fault_en("Client", "looks like we got \"Body\" without function call", NULL, NULL, NULL); } } } else { if (*version == SOAP_1_1) { attr = get_attribute_ex(func->properties,"encodingStyle",SOAP_1_1_ENV_NAMESPACE); if (attr && strcmp((char*)attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) { - soap_server_fault("Client","Unknown Data Encoding Style", NULL, NULL, NULL); + soap_server_fault_en("Client","Unknown Data Encoding Style", NULL, NULL, NULL); } } else { attr = get_attribute_ex(func->properties,"encodingStyle",SOAP_1_2_ENV_NAMESPACE); if (attr && strcmp((char*)attr->children->content,SOAP_1_2_ENC_NAMESPACE) != 0) { - soap_server_fault("DataEncodingUnknown","Unknown Data Encoding Style", NULL, NULL, NULL); + soap_server_fault_en("DataEncodingUnknown","Unknown Data Encoding Style", NULL, NULL, NULL); } } if (!function) { @@ -3271,7 +3298,7 @@ static sdlFunctionPtr deserialize_function_call(sdlPtr sdl, xmlDocPtr request, c } if (sdl != NULL && function == NULL) { if (*version == SOAP_1_2) { - soap_server_fault("rpc:ProcedureNotPresent","Procedure not present", NULL, NULL, NULL); + soap_server_fault_en("rpc:ProcedureNotPresent","Procedure not present", NULL, NULL, NULL); } else { php_error(E_ERROR, "Procedure '%s' not present", func->name); } @@ -3285,12 +3312,12 @@ static sdlFunctionPtr deserialize_function_call(sdlPtr sdl, xmlDocPtr request, c attr = head->properties; while (attr != NULL) { if (attr->ns == NULL) { - soap_server_fault("Client", "A SOAP Header element cannot have non Namespace qualified attributes", NULL, NULL, NULL); + soap_server_fault_en("Client", "A SOAP Header element cannot have non Namespace qualified attributes", NULL, NULL, NULL); } else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) { if (*version == SOAP_1_2) { - soap_server_fault("Client", "encodingStyle cannot be specified on the Header", NULL, NULL, NULL); + soap_server_fault_en("Client", "encodingStyle cannot be specified on the Header", NULL, NULL, NULL); } else if (strcmp((char*)attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) { - soap_server_fault("Client", "Unknown data encoding style", NULL, NULL, NULL); + soap_server_fault_en("Client", "Unknown data encoding style", NULL, NULL, NULL); } } attr = attr->next; @@ -3304,7 +3331,7 @@ static sdlFunctionPtr deserialize_function_call(sdlPtr sdl, xmlDocPtr request, c if (*version == SOAP_1_1) { attr = get_attribute_ex(hdr_func->properties,"encodingStyle",SOAP_1_1_ENV_NAMESPACE); if (attr && strcmp((char*)attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) { - soap_server_fault("Client","Unknown Data Encoding Style", NULL, NULL, NULL); + soap_server_fault_en("Client","Unknown Data Encoding Style", NULL, NULL, NULL); } attr = get_attribute_ex(hdr_func->properties,"actor",envelope_ns); if (attr != NULL) { @@ -3316,7 +3343,7 @@ static sdlFunctionPtr deserialize_function_call(sdlPtr sdl, xmlDocPtr request, c } else if (*version == SOAP_1_2) { attr = get_attribute_ex(hdr_func->properties,"encodingStyle",SOAP_1_2_ENV_NAMESPACE); if (attr && strcmp((char*)attr->children->content,SOAP_1_2_ENC_NAMESPACE) != 0) { - soap_server_fault("DataEncodingUnknown","Unknown Data Encoding Style", NULL, NULL, NULL); + soap_server_fault_en("DataEncodingUnknown","Unknown Data Encoding Style", NULL, NULL, NULL); } attr = get_attribute_ex(hdr_func->properties,"role",envelope_ns); if (attr != NULL) { @@ -3336,7 +3363,7 @@ static sdlFunctionPtr deserialize_function_call(sdlPtr sdl, xmlDocPtr request, c strcmp((char*)attr->children->content,"false") == 0) { mustUnderstand = 0; } else { - soap_server_fault("Client","mustUnderstand value is not boolean", NULL, NULL, NULL); + soap_server_fault_en("Client","mustUnderstand value is not boolean", NULL, NULL, NULL); } } h = emalloc(sizeof(soapHeader)); @@ -3565,7 +3592,7 @@ static xmlDocPtr serialize_response_call(sdlFunctionPtr function, const char *fu ns = xmlNewNs(envelope, BAD_CAST(SOAP_1_2_ENV_NAMESPACE), BAD_CAST(SOAP_1_2_ENV_NS_PREFIX)); xmlSetNs(envelope,ns); } else { - soap_server_fault("Server", "Unknown SOAP version", NULL, NULL, NULL); + soap_server_fault_en("Server", "Unknown SOAP version", NULL, NULL, NULL); } xmlDocSetRootElement(doc, envelope); @@ -3734,6 +3761,11 @@ static xmlDocPtr serialize_response_call(sdlFunctionPtr function, const char *fu node = master_to_xml(get_conversion(IS_STRING), tmp, SOAP_LITERAL, node); xmlNodeSetName(node, BAD_CAST("Text")); xmlSetNs(node, ns); + + /* xml:lang attribute is required for in SOAP 1.2 */ + tmp = Z_FAULT_LANG_P(ret); + zend_string *lang = Z_STR_P(tmp); + xmlNodeSetLang(node, BAD_CAST ZSTR_VAL(lang)); } detail_name = SOAP_1_2_ENV_NS_PREFIX":Detail"; } diff --git a/ext/soap/soap.stub.php b/ext/soap/soap.stub.php index 82f884e24b308..2520bd1346963 100644 --- a/ext/soap/soap.stub.php +++ b/ext/soap/soap.stub.php @@ -477,8 +477,9 @@ class SoapFault extends Exception public mixed $detail = null; public ?string $_name = null; public mixed $headerfault = null; + public string $lang = ""; - public function __construct(array|string|null $code, string $string, ?string $actor = null, mixed $details = null, ?string $name = null, mixed $headerFault = null) {} + public function __construct(array|string|null $code, string $string, ?string $actor = null, mixed $details = null, ?string $name = null, mixed $headerFault = null, string $lang = "") {} public function __toString(): string {} } @@ -502,7 +503,7 @@ class SoapServer public function __construct(?string $wsdl, array $options = []) {} /** @tentative-return-type */ - public function fault(string $code, string $string, string $actor = "", mixed $details = null, string $name = ""): void {} + public function fault(string $code, string $string, string $actor = "", mixed $details = null, string $name = "", string $lang = ""): void {} /** @tentative-return-type */ public function addSoapHeader(SoapHeader $header): void {} diff --git a/ext/soap/soap_arginfo.h b/ext/soap/soap_arginfo.h index 9ec093c5c9cd2..e932f2af71093 100644 --- a/ext/soap/soap_arginfo.h +++ b/ext/soap/soap_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 7712aba90b16090fbe7c124c1e3f26b2cc3e2ab2 */ + * Stub hash: 78a27b18c6b4007494a6aed9acc5f6e99c6f0350 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_use_soap_error_handler, 0, 0, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, enable, _IS_BOOL, 0, "true") @@ -29,6 +29,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_SoapFault___construct, 0, 0, 2) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, details, IS_MIXED, 0, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, name, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, headerFault, IS_MIXED, 0, "null") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, lang, IS_STRING, 0, "\"\"") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_SoapFault___toString, 0, 0, IS_STRING, 0) @@ -54,6 +55,7 @@ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_SoapServer_fault ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, actor, IS_STRING, 0, "\"\"") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, details, IS_MIXED, 0, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, name, IS_STRING, 0, "\"\"") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, lang, IS_STRING, 0, "\"\"") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_SoapServer_addSoapHeader, 0, 1, IS_VOID, 0) @@ -444,6 +446,12 @@ static zend_class_entry *register_class_SoapFault(zend_class_entry *class_entry_ zend_declare_typed_property(class_entry, property_headerfault_name, &property_headerfault_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ANY)); zend_string_release(property_headerfault_name); + zval property_lang_default_value; + ZVAL_EMPTY_STRING(&property_lang_default_value); + zend_string *property_lang_name = zend_string_init("lang", sizeof("lang") - 1, 1); + zend_declare_typed_property(class_entry, property_lang_name, &property_lang_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); + zend_string_release(property_lang_name); + return class_entry; } diff --git a/ext/soap/tests/bugs/bug38005.phpt b/ext/soap/tests/bugs/bug38005.phpt index e77278b1b6b64..ca3944ebc3db3 100644 --- a/ext/soap/tests/bugs/bug38005.phpt +++ b/ext/soap/tests/bugs/bug38005.phpt @@ -42,4 +42,4 @@ echo($client->__getLastResponse()); --EXPECT-- This is our fault: � -TestThis is our fault: Ä +TestThis is our fault: Ä diff --git a/ext/soap/tests/bugs/bug68996.phpt b/ext/soap/tests/bugs/bug68996.phpt index 618f5ec730e7e..bcc0e66cbebf9 100644 --- a/ext/soap/tests/bugs/bug68996.phpt +++ b/ext/soap/tests/bugs/bug68996.phpt @@ -56,4 +56,4 @@ handleFormatted($s, $HTTP_RAW_POST_DATA); some msg -some msg +some msg diff --git a/ext/soap/tests/bugs/bug73037.phpt b/ext/soap/tests/bugs/bug73037.phpt index da89382beb2c0..7a5b997767729 100644 --- a/ext/soap/tests/bugs/bug73037.phpt +++ b/ext/soap/tests/bugs/bug73037.phpt @@ -109,12 +109,13 @@ HDRS; $out .= fread($fp, 1024); } - $pos = strpos($out, ""); + $marker = ''; + $pos = strpos($out, $marker); if (false === $pos) { echo $out; goto cleanup; } - $pos0 = $pos + strlen(""); + $pos0 = $pos + strlen($marker); $pos = strpos($out, ""); if (false === $pos) { echo $out; diff --git a/ext/soap/tests/fault_language.phpt b/ext/soap/tests/fault_language.phpt new file mode 100644 index 0000000000000..9cadad2619f03 --- /dev/null +++ b/ext/soap/tests/fault_language.phpt @@ -0,0 +1,29 @@ +--TEST-- +SOAP Server: user fault with language +--EXTENSIONS-- +soap +--FILE-- +fault("MyFault", "My fault string", lang: "custom"); +} + +$server = new SoapServer(null, ['uri' => 'http://testuri.org', 'soap_version' => SOAP_1_2]); +$server->addFunction("test"); + +$HTTP_RAW_POST_DATA = << + + + + + +EOF; + +$server->handle($HTTP_RAW_POST_DATA); +?> +--EXPECT-- + +MyFaultMy fault string diff --git a/ext/soap/tests/soap12/T12.phpt b/ext/soap/tests/soap12/T12.phpt index d3f21ca601446..e659ba0e216dd 100644 --- a/ext/soap/tests/soap12/T12.phpt +++ b/ext/soap/tests/soap12/T12.phpt @@ -20,4 +20,4 @@ include "soap12-test.inc"; ?> --EXPECT-- -env:MustUnderstandHeader not understood +env:MustUnderstandHeader not understood diff --git a/ext/soap/tests/soap12/T13.phpt b/ext/soap/tests/soap12/T13.phpt index 011409b189a46..9a32367164273 100644 --- a/ext/soap/tests/soap12/T13.phpt +++ b/ext/soap/tests/soap12/T13.phpt @@ -20,4 +20,4 @@ include "soap12-test.inc"; ?> --EXPECT-- -env:MustUnderstandHeader not understood +env:MustUnderstandHeader not understood diff --git a/ext/soap/tests/soap12/T14.phpt b/ext/soap/tests/soap12/T14.phpt index 30916455a471d..4ed23550b099b 100644 --- a/ext/soap/tests/soap12/T14.phpt +++ b/ext/soap/tests/soap12/T14.phpt @@ -20,4 +20,4 @@ include "soap12-test.inc"; ?> --EXPECT-- -env:SendermustUnderstand value is not boolean +env:SendermustUnderstand value is not boolean diff --git a/ext/soap/tests/soap12/T23.phpt b/ext/soap/tests/soap12/T23.phpt index 1df101db6aa98..4f7f02893cf89 100644 --- a/ext/soap/tests/soap12/T23.phpt +++ b/ext/soap/tests/soap12/T23.phpt @@ -21,4 +21,4 @@ include "soap12-test.inc"; ?> --EXPECT-- -env:SendermustUnderstand value is not boolean +env:SendermustUnderstand value is not boolean diff --git a/ext/soap/tests/soap12/T24.phpt b/ext/soap/tests/soap12/T24.phpt index a5b304d9843c2..f170b66c704ad 100644 --- a/ext/soap/tests/soap12/T24.phpt +++ b/ext/soap/tests/soap12/T24.phpt @@ -18,4 +18,4 @@ include "soap12-test.inc"; ?> --EXPECT-- -env:VersionMismatchWrong Version +env:VersionMismatchWrong Version diff --git a/ext/soap/tests/soap12/T25.phpt b/ext/soap/tests/soap12/T25.phpt index 1993d6723a35f..f6e9bd8b4867c 100644 --- a/ext/soap/tests/soap12/T25.phpt +++ b/ext/soap/tests/soap12/T25.phpt @@ -19,4 +19,4 @@ include "soap12-test.inc"; ?> --EXPECT-- -env:ReceiverDTD are not supported by SOAP +env:ReceiverDTD are not supported by SOAP diff --git a/ext/soap/tests/soap12/T27.phpt b/ext/soap/tests/soap12/T27.phpt index 097a0f6353072..09591b7faebdd 100644 --- a/ext/soap/tests/soap12/T27.phpt +++ b/ext/soap/tests/soap12/T27.phpt @@ -25,4 +25,4 @@ include "soap12-test.inc"; ?> --EXPECT-- -env:ReceiverSOAP-ERROR: Encoding: Violation of encoding rules +env:ReceiverSOAP-ERROR: Encoding: Violation of encoding rules diff --git a/ext/soap/tests/soap12/T28.phpt b/ext/soap/tests/soap12/T28.phpt index 23deba54acd0a..01a3795e47094 100644 --- a/ext/soap/tests/soap12/T28.phpt +++ b/ext/soap/tests/soap12/T28.phpt @@ -18,4 +18,4 @@ include "soap12-test.inc"; ?> --EXPECT-- -env:SenderencodingStyle cannot be specified on the Body +env:SenderencodingStyle cannot be specified on the Body diff --git a/ext/soap/tests/soap12/T33.phpt b/ext/soap/tests/soap12/T33.phpt index bd9667186a062..eccb85234d1cc 100644 --- a/ext/soap/tests/soap12/T33.phpt +++ b/ext/soap/tests/soap12/T33.phpt @@ -17,4 +17,4 @@ include "soap12-test.inc"; ?> --EXPECT-- -rpc:ProcedureNotPresentProcedure not present +rpc:ProcedureNotPresentProcedure not present diff --git a/ext/soap/tests/soap12/T35.phpt b/ext/soap/tests/soap12/T35.phpt index a2d6436b7b28c..76d72be4372bc 100644 --- a/ext/soap/tests/soap12/T35.phpt +++ b/ext/soap/tests/soap12/T35.phpt @@ -21,4 +21,4 @@ include "soap12-test.inc"; ?> --EXPECT-- -env:MustUnderstandHeader not understood +env:MustUnderstandHeader not understood diff --git a/ext/soap/tests/soap12/T36.phpt b/ext/soap/tests/soap12/T36.phpt index 86501ff740427..44cac71747c61 100644 --- a/ext/soap/tests/soap12/T36.phpt +++ b/ext/soap/tests/soap12/T36.phpt @@ -20,4 +20,4 @@ include "soap12-test.inc"; ?> --EXPECT-- -env:MustUnderstandHeader not understood +env:MustUnderstandHeader not understood diff --git a/ext/soap/tests/soap12/T39.phpt b/ext/soap/tests/soap12/T39.phpt index 735e4882a6f5b..2d46655278aa5 100644 --- a/ext/soap/tests/soap12/T39.phpt +++ b/ext/soap/tests/soap12/T39.phpt @@ -19,4 +19,4 @@ include "soap12-test.inc"; ?> --EXPECT-- -env:SendermustUnderstand value is not boolean +env:SendermustUnderstand value is not boolean diff --git a/ext/soap/tests/soap12/T56.phpt b/ext/soap/tests/soap12/T56.phpt index 7922bf78d1828..8feddb651d42b 100644 --- a/ext/soap/tests/soap12/T56.phpt +++ b/ext/soap/tests/soap12/T56.phpt @@ -30,4 +30,4 @@ include "soap12-test.inc"; ?> --EXPECT-- -env:ReceiverSOAP-ERROR: Encoding: Unresolved reference '#data-2' +env:ReceiverSOAP-ERROR: Encoding: Unresolved reference '#data-2' diff --git a/ext/soap/tests/soap12/T58.phpt b/ext/soap/tests/soap12/T58.phpt index 59a9eba0b6116..69c20a4f8670e 100644 --- a/ext/soap/tests/soap12/T58.phpt +++ b/ext/soap/tests/soap12/T58.phpt @@ -24,4 +24,4 @@ include "soap12-test.inc"; ?> --EXPECT-- -env:ReceiverSOAP-ERROR: Encoding: Violation of encoding rules +env:ReceiverSOAP-ERROR: Encoding: Violation of encoding rules diff --git a/ext/soap/tests/soap12/T59.phpt b/ext/soap/tests/soap12/T59.phpt index 4413301730467..69d597d9f96e7 100644 --- a/ext/soap/tests/soap12/T59.phpt +++ b/ext/soap/tests/soap12/T59.phpt @@ -25,4 +25,4 @@ include "soap12-test.inc"; ?> --EXPECT-- -env:ReceiverSOAP-ERROR: Encoding: Violation of id and ref information items '#data' +env:ReceiverSOAP-ERROR: Encoding: Violation of id and ref information items '#data' diff --git a/ext/soap/tests/soap12/T61.phpt b/ext/soap/tests/soap12/T61.phpt index 79f5c1efff5ad..44fc42d0e09ab 100644 --- a/ext/soap/tests/soap12/T61.phpt +++ b/ext/soap/tests/soap12/T61.phpt @@ -25,4 +25,4 @@ include "soap12-test.inc"; ?> --EXPECT-- -env:ReceiverSOAP-ERROR: Encoding: '*' may only be first arraySize value in list +env:ReceiverSOAP-ERROR: Encoding: '*' may only be first arraySize value in list diff --git a/ext/soap/tests/soap12/T63.phpt b/ext/soap/tests/soap12/T63.phpt index 4706241668de7..a8cf3c431b24b 100644 --- a/ext/soap/tests/soap12/T63.phpt +++ b/ext/soap/tests/soap12/T63.phpt @@ -21,5 +21,5 @@ include "soap12-test.inc"; ?> --EXPECT-- -Country code must be 2 letters.env:SenderNot a valid country code +Country code must be 2 letters.env:SenderNot a valid country code ok diff --git a/ext/soap/tests/soap12/T64.phpt b/ext/soap/tests/soap12/T64.phpt index 8196644e0472d..aea1caab38cd4 100644 --- a/ext/soap/tests/soap12/T64.phpt +++ b/ext/soap/tests/soap12/T64.phpt @@ -21,4 +21,4 @@ include "soap12-test.inc"; ?> --EXPECT-- -env:ReceiverDTD are not supported by SOAP +env:ReceiverDTD are not supported by SOAP diff --git a/ext/soap/tests/soap12/T65.phpt b/ext/soap/tests/soap12/T65.phpt index 0c6f3b953e4f0..9ddd97f5d598a 100644 --- a/ext/soap/tests/soap12/T65.phpt +++ b/ext/soap/tests/soap12/T65.phpt @@ -23,4 +23,4 @@ include "soap12-test.inc"; ?> --EXPECT-- -env:ReceiverDTD are not supported by SOAP +env:ReceiverDTD are not supported by SOAP diff --git a/ext/soap/tests/soap12/T69.phpt b/ext/soap/tests/soap12/T69.phpt index 44097d982e74e..c0aed746618f6 100644 --- a/ext/soap/tests/soap12/T69.phpt +++ b/ext/soap/tests/soap12/T69.phpt @@ -16,4 +16,4 @@ include "soap12-test.inc"; ?> --EXPECT-- -env:SenderBody must be present in a SOAP envelope +env:SenderBody must be present in a SOAP envelope diff --git a/ext/soap/tests/soap12/T70.phpt b/ext/soap/tests/soap12/T70.phpt index 7a9be2d3ecc96..ee36184a4029c 100644 --- a/ext/soap/tests/soap12/T70.phpt +++ b/ext/soap/tests/soap12/T70.phpt @@ -20,4 +20,4 @@ include "soap12-test.inc"; ?> --EXPECT-- -env:SenderA SOAP 1.2 envelope can contain only Header and Body +env:SenderA SOAP 1.2 envelope can contain only Header and Body diff --git a/ext/soap/tests/soap12/T71.phpt b/ext/soap/tests/soap12/T71.phpt index 7bed55473d981..ef0eeb6a8c7aa 100644 --- a/ext/soap/tests/soap12/T71.phpt +++ b/ext/soap/tests/soap12/T71.phpt @@ -21,4 +21,4 @@ include "soap12-test.inc"; ?> --EXPECT-- -env:SenderA SOAP Envelope element cannot have non Namespace qualified attributes +env:SenderA SOAP Envelope element cannot have non Namespace qualified attributes diff --git a/ext/soap/tests/soap12/T72.phpt b/ext/soap/tests/soap12/T72.phpt index 76ae9d57bf1fb..8fc374901a401 100644 --- a/ext/soap/tests/soap12/T72.phpt +++ b/ext/soap/tests/soap12/T72.phpt @@ -19,4 +19,4 @@ include "soap12-test.inc"; ?> --EXPECT-- -env:SenderencodingStyle cannot be specified on the Envelope +env:SenderencodingStyle cannot be specified on the Envelope diff --git a/ext/soap/tests/soap12/T80.phpt b/ext/soap/tests/soap12/T80.phpt index 521c34651b638..c7c03c78e35d0 100644 --- a/ext/soap/tests/soap12/T80.phpt +++ b/ext/soap/tests/soap12/T80.phpt @@ -16,4 +16,4 @@ include "soap12-test.inc"; ?> --EXPECT-- -env:DataEncodingUnknownUnknown Data Encoding Style +env:DataEncodingUnknownUnknown Data Encoding Style From c6b058b7d26d2501c3e8e75f5642f746693d4a7b Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Thu, 19 Jun 2025 22:48:57 +0200 Subject: [PATCH 041/120] Fix memory leaks when returning refcounted value from curl callback Closes GH-18883. --- NEWS | 4 +++ ext/curl/curl_private.h | 3 +++ ext/curl/interface.c | 22 +++++++++++---- ext/curl/multi.c | 2 +- .../refcounted_return_must_not_leak.phpt | 27 +++++++++++++++++++ 5 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 ext/curl/tests/refcounted_return_must_not_leak.phpt diff --git a/NEWS b/NEWS index af154569e2843..1d91c11862ff7 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,10 @@ PHP NEWS . Fixed bug GH-18833 (Use after free with weakmaps dependent on destruction order). (Daniil Gentili) +- Curl: + . Fix memory leaks when returning refcounted value from curl callback. + (nielsdos) + 03 Jul 2025, PHP 8.3.23 - Core: diff --git a/ext/curl/curl_private.h b/ext/curl/curl_private.h index 3800d6533e555..66cba9d562adb 100644 --- a/ext/curl/curl_private.h +++ b/ext/curl/curl_private.h @@ -147,6 +147,9 @@ void _php_curl_multi_cleanup_list(void *data); void _php_curl_verify_handlers(php_curl *ch, bool reporterror); void _php_setup_easy_copy_handlers(php_curl *ch, php_curl *source); +/* Consumes `zv` */ +zend_long php_curl_get_long(zval *zv); + static inline php_curl *curl_from_obj(zend_object *obj) { return (php_curl *)((char *)(obj) - XtOffsetOf(php_curl, std)); } diff --git a/ext/curl/interface.c b/ext/curl/interface.c index 61d830e8abfe1..6c480907b7629 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -623,7 +623,7 @@ static size_t curl_write(char *data, size_t size, size_t nmemb, void *ctx) length = -1; } else if (!Z_ISUNDEF(retval)) { _php_curl_verify_handlers(ch, /* reporterror */ true); - length = zval_get_long(&retval); + length = php_curl_get_long(&retval); } zval_ptr_dtor(&argv[0]); @@ -667,7 +667,7 @@ static int curl_fnmatch(void *ctx, const char *pattern, const char *string) php_error_docref(NULL, E_WARNING, "Cannot call the CURLOPT_FNMATCH_FUNCTION"); } else if (!Z_ISUNDEF(retval)) { _php_curl_verify_handlers(ch, /* reporterror */ true); - rval = zval_get_long(&retval); + rval = php_curl_get_long(&retval); } zval_ptr_dtor(&argv[0]); zval_ptr_dtor(&argv[1]); @@ -715,7 +715,7 @@ static size_t curl_progress(void *clientp, double dltotal, double dlnow, double php_error_docref(NULL, E_WARNING, "Cannot call the CURLOPT_PROGRESSFUNCTION"); } else if (!Z_ISUNDEF(retval)) { _php_curl_verify_handlers(ch, /* reporterror */ true); - if (0 != zval_get_long(&retval)) { + if (0 != php_curl_get_long(&retval)) { rval = 1; } } @@ -764,7 +764,7 @@ static size_t curl_xferinfo(void *clientp, curl_off_t dltotal, curl_off_t dlnow, php_error_docref(NULL, E_WARNING, "Cannot call the CURLOPT_XFERINFOFUNCTION"); } else if (!Z_ISUNDEF(retval)) { _php_curl_verify_handlers(ch, /* reporterror */ true); - if (0 != zval_get_long(&retval)) { + if (0 != php_curl_get_long(&retval)) { rval = 1; } } @@ -821,6 +821,7 @@ static int curl_ssh_hostkeyfunction(void *clientp, int keytype, const char *key, } } else { zend_throw_error(NULL, "The CURLOPT_SSH_HOSTKEYFUNCTION callback must return either CURLKHMATCH_OK or CURLKHMATCH_MISMATCH"); + zval_ptr_dtor(&retval); } } zval_ptr_dtor(&argv[0]); @@ -938,7 +939,7 @@ static size_t curl_write_header(char *data, size_t size, size_t nmemb, void *ctx length = -1; } else if (!Z_ISUNDEF(retval)) { _php_curl_verify_handlers(ch, /* reporterror */ true); - length = zval_get_long(&retval); + length = php_curl_get_long(&retval); } zval_ptr_dtor(&argv[0]); zval_ptr_dtor(&argv[1]); @@ -1290,6 +1291,17 @@ void _php_setup_easy_copy_handlers(php_curl *ch, php_curl *source) (*source->clone)++; } +zend_long php_curl_get_long(zval *zv) +{ + if (EXPECTED(Z_TYPE_P(zv) == IS_LONG)) { + return Z_LVAL_P(zv); + } else { + zend_long ret = zval_get_long(zv); + zval_ptr_dtor(zv); + return ret; + } +} + #if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 */ static size_t read_cb(char *buffer, size_t size, size_t nitems, void *arg) /* {{{ */ { diff --git a/ext/curl/multi.c b/ext/curl/multi.c index be8b26cec9162..09802d7e37d50 100644 --- a/ext/curl/multi.c +++ b/ext/curl/multi.c @@ -430,7 +430,7 @@ static int _php_server_push_callback(CURL *parent_ch, CURL *easy, size_t num_hea if (error == FAILURE) { php_error_docref(NULL, E_WARNING, "Cannot call the CURLMOPT_PUSHFUNCTION"); } else if (!Z_ISUNDEF(retval)) { - if (CURL_PUSH_DENY != zval_get_long(&retval)) { + if (CURL_PUSH_DENY != php_curl_get_long(&retval)) { rval = CURL_PUSH_OK; zend_llist_add_element(&mh->easyh, &pz_ch); } else { diff --git a/ext/curl/tests/refcounted_return_must_not_leak.phpt b/ext/curl/tests/refcounted_return_must_not_leak.phpt new file mode 100644 index 0000000000000..b4b07a1a4fc88 --- /dev/null +++ b/ext/curl/tests/refcounted_return_must_not_leak.phpt @@ -0,0 +1,27 @@ +--TEST-- +Returning refcounted value from callback must not leak +--EXTENSIONS-- +curl +--FILE-- + +--EXPECT-- +ok From 5bd18e3fdc1abdedd5c418095fd8a41f77bae146 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 21 Jun 2025 18:03:50 +0100 Subject: [PATCH 042/120] ext/zlib: Refactor tests (#18887) - Use INI sections - Use CGI sections - Move data into a subfolder - Remove ZPP tests - Fix various bugs within tests - Simplify some Found while working on #18879 --- ext/zlib/tests/002.phpt | 4 +- ext/zlib/tests/003.phpt | 2 +- ext/zlib/tests/bug55544-win.phpt | Bin 564 -> 569 bytes ext/zlib/tests/bug60761.phpt | 7 +- ext/zlib/tests/bug61139.phpt | 2 +- ext/zlib/tests/bug71417.phpt | 2 +- ext/zlib/tests/bug74240.phpt | 4 +- ext/zlib/tests/compress_zlib_wrapper.phpt | 8 +- ext/zlib/tests/{ => data}/data.inc | 0 ext/zlib/tests/{ => data}/func.inc | 0 .../tests/{004.txt.gz => data/test.txt.gz} | Bin .../zlib/tests/data/windows-test.txt.gz | Bin ext/zlib/tests/deflate_init_reuse.phpt | 3 +- ext/zlib/tests/gh16883.phpt | 4 +- ext/zlib/tests/gzclose_basic.phpt | 2 +- ext/zlib/tests/gzcompress_basic1.phpt | 54 ++++----- ext/zlib/tests/gzcompress_error1.phpt | 1 - ext/zlib/tests/gzcompress_variation1.phpt | 2 +- ext/zlib/tests/gzdeflate_basic1.phpt | 54 ++++----- ext/zlib/tests/gzdeflate_variation1.phpt | 4 +- ext/zlib/tests/gzencode_basic1.phpt | 10 +- .../tests/{007.phpt => gzencode_invalid.phpt} | 0 ext/zlib/tests/gzencode_variation1-win32.phpt | 2 +- ext/zlib/tests/gzencode_variation1.phpt | 4 +- ext/zlib/tests/gzencode_variation2-win32.phpt | 6 +- ext/zlib/tests/gzencode_variation2.phpt | 4 - ext/zlib/tests/gzeof_basic.phpt | 2 +- ext/zlib/tests/{004.phpt => gzfile-mb.phpt} | 10 +- ...43\202\214\343\201\276\343\201\231.txt.gz" | Bin ext/zlib/tests/gzfile_basic.phpt | 9 +- ext/zlib/tests/gzfile_basic2.phpt | 9 +- .../{004-mb.phpt => gzfile_open_gz.phpt} | 12 +- ext/zlib/tests/gzfile_variation12.phpt | 104 ------------------ ext/zlib/tests/gzfile_variation4.phpt | 39 ------- ext/zlib/tests/gzfile_variation5.phpt | 35 ------ ext/zlib/tests/gzfile_variation7.phpt | 33 +----- ext/zlib/tests/gzfile_variation9.phpt | 103 ----------------- ext/zlib/tests/gzgetc_basic.phpt | 5 +- ext/zlib/tests/gzgetc_basic_1.phpt | 4 +- ext/zlib/tests/gzgets_basic.phpt | 2 +- ext/zlib/tests/gzinflate_error1.phpt | 2 +- ext/zlib/tests/gzinflate_length.phpt | 4 +- ext/zlib/tests/gzopen_basic.phpt | 2 +- ext/zlib/tests/gzopen_variation7.phpt | 2 +- ext/zlib/tests/gzopen_variation9.phpt | 4 +- ext/zlib/tests/gzpassthru_basic.phpt | 2 +- ext/zlib/tests/gzread_basic.phpt | 2 +- ext/zlib/tests/gzread_error2.phpt | 2 +- ext/zlib/tests/gzrewind_basic.phpt | 2 +- ext/zlib/tests/gzrewind_basic2.phpt | 2 +- ext/zlib/tests/gzseek_basic.phpt | 2 +- ext/zlib/tests/gzseek_variation2.phpt | 2 +- ext/zlib/tests/gzseek_variation3.phpt | 2 +- ext/zlib/tests/gzseek_variation6.phpt | 2 +- ext/zlib/tests/gztell_basic.phpt | 2 +- ext/zlib/tests/gzuncompress_basic1.phpt | 2 +- ext/zlib/tests/gzwrite_variation1.phpt | 2 +- ext/zlib/tests/ob_001.phpt | 4 +- ext/zlib/tests/ob_003.phpt | 4 +- ext/zlib/tests/ob_004.phpt | 4 +- ext/zlib/tests/ob_005.phpt | 5 +- ext/zlib/tests/ob_gzhandler_legacy_002.phpt | 5 +- ext/zlib/tests/readgzfile_variation12.phpt | 52 --------- ext/zlib/tests/readgzfile_variation4.phpt | 39 ------- ext/zlib/tests/readgzfile_variation5.phpt | 35 ------ ext/zlib/tests/readgzfile_variation7.phpt | 34 +----- ext/zlib/tests/readgzfile_variation9.phpt | 51 --------- .../tests/zlib_lock_mandatory_windows.phpt | 8 +- ext/zlib/tests/zlib_scheme_copy_basic.phpt | 2 +- .../tests/zlib_scheme_copy_variation1.phpt | 2 +- ext/zlib/tests/zlib_scheme_file_basic.phpt | 2 +- .../zlib_scheme_file_get_contents_basic.phpt | 2 +- .../zlib_scheme_file_read_file_basic.phpt | 2 +- ext/zlib/tests/zlib_scheme_fopen_basic.phpt | 2 +- .../tests/zlib_scheme_fopen_variation1.phpt | 4 +- ext/zlib/tests/zlib_scheme_rename_basic.phpt | 2 +- ext/zlib/tests/zlib_scheme_stat_basic2.phpt | 8 +- ext/zlib/tests/zlib_scheme_unlink_basic.phpt | 2 +- ext/zlib/tests/zlib_wrapper_flock_basic.phpt | 2 +- ext/zlib/tests/zlib_wrapper_fstat_basic.phpt | 2 +- .../tests/zlib_wrapper_ftruncate_basic.phpt | 2 +- ext/zlib/tests/zlib_wrapper_level.phpt | 2 +- .../tests/zlib_wrapper_meta_data_basic.phpt | 8 +- 83 files changed, 171 insertions(+), 698 deletions(-) rename ext/zlib/tests/{ => data}/data.inc (100%) rename ext/zlib/tests/{ => data}/func.inc (100%) rename ext/zlib/tests/{004.txt.gz => data/test.txt.gz} (100%) rename "ext/zlib/tests/004\347\247\201\343\201\257\343\202\254\343\203\251\343\202\271\343\202\222\351\243\237\343\201\271\343\202\211\343\202\214\343\201\276\343\201\231.txt.gz" => ext/zlib/tests/data/windows-test.txt.gz (100%) rename ext/zlib/tests/{007.phpt => gzencode_invalid.phpt} (100%) rename ext/zlib/tests/{004.phpt => gzfile-mb.phpt} (74%) rename ext/zlib/tests/005.txt.gz => "ext/zlib/tests/gzfile-mb\347\247\201\343\201\257\343\202\254\343\203\251\343\202\271\343\202\222\351\243\237\343\201\271\343\202\211\343\202\214\343\201\276\343\201\231.txt.gz" (100%) rename ext/zlib/tests/{004-mb.phpt => gzfile_open_gz.phpt} (66%) delete mode 100644 ext/zlib/tests/gzfile_variation12.phpt delete mode 100644 ext/zlib/tests/gzfile_variation4.phpt delete mode 100644 ext/zlib/tests/gzfile_variation5.phpt delete mode 100644 ext/zlib/tests/gzfile_variation9.phpt delete mode 100644 ext/zlib/tests/readgzfile_variation12.phpt delete mode 100644 ext/zlib/tests/readgzfile_variation4.phpt delete mode 100644 ext/zlib/tests/readgzfile_variation5.phpt delete mode 100644 ext/zlib/tests/readgzfile_variation9.phpt diff --git a/ext/zlib/tests/002.phpt b/ext/zlib/tests/002.phpt index 83f701e5aaf19..6564cc3f07388 100644 --- a/ext/zlib/tests/002.phpt +++ b/ext/zlib/tests/002.phpt @@ -8,14 +8,14 @@ $original = str_repeat("hallo php",4096); $packed=gzcompress($original); echo strlen($packed)." ".strlen($original)."\n"; $unpacked=gzuncompress($packed); -if (strcmp($original,$unpacked)==0) echo "Strings are equal\n"; +if ($original === $unpacked) echo "Strings are equal\n"; /* with explicit compression level, length */ $original = str_repeat("hallo php",4096); $packed=gzcompress($original, 9); echo strlen($packed)." ".strlen($original)."\n"; $unpacked=gzuncompress($packed, 40000); -if (strcmp($original,$unpacked)==0) echo "Strings are equal\n"; +if ($original === $unpacked) echo "Strings are equal\n"; ?> --EXPECT-- 106 36864 diff --git a/ext/zlib/tests/003.phpt b/ext/zlib/tests/003.phpt index 6fc5a71980ba6..0c731a0dfafba 100644 --- a/ext/zlib/tests/003.phpt +++ b/ext/zlib/tests/003.phpt @@ -7,7 +7,7 @@ zlib $original = str_repeat("hallo php",4096); $packed = gzencode($original); echo strlen($packed)." ".strlen($original). "\n"; -if (strcmp($original, gzdecode($packed)) == 0) echo "Strings are equal"; +if ($original === gzdecode($packed)) echo "Strings are equal\n"; ?> --EXPECT-- 118 36864 diff --git a/ext/zlib/tests/bug55544-win.phpt b/ext/zlib/tests/bug55544-win.phpt index 5c94236a2f21f457485fad58085a468f96ab2e83..11116da28b6d97cbd899cd876e23526963a35fc2 100644 GIT binary patch delta 16 XcmdnOvXf=P5!RH%l0^NDM+z7LI2Hze delta 10 RcmdnVvV~>Bk&Pz{7y%ks1hoJF diff --git a/ext/zlib/tests/bug60761.phpt b/ext/zlib/tests/bug60761.phpt index 735123869432d..16577f869081b 100644 --- a/ext/zlib/tests/bug60761.phpt +++ b/ext/zlib/tests/bug60761.phpt @@ -2,14 +2,13 @@ checks zlib compression output size is always the same --EXTENSIONS-- zlib +--INI-- +zlib.output_compression=4096 +zlib.output_compression_level=9 --CGI-- --FILE-- --CLEAN-- --EXPECTF-- Warning: gzopen(): gzopen failed in %s on line %d diff --git a/ext/zlib/tests/bug71417.phpt b/ext/zlib/tests/bug71417.phpt index 8d871a329e7fe..ee8b30f18e998 100644 --- a/ext/zlib/tests/bug71417.phpt +++ b/ext/zlib/tests/bug71417.phpt @@ -45,7 +45,7 @@ function test($case) { // The gzdecode() function applied to the corrupted compressed data always // detects the error: // --> gzdecode(): PHP Fatal error: Uncaught ErrorException: gzdecode(): data error in ... - echo "gzdecode(): ", rawurldecode(gzdecode($compressed)), "\n"; + echo "gzdecode(): ", rawurldecode((string) gzdecode($compressed)), "\n"; file_put_contents($fn, $compressed); diff --git a/ext/zlib/tests/bug74240.phpt b/ext/zlib/tests/bug74240.phpt index c3dbcc26e369e..f45cd04f71c0e 100644 --- a/ext/zlib/tests/bug74240.phpt +++ b/ext/zlib/tests/bug74240.phpt @@ -2,11 +2,11 @@ Bug #74240 (deflate_add can allocate too much memory) --EXTENSIONS-- zlib +--INI-- +memory_limit=64M --FILE-- ===DONE=== --EXPECT-- +bool(true) ===DONE=== diff --git a/ext/zlib/tests/gh16883.phpt b/ext/zlib/tests/gh16883.phpt index c3d81d4537938..8f22d1662278a 100644 --- a/ext/zlib/tests/gh16883.phpt +++ b/ext/zlib/tests/gh16883.phpt @@ -29,9 +29,9 @@ stream_context_set_default([ $f = gzopen('http://'.PHP_CLI_SERVER_HOSTNAME.':'.PHP_CLI_SERVER_PORT, 'r'); var_dump(stream_get_contents($f)); -var_dump(gzfile('http://'.PHP_CLI_SERVER_HOSTNAME.':'.PHP_CLI_SERVER_PORT, 'r')); +var_dump(gzfile('http://'.PHP_CLI_SERVER_HOSTNAME.':'.PHP_CLI_SERVER_PORT)); -var_dump(readgzfile('http://'.PHP_CLI_SERVER_HOSTNAME.':'.PHP_CLI_SERVER_PORT, 'r')); +var_dump(readgzfile('http://'.PHP_CLI_SERVER_HOSTNAME.':'.PHP_CLI_SERVER_PORT)); ?> --EXPECT-- diff --git a/ext/zlib/tests/gzclose_basic.phpt b/ext/zlib/tests/gzclose_basic.phpt index c1d6edf4d95e1..f2e03a579de5e 100644 --- a/ext/zlib/tests/gzclose_basic.phpt +++ b/ext/zlib/tests/gzclose_basic.phpt @@ -7,7 +7,7 @@ zlib // note that gzclose is an alias to fclose. parameter checking tests will be // the same as fclose -$f = __DIR__."/004.txt.gz"; +$f = __DIR__."/data/test.txt.gz"; $h = gzopen($f, 'r'); gzread($h, 20); var_dump(gzclose($h)); diff --git a/ext/zlib/tests/gzcompress_basic1.phpt b/ext/zlib/tests/gzcompress_basic1.phpt index 8899deaed0f72..606da46e5c873 100644 --- a/ext/zlib/tests/gzcompress_basic1.phpt +++ b/ext/zlib/tests/gzcompress_basic1.phpt @@ -8,7 +8,7 @@ zlib * add a comment here to say what the test is supposed to do */ -include(__DIR__ . '/data.inc'); +include(__DIR__ . '/data/data.inc'); echo "*** Testing gzcompress() : basic functionality ***\n"; @@ -23,68 +23,68 @@ $smallstring = "A small string to compress\n"; for($i = -1; $i < 10; $i++) { echo "-- Compression level $i --\n"; $output = gzcompress($data, $i); - var_dump(strcmp(gzuncompress($output), $data)); + var_dump(gzuncompress($output) === $data); } // Compressing a smaller string for($i = -1; $i < 10; $i++) { echo "-- Compression level $i --\n"; $output = gzcompress($smallstring, $i); - var_dump(strcmp(gzuncompress($output), $smallstring)); + var_dump(gzuncompress($output) === $smallstring); } // Calling gzcompress() with mandatory arguments echo "\n-- Testing with no specified compression level --\n"; $output = gzcompress($smallstring); - var_dump(strcmp(gzuncompress($output), $smallstring)); +var_dump(gzuncompress($output) === $smallstring); ?> --EXPECT-- *** Testing gzcompress() : basic functionality *** -- Compression level -1 -- -int(0) +bool(true) -- Compression level 0 -- -int(0) +bool(true) -- Compression level 1 -- -int(0) +bool(true) -- Compression level 2 -- -int(0) +bool(true) -- Compression level 3 -- -int(0) +bool(true) -- Compression level 4 -- -int(0) +bool(true) -- Compression level 5 -- -int(0) +bool(true) -- Compression level 6 -- -int(0) +bool(true) -- Compression level 7 -- -int(0) +bool(true) -- Compression level 8 -- -int(0) +bool(true) -- Compression level 9 -- -int(0) +bool(true) -- Compression level -1 -- -int(0) +bool(true) -- Compression level 0 -- -int(0) +bool(true) -- Compression level 1 -- -int(0) +bool(true) -- Compression level 2 -- -int(0) +bool(true) -- Compression level 3 -- -int(0) +bool(true) -- Compression level 4 -- -int(0) +bool(true) -- Compression level 5 -- -int(0) +bool(true) -- Compression level 6 -- -int(0) +bool(true) -- Compression level 7 -- -int(0) +bool(true) -- Compression level 8 -- -int(0) +bool(true) -- Compression level 9 -- -int(0) +bool(true) -- Testing with no specified compression level -- -int(0) +bool(true) diff --git a/ext/zlib/tests/gzcompress_error1.phpt b/ext/zlib/tests/gzcompress_error1.phpt index a34ceaf7248fd..b21743755417f 100644 --- a/ext/zlib/tests/gzcompress_error1.phpt +++ b/ext/zlib/tests/gzcompress_error1.phpt @@ -20,7 +20,6 @@ try { } echo "\n-- Testing with invalid encoding --\n"; -$data = 'string_val'; $level = 2; $encoding = 99; try { diff --git a/ext/zlib/tests/gzcompress_variation1.phpt b/ext/zlib/tests/gzcompress_variation1.phpt index 81dafa737c305..032a77a1a55ab 100644 --- a/ext/zlib/tests/gzcompress_variation1.phpt +++ b/ext/zlib/tests/gzcompress_variation1.phpt @@ -4,7 +4,7 @@ Test gzcompress() function : variation zlib --FILE-- --EXPECT-- *** Testing gzdeflate() : basic functionality *** -- Compression level -1 -- -int(0) +bool(true) -- Compression level 0 -- -int(0) +bool(true) -- Compression level 1 -- -int(0) +bool(true) -- Compression level 2 -- -int(0) +bool(true) -- Compression level 3 -- -int(0) +bool(true) -- Compression level 4 -- -int(0) +bool(true) -- Compression level 5 -- -int(0) +bool(true) -- Compression level 6 -- -int(0) +bool(true) -- Compression level 7 -- -int(0) +bool(true) -- Compression level 8 -- -int(0) +bool(true) -- Compression level 9 -- -int(0) +bool(true) -- Compression level -1 -- -int(0) +bool(true) -- Compression level 0 -- -int(0) +bool(true) -- Compression level 1 -- -int(0) +bool(true) -- Compression level 2 -- -int(0) +bool(true) -- Compression level 3 -- -int(0) +bool(true) -- Compression level 4 -- -int(0) +bool(true) -- Compression level 5 -- -int(0) +bool(true) -- Compression level 6 -- -int(0) +bool(true) -- Compression level 7 -- -int(0) +bool(true) -- Compression level 8 -- -int(0) +bool(true) -- Compression level 9 -- -int(0) +bool(true) -- Testing with no specified compression level -- -int(0) +bool(true) diff --git a/ext/zlib/tests/gzdeflate_variation1.phpt b/ext/zlib/tests/gzdeflate_variation1.phpt index 21456a9887659..b2d98ce978d04 100644 --- a/ext/zlib/tests/gzdeflate_variation1.phpt +++ b/ext/zlib/tests/gzdeflate_variation1.phpt @@ -4,12 +4,10 @@ Test gzdeflate() function : variation zlib --FILE-- --EXPECTF-- *** Testing gzencode() : basic functionality *** diff --git a/ext/zlib/tests/007.phpt b/ext/zlib/tests/gzencode_invalid.phpt similarity index 100% rename from ext/zlib/tests/007.phpt rename to ext/zlib/tests/gzencode_invalid.phpt diff --git a/ext/zlib/tests/gzencode_variation1-win32.phpt b/ext/zlib/tests/gzencode_variation1-win32.phpt index 31329bb5ea9cc..c6d261567c90e 100644 --- a/ext/zlib/tests/gzencode_variation1-win32.phpt +++ b/ext/zlib/tests/gzencode_variation1-win32.phpt @@ -11,7 +11,7 @@ if (substr(PHP_OS, 0, 3) != "WIN") { --FILE-- --FILE-- ---EXPECTF-- -Warning: gzfile(nonexistent_file_gzfile): Failed to open stream: No such file or directory in %s on line %d -bool(false) +--EXPECT-- array(6) { [0]=> string(36) "When you're taught through feelings diff --git a/ext/zlib/tests/005.txt.gz "b/ext/zlib/tests/gzfile-mb\347\247\201\343\201\257\343\202\254\343\203\251\343\202\271\343\202\222\351\243\237\343\201\271\343\202\211\343\202\214\343\201\276\343\201\231.txt.gz" similarity index 100% rename from ext/zlib/tests/005.txt.gz rename to "ext/zlib/tests/gzfile-mb\347\247\201\343\201\257\343\202\254\343\203\251\343\202\271\343\202\222\351\243\237\343\201\271\343\202\211\343\202\214\343\201\276\343\201\231.txt.gz" diff --git a/ext/zlib/tests/gzfile_basic.phpt b/ext/zlib/tests/gzfile_basic.phpt index 26cde7397cea1..a993893c1dc6c 100644 --- a/ext/zlib/tests/gzfile_basic.phpt +++ b/ext/zlib/tests/gzfile_basic.phpt @@ -19,8 +19,13 @@ gzclose($h); var_dump(gzfile( $filename ) ); -unlink($filename); -rmdir($dirname); +?> +--CLEAN-- + --EXPECT-- array(3) { diff --git a/ext/zlib/tests/gzfile_basic2.phpt b/ext/zlib/tests/gzfile_basic2.phpt index 2b59656a6f314..b098692620a26 100644 --- a/ext/zlib/tests/gzfile_basic2.phpt +++ b/ext/zlib/tests/gzfile_basic2.phpt @@ -19,8 +19,13 @@ fclose($h); var_dump(gzfile( $filename ) ); -unlink($filename); -rmdir($dirname); +?> +--CLEAN-- + --EXPECT-- array(3) { diff --git a/ext/zlib/tests/004-mb.phpt b/ext/zlib/tests/gzfile_open_gz.phpt similarity index 66% rename from ext/zlib/tests/004-mb.phpt rename to ext/zlib/tests/gzfile_open_gz.phpt index 9cf6dd628c6a1..7614a3ddcac1c 100644 --- a/ext/zlib/tests/004-mb.phpt +++ b/ext/zlib/tests/gzfile_open_gz.phpt @@ -1,20 +1,16 @@ --TEST-- -gzfile() with various invalid params +gzfile() with a proper gz file --EXTENSIONS-- zlib --FILE-- ---EXPECTF-- -Warning: gzfile(nonexistent_file_gzfile): Failed to open stream: No such file or directory in %s on line %d -bool(false) +--EXPECT-- array(6) { [0]=> string(36) "When you're taught through feelings diff --git a/ext/zlib/tests/gzfile_variation12.phpt b/ext/zlib/tests/gzfile_variation12.phpt deleted file mode 100644 index 6985442d6e583..0000000000000 --- a/ext/zlib/tests/gzfile_variation12.phpt +++ /dev/null @@ -1,104 +0,0 @@ ---TEST-- -Test function gzfile() by substituting argument 2 with int values. ---EXTENSIONS-- -zlib ---FILE-- - 0, - 'int 1' => 1, - 'int 12345' => 12345, - 'int -12345' => -2345, - ); - - -foreach ( $variation as $var ) { - var_dump(gzfile( $filename, $var ) ); -} -?> ---EXPECT-- -array(6) { - [0]=> - string(36) "When you're taught through feelings -" - [1]=> - string(26) "Destiny flying high above -" - [2]=> - string(38) "all I know is that you can realize it -" - [3]=> - string(18) "Destiny who cares -" - [4]=> - string(19) "as it turns around -" - [5]=> - string(39) "and I know that it descends down on me -" -} -array(6) { - [0]=> - string(36) "When you're taught through feelings -" - [1]=> - string(26) "Destiny flying high above -" - [2]=> - string(38) "all I know is that you can realize it -" - [3]=> - string(18) "Destiny who cares -" - [4]=> - string(19) "as it turns around -" - [5]=> - string(39) "and I know that it descends down on me -" -} -array(6) { - [0]=> - string(36) "When you're taught through feelings -" - [1]=> - string(26) "Destiny flying high above -" - [2]=> - string(38) "all I know is that you can realize it -" - [3]=> - string(18) "Destiny who cares -" - [4]=> - string(19) "as it turns around -" - [5]=> - string(39) "and I know that it descends down on me -" -} -array(6) { - [0]=> - string(36) "When you're taught through feelings -" - [1]=> - string(26) "Destiny flying high above -" - [2]=> - string(38) "all I know is that you can realize it -" - [3]=> - string(18) "Destiny who cares -" - [4]=> - string(19) "as it turns around -" - [5]=> - string(39) "and I know that it descends down on me -" -} diff --git a/ext/zlib/tests/gzfile_variation4.phpt b/ext/zlib/tests/gzfile_variation4.phpt deleted file mode 100644 index 86d84899b86e9..0000000000000 --- a/ext/zlib/tests/gzfile_variation4.phpt +++ /dev/null @@ -1,39 +0,0 @@ ---TEST-- -Test function gzfile() by substituting argument 1 with float values. ---EXTENSIONS-- -zlib ---FILE-- - 10.5, - 'float -10.5' => -10.5, - 'float 12.3456789000e10' => 12.3456789000e10, - 'float -12.3456789000e10' => -12.3456789000e10, - 'float .5' => .5, - ); - - -foreach ( $variation as $var ) { - var_dump(gzfile( $var , $use_include_path ) ); -} -?> ---EXPECTF-- -Warning: gzfile(10.5): Failed to open stream: No such file or directory in %s on line %d -bool(false) - -Warning: gzfile(-10.5): Failed to open stream: No such file or directory in %s on line %d -bool(false) - -Warning: gzfile(123456789000): Failed to open stream: No such file or directory in %s on line %d -bool(false) - -Warning: gzfile(-123456789000): Failed to open stream: No such file or directory in %s on line %d -bool(false) - -Warning: gzfile(0.5): Failed to open stream: No such file or directory in %s on line %d -bool(false) diff --git a/ext/zlib/tests/gzfile_variation5.phpt b/ext/zlib/tests/gzfile_variation5.phpt deleted file mode 100644 index 75751ea12cc77..0000000000000 --- a/ext/zlib/tests/gzfile_variation5.phpt +++ /dev/null @@ -1,35 +0,0 @@ ---TEST-- -Test function gzfile() by substituting argument 1 with int values. ---EXTENSIONS-- -zlib ---FILE-- - 0, - 'int 1' => 1, - 'int 12345' => 12345, - 'int -12345' => -2345, - ); - - -foreach ( $variation as $var ) { - var_dump(gzfile( $var , $use_include_path ) ); -} -?> ---EXPECTF-- -Warning: gzfile(0): Failed to open stream: No such file or directory in %s on line %d -bool(false) - -Warning: gzfile(1): Failed to open stream: No such file or directory in %s on line %d -bool(false) - -Warning: gzfile(12345): Failed to open stream: No such file or directory in %s on line %d -bool(false) - -Warning: gzfile(-2345): Failed to open stream: No such file or directory in %s on line %d -bool(false) diff --git a/ext/zlib/tests/gzfile_variation7.phpt b/ext/zlib/tests/gzfile_variation7.phpt index 834f8937e823f..ca221c12cff3f 100644 --- a/ext/zlib/tests/gzfile_variation7.phpt +++ b/ext/zlib/tests/gzfile_variation7.phpt @@ -1,39 +1,18 @@ --TEST-- -Test function gzfile() by substituting argument 1 with string values. +gzfile() with unknown file --EXTENSIONS-- zlib --FILE-- "string", - 'string SQ' => 'string', - 'mixed case string' => "sTrInG", - 'heredoc' => $heredoc - ); - - -foreach ( $variation_array as $var ) { - var_dump(gzfile( $var , $use_include_path ) ); -} +var_dump(gzfile($filename, false)); +var_dump(gzfile($filename, true)); ?> --EXPECTF-- -Warning: gzfile(string): Failed to open stream: No such file or directory in %s on line %d -bool(false) - -Warning: gzfile(string): Failed to open stream: No such file or directory in %s on line %d -bool(false) - -Warning: gzfile(sTrInG): Failed to open stream: No such file or directory in %s on line %d +Warning: gzfile(nonexistent_file_gzfile.txt.gz): Failed to open stream: No such file or directory in %s on line %d bool(false) -Warning: gzfile(hello world): Failed to open stream: No such file or directory in %s on line %d +Warning: gzfile(nonexistent_file_gzfile.txt.gz): Failed to open stream: No such file or directory in %s on line %d bool(false) diff --git a/ext/zlib/tests/gzfile_variation9.phpt b/ext/zlib/tests/gzfile_variation9.phpt deleted file mode 100644 index f2919d79be5c1..0000000000000 --- a/ext/zlib/tests/gzfile_variation9.phpt +++ /dev/null @@ -1,103 +0,0 @@ ---TEST-- -Test function gzfile() by substituting argument 2 with boolean values. ---EXTENSIONS-- -zlib ---FILE-- - true, - 'lowercase false' =>false, - 'uppercase TRUE' =>TRUE, - 'uppercase FALSE' =>FALSE, - ); - - -foreach ( $variation as $var ) { - var_dump(gzfile( $filename, $var ) ); -} -?> ---EXPECT-- -array(6) { - [0]=> - string(36) "When you're taught through feelings -" - [1]=> - string(26) "Destiny flying high above -" - [2]=> - string(38) "all I know is that you can realize it -" - [3]=> - string(18) "Destiny who cares -" - [4]=> - string(19) "as it turns around -" - [5]=> - string(39) "and I know that it descends down on me -" -} -array(6) { - [0]=> - string(36) "When you're taught through feelings -" - [1]=> - string(26) "Destiny flying high above -" - [2]=> - string(38) "all I know is that you can realize it -" - [3]=> - string(18) "Destiny who cares -" - [4]=> - string(19) "as it turns around -" - [5]=> - string(39) "and I know that it descends down on me -" -} -array(6) { - [0]=> - string(36) "When you're taught through feelings -" - [1]=> - string(26) "Destiny flying high above -" - [2]=> - string(38) "all I know is that you can realize it -" - [3]=> - string(18) "Destiny who cares -" - [4]=> - string(19) "as it turns around -" - [5]=> - string(39) "and I know that it descends down on me -" -} -array(6) { - [0]=> - string(36) "When you're taught through feelings -" - [1]=> - string(26) "Destiny flying high above -" - [2]=> - string(38) "all I know is that you can realize it -" - [3]=> - string(18) "Destiny who cares -" - [4]=> - string(19) "as it turns around -" - [5]=> - string(39) "and I know that it descends down on me -" -} diff --git a/ext/zlib/tests/gzgetc_basic.phpt b/ext/zlib/tests/gzgetc_basic.phpt index 7164c23098d92..ce366e4b6b31a 100644 --- a/ext/zlib/tests/gzgetc_basic.phpt +++ b/ext/zlib/tests/gzgetc_basic.phpt @@ -4,8 +4,7 @@ Test function gzgetc() by calling it with its expected arguments zlib 1.2.5 zlib --SKIPIF-- 0) { die('skip - only for zlib <= 1.2.5'); } @@ -16,7 +15,7 @@ if (version_compare(get_zlib_version(), '1.2.5') > 0) { // note that gzgets is an alias to fgets. parameter checking tests will be // the same as gzgets -$f = __DIR__."/004.txt.gz"; +$f = __DIR__."/data/test.txt.gz"; $h = gzopen($f, 'r'); $count = 0; diff --git a/ext/zlib/tests/gzgetc_basic_1.phpt b/ext/zlib/tests/gzgetc_basic_1.phpt index e70c5814fcbc8..cf6da96e5612f 100644 --- a/ext/zlib/tests/gzgetc_basic_1.phpt +++ b/ext/zlib/tests/gzgetc_basic_1.phpt @@ -5,7 +5,7 @@ zlib --SKIPIF-- = 1.2.7'); } @@ -16,7 +16,7 @@ if (version_compare(get_zlib_version(), '1.2.7') < 0) { // note that gzgets is an alias to fgets. parameter checking tests will be // the same as gzgets -$f = __DIR__."/004.txt.gz"; +$f = __DIR__."/data/test.txt.gz"; $h = gzopen($f, 'r'); if ($h) { $count = 0; diff --git a/ext/zlib/tests/gzgets_basic.phpt b/ext/zlib/tests/gzgets_basic.phpt index f43b3ad5342c3..a971d5e3a620c 100644 --- a/ext/zlib/tests/gzgets_basic.phpt +++ b/ext/zlib/tests/gzgets_basic.phpt @@ -8,7 +8,7 @@ zlib // note that gzgets is an alias to fgets. parameter checking tests will be // the same as fgets -$f = __DIR__."/004.txt.gz"; +$f = __DIR__."/data/test.txt.gz"; $h = gzopen($f, 'r'); $lengths = array(10, 14, 7, 99); foreach ($lengths as $length) { diff --git a/ext/zlib/tests/gzinflate_error1.phpt b/ext/zlib/tests/gzinflate_error1.phpt index 8d4abdf529b02..4d02c2604e30e 100644 --- a/ext/zlib/tests/gzinflate_error1.phpt +++ b/ext/zlib/tests/gzinflate_error1.phpt @@ -4,7 +4,7 @@ Test gzinflate() function : error conditions zlib --FILE-- +--CGI-- --GET-- a=b --INI-- diff --git a/ext/zlib/tests/ob_003.phpt b/ext/zlib/tests/ob_003.phpt index 647a120627044..70bd209f3824c 100644 --- a/ext/zlib/tests/ob_003.phpt +++ b/ext/zlib/tests/ob_003.phpt @@ -3,9 +3,7 @@ zlib.output_compression --EXTENSIONS-- zlib --SKIPIF-- - +--CGI-- --INI-- zlib.output_compression=0 --ENV-- diff --git a/ext/zlib/tests/ob_004.phpt b/ext/zlib/tests/ob_004.phpt index ac4ec2d862db1..dc48c39aa1f20 100644 --- a/ext/zlib/tests/ob_004.phpt +++ b/ext/zlib/tests/ob_004.phpt @@ -3,9 +3,7 @@ ob_gzhandler --EXTENSIONS-- zlib --SKIPIF-- - +--CGI-- --INI-- zlib.output_compression=0 --ENV-- diff --git a/ext/zlib/tests/ob_005.phpt b/ext/zlib/tests/ob_005.phpt index aaa9856dbaab7..343d548161808 100644 --- a/ext/zlib/tests/ob_005.phpt +++ b/ext/zlib/tests/ob_005.phpt @@ -2,10 +2,7 @@ ob_gzhandler --EXTENSIONS-- zlib ---SKIPIF-- - +--CGI- --INI-- zlib.output_compression=0 --ENV-- diff --git a/ext/zlib/tests/ob_gzhandler_legacy_002.phpt b/ext/zlib/tests/ob_gzhandler_legacy_002.phpt index 6789ba2d53f90..41cdda1f8d671 100644 --- a/ext/zlib/tests/ob_gzhandler_legacy_002.phpt +++ b/ext/zlib/tests/ob_gzhandler_legacy_002.phpt @@ -2,10 +2,7 @@ ob_gzhandler legacy --EXTENSIONS-- zlib ---SKIPIF-- - +--CGI-- --INI-- zlib.output_compression=0 --ENV-- diff --git a/ext/zlib/tests/readgzfile_variation12.phpt b/ext/zlib/tests/readgzfile_variation12.phpt deleted file mode 100644 index 02c18fc41f8d1..0000000000000 --- a/ext/zlib/tests/readgzfile_variation12.phpt +++ /dev/null @@ -1,52 +0,0 @@ ---TEST-- -Test function readgzfile() by substituting argument 2 with int values. ---EXTENSIONS-- -zlib ---FILE-- - 0, - 'int 1' => 1, - 'int 12345' => 12345, - 'int -12345' => -2345, - ); - - -foreach ( $variation as $var ) { - var_dump(readgzfile( $filename, $var ) ); -} -?> ---EXPECT-- -When you're taught through feelings -Destiny flying high above -all I know is that you can realize it -Destiny who cares -as it turns around -and I know that it descends down on me -int(176) -When you're taught through feelings -Destiny flying high above -all I know is that you can realize it -Destiny who cares -as it turns around -and I know that it descends down on me -int(176) -When you're taught through feelings -Destiny flying high above -all I know is that you can realize it -Destiny who cares -as it turns around -and I know that it descends down on me -int(176) -When you're taught through feelings -Destiny flying high above -all I know is that you can realize it -Destiny who cares -as it turns around -and I know that it descends down on me -int(176) diff --git a/ext/zlib/tests/readgzfile_variation4.phpt b/ext/zlib/tests/readgzfile_variation4.phpt deleted file mode 100644 index 85854b024fc56..0000000000000 --- a/ext/zlib/tests/readgzfile_variation4.phpt +++ /dev/null @@ -1,39 +0,0 @@ ---TEST-- -Test function readgzfile() by substituting argument 1 with float values. ---EXTENSIONS-- -zlib ---FILE-- - 10.5, - 'float -10.5' => -10.5, - 'float 12.3456789000e10' => 12.3456789000e10, - 'float -12.3456789000e10' => -12.3456789000e10, - 'float .5' => .5, - ); - - -foreach ( $variation as $var ) { - var_dump(readgzfile( $var , $use_include_path ) ); -} -?> ---EXPECTF-- -Warning: readgzfile(10.5): Failed to open stream: No such file or directory in %s on line %d -bool(false) - -Warning: readgzfile(-10.5): Failed to open stream: No such file or directory in %s on line %d -bool(false) - -Warning: readgzfile(123456789000): Failed to open stream: No such file or directory in %s on line %d -bool(false) - -Warning: readgzfile(-123456789000): Failed to open stream: No such file or directory in %s on line %d -bool(false) - -Warning: readgzfile(0.5): Failed to open stream: No such file or directory in %s on line %d -bool(false) diff --git a/ext/zlib/tests/readgzfile_variation5.phpt b/ext/zlib/tests/readgzfile_variation5.phpt deleted file mode 100644 index 039812ba2e813..0000000000000 --- a/ext/zlib/tests/readgzfile_variation5.phpt +++ /dev/null @@ -1,35 +0,0 @@ ---TEST-- -Test function readgzfile() by substituting argument 1 with int values. ---EXTENSIONS-- -zlib ---FILE-- - 0, - 'int 1' => 1, - 'int 12345' => 12345, - 'int -12345' => -2345, - ); - - -foreach ( $variation as $var ) { - var_dump(readgzfile( $var , $use_include_path ) ); -} -?> ---EXPECTF-- -Warning: readgzfile(0): Failed to open stream: No such file or directory in %s on line %d -bool(false) - -Warning: readgzfile(1): Failed to open stream: No such file or directory in %s on line %d -bool(false) - -Warning: readgzfile(12345): Failed to open stream: No such file or directory in %s on line %d -bool(false) - -Warning: readgzfile(-2345): Failed to open stream: No such file or directory in %s on line %d -bool(false) diff --git a/ext/zlib/tests/readgzfile_variation7.phpt b/ext/zlib/tests/readgzfile_variation7.phpt index 0d357c6774b69..6f201abe2361b 100644 --- a/ext/zlib/tests/readgzfile_variation7.phpt +++ b/ext/zlib/tests/readgzfile_variation7.phpt @@ -1,39 +1,17 @@ --TEST-- -Test function readgzfile() by substituting argument 1 with string values. +readgzfile() with unknown file --EXTENSIONS-- zlib --FILE-- "string", - 'string SQ' => 'string', - 'mixed case string' => "sTrInG", - 'heredoc' => $heredoc - ); - - -foreach ( $variation_array as $var ) { - var_dump(readgzfile( $var , $use_include_path ) ); -} +$file = "unknown_file.txt.gz"; +var_dump(readgzfile($file, false)); +var_dump(readgzfile($file, true)); ?> --EXPECTF-- -Warning: readgzfile(string): Failed to open stream: No such file or directory in %s on line %d -bool(false) - -Warning: readgzfile(string): Failed to open stream: No such file or directory in %s on line %d -bool(false) - -Warning: readgzfile(sTrInG): Failed to open stream: No such file or directory in %s on line %d +Warning: readgzfile(unknown_file.txt.gz): Failed to open stream: No such file or directory in %s on line %d bool(false) -Warning: readgzfile(hello world): Failed to open stream: No such file or directory in %s on line %d +Warning: readgzfile(unknown_file.txt.gz): Failed to open stream: No such file or directory in %s on line %d bool(false) diff --git a/ext/zlib/tests/readgzfile_variation9.phpt b/ext/zlib/tests/readgzfile_variation9.phpt deleted file mode 100644 index 011ded054b780..0000000000000 --- a/ext/zlib/tests/readgzfile_variation9.phpt +++ /dev/null @@ -1,51 +0,0 @@ ---TEST-- -Test function readgzfile() by substituting argument 2 with boolean values. ---EXTENSIONS-- -zlib ---FILE-- - true, - 'lowercase false' =>false, - 'uppercase TRUE' =>TRUE, - 'uppercase FALSE' =>FALSE, - ); - - -foreach ( $variation as $var ) { - var_dump(readgzfile( $filename, $var ) ); -} -?> ---EXPECT-- -When you're taught through feelings -Destiny flying high above -all I know is that you can realize it -Destiny who cares -as it turns around -and I know that it descends down on me -int(176) -When you're taught through feelings -Destiny flying high above -all I know is that you can realize it -Destiny who cares -as it turns around -and I know that it descends down on me -int(176) -When you're taught through feelings -Destiny flying high above -all I know is that you can realize it -Destiny who cares -as it turns around -and I know that it descends down on me -int(176) -When you're taught through feelings -Destiny flying high above -all I know is that you can realize it -Destiny who cares -as it turns around -and I know that it descends down on me -int(176) diff --git a/ext/zlib/tests/zlib_lock_mandatory_windows.phpt b/ext/zlib/tests/zlib_lock_mandatory_windows.phpt index 04ed2ab251056..4cb8df4f2ad0f 100644 --- a/ext/zlib/tests/zlib_lock_mandatory_windows.phpt +++ b/ext/zlib/tests/zlib_lock_mandatory_windows.phpt @@ -10,7 +10,7 @@ if (PHP_OS_FAMILY !== "Windows") die("skip Only for Windows because it has manda diff --git a/ext/zlib/tests/zlib_scheme_fopen_basic.phpt b/ext/zlib/tests/zlib_scheme_fopen_basic.phpt index 9d366670f1ca8..fbac2f82ae637 100644 --- a/ext/zlib/tests/zlib_scheme_fopen_basic.phpt +++ b/ext/zlib/tests/zlib_scheme_fopen_basic.phpt @@ -4,7 +4,7 @@ Test compress.zlib:// scheme with the fopen zlib --FILE-- --EXPECTF-- -file=compress.zlib://file://%s/004.txt.gz +file=compress.zlib://file://%s/test.txt.gz When you're taught through feelings Destiny flying high above diff --git a/ext/zlib/tests/zlib_scheme_rename_basic.phpt b/ext/zlib/tests/zlib_scheme_rename_basic.phpt index be9df167220a5..506ac9cb92367 100644 --- a/ext/zlib/tests/zlib_scheme_rename_basic.phpt +++ b/ext/zlib/tests/zlib_scheme_rename_basic.phpt @@ -4,7 +4,7 @@ Test compress.zlib:// scheme with the unlink function zlib --FILE-- --FILE-- bool(true) ["uri"]=> - string(%d) "compress.zlib://%s/004.txt.gz" + string(%d) "compress.zlib://%s/test.txt.gz" } From a36b8fdc9423b015de005f724392e34a1cb21a62 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Thu, 5 Jun 2025 19:30:37 +0200 Subject: [PATCH 043/120] Fix GH-13264: fgets() and stream_get_line() do not return false on filter fatal error This happens because there are no checks in php_stream_fill_read_buffer calls. This should not fail always but only on fatal error so special flag is needed for that. Closes GH-18778 --- NEWS | 4 ++ ext/sqlite3/sqlite3.c | 4 ++ ext/standard/tests/filters/gh13264.phpt | 72 ++++++++++++++----------- main/php_streams.h | 3 ++ main/streams/memory.c | 5 ++ main/streams/streams.c | 16 +++++- 6 files changed, 70 insertions(+), 34 deletions(-) diff --git a/NEWS b/NEWS index 1d91c11862ff7..9881c36d4b012 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,10 @@ PHP NEWS . Fix memory leaks when returning refcounted value from curl callback. (nielsdos) +- Streams: + . Fixed GH-13264 (fgets() and stream_get_line() do not return false on filter + fatal error). (Jakub Zelenka) + 03 Jul 2025, PHP 8.3.23 - Core: diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c index 09cb57410c87f..9b3286b70220d 100644 --- a/ext/sqlite3/sqlite3.c +++ b/ext/sqlite3/sqlite3.c @@ -1165,6 +1165,7 @@ static int php_sqlite3_stream_seek(php_stream *stream, zend_off_t offset, int wh sqlite3_stream->position = sqlite3_stream->position + offset; *newoffs = sqlite3_stream->position; stream->eof = 0; + stream->fatal_error = 0; return 0; } } else { @@ -1176,6 +1177,7 @@ static int php_sqlite3_stream_seek(php_stream *stream, zend_off_t offset, int wh sqlite3_stream->position = sqlite3_stream->position + offset; *newoffs = sqlite3_stream->position; stream->eof = 0; + stream->fatal_error = 0; return 0; } } @@ -1188,6 +1190,7 @@ static int php_sqlite3_stream_seek(php_stream *stream, zend_off_t offset, int wh sqlite3_stream->position = offset; *newoffs = sqlite3_stream->position; stream->eof = 0; + stream->fatal_error = 0; return 0; } case SEEK_END: @@ -1203,6 +1206,7 @@ static int php_sqlite3_stream_seek(php_stream *stream, zend_off_t offset, int wh sqlite3_stream->position = sqlite3_stream->size + offset; *newoffs = sqlite3_stream->position; stream->eof = 0; + stream->fatal_error = 0; return 0; } default: diff --git a/ext/standard/tests/filters/gh13264.phpt b/ext/standard/tests/filters/gh13264.phpt index e992d0868898d..f778bbf915a7b 100644 --- a/ext/standard/tests/filters/gh13264.phpt +++ b/ext/standard/tests/filters/gh13264.phpt @@ -1,49 +1,57 @@ --TEST-- -GH-81475: Memory leak during stream filter failure +GH-13264: fgets() and stream_get_line() do not return false on filter fatal error --SKIPIF-- --FILE-- 15]); -// Rewind and add the zlib filter -rewind($stream); -stream_filter_append($stream, 'zlib.inflate', STREAM_FILTER_READ, ['window' => 15]); + return $stream; +} -// Read the filtered stream line by line. +// Read the filtered stream line by line using fgets. +$stream = create_stream(); while (($line = fgets($stream)) !== false) { - $error = error_get_last(); - if ($error !== null) { - // An error is thrown but fgets didn't return false - var_dump(error_get_last()); - var_dump($line); - } + $error = error_get_last(); + if ($error !== null) { + // An error is thrown but fgets didn't return false + var_dump(error_get_last()); + var_dump($line); + } } +fclose($stream); +error_clear_last(); +// Read the filtered stream line by line using stream_get_line. +$stream = create_stream(); +while (($line = stream_get_line($stream, 0, "\n")) !== false) { + $error = error_get_last(); + if ($error !== null) { + // An error is thrown but stream_get_line didn't return false + var_dump(error_get_last()); + var_dump($line); + } +} fclose($stream); ?> --EXPECTF-- Notice: fgets(): zlib: data error in %s on line %d -array(4) { - ["type"]=> - int(8) - ["message"]=> - string(25) "fgets(): zlib: data error" - ["file"]=> - string(%d) "%s" - ["line"]=> - int(%d) -} -string(%d) "Hello%s" +Notice: stream_get_line(): zlib: data error in %s on line %d diff --git a/main/php_streams.h b/main/php_streams.h index 31b80de986053..8996ee8bcb071 100644 --- a/main/php_streams.h +++ b/main/php_streams.h @@ -223,6 +223,9 @@ struct _php_stream { /* whether stdio cast flushing is in progress */ uint16_t fclose_stdiocast_flush_in_progress:1; + /* whether fatal error happened and all operations should terminates as soon as possible */ + uint16_t fatal_error:1; + char mode[16]; /* "rwb" etc. ala stdio */ uint32_t flags; /* PHP_STREAM_FLAG_XXX */ diff --git a/main/streams/memory.c b/main/streams/memory.c index ce11aec382bfe..785109db6582c 100644 --- a/main/streams/memory.c +++ b/main/streams/memory.c @@ -136,10 +136,12 @@ static int php_stream_memory_seek(php_stream *stream, zend_off_t offset, int whe ms->fpos = ms->fpos + offset; *newoffs = ms->fpos; stream->eof = 0; + stream->fatal_error = 0; return 0; } } else { stream->eof = 0; + stream->fatal_error = 0; ms->fpos = ms->fpos + offset; *newoffs = ms->fpos; return 0; @@ -153,6 +155,7 @@ static int php_stream_memory_seek(php_stream *stream, zend_off_t offset, int whe ms->fpos = offset; *newoffs = ms->fpos; stream->eof = 0; + stream->fatal_error = 0; return 0; } case SEEK_END: @@ -160,6 +163,7 @@ static int php_stream_memory_seek(php_stream *stream, zend_off_t offset, int whe ms->fpos = ZSTR_LEN(ms->data) + offset; *newoffs = ms->fpos; stream->eof = 0; + stream->fatal_error = 0; return 0; } else if (ZSTR_LEN(ms->data) < (size_t)(-offset)) { ms->fpos = 0; @@ -169,6 +173,7 @@ static int php_stream_memory_seek(php_stream *stream, zend_off_t offset, int whe ms->fpos = ZSTR_LEN(ms->data) + offset; *newoffs = ms->fpos; stream->eof = 0; + stream->fatal_error = 0; return 0; } default: diff --git a/main/streams/streams.c b/main/streams/streams.c index 4f9c88e4774c4..1471c98558e18 100644 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -636,6 +636,7 @@ PHPAPI zend_result _php_stream_fill_read_buffer(php_stream *stream, size_t size) /* some fatal error. Theoretically, the stream is borked, so all * further reads should fail. */ stream->eof = 1; + stream->fatal_error = 1; /* free all data left in brigades */ while ((bucket = brig_inp->head)) { /* Remove unconsumed buckets from the input brigade */ @@ -1009,7 +1010,12 @@ PHPAPI char *_php_stream_get_line(php_stream *stream, char *buf, size_t maxlen, } } - php_stream_fill_read_buffer(stream, toread); + if (php_stream_fill_read_buffer(stream, toread) == FAILURE && stream->fatal_error) { + if (grow_mode) { + efree(bufstart); + } + return NULL; + } if (stream->writepos - stream->readpos == 0) { break; @@ -1084,7 +1090,9 @@ PHPAPI zend_string *php_stream_get_record(php_stream *stream, size_t maxlen, con to_read_now = MIN(maxlen - buffered_len, stream->chunk_size); - php_stream_fill_read_buffer(stream, buffered_len + to_read_now); + if (php_stream_fill_read_buffer(stream, buffered_len + to_read_now) == FAILURE && stream->fatal_error) { + return NULL; + } just_read = STREAM_BUFFERED_AMOUNT(stream) - buffered_len; @@ -1357,6 +1365,7 @@ PHPAPI int _php_stream_seek(php_stream *stream, zend_off_t offset, int whence) stream->readpos += offset; /* if offset = ..., then readpos = writepos */ stream->position += offset; stream->eof = 0; + stream->fatal_error = 0; return 0; } break; @@ -1366,6 +1375,7 @@ PHPAPI int _php_stream_seek(php_stream *stream, zend_off_t offset, int whence) stream->readpos += offset - stream->position; stream->position = offset; stream->eof = 0; + stream->fatal_error = 0; return 0; } break; @@ -1400,6 +1410,7 @@ PHPAPI int _php_stream_seek(php_stream *stream, zend_off_t offset, int whence) if (((stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0) || ret == 0) { if (ret == 0) { stream->eof = 0; + stream->fatal_error = 0; } /* invalidate the buffer contents */ @@ -1422,6 +1433,7 @@ PHPAPI int _php_stream_seek(php_stream *stream, zend_off_t offset, int whence) offset -= didread; } stream->eof = 0; + stream->fatal_error = 0; return 0; } From 4fadf647d27118e34cc83fc98fcd4ead436c23cb Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 21 Jun 2025 00:47:40 +0200 Subject: [PATCH 044/120] Refactor dom_nnodemap_objects_new() - Use ecalloc() to not miss initializing any field. - Merge declarations and assignments. --- ext/dom/php_dom.c | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c index f2c1ec2c62b8b..b1f7eca80f104 100644 --- a/ext/dom/php_dom.c +++ b/ext/dom/php_dom.c @@ -1603,26 +1603,10 @@ void dom_nnodemap_objects_free_storage(zend_object *object) /* {{{ */ zend_object *dom_nnodemap_objects_new(zend_class_entry *class_type) { - dom_object *intern; - dom_nnodemap_object *objmap; - - intern = dom_objects_set_class(class_type); - intern->ptr = emalloc(sizeof(dom_nnodemap_object)); - objmap = (dom_nnodemap_object *)intern->ptr; - ZVAL_UNDEF(&objmap->baseobj_zv); - objmap->baseobj = NULL; - objmap->nodetype = 0; - objmap->ht = NULL; - objmap->local = NULL; - objmap->local_lower = NULL; - objmap->release_local = false; - objmap->ns = NULL; - objmap->release_ns = false; - objmap->cache_tag.modification_nr = 0; + dom_object *intern = dom_objects_set_class(class_type); + intern->ptr = ecalloc(1, sizeof(dom_nnodemap_object)); + dom_nnodemap_object *objmap = intern->ptr; objmap->cached_length = -1; - objmap->cached_obj = NULL; - objmap->cached_obj_index = 0; - objmap->dict = NULL; return &intern->std; } From ff0a2cff05ca5319fcd1367245cbebbe65042ab4 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 21 Jun 2025 15:37:45 +0200 Subject: [PATCH 045/120] Refactor implementation of DOM nodelists, named maps, and iterators The code was really messy with lots of checks and inconsistencies. This splits everything up into different functions and now everything is relayed to a handler vtable. --- ext/dom/config.m4 | 1 + ext/dom/config.w32 | 2 +- ext/dom/documenttype.c | 4 +- ext/dom/dom_iterators.c | 137 +----- ext/dom/element.c | 4 +- ext/dom/namednodemap.c | 126 +----- ext/dom/node.c | 4 +- ext/dom/nodelist.c | 163 +------ ext/dom/obj_map.c | 413 ++++++++++++++++++ ext/dom/obj_map.h | 39 ++ ext/dom/parentnode/css_selectors.c | 2 +- ext/dom/php_dom.c | 24 +- ext/dom/php_dom.h | 13 +- .../spec/Document_importLegacyNode.phpt | 6 +- .../modern/spec/NamedNodeMap_dimensions.phpt | 2 +- ext/dom/xpath.c | 2 +- 16 files changed, 521 insertions(+), 421 deletions(-) create mode 100644 ext/dom/obj_map.c create mode 100644 ext/dom/obj_map.h diff --git a/ext/dom/config.m4 b/ext/dom/config.m4 index 00934ceb55966..d51b1c2ac5202 100644 --- a/ext/dom/config.m4 +++ b/ext/dom/config.m4 @@ -33,6 +33,7 @@ if test "$PHP_DOM" != "no"; then node.c nodelist.c notation.c + obj_map.c parentnode/css_selectors.c parentnode/tree.c php_dom.c diff --git a/ext/dom/config.w32 b/ext/dom/config.w32 index d9e969a3845c4..2d8f3f3519c4a 100644 --- a/ext/dom/config.w32 +++ b/ext/dom/config.w32 @@ -15,7 +15,7 @@ if (PHP_DOM == "yes") { entity.c nodelist.c html_collection.c text.c comment.c \ entityreference.c \ token_list.c \ - notation.c xpath.c dom_iterators.c \ + notation.c obj_map.c xpath.c dom_iterators.c \ namednodemap.c xpath_callbacks.c", null, "/I ext/lexbor"); ADD_EXTENSION_DEP('dom', 'lexbor'); diff --git a/ext/dom/documenttype.c b/ext/dom/documenttype.c index 32bf556295161..895a34cebf650 100644 --- a/ext/dom/documenttype.c +++ b/ext/dom/documenttype.c @@ -53,7 +53,7 @@ zend_result dom_documenttype_entities_read(dom_object *obj, zval *retval) xmlHashTable *entityht = (xmlHashTable *) dtdptr->entities; dom_object *intern = Z_DOMOBJ_P(retval); - dom_namednode_iter(obj, XML_ENTITY_NODE, intern, entityht, NULL, NULL); + dom_namednode_iter(obj, intern, entityht, NULL, NULL, &php_dom_obj_map_entities); return SUCCESS; } @@ -74,7 +74,7 @@ zend_result dom_documenttype_notations_read(dom_object *obj, zval *retval) xmlHashTable *notationht = (xmlHashTable *) dtdptr->notations; dom_object *intern = Z_DOMOBJ_P(retval); - dom_namednode_iter(obj, XML_NOTATION_NODE, intern, notationht, NULL, NULL); + dom_namednode_iter(obj, intern, notationht, NULL, NULL, &php_dom_obj_map_notations); return SUCCESS; } diff --git a/ext/dom/dom_iterators.c b/ext/dom/dom_iterators.c index a0797967d1e76..19c4ea41adadb 100644 --- a/ext/dom/dom_iterators.c +++ b/ext/dom/dom_iterators.c @@ -68,7 +68,7 @@ xmlNodePtr create_notation(const xmlChar *name, const xmlChar *ExternalID, const } /* }}} */ -static xmlNode *php_dom_libxml_hash_iter_ex(xmlHashTable *ht, int index) +xmlNodePtr php_dom_libxml_hash_iter(xmlHashTable *ht, int index) { int htsize; @@ -84,18 +84,6 @@ static xmlNode *php_dom_libxml_hash_iter_ex(xmlHashTable *ht, int index) } } -xmlNode *php_dom_libxml_hash_iter(dom_nnodemap_object *objmap, int index) -{ - xmlNode *curnode = php_dom_libxml_hash_iter_ex(objmap->ht, index); - - if (curnode != NULL && objmap->nodetype != XML_ENTITY_NODE) { - xmlNotation *notation = (xmlNotation *) curnode; - curnode = create_notation(notation->name, notation->PublicID, notation->SystemID); - } - - return curnode; -} - static void php_dom_iterator_dtor(zend_object_iterator *iter) /* {{{ */ { php_dom_iterator *iterator = (php_dom_iterator *)iter; @@ -109,7 +97,7 @@ static zend_result php_dom_iterator_valid(zend_object_iterator *iter) /* {{{ */ { php_dom_iterator *iterator = (php_dom_iterator *)iter; - if (Z_TYPE(iterator->curobj) != IS_UNDEF) { + if (!Z_ISNULL(iterator->curobj)) { return SUCCESS; } else { return FAILURE; @@ -120,7 +108,7 @@ static zend_result php_dom_iterator_valid(zend_object_iterator *iter) /* {{{ */ zval *php_dom_iterator_current_data(zend_object_iterator *iter) /* {{{ */ { php_dom_iterator *iterator = (php_dom_iterator *)iter; - return Z_ISUNDEF(iterator->curobj) ? NULL : &iterator->curobj; + return Z_ISNULL(iterator->curobj) ? NULL : &iterator->curobj; } /* }}} */ @@ -131,14 +119,14 @@ static void php_dom_iterator_current_key(zend_object_iterator *iter, zval *key) /* Only dtd named node maps, i.e. the ones based on a libxml hash table or attribute collections, * are keyed by the name because in that case the name is unique. */ - if (!objmap->ht && objmap->nodetype != XML_ATTRIBUTE_NODE) { + if (objmap->handler->nameless) { ZVAL_LONG(key, iterator->index); } else { dom_object *intern = Z_DOMOBJ_P(&iterator->curobj); - if (intern != NULL && intern->ptr != NULL) { + if (intern->ptr != NULL) { xmlNodePtr curnode = ((php_libxml_node_ptr *)intern->ptr)->node; - if (objmap->nodetype == XML_ATTRIBUTE_NODE && php_dom_follow_spec_intern(intern)) { + if (curnode->type == XML_ATTRIBUTE_NODE && php_dom_follow_spec_intern(intern)) { ZVAL_NEW_STR(key, dom_node_get_node_name_attribute_or_element(curnode, false)); } else { ZVAL_STRINGL(key, (const char *) curnode->name, xmlStrlen(curnode->name)); @@ -150,99 +138,36 @@ static void php_dom_iterator_current_key(zend_object_iterator *iter, zval *key) } /* }}} */ -static xmlNodePtr dom_fetch_first_iteration_item(dom_nnodemap_object *objmap) -{ - xmlNodePtr basep = dom_object_get_node(objmap->baseobj); - if (!basep) { - return NULL; - } - if (objmap->nodetype == XML_ATTRIBUTE_NODE || objmap->nodetype == XML_ELEMENT_NODE) { - if (objmap->nodetype == XML_ATTRIBUTE_NODE) { - return (xmlNodePtr) basep->properties; - } else { - return dom_nodelist_iter_start_first_child(basep); - } - } else { - zend_long curindex = 0; - xmlNodePtr nodep = php_dom_first_child_of_container_node(basep); - return dom_get_elements_by_tag_name_ns_raw( - basep, nodep, objmap->ns, objmap->local, objmap->local_lower, &curindex, 0); - } -} - static void php_dom_iterator_move_forward(zend_object_iterator *iter) /* {{{ */ { - xmlNodePtr curnode = NULL; - php_dom_iterator *iterator = (php_dom_iterator *)iter; - if (Z_ISUNDEF(iterator->curobj)) { + if (Z_ISNULL(iterator->curobj)) { return; } iterator->index++; + zval garbage; + ZVAL_COPY_VALUE(&garbage, &iterator->curobj); + ZVAL_NULL(&iterator->curobj); dom_object *intern = Z_DOMOBJ_P(&iterator->curobj); dom_nnodemap_object *objmap = php_dom_iterator_get_nnmap(iterator); - if (intern != NULL && intern->ptr != NULL) { - if (objmap->nodetype != XML_ENTITY_NODE && - objmap->nodetype != XML_NOTATION_NODE) { - if (objmap->nodetype == DOM_NODESET) { - HashTable *nodeht = Z_ARRVAL_P(&objmap->baseobj_zv); - zval *entry = zend_hash_index_find(nodeht, iterator->index); - if (entry) { - zval_ptr_dtor(&iterator->curobj); - ZVAL_COPY(&iterator->curobj, entry); - return; - } - } else { - if (objmap->nodetype == XML_ATTRIBUTE_NODE || - objmap->nodetype == XML_ELEMENT_NODE) { - - /* Note: keep legacy behaviour for non-spec mode. */ - if (php_dom_follow_spec_intern(intern) && php_dom_is_cache_tag_stale_from_doc_ptr(&iterator->cache_tag, intern->document)) { - php_dom_mark_cache_tag_up_to_date_from_doc_ref(&iterator->cache_tag, intern->document); - curnode = dom_fetch_first_iteration_item(objmap); - zend_ulong index = 0; - while (curnode != NULL && index++ < iterator->index) { - curnode = curnode->next; - } - } else { - curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node; - curnode = curnode->next; - } - } else { - /* The collection is live, we nav the tree from the base object if we cannot - * use the cache to restart from the last point. */ - xmlNodePtr basenode = dom_object_get_node(objmap->baseobj); - - /* We have a strong reference to the base node via baseobj_zv, this cannot become NULL */ - ZEND_ASSERT(basenode != NULL); - - zend_long previndex; - if (php_dom_is_cache_tag_stale_from_node(&iterator->cache_tag, basenode)) { - php_dom_mark_cache_tag_up_to_date_from_node(&iterator->cache_tag, basenode); - previndex = 0; - curnode = php_dom_first_child_of_container_node(basenode); - } else { - previndex = iterator->index - 1; - curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->ptr)->node; - } - curnode = dom_get_elements_by_tag_name_ns_raw( - basenode, curnode, objmap->ns, objmap->local, objmap->local_lower, &previndex, iterator->index); - } + if (intern->ptr != NULL) { + /* Note: keep legacy behaviour for non-spec mode. */ + /* TODO: make this prettier */ + if (!php_dom_follow_spec_intern(intern) && (objmap->handler == &php_dom_obj_map_attributes || objmap->handler == &php_dom_obj_map_child_nodes)) { + xmlNodePtr curnode = ((php_libxml_node_ptr *) intern->ptr)->node; + curnode = curnode->next; + if (curnode) { + php_dom_create_object(curnode, &iterator->curobj, objmap->baseobj); } } else { - curnode = php_dom_libxml_hash_iter(objmap, iterator->index); + objmap->handler->get_item(objmap, (zend_long) iterator->index, &iterator->curobj); } } - zval_ptr_dtor(&iterator->curobj); - ZVAL_UNDEF(&iterator->curobj); - - if (curnode) { - php_dom_create_object(curnode, &iterator->curobj, objmap->baseobj); - } + zval_ptr_dtor(&garbage); } /* }}} */ @@ -261,7 +186,6 @@ zend_object_iterator *php_dom_get_iterator(zend_class_entry *ce, zval *object, i { dom_object *intern; dom_nnodemap_object *objmap; - xmlNodePtr curnode=NULL; php_dom_iterator *iterator; if (by_ref) { @@ -277,26 +201,7 @@ zend_object_iterator *php_dom_get_iterator(zend_class_entry *ce, zval *object, i intern = Z_DOMOBJ_P(object); objmap = (dom_nnodemap_object *)intern->ptr; - if (objmap != NULL) { - if (objmap->nodetype != XML_ENTITY_NODE && - objmap->nodetype != XML_NOTATION_NODE) { - if (objmap->nodetype == DOM_NODESET) { - HashTable *nodeht = Z_ARRVAL_P(&objmap->baseobj_zv); - zval *entry = zend_hash_index_find(nodeht, 0); - if (entry) { - ZVAL_COPY(&iterator->curobj, entry); - } - } else { - curnode = dom_fetch_first_iteration_item(objmap); - } - } else { - curnode = php_dom_libxml_hash_iter(objmap, 0); - } - } - - if (curnode) { - php_dom_create_object(curnode, &iterator->curobj, objmap->baseobj); - } + objmap->handler->get_item(objmap, 0, &iterator->curobj); return &iterator->intern; } diff --git a/ext/dom/element.c b/ext/dom/element.c index 4aa56f3691b2f..d0fc0b4a4d3e2 100644 --- a/ext/dom/element.c +++ b/ext/dom/element.c @@ -825,7 +825,7 @@ static void dom_element_get_elements_by_tag_name(INTERNAL_FUNCTION_PARAMETERS, z object_init_ex(return_value, iter_ce); namednode = Z_DOMOBJ_P(return_value); - dom_namednode_iter(intern, 0, namednode, NULL, name, NULL); + dom_namednode_iter(intern, namednode, NULL, name, NULL, &php_dom_obj_map_by_tag_name); } PHP_METHOD(DOMElement, getElementsByTagName) @@ -1257,7 +1257,7 @@ static void dom_element_get_elements_by_tag_name_ns(INTERNAL_FUNCTION_PARAMETERS object_init_ex(return_value, iter_ce); namednode = Z_DOMOBJ_P(return_value); - dom_namednode_iter(intern, 0, namednode, NULL, name, uri); + dom_namednode_iter(intern, namednode, NULL, name, uri, &php_dom_obj_map_by_tag_name); } PHP_METHOD(DOMElement, getElementsByTagNameNS) diff --git a/ext/dom/namednodemap.c b/ext/dom/namednodemap.c index 73f1f09e9dae8..2f8f6d10132c2 100644 --- a/ext/dom/namednodemap.c +++ b/ext/dom/namednodemap.c @@ -33,24 +33,12 @@ zend_long php_dom_get_namednodemap_length(dom_object *obj) { - dom_nnodemap_object *objmap = (dom_nnodemap_object *) obj->ptr; + dom_nnodemap_object *objmap = obj->ptr; if (!objmap) { return 0; } - if (objmap->nodetype == XML_NOTATION_NODE || objmap->nodetype == XML_ENTITY_NODE) { - return objmap->ht ? xmlHashSize(objmap->ht) : 0; - } - - zend_long count = 0; - xmlNodePtr nodep = dom_object_get_node(objmap->baseobj); - if (nodep) { - for (xmlAttrPtr curnode = nodep->properties; curnode; curnode = curnode->next) { - count++; - } - } - - return count; + return objmap->handler->length(objmap); } /* {{{ length int @@ -66,43 +54,9 @@ zend_result dom_namednodemap_length_read(dom_object *obj, zval *retval) /* }}} */ -xmlNodePtr php_dom_named_node_map_get_named_item(dom_nnodemap_object *objmap, const zend_string *named, bool may_transform) -{ - xmlNodePtr itemnode = NULL; - if (objmap != NULL) { - if ((objmap->nodetype == XML_NOTATION_NODE) || - objmap->nodetype == XML_ENTITY_NODE) { - if (objmap->ht) { - if (objmap->nodetype == XML_ENTITY_NODE) { - itemnode = (xmlNodePtr)xmlHashLookup(objmap->ht, BAD_CAST ZSTR_VAL(named)); - } else { - xmlNotationPtr notep = xmlHashLookup(objmap->ht, BAD_CAST ZSTR_VAL(named)); - if (notep) { - if (may_transform) { - itemnode = create_notation(notep->name, notep->PublicID, notep->SystemID); - } else { - itemnode = (xmlNodePtr) notep; - } - } - } - } - } else { - xmlNodePtr nodep = dom_object_get_node(objmap->baseobj); - if (nodep) { - if (php_dom_follow_spec_intern(objmap->baseobj)) { - itemnode = (xmlNodePtr) php_dom_get_attribute_node(nodep, BAD_CAST ZSTR_VAL(named), ZSTR_LEN(named)); - } else { - itemnode = (xmlNodePtr) xmlHasProp(nodep, BAD_CAST ZSTR_VAL(named)); - } - } - } - } - return itemnode; -} - -void php_dom_named_node_map_get_named_item_into_zval(dom_nnodemap_object *objmap, const zend_string *named, zval *return_value) +void php_dom_named_node_map_get_named_item_into_zval(dom_nnodemap_object *objmap, const zend_string *named, const char *ns, zval *return_value) { - xmlNodePtr itemnode = php_dom_named_node_map_get_named_item(objmap, named, true); + xmlNodePtr itemnode = objmap->handler->get_named_item(objmap, named, ns); if (itemnode) { DOM_RET_OBJ(itemnode, objmap->baseobj); } else { @@ -122,45 +76,10 @@ PHP_METHOD(DOMNamedNodeMap, getNamedItem) } dom_nnodemap_object *objmap = Z_DOMOBJ_P(ZEND_THIS)->ptr; - php_dom_named_node_map_get_named_item_into_zval(objmap, named, return_value); + php_dom_named_node_map_get_named_item_into_zval(objmap, named, NULL, return_value); } /* }}} end dom_namednodemap_get_named_item */ -xmlNodePtr php_dom_named_node_map_get_item(dom_nnodemap_object *objmap, zend_long index) -{ - xmlNodePtr itemnode = NULL; - if (objmap != NULL) { - if ((objmap->nodetype == XML_NOTATION_NODE) || - objmap->nodetype == XML_ENTITY_NODE) { - if (objmap->ht) { - itemnode = php_dom_libxml_hash_iter(objmap, index); - } - } else { - xmlNodePtr nodep = dom_object_get_node(objmap->baseobj); - if (nodep) { - xmlNodePtr curnode = (xmlNodePtr)nodep->properties; - zend_long count = 0; - while (count < index && curnode != NULL) { - count++; - curnode = curnode->next; - } - itemnode = curnode; - } - } - } - return itemnode; -} - -void php_dom_named_node_map_get_item_into_zval(dom_nnodemap_object *objmap, zend_long index, zval *return_value) -{ - xmlNodePtr itemnode = php_dom_named_node_map_get_item(objmap, index); - if (itemnode) { - DOM_RET_OBJ(itemnode, objmap->baseobj); - } else { - RETURN_NULL(); - } -} - /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-349467F9 Since: */ @@ -177,7 +96,7 @@ PHP_METHOD(DOMNamedNodeMap, item) dom_object *intern = Z_DOMOBJ_P(ZEND_THIS); dom_nnodemap_object *objmap = intern->ptr; - php_dom_named_node_map_get_item_into_zval(objmap, index, return_value); + objmap->handler->get_item(objmap, index, return_value); } /* }}} end dom_namednodemap_item */ @@ -186,16 +105,14 @@ Since: DOM Level 2 */ PHP_METHOD(DOMNamedNodeMap, getNamedItemNS) { - size_t namedlen=0, urilen=0; + size_t urilen=0; dom_object *intern; - xmlNodePtr itemnode = NULL; - char *uri, *named; + char *uri; + zend_string *named; dom_nnodemap_object *objmap; - xmlNodePtr nodep; - xmlNotation *notep = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "s!s", &uri, &urilen, &named, &namedlen) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s!S", &uri, &urilen, &named) == FAILURE) { RETURN_THROWS(); } @@ -204,28 +121,7 @@ PHP_METHOD(DOMNamedNodeMap, getNamedItemNS) objmap = (dom_nnodemap_object *)intern->ptr; if (objmap != NULL) { - if ((objmap->nodetype == XML_NOTATION_NODE) || - objmap->nodetype == XML_ENTITY_NODE) { - if (objmap->ht) { - if (objmap->nodetype == XML_ENTITY_NODE) { - itemnode = (xmlNodePtr)xmlHashLookup(objmap->ht, BAD_CAST named); - } else { - notep = (xmlNotation *)xmlHashLookup(objmap->ht, BAD_CAST named); - if (notep) { - itemnode = create_notation(notep->name, notep->PublicID, notep->SystemID); - } - } - } - } else { - nodep = dom_object_get_node(objmap->baseobj); - if (nodep) { - itemnode = (xmlNodePtr)xmlHasNsProp(nodep, BAD_CAST named, BAD_CAST uri); - } - } - } - - if (itemnode) { - DOM_RET_OBJ(itemnode, objmap->baseobj); + php_dom_named_node_map_get_named_item_into_zval(objmap, named, uri, return_value); } } /* }}} end dom_namednodemap_get_named_item_ns */ diff --git a/ext/dom/node.c b/ext/dom/node.c index c9bf45e887db8..99069d778ebfe 100644 --- a/ext/dom/node.c +++ b/ext/dom/node.c @@ -288,7 +288,7 @@ zend_result dom_node_child_nodes_read(dom_object *obj, zval *retval) object_init_ex(retval, dom_get_nodelist_ce(php_dom_follow_spec_intern(obj))); dom_object *intern = Z_DOMOBJ_P(retval); - dom_namednode_iter(obj, XML_ELEMENT_NODE, intern, NULL, NULL, NULL); + dom_namednode_iter(obj, intern, NULL, NULL, NULL, &php_dom_obj_map_child_nodes); return SUCCESS; } @@ -422,7 +422,7 @@ zend_result dom_node_attributes_read(dom_object *obj, zval *retval) if (nodep->type == XML_ELEMENT_NODE) { object_init_ex(retval, dom_get_namednodemap_ce(php_dom_follow_spec_intern(obj))); dom_object *intern = Z_DOMOBJ_P(retval); - dom_namednode_iter(obj, XML_ATTRIBUTE_NODE, intern, NULL, NULL, NULL); + dom_namednode_iter(obj, intern, NULL, NULL, NULL, &php_dom_obj_map_attributes); } else { ZVAL_NULL(retval); } diff --git a/ext/dom/nodelist.c b/ext/dom/nodelist.c index 819b7396b69c7..46a10a362a071 100644 --- a/ext/dom/nodelist.c +++ b/ext/dom/nodelist.c @@ -32,24 +32,6 @@ * Since: */ -static zend_always_inline void objmap_cache_release_cached_obj(dom_nnodemap_object *objmap) -{ - if (objmap->cached_obj) { - /* Since the DOM is a tree there can be no cycles. */ - if (GC_DELREF(&objmap->cached_obj->std) == 0) { - zend_objects_store_del(&objmap->cached_obj->std); - } - objmap->cached_obj = NULL; - objmap->cached_obj_index = 0; - } -} - -static zend_always_inline void reset_objmap_cache(dom_nnodemap_object *objmap) -{ - objmap_cache_release_cached_obj(objmap); - objmap->cached_length = -1; -} - xmlNodePtr dom_nodelist_iter_start_first_child(xmlNodePtr nodep) { if (nodep->type == XML_ENTITY_REF_NODE) { @@ -60,60 +42,6 @@ xmlNodePtr dom_nodelist_iter_start_first_child(xmlNodePtr nodep) return nodep->children; } -zend_long php_dom_get_nodelist_length(dom_object *obj) -{ - dom_nnodemap_object *objmap = (dom_nnodemap_object *) obj->ptr; - if (!objmap) { - return 0; - } - - if (objmap->ht) { - return xmlHashSize(objmap->ht); - } - - if (objmap->nodetype == DOM_NODESET) { - HashTable *nodeht = Z_ARRVAL_P(&objmap->baseobj_zv); - return zend_hash_num_elements(nodeht); - } - - xmlNodePtr nodep = dom_object_get_node(objmap->baseobj); - if (!nodep) { - return 0; - } - - if (!php_dom_is_cache_tag_stale_from_node(&objmap->cache_tag, nodep)) { - if (objmap->cached_length >= 0) { - return objmap->cached_length; - } - /* Only the length is out-of-date, the cache tag is still valid. - * Therefore, only overwrite the length and keep the currently cached object. */ - } else { - php_dom_mark_cache_tag_up_to_date_from_node(&objmap->cache_tag, nodep); - reset_objmap_cache(objmap); - } - - zend_long count = 0; - if (objmap->nodetype == XML_ATTRIBUTE_NODE || objmap->nodetype == XML_ELEMENT_NODE) { - xmlNodePtr curnode = dom_nodelist_iter_start_first_child(nodep); - if (curnode) { - count++; - while (curnode->next != NULL) { - count++; - curnode = curnode->next; - } - } - } else { - xmlNodePtr basep = nodep; - nodep = php_dom_first_child_of_container_node(basep); - dom_get_elements_by_tag_name_ns_raw( - basep, nodep, objmap->ns, objmap->local, objmap->local_lower, &count, ZEND_LONG_MAX - 1 /* because of <= */); - } - - objmap->cached_length = count; - - return count; -} - /* {{{ length int readonly=yes URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#ID-203510337 @@ -137,94 +65,11 @@ PHP_METHOD(DOMNodeList, count) void php_dom_nodelist_get_item_into_zval(dom_nnodemap_object *objmap, zend_long index, zval *return_value) { - xmlNodePtr itemnode = NULL; - bool cache_itemnode = false; - if (index >= 0) { - if (objmap != NULL) { - if (objmap->ht) { - itemnode = php_dom_libxml_hash_iter(objmap, index); - } else { - if (objmap->nodetype == DOM_NODESET) { - HashTable *nodeht = Z_ARRVAL_P(&objmap->baseobj_zv); - zval *entry = zend_hash_index_find(nodeht, index); - if (entry) { - ZVAL_COPY(return_value, entry); - return; - } - } else if (objmap->baseobj) { - xmlNodePtr basep = dom_object_get_node(objmap->baseobj); - if (basep) { - xmlNodePtr nodep = basep; - /* For now we're only able to use cache for forward search. - * TODO: in the future we could extend the logic of the node list such that backwards searches - * are also possible. */ - bool restart = true; - zend_long relative_index = index; - if (index >= objmap->cached_obj_index && objmap->cached_obj && !php_dom_is_cache_tag_stale_from_node(&objmap->cache_tag, nodep)) { - xmlNodePtr cached_obj_xml_node = dom_object_get_node(objmap->cached_obj); - - /* The node cannot be NULL if the cache is valid. If it is NULL, then it means we - * forgot an invalidation somewhere. Take the defensive programming approach and invalidate - * it here if it's NULL (except in debug mode where we would want to catch this). */ - if (UNEXPECTED(cached_obj_xml_node == NULL)) { -#if ZEND_DEBUG - ZEND_UNREACHABLE(); -#endif - reset_objmap_cache(objmap); - } else { - restart = false; - relative_index -= objmap->cached_obj_index; - nodep = cached_obj_xml_node; - } - } - zend_long count = 0; - if (objmap->nodetype == XML_ATTRIBUTE_NODE || objmap->nodetype == XML_ELEMENT_NODE) { - if (restart) { - nodep = dom_nodelist_iter_start_first_child(nodep); - } - while (count < relative_index && nodep != NULL) { - count++; - nodep = nodep->next; - } - itemnode = nodep; - } else { - if (restart) { - nodep = php_dom_first_child_of_container_node(basep); - } - itemnode = dom_get_elements_by_tag_name_ns_raw(basep, nodep, objmap->ns, objmap->local, objmap->local_lower, &count, relative_index); - } - cache_itemnode = true; - } - } - } - } - - if (itemnode) { - DOM_RET_OBJ(itemnode, objmap->baseobj); - if (cache_itemnode) { - /* Hold additional reference for the cache, must happen before releasing the cache - * because we might be the last reference holder. - * Instead of storing and copying zvals, we store the object pointer directly. - * This saves us some bytes because a pointer is smaller than a zval. - * This also means we have to manually refcount the objects here, and remove the reference count - * in reset_objmap_cache() and the destructor. */ - dom_object *cached_obj = Z_DOMOBJ_P(return_value); - GC_ADDREF(&cached_obj->std); - /* If the tag is stale, all cached data is useless. Otherwise only the cached object is useless. */ - if (php_dom_is_cache_tag_stale_from_node(&objmap->cache_tag, itemnode)) { - php_dom_mark_cache_tag_up_to_date_from_node(&objmap->cache_tag, itemnode); - reset_objmap_cache(objmap); - } else { - objmap_cache_release_cached_obj(objmap); - } - objmap->cached_obj_index = index; - objmap->cached_obj = cached_obj; - } - return; - } + if (EXPECTED(objmap)) { + objmap->handler->get_item(objmap, index, return_value); + } else { + RETURN_NULL(); } - - RETVAL_NULL(); } /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#ID-844377136 diff --git a/ext/dom/obj_map.c b/ext/dom/obj_map.c new file mode 100644 index 0000000000000..f2a93fe3ef870 --- /dev/null +++ b/ext/dom/obj_map.c @@ -0,0 +1,413 @@ +/* + +----------------------------------------------------------------------+ + | 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: Christian Stocker | + | Rob Richards | + | Niels Dossche | + +----------------------------------------------------------------------+ +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "php.h" +#if defined(HAVE_LIBXML) && defined(HAVE_DOM) +#include "php_dom.h" +#include "obj_map.h" + +static zend_always_inline void objmap_cache_release_cached_obj(dom_nnodemap_object *objmap) +{ + if (objmap->cached_obj) { + /* Since the DOM is a tree there can be no cycles. */ + if (GC_DELREF(&objmap->cached_obj->std) == 0) { + zend_objects_store_del(&objmap->cached_obj->std); + } + objmap->cached_obj = NULL; + objmap->cached_obj_index = 0; + } +} + +static zend_always_inline void reset_objmap_cache(dom_nnodemap_object *objmap) +{ + objmap_cache_release_cached_obj(objmap); + objmap->cached_length = -1; +} + +/************************** + * === Length methods === * + **************************/ + +static zend_long dom_map_get_xmlht_length(dom_nnodemap_object *map) +{ + /* Note: if there are, for example, no entities or notations then the hash table can be NULL. */ + return map->ht ? xmlHashSize(map->ht) : 0; +} + +static zend_long dom_map_get_nodeset_length(dom_nnodemap_object *map) +{ + HashTable *nodeht = Z_ARRVAL(map->baseobj_zv); + return zend_hash_num_elements(nodeht); +} + +static zend_long dom_map_get_prop_length(dom_nnodemap_object *map) +{ + zend_long count = 0; + xmlNodePtr nodep = dom_object_get_node(map->baseobj); + if (nodep) { + for (xmlAttrPtr curnode = nodep->properties; curnode; curnode = curnode->next) { + count++; + } + } + return count; +} + +static zend_long dom_map_get_nodes_length(dom_nnodemap_object *map) +{ + zend_long count = 0; + xmlNodePtr nodep = dom_object_get_node(map->baseobj); + if (nodep) { + for (xmlNodePtr curnode = dom_nodelist_iter_start_first_child(nodep); curnode; curnode = curnode->next) { + count++; + } + } + return count; +} + +static zend_long dom_map_get_by_tag_name_length(dom_nnodemap_object *map) +{ + xmlNodePtr nodep = dom_object_get_node(map->baseobj); + zend_long count = 0; + if (nodep) { + xmlNodePtr basep = nodep; + nodep = php_dom_first_child_of_container_node(basep); + dom_get_elements_by_tag_name_ns_raw( + basep, nodep, map->ns, map->local, map->local_lower, &count, ZEND_LONG_MAX - 1 /* because of <= */); + } + return count; +} + +static zend_long dom_map_get_zero_length(dom_nnodemap_object *map) +{ + return 0; +} + +/************************ + * === Item lookups === * + ************************/ + +static void dom_ret_node_to_zobj(dom_nnodemap_object *map, xmlNodePtr node, zval *return_value) +{ + if (node) { + DOM_RET_OBJ(node, map->baseobj); + } else { + RETURN_NULL(); + } +} + +static void dom_map_get_entity_item(dom_nnodemap_object *map, zend_long index, zval *return_value) +{ + xmlNodePtr node = map->ht ? php_dom_libxml_hash_iter(map->ht, index) : NULL; + dom_ret_node_to_zobj(map, node, return_value); +} + +static void dom_map_get_notation_item(dom_nnodemap_object *map, zend_long index, zval *return_value) +{ + xmlNodePtr node = map->ht ? php_dom_libxml_hash_iter(map->ht, index) : NULL; + if (node) { + xmlNotation *notation = (xmlNotation *) node; + node = create_notation(notation->name, notation->PublicID, notation->SystemID); + } + dom_ret_node_to_zobj(map, node, return_value); +} + +static void dom_map_get_nodeset_item(dom_nnodemap_object *map, zend_long index, zval *return_value) +{ + HashTable *nodeht = Z_ARRVAL(map->baseobj_zv); + zval *entry = zend_hash_index_find(nodeht, index); + if (entry) { + RETURN_COPY(entry); + } else { + RETURN_NULL(); + } +} + +typedef struct dom_node_idx_pair { + xmlNodePtr node; + zend_long index; +} dom_node_idx_pair; + +static dom_node_idx_pair dom_obj_map_get_start_point(dom_nnodemap_object *map, xmlNodePtr basep, zend_long index) +{ + dom_node_idx_pair ret; + ZEND_ASSERT(basep != NULL); + /* For now we're only able to use cache for forward search. + * TODO: in the future we could extend the logic of the node list such that backwards searches + * are also possible. */ + bool restart = true; + zend_long relative_index = index; + if (index >= map->cached_obj_index && map->cached_obj && !php_dom_is_cache_tag_stale_from_node(&map->cache_tag, basep)) { + xmlNodePtr cached_obj_xml_node = dom_object_get_node(map->cached_obj); + + /* The node cannot be NULL if the cache is valid. If it is NULL, then it means we + * forgot an invalidation somewhere. Take the defensive programming approach and invalidate + * it here if it's NULL (except in debug mode where we would want to catch this). */ + if (UNEXPECTED(cached_obj_xml_node == NULL)) { +#if ZEND_DEBUG + ZEND_UNREACHABLE(); +#endif + reset_objmap_cache(map); + } else { + restart = false; + relative_index -= map->cached_obj_index; + basep = cached_obj_xml_node; + } + } + ret.node = restart ? NULL : basep; + ret.index = relative_index; + return ret; +} + +static void dom_map_cache_obj(dom_nnodemap_object *map, xmlNodePtr itemnode, zend_long index, zval *return_value) +{ + /* Hold additional reference for the cache, must happen before releasing the cache + * because we might be the last reference holder. + * Instead of storing and copying zvals, we store the object pointer directly. + * This saves us some bytes because a pointer is smaller than a zval. + * This also means we have to manually refcount the objects here, and remove the reference count + * in reset_objmap_cache() and the destructor. */ + dom_object *cached_obj = Z_DOMOBJ_P(return_value); + GC_ADDREF(&cached_obj->std); + /* If the tag is stale, all cached data is useless. Otherwise only the cached object is useless. */ + if (php_dom_is_cache_tag_stale_from_node(&map->cache_tag, itemnode)) { + php_dom_mark_cache_tag_up_to_date_from_node(&map->cache_tag, itemnode); + reset_objmap_cache(map); + } else { + objmap_cache_release_cached_obj(map); + } + map->cached_obj_index = index; + map->cached_obj = cached_obj; +} + +static xmlNodePtr dom_map_get_attr_start(xmlNodePtr node) +{ + ZEND_ASSERT(node->type == XML_ELEMENT_NODE); + return (xmlNodePtr) node->properties; +} + +static void dom_map_get_chain_item(dom_nnodemap_object *map, zend_long index, zval *return_value, xmlNodePtr (*get_start)(xmlNodePtr)) +{ + xmlNodePtr nodep = dom_object_get_node(map->baseobj); + xmlNodePtr itemnode = NULL; + if (nodep && index >= 0) { + dom_node_idx_pair start_point = dom_obj_map_get_start_point(map, nodep, index); + itemnode = start_point.node ? start_point.node : get_start(nodep); + for (; start_point.index > 0 && itemnode; itemnode = itemnode->next, start_point.index--); + } + dom_ret_node_to_zobj(map, itemnode, return_value); + if (itemnode) { + dom_map_cache_obj(map, itemnode, index, return_value); + } +} + +static void dom_map_get_attributes_item(dom_nnodemap_object *map, zend_long index, zval *return_value) +{ + dom_map_get_chain_item(map, index, return_value, dom_map_get_attr_start); +} + +static void dom_map_get_nodes_item(dom_nnodemap_object *map, zend_long index, zval *return_value) +{ + dom_map_get_chain_item(map, index, return_value, dom_nodelist_iter_start_first_child); +} + +static void dom_map_get_by_tag_name_item(dom_nnodemap_object *map, zend_long index, zval *return_value) +{ + xmlNodePtr nodep = dom_object_get_node(map->baseobj); + xmlNodePtr itemnode = NULL; + if (nodep && index >= 0) { + zend_long count = 0; + dom_node_idx_pair start_point = dom_obj_map_get_start_point(map, nodep, index); + itemnode = start_point.node ? start_point.node : php_dom_first_child_of_container_node(nodep); + itemnode = dom_get_elements_by_tag_name_ns_raw(nodep, itemnode, map->ns, map->local, map->local_lower, &count, start_point.index); + } + dom_ret_node_to_zobj(map, itemnode, return_value); + if (itemnode) { + dom_map_cache_obj(map, itemnode, index, return_value); + } +} + +static void dom_map_get_null_item(dom_nnodemap_object *map, zend_long index, zval *return_value) +{ + RETURN_NULL(); +} + +/*********************** + * === Common APIs === * + ***********************/ + +zend_long php_dom_get_nodelist_length(dom_object *obj) +{ + dom_nnodemap_object *objmap = obj->ptr; + if (!objmap) { + return 0; + } + + if (objmap->handler->use_cache) { + xmlNodePtr nodep = dom_object_get_node(objmap->baseobj); + if (!nodep) { + return 0; + } + + if (!php_dom_is_cache_tag_stale_from_node(&objmap->cache_tag, nodep)) { + if (objmap->cached_length >= 0) { + return objmap->cached_length; + } + /* Only the length is out-of-date, the cache tag is still valid. + * Therefore, only overwrite the length and keep the currently cached object. */ + } else { + php_dom_mark_cache_tag_up_to_date_from_node(&objmap->cache_tag, nodep); + reset_objmap_cache(objmap); + } + } + + zend_long count = objmap->handler->length(objmap); + + if (objmap->handler->use_cache) { + objmap->cached_length = count; + } + + return count; +} + +/********************** + * === Named item === * + **********************/ + +static xmlNodePtr dom_map_get_named_item_entity(dom_nnodemap_object *map, const zend_string *named, const char *ns) +{ + return xmlHashLookup(map->ht, BAD_CAST ZSTR_VAL(named)); +} + +static bool dom_map_has_named_item_xmlht(dom_nnodemap_object *map, const zend_string *named, const char *ns) +{ + return dom_map_get_named_item_entity(map, named, ns) != NULL; +} + +static xmlNodePtr dom_map_get_named_item_notation(dom_nnodemap_object *map, const zend_string *named, const char *ns) +{ + xmlNotationPtr notation = xmlHashLookup(map->ht, BAD_CAST ZSTR_VAL(named)); + if (notation) { + return create_notation(notation->name, notation->PublicID, notation->SystemID); + } + return NULL; +} + +static xmlNodePtr dom_map_get_named_item_prop(dom_nnodemap_object *map, const zend_string *named, const char *ns) +{ + xmlNodePtr nodep = dom_object_get_node(map->baseobj); + if (nodep) { + if (php_dom_follow_spec_intern(map->baseobj)) { + return (xmlNodePtr) php_dom_get_attribute_node(nodep, BAD_CAST ZSTR_VAL(named), ZSTR_LEN(named)); + } else { + if (ns) { + return (xmlNodePtr) xmlHasNsProp(nodep, BAD_CAST ZSTR_VAL(named), BAD_CAST ns); + } else { + return (xmlNodePtr) xmlHasProp(nodep, BAD_CAST ZSTR_VAL(named)); + } + } + } + return NULL; +} + +static bool dom_map_has_named_item_prop(dom_nnodemap_object *map, const zend_string *named, const char *ns) +{ + return dom_map_get_named_item_prop(map, named, ns) != NULL; +} + +static xmlNodePtr dom_map_get_named_item_null(dom_nnodemap_object *map, const zend_string *named, const char *ns) +{ + return NULL; +} + +static bool dom_map_has_named_item_null(dom_nnodemap_object *map, const zend_string *named, const char *ns) +{ + return false; +} + +/************************** + * === Handler tables === * + **************************/ + +const php_dom_obj_map_handler php_dom_obj_map_attributes = { + .length = dom_map_get_prop_length, + .get_item = dom_map_get_attributes_item, + .get_named_item = dom_map_get_named_item_prop, + .has_named_item = dom_map_has_named_item_prop, + .use_cache = true, + .nameless = false, +}; + +const php_dom_obj_map_handler php_dom_obj_map_by_tag_name = { + .length = dom_map_get_by_tag_name_length, + .get_item = dom_map_get_by_tag_name_item, + .get_named_item = dom_map_get_named_item_null, + .has_named_item = dom_map_has_named_item_null, + .use_cache = true, + .nameless = true, +}; + +const php_dom_obj_map_handler php_dom_obj_map_child_nodes = { + .length = dom_map_get_nodes_length, + .get_item = dom_map_get_nodes_item, + .get_named_item = dom_map_get_named_item_null, + .has_named_item = dom_map_has_named_item_null, + .use_cache = true, + .nameless = true, +}; + +const php_dom_obj_map_handler php_dom_obj_map_nodeset = { + .length = dom_map_get_nodeset_length, + .get_item = dom_map_get_nodeset_item, + .get_named_item = dom_map_get_named_item_null, + .has_named_item = dom_map_has_named_item_null, + .use_cache = false, + .nameless = true, +}; + +const php_dom_obj_map_handler php_dom_obj_map_entities = { + .length = dom_map_get_xmlht_length, + .get_item = dom_map_get_entity_item, + .get_named_item = dom_map_get_named_item_entity, + .has_named_item = dom_map_has_named_item_xmlht, + .use_cache = false, + .nameless = false, +}; + +const php_dom_obj_map_handler php_dom_obj_map_notations = { + .length = dom_map_get_xmlht_length, + .get_item = dom_map_get_notation_item, + .get_named_item = dom_map_get_named_item_notation, + .has_named_item = dom_map_has_named_item_xmlht, + .use_cache = false, + .nameless = false, +}; + +const php_dom_obj_map_handler php_dom_obj_map_noop = { + .length = dom_map_get_zero_length, + .get_item = dom_map_get_null_item, + .get_named_item = dom_map_get_named_item_null, + .has_named_item = dom_map_has_named_item_null, + .use_cache = false, + .nameless = true, +}; + +#endif diff --git a/ext/dom/obj_map.h b/ext/dom/obj_map.h new file mode 100644 index 0000000000000..511b71fcc7485 --- /dev/null +++ b/ext/dom/obj_map.h @@ -0,0 +1,39 @@ +/* + +----------------------------------------------------------------------+ + | 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: Niels Dossche | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHP_DOM_OBJ_MAP_H +#define PHP_DOM_OBJ_MAP_H + +typedef struct dom_nnodemap_object dom_nnodemap_object; + +typedef struct php_dom_obj_map_handler { + zend_long (*length)(dom_nnodemap_object *); + void (*get_item)(dom_nnodemap_object *, zend_long, zval *); + xmlNodePtr (*get_named_item)(dom_nnodemap_object *, const zend_string *, const char *); + bool (*has_named_item)(dom_nnodemap_object *, const zend_string *, const char *); + bool use_cache; + bool nameless; +} php_dom_obj_map_handler; + +extern const php_dom_obj_map_handler php_dom_obj_map_attributes; +extern const php_dom_obj_map_handler php_dom_obj_map_by_tag_name; +extern const php_dom_obj_map_handler php_dom_obj_map_child_nodes; +extern const php_dom_obj_map_handler php_dom_obj_map_nodeset; +extern const php_dom_obj_map_handler php_dom_obj_map_entities; +extern const php_dom_obj_map_handler php_dom_obj_map_notations; +extern const php_dom_obj_map_handler php_dom_obj_map_noop; + +#endif diff --git a/ext/dom/parentnode/css_selectors.c b/ext/dom/parentnode/css_selectors.c index e681d2b9073fe..10b517a248d46 100644 --- a/ext/dom/parentnode/css_selectors.c +++ b/ext/dom/parentnode/css_selectors.c @@ -249,7 +249,7 @@ void dom_parent_node_query_selector_all(xmlNodePtr thisp, dom_object *intern, zv dom_object *ret_obj = Z_DOMOBJ_P(return_value); dom_nnodemap_object *mapptr = (dom_nnodemap_object *) ret_obj->ptr; ZVAL_ARR(&mapptr->baseobj_zv, list); - mapptr->nodetype = DOM_NODESET; + mapptr->handler = &php_dom_obj_map_nodeset; } } diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c index b1f7eca80f104..d9ed01d2e7d6e 100644 --- a/ext/dom/php_dom.c +++ b/ext/dom/php_dom.c @@ -1456,7 +1456,8 @@ void dom_objects_free_storage(zend_object *object) } /* }}} */ -void dom_namednode_iter(dom_object *basenode, int ntype, dom_object *intern, xmlHashTablePtr ht, zend_string *local, zend_string *ns) /* {{{ */ +/* TODO: move me to obj_map.c */ +void dom_namednode_iter(dom_object *basenode, dom_object *intern, xmlHashTablePtr ht, zend_string *local, zend_string *ns, const php_dom_obj_map_handler *handler) /* {{{ */ { dom_nnodemap_object *mapptr = (dom_nnodemap_object *) intern->ptr; @@ -1466,8 +1467,8 @@ void dom_namednode_iter(dom_object *basenode, int ntype, dom_object *intern, xml xmlDocPtr doc = basenode->document ? basenode->document->ptr : NULL; + mapptr->handler = handler; mapptr->baseobj = basenode; - mapptr->nodetype = ntype; mapptr->ht = ht; if (EXPECTED(doc != NULL)) { mapptr->dict = doc->dict; @@ -1607,6 +1608,7 @@ zend_object *dom_nnodemap_objects_new(zend_class_entry *class_type) intern->ptr = ecalloc(1, sizeof(dom_nnodemap_object)); dom_nnodemap_object *objmap = intern->ptr; objmap->cached_length = -1; + objmap->handler = &php_dom_obj_map_noop; return &intern->std; } @@ -2380,7 +2382,7 @@ static zval *dom_nodemap_read_dimension(zend_object *object, zval *offset, int t zend_long lval; if (dom_nodemap_or_nodelist_process_offset_as_named(offset, &lval)) { /* exceptional case, switch to named lookup */ - php_dom_named_node_map_get_named_item_into_zval(php_dom_obj_from_obj(object)->ptr, Z_STR_P(offset), rv); + php_dom_named_node_map_get_named_item_into_zval(php_dom_obj_from_obj(object)->ptr, Z_STR_P(offset), NULL, rv); return rv; } @@ -2390,7 +2392,8 @@ static zval *dom_nodemap_read_dimension(zend_object *object, zval *offset, int t return NULL; } - php_dom_named_node_map_get_item_into_zval(php_dom_obj_from_obj(object)->ptr, lval, rv); + dom_nnodemap_object *map = php_dom_obj_from_obj(object)->ptr; + map->handler->get_item(map, lval, rv); return rv; } @@ -2404,7 +2407,8 @@ static int dom_nodemap_has_dimension(zend_object *object, zval *member, int chec zend_long offset; if (dom_nodemap_or_nodelist_process_offset_as_named(member, &offset)) { /* exceptional case, switch to named lookup */ - return php_dom_named_node_map_get_named_item(php_dom_obj_from_obj(object)->ptr, Z_STR_P(member), false) != NULL; + dom_nnodemap_object *map = php_dom_obj_from_obj(object)->ptr; + return map->handler->has_named_item(map, Z_STR_P(member), NULL); } return offset >= 0 && offset < php_dom_get_namednodemap_length(php_dom_obj_from_obj(object)); @@ -2423,14 +2427,14 @@ static zval *dom_modern_nodemap_read_dimension(zend_object *object, zval *offset if (Z_TYPE_P(offset) == IS_STRING) { zend_ulong lval; if (ZEND_HANDLE_NUMERIC(Z_STR_P(offset), lval)) { - php_dom_named_node_map_get_item_into_zval(map, (zend_long) lval, rv); + map->handler->get_item(map, (zend_long) lval, rv); } else { - php_dom_named_node_map_get_named_item_into_zval(map, Z_STR_P(offset), rv); + php_dom_named_node_map_get_named_item_into_zval(map, Z_STR_P(offset), NULL, rv); } } else if (Z_TYPE_P(offset) == IS_LONG) { - php_dom_named_node_map_get_item_into_zval(map, Z_LVAL_P(offset), rv); + map->handler->get_item(map, Z_LVAL_P(offset), rv); } else if (Z_TYPE_P(offset) == IS_DOUBLE) { - php_dom_named_node_map_get_item_into_zval(map, zend_dval_to_lval_safe(Z_DVAL_P(offset)), rv); + map->handler->get_item(map, zend_dval_to_lval_safe(Z_DVAL_P(offset)), rv); } else { zend_illegal_container_offset(object->ce->name, offset, type); return NULL; @@ -2453,7 +2457,7 @@ static int dom_modern_nodemap_has_dimension(zend_object *object, zval *member, i if (ZEND_HANDLE_NUMERIC(Z_STR_P(member), lval)) { return (zend_long) lval >= 0 && (zend_long) lval < php_dom_get_namednodemap_length(obj); } else { - return php_dom_named_node_map_get_named_item(map, Z_STR_P(member), false) != NULL; + return map->handler->has_named_item(map, Z_STR_P(member), NULL); } } else if (Z_TYPE_P(member) == IS_LONG) { zend_long offset = Z_LVAL_P(member); diff --git a/ext/dom/php_dom.h b/ext/dom/php_dom.h index ede77f08626cc..571f99cfe2be3 100644 --- a/ext/dom/php_dom.h +++ b/ext/dom/php_dom.h @@ -56,13 +56,12 @@ extern zend_module_entry dom_module_entry; #include "xpath_callbacks.h" #include "zend_exceptions.h" #include "dom_ce.h" +#include "obj_map.h" /* DOM API_VERSION, please bump it up, if you change anything in the API therefore it's easier for the script-programmers to check, what's working how Can be checked with phpversion("dom"); */ #define DOM_API_VERSION "20031129" -/* Define a custom type for iterating using an unused nodetype */ -#define DOM_NODESET XML_XINCLUDE_START typedef struct dom_xpath_object { php_dom_xpath_callbacks xpath_callbacks; @@ -80,7 +79,6 @@ static inline dom_xpath_object *php_xpath_obj_from_obj(zend_object *obj) { typedef struct dom_nnodemap_object { dom_object *baseobj; zval baseobj_zv; - int nodetype; int cached_length; xmlHashTable *ht; xmlChar *local; @@ -90,6 +88,7 @@ typedef struct dom_nnodemap_object { dom_object *cached_obj; zend_long cached_obj_index; xmlDictPtr dict; + const php_dom_obj_map_handler *handler; bool release_local : 1; bool release_ns : 1; } dom_nnodemap_object; @@ -146,9 +145,9 @@ int dom_hierarchy(xmlNodePtr parent, xmlNodePtr child); bool dom_has_feature(zend_string *feature, zend_string *version); bool dom_node_is_read_only(const xmlNode *node); bool dom_node_children_valid(const xmlNode *node); -void dom_namednode_iter(dom_object *basenode, int ntype, dom_object *intern, xmlHashTablePtr ht, zend_string *local, zend_string *ns); +void dom_namednode_iter(dom_object *basenode, dom_object *intern, xmlHashTablePtr ht, zend_string *local, zend_string *ns, const php_dom_obj_map_handler *handler); xmlNodePtr create_notation(const xmlChar *name, const xmlChar *ExternalID, const xmlChar *SystemID); -xmlNode *php_dom_libxml_hash_iter(dom_nnodemap_object *objmap, int index); +xmlNode *php_dom_libxml_hash_iter(xmlHashTable *ht, int index); zend_object_iterator *php_dom_get_iterator(zend_class_entry *ce, zval *object, int by_ref); void dom_set_doc_classmap(php_libxml_ref_obj *document, zend_class_entry *basece, zend_class_entry *ce); xmlNodePtr php_dom_create_fake_namespace_decl(xmlNodePtr nodep, xmlNsPtr original, zval *return_value, dom_object *parent_intern); @@ -211,10 +210,8 @@ void dom_element_closest(xmlNodePtr thisp, dom_object *intern, zval *return_valu xmlNodePtr dom_parse_fragment(dom_object *obj, xmlNodePtr context_node, const zend_string *input); /* nodemap and nodelist APIs */ -xmlNodePtr php_dom_named_node_map_get_named_item(dom_nnodemap_object *objmap, const zend_string *named, bool may_transform); -void php_dom_named_node_map_get_named_item_into_zval(dom_nnodemap_object *objmap, const zend_string *named, zval *return_value); +void php_dom_named_node_map_get_named_item_into_zval(dom_nnodemap_object *objmap, const zend_string *named, const char *ns, zval *return_value); xmlNodePtr php_dom_named_node_map_get_item(dom_nnodemap_object *objmap, zend_long index); -void php_dom_named_node_map_get_item_into_zval(dom_nnodemap_object *objmap, zend_long index, zval *return_value); zend_long php_dom_get_namednodemap_length(dom_object *obj); xmlNodePtr dom_nodelist_iter_start_first_child(xmlNodePtr nodep); diff --git a/ext/dom/tests/modern/spec/Document_importLegacyNode.phpt b/ext/dom/tests/modern/spec/Document_importLegacyNode.phpt index 8a6f324c3dc35..bc8c8fe050e4f 100644 --- a/ext/dom/tests/modern/spec/Document_importLegacyNode.phpt +++ b/ext/dom/tests/modern/spec/Document_importLegacyNode.phpt @@ -36,8 +36,8 @@ foreach ($new->getElementsByTagName('child') as $child) { echo $new->saveXml(), "\n"; ?> ---EXPECT-- -object(Dom\NamedNodeMap)#5 (1) { +--EXPECTF-- +object(Dom\NamedNodeMap)#%d (1) { ["length"]=> int(2) } @@ -47,7 +47,7 @@ namespaceURI: string(29) "http://www.w3.org/2000/xmlns/" name: string(1) "a" prefix: NULL namespaceURI: NULL -object(Dom\NamedNodeMap)#3 (1) { +object(Dom\NamedNodeMap)#%d (1) { ["length"]=> int(3) } diff --git a/ext/dom/tests/modern/spec/NamedNodeMap_dimensions.phpt b/ext/dom/tests/modern/spec/NamedNodeMap_dimensions.phpt index 38e00defe6223..cf446881559bc 100644 --- a/ext/dom/tests/modern/spec/NamedNodeMap_dimensions.phpt +++ b/ext/dom/tests/modern/spec/NamedNodeMap_dimensions.phpt @@ -22,7 +22,7 @@ foreach ($test_values as $value) { ?> --EXPECTF-- --- -1 --- -string(1) "a" +string(3) "N/A" bool(false) bool(true) --- 0 --- diff --git a/ext/dom/xpath.c b/ext/dom/xpath.c index 8707af1fa94cf..b410f7b264997 100644 --- a/ext/dom/xpath.c +++ b/ext/dom/xpath.c @@ -239,7 +239,7 @@ static void dom_xpath_iter(zval *baseobj, dom_object *intern) /* {{{ */ dom_nnodemap_object *mapptr = (dom_nnodemap_object *) intern->ptr; ZVAL_COPY_VALUE(&mapptr->baseobj_zv, baseobj); - mapptr->nodetype = DOM_NODESET; + mapptr->handler = &php_dom_obj_map_nodeset; } /* }}} */ From 0ab5f70b3cc9705873586657f9910a7dd7d466f4 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 21 Jun 2025 21:57:16 +0200 Subject: [PATCH 046/120] ext/spl: Remove bool type coercions in tests --- ext/spl/tests/bug36287.phpt | 2 +- ext/spl/tests/iterator_003.phpt | 2 +- ext/spl/tests/pqueue_001.phpt | 8 ++++---- ext/spl/tests/spl_003.phpt | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ext/spl/tests/bug36287.phpt b/ext/spl/tests/bug36287.phpt index 0fa6e1bc1eefd..8ea9123eb8a46 100644 --- a/ext/spl/tests/bug36287.phpt +++ b/ext/spl/tests/bug36287.phpt @@ -3,7 +3,7 @@ Bug #36287 (Segfault with SplFileInfo conversion) --FILE-- students->getIterator(), true); + return new CachingIterator($this->students->getIterator()); } } diff --git a/ext/spl/tests/pqueue_001.phpt b/ext/spl/tests/pqueue_001.phpt index 2b67ad4a2a247..a318487273eb7 100644 --- a/ext/spl/tests/pqueue_001.phpt +++ b/ext/spl/tests/pqueue_001.phpt @@ -16,7 +16,7 @@ $pq->insert("b", 2); $pq->insert("c", 0); foreach ($pq as $k=>$v) { - echo "$k=>".print_r($v, 1)."\n"; + echo "$k=>".print_r($v, true)."\n"; } echo "EXTR_BOTH\n"; @@ -29,7 +29,7 @@ $pq1->insert("b", 2); $pq1->insert("c", 0); foreach ($pq1 as $k=>$v) { - echo "$k=>".print_r($v, 1)."\n"; + echo "$k=>".print_r($v, true)."\n"; } echo "EXTR_DATA\n"; @@ -42,7 +42,7 @@ $pq2->insert("b", 2); $pq2->insert("c", 0); foreach ($pq2 as $k=>$v) { - echo "$k=>".print_r($v, 1)."\n"; + echo "$k=>".print_r($v, true)."\n"; } echo "EXTR_PRIORITY\n"; @@ -55,7 +55,7 @@ $pq3->insert("b", 2); $pq3->insert("c", 0); foreach ($pq3 as $k=>$v) { - echo "$k=>".print_r($v, 1)."\n"; + echo "$k=>".print_r($v, true)."\n"; } ?> diff --git a/ext/spl/tests/spl_003.phpt b/ext/spl/tests/spl_003.phpt index a9080c7298d25..f7e70db90f421 100644 --- a/ext/spl/tests/spl_003.phpt +++ b/ext/spl/tests/spl_003.phpt @@ -16,8 +16,8 @@ var_dump(class_parents(new c), class_parents(new b), class_parents("b"), class_parents("d"), - class_parents("foo", 0), - class_parents("foo", 1) + class_parents("foo", false), + class_parents("foo", true) ); interface iface1{} @@ -26,7 +26,7 @@ class f implements iface1, iface2{} var_dump(class_implements(new a), class_implements("a"), class_implements("aaa"), - class_implements("bbb", 0) + class_implements("bbb", false) ); ?> From 091308cb3e3ac8ddb4438d1c9ae1e67ca3492b9c Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 21 Jun 2025 22:01:49 +0200 Subject: [PATCH 047/120] ext/soap: Remove bool type coercions in tests --- .../tests/interop/Round4/GroupH/r4_groupH_soapfault_004w.phpt | 2 +- ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_030w.phpt | 2 +- ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_031w.phpt | 2 +- ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_032w.phpt | 2 +- ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_033w.phpt | 2 +- ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_034w.phpt | 2 +- ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_035w.phpt | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ext/soap/tests/interop/Round4/GroupH/r4_groupH_soapfault_004w.phpt b/ext/soap/tests/interop/Round4/GroupH/r4_groupH_soapfault_004w.phpt index 5c50cbc840345..69ba8880ad581 100644 --- a/ext/soap/tests/interop/Round4/GroupH/r4_groupH_soapfault_004w.phpt +++ b/ext/soap/tests/interop/Round4/GroupH/r4_groupH_soapfault_004w.phpt @@ -6,7 +6,7 @@ soap soap.wsdl_cache_enabled=0 --FILE-- 1,"exceptions"=>0)); $client->__soapCall("echoVersionMismatchFault",array(), null, $hdr); echo $client->__getlastrequest(); diff --git a/ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_030w.phpt b/ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_030w.phpt index 1812b7751190b..cc5c5e608a784 100644 --- a/ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_030w.phpt +++ b/ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_030w.phpt @@ -6,7 +6,7 @@ soap soap.wsdl_cache_enabled=0 --FILE-- "Hello World"), 1); +$hdr = new SoapHeader("http://soapinterop.org/","echoMeStringRequest", array("varString"=>"Hello World"), true); $client = new SoapClient(__DIR__."/round4_groupI_xsd.wsdl",array("trace"=>1,"exceptions"=>0)); $client->__soapCall("echoVoidSoapHeader",array(),null,$hdr); echo $client->__getlastrequest(); diff --git a/ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_031w.phpt b/ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_031w.phpt index 2b89e057e99cc..d0255f1de5479 100644 --- a/ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_031w.phpt +++ b/ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_031w.phpt @@ -6,7 +6,7 @@ soap soap.wsdl_cache_enabled=0 --FILE-- 1,"exceptions"=>0)); $client->__soapCall("echoVoidSoapHeader",array(),null,$hdr); echo $client->__getlastrequest(); diff --git a/ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_032w.phpt b/ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_032w.phpt index 508f3c0a32553..57b3292764c16 100644 --- a/ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_032w.phpt +++ b/ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_032w.phpt @@ -7,7 +7,7 @@ precision=14 soap.wsdl_cache_enabled=0 --FILE-- 34,"varString"=>"arg","varFloat"=>12.345), 1); +$hdr = new SoapHeader("http://soapinterop.org/","echoMeComplexTypeRequest", array("varInt"=>34,"varString"=>"arg","varFloat"=>12.345), true); $client = new SoapClient(__DIR__."/round4_groupI_xsd.wsdl",array("trace"=>1,"exceptions"=>0)); $client->__soapCall("echoVoidSoapHeader",array(),null,$hdr); echo $client->__getlastrequest(); diff --git a/ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_033w.phpt b/ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_033w.phpt index c2b47eeaa6918..677641c98153e 100644 --- a/ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_033w.phpt +++ b/ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_033w.phpt @@ -7,7 +7,7 @@ precision=14 soap.wsdl_cache_enabled=0 --FILE-- 34,"varFloat"=>12.345), 1); +$hdr = new SoapHeader("http://soapinterop.org/","echoMeComplexTypeRequest", array("varInt"=>34,"varFloat"=>12.345), true); $client = new SoapClient(__DIR__."/round4_groupI_xsd.wsdl",array("trace"=>1,"exceptions"=>0)); $client->__soapCall("echoVoidSoapHeader",array(),null,$hdr); echo $client->__getlastrequest(); diff --git a/ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_034w.phpt b/ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_034w.phpt index 2804699a3891c..cbb3b4ed34870 100644 --- a/ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_034w.phpt +++ b/ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_034w.phpt @@ -6,7 +6,7 @@ soap soap.wsdl_cache_enabled=0 --FILE-- "Hello World"), 1, SOAP_ACTOR_NEXT); +$hdr = new SoapHeader("http://soapinterop.org/","echoMeStringRequest", array("varString"=>"Hello World"), true, SOAP_ACTOR_NEXT); $client = new SoapClient(__DIR__."/round4_groupI_xsd.wsdl",array("trace"=>1,"exceptions"=>0)); $client->__soapCall("echoVoidSoapHeader",array(),null,$hdr); echo $client->__getlastrequest(); diff --git a/ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_035w.phpt b/ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_035w.phpt index 75eb891533b34..0e2674c9bf4e8 100644 --- a/ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_035w.phpt +++ b/ext/soap/tests/interop/Round4/GroupI/r4_groupI_xsd_035w.phpt @@ -7,7 +7,7 @@ precision=14 soap.wsdl_cache_enabled=0 --FILE-- 34,"varString"=>"arg","varFloat"=>12.345), 1, SOAP_ACTOR_NEXT); +$hdr = new SoapHeader("http://soapinterop.org/","echoMeComplexTypeRequest", array("varInt"=>34,"varString"=>"arg","varFloat"=>12.345), true, SOAP_ACTOR_NEXT); $client = new SoapClient(__DIR__."/round4_groupI_xsd.wsdl",array("trace"=>1,"exceptions"=>0)); $client->__soapCall("echoVoidSoapHeader",array(),null,$hdr); echo $client->__getlastrequest(); From 8316ff2b0a75cbb76f7fc4152d8f5b63f3873161 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 21 Jun 2025 22:05:53 +0200 Subject: [PATCH 048/120] ext/dba: Remove bool type coercions in tests --- ext/dba/tests/dba_handlers.phpt | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/ext/dba/tests/dba_handlers.phpt b/ext/dba/tests/dba_handlers.phpt index b0dd54242370a..bc00d2ec6d4ce 100644 --- a/ext/dba/tests/dba_handlers.phpt +++ b/ext/dba/tests/dba_handlers.phpt @@ -37,12 +37,8 @@ echo "Test 2\n"; check(dba_handlers(false)); -echo "Test 3\n"; - -check(dba_handlers(0)); - -echo "Test 4 - full info\n"; -$h = dba_handlers(1); +echo "Test 3 - full info\n"; +$h = dba_handlers(true); foreach ($h as $key => $val) { if ($key === "flatfile") { echo "Success: flatfile enabled\n"; @@ -60,7 +56,5 @@ Test 1 Success: flatfile enabled Test 2 Success: flatfile enabled -Test 3 -Success: flatfile enabled -Test 4 - full info +Test 3 - full info Success: flatfile enabled From 5f3e10de8bb4c0171a361e6e2565fbeaad282b6f Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 21 Jun 2025 22:07:16 +0200 Subject: [PATCH 049/120] ext/bz2: Remove bool type coercions in tests --- ext/bz2/tests/005.phpt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ext/bz2/tests/005.phpt b/ext/bz2/tests/005.phpt index d32d5b687f0f5..8a715787f31d0 100644 --- a/ext/bz2/tests/005.phpt +++ b/ext/bz2/tests/005.phpt @@ -18,12 +18,12 @@ $data2 = bzcompress($string, 1, 10); $data3 = $data2; $data3[3] = 0; -var_dump(bzdecompress(1,1)); +var_dump(bzdecompress(1, true)); var_dump(bzdecompress($data3)); -var_dump(bzdecompress($data3,1)); +var_dump(bzdecompress($data3, true)); -var_dump(bzdecompress($data, 0)); -var_dump(bzdecompress($data, 1)); +var_dump(bzdecompress($data, false)); +var_dump(bzdecompress($data, true)); var_dump(bzdecompress($data)); var_dump(bzdecompress($data2)); From fa81a231385495d440f879234c8110715cc82020 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 21 Jun 2025 22:07:54 +0200 Subject: [PATCH 050/120] ext/exif: Remove bool type coercions in tests --- ext/exif/tests/bug72627.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/exif/tests/bug72627.phpt b/ext/exif/tests/bug72627.phpt index 179619ff72349..b0bc50777bba7 100644 --- a/ext/exif/tests/bug72627.phpt +++ b/ext/exif/tests/bug72627.phpt @@ -4,7 +4,7 @@ Bug #72627 (Memory Leakage In exif_process_IFD_in_TIFF) exif --FILE-- --EXPECTF-- From 37549e4563af40cf46484c3d9174403c85a94bb4 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 21 Jun 2025 22:11:42 +0200 Subject: [PATCH 051/120] ext/gmp: Remove bool type coercions in tests --- ext/gmp/tests/gmp_setbit.phpt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ext/gmp/tests/gmp_setbit.phpt b/ext/gmp/tests/gmp_setbit.phpt index 70b9e50694823..775042ef9737f 100644 --- a/ext/gmp/tests/gmp_setbit.phpt +++ b/ext/gmp/tests/gmp_setbit.phpt @@ -6,30 +6,30 @@ gmp getMessage() . \PHP_EOL; } var_dump(gmp_strval($n)); $n = gmp_init(5); -gmp_setbit($n, 2, 0); +gmp_setbit($n, 2, false); var_dump(gmp_strval($n)); $n = gmp_init(5); -gmp_setbit($n, 1, 1); +gmp_setbit($n, 1, true); var_dump(gmp_strval($n)); $n = gmp_init("100000000000"); -gmp_setbit($n, 23, 1); +gmp_setbit($n, 23, true); var_dump(gmp_strval($n)); -gmp_setbit($n, 23, 0); +gmp_setbit($n, 23, false); var_dump(gmp_strval($n)); gmp_setbit($n, 3); From 8526de84a504cc3fead9a1734ea663e8fd2669f3 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 21 Jun 2025 22:32:11 +0200 Subject: [PATCH 052/120] Move common obj_map API functions to obj_map.c --- ext/dom/documenttype.c | 5 ++- ext/dom/dom_iterators.c | 2 +- ext/dom/element.c | 6 +-- ext/dom/html_collection.c | 3 +- ext/dom/namednodemap.c | 15 ++------ ext/dom/node.c | 5 ++- ext/dom/nodelist.c | 14 ++----- ext/dom/nodelist.h | 2 - ext/dom/obj_map.c | 61 ++++++++++++++++++++++++++++++ ext/dom/obj_map.h | 34 ++++++++++++++--- ext/dom/parentnode/css_selectors.c | 1 + ext/dom/php_dom.c | 51 ++----------------------- ext/dom/php_dom.h | 22 +---------- ext/dom/xpath.c | 2 +- 14 files changed, 114 insertions(+), 109 deletions(-) diff --git a/ext/dom/documenttype.c b/ext/dom/documenttype.c index 895a34cebf650..63da0306649a9 100644 --- a/ext/dom/documenttype.c +++ b/ext/dom/documenttype.c @@ -22,6 +22,7 @@ #include "php.h" #if defined(HAVE_LIBXML) && defined(HAVE_DOM) #include "php_dom.h" +#include "obj_map.h" #include "dom_properties.h" #include "internal_helpers.h" @@ -53,7 +54,7 @@ zend_result dom_documenttype_entities_read(dom_object *obj, zval *retval) xmlHashTable *entityht = (xmlHashTable *) dtdptr->entities; dom_object *intern = Z_DOMOBJ_P(retval); - dom_namednode_iter(obj, intern, entityht, NULL, NULL, &php_dom_obj_map_entities); + php_dom_create_obj_map(obj, intern, entityht, NULL, NULL, &php_dom_obj_map_entities); return SUCCESS; } @@ -74,7 +75,7 @@ zend_result dom_documenttype_notations_read(dom_object *obj, zval *retval) xmlHashTable *notationht = (xmlHashTable *) dtdptr->notations; dom_object *intern = Z_DOMOBJ_P(retval); - dom_namednode_iter(obj, intern, notationht, NULL, NULL, &php_dom_obj_map_notations); + php_dom_create_obj_map(obj, intern, notationht, NULL, NULL, &php_dom_obj_map_notations); return SUCCESS; } diff --git a/ext/dom/dom_iterators.c b/ext/dom/dom_iterators.c index 19c4ea41adadb..90e973723f6c6 100644 --- a/ext/dom/dom_iterators.c +++ b/ext/dom/dom_iterators.c @@ -22,7 +22,7 @@ #include "php.h" #if defined(HAVE_LIBXML) && defined(HAVE_DOM) #include "php_dom.h" -#include "dom_ce.h" +#include "obj_map.h" typedef struct nodeIterator { int cur; diff --git a/ext/dom/element.c b/ext/dom/element.c index d0fc0b4a4d3e2..27e2845c9f0cb 100644 --- a/ext/dom/element.c +++ b/ext/dom/element.c @@ -23,8 +23,8 @@ #if defined(HAVE_LIBXML) && defined(HAVE_DOM) #include "zend_enum.h" #include "php_dom.h" +#include "obj_map.h" #include "namespace_compat.h" -#include "private_data.h" #include "internal_helpers.h" #include "dom_properties.h" #include "token_list.h" @@ -825,7 +825,7 @@ static void dom_element_get_elements_by_tag_name(INTERNAL_FUNCTION_PARAMETERS, z object_init_ex(return_value, iter_ce); namednode = Z_DOMOBJ_P(return_value); - dom_namednode_iter(intern, namednode, NULL, name, NULL, &php_dom_obj_map_by_tag_name); + php_dom_create_obj_map(intern, namednode, NULL, name, NULL, &php_dom_obj_map_by_tag_name); } PHP_METHOD(DOMElement, getElementsByTagName) @@ -1257,7 +1257,7 @@ static void dom_element_get_elements_by_tag_name_ns(INTERNAL_FUNCTION_PARAMETERS object_init_ex(return_value, iter_ce); namednode = Z_DOMOBJ_P(return_value); - dom_namednode_iter(intern, namednode, NULL, name, uri, &php_dom_obj_map_by_tag_name); + php_dom_create_obj_map(intern, namednode, NULL, name, uri, &php_dom_obj_map_by_tag_name); } PHP_METHOD(DOMElement, getElementsByTagNameNS) diff --git a/ext/dom/html_collection.c b/ext/dom/html_collection.c index e4c0446016685..e5dca84de75ff 100644 --- a/ext/dom/html_collection.c +++ b/ext/dom/html_collection.c @@ -21,6 +21,7 @@ #include "php.h" #if defined(HAVE_LIBXML) && defined(HAVE_DOM) #include "php_dom.h" +#include "obj_map.h" #include "nodelist.h" #include "html_collection.h" #include "namespace_compat.h" @@ -115,7 +116,7 @@ zval *dom_html_collection_read_dimension(zend_object *object, zval *offset, int dom_html_collection_named_item_into_zval(rv, index.str, object); } else { ZEND_ASSERT(index.type == DOM_NODELIST_DIM_LONG); - php_dom_nodelist_get_item_into_zval(php_dom_obj_from_obj(object)->ptr, index.lval, rv); + php_dom_obj_map_get_item_into_zval(php_dom_obj_from_obj(object)->ptr, index.lval, rv); } return rv; diff --git a/ext/dom/namednodemap.c b/ext/dom/namednodemap.c index 2f8f6d10132c2..953731ad84487 100644 --- a/ext/dom/namednodemap.c +++ b/ext/dom/namednodemap.c @@ -22,6 +22,7 @@ #include "php.h" #if defined(HAVE_LIBXML) && defined(HAVE_DOM) #include "php_dom.h" +#include "obj_map.h" #include "zend_interfaces.h" /* @@ -54,16 +55,6 @@ zend_result dom_namednodemap_length_read(dom_object *obj, zval *retval) /* }}} */ -void php_dom_named_node_map_get_named_item_into_zval(dom_nnodemap_object *objmap, const zend_string *named, const char *ns, zval *return_value) -{ - xmlNodePtr itemnode = objmap->handler->get_named_item(objmap, named, ns); - if (itemnode) { - DOM_RET_OBJ(itemnode, objmap->baseobj); - } else { - RETURN_NULL(); - } -} - /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1074577549 Since: */ @@ -76,7 +67,7 @@ PHP_METHOD(DOMNamedNodeMap, getNamedItem) } dom_nnodemap_object *objmap = Z_DOMOBJ_P(ZEND_THIS)->ptr; - php_dom_named_node_map_get_named_item_into_zval(objmap, named, NULL, return_value); + php_dom_obj_map_get_named_item_into_zval(objmap, named, NULL, return_value); } /* }}} end dom_namednodemap_get_named_item */ @@ -121,7 +112,7 @@ PHP_METHOD(DOMNamedNodeMap, getNamedItemNS) objmap = (dom_nnodemap_object *)intern->ptr; if (objmap != NULL) { - php_dom_named_node_map_get_named_item_into_zval(objmap, named, uri, return_value); + php_dom_obj_map_get_named_item_into_zval(objmap, named, uri, return_value); } } /* }}} end dom_namednodemap_get_named_item_ns */ diff --git a/ext/dom/node.c b/ext/dom/node.c index 99069d778ebfe..dba4bb8db87cd 100644 --- a/ext/dom/node.c +++ b/ext/dom/node.c @@ -22,6 +22,7 @@ #include "php.h" #if defined(HAVE_LIBXML) && defined(HAVE_DOM) #include "php_dom.h" +#include "obj_map.h" #include "namespace_compat.h" #include "private_data.h" #include "internal_helpers.h" @@ -288,7 +289,7 @@ zend_result dom_node_child_nodes_read(dom_object *obj, zval *retval) object_init_ex(retval, dom_get_nodelist_ce(php_dom_follow_spec_intern(obj))); dom_object *intern = Z_DOMOBJ_P(retval); - dom_namednode_iter(obj, intern, NULL, NULL, NULL, &php_dom_obj_map_child_nodes); + php_dom_create_obj_map(obj, intern, NULL, NULL, NULL, &php_dom_obj_map_child_nodes); return SUCCESS; } @@ -422,7 +423,7 @@ zend_result dom_node_attributes_read(dom_object *obj, zval *retval) if (nodep->type == XML_ELEMENT_NODE) { object_init_ex(retval, dom_get_namednodemap_ce(php_dom_follow_spec_intern(obj))); dom_object *intern = Z_DOMOBJ_P(retval); - dom_namednode_iter(obj, intern, NULL, NULL, NULL, &php_dom_obj_map_attributes); + php_dom_create_obj_map(obj, intern, NULL, NULL, NULL, &php_dom_obj_map_attributes); } else { ZVAL_NULL(retval); } diff --git a/ext/dom/nodelist.c b/ext/dom/nodelist.c index 46a10a362a071..5e3de728e4fae 100644 --- a/ext/dom/nodelist.c +++ b/ext/dom/nodelist.c @@ -22,6 +22,7 @@ #include "php.h" #if defined(HAVE_LIBXML) && defined(HAVE_DOM) #include "php_dom.h" +#include "obj_map.h" #include "nodelist.h" #include "zend_interfaces.h" @@ -63,15 +64,6 @@ PHP_METHOD(DOMNodeList, count) } /* }}} end dom_nodelist_count */ -void php_dom_nodelist_get_item_into_zval(dom_nnodemap_object *objmap, zend_long index, zval *return_value) -{ - if (EXPECTED(objmap)) { - objmap->handler->get_item(objmap, index, return_value); - } else { - RETURN_NULL(); - } -} - /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#ID-844377136 Since: */ @@ -85,7 +77,7 @@ PHP_METHOD(DOMNodeList, item) zval *id = ZEND_THIS; dom_object *intern = Z_DOMOBJ_P(id); dom_nnodemap_object *objmap = intern->ptr; - php_dom_nodelist_get_item_into_zval(objmap, index, return_value); + php_dom_obj_map_get_item_into_zval(objmap, index, return_value); } /* }}} end dom_nodelist_item */ @@ -136,7 +128,7 @@ zval *dom_modern_nodelist_read_dimension(zend_object *object, zval *offset, int return NULL; } - php_dom_nodelist_get_item_into_zval(php_dom_obj_from_obj(object)->ptr, index.lval, rv); + php_dom_obj_map_get_item_into_zval(php_dom_obj_from_obj(object)->ptr, index.lval, rv); return rv; } diff --git a/ext/dom/nodelist.h b/ext/dom/nodelist.h index 5ac3de1e46c44..5c5653eea6dce 100644 --- a/ext/dom/nodelist.h +++ b/ext/dom/nodelist.h @@ -31,8 +31,6 @@ typedef struct dom_nodelist_dimension_index { enum dom_nodelist_dimension_index_type type; } dom_nodelist_dimension_index; -void php_dom_nodelist_get_item_into_zval(dom_nnodemap_object *objmap, zend_long index, zval *return_value); -zend_long php_dom_get_nodelist_length(dom_object *obj); dom_nodelist_dimension_index dom_modern_nodelist_get_index(const zval *offset); zval *dom_modern_nodelist_read_dimension(zend_object *object, zval *offset, int type, zval *rv); int dom_modern_nodelist_has_dimension(zend_object *object, zval *member, int check_empty); diff --git a/ext/dom/obj_map.c b/ext/dom/obj_map.c index f2a93fe3ef870..c92a5834f3c9e 100644 --- a/ext/dom/obj_map.c +++ b/ext/dom/obj_map.c @@ -288,6 +288,67 @@ zend_long php_dom_get_nodelist_length(dom_object *obj) return count; } +void php_dom_create_obj_map(dom_object *basenode, dom_object *intern, xmlHashTablePtr ht, zend_string *local, zend_string *ns, const php_dom_obj_map_handler *handler) +{ + dom_nnodemap_object *mapptr = intern->ptr; + + ZEND_ASSERT(basenode != NULL); + + ZVAL_OBJ_COPY(&mapptr->baseobj_zv, &basenode->std); + + xmlDocPtr doc = basenode->document ? basenode->document->ptr : NULL; + + mapptr->handler = handler; + mapptr->baseobj = basenode; + mapptr->ht = ht; + if (EXPECTED(doc != NULL)) { + mapptr->dict = doc->dict; + xmlDictReference(doc->dict); + } + + const xmlChar* tmp; + + if (local) { + int len = (int) ZSTR_LEN(local); + if (doc != NULL && (tmp = xmlDictExists(doc->dict, (const xmlChar *)ZSTR_VAL(local), len)) != NULL) { + mapptr->local = BAD_CAST tmp; + } else { + mapptr->local = BAD_CAST ZSTR_VAL(zend_string_copy(local)); + mapptr->release_local = true; + } + mapptr->local_lower = zend_string_tolower(local); + } + + if (ns) { + int len = (int) ZSTR_LEN(ns); + if (doc != NULL && (tmp = xmlDictExists(doc->dict, (const xmlChar *)ZSTR_VAL(ns), len)) != NULL) { + mapptr->ns = BAD_CAST tmp; + } else { + mapptr->ns = BAD_CAST ZSTR_VAL(zend_string_copy(ns)); + mapptr->release_ns = true; + } + } +} + +void php_dom_obj_map_get_item_into_zval(dom_nnodemap_object *objmap, zend_long index, zval *return_value) +{ + if (EXPECTED(objmap)) { + objmap->handler->get_item(objmap, index, return_value); + } else { + RETURN_NULL(); + } +} + +void php_dom_obj_map_get_named_item_into_zval(dom_nnodemap_object *objmap, const zend_string *named, const char *ns, zval *return_value) +{ + xmlNodePtr itemnode = objmap->handler->get_named_item(objmap, named, ns); + if (itemnode) { + DOM_RET_OBJ(itemnode, objmap->baseobj); + } else { + RETURN_NULL(); + } +} + /********************** * === Named item === * **********************/ diff --git a/ext/dom/obj_map.h b/ext/dom/obj_map.h index 511b71fcc7485..70b6fdd107b49 100644 --- a/ext/dom/obj_map.h +++ b/ext/dom/obj_map.h @@ -20,14 +20,36 @@ typedef struct dom_nnodemap_object dom_nnodemap_object; typedef struct php_dom_obj_map_handler { - zend_long (*length)(dom_nnodemap_object *); - void (*get_item)(dom_nnodemap_object *, zend_long, zval *); - xmlNodePtr (*get_named_item)(dom_nnodemap_object *, const zend_string *, const char *); - bool (*has_named_item)(dom_nnodemap_object *, const zend_string *, const char *); - bool use_cache; - bool nameless; + zend_long (*length)(dom_nnodemap_object *); + void (*get_item)(dom_nnodemap_object *, zend_long, zval *); + xmlNodePtr (*get_named_item)(dom_nnodemap_object *, const zend_string *, const char *); + bool (*has_named_item)(dom_nnodemap_object *, const zend_string *, const char *); + bool use_cache; + bool nameless; } php_dom_obj_map_handler; +typedef struct dom_nnodemap_object { + dom_object *baseobj; + zval baseobj_zv; + int cached_length; + xmlHashTable *ht; + xmlChar *local; + zend_string *local_lower; + xmlChar *ns; + php_libxml_cache_tag cache_tag; + dom_object *cached_obj; + zend_long cached_obj_index; + xmlDictPtr dict; + const php_dom_obj_map_handler *handler; + bool release_local : 1; + bool release_ns : 1; +} dom_nnodemap_object; + +void php_dom_create_obj_map(dom_object *basenode, dom_object *intern, xmlHashTablePtr ht, zend_string *local, zend_string *ns, const php_dom_obj_map_handler *handler); +void php_dom_obj_map_get_named_item_into_zval(dom_nnodemap_object *objmap, const zend_string *named, const char *ns, zval *return_value); +void php_dom_obj_map_get_item_into_zval(dom_nnodemap_object *objmap, zend_long index, zval *return_value); +zend_long php_dom_get_nodelist_length(dom_object *obj); + extern const php_dom_obj_map_handler php_dom_obj_map_attributes; extern const php_dom_obj_map_handler php_dom_obj_map_by_tag_name; extern const php_dom_obj_map_handler php_dom_obj_map_child_nodes; diff --git a/ext/dom/parentnode/css_selectors.c b/ext/dom/parentnode/css_selectors.c index 10b517a248d46..b9d2edee723bc 100644 --- a/ext/dom/parentnode/css_selectors.c +++ b/ext/dom/parentnode/css_selectors.c @@ -21,6 +21,7 @@ #include "php.h" #if defined(HAVE_LIBXML) && defined(HAVE_DOM) #include "../php_dom.h" +#include "../obj_map.h" #include "ext/lexbor/lexbor/css/parser.h" #include "../lexbor/selectors-adapted/selectors.h" diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c index d9ed01d2e7d6e..e71e4e259c304 100644 --- a/ext/dom/php_dom.c +++ b/ext/dom/php_dom.c @@ -24,6 +24,7 @@ #if defined(HAVE_LIBXML) && defined(HAVE_DOM) #include "zend_enum.h" #include "php_dom.h" +#include "obj_map.h" #include "nodelist.h" #include "html_collection.h" #include "namespace_compat.h" @@ -1456,50 +1457,6 @@ void dom_objects_free_storage(zend_object *object) } /* }}} */ -/* TODO: move me to obj_map.c */ -void dom_namednode_iter(dom_object *basenode, dom_object *intern, xmlHashTablePtr ht, zend_string *local, zend_string *ns, const php_dom_obj_map_handler *handler) /* {{{ */ -{ - dom_nnodemap_object *mapptr = (dom_nnodemap_object *) intern->ptr; - - ZEND_ASSERT(basenode != NULL); - - ZVAL_OBJ_COPY(&mapptr->baseobj_zv, &basenode->std); - - xmlDocPtr doc = basenode->document ? basenode->document->ptr : NULL; - - mapptr->handler = handler; - mapptr->baseobj = basenode; - mapptr->ht = ht; - if (EXPECTED(doc != NULL)) { - mapptr->dict = doc->dict; - xmlDictReference(doc->dict); - } - - const xmlChar* tmp; - - if (local) { - int len = (int) ZSTR_LEN(local); - if (doc != NULL && (tmp = xmlDictExists(doc->dict, (const xmlChar *)ZSTR_VAL(local), len)) != NULL) { - mapptr->local = BAD_CAST tmp; - } else { - mapptr->local = BAD_CAST ZSTR_VAL(zend_string_copy(local)); - mapptr->release_local = true; - } - mapptr->local_lower = zend_string_tolower(local); - } - - if (ns) { - int len = (int) ZSTR_LEN(ns); - if (doc != NULL && (tmp = xmlDictExists(doc->dict, (const xmlChar *)ZSTR_VAL(ns), len)) != NULL) { - mapptr->ns = BAD_CAST tmp; - } else { - mapptr->ns = BAD_CAST ZSTR_VAL(zend_string_copy(ns)); - mapptr->release_ns = true; - } - } -} -/* }}} */ - static void dom_objects_set_class_ex(zend_class_entry *class_type, dom_object *intern) { zend_class_entry *base_class = class_type; @@ -2294,7 +2251,7 @@ static zval *dom_nodelist_read_dimension(zend_object *object, zval *offset, int return rv; } - php_dom_nodelist_get_item_into_zval(php_dom_obj_from_obj(object)->ptr, lval, rv); + php_dom_obj_map_get_item_into_zval(php_dom_obj_from_obj(object)->ptr, lval, rv); return rv; } @@ -2382,7 +2339,7 @@ static zval *dom_nodemap_read_dimension(zend_object *object, zval *offset, int t zend_long lval; if (dom_nodemap_or_nodelist_process_offset_as_named(offset, &lval)) { /* exceptional case, switch to named lookup */ - php_dom_named_node_map_get_named_item_into_zval(php_dom_obj_from_obj(object)->ptr, Z_STR_P(offset), NULL, rv); + php_dom_obj_map_get_named_item_into_zval(php_dom_obj_from_obj(object)->ptr, Z_STR_P(offset), NULL, rv); return rv; } @@ -2429,7 +2386,7 @@ static zval *dom_modern_nodemap_read_dimension(zend_object *object, zval *offset if (ZEND_HANDLE_NUMERIC(Z_STR_P(offset), lval)) { map->handler->get_item(map, (zend_long) lval, rv); } else { - php_dom_named_node_map_get_named_item_into_zval(map, Z_STR_P(offset), NULL, rv); + php_dom_obj_map_get_named_item_into_zval(map, Z_STR_P(offset), NULL, rv); } } else if (Z_TYPE_P(offset) == IS_LONG) { map->handler->get_item(map, Z_LVAL_P(offset), rv); diff --git a/ext/dom/php_dom.h b/ext/dom/php_dom.h index 571f99cfe2be3..0ff8692c4cc74 100644 --- a/ext/dom/php_dom.h +++ b/ext/dom/php_dom.h @@ -56,7 +56,7 @@ extern zend_module_entry dom_module_entry; #include "xpath_callbacks.h" #include "zend_exceptions.h" #include "dom_ce.h" -#include "obj_map.h" + /* DOM API_VERSION, please bump it up, if you change anything in the API therefore it's easier for the script-programmers to check, what's working how Can be checked with phpversion("dom"); @@ -76,23 +76,6 @@ static inline dom_xpath_object *php_xpath_obj_from_obj(zend_object *obj) { #define Z_XPATHOBJ_P(zv) php_xpath_obj_from_obj(Z_OBJ_P((zv))) -typedef struct dom_nnodemap_object { - dom_object *baseobj; - zval baseobj_zv; - int cached_length; - xmlHashTable *ht; - xmlChar *local; - zend_string *local_lower; - xmlChar *ns; - php_libxml_cache_tag cache_tag; - dom_object *cached_obj; - zend_long cached_obj_index; - xmlDictPtr dict; - const php_dom_obj_map_handler *handler; - bool release_local : 1; - bool release_ns : 1; -} dom_nnodemap_object; - typedef struct { zend_object_iterator intern; zval curobj; @@ -145,7 +128,6 @@ int dom_hierarchy(xmlNodePtr parent, xmlNodePtr child); bool dom_has_feature(zend_string *feature, zend_string *version); bool dom_node_is_read_only(const xmlNode *node); bool dom_node_children_valid(const xmlNode *node); -void dom_namednode_iter(dom_object *basenode, dom_object *intern, xmlHashTablePtr ht, zend_string *local, zend_string *ns, const php_dom_obj_map_handler *handler); xmlNodePtr create_notation(const xmlChar *name, const xmlChar *ExternalID, const xmlChar *SystemID); xmlNode *php_dom_libxml_hash_iter(xmlHashTable *ht, int index); zend_object_iterator *php_dom_get_iterator(zend_class_entry *ce, zval *object, int by_ref); @@ -210,8 +192,6 @@ void dom_element_closest(xmlNodePtr thisp, dom_object *intern, zval *return_valu xmlNodePtr dom_parse_fragment(dom_object *obj, xmlNodePtr context_node, const zend_string *input); /* nodemap and nodelist APIs */ -void php_dom_named_node_map_get_named_item_into_zval(dom_nnodemap_object *objmap, const zend_string *named, const char *ns, zval *return_value); -xmlNodePtr php_dom_named_node_map_get_item(dom_nnodemap_object *objmap, zend_long index); zend_long php_dom_get_namednodemap_length(dom_object *obj); xmlNodePtr dom_nodelist_iter_start_first_child(xmlNodePtr nodep); diff --git a/ext/dom/xpath.c b/ext/dom/xpath.c index b410f7b264997..ebf61f10e80bf 100644 --- a/ext/dom/xpath.c +++ b/ext/dom/xpath.c @@ -22,8 +22,8 @@ #include "php.h" #if defined(HAVE_LIBXML) && defined(HAVE_DOM) #include "php_dom.h" +#include "obj_map.h" #include "namespace_compat.h" -#include "private_data.h" #include "internal_helpers.h" #define PHP_DOM_XPATH_QUERY 0 From 26aea0ed3780382490d51c7ab5859af4ae55bdd9 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 21 Jun 2025 22:34:23 +0200 Subject: [PATCH 053/120] Tweak sizes of some dom_nnodemap_object fields We don't have to pack the bools, and the cached index would better be a zend_long so we don't get implicit narrowing. --- ext/dom/obj_map.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/dom/obj_map.h b/ext/dom/obj_map.h index 70b6fdd107b49..b1649999fbf16 100644 --- a/ext/dom/obj_map.h +++ b/ext/dom/obj_map.h @@ -31,7 +31,7 @@ typedef struct php_dom_obj_map_handler { typedef struct dom_nnodemap_object { dom_object *baseobj; zval baseobj_zv; - int cached_length; + zend_long cached_length; xmlHashTable *ht; xmlChar *local; zend_string *local_lower; @@ -41,8 +41,8 @@ typedef struct dom_nnodemap_object { zend_long cached_obj_index; xmlDictPtr dict; const php_dom_obj_map_handler *handler; - bool release_local : 1; - bool release_ns : 1; + bool release_local; + bool release_ns; } dom_nnodemap_object; void php_dom_create_obj_map(dom_object *basenode, dom_object *intern, xmlHashTablePtr ht, zend_string *local, zend_string *ns, const php_dom_obj_map_handler *handler); From 873634278200d6b617bc135e224f36a8379ba410 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 21 Jun 2025 22:38:01 +0200 Subject: [PATCH 054/120] Pack dom_nnodemap_object fields together with a union that can't be active at the same time --- ext/dom/obj_map.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ext/dom/obj_map.h b/ext/dom/obj_map.h index b1649999fbf16..4935799564286 100644 --- a/ext/dom/obj_map.h +++ b/ext/dom/obj_map.h @@ -32,10 +32,14 @@ typedef struct dom_nnodemap_object { dom_object *baseobj; zval baseobj_zv; zend_long cached_length; - xmlHashTable *ht; - xmlChar *local; - zend_string *local_lower; - xmlChar *ns; + union { + xmlHashTable *ht; + struct { + xmlChar *local; + zend_string *local_lower; + xmlChar *ns; + }; + }; php_libxml_cache_tag cache_tag; dom_object *cached_obj; zend_long cached_obj_index; From 479e9be45d7ca51e7cb09663c9e36d45fcd10960 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 21 Jun 2025 23:13:04 +0200 Subject: [PATCH 055/120] Store hash table entry directly in dom_nnodemap_object Splits the purpose of the baseobj_zv: now no longer either is an array or an object. Stores the hash table pointer directly, if used. --- ext/dom/obj_map.c | 8 +++----- ext/dom/obj_map.h | 3 ++- ext/dom/parentnode/css_selectors.c | 3 ++- ext/dom/php_dom.c | 7 +++++-- ext/dom/xpath.c | 18 ++++++++---------- 5 files changed, 20 insertions(+), 19 deletions(-) diff --git a/ext/dom/obj_map.c b/ext/dom/obj_map.c index c92a5834f3c9e..12407a560112e 100644 --- a/ext/dom/obj_map.c +++ b/ext/dom/obj_map.c @@ -55,8 +55,7 @@ static zend_long dom_map_get_xmlht_length(dom_nnodemap_object *map) static zend_long dom_map_get_nodeset_length(dom_nnodemap_object *map) { - HashTable *nodeht = Z_ARRVAL(map->baseobj_zv); - return zend_hash_num_elements(nodeht); + return zend_hash_num_elements(map->array); } static zend_long dom_map_get_prop_length(dom_nnodemap_object *map) @@ -132,8 +131,7 @@ static void dom_map_get_notation_item(dom_nnodemap_object *map, zend_long index, static void dom_map_get_nodeset_item(dom_nnodemap_object *map, zend_long index, zval *return_value) { - HashTable *nodeht = Z_ARRVAL(map->baseobj_zv); - zval *entry = zend_hash_index_find(nodeht, index); + zval *entry = zend_hash_index_find(map->array, index); if (entry) { RETURN_COPY(entry); } else { @@ -294,7 +292,7 @@ void php_dom_create_obj_map(dom_object *basenode, dom_object *intern, xmlHashTab ZEND_ASSERT(basenode != NULL); - ZVAL_OBJ_COPY(&mapptr->baseobj_zv, &basenode->std); + GC_ADDREF(&basenode->std); xmlDocPtr doc = basenode->document ? basenode->document->ptr : NULL; diff --git a/ext/dom/obj_map.h b/ext/dom/obj_map.h index 4935799564286..e1de9addd98f2 100644 --- a/ext/dom/obj_map.h +++ b/ext/dom/obj_map.h @@ -30,10 +30,10 @@ typedef struct php_dom_obj_map_handler { typedef struct dom_nnodemap_object { dom_object *baseobj; - zval baseobj_zv; zend_long cached_length; union { xmlHashTable *ht; + HashTable *array; struct { xmlChar *local; zend_string *local_lower; @@ -47,6 +47,7 @@ typedef struct dom_nnodemap_object { const php_dom_obj_map_handler *handler; bool release_local; bool release_ns; + bool release_array; } dom_nnodemap_object; void php_dom_create_obj_map(dom_object *basenode, dom_object *intern, xmlHashTablePtr ht, zend_string *local, zend_string *ns, const php_dom_obj_map_handler *handler); diff --git a/ext/dom/parentnode/css_selectors.c b/ext/dom/parentnode/css_selectors.c index b9d2edee723bc..4f77359835ce5 100644 --- a/ext/dom/parentnode/css_selectors.c +++ b/ext/dom/parentnode/css_selectors.c @@ -249,7 +249,8 @@ void dom_parent_node_query_selector_all(xmlNodePtr thisp, dom_object *intern, zv object_init_ex(return_value, dom_modern_nodelist_class_entry); dom_object *ret_obj = Z_DOMOBJ_P(return_value); dom_nnodemap_object *mapptr = (dom_nnodemap_object *) ret_obj->ptr; - ZVAL_ARR(&mapptr->baseobj_zv, list); + mapptr->array = list; + mapptr->release_array = true; mapptr->handler = &php_dom_obj_map_nodeset; } } diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c index e71e4e259c304..6e85ea887e4ec 100644 --- a/ext/dom/php_dom.c +++ b/ext/dom/php_dom.c @@ -1545,8 +1545,11 @@ void dom_nnodemap_objects_free_storage(zend_object *object) /* {{{ */ if (objmap->local_lower) { zend_string_release(objmap->local_lower); } - if (!Z_ISUNDEF(objmap->baseobj_zv)) { - zval_ptr_dtor(&objmap->baseobj_zv); + if (objmap->release_array) { + zend_array_release(objmap->array); + } + if (objmap->baseobj) { + OBJ_RELEASE(&objmap->baseobj->std); } xmlDictFree(objmap->dict); efree(objmap); diff --git a/ext/dom/xpath.c b/ext/dom/xpath.c index ebf61f10e80bf..21baa59ffed0b 100644 --- a/ext/dom/xpath.c +++ b/ext/dom/xpath.c @@ -234,15 +234,6 @@ PHP_METHOD(DOMXPath, registerNamespace) } /* }}} */ -static void dom_xpath_iter(zval *baseobj, dom_object *intern) /* {{{ */ -{ - dom_nnodemap_object *mapptr = (dom_nnodemap_object *) intern->ptr; - - ZVAL_COPY_VALUE(&mapptr->baseobj_zv, baseobj); - mapptr->handler = &php_dom_obj_map_nodeset; -} -/* }}} */ - static void php_xpath_eval(INTERNAL_FUNCTION_PARAMETERS, int type, bool modern) /* {{{ */ { zval *context = NULL; @@ -335,6 +326,7 @@ static void php_xpath_eval(INTERNAL_FUNCTION_PARAMETERS, int type, bool modern) { xmlNodeSetPtr nodesetp; zval retval; + bool release_array = false; if (xpathobjp->type == XPATH_NODESET && NULL != (nodesetp = xpathobjp->nodesetval) && nodesetp->nodeNr) { array_init_size(&retval, nodesetp->nodeNr); @@ -369,12 +361,18 @@ static void php_xpath_eval(INTERNAL_FUNCTION_PARAMETERS, int type, bool modern) } add_next_index_zval(&retval, &child); } + release_array = true; } else { ZVAL_EMPTY_ARRAY(&retval); } + object_init_ex(return_value, dom_get_nodelist_ce(modern)); nodeobj = Z_DOMOBJ_P(return_value); - dom_xpath_iter(&retval, nodeobj); + dom_nnodemap_object *mapptr = nodeobj->ptr; + + mapptr->array = Z_ARR(retval); + mapptr->release_array = release_array; + mapptr->handler = &php_dom_obj_map_nodeset; break; } From 9b6df109c7fbca47ef1f1744d94e31f0d4acfd02 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 22 Jun 2025 12:31:06 +0200 Subject: [PATCH 056/120] Don't use the obj_map cache for attributes (#18895) --- ext/dom/obj_map.c | 28 ++++++++----------- .../common/attr_named_node_map_cache.phpt | 17 +++++++++++ 2 files changed, 29 insertions(+), 16 deletions(-) create mode 100644 ext/dom/tests/modern/common/attr_named_node_map_cache.phpt diff --git a/ext/dom/obj_map.c b/ext/dom/obj_map.c index 12407a560112e..fe71a6f47a38a 100644 --- a/ext/dom/obj_map.c +++ b/ext/dom/obj_map.c @@ -196,19 +196,25 @@ static void dom_map_cache_obj(dom_nnodemap_object *map, xmlNodePtr itemnode, zen map->cached_obj = cached_obj; } -static xmlNodePtr dom_map_get_attr_start(xmlNodePtr node) +static void dom_map_get_attributes_item(dom_nnodemap_object *map, zend_long index, zval *return_value) { - ZEND_ASSERT(node->type == XML_ELEMENT_NODE); - return (xmlNodePtr) node->properties; + xmlNodePtr nodep = dom_object_get_node(map->baseobj); + xmlNodePtr itemnode = NULL; + if (nodep && index >= 0) { + ZEND_ASSERT(nodep->type == XML_ELEMENT_NODE); + itemnode = (xmlNodePtr) nodep->properties; + for (; index > 0 && itemnode; itemnode = itemnode->next, index--); + } + dom_ret_node_to_zobj(map, itemnode, return_value); } -static void dom_map_get_chain_item(dom_nnodemap_object *map, zend_long index, zval *return_value, xmlNodePtr (*get_start)(xmlNodePtr)) +static void dom_map_get_nodes_item(dom_nnodemap_object *map, zend_long index, zval *return_value) { xmlNodePtr nodep = dom_object_get_node(map->baseobj); xmlNodePtr itemnode = NULL; if (nodep && index >= 0) { dom_node_idx_pair start_point = dom_obj_map_get_start_point(map, nodep, index); - itemnode = start_point.node ? start_point.node : get_start(nodep); + itemnode = start_point.node ? start_point.node : dom_nodelist_iter_start_first_child(nodep); for (; start_point.index > 0 && itemnode; itemnode = itemnode->next, start_point.index--); } dom_ret_node_to_zobj(map, itemnode, return_value); @@ -217,16 +223,6 @@ static void dom_map_get_chain_item(dom_nnodemap_object *map, zend_long index, zv } } -static void dom_map_get_attributes_item(dom_nnodemap_object *map, zend_long index, zval *return_value) -{ - dom_map_get_chain_item(map, index, return_value, dom_map_get_attr_start); -} - -static void dom_map_get_nodes_item(dom_nnodemap_object *map, zend_long index, zval *return_value) -{ - dom_map_get_chain_item(map, index, return_value, dom_nodelist_iter_start_first_child); -} - static void dom_map_get_by_tag_name_item(dom_nnodemap_object *map, zend_long index, zval *return_value) { xmlNodePtr nodep = dom_object_get_node(map->baseobj); @@ -411,7 +407,7 @@ const php_dom_obj_map_handler php_dom_obj_map_attributes = { .get_item = dom_map_get_attributes_item, .get_named_item = dom_map_get_named_item_prop, .has_named_item = dom_map_has_named_item_prop, - .use_cache = true, + .use_cache = false, .nameless = false, }; diff --git a/ext/dom/tests/modern/common/attr_named_node_map_cache.phpt b/ext/dom/tests/modern/common/attr_named_node_map_cache.phpt new file mode 100644 index 0000000000000..18dedaddb9a9e --- /dev/null +++ b/ext/dom/tests/modern/common/attr_named_node_map_cache.phpt @@ -0,0 +1,17 @@ +--TEST-- +Attribute named node map cache +--EXTENSIONS-- +dom +--FILE-- +'); +$attrs = $dom->documentElement->attributes; +var_dump($attrs[1]->nodeName); +$dom->documentElement->removeAttribute('b'); +var_dump($attrs[1]->nodeName); + +?> +--EXPECT-- +string(1) "b" +string(1) "c" From 2694eb9df04beaab1bc052a4da53d9adc6c29f0a Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sun, 22 Jun 2025 08:00:08 +0100 Subject: [PATCH 057/120] Fixed GH-18902: ldap_exop/ldap_exop_sync assert triggered on empty request OID close GH-18903 --- NEWS | 4 ++++ ext/ldap/ldap.c | 7 ++++++- ext/ldap/tests/gh18902.phpt | 30 ++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 ext/ldap/tests/gh18902.phpt diff --git a/NEWS b/NEWS index 9881c36d4b012..25706b1efc0a0 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,10 @@ PHP NEWS . Fix memory leaks when returning refcounted value from curl callback. (nielsdos) +- LDAP: + . Fixed GH-18902 ldap_exop/ldap_exop_sync assert triggered on empty + request OID. (David Carlier) + - Streams: . Fixed GH-13264 (fgets() and stream_get_line() do not return false on filter fatal error). (Jakub Zelenka) diff --git a/ext/ldap/ldap.c b/ext/ldap/ldap.c index fecb8846400a6..769e6caa277b4 100644 --- a/ext/ldap/ldap.c +++ b/ext/ldap/ldap.c @@ -4036,7 +4036,12 @@ static void php_ldap_exop(INTERNAL_FUNCTION_PARAMETERS, bool force_sync) { LDAPControl **lserverctrls = NULL; int rc, msgid; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "OS|S!a!zz", &link, ldap_link_ce, &reqoid, &reqdata, &serverctrls, &retdata, &retoid) != SUCCESS) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "OP|S!a!zz", &link, ldap_link_ce, &reqoid, &reqdata, &serverctrls, &retdata, &retoid) != SUCCESS) { + RETURN_THROWS(); + } + + if (ZSTR_LEN(reqoid) == 0) { + zend_argument_value_error(2, "must not be empty"); RETURN_THROWS(); } diff --git a/ext/ldap/tests/gh18902.phpt b/ext/ldap/tests/gh18902.phpt new file mode 100644 index 0000000000000..329cbb59c1b11 --- /dev/null +++ b/ext/ldap/tests/gh18902.phpt @@ -0,0 +1,30 @@ +--TEST-- +GH-17704 (ldap_search fails when $attributes contains a non-packed array with numerical keys) +--EXTENSIONS-- +ldap +--FILE-- +getMessage(), PHP_EOL; +} + +try { + ldap_exop_sync($conn,""); +} catch (\ValueError $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + ldap_exop_sync($conn,"test\0"); +} catch (\ValueError $e) { + echo $e->getMessage(), PHP_EOL; +} +?> +--EXPECTF-- +ldap_exop(): Argument #2 ($request_oid) must not contain any null bytes +ldap_exop_sync(): Argument #2 ($request_oid) must not be empty +ldap_exop_sync(): Argument #2 ($request_oid) must not contain any null bytes From a5f21ca7005f3825c47d52772ee2f66c6a81cf86 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 22 Jun 2025 10:13:06 +0200 Subject: [PATCH 058/120] Fix GH-18901: integer overflow mb_split We prevent signed overflow by making the count unsigned. The actual interpretation of the count doesn't matter as it's just used to denote a limit. The test output for some limit values looks strange though, so that may need extra investigation. However, that's orthogonal to this fix. Closes GH-18906. --- NEWS | 3 ++ ext/mbstring/php_mbregex.c | 2 +- ext/mbstring/tests/gh18901.phpt | 54 +++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 ext/mbstring/tests/gh18901.phpt diff --git a/NEWS b/NEWS index 25706b1efc0a0..ea77125b205eb 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,9 @@ PHP NEWS . Fixed GH-18902 ldap_exop/ldap_exop_sync assert triggered on empty request OID. (David Carlier) +- MbString: + . Fixed bug GH-18901 (integer overflow mb_split). (nielsdos) + - Streams: . Fixed GH-13264 (fgets() and stream_get_line() do not return false on filter fatal error). (Jakub Zelenka) diff --git a/ext/mbstring/php_mbregex.c b/ext/mbstring/php_mbregex.c index 99dc91e34dcae..86bc5f61d8543 100644 --- a/ext/mbstring/php_mbregex.c +++ b/ext/mbstring/php_mbregex.c @@ -1184,7 +1184,7 @@ PHP_FUNCTION(mb_split) size_t string_len; int err; - zend_long count = -1; + zend_ulong count = -1; /* unsigned, it's a limit and we want to prevent signed overflow */ if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|l", &arg_pattern, &arg_pattern_len, &string, &string_len, &count) == FAILURE) { RETURN_THROWS(); diff --git a/ext/mbstring/tests/gh18901.phpt b/ext/mbstring/tests/gh18901.phpt new file mode 100644 index 0000000000000..8d862a537c3b1 --- /dev/null +++ b/ext/mbstring/tests/gh18901.phpt @@ -0,0 +1,54 @@ +--TEST-- +GH-18901 (integer overflow mb_split) +--EXTENSIONS-- +mbstring +--SKIPIF-- + +--FILE-- + +--EXPECT-- +array(4) { + [0]=> + string(0) "" + [1]=> + string(0) "" + [2]=> + string(0) "" + [3]=> + string(0) "" +} +array(4) { + [0]=> + string(0) "" + [1]=> + string(0) "" + [2]=> + string(0) "" + [3]=> + string(0) "" +} +array(4) { + [0]=> + string(0) "" + [1]=> + string(0) "" + [2]=> + string(0) "" + [3]=> + string(0) "" +} +array(1) { + [0]=> + string(3) "123" +} +array(1) { + [0]=> + string(3) "123" +} From 3df665a8889d76216c80a6e21f1201ddc8eab1d9 Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Sun, 22 Jun 2025 15:19:08 +0200 Subject: [PATCH 059/120] [Windows build] Remove redundant flags definitions (#18890) The /d2FuncCache1 compile option is already added by toolset_setup_common_cflags() in confutils.js to all targets. ZEND_DVAL_TO_LVAL_CAST_OK was removed in 3725717de18fd60a679a02210b3ed14517972524. --- win32/build/config.w32 | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/win32/build/config.w32 b/win32/build/config.w32 index f509e4eae9337..403f0aa6efbfe 100644 --- a/win32/build/config.w32 +++ b/win32/build/config.w32 @@ -285,12 +285,6 @@ if (TARGET_ARCH == 'x64') { } ADD_FLAG("CFLAGS_BD_ZEND", "/D ZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); -if (VS_TOOLSET && VCVERS >= 1914) { - ADD_FLAG("CFLAGS_BD_ZEND", "/d2FuncCache1"); -} - -/* XXX inspect this for other toolsets */ -//AC_DEFINE('ZEND_DVAL_TO_LVAL_CAST_OK', 1); ADD_SOURCES("main", "main.c snprintf.c spprintf.c getopt.c fopen_wrappers.c \ php_ini_builder.c php_glob.c \ @@ -299,9 +293,6 @@ ADD_SOURCES("main", "main.c snprintf.c spprintf.c getopt.c fopen_wrappers.c \ php_open_temporary_file.c output.c internal_functions.c \ php_syslog.c php_odbc_utils.c safe_bcmp.c"); ADD_FLAG("CFLAGS_BD_MAIN", "/D ZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); -if (VS_TOOLSET && VCVERS >= 1914) { - ADD_FLAG("CFLAGS_BD_MAIN", "/d2FuncCache1"); -} AC_DEFINE('HAVE_STRNLEN', 1); @@ -310,9 +301,6 @@ AC_DEFINE('ZEND_CHECK_STACK_LIMIT', 1) ADD_SOURCES("main/streams", "streams.c cast.c memory.c filter.c plain_wrapper.c \ userspace.c transports.c xp_socket.c mmap.c glob_wrapper.c"); ADD_FLAG("CFLAGS_BD_MAIN_STREAMS", "/D ZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); -if (VS_TOOLSET && VCVERS >= 1914) { - ADD_FLAG("CFLAGS_BD_MAIN_STREAMS", "/d2FuncCache1"); -} ADD_SOURCES("win32", "dllmain.c readdir.c \ registry.c select.c sendmail.c time.c winutil.c wsyslog.c globals.c \ @@ -320,9 +308,6 @@ ADD_SOURCES("win32", "dllmain.c readdir.c \ fnmatch.c sockets.c console.c signal.c"); ADD_FLAG("CFLAGS_BD_WIN32", "/D ZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); -if (VS_TOOLSET && VCVERS >= 1914) { - ADD_FLAG("CFLAGS_BD_WIN32", "/d2FuncCache1"); -} PHP_INSTALL_HEADERS("", "Zend/ TSRM/ main/ main/streams/ win32/"); PHP_INSTALL_HEADERS("Zend/Optimizer", "zend_call_graph.h zend_cfg.h zend_dfg.h zend_dump.h zend_func_info.h zend_inference.h zend_optimizer.h zend_ssa.h zend_worklist.h"); From 4f1b005522ddbd776ea3714851219e6c517aee8f Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Sun, 22 Jun 2025 16:03:55 +0200 Subject: [PATCH 060/120] Autotools: Enable tsrmls cache in hash extension on big endian (#15303) When system is detected as big endian this enables the TSRM Local Storage static cache with the ZEND_ENABLE_STATIC_TSRMLS_CACHE compilation flag. Previously it was enabled only on little endian systems. --- ext/hash/config.m4 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/hash/config.m4 b/ext/hash/config.m4 index 1eef801a2fea8..5248786efb084 100644 --- a/ext/hash/config.m4 +++ b/ext/hash/config.m4 @@ -31,7 +31,7 @@ AS_VAR_IF([ac_cv_c_bigendian_php], [yes], [ SHA3_OPT_SRC="$SHA3_DIR/KeccakP-1600-opt64.c" ]) EXT_HASH_SHA3_SOURCES="$SHA3_OPT_SRC $SHA3_DIR/KeccakHash.c $SHA3_DIR/KeccakSponge.c" - PHP_HASH_CFLAGS="$PHP_HASH_CFLAGS -I@ext_srcdir@/$SHA3_DIR -DKeccakP200_excluded -DKeccakP400_excluded -DKeccakP800_excluded -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1" + PHP_HASH_CFLAGS="$PHP_HASH_CFLAGS -I@ext_srcdir@/$SHA3_DIR -DKeccakP200_excluded -DKeccakP400_excluded -DKeccakP800_excluded" ]) PHP_NEW_EXTENSION([hash], m4_normalize([ @@ -58,7 +58,7 @@ PHP_NEW_EXTENSION([hash], m4_normalize([ murmur/PMurHash128.c ]), [no],, - [$PHP_HASH_CFLAGS]) + [$PHP_HASH_CFLAGS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1]) PHP_ADD_BUILD_DIR([$ext_builddir/murmur]) AS_VAR_IF([SHA3_DIR],,, [PHP_ADD_BUILD_DIR([$ext_builddir/$SHA3_DIR])]) PHP_INSTALL_HEADERS([ext/hash], m4_normalize([ From 01c3001eb76456c37753032e89c1cbc031904a85 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Sun, 22 Jun 2025 19:47:36 +0100 Subject: [PATCH 061/120] ext/tidy: zend_parse_parameters_none -> ZEND_PARSE_PARAMETERS_NONE macro (#18913) --- ext/tidy/tidy.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ext/tidy/tidy.c b/ext/tidy/tidy.c index 18fcc1bfdce68..fe2a0648af683 100644 --- a/ext/tidy/tidy.c +++ b/ext/tidy/tidy.c @@ -67,9 +67,7 @@ #define TIDY_FETCH_ONLY_OBJECT \ PHPTidyObj *obj; \ - if (zend_parse_parameters_none() != SUCCESS) { \ - RETURN_THROWS(); \ - } \ + ZEND_PARSE_PARAMETERS_NONE(); \ obj = Z_TIDY_P(ZEND_THIS); \ #define TIDY_SET_DEFAULT_CONFIG(_doc) \ @@ -1140,9 +1138,7 @@ PHP_FUNCTION(tidy_diagnose) /* {{{ Get release date (version) for Tidy library */ PHP_FUNCTION(tidy_get_release) { - if (zend_parse_parameters_none() != SUCCESS) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); #ifdef HAVE_TIDYRELEASEDATE RETURN_STRING((const char *)tidyReleaseDate()); From 4dfba7a2503c74db5d5337225e1406ceae1df87e Mon Sep 17 00:00:00 2001 From: DanielEScherzer Date: Sun, 22 Jun 2025 12:29:26 -0700 Subject: [PATCH 062/120] [RFC] Final Property Promotion https://wiki.php.net/rfc/final_promotion --- NEWS | 2 ++ UPGRADING | 2 ++ .../property_hooks/final_prop_promoted_1.phpt | 18 ++++++++++++ .../property_hooks/final_prop_promoted_2.phpt | 18 ++++++++++++ .../property_hooks/final_prop_promoted_3.phpt | 18 ++++++++++++ .../property_hooks/final_prop_promoted_4.phpt | 18 ++++++++++++ .../property_hooks/final_prop_promoted_5.phpt | 28 +++++++++++++++++++ .../final_prop_promoted_ast.phpt | 18 ++++++++++++ Zend/zend_ast.c | 3 ++ Zend/zend_compile.c | 10 ++----- .../tests/ReflectionProperty_isFinal.phpt | 4 +++ 11 files changed, 131 insertions(+), 8 deletions(-) create mode 100644 Zend/tests/property_hooks/final_prop_promoted_1.phpt create mode 100644 Zend/tests/property_hooks/final_prop_promoted_2.phpt create mode 100644 Zend/tests/property_hooks/final_prop_promoted_3.phpt create mode 100644 Zend/tests/property_hooks/final_prop_promoted_4.phpt create mode 100644 Zend/tests/property_hooks/final_prop_promoted_5.phpt create mode 100644 Zend/tests/property_hooks/final_prop_promoted_ast.phpt diff --git a/NEWS b/NEWS index fb117a221a37a..dfa90ed08f62c 100644 --- a/NEWS +++ b/NEWS @@ -56,6 +56,8 @@ PHP NEWS . Properly handle __debugInfo() returning an array reference. (nielsdos) . Properly handle reference return value from __toString(). (nielsdos) . Added the pipe (|>) operator. (crell) + . Added support for `final` with constructor property promotion. + (DanielEScherzer) - Curl: . Added curl_multi_get_handles(). (timwolla) diff --git a/UPGRADING b/UPGRADING index 72bb5d76da936..e551f0c894260 100644 --- a/UPGRADING +++ b/UPGRADING @@ -146,6 +146,8 @@ PHP 8.5 UPGRADE NOTES RFC: https://wiki.php.net/rfc/attributes-on-constants . Added the pipe (|>) operator. RFC: https://wiki.php.net/rfc/pipe-operator-v3 + . Constructor property promotion can now be used for final properties. + RFC: https://wiki.php.net/rfc/final_promotion - Curl: . Added support for share handles that are persisted across multiple PHP diff --git a/Zend/tests/property_hooks/final_prop_promoted_1.phpt b/Zend/tests/property_hooks/final_prop_promoted_1.phpt new file mode 100644 index 0000000000000..740588d8aa2ae --- /dev/null +++ b/Zend/tests/property_hooks/final_prop_promoted_1.phpt @@ -0,0 +1,18 @@ +--TEST-- +Promoted property may be marked final (hook) +--FILE-- + +--EXPECTF-- +Fatal error: Cannot override final property A::$prop in %s on line %d diff --git a/Zend/tests/property_hooks/final_prop_promoted_2.phpt b/Zend/tests/property_hooks/final_prop_promoted_2.phpt new file mode 100644 index 0000000000000..535a7ceabd317 --- /dev/null +++ b/Zend/tests/property_hooks/final_prop_promoted_2.phpt @@ -0,0 +1,18 @@ +--TEST-- +Promoted property may be marked final (normal) +--FILE-- + +--EXPECTF-- +Fatal error: Cannot override final property A::$prop in %s on line %d diff --git a/Zend/tests/property_hooks/final_prop_promoted_3.phpt b/Zend/tests/property_hooks/final_prop_promoted_3.phpt new file mode 100644 index 0000000000000..600d18df84c9a --- /dev/null +++ b/Zend/tests/property_hooks/final_prop_promoted_3.phpt @@ -0,0 +1,18 @@ +--TEST-- +Promoted property may be marked final (no visibility needed) +--FILE-- + +--EXPECTF-- +Fatal error: Cannot override final property A::$prop in %s on line %d diff --git a/Zend/tests/property_hooks/final_prop_promoted_4.phpt b/Zend/tests/property_hooks/final_prop_promoted_4.phpt new file mode 100644 index 0000000000000..2b8270ff5a062 --- /dev/null +++ b/Zend/tests/property_hooks/final_prop_promoted_4.phpt @@ -0,0 +1,18 @@ +--TEST-- +Final promoted property conflicts with non-promoted non-hooked property +--FILE-- + +--EXPECTF-- +Fatal error: Cannot override final property A::$prop in %s on line %d diff --git a/Zend/tests/property_hooks/final_prop_promoted_5.phpt b/Zend/tests/property_hooks/final_prop_promoted_5.phpt new file mode 100644 index 0000000000000..3e592f99b3416 --- /dev/null +++ b/Zend/tests/property_hooks/final_prop_promoted_5.phpt @@ -0,0 +1,28 @@ +--TEST-- +Non-promoted constructor parameter does not conflict with final promoted property +--FILE-- + +--EXPECT-- +B::__construct(): test +A::__construct(): test diff --git a/Zend/tests/property_hooks/final_prop_promoted_ast.phpt b/Zend/tests/property_hooks/final_prop_promoted_ast.phpt new file mode 100644 index 0000000000000..32aa1f27dc323 --- /dev/null +++ b/Zend/tests/property_hooks/final_prop_promoted_ast.phpt @@ -0,0 +1,18 @@ +--TEST-- +Confirm that the AST indicates final promoted properties +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECT-- +assert(false && new class { + public function __construct(public final $prop) { + } + +}) diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index beecf51216a94..cdc86faa95aa3 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -2795,6 +2795,9 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio zend_ast_export_attributes(str, ast->child[3], indent, 0); } zend_ast_export_visibility(str, ast->attr, ZEND_MODIFIER_TARGET_CPP); + if (ast->attr & ZEND_ACC_FINAL) { + smart_str_appends(str, "final "); + } if (ast->child[0]) { zend_ast_export_type(str, ast->child[0], indent); smart_str_appendc(str, ' '); diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 2bc0cf7b703d9..28bea1a21d759 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -903,13 +903,7 @@ uint32_t zend_modifier_token_to_flag(zend_modifier_target target, uint32_t token } break; case T_FINAL: - if (target == ZEND_MODIFIER_TARGET_METHOD - || target == ZEND_MODIFIER_TARGET_CONSTANT - || target == ZEND_MODIFIER_TARGET_PROPERTY - || target == ZEND_MODIFIER_TARGET_PROPERTY_HOOK) { - return ZEND_ACC_FINAL; - } - break; + return ZEND_ACC_FINAL; case T_STATIC: if (target == ZEND_MODIFIER_TARGET_PROPERTY || target == ZEND_MODIFIER_TARGET_METHOD) { return ZEND_ACC_STATIC; @@ -7681,7 +7675,7 @@ static void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32 zend_string *name = zval_make_interned_string(zend_ast_get_zval(var_ast)); bool is_ref = (param_ast->attr & ZEND_PARAM_REF) != 0; bool is_variadic = (param_ast->attr & ZEND_PARAM_VARIADIC) != 0; - uint32_t property_flags = param_ast->attr & (ZEND_ACC_PPP_MASK | ZEND_ACC_PPP_SET_MASK | ZEND_ACC_READONLY); + uint32_t property_flags = param_ast->attr & (ZEND_ACC_PPP_MASK | ZEND_ACC_PPP_SET_MASK | ZEND_ACC_READONLY | ZEND_ACC_FINAL); bool is_promoted = property_flags || hooks_ast; znode var_node, default_node; diff --git a/ext/reflection/tests/ReflectionProperty_isFinal.phpt b/ext/reflection/tests/ReflectionProperty_isFinal.phpt index 62b792fd7253f..f01835efbed25 100644 --- a/ext/reflection/tests/ReflectionProperty_isFinal.phpt +++ b/ext/reflection/tests/ReflectionProperty_isFinal.phpt @@ -12,6 +12,8 @@ class C { public protected(set) final mixed $p6; public private(set) mixed $p7; public private(set) final mixed $p8; + + public function __construct(final $p9, public $p10) {} } $rc = new ReflectionClass(C::class); @@ -30,3 +32,5 @@ p5: bool(false) p6: bool(true) p7: bool(true) p8: bool(true) +p9: bool(true) +p10: bool(false) From ddd33fd7e4e88f96fef91180b6bdf6d7af3af18e Mon Sep 17 00:00:00 2001 From: DanielEScherzer Date: Sun, 22 Jun 2025 14:35:28 -0700 Subject: [PATCH 063/120] Generated arginfo headers: combine preprocessor conditional blocks (2) (#18667) When global constants' or class constants' availability is based on some preprocessor condition, the generated arginfo header files wrap the declarations in the preprocessor `#if` conditional blocks, one per declaration, even if they are in the same conditional block based on comments in the stub file. Instead of having multiple conditional blocks one after the other with the same condition, combine them into a single conditional block. --- build/gen_stub.php | 30 ++-- ext/com_dotnet/com_extension_arginfo.h | 2 - ext/curl/curl_arginfo.h | 158 ------------------ ext/dba/dba_arginfo.h | 2 - ext/gd/gd_arginfo.h | 18 -- .../listformatter/listformatter_arginfo.h | 6 - ext/intl/spoofchecker/spoofchecker_arginfo.h | 12 -- ext/intl/uchar/uchar_arginfo.h | 4 - ext/ldap/ldap_arginfo.h | 96 ----------- ext/odbc/odbc_arginfo.h | 32 ---- ext/openssl/openssl_arginfo.h | 16 -- ext/openssl/openssl_pwhash_arginfo.h | 10 -- ext/pcntl/pcntl_arginfo.h | 28 ---- ext/pdo_mysql/pdo_mysql_arginfo.h | 4 - ext/pdo_sqlite/pdo_sqlite_arginfo.h | 4 - ext/sockets/sockets_arginfo.h | 76 --------- ext/sodium/libsodium_arginfo.h | 82 --------- ext/sodium/sodium_pwhash_arginfo.h | 10 -- ext/standard/basic_functions_arginfo.h | 106 ------------ ext/standard/file_arginfo.h | 4 - ext/standard/password_arginfo.h | 10 -- ext/tidy/tidy_arginfo.h | 54 ------ ext/xsl/php_xsl_arginfo.h | 2 - ext/zip/php_zip_arginfo.h | 44 ----- main/main_arginfo.h | 20 --- 25 files changed, 13 insertions(+), 817 deletions(-) diff --git a/build/gen_stub.php b/build/gen_stub.php index ff86106e8a2a4..fcef8213d0b55 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -2749,23 +2749,15 @@ public function getDeclaration(array $allConstInfos): string throw new Exception("Constant " . $this->name->__toString() . " must have a @cvalue annotation"); } - $code = ""; - - if ($this->cond) { - $code .= "#if {$this->cond}\n"; - } + // Condition will be added by generateCodeWithConditions() if ($this->name->isClassConst()) { - $code .= $this->getClassConstDeclaration($value, $allConstInfos); + $code = $this->getClassConstDeclaration($value, $allConstInfos); } else { - $code .= $this->getGlobalConstDeclaration($value); + $code = $this->getGlobalConstDeclaration($value); } $code .= $this->getValueAssertion($value); - if ($this->cond) { - $code .= "#endif\n"; - } - return $code; } @@ -3556,9 +3548,11 @@ function (Name $item) { $code .= "\tzend_register_class_alias(\"" . str_replace("\\", "\\\\", $this->alias) . "\", class_entry);\n"; } - foreach ($this->constInfos as $const) { - $code .= $const->getDeclaration($allConstInfos); - } + $code .= generateCodeWithConditions( + $this->constInfos, + '', + static fn (ConstInfo $const): string => $const->getDeclaration($allConstInfos) + ); foreach ($this->enumCaseInfos as $enumCase) { $code .= $enumCase->getDeclaration($allConstInfos); @@ -5192,9 +5186,11 @@ static function (FuncInfo $funcInfo) use ($fileInfo, &$generatedFunctionDeclarat $code .= "\nstatic void register_{$stubFilenameWithoutExtension}_symbols(int module_number)\n"; $code .= "{\n"; - foreach ($fileInfo->constInfos as $constInfo) { - $code .= $constInfo->getDeclaration($allConstInfos); - } + $code .= generateCodeWithConditions( + $fileInfo->constInfos, + '', + static fn (ConstInfo $constInfo): string => $constInfo->getDeclaration($allConstInfos) + ); if ($attributeInitializationCode !== "" && $fileInfo->constInfos) { $code .= "\n"; diff --git a/ext/com_dotnet/com_extension_arginfo.h b/ext/com_dotnet/com_extension_arginfo.h index b5773f17fda3d..a2bcbf31c968b 100644 --- a/ext/com_dotnet/com_extension_arginfo.h +++ b/ext/com_dotnet/com_extension_arginfo.h @@ -281,8 +281,6 @@ static void register_com_extension_symbols(int module_number) REGISTER_LONG_CONSTANT("MK_E_UNAVAILABLE", PHP_MK_E_UNAVAILABLE, CONST_PERSISTENT); #if SIZEOF_ZEND_LONG == 8 REGISTER_LONG_CONSTANT("VT_UI8", VT_UI8, CONST_PERSISTENT); -#endif -#if SIZEOF_ZEND_LONG == 8 REGISTER_LONG_CONSTANT("VT_I8", VT_I8, CONST_PERSISTENT); #endif } diff --git a/ext/curl/curl_arginfo.h b/ext/curl/curl_arginfo.h index 8928da3f47453..ef267cd803ba2 100644 --- a/ext/curl/curl_arginfo.h +++ b/ext/curl/curl_arginfo.h @@ -328,11 +328,7 @@ static void register_curl_symbols(int module_number) REGISTER_LONG_CONSTANT("CURLOPT_DEBUGFUNCTION", CURLOPT_DEBUGFUNCTION, CONST_PERSISTENT); #if LIBCURL_VERSION_NUM >= 0x080d00 /* Available since 8.13.0 */ REGISTER_LONG_CONSTANT("CURLFOLLOW_ALL", CURLFOLLOW_ALL, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x080d00 /* Available since 8.13.0 */ REGISTER_LONG_CONSTANT("CURLFOLLOW_OBEYCODE", CURLFOLLOW_OBEYCODE, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x080d00 /* Available since 8.13.0 */ REGISTER_LONG_CONSTANT("CURLFOLLOW_FIRSTONLY", CURLFOLLOW_FIRSTONLY, CONST_PERSISTENT); #endif REGISTER_LONG_CONSTANT("CURLINFO_TEXT", CURLINFO_TEXT, CONST_PERSISTENT); @@ -436,14 +432,10 @@ static void register_curl_symbols(int module_number) #endif #if LIBCURL_VERSION_NUM >= 0x075400 /* Available since 7.84.0 */ REGISTER_LONG_CONSTANT("CURLINFO_CAPATH", CURLINFO_CAPATH, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x075400 /* Available since 7.84.0 */ REGISTER_LONG_CONSTANT("CURLINFO_CAINFO", CURLINFO_CAINFO, CONST_PERSISTENT); #endif #if LIBCURL_VERSION_NUM >= 0x080c00 /* Available since 8.12.0 */ REGISTER_LONG_CONSTANT("CURLINFO_HTTPAUTH_USED", CURLINFO_HTTPAUTH_USED, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x080c00 /* Available since 8.12.0 */ REGISTER_LONG_CONSTANT("CURLINFO_PROXYAUTH_USED", CURLINFO_PROXYAUTH_USED, CONST_PERSISTENT); #endif REGISTER_LONG_CONSTANT("CURLMSG_DONE", CURLMSG_DONE, CONST_PERSISTENT); @@ -838,11 +830,7 @@ static void register_curl_symbols(int module_number) REGISTER_LONG_CONSTANT("CURLOPT_TLS13_CIPHERS", CURLOPT_TLS13_CIPHERS, CONST_PERSISTENT); #if LIBCURL_VERSION_NUM >= 0x073E00 /* Available since 7.62.0 */ REGISTER_LONG_CONSTANT("CURLOPT_DOH_URL", CURLOPT_DOH_URL, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x073E00 /* Available since 7.62.0 */ REGISTER_LONG_CONSTANT("CURLOPT_UPKEEP_INTERVAL_MS", CURLOPT_UPKEEP_INTERVAL_MS, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x073E00 /* Available since 7.62.0 */ REGISTER_LONG_CONSTANT("CURLOPT_UPLOAD_BUFFERSIZE", CURLOPT_UPLOAD_BUFFERSIZE, CONST_PERSISTENT); #endif #if LIBCURL_VERSION_NUM >= 0x074000 /* Available since 7.64.0 */ @@ -850,23 +838,11 @@ static void register_curl_symbols(int module_number) #endif #if LIBCURL_VERSION_NUM >= 0x074001 /* Available since 7.64.1 */ REGISTER_LONG_CONSTANT("CURLALTSVC_H1", CURLALTSVC_H1, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074001 /* Available since 7.64.1 */ REGISTER_LONG_CONSTANT("CURLALTSVC_H2", CURLALTSVC_H2, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074001 /* Available since 7.64.1 */ REGISTER_LONG_CONSTANT("CURLALTSVC_H3", CURLALTSVC_H3, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074001 /* Available since 7.64.1 */ REGISTER_LONG_CONSTANT("CURLALTSVC_READONLYFILE", CURLALTSVC_READONLYFILE, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074001 /* Available since 7.64.1 */ REGISTER_LONG_CONSTANT("CURLOPT_ALTSVC", CURLOPT_ALTSVC, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074001 /* Available since 7.64.1 */ REGISTER_LONG_CONSTANT("CURLOPT_ALTSVC_CTRL", CURLOPT_ALTSVC_CTRL, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074001 /* Available since 7.64.1 */ REGISTER_LONG_CONSTANT("CURL_VERSION_ALTSVC", CURL_VERSION_ALTSVC, CONST_PERSISTENT); #endif #if LIBCURL_VERSION_NUM >= 0x074100 /* Available since 7.65.0 */ @@ -874,14 +850,8 @@ static void register_curl_symbols(int module_number) #endif #if LIBCURL_VERSION_NUM >= 0x074200 /* Available since 7.66.0 */ REGISTER_LONG_CONSTANT("CURLOPT_SASL_AUTHZID", CURLOPT_SASL_AUTHZID, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074200 /* Available since 7.66.0 */ REGISTER_LONG_CONSTANT("CURL_VERSION_HTTP3", CURL_VERSION_HTTP3, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074200 /* Available since 7.66.0 */ REGISTER_LONG_CONSTANT("CURLINFO_RETRY_AFTER", CURLINFO_RETRY_AFTER, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074200 /* Available since 7.66.0 */ REGISTER_LONG_CONSTANT("CURL_HTTP_VERSION_3", CURL_HTTP_VERSION_3, CONST_PERSISTENT); #endif #if LIBCURL_VERSION_NUM >= 0x074300 /* Available since 7.67.0 */ @@ -898,212 +868,90 @@ static void register_curl_symbols(int module_number) #endif #if LIBCURL_VERSION_NUM >= 0x074700 /* Available since 7.71.0 */ REGISTER_LONG_CONSTANT("CURLOPT_ISSUERCERT_BLOB", CURLOPT_ISSUERCERT_BLOB, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074700 /* Available since 7.71.0 */ REGISTER_LONG_CONSTANT("CURLOPT_PROXY_ISSUERCERT", CURLOPT_PROXY_ISSUERCERT, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074700 /* Available since 7.71.0 */ REGISTER_LONG_CONSTANT("CURLOPT_PROXY_ISSUERCERT_BLOB", CURLOPT_PROXY_ISSUERCERT_BLOB, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074700 /* Available since 7.71.0 */ REGISTER_LONG_CONSTANT("CURLOPT_PROXY_SSLCERT_BLOB", CURLOPT_PROXY_SSLCERT_BLOB, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074700 /* Available since 7.71.0 */ REGISTER_LONG_CONSTANT("CURLOPT_PROXY_SSLKEY_BLOB", CURLOPT_PROXY_SSLKEY_BLOB, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074700 /* Available since 7.71.0 */ REGISTER_LONG_CONSTANT("CURLOPT_SSLCERT_BLOB", CURLOPT_SSLCERT_BLOB, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074700 /* Available since 7.71.0 */ REGISTER_LONG_CONSTANT("CURLOPT_SSLKEY_BLOB", CURLOPT_SSLKEY_BLOB, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074700 /* Available since 7.71.0 */ REGISTER_LONG_CONSTANT("CURLPROTO_MQTT", CURLPROTO_MQTT, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074700 /* Available since 7.71.0 */ REGISTER_LONG_CONSTANT("CURLSSLOPT_NATIVE_CA", CURLSSLOPT_NATIVE_CA, CONST_PERSISTENT); #endif #if LIBCURL_VERSION_NUM >= 0x074800 /* Available since 7.72.0 */ REGISTER_LONG_CONSTANT("CURL_VERSION_UNICODE", CURL_VERSION_UNICODE, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074800 /* Available since 7.72.0 */ REGISTER_LONG_CONSTANT("CURL_VERSION_ZSTD", CURL_VERSION_ZSTD, CONST_PERSISTENT); #endif #if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLE_PROXY", CURLE_PROXY, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLINFO_PROXY_ERROR", CURLINFO_PROXY_ERROR, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLOPT_SSL_EC_CURVES", CURLOPT_SSL_EC_CURVES, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_BAD_ADDRESS_TYPE", CURLPX_BAD_ADDRESS_TYPE, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_BAD_VERSION", CURLPX_BAD_VERSION, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_CLOSED", CURLPX_CLOSED, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_GSSAPI", CURLPX_GSSAPI, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_GSSAPI_PERMSG", CURLPX_GSSAPI_PERMSG, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_GSSAPI_PROTECTION", CURLPX_GSSAPI_PROTECTION, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_IDENTD", CURLPX_IDENTD, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_IDENTD_DIFFER", CURLPX_IDENTD_DIFFER, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_LONG_HOSTNAME", CURLPX_LONG_HOSTNAME, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_LONG_PASSWD", CURLPX_LONG_PASSWD, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_LONG_USER", CURLPX_LONG_USER, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_NO_AUTH", CURLPX_NO_AUTH, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_OK", CURLPX_OK, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_RECV_ADDRESS", CURLPX_RECV_ADDRESS, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_RECV_AUTH", CURLPX_RECV_AUTH, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_RECV_CONNECT", CURLPX_RECV_CONNECT, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_RECV_REQACK", CURLPX_RECV_REQACK, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED", CURLPX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_REPLY_COMMAND_NOT_SUPPORTED", CURLPX_REPLY_COMMAND_NOT_SUPPORTED, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_REPLY_CONNECTION_REFUSED", CURLPX_REPLY_CONNECTION_REFUSED, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_REPLY_GENERAL_SERVER_FAILURE", CURLPX_REPLY_GENERAL_SERVER_FAILURE, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_REPLY_HOST_UNREACHABLE", CURLPX_REPLY_HOST_UNREACHABLE, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_REPLY_NETWORK_UNREACHABLE", CURLPX_REPLY_NETWORK_UNREACHABLE, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_REPLY_NOT_ALLOWED", CURLPX_REPLY_NOT_ALLOWED, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_REPLY_TTL_EXPIRED", CURLPX_REPLY_TTL_EXPIRED, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_REPLY_UNASSIGNED", CURLPX_REPLY_UNASSIGNED, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_REQUEST_FAILED", CURLPX_REQUEST_FAILED, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_RESOLVE_HOST", CURLPX_RESOLVE_HOST, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_SEND_AUTH", CURLPX_SEND_AUTH, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_SEND_CONNECT", CURLPX_SEND_CONNECT, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_SEND_REQUEST", CURLPX_SEND_REQUEST, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_UNKNOWN_FAIL", CURLPX_UNKNOWN_FAIL, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_UNKNOWN_MODE", CURLPX_UNKNOWN_MODE, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074900 /* Available since 7.73.0 */ REGISTER_LONG_CONSTANT("CURLPX_USER_REJECTED", CURLPX_USER_REJECTED, CONST_PERSISTENT); #endif #if LIBCURL_VERSION_NUM >= 0x074a00 /* Available since 7.74.0 */ REGISTER_LONG_CONSTANT("CURLHSTS_ENABLE", CURLHSTS_ENABLE, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074a00 /* Available since 7.74.0 */ REGISTER_LONG_CONSTANT("CURLHSTS_READONLYFILE", CURLHSTS_READONLYFILE, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074a00 /* Available since 7.74.0 */ REGISTER_LONG_CONSTANT("CURLOPT_HSTS", CURLOPT_HSTS, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074a00 /* Available since 7.74.0 */ REGISTER_LONG_CONSTANT("CURLOPT_HSTS_CTRL", CURLOPT_HSTS_CTRL, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074a00 /* Available since 7.74.0 */ REGISTER_LONG_CONSTANT("CURL_VERSION_HSTS", CURL_VERSION_HSTS, CONST_PERSISTENT); #endif #if LIBCURL_VERSION_NUM >= 0x074b00 /* Available since 7.75.0 */ REGISTER_LONG_CONSTANT("CURLAUTH_AWS_SIGV4", CURLAUTH_AWS_SIGV4, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074b00 /* Available since 7.75.0 */ REGISTER_LONG_CONSTANT("CURLOPT_AWS_SIGV4", CURLOPT_AWS_SIGV4, CONST_PERSISTENT); #endif #if LIBCURL_VERSION_NUM >= 0x074c00 /* Available since 7.76.0 */ REGISTER_LONG_CONSTANT("CURLINFO_REFERER", CURLINFO_REFERER, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074c00 /* Available since 7.76.0 */ REGISTER_LONG_CONSTANT("CURLOPT_DOH_SSL_VERIFYHOST", CURLOPT_DOH_SSL_VERIFYHOST, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074c00 /* Available since 7.76.0 */ REGISTER_LONG_CONSTANT("CURLOPT_DOH_SSL_VERIFYPEER", CURLOPT_DOH_SSL_VERIFYPEER, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074c00 /* Available since 7.76.0 */ REGISTER_LONG_CONSTANT("CURLOPT_DOH_SSL_VERIFYSTATUS", CURLOPT_DOH_SSL_VERIFYSTATUS, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074c00 /* Available since 7.76.0 */ REGISTER_LONG_CONSTANT("CURL_VERSION_GSASL", CURL_VERSION_GSASL, CONST_PERSISTENT); #endif #if LIBCURL_VERSION_NUM >= 0x074d00 /* Available since 7.77.0 */ REGISTER_LONG_CONSTANT("CURLOPT_CAINFO_BLOB", CURLOPT_CAINFO_BLOB, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074d00 /* Available since 7.77.0 */ REGISTER_LONG_CONSTANT("CURLOPT_PROXY_CAINFO_BLOB", CURLOPT_PROXY_CAINFO_BLOB, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x074d00 /* Available since 7.77.0 */ REGISTER_LONG_CONSTANT("CURLSSLOPT_AUTO_CLIENT_CERT", CURLSSLOPT_AUTO_CLIENT_CERT, CONST_PERSISTENT); #endif #if LIBCURL_VERSION_NUM >= 0x075000 /* Available since 7.80.0 */ REGISTER_LONG_CONSTANT("CURLOPT_MAXLIFETIME_CONN", CURLOPT_MAXLIFETIME_CONN, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x075000 /* Available since 7.80.0 */ REGISTER_LONG_CONSTANT("CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256", CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x075000 /* Available since 7.80.0 */ REGISTER_LONG_CONSTANT("CURLOPT_PREREQFUNCTION", CURLOPT_PREREQFUNCTION, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x075000 /* Available since 7.80.0 */ REGISTER_LONG_CONSTANT("CURL_PREREQFUNC_OK", CURL_PREREQFUNC_OK, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x075000 /* Available since 7.80.0 */ REGISTER_LONG_CONSTANT("CURL_PREREQFUNC_ABORT", CURL_PREREQFUNC_ABORT, CONST_PERSISTENT); #endif #if LIBCURL_VERSION_NUM >= 0x075100 /* Available since 7.81.0 */ REGISTER_LONG_CONSTANT("CURLOPT_MIME_OPTIONS", CURLOPT_MIME_OPTIONS, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x075100 /* Available since 7.81.0 */ REGISTER_LONG_CONSTANT("CURLMIMEOPT_FORMESCAPE", CURLMIMEOPT_FORMESCAPE, CONST_PERSISTENT); #endif #if LIBCURL_VERSION_NUM >= 0x075400 /* Available since 7.84.0 */ @@ -1111,20 +959,14 @@ static void register_curl_symbols(int module_number) #endif #if LIBCURL_VERSION_NUM >= 0x075500 /* Available since 7.85.0 */ REGISTER_LONG_CONSTANT("CURLOPT_PROTOCOLS_STR", CURLOPT_PROTOCOLS_STR, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x075500 /* Available since 7.85.0 */ REGISTER_LONG_CONSTANT("CURLOPT_REDIR_PROTOCOLS_STR", CURLOPT_REDIR_PROTOCOLS_STR, CONST_PERSISTENT); #endif #if LIBCURL_VERSION_NUM >= 0x075600 /* Available since 7.86.0 */ REGISTER_LONG_CONSTANT("CURLOPT_WS_OPTIONS", CURLOPT_WS_OPTIONS, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x075600 /* Available since 7.86.0 */ REGISTER_LONG_CONSTANT("CURLWS_RAW_MODE", CURLWS_RAW_MODE, CONST_PERSISTENT); #endif #if LIBCURL_VERSION_NUM >= 0x075700 /* Available since 7.87.0 */ REGISTER_LONG_CONSTANT("CURLOPT_CA_CACHE_TIMEOUT", CURLOPT_CA_CACHE_TIMEOUT, CONST_PERSISTENT); -#endif -#if LIBCURL_VERSION_NUM >= 0x075700 /* Available since 7.87.0 */ REGISTER_LONG_CONSTANT("CURLOPT_QUICK_EXIT", CURLOPT_QUICK_EXIT, CONST_PERSISTENT); #endif #if LIBCURL_VERSION_NUM >= 0x075800 /* Available since 7.88.0 */ diff --git a/ext/dba/dba_arginfo.h b/ext/dba/dba_arginfo.h index 97a45381c92bf..c2befedfda7c7 100644 --- a/ext/dba/dba_arginfo.h +++ b/ext/dba/dba_arginfo.h @@ -99,8 +99,6 @@ static void register_dba_symbols(int module_number) { #if defined(DBA_LMDB) REGISTER_LONG_CONSTANT("DBA_LMDB_USE_SUB_DIR", 0, CONST_PERSISTENT); -#endif -#if defined(DBA_LMDB) REGISTER_LONG_CONSTANT("DBA_LMDB_NO_SUB_DIR", MDB_NOSUBDIR, CONST_PERSISTENT); #endif } diff --git a/ext/gd/gd_arginfo.h b/ext/gd/gd_arginfo.h index 5cf4f2f29a9bd..c80aaac463348 100644 --- a/ext/gd/gd_arginfo.h +++ b/ext/gd/gd_arginfo.h @@ -932,35 +932,17 @@ static void register_gd_symbols(int module_number) #endif #if (defined(GD_MAJOR_VERSION) && defined(GD_MINOR_VERSION) && defined(GD_RELEASE_VERSION) && defined(GD_EXTRA_VERSION)) REGISTER_LONG_CONSTANT("GD_MAJOR_VERSION", GD_MAJOR_VERSION, CONST_PERSISTENT); -#endif -#if (defined(GD_MAJOR_VERSION) && defined(GD_MINOR_VERSION) && defined(GD_RELEASE_VERSION) && defined(GD_EXTRA_VERSION)) REGISTER_LONG_CONSTANT("GD_MINOR_VERSION", GD_MINOR_VERSION, CONST_PERSISTENT); -#endif -#if (defined(GD_MAJOR_VERSION) && defined(GD_MINOR_VERSION) && defined(GD_RELEASE_VERSION) && defined(GD_EXTRA_VERSION)) REGISTER_LONG_CONSTANT("GD_RELEASE_VERSION", GD_RELEASE_VERSION, CONST_PERSISTENT); -#endif -#if (defined(GD_MAJOR_VERSION) && defined(GD_MINOR_VERSION) && defined(GD_RELEASE_VERSION) && defined(GD_EXTRA_VERSION)) REGISTER_STRING_CONSTANT("GD_EXTRA_VERSION", GD_EXTRA_VERSION, CONST_PERSISTENT); #endif #if defined(HAVE_GD_PNG) REGISTER_LONG_CONSTANT("PNG_NO_FILTER", 0x0, CONST_PERSISTENT); -#endif -#if defined(HAVE_GD_PNG) REGISTER_LONG_CONSTANT("PNG_FILTER_NONE", 0x8, CONST_PERSISTENT); -#endif -#if defined(HAVE_GD_PNG) REGISTER_LONG_CONSTANT("PNG_FILTER_SUB", 0x10, CONST_PERSISTENT); -#endif -#if defined(HAVE_GD_PNG) REGISTER_LONG_CONSTANT("PNG_FILTER_UP", 0x20, CONST_PERSISTENT); -#endif -#if defined(HAVE_GD_PNG) REGISTER_LONG_CONSTANT("PNG_FILTER_AVG", 0x40, CONST_PERSISTENT); -#endif -#if defined(HAVE_GD_PNG) REGISTER_LONG_CONSTANT("PNG_FILTER_PAETH", 0x80, CONST_PERSISTENT); -#endif -#if defined(HAVE_GD_PNG) REGISTER_LONG_CONSTANT("PNG_ALL_FILTERS", 0x8 | 0x10 | 0x20 | 0x40 | 0x80, CONST_PERSISTENT); #endif } diff --git a/ext/intl/listformatter/listformatter_arginfo.h b/ext/intl/listformatter/listformatter_arginfo.h index d9a4c3fb84ddc..3a2afa2d1c2d9 100644 --- a/ext/intl/listformatter/listformatter_arginfo.h +++ b/ext/intl/listformatter/listformatter_arginfo.h @@ -59,16 +59,12 @@ static zend_class_entry *register_class_IntlListFormatter(void) zend_string *const_TYPE_OR_name = zend_string_init_interned("TYPE_OR", sizeof("TYPE_OR") - 1, 1); zend_declare_typed_class_constant(class_entry, const_TYPE_OR_name, &const_TYPE_OR_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_TYPE_OR_name); -#endif -#if U_ICU_VERSION_MAJOR_NUM >= 67 zval const_TYPE_UNITS_value; ZVAL_LONG(&const_TYPE_UNITS_value, ULISTFMT_TYPE_UNITS); zend_string *const_TYPE_UNITS_name = zend_string_init_interned("TYPE_UNITS", sizeof("TYPE_UNITS") - 1, 1); zend_declare_typed_class_constant(class_entry, const_TYPE_UNITS_name, &const_TYPE_UNITS_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_TYPE_UNITS_name); -#endif -#if U_ICU_VERSION_MAJOR_NUM >= 67 zval const_WIDTH_WIDE_value; ZVAL_LONG(&const_WIDTH_WIDE_value, ULISTFMT_WIDTH_WIDE); @@ -91,8 +87,6 @@ static zend_class_entry *register_class_IntlListFormatter(void) zend_string *const_WIDTH_SHORT_name = zend_string_init_interned("WIDTH_SHORT", sizeof("WIDTH_SHORT") - 1, 1); zend_declare_typed_class_constant(class_entry, const_WIDTH_SHORT_name, &const_WIDTH_SHORT_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_WIDTH_SHORT_name); -#endif -#if U_ICU_VERSION_MAJOR_NUM >= 67 zval const_WIDTH_NARROW_value; ZVAL_LONG(&const_WIDTH_NARROW_value, ULISTFMT_WIDTH_NARROW); diff --git a/ext/intl/spoofchecker/spoofchecker_arginfo.h b/ext/intl/spoofchecker/spoofchecker_arginfo.h index cee17335dcd40..6a3c0e55aa27d 100644 --- a/ext/intl/spoofchecker/spoofchecker_arginfo.h +++ b/ext/intl/spoofchecker/spoofchecker_arginfo.h @@ -112,48 +112,36 @@ static zend_class_entry *register_class_Spoofchecker(void) zend_string *const_ASCII_name = zend_string_init_interned("ASCII", sizeof("ASCII") - 1, 1); zend_declare_typed_class_constant(class_entry, const_ASCII_name, &const_ASCII_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_ASCII_name); -#endif -#if U_ICU_VERSION_MAJOR_NUM >= 58 zval const_HIGHLY_RESTRICTIVE_value; ZVAL_LONG(&const_HIGHLY_RESTRICTIVE_value, USPOOF_HIGHLY_RESTRICTIVE); zend_string *const_HIGHLY_RESTRICTIVE_name = zend_string_init_interned("HIGHLY_RESTRICTIVE", sizeof("HIGHLY_RESTRICTIVE") - 1, 1); zend_declare_typed_class_constant(class_entry, const_HIGHLY_RESTRICTIVE_name, &const_HIGHLY_RESTRICTIVE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_HIGHLY_RESTRICTIVE_name); -#endif -#if U_ICU_VERSION_MAJOR_NUM >= 58 zval const_MODERATELY_RESTRICTIVE_value; ZVAL_LONG(&const_MODERATELY_RESTRICTIVE_value, USPOOF_MODERATELY_RESTRICTIVE); zend_string *const_MODERATELY_RESTRICTIVE_name = zend_string_init_interned("MODERATELY_RESTRICTIVE", sizeof("MODERATELY_RESTRICTIVE") - 1, 1); zend_declare_typed_class_constant(class_entry, const_MODERATELY_RESTRICTIVE_name, &const_MODERATELY_RESTRICTIVE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_MODERATELY_RESTRICTIVE_name); -#endif -#if U_ICU_VERSION_MAJOR_NUM >= 58 zval const_MINIMALLY_RESTRICTIVE_value; ZVAL_LONG(&const_MINIMALLY_RESTRICTIVE_value, USPOOF_MINIMALLY_RESTRICTIVE); zend_string *const_MINIMALLY_RESTRICTIVE_name = zend_string_init_interned("MINIMALLY_RESTRICTIVE", sizeof("MINIMALLY_RESTRICTIVE") - 1, 1); zend_declare_typed_class_constant(class_entry, const_MINIMALLY_RESTRICTIVE_name, &const_MINIMALLY_RESTRICTIVE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_MINIMALLY_RESTRICTIVE_name); -#endif -#if U_ICU_VERSION_MAJOR_NUM >= 58 zval const_UNRESTRICTIVE_value; ZVAL_LONG(&const_UNRESTRICTIVE_value, USPOOF_UNRESTRICTIVE); zend_string *const_UNRESTRICTIVE_name = zend_string_init_interned("UNRESTRICTIVE", sizeof("UNRESTRICTIVE") - 1, 1); zend_declare_typed_class_constant(class_entry, const_UNRESTRICTIVE_name, &const_UNRESTRICTIVE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_UNRESTRICTIVE_name); -#endif -#if U_ICU_VERSION_MAJOR_NUM >= 58 zval const_SINGLE_SCRIPT_RESTRICTIVE_value; ZVAL_LONG(&const_SINGLE_SCRIPT_RESTRICTIVE_value, USPOOF_SINGLE_SCRIPT_RESTRICTIVE); zend_string *const_SINGLE_SCRIPT_RESTRICTIVE_name = zend_string_init_interned("SINGLE_SCRIPT_RESTRICTIVE", sizeof("SINGLE_SCRIPT_RESTRICTIVE") - 1, 1); zend_declare_typed_class_constant(class_entry, const_SINGLE_SCRIPT_RESTRICTIVE_name, &const_SINGLE_SCRIPT_RESTRICTIVE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_SINGLE_SCRIPT_RESTRICTIVE_name); -#endif -#if U_ICU_VERSION_MAJOR_NUM >= 58 zval const_MIXED_NUMBERS_value; ZVAL_LONG(&const_MIXED_NUMBERS_value, USPOOF_MIXED_NUMBERS); diff --git a/ext/intl/uchar/uchar_arginfo.h b/ext/intl/uchar/uchar_arginfo.h index 085b3b0a5eff3..f290fb2b958ec 100644 --- a/ext/intl/uchar/uchar_arginfo.h +++ b/ext/intl/uchar/uchar_arginfo.h @@ -465,16 +465,12 @@ static zend_class_entry *register_class_IntlChar(void) zend_string *const_PROPERTY_IDS_UNARY_OPERATOR_name = zend_string_init_interned("PROPERTY_IDS_UNARY_OPERATOR", sizeof("PROPERTY_IDS_UNARY_OPERATOR") - 1, 1); zend_declare_typed_class_constant(class_entry, const_PROPERTY_IDS_UNARY_OPERATOR_name, &const_PROPERTY_IDS_UNARY_OPERATOR_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_PROPERTY_IDS_UNARY_OPERATOR_name); -#endif -#if U_ICU_VERSION_MAJOR_NUM >= 74 zval const_PROPERTY_ID_COMPAT_MATH_START_value; ZVAL_LONG(&const_PROPERTY_ID_COMPAT_MATH_START_value, UCHAR_ID_COMPAT_MATH_START); zend_string *const_PROPERTY_ID_COMPAT_MATH_START_name = zend_string_init_interned("PROPERTY_ID_COMPAT_MATH_START", sizeof("PROPERTY_ID_COMPAT_MATH_START") - 1, 1); zend_declare_typed_class_constant(class_entry, const_PROPERTY_ID_COMPAT_MATH_START_name, &const_PROPERTY_ID_COMPAT_MATH_START_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_PROPERTY_ID_COMPAT_MATH_START_name); -#endif -#if U_ICU_VERSION_MAJOR_NUM >= 74 zval const_PROPERTY_ID_COMPAT_MATH_CONTINUE_value; ZVAL_LONG(&const_PROPERTY_ID_COMPAT_MATH_CONTINUE_value, UCHAR_ID_COMPAT_MATH_CONTINUE); diff --git a/ext/ldap/ldap_arginfo.h b/ext/ldap/ldap_arginfo.h index 984a4bab9a69f..3341b736bb2f1 100644 --- a/ext/ldap/ldap_arginfo.h +++ b/ext/ldap/ldap_arginfo.h @@ -541,11 +541,7 @@ static void register_ldap_symbols(int module_number) REGISTER_STRING_CONSTANT("LDAP_MODIFY_BATCH_VALUES", LDAP_MODIFY_BATCH_VALUES, CONST_PERSISTENT); #if ((LDAP_API_VERSION > 2000) || defined(HAVE_ORALDAP)) REGISTER_LONG_CONSTANT("LDAP_OPT_DEREF", LDAP_OPT_DEREF, CONST_PERSISTENT); -#endif -#if ((LDAP_API_VERSION > 2000) || defined(HAVE_ORALDAP)) REGISTER_LONG_CONSTANT("LDAP_OPT_SIZELIMIT", LDAP_OPT_SIZELIMIT, CONST_PERSISTENT); -#endif -#if ((LDAP_API_VERSION > 2000) || defined(HAVE_ORALDAP)) REGISTER_LONG_CONSTANT("LDAP_OPT_TIMELIMIT", LDAP_OPT_TIMELIMIT, CONST_PERSISTENT); #endif #if ((LDAP_API_VERSION > 2000) || defined(HAVE_ORALDAP)) && defined(LDAP_OPT_NETWORK_TIMEOUT) @@ -559,11 +555,7 @@ static void register_ldap_symbols(int module_number) #endif #if ((LDAP_API_VERSION > 2000) || defined(HAVE_ORALDAP)) REGISTER_LONG_CONSTANT("LDAP_OPT_PROTOCOL_VERSION", LDAP_OPT_PROTOCOL_VERSION, CONST_PERSISTENT); -#endif -#if ((LDAP_API_VERSION > 2000) || defined(HAVE_ORALDAP)) REGISTER_LONG_CONSTANT("LDAP_OPT_ERROR_NUMBER", LDAP_OPT_ERROR_NUMBER, CONST_PERSISTENT); -#endif -#if ((LDAP_API_VERSION > 2000) || defined(HAVE_ORALDAP)) REGISTER_LONG_CONSTANT("LDAP_OPT_REFERRALS", LDAP_OPT_REFERRALS, CONST_PERSISTENT); #endif #if ((LDAP_API_VERSION > 2000) || defined(HAVE_ORALDAP)) && defined(LDAP_OPT_RESTART) @@ -580,8 +572,6 @@ static void register_ldap_symbols(int module_number) #endif #if ((LDAP_API_VERSION > 2000) || defined(HAVE_ORALDAP)) REGISTER_LONG_CONSTANT("LDAP_OPT_SERVER_CONTROLS", LDAP_OPT_SERVER_CONTROLS, CONST_PERSISTENT); -#endif -#if ((LDAP_API_VERSION > 2000) || defined(HAVE_ORALDAP)) REGISTER_LONG_CONSTANT("LDAP_OPT_CLIENT_CONTROLS", LDAP_OPT_CLIENT_CONTROLS, CONST_PERSISTENT); #endif #if defined(LDAP_OPT_DEBUG_LEVEL) @@ -592,14 +582,8 @@ static void register_ldap_symbols(int module_number) #endif #if defined(HAVE_LDAP_SASL) REGISTER_LONG_CONSTANT("LDAP_OPT_X_SASL_MECH", LDAP_OPT_X_SASL_MECH, CONST_PERSISTENT); -#endif -#if defined(HAVE_LDAP_SASL) REGISTER_LONG_CONSTANT("LDAP_OPT_X_SASL_REALM", LDAP_OPT_X_SASL_REALM, CONST_PERSISTENT); -#endif -#if defined(HAVE_LDAP_SASL) REGISTER_LONG_CONSTANT("LDAP_OPT_X_SASL_AUTHCID", LDAP_OPT_X_SASL_AUTHCID, CONST_PERSISTENT); -#endif -#if defined(HAVE_LDAP_SASL) REGISTER_LONG_CONSTANT("LDAP_OPT_X_SASL_AUTHZID", LDAP_OPT_X_SASL_AUTHZID, CONST_PERSISTENT); #endif #if defined(LDAP_OPT_X_SASL_NOCANON) @@ -610,59 +594,27 @@ static void register_ldap_symbols(int module_number) #endif #if defined(HAVE_ORALDAP) REGISTER_LONG_CONSTANT("GSLC_SSL_NO_AUTH", GSLC_SSL_NO_AUTH, CONST_PERSISTENT); -#endif -#if defined(HAVE_ORALDAP) REGISTER_LONG_CONSTANT("GSLC_SSL_ONEWAY_AUTH", GSLC_SSL_ONEWAY_AUTH, CONST_PERSISTENT); -#endif -#if defined(HAVE_ORALDAP) REGISTER_LONG_CONSTANT("GSLC_SSL_TWOWAY_AUTH", GSLC_SSL_TWOWAY_AUTH, CONST_PERSISTENT); #endif #if (LDAP_API_VERSION > 2000) REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_REQUIRE_CERT", LDAP_OPT_X_TLS_REQUIRE_CERT, CONST_PERSISTENT); -#endif -#if (LDAP_API_VERSION > 2000) REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_NEVER", LDAP_OPT_X_TLS_NEVER, CONST_PERSISTENT); -#endif -#if (LDAP_API_VERSION > 2000) REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_HARD", LDAP_OPT_X_TLS_HARD, CONST_PERSISTENT); -#endif -#if (LDAP_API_VERSION > 2000) REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_DEMAND", LDAP_OPT_X_TLS_DEMAND, CONST_PERSISTENT); -#endif -#if (LDAP_API_VERSION > 2000) REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_ALLOW", LDAP_OPT_X_TLS_ALLOW, CONST_PERSISTENT); -#endif -#if (LDAP_API_VERSION > 2000) REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_TRY", LDAP_OPT_X_TLS_TRY, CONST_PERSISTENT); -#endif -#if (LDAP_API_VERSION > 2000) REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_CACERTDIR", LDAP_OPT_X_TLS_CACERTDIR, CONST_PERSISTENT); -#endif -#if (LDAP_API_VERSION > 2000) REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_CACERTFILE", LDAP_OPT_X_TLS_CACERTFILE, CONST_PERSISTENT); -#endif -#if (LDAP_API_VERSION > 2000) REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_CERTFILE", LDAP_OPT_X_TLS_CERTFILE, CONST_PERSISTENT); -#endif -#if (LDAP_API_VERSION > 2000) REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_CIPHER_SUITE", LDAP_OPT_X_TLS_CIPHER_SUITE, CONST_PERSISTENT); -#endif -#if (LDAP_API_VERSION > 2000) REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_KEYFILE", LDAP_OPT_X_TLS_KEYFILE, CONST_PERSISTENT); -#endif -#if (LDAP_API_VERSION > 2000) REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_RANDOM_FILE", LDAP_OPT_X_TLS_RANDOM_FILE, CONST_PERSISTENT); #endif #if defined(LDAP_OPT_X_TLS_CRLCHECK) REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_CRLCHECK", LDAP_OPT_X_TLS_CRLCHECK, CONST_PERSISTENT); -#endif -#if defined(LDAP_OPT_X_TLS_CRLCHECK) REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_CRL_NONE", LDAP_OPT_X_TLS_CRL_NONE, CONST_PERSISTENT); -#endif -#if defined(LDAP_OPT_X_TLS_CRLCHECK) REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_CRL_PEER", LDAP_OPT_X_TLS_CRL_PEER, CONST_PERSISTENT); -#endif -#if defined(LDAP_OPT_X_TLS_CRLCHECK) REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_CRL_ALL", LDAP_OPT_X_TLS_CRL_ALL, CONST_PERSISTENT); #endif #if defined(LDAP_OPT_X_TLS_DHFILE) @@ -673,20 +625,10 @@ static void register_ldap_symbols(int module_number) #endif #if defined(LDAP_OPT_X_TLS_PROTOCOL_MIN) REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_PROTOCOL_MIN", LDAP_OPT_X_TLS_PROTOCOL_MIN, CONST_PERSISTENT); -#endif -#if defined(LDAP_OPT_X_TLS_PROTOCOL_MIN) REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_PROTOCOL_SSL2", LDAP_OPT_X_TLS_PROTOCOL_SSL2, CONST_PERSISTENT); -#endif -#if defined(LDAP_OPT_X_TLS_PROTOCOL_MIN) REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_PROTOCOL_SSL3", LDAP_OPT_X_TLS_PROTOCOL_SSL3, CONST_PERSISTENT); -#endif -#if defined(LDAP_OPT_X_TLS_PROTOCOL_MIN) REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_PROTOCOL_TLS1_0", LDAP_OPT_X_TLS_PROTOCOL_TLS1_0, CONST_PERSISTENT); -#endif -#if defined(LDAP_OPT_X_TLS_PROTOCOL_MIN) REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_PROTOCOL_TLS1_1", LDAP_OPT_X_TLS_PROTOCOL_TLS1_1, CONST_PERSISTENT); -#endif -#if defined(LDAP_OPT_X_TLS_PROTOCOL_MIN) REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_PROTOCOL_TLS1_2", LDAP_OPT_X_TLS_PROTOCOL_TLS1_2, CONST_PERSISTENT); #endif #if defined(LDAP_OPT_X_TLS_PROTOCOL_TLS1_3) @@ -700,28 +642,16 @@ static void register_ldap_symbols(int module_number) #endif #if defined(LDAP_OPT_X_KEEPALIVE_IDLE) REGISTER_LONG_CONSTANT("LDAP_OPT_X_KEEPALIVE_IDLE", LDAP_OPT_X_KEEPALIVE_IDLE, CONST_PERSISTENT); -#endif -#if defined(LDAP_OPT_X_KEEPALIVE_IDLE) REGISTER_LONG_CONSTANT("LDAP_OPT_X_KEEPALIVE_PROBES", LDAP_OPT_X_KEEPALIVE_PROBES, CONST_PERSISTENT); -#endif -#if defined(LDAP_OPT_X_KEEPALIVE_IDLE) REGISTER_LONG_CONSTANT("LDAP_OPT_X_KEEPALIVE_INTERVAL", LDAP_OPT_X_KEEPALIVE_INTERVAL, CONST_PERSISTENT); #endif REGISTER_LONG_CONSTANT("LDAP_ESCAPE_FILTER", PHP_LDAP_ESCAPE_FILTER, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("LDAP_ESCAPE_DN", PHP_LDAP_ESCAPE_DN, CONST_PERSISTENT); #if defined(HAVE_LDAP_EXTENDED_OPERATION_S) REGISTER_STRING_CONSTANT("LDAP_EXOP_START_TLS", LDAP_EXOP_START_TLS, CONST_PERSISTENT); -#endif -#if defined(HAVE_LDAP_EXTENDED_OPERATION_S) REGISTER_STRING_CONSTANT("LDAP_EXOP_MODIFY_PASSWD", LDAP_EXOP_MODIFY_PASSWD, CONST_PERSISTENT); -#endif -#if defined(HAVE_LDAP_EXTENDED_OPERATION_S) REGISTER_STRING_CONSTANT("LDAP_EXOP_REFRESH", LDAP_EXOP_REFRESH, CONST_PERSISTENT); -#endif -#if defined(HAVE_LDAP_EXTENDED_OPERATION_S) REGISTER_STRING_CONSTANT("LDAP_EXOP_WHO_AM_I", LDAP_EXOP_WHO_AM_I, CONST_PERSISTENT); -#endif -#if defined(HAVE_LDAP_EXTENDED_OPERATION_S) REGISTER_STRING_CONSTANT("LDAP_EXOP_TURN", LDAP_EXOP_TURN, CONST_PERSISTENT); #endif #if defined(LDAP_CONTROL_MANAGEDSAIT) @@ -738,17 +668,11 @@ static void register_ldap_symbols(int module_number) #endif #if defined(LDAP_CONTROL_ASSERT) REGISTER_STRING_CONSTANT("LDAP_CONTROL_ASSERT", LDAP_CONTROL_ASSERT, CONST_PERSISTENT); -#endif -#if defined(LDAP_CONTROL_ASSERT) REGISTER_STRING_CONSTANT("LDAP_CONTROL_PRE_READ", LDAP_CONTROL_PRE_READ, CONST_PERSISTENT); -#endif -#if defined(LDAP_CONTROL_ASSERT) REGISTER_STRING_CONSTANT("LDAP_CONTROL_POST_READ", LDAP_CONTROL_POST_READ, CONST_PERSISTENT); #endif #if defined(LDAP_CONTROL_SORTREQUEST) REGISTER_STRING_CONSTANT("LDAP_CONTROL_SORTREQUEST", LDAP_CONTROL_SORTREQUEST, CONST_PERSISTENT); -#endif -#if defined(LDAP_CONTROL_SORTREQUEST) REGISTER_STRING_CONSTANT("LDAP_CONTROL_SORTRESPONSE", LDAP_CONTROL_SORTRESPONSE, CONST_PERSISTENT); #endif #if defined(LDAP_CONTROL_PAGEDRESULTS) @@ -756,17 +680,11 @@ static void register_ldap_symbols(int module_number) #endif #if defined(LDAP_CONTROL_AUTHZID_REQUEST) REGISTER_STRING_CONSTANT("LDAP_CONTROL_AUTHZID_REQUEST", LDAP_CONTROL_AUTHZID_REQUEST, CONST_PERSISTENT); -#endif -#if defined(LDAP_CONTROL_AUTHZID_REQUEST) REGISTER_STRING_CONSTANT("LDAP_CONTROL_AUTHZID_RESPONSE", LDAP_CONTROL_AUTHZID_RESPONSE, CONST_PERSISTENT); #endif #if defined(LDAP_CONTROL_SYNC) REGISTER_STRING_CONSTANT("LDAP_CONTROL_SYNC", LDAP_CONTROL_SYNC, CONST_PERSISTENT); -#endif -#if defined(LDAP_CONTROL_SYNC) REGISTER_STRING_CONSTANT("LDAP_CONTROL_SYNC_STATE", LDAP_CONTROL_SYNC_STATE, CONST_PERSISTENT); -#endif -#if defined(LDAP_CONTROL_SYNC) REGISTER_STRING_CONSTANT("LDAP_CONTROL_SYNC_DONE", LDAP_CONTROL_SYNC_DONE, CONST_PERSISTENT); #endif #if defined(LDAP_CONTROL_DONTUSECOPY) @@ -774,32 +692,18 @@ static void register_ldap_symbols(int module_number) #endif #if defined(LDAP_CONTROL_PASSWORDPOLICYREQUEST) REGISTER_STRING_CONSTANT("LDAP_CONTROL_PASSWORDPOLICYREQUEST", LDAP_CONTROL_PASSWORDPOLICYREQUEST, CONST_PERSISTENT); -#endif -#if defined(LDAP_CONTROL_PASSWORDPOLICYREQUEST) REGISTER_STRING_CONSTANT("LDAP_CONTROL_PASSWORDPOLICYRESPONSE", LDAP_CONTROL_PASSWORDPOLICYRESPONSE, CONST_PERSISTENT); #endif #if defined(LDAP_CONTROL_X_INCREMENTAL_VALUES) REGISTER_STRING_CONSTANT("LDAP_CONTROL_X_INCREMENTAL_VALUES", LDAP_CONTROL_X_INCREMENTAL_VALUES, CONST_PERSISTENT); -#endif -#if defined(LDAP_CONTROL_X_INCREMENTAL_VALUES) REGISTER_STRING_CONSTANT("LDAP_CONTROL_X_DOMAIN_SCOPE", LDAP_CONTROL_X_DOMAIN_SCOPE, CONST_PERSISTENT); -#endif -#if defined(LDAP_CONTROL_X_INCREMENTAL_VALUES) REGISTER_STRING_CONSTANT("LDAP_CONTROL_X_PERMISSIVE_MODIFY", LDAP_CONTROL_X_PERMISSIVE_MODIFY, CONST_PERSISTENT); -#endif -#if defined(LDAP_CONTROL_X_INCREMENTAL_VALUES) REGISTER_STRING_CONSTANT("LDAP_CONTROL_X_SEARCH_OPTIONS", LDAP_CONTROL_X_SEARCH_OPTIONS, CONST_PERSISTENT); -#endif -#if defined(LDAP_CONTROL_X_INCREMENTAL_VALUES) REGISTER_STRING_CONSTANT("LDAP_CONTROL_X_TREE_DELETE", LDAP_CONTROL_X_TREE_DELETE, CONST_PERSISTENT); -#endif -#if defined(LDAP_CONTROL_X_INCREMENTAL_VALUES) REGISTER_STRING_CONSTANT("LDAP_CONTROL_X_EXTENDED_DN", LDAP_CONTROL_X_EXTENDED_DN, CONST_PERSISTENT); #endif #if defined(LDAP_CONTROL_VLVREQUEST) REGISTER_STRING_CONSTANT("LDAP_CONTROL_VLVREQUEST", LDAP_CONTROL_VLVREQUEST, CONST_PERSISTENT); -#endif -#if defined(LDAP_CONTROL_VLVREQUEST) REGISTER_STRING_CONSTANT("LDAP_CONTROL_VLVRESPONSE", LDAP_CONTROL_VLVRESPONSE, CONST_PERSISTENT); #endif diff --git a/ext/odbc/odbc_arginfo.h b/ext/odbc/odbc_arginfo.h index 91df4da846d49..d458fee43383b 100644 --- a/ext/odbc/odbc_arginfo.h +++ b/ext/odbc/odbc_arginfo.h @@ -410,53 +410,21 @@ static void register_odbc_symbols(int module_number) REGISTER_LONG_CONSTANT("SQL_TIMESTAMP", SQL_TIMESTAMP, CONST_PERSISTENT); #if (defined(ODBCVER) && (ODBCVER >= 0x0300)) REGISTER_LONG_CONSTANT("SQL_TYPE_DATE", SQL_TYPE_DATE, CONST_PERSISTENT); -#endif -#if (defined(ODBCVER) && (ODBCVER >= 0x0300)) REGISTER_LONG_CONSTANT("SQL_TYPE_TIME", SQL_TYPE_TIME, CONST_PERSISTENT); -#endif -#if (defined(ODBCVER) && (ODBCVER >= 0x0300)) REGISTER_LONG_CONSTANT("SQL_TYPE_TIMESTAMP", SQL_TYPE_TIMESTAMP, CONST_PERSISTENT); -#endif -#if (defined(ODBCVER) && (ODBCVER >= 0x0300)) REGISTER_LONG_CONSTANT("SQL_WCHAR", SQL_WCHAR, CONST_PERSISTENT); -#endif -#if (defined(ODBCVER) && (ODBCVER >= 0x0300)) REGISTER_LONG_CONSTANT("SQL_WVARCHAR", SQL_WVARCHAR, CONST_PERSISTENT); -#endif -#if (defined(ODBCVER) && (ODBCVER >= 0x0300)) REGISTER_LONG_CONSTANT("SQL_WLONGVARCHAR", SQL_WLONGVARCHAR, CONST_PERSISTENT); -#endif -#if (defined(ODBCVER) && (ODBCVER >= 0x0300)) REGISTER_LONG_CONSTANT("SQL_BEST_ROWID", SQL_BEST_ROWID, CONST_PERSISTENT); -#endif -#if (defined(ODBCVER) && (ODBCVER >= 0x0300)) REGISTER_LONG_CONSTANT("SQL_ROWVER", SQL_ROWVER, CONST_PERSISTENT); -#endif -#if (defined(ODBCVER) && (ODBCVER >= 0x0300)) REGISTER_LONG_CONSTANT("SQL_SCOPE_CURROW", SQL_SCOPE_CURROW, CONST_PERSISTENT); -#endif -#if (defined(ODBCVER) && (ODBCVER >= 0x0300)) REGISTER_LONG_CONSTANT("SQL_SCOPE_TRANSACTION", SQL_SCOPE_TRANSACTION, CONST_PERSISTENT); -#endif -#if (defined(ODBCVER) && (ODBCVER >= 0x0300)) REGISTER_LONG_CONSTANT("SQL_SCOPE_SESSION", SQL_SCOPE_SESSION, CONST_PERSISTENT); -#endif -#if (defined(ODBCVER) && (ODBCVER >= 0x0300)) REGISTER_LONG_CONSTANT("SQL_NO_NULLS", SQL_NO_NULLS, CONST_PERSISTENT); -#endif -#if (defined(ODBCVER) && (ODBCVER >= 0x0300)) REGISTER_LONG_CONSTANT("SQL_NULLABLE", SQL_NULLABLE, CONST_PERSISTENT); -#endif -#if (defined(ODBCVER) && (ODBCVER >= 0x0300)) REGISTER_LONG_CONSTANT("SQL_INDEX_UNIQUE", SQL_INDEX_UNIQUE, CONST_PERSISTENT); -#endif -#if (defined(ODBCVER) && (ODBCVER >= 0x0300)) REGISTER_LONG_CONSTANT("SQL_INDEX_ALL", SQL_INDEX_ALL, CONST_PERSISTENT); -#endif -#if (defined(ODBCVER) && (ODBCVER >= 0x0300)) REGISTER_LONG_CONSTANT("SQL_ENSURE", SQL_ENSURE, CONST_PERSISTENT); -#endif -#if (defined(ODBCVER) && (ODBCVER >= 0x0300)) REGISTER_LONG_CONSTANT("SQL_QUICK", SQL_QUICK, CONST_PERSISTENT); #endif diff --git a/ext/openssl/openssl_arginfo.h b/ext/openssl/openssl_arginfo.h index 94f59ce268510..fb53dcae903e7 100644 --- a/ext/openssl/openssl_arginfo.h +++ b/ext/openssl/openssl_arginfo.h @@ -600,26 +600,16 @@ static void register_openssl_symbols(int module_number) REGISTER_STRING_CONSTANT("OPENSSL_DEFAULT_STREAM_CIPHERS", OPENSSL_DEFAULT_STREAM_CIPHERS, CONST_PERSISTENT); #if !defined(OPENSSL_NO_RC2) REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_40", PHP_OPENSSL_CIPHER_RC2_40, CONST_PERSISTENT); -#endif -#if !defined(OPENSSL_NO_RC2) REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_128", PHP_OPENSSL_CIPHER_RC2_128, CONST_PERSISTENT); -#endif -#if !defined(OPENSSL_NO_RC2) REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_64", PHP_OPENSSL_CIPHER_RC2_64, CONST_PERSISTENT); #endif #if !defined(OPENSSL_NO_DES) REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_DES", PHP_OPENSSL_CIPHER_DES, CONST_PERSISTENT); -#endif -#if !defined(OPENSSL_NO_DES) REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_3DES", PHP_OPENSSL_CIPHER_3DES, CONST_PERSISTENT); #endif #if !defined(OPENSSL_NO_AES) REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_AES_128_CBC", PHP_OPENSSL_CIPHER_AES_128_CBC, CONST_PERSISTENT); -#endif -#if !defined(OPENSSL_NO_AES) REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_AES_192_CBC", PHP_OPENSSL_CIPHER_AES_192_CBC, CONST_PERSISTENT); -#endif -#if !defined(OPENSSL_NO_AES) REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_AES_256_CBC", PHP_OPENSSL_CIPHER_AES_256_CBC, CONST_PERSISTENT); #endif REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_RSA", OPENSSL_KEYTYPE_RSA, CONST_PERSISTENT); @@ -632,14 +622,8 @@ static void register_openssl_symbols(int module_number) #endif #if PHP_OPENSSL_API_VERSION >= 0x30000 REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_X25519", OPENSSL_KEYTYPE_X25519, CONST_PERSISTENT); -#endif -#if PHP_OPENSSL_API_VERSION >= 0x30000 REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_ED25519", OPENSSL_KEYTYPE_ED25519, CONST_PERSISTENT); -#endif -#if PHP_OPENSSL_API_VERSION >= 0x30000 REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_X448", OPENSSL_KEYTYPE_X448, CONST_PERSISTENT); -#endif -#if PHP_OPENSSL_API_VERSION >= 0x30000 REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_ED448", OPENSSL_KEYTYPE_ED448, CONST_PERSISTENT); #endif REGISTER_LONG_CONSTANT("OPENSSL_RAW_DATA", OPENSSL_RAW_DATA, CONST_PERSISTENT); diff --git a/ext/openssl/openssl_pwhash_arginfo.h b/ext/openssl/openssl_pwhash_arginfo.h index 7696675a5a84f..b4213158a169a 100644 --- a/ext/openssl/openssl_pwhash_arginfo.h +++ b/ext/openssl/openssl_pwhash_arginfo.h @@ -5,20 +5,10 @@ static void register_openssl_pwhash_symbols(int module_number) { #if defined(HAVE_OPENSSL_ARGON2) REGISTER_STRING_CONSTANT("PASSWORD_ARGON2I", "argon2i", CONST_PERSISTENT); -#endif -#if defined(HAVE_OPENSSL_ARGON2) REGISTER_STRING_CONSTANT("PASSWORD_ARGON2ID", "argon2id", CONST_PERSISTENT); -#endif -#if defined(HAVE_OPENSSL_ARGON2) REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_DEFAULT_MEMORY_COST", PHP_OPENSSL_PWHASH_MEMLIMIT, CONST_PERSISTENT); -#endif -#if defined(HAVE_OPENSSL_ARGON2) REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_DEFAULT_TIME_COST", PHP_OPENSSL_PWHASH_ITERLIMIT, CONST_PERSISTENT); -#endif -#if defined(HAVE_OPENSSL_ARGON2) REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_DEFAULT_THREADS", PHP_OPENSSL_PWHASH_THREADS, CONST_PERSISTENT); -#endif -#if defined(HAVE_OPENSSL_ARGON2) REGISTER_STRING_CONSTANT("PASSWORD_ARGON2_PROVIDER", "openssl", CONST_PERSISTENT); #endif } diff --git a/ext/pcntl/pcntl_arginfo.h b/ext/pcntl/pcntl_arginfo.h index 8da7cb70a6aa7..bc6581d41e17e 100644 --- a/ext/pcntl/pcntl_arginfo.h +++ b/ext/pcntl/pcntl_arginfo.h @@ -317,11 +317,7 @@ static void register_pcntl_symbols(int module_number) #endif #if defined(HAVE_WAITID) && defined(HAVE_POSIX_IDTYPES) REGISTER_LONG_CONSTANT("P_ALL", LONG_CONST(P_ALL), CONST_PERSISTENT); -#endif -#if defined(HAVE_WAITID) && defined(HAVE_POSIX_IDTYPES) REGISTER_LONG_CONSTANT("P_PID", LONG_CONST(P_PID), CONST_PERSISTENT); -#endif -#if defined(HAVE_WAITID) && defined(HAVE_POSIX_IDTYPES) REGISTER_LONG_CONSTANT("P_PGID", LONG_CONST(P_PGID), CONST_PERSISTENT); #endif #if defined(HAVE_WAITID) && defined(HAVE_LINUX_IDTYPES) @@ -329,11 +325,7 @@ static void register_pcntl_symbols(int module_number) #endif #if defined(HAVE_WAITID) && defined(HAVE_NETBSD_IDTYPES) REGISTER_LONG_CONSTANT("P_UID", LONG_CONST(P_UID), CONST_PERSISTENT); -#endif -#if defined(HAVE_WAITID) && defined(HAVE_NETBSD_IDTYPES) REGISTER_LONG_CONSTANT("P_GID", LONG_CONST(P_GID), CONST_PERSISTENT); -#endif -#if defined(HAVE_WAITID) && defined(HAVE_NETBSD_IDTYPES) REGISTER_LONG_CONSTANT("P_SID", LONG_CONST(P_SID), CONST_PERSISTENT); #endif #if defined(HAVE_WAITID) && defined(HAVE_FREEBSD_IDTYPES) @@ -394,8 +386,6 @@ static void register_pcntl_symbols(int module_number) #endif #if defined(SIGSYS) REGISTER_LONG_CONSTANT("SIGSYS", LONG_CONST(SIGSYS), CONST_PERSISTENT); -#endif -#if defined(SIGSYS) REGISTER_LONG_CONSTANT("SIGBABY", LONG_CONST(SIGSYS), CONST_PERSISTENT); #endif #if defined(SIGCKPT) @@ -412,26 +402,16 @@ static void register_pcntl_symbols(int module_number) #endif #if (defined(HAVE_GETPRIORITY) || defined(HAVE_SETPRIORITY)) REGISTER_LONG_CONSTANT("PRIO_PGRP", PRIO_PGRP, CONST_PERSISTENT); -#endif -#if (defined(HAVE_GETPRIORITY) || defined(HAVE_SETPRIORITY)) REGISTER_LONG_CONSTANT("PRIO_USER", PRIO_USER, CONST_PERSISTENT); -#endif -#if (defined(HAVE_GETPRIORITY) || defined(HAVE_SETPRIORITY)) REGISTER_LONG_CONSTANT("PRIO_PROCESS", PRIO_PROCESS, CONST_PERSISTENT); #endif #if (defined(HAVE_GETPRIORITY) || defined(HAVE_SETPRIORITY)) && defined(PRIO_DARWIN_BG) REGISTER_LONG_CONSTANT("PRIO_DARWIN_BG", PRIO_DARWIN_BG, CONST_PERSISTENT); -#endif -#if (defined(HAVE_GETPRIORITY) || defined(HAVE_SETPRIORITY)) && defined(PRIO_DARWIN_BG) REGISTER_LONG_CONSTANT("PRIO_DARWIN_THREAD", PRIO_DARWIN_THREAD, CONST_PERSISTENT); #endif #if defined(HAVE_SIGPROCMASK) REGISTER_LONG_CONSTANT("SIG_BLOCK", SIG_BLOCK, CONST_PERSISTENT); -#endif -#if defined(HAVE_SIGPROCMASK) REGISTER_LONG_CONSTANT("SIG_UNBLOCK", SIG_UNBLOCK, CONST_PERSISTENT); -#endif -#if defined(HAVE_SIGPROCMASK) REGISTER_LONG_CONSTANT("SIG_SETMASK", SIG_SETMASK, CONST_PERSISTENT); #endif #if (defined(HAVE_SIGWAITINFO) && defined(HAVE_SIGTIMEDWAIT)) @@ -445,14 +425,8 @@ static void register_pcntl_symbols(int module_number) #endif #if (defined(HAVE_SIGWAITINFO) && defined(HAVE_SIGTIMEDWAIT)) REGISTER_LONG_CONSTANT("SI_QUEUE", SI_QUEUE, CONST_PERSISTENT); -#endif -#if (defined(HAVE_SIGWAITINFO) && defined(HAVE_SIGTIMEDWAIT)) REGISTER_LONG_CONSTANT("SI_TIMER", SI_TIMER, CONST_PERSISTENT); -#endif -#if (defined(HAVE_SIGWAITINFO) && defined(HAVE_SIGTIMEDWAIT)) REGISTER_LONG_CONSTANT("SI_MESGQ", SI_MESGQ, CONST_PERSISTENT); -#endif -#if (defined(HAVE_SIGWAITINFO) && defined(HAVE_SIGTIMEDWAIT)) REGISTER_LONG_CONSTANT("SI_ASYNCIO", SI_ASYNCIO, CONST_PERSISTENT); #endif #if (defined(HAVE_SIGWAITINFO) && defined(HAVE_SIGTIMEDWAIT)) && defined(SI_SIGIO) @@ -610,8 +584,6 @@ static void register_pcntl_symbols(int module_number) #endif #if defined(HAVE_FORKX) REGISTER_LONG_CONSTANT("FORK_NOSIGCHLD", FORK_NOSIGCHLD, CONST_PERSISTENT); -#endif -#if defined(HAVE_FORKX) REGISTER_LONG_CONSTANT("FORK_WAITPID", FORK_WAITPID, CONST_PERSISTENT); #endif #if defined(EINTR) diff --git a/ext/pdo_mysql/pdo_mysql_arginfo.h b/ext/pdo_mysql/pdo_mysql_arginfo.h index a6a1b5e1b5c78..0e9c04bd3cfd3 100644 --- a/ext/pdo_mysql/pdo_mysql_arginfo.h +++ b/ext/pdo_mysql/pdo_mysql_arginfo.h @@ -42,16 +42,12 @@ static zend_class_entry *register_class_Pdo_Mysql(zend_class_entry *class_entry_ zend_string *const_ATTR_MAX_BUFFER_SIZE_name = zend_string_init_interned("ATTR_MAX_BUFFER_SIZE", sizeof("ATTR_MAX_BUFFER_SIZE") - 1, 1); zend_declare_typed_class_constant(class_entry, const_ATTR_MAX_BUFFER_SIZE_name, &const_ATTR_MAX_BUFFER_SIZE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_ATTR_MAX_BUFFER_SIZE_name); -#endif -#if !defined(PDO_USE_MYSQLND) zval const_ATTR_READ_DEFAULT_FILE_value; ZVAL_LONG(&const_ATTR_READ_DEFAULT_FILE_value, PDO_MYSQL_ATTR_READ_DEFAULT_FILE); zend_string *const_ATTR_READ_DEFAULT_FILE_name = zend_string_init_interned("ATTR_READ_DEFAULT_FILE", sizeof("ATTR_READ_DEFAULT_FILE") - 1, 1); zend_declare_typed_class_constant(class_entry, const_ATTR_READ_DEFAULT_FILE_name, &const_ATTR_READ_DEFAULT_FILE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_ATTR_READ_DEFAULT_FILE_name); -#endif -#if !defined(PDO_USE_MYSQLND) zval const_ATTR_READ_DEFAULT_GROUP_value; ZVAL_LONG(&const_ATTR_READ_DEFAULT_GROUP_value, PDO_MYSQL_ATTR_READ_DEFAULT_GROUP); diff --git a/ext/pdo_sqlite/pdo_sqlite_arginfo.h b/ext/pdo_sqlite/pdo_sqlite_arginfo.h index 02cf12673ce53..e2cd71723706e 100644 --- a/ext/pdo_sqlite/pdo_sqlite_arginfo.h +++ b/ext/pdo_sqlite/pdo_sqlite_arginfo.h @@ -128,16 +128,12 @@ static zend_class_entry *register_class_Pdo_Sqlite(zend_class_entry *class_entry zend_string *const_EXPLAIN_MODE_PREPARED_name = zend_string_init_interned("EXPLAIN_MODE_PREPARED", sizeof("EXPLAIN_MODE_PREPARED") - 1, 1); zend_declare_typed_class_constant(class_entry, const_EXPLAIN_MODE_PREPARED_name, &const_EXPLAIN_MODE_PREPARED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_EXPLAIN_MODE_PREPARED_name); -#endif -#if SQLITE_VERSION_NUMBER >= 3043000 zval const_EXPLAIN_MODE_EXPLAIN_value; ZVAL_LONG(&const_EXPLAIN_MODE_EXPLAIN_value, 1); zend_string *const_EXPLAIN_MODE_EXPLAIN_name = zend_string_init_interned("EXPLAIN_MODE_EXPLAIN", sizeof("EXPLAIN_MODE_EXPLAIN") - 1, 1); zend_declare_typed_class_constant(class_entry, const_EXPLAIN_MODE_EXPLAIN_name, &const_EXPLAIN_MODE_EXPLAIN_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_EXPLAIN_MODE_EXPLAIN_name); -#endif -#if SQLITE_VERSION_NUMBER >= 3043000 zval const_EXPLAIN_MODE_EXPLAIN_QUERY_PLAN_value; ZVAL_LONG(&const_EXPLAIN_MODE_EXPLAIN_QUERY_PLAN_value, 2); diff --git a/ext/sockets/sockets_arginfo.h b/ext/sockets/sockets_arginfo.h index 4be006bc7f0af..b7af6eb6b89ac 100644 --- a/ext/sockets/sockets_arginfo.h +++ b/ext/sockets/sockets_arginfo.h @@ -413,17 +413,9 @@ static void register_sockets_symbols(int module_number) #endif #if defined(SO_USER_COOKIE) REGISTER_LONG_CONSTANT("SO_LABEL", SO_LABEL, CONST_PERSISTENT); -#endif -#if defined(SO_USER_COOKIE) REGISTER_LONG_CONSTANT("SO_PEERLABEL", SO_PEERLABEL, CONST_PERSISTENT); -#endif -#if defined(SO_USER_COOKIE) REGISTER_LONG_CONSTANT("SO_LISTENQLIMIT", SO_LISTENQLIMIT, CONST_PERSISTENT); -#endif -#if defined(SO_USER_COOKIE) REGISTER_LONG_CONSTANT("SO_LISTENQLEN", SO_LISTENQLEN, CONST_PERSISTENT); -#endif -#if defined(SO_USER_COOKIE) REGISTER_LONG_CONSTANT("SO_USER_COOKIE", SO_USER_COOKIE, CONST_PERSISTENT); #endif #if defined(SO_SETFIB) @@ -443,11 +435,7 @@ static void register_sockets_symbols(int module_number) #endif #if defined(SOL_FILTER) REGISTER_LONG_CONSTANT("SOL_FILTER", SOL_FILTER, CONST_PERSISTENT); -#endif -#if defined(SOL_FILTER) REGISTER_LONG_CONSTANT("FIL_ATTACH", FIL_ATTACH, CONST_PERSISTENT); -#endif -#if defined(SOL_FILTER) REGISTER_LONG_CONSTANT("FIL_DETACH", FIL_DETACH, CONST_PERSISTENT); #endif #if defined(SO_DONTTRUNC) @@ -556,11 +544,7 @@ static void register_sockets_symbols(int module_number) #endif #if defined(TCP_KEEPIDLE) REGISTER_LONG_CONSTANT("TCP_KEEPIDLE", TCP_KEEPIDLE, CONST_PERSISTENT); -#endif -#if defined(TCP_KEEPIDLE) REGISTER_LONG_CONSTANT("TCP_KEEPINTVL", TCP_KEEPINTVL, CONST_PERSISTENT); -#endif -#if defined(TCP_KEEPIDLE) REGISTER_LONG_CONSTANT("TCP_KEEPCNT", TCP_KEEPCNT, CONST_PERSISTENT); #endif #if defined(TCP_FUNCTION_BLK) @@ -571,11 +555,7 @@ static void register_sockets_symbols(int module_number) #endif #if defined(TCP_REUSPORT_LB_NUMA) REGISTER_LONG_CONSTANT("TCP_REUSPORT_LB_NUMA", TCP_REUSPORT_LB_NUMA, CONST_PERSISTENT); -#endif -#if defined(TCP_REUSPORT_LB_NUMA) REGISTER_LONG_CONSTANT("TCP_REUSPORT_LB_NUMA_NODOM", TCP_REUSPORT_LB_NUMA_NODOM, CONST_PERSISTENT); -#endif -#if defined(TCP_REUSPORT_LB_NUMA) REGISTER_LONG_CONSTANT("TCP_REUSPORT_LB_NUMA_CURDOM", TCP_REUSPORT_LB_NUMA_CURDOM, CONST_PERSISTENT); #endif #if defined(TCP_BBR_ALGORITHM) @@ -587,14 +567,8 @@ static void register_sockets_symbols(int module_number) REGISTER_LONG_CONSTANT("MCAST_LEAVE_GROUP", PHP_MCAST_LEAVE_GROUP, CONST_PERSISTENT); #if defined(HAS_MCAST_EXT) REGISTER_LONG_CONSTANT("MCAST_BLOCK_SOURCE", PHP_MCAST_BLOCK_SOURCE, CONST_PERSISTENT); -#endif -#if defined(HAS_MCAST_EXT) REGISTER_LONG_CONSTANT("MCAST_UNBLOCK_SOURCE", PHP_MCAST_UNBLOCK_SOURCE, CONST_PERSISTENT); -#endif -#if defined(HAS_MCAST_EXT) REGISTER_LONG_CONSTANT("MCAST_JOIN_SOURCE_GROUP", PHP_MCAST_JOIN_SOURCE_GROUP, CONST_PERSISTENT); -#endif -#if defined(HAS_MCAST_EXT) REGISTER_LONG_CONSTANT("MCAST_LEAVE_SOURCE_GROUP", PHP_MCAST_LEAVE_SOURCE_GROUP, CONST_PERSISTENT); #endif REGISTER_LONG_CONSTANT("IP_MULTICAST_IF", IP_MULTICAST_IF, CONST_PERSISTENT); @@ -605,11 +579,7 @@ static void register_sockets_symbols(int module_number) #endif #if defined(HAVE_IPV6) REGISTER_LONG_CONSTANT("IPV6_MULTICAST_IF", IPV6_MULTICAST_IF, CONST_PERSISTENT); -#endif -#if defined(HAVE_IPV6) REGISTER_LONG_CONSTANT("IPV6_MULTICAST_HOPS", IPV6_MULTICAST_HOPS, CONST_PERSISTENT); -#endif -#if defined(HAVE_IPV6) REGISTER_LONG_CONSTANT("IPV6_MULTICAST_LOOP", IPV6_MULTICAST_LOOP, CONST_PERSISTENT); #endif #if defined(IPV6_V6ONLY) @@ -617,14 +587,8 @@ static void register_sockets_symbols(int module_number) #endif #if defined(IP_PORTRANGE) REGISTER_LONG_CONSTANT("IP_PORTRANGE", IP_PORTRANGE, CONST_PERSISTENT); -#endif -#if defined(IP_PORTRANGE) REGISTER_LONG_CONSTANT("IP_PORTRANGE_DEFAULT", IP_PORTRANGE_DEFAULT, CONST_PERSISTENT); -#endif -#if defined(IP_PORTRANGE) REGISTER_LONG_CONSTANT("IP_PORTRANGE_HIGH", IP_PORTRANGE_HIGH, CONST_PERSISTENT); -#endif -#if defined(IP_PORTRANGE) REGISTER_LONG_CONSTANT("IP_PORTRANGE_LOW", IP_PORTRANGE_LOW, CONST_PERSISTENT); #endif #if defined(EPERM) @@ -932,32 +896,14 @@ static void register_sockets_symbols(int module_number) #endif #if defined(PHP_WIN32) REGISTER_LONG_CONSTANT("SOCKET_ESTALE", WSAESTALE, CONST_PERSISTENT); -#endif -#if defined(PHP_WIN32) REGISTER_LONG_CONSTANT("SOCKET_EDISCON", WSAEDISCON, CONST_PERSISTENT); -#endif -#if defined(PHP_WIN32) REGISTER_LONG_CONSTANT("SOCKET_SYSNOTREADY", WSASYSNOTREADY, CONST_PERSISTENT); -#endif -#if defined(PHP_WIN32) REGISTER_LONG_CONSTANT("SOCKET_VERNOTSUPPORTED", WSAVERNOTSUPPORTED, CONST_PERSISTENT); -#endif -#if defined(PHP_WIN32) REGISTER_LONG_CONSTANT("SOCKET_NOTINITIALISED", WSANOTINITIALISED, CONST_PERSISTENT); -#endif -#if defined(PHP_WIN32) REGISTER_LONG_CONSTANT("SOCKET_HOST_NOT_FOUND", WSAHOST_NOT_FOUND, CONST_PERSISTENT); -#endif -#if defined(PHP_WIN32) REGISTER_LONG_CONSTANT("SOCKET_TRY_AGAIN", WSATRY_AGAIN, CONST_PERSISTENT); -#endif -#if defined(PHP_WIN32) REGISTER_LONG_CONSTANT("SOCKET_NO_RECOVERY", WSANO_RECOVERY, CONST_PERSISTENT); -#endif -#if defined(PHP_WIN32) REGISTER_LONG_CONSTANT("SOCKET_NO_DATA", WSANO_DATA, CONST_PERSISTENT); -#endif -#if defined(PHP_WIN32) REGISTER_LONG_CONSTANT("SOCKET_NO_ADDRESS", WSANO_ADDRESS, CONST_PERSISTENT); #endif REGISTER_LONG_CONSTANT("IPPROTO_IP", IPPROTO_IP, CONST_PERSISTENT); @@ -990,8 +936,6 @@ static void register_sockets_symbols(int module_number) REGISTER_LONG_CONSTANT("AI_ADDRCONFIG", AI_ADDRCONFIG, CONST_PERSISTENT); #if defined(AI_IDN) REGISTER_LONG_CONSTANT("AI_IDN", AI_IDN, CONST_PERSISTENT); -#endif -#if defined(AI_IDN) REGISTER_LONG_CONSTANT("AI_CANONIDN", AI_CANONIDN, CONST_PERSISTENT); #endif #if defined(AI_NUMERICSERV) @@ -1002,20 +946,14 @@ static void register_sockets_symbols(int module_number) #endif #if (defined(IPV6_RECVPKTINFO) && defined(HAVE_IPV6)) REGISTER_LONG_CONSTANT("IPV6_RECVPKTINFO", IPV6_RECVPKTINFO, CONST_PERSISTENT); -#endif -#if (defined(IPV6_RECVPKTINFO) && defined(HAVE_IPV6)) REGISTER_LONG_CONSTANT("IPV6_PKTINFO", IPV6_PKTINFO, CONST_PERSISTENT); #endif #if (defined(IPV6_RECVHOPLIMIT) && defined(HAVE_IPV6)) REGISTER_LONG_CONSTANT("IPV6_RECVHOPLIMIT", IPV6_RECVHOPLIMIT, CONST_PERSISTENT); -#endif -#if (defined(IPV6_RECVHOPLIMIT) && defined(HAVE_IPV6)) REGISTER_LONG_CONSTANT("IPV6_HOPLIMIT", IPV6_HOPLIMIT, CONST_PERSISTENT); #endif #if (defined(IPV6_RECVTCLASS) && defined(HAVE_IPV6)) REGISTER_LONG_CONSTANT("IPV6_RECVTCLASS", IPV6_RECVTCLASS, CONST_PERSISTENT); -#endif -#if (defined(IPV6_RECVTCLASS) && defined(HAVE_IPV6)) REGISTER_LONG_CONSTANT("IPV6_TCLASS", IPV6_TCLASS, CONST_PERSISTENT); #endif #if defined(SCM_RIGHTS) @@ -1032,14 +970,10 @@ static void register_sockets_symbols(int module_number) #endif #if defined(LOCAL_CREDS_PERSISTENT) REGISTER_LONG_CONSTANT("SCM_CREDS2", SCM_CREDS2, CONST_PERSISTENT); -#endif -#if defined(LOCAL_CREDS_PERSISTENT) REGISTER_LONG_CONSTANT("LOCAL_CREDS_PERSISTENT", LOCAL_CREDS_PERSISTENT, CONST_PERSISTENT); #endif #if (!defined(LOCAL_CREDS_PERSISTENT) && defined(LOCAL_CREDS)) REGISTER_LONG_CONSTANT("SCM_CREDS", SCM_CREDS, CONST_PERSISTENT); -#endif -#if (!defined(LOCAL_CREDS_PERSISTENT) && defined(LOCAL_CREDS)) REGISTER_LONG_CONSTANT("LOCAL_CREDS", LOCAL_CREDS, CONST_PERSISTENT); #endif #if defined(SO_ATTACH_REUSEPORT_CBPF) @@ -1098,14 +1032,8 @@ static void register_sockets_symbols(int module_number) #endif #if defined(ETH_P_ALL) REGISTER_LONG_CONSTANT("ETH_P_IP", ETH_P_IP, CONST_PERSISTENT); -#endif -#if defined(ETH_P_ALL) REGISTER_LONG_CONSTANT("ETH_P_IPV6", ETH_P_IPV6, CONST_PERSISTENT); -#endif -#if defined(ETH_P_ALL) REGISTER_LONG_CONSTANT("ETH_P_LOOP", ETH_P_LOOP, CONST_PERSISTENT); -#endif -#if defined(ETH_P_ALL) REGISTER_LONG_CONSTANT("ETH_P_ALL", ETH_P_ALL, CONST_PERSISTENT); #endif #if defined(UDP_SEGMENT) @@ -1113,11 +1041,7 @@ static void register_sockets_symbols(int module_number) #endif #if defined(SHUT_RDWR) REGISTER_LONG_CONSTANT("SHUT_RD", SHUT_RD, CONST_PERSISTENT); -#endif -#if defined(SHUT_RDWR) REGISTER_LONG_CONSTANT("SHUT_WR", SHUT_WR, CONST_PERSISTENT); -#endif -#if defined(SHUT_RDWR) REGISTER_LONG_CONSTANT("SHUT_RDWR", SHUT_RDWR, CONST_PERSISTENT); #endif } diff --git a/ext/sodium/libsodium_arginfo.h b/ext/sodium/libsodium_arginfo.h index f91a7c5dfe0d9..5fbd831c22e4a 100644 --- a/ext/sodium/libsodium_arginfo.h +++ b/ext/sodium/libsodium_arginfo.h @@ -762,38 +762,20 @@ static void register_libsodium_symbols(int module_number) REGISTER_LONG_CONSTANT("SODIUM_LIBRARY_MINOR_VERSION", sodium_library_version_minor(), CONST_PERSISTENT); #if defined(HAVE_AESGCM) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_AES256GCM_KEYBYTES", crypto_aead_aes256gcm_KEYBYTES, CONST_PERSISTENT); -#endif -#if defined(HAVE_AESGCM) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_AES256GCM_NSECBYTES", crypto_aead_aes256gcm_NSECBYTES, CONST_PERSISTENT); -#endif -#if defined(HAVE_AESGCM) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_AES256GCM_NPUBBYTES", crypto_aead_aes256gcm_NPUBBYTES, CONST_PERSISTENT); -#endif -#if defined(HAVE_AESGCM) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_AES256GCM_ABYTES", crypto_aead_aes256gcm_ABYTES, CONST_PERSISTENT); #endif #if defined(crypto_aead_aegis128l_KEYBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_AEGIS128L_KEYBYTES", crypto_aead_aegis128l_KEYBYTES, CONST_PERSISTENT); -#endif -#if defined(crypto_aead_aegis128l_KEYBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_AEGIS128L_NSECBYTES", crypto_aead_aegis128l_NSECBYTES, CONST_PERSISTENT); -#endif -#if defined(crypto_aead_aegis128l_KEYBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_AEGIS128L_NPUBBYTES", crypto_aead_aegis128l_NPUBBYTES, CONST_PERSISTENT); -#endif -#if defined(crypto_aead_aegis128l_KEYBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_AEGIS128L_ABYTES", crypto_aead_aegis128l_ABYTES, CONST_PERSISTENT); #endif #if defined(crypto_aead_aegis256_KEYBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_AEGIS256_KEYBYTES", crypto_aead_aegis256_KEYBYTES, CONST_PERSISTENT); -#endif -#if defined(crypto_aead_aegis256_KEYBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_AEGIS256_NSECBYTES", crypto_aead_aegis256_NSECBYTES, CONST_PERSISTENT); -#endif -#if defined(crypto_aead_aegis256_KEYBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_AEGIS256_NPUBBYTES", crypto_aead_aegis256_NPUBBYTES, CONST_PERSISTENT); -#endif -#if defined(crypto_aead_aegis256_KEYBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_AEGIS256_ABYTES", crypto_aead_aegis256_ABYTES, CONST_PERSISTENT); #endif REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES", crypto_aead_chacha20poly1305_KEYBYTES, CONST_PERSISTENT); @@ -806,14 +788,8 @@ static void register_libsodium_symbols(int module_number) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_ABYTES", crypto_aead_chacha20poly1305_IETF_ABYTES, CONST_PERSISTENT); #if defined(crypto_aead_xchacha20poly1305_IETF_NPUBBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES", crypto_aead_xchacha20poly1305_IETF_KEYBYTES, CONST_PERSISTENT); -#endif -#if defined(crypto_aead_xchacha20poly1305_IETF_NPUBBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NSECBYTES", crypto_aead_xchacha20poly1305_IETF_NSECBYTES, CONST_PERSISTENT); -#endif -#if defined(crypto_aead_xchacha20poly1305_IETF_NPUBBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES", crypto_aead_xchacha20poly1305_IETF_NPUBBYTES, CONST_PERSISTENT); -#endif -#if defined(crypto_aead_xchacha20poly1305_IETF_NPUBBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES", crypto_aead_xchacha20poly1305_IETF_ABYTES, CONST_PERSISTENT); #endif REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_AUTH_BYTES", crypto_auth_BYTES, CONST_PERSISTENT); @@ -836,26 +812,12 @@ static void register_libsodium_symbols(int module_number) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_KX_KEYPAIRBYTES", SODIUM_CRYPTO_KX_KEYPAIRBYTES(), CONST_PERSISTENT); #if defined(crypto_secretstream_xchacha20poly1305_ABYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES", crypto_secretstream_xchacha20poly1305_ABYTES, CONST_PERSISTENT); -#endif -#if defined(crypto_secretstream_xchacha20poly1305_ABYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES", crypto_secretstream_xchacha20poly1305_HEADERBYTES, CONST_PERSISTENT); -#endif -#if defined(crypto_secretstream_xchacha20poly1305_ABYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES", crypto_secretstream_xchacha20poly1305_KEYBYTES, CONST_PERSISTENT); -#endif -#if defined(crypto_secretstream_xchacha20poly1305_ABYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX", crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX, CONST_PERSISTENT); -#endif -#if defined(crypto_secretstream_xchacha20poly1305_ABYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_MESSAGE", crypto_secretstream_xchacha20poly1305_TAG_MESSAGE, CONST_PERSISTENT); -#endif -#if defined(crypto_secretstream_xchacha20poly1305_ABYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PUSH", crypto_secretstream_xchacha20poly1305_TAG_PUSH, CONST_PERSISTENT); -#endif -#if defined(crypto_secretstream_xchacha20poly1305_ABYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY", crypto_secretstream_xchacha20poly1305_TAG_REKEY, CONST_PERSISTENT); -#endif -#if defined(crypto_secretstream_xchacha20poly1305_ABYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL", crypto_secretstream_xchacha20poly1305_TAG_FINAL, CONST_PERSISTENT); #endif REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_GENERICHASH_BYTES", crypto_generichash_BYTES, CONST_PERSISTENT); @@ -872,47 +834,21 @@ static void register_libsodium_symbols(int module_number) #endif #if defined(crypto_pwhash_SALTBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_PWHASH_ALG_DEFAULT", crypto_pwhash_ALG_DEFAULT, CONST_PERSISTENT); -#endif -#if defined(crypto_pwhash_SALTBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_PWHASH_SALTBYTES", crypto_pwhash_SALTBYTES, CONST_PERSISTENT); -#endif -#if defined(crypto_pwhash_SALTBYTES) REGISTER_STRING_CONSTANT("SODIUM_CRYPTO_PWHASH_STRPREFIX", crypto_pwhash_STRPREFIX, CONST_PERSISTENT); -#endif -#if defined(crypto_pwhash_SALTBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE", crypto_pwhash_opslimit_interactive(), CONST_PERSISTENT); -#endif -#if defined(crypto_pwhash_SALTBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE", crypto_pwhash_memlimit_interactive(), CONST_PERSISTENT); -#endif -#if defined(crypto_pwhash_SALTBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_PWHASH_OPSLIMIT_MODERATE", crypto_pwhash_opslimit_moderate(), CONST_PERSISTENT); -#endif -#if defined(crypto_pwhash_SALTBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_PWHASH_MEMLIMIT_MODERATE", crypto_pwhash_memlimit_moderate(), CONST_PERSISTENT); -#endif -#if defined(crypto_pwhash_SALTBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_PWHASH_OPSLIMIT_SENSITIVE", crypto_pwhash_opslimit_sensitive(), CONST_PERSISTENT); -#endif -#if defined(crypto_pwhash_SALTBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_PWHASH_MEMLIMIT_SENSITIVE", crypto_pwhash_memlimit_sensitive(), CONST_PERSISTENT); #endif #if defined(crypto_pwhash_scryptsalsa208sha256_SALTBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_SALTBYTES", crypto_pwhash_scryptsalsa208sha256_SALTBYTES, CONST_PERSISTENT); -#endif -#if defined(crypto_pwhash_scryptsalsa208sha256_SALTBYTES) REGISTER_STRING_CONSTANT("SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_STRPREFIX", crypto_pwhash_scryptsalsa208sha256_STRPREFIX, CONST_PERSISTENT); -#endif -#if defined(crypto_pwhash_scryptsalsa208sha256_SALTBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_INTERACTIVE", crypto_pwhash_scryptsalsa208sha256_opslimit_interactive(), CONST_PERSISTENT); -#endif -#if defined(crypto_pwhash_scryptsalsa208sha256_SALTBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_INTERACTIVE", crypto_pwhash_scryptsalsa208sha256_memlimit_interactive(), CONST_PERSISTENT); -#endif -#if defined(crypto_pwhash_scryptsalsa208sha256_SALTBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_SENSITIVE", crypto_pwhash_scryptsalsa208sha256_opslimit_sensitive(), CONST_PERSISTENT); -#endif -#if defined(crypto_pwhash_scryptsalsa208sha256_SALTBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_SENSITIVE", crypto_pwhash_scryptsalsa208sha256_memlimit_sensitive(), CONST_PERSISTENT); #endif REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SCALARMULT_BYTES", crypto_scalarmult_BYTES, CONST_PERSISTENT); @@ -931,38 +867,20 @@ static void register_libsodium_symbols(int module_number) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_STREAM_KEYBYTES", crypto_stream_KEYBYTES, CONST_PERSISTENT); #if defined(crypto_stream_xchacha20_KEYBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_STREAM_XCHACHA20_NONCEBYTES", crypto_stream_xchacha20_NONCEBYTES, CONST_PERSISTENT); -#endif -#if defined(crypto_stream_xchacha20_KEYBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_STREAM_XCHACHA20_KEYBYTES", crypto_stream_xchacha20_KEYBYTES, CONST_PERSISTENT); #endif #if defined(sodium_base64_VARIANT_ORIGINAL) REGISTER_LONG_CONSTANT("SODIUM_BASE64_VARIANT_ORIGINAL", sodium_base64_VARIANT_ORIGINAL, CONST_PERSISTENT); -#endif -#if defined(sodium_base64_VARIANT_ORIGINAL) REGISTER_LONG_CONSTANT("SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING", sodium_base64_VARIANT_ORIGINAL_NO_PADDING, CONST_PERSISTENT); -#endif -#if defined(sodium_base64_VARIANT_ORIGINAL) REGISTER_LONG_CONSTANT("SODIUM_BASE64_VARIANT_URLSAFE", sodium_base64_VARIANT_URLSAFE, CONST_PERSISTENT); -#endif -#if defined(sodium_base64_VARIANT_ORIGINAL) REGISTER_LONG_CONSTANT("SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING", sodium_base64_VARIANT_URLSAFE_NO_PADDING, CONST_PERSISTENT); #endif #if defined(crypto_core_ristretto255_HASHBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SCALARMULT_RISTRETTO255_BYTES", crypto_scalarmult_ristretto255_BYTES, CONST_PERSISTENT); -#endif -#if defined(crypto_core_ristretto255_HASHBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_SCALARMULT_RISTRETTO255_SCALARBYTES", crypto_scalarmult_ristretto255_SCALARBYTES, CONST_PERSISTENT); -#endif -#if defined(crypto_core_ristretto255_HASHBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_CORE_RISTRETTO255_BYTES", crypto_core_ristretto255_BYTES, CONST_PERSISTENT); -#endif -#if defined(crypto_core_ristretto255_HASHBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_CORE_RISTRETTO255_HASHBYTES", crypto_core_ristretto255_HASHBYTES, CONST_PERSISTENT); -#endif -#if defined(crypto_core_ristretto255_HASHBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES", crypto_core_ristretto255_SCALARBYTES, CONST_PERSISTENT); -#endif -#if defined(crypto_core_ristretto255_HASHBYTES) REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_CORE_RISTRETTO255_NONREDUCEDSCALARBYTES", crypto_core_ristretto255_NONREDUCEDSCALARBYTES, CONST_PERSISTENT); #endif diff --git a/ext/sodium/sodium_pwhash_arginfo.h b/ext/sodium/sodium_pwhash_arginfo.h index b33d5b5b96f77..465f3090191d1 100644 --- a/ext/sodium/sodium_pwhash_arginfo.h +++ b/ext/sodium/sodium_pwhash_arginfo.h @@ -5,20 +5,10 @@ static void register_sodium_pwhash_symbols(int module_number) { #if SODIUM_LIBRARY_VERSION_MAJOR > 9 || (SODIUM_LIBRARY_VERSION_MAJOR == 9 && SODIUM_LIBRARY_VERSION_MINOR >= 6) REGISTER_STRING_CONSTANT("PASSWORD_ARGON2I", "argon2i", CONST_PERSISTENT); -#endif -#if SODIUM_LIBRARY_VERSION_MAJOR > 9 || (SODIUM_LIBRARY_VERSION_MAJOR == 9 && SODIUM_LIBRARY_VERSION_MINOR >= 6) REGISTER_STRING_CONSTANT("PASSWORD_ARGON2ID", "argon2id", CONST_PERSISTENT); -#endif -#if SODIUM_LIBRARY_VERSION_MAJOR > 9 || (SODIUM_LIBRARY_VERSION_MAJOR == 9 && SODIUM_LIBRARY_VERSION_MINOR >= 6) REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_DEFAULT_MEMORY_COST", PHP_SODIUM_PWHASH_MEMLIMIT, CONST_PERSISTENT); -#endif -#if SODIUM_LIBRARY_VERSION_MAJOR > 9 || (SODIUM_LIBRARY_VERSION_MAJOR == 9 && SODIUM_LIBRARY_VERSION_MINOR >= 6) REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_DEFAULT_TIME_COST", PHP_SODIUM_PWHASH_OPSLIMIT, CONST_PERSISTENT); -#endif -#if SODIUM_LIBRARY_VERSION_MAJOR > 9 || (SODIUM_LIBRARY_VERSION_MAJOR == 9 && SODIUM_LIBRARY_VERSION_MINOR >= 6) REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_DEFAULT_THREADS", PHP_SODIUM_PWHASH_THREADS, CONST_PERSISTENT); -#endif -#if SODIUM_LIBRARY_VERSION_MAJOR > 9 || (SODIUM_LIBRARY_VERSION_MAJOR == 9 && SODIUM_LIBRARY_VERSION_MINOR >= 6) REGISTER_STRING_CONSTANT("PASSWORD_ARGON2_PROVIDER", "sodium", CONST_PERSISTENT); #endif } diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index d221a221f4132..37df4de7bdfcd 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -3592,20 +3592,10 @@ static void register_basic_functions_symbols(int module_number) REGISTER_LONG_CONSTANT("CRYPT_SHA512", 1, CONST_PERSISTENT); #if (defined(PHP_WIN32) || (defined(HAVE_DNS_SEARCH_FUNC) && defined(HAVE_FULL_DNS_FUNCS))) REGISTER_LONG_CONSTANT("DNS_A", PHP_DNS_A, CONST_PERSISTENT); -#endif -#if (defined(PHP_WIN32) || (defined(HAVE_DNS_SEARCH_FUNC) && defined(HAVE_FULL_DNS_FUNCS))) REGISTER_LONG_CONSTANT("DNS_NS", PHP_DNS_NS, CONST_PERSISTENT); -#endif -#if (defined(PHP_WIN32) || (defined(HAVE_DNS_SEARCH_FUNC) && defined(HAVE_FULL_DNS_FUNCS))) REGISTER_LONG_CONSTANT("DNS_CNAME", PHP_DNS_CNAME, CONST_PERSISTENT); -#endif -#if (defined(PHP_WIN32) || (defined(HAVE_DNS_SEARCH_FUNC) && defined(HAVE_FULL_DNS_FUNCS))) REGISTER_LONG_CONSTANT("DNS_SOA", PHP_DNS_SOA, CONST_PERSISTENT); -#endif -#if (defined(PHP_WIN32) || (defined(HAVE_DNS_SEARCH_FUNC) && defined(HAVE_FULL_DNS_FUNCS))) REGISTER_LONG_CONSTANT("DNS_PTR", PHP_DNS_PTR, CONST_PERSISTENT); -#endif -#if (defined(PHP_WIN32) || (defined(HAVE_DNS_SEARCH_FUNC) && defined(HAVE_FULL_DNS_FUNCS))) REGISTER_LONG_CONSTANT("DNS_HINFO", PHP_DNS_HINFO, CONST_PERSISTENT); #endif #if (defined(PHP_WIN32) || (defined(HAVE_DNS_SEARCH_FUNC) && defined(HAVE_FULL_DNS_FUNCS))) && (!defined(PHP_WIN32)) @@ -3613,26 +3603,12 @@ static void register_basic_functions_symbols(int module_number) #endif #if (defined(PHP_WIN32) || (defined(HAVE_DNS_SEARCH_FUNC) && defined(HAVE_FULL_DNS_FUNCS))) REGISTER_LONG_CONSTANT("DNS_MX", PHP_DNS_MX, CONST_PERSISTENT); -#endif -#if (defined(PHP_WIN32) || (defined(HAVE_DNS_SEARCH_FUNC) && defined(HAVE_FULL_DNS_FUNCS))) REGISTER_LONG_CONSTANT("DNS_TXT", PHP_DNS_TXT, CONST_PERSISTENT); -#endif -#if (defined(PHP_WIN32) || (defined(HAVE_DNS_SEARCH_FUNC) && defined(HAVE_FULL_DNS_FUNCS))) REGISTER_LONG_CONSTANT("DNS_SRV", PHP_DNS_SRV, CONST_PERSISTENT); -#endif -#if (defined(PHP_WIN32) || (defined(HAVE_DNS_SEARCH_FUNC) && defined(HAVE_FULL_DNS_FUNCS))) REGISTER_LONG_CONSTANT("DNS_NAPTR", PHP_DNS_NAPTR, CONST_PERSISTENT); -#endif -#if (defined(PHP_WIN32) || (defined(HAVE_DNS_SEARCH_FUNC) && defined(HAVE_FULL_DNS_FUNCS))) REGISTER_LONG_CONSTANT("DNS_AAAA", PHP_DNS_AAAA, CONST_PERSISTENT); -#endif -#if (defined(PHP_WIN32) || (defined(HAVE_DNS_SEARCH_FUNC) && defined(HAVE_FULL_DNS_FUNCS))) REGISTER_LONG_CONSTANT("DNS_A6", PHP_DNS_A6, CONST_PERSISTENT); -#endif -#if (defined(PHP_WIN32) || (defined(HAVE_DNS_SEARCH_FUNC) && defined(HAVE_FULL_DNS_FUNCS))) REGISTER_LONG_CONSTANT("DNS_ANY", PHP_DNS_ANY, CONST_PERSISTENT); -#endif -#if (defined(PHP_WIN32) || (defined(HAVE_DNS_SEARCH_FUNC) && defined(HAVE_FULL_DNS_FUNCS))) REGISTER_LONG_CONSTANT("DNS_ALL", PHP_DNS_ALL, CONST_PERSISTENT); #endif REGISTER_LONG_CONSTANT("HTML_SPECIALCHARS", PHP_HTML_SPECIALCHARS, CONST_PERSISTENT); @@ -3716,26 +3692,12 @@ static void register_basic_functions_symbols(int module_number) #endif #if !defined(PHP_WIN32) REGISTER_LONG_CONSTANT("LOG_LOCAL0", LOG_LOCAL0, CONST_PERSISTENT); -#endif -#if !defined(PHP_WIN32) REGISTER_LONG_CONSTANT("LOG_LOCAL1", LOG_LOCAL1, CONST_PERSISTENT); -#endif -#if !defined(PHP_WIN32) REGISTER_LONG_CONSTANT("LOG_LOCAL2", LOG_LOCAL2, CONST_PERSISTENT); -#endif -#if !defined(PHP_WIN32) REGISTER_LONG_CONSTANT("LOG_LOCAL3", LOG_LOCAL3, CONST_PERSISTENT); -#endif -#if !defined(PHP_WIN32) REGISTER_LONG_CONSTANT("LOG_LOCAL4", LOG_LOCAL4, CONST_PERSISTENT); -#endif -#if !defined(PHP_WIN32) REGISTER_LONG_CONSTANT("LOG_LOCAL5", LOG_LOCAL5, CONST_PERSISTENT); -#endif -#if !defined(PHP_WIN32) REGISTER_LONG_CONSTANT("LOG_LOCAL6", LOG_LOCAL6, CONST_PERSISTENT); -#endif -#if !defined(PHP_WIN32) REGISTER_LONG_CONSTANT("LOG_LOCAL7", LOG_LOCAL7, CONST_PERSISTENT); #endif REGISTER_LONG_CONSTANT("LOG_PID", LOG_PID, CONST_PERSISTENT); @@ -3768,116 +3730,48 @@ static void register_basic_functions_symbols(int module_number) #endif #if defined(HAVE_NL_LANGINFO) && defined(ABDAY_1) REGISTER_LONG_CONSTANT("ABDAY_1", ABDAY_1, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(ABDAY_1) REGISTER_LONG_CONSTANT("ABDAY_2", ABDAY_2, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(ABDAY_1) REGISTER_LONG_CONSTANT("ABDAY_3", ABDAY_3, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(ABDAY_1) REGISTER_LONG_CONSTANT("ABDAY_4", ABDAY_4, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(ABDAY_1) REGISTER_LONG_CONSTANT("ABDAY_5", ABDAY_5, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(ABDAY_1) REGISTER_LONG_CONSTANT("ABDAY_6", ABDAY_6, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(ABDAY_1) REGISTER_LONG_CONSTANT("ABDAY_7", ABDAY_7, CONST_PERSISTENT); #endif #if defined(HAVE_NL_LANGINFO) && defined(DAY_1) REGISTER_LONG_CONSTANT("DAY_1", DAY_1, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(DAY_1) REGISTER_LONG_CONSTANT("DAY_2", DAY_2, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(DAY_1) REGISTER_LONG_CONSTANT("DAY_3", DAY_3, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(DAY_1) REGISTER_LONG_CONSTANT("DAY_4", DAY_4, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(DAY_1) REGISTER_LONG_CONSTANT("DAY_5", DAY_5, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(DAY_1) REGISTER_LONG_CONSTANT("DAY_6", DAY_6, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(DAY_1) REGISTER_LONG_CONSTANT("DAY_7", DAY_7, CONST_PERSISTENT); #endif #if defined(HAVE_NL_LANGINFO) && defined(ABMON_1) REGISTER_LONG_CONSTANT("ABMON_1", ABMON_1, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(ABMON_1) REGISTER_LONG_CONSTANT("ABMON_2", ABMON_2, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(ABMON_1) REGISTER_LONG_CONSTANT("ABMON_3", ABMON_3, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(ABMON_1) REGISTER_LONG_CONSTANT("ABMON_4", ABMON_4, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(ABMON_1) REGISTER_LONG_CONSTANT("ABMON_5", ABMON_5, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(ABMON_1) REGISTER_LONG_CONSTANT("ABMON_6", ABMON_6, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(ABMON_1) REGISTER_LONG_CONSTANT("ABMON_7", ABMON_7, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(ABMON_1) REGISTER_LONG_CONSTANT("ABMON_8", ABMON_8, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(ABMON_1) REGISTER_LONG_CONSTANT("ABMON_9", ABMON_9, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(ABMON_1) REGISTER_LONG_CONSTANT("ABMON_10", ABMON_10, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(ABMON_1) REGISTER_LONG_CONSTANT("ABMON_11", ABMON_11, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(ABMON_1) REGISTER_LONG_CONSTANT("ABMON_12", ABMON_12, CONST_PERSISTENT); #endif #if defined(HAVE_NL_LANGINFO) && defined(MON_1) REGISTER_LONG_CONSTANT("MON_1", MON_1, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(MON_1) REGISTER_LONG_CONSTANT("MON_2", MON_2, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(MON_1) REGISTER_LONG_CONSTANT("MON_3", MON_3, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(MON_1) REGISTER_LONG_CONSTANT("MON_4", MON_4, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(MON_1) REGISTER_LONG_CONSTANT("MON_5", MON_5, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(MON_1) REGISTER_LONG_CONSTANT("MON_6", MON_6, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(MON_1) REGISTER_LONG_CONSTANT("MON_7", MON_7, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(MON_1) REGISTER_LONG_CONSTANT("MON_8", MON_8, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(MON_1) REGISTER_LONG_CONSTANT("MON_9", MON_9, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(MON_1) REGISTER_LONG_CONSTANT("MON_10", MON_10, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(MON_1) REGISTER_LONG_CONSTANT("MON_11", MON_11, CONST_PERSISTENT); -#endif -#if defined(HAVE_NL_LANGINFO) && defined(MON_1) REGISTER_LONG_CONSTANT("MON_12", MON_12, CONST_PERSISTENT); #endif #if defined(HAVE_NL_LANGINFO) && defined(AM_STR) diff --git a/ext/standard/file_arginfo.h b/ext/standard/file_arginfo.h index b96e587a2ea1d..7dc8fcf80aabe 100644 --- a/ext/standard/file_arginfo.h +++ b/ext/standard/file_arginfo.h @@ -112,11 +112,7 @@ static void register_file_symbols(int module_number) REGISTER_LONG_CONSTANT("FILE_BINARY", 0, CONST_PERSISTENT | CONST_DEPRECATED); #if defined(HAVE_FNMATCH) REGISTER_LONG_CONSTANT("FNM_NOESCAPE", FNM_NOESCAPE, CONST_PERSISTENT); -#endif -#if defined(HAVE_FNMATCH) REGISTER_LONG_CONSTANT("FNM_PATHNAME", FNM_PATHNAME, CONST_PERSISTENT); -#endif -#if defined(HAVE_FNMATCH) REGISTER_LONG_CONSTANT("FNM_PERIOD", FNM_PERIOD, CONST_PERSISTENT); #endif #if defined(HAVE_FNMATCH) && defined(FNM_CASEFOLD) diff --git a/ext/standard/password_arginfo.h b/ext/standard/password_arginfo.h index bf1b614273a4a..fd25fbed67739 100644 --- a/ext/standard/password_arginfo.h +++ b/ext/standard/password_arginfo.h @@ -8,20 +8,10 @@ static void register_password_symbols(int module_number) REGISTER_LONG_CONSTANT("PASSWORD_BCRYPT_DEFAULT_COST", PHP_PASSWORD_BCRYPT_COST, CONST_PERSISTENT); #if defined(HAVE_ARGON2LIB) REGISTER_STRING_CONSTANT("PASSWORD_ARGON2I", "argon2i", CONST_PERSISTENT); -#endif -#if defined(HAVE_ARGON2LIB) REGISTER_STRING_CONSTANT("PASSWORD_ARGON2ID", "argon2id", CONST_PERSISTENT); -#endif -#if defined(HAVE_ARGON2LIB) REGISTER_STRING_CONSTANT("PASSWORD_ARGON2_PROVIDER", "standard", CONST_PERSISTENT); -#endif -#if defined(HAVE_ARGON2LIB) REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_DEFAULT_MEMORY_COST", PHP_PASSWORD_ARGON2_MEMORY_COST, CONST_PERSISTENT); -#endif -#if defined(HAVE_ARGON2LIB) REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_DEFAULT_TIME_COST", PHP_PASSWORD_ARGON2_TIME_COST, CONST_PERSISTENT); -#endif -#if defined(HAVE_ARGON2LIB) REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_DEFAULT_THREADS", PHP_PASSWORD_ARGON2_THREADS, CONST_PERSISTENT); #endif } diff --git a/ext/tidy/tidy_arginfo.h b/ext/tidy/tidy_arginfo.h index b7dae788ef316..4084a29f4d908 100644 --- a/ext/tidy/tidy_arginfo.h +++ b/ext/tidy/tidy_arginfo.h @@ -437,86 +437,32 @@ static void register_tidy_symbols(int module_number) REGISTER_LONG_CONSTANT("TIDY_TAG_XMP", TidyTag_XMP, CONST_PERSISTENT); #if defined(HAVE_TIDYBUFFIO_H) REGISTER_LONG_CONSTANT("TIDY_TAG_ARTICLE", TidyTag_ARTICLE, CONST_PERSISTENT); -#endif -#if defined(HAVE_TIDYBUFFIO_H) REGISTER_LONG_CONSTANT("TIDY_TAG_ASIDE", TidyTag_ASIDE, CONST_PERSISTENT); -#endif -#if defined(HAVE_TIDYBUFFIO_H) REGISTER_LONG_CONSTANT("TIDY_TAG_AUDIO", TidyTag_AUDIO, CONST_PERSISTENT); -#endif -#if defined(HAVE_TIDYBUFFIO_H) REGISTER_LONG_CONSTANT("TIDY_TAG_BDI", TidyTag_BDI, CONST_PERSISTENT); -#endif -#if defined(HAVE_TIDYBUFFIO_H) REGISTER_LONG_CONSTANT("TIDY_TAG_CANVAS", TidyTag_CANVAS, CONST_PERSISTENT); -#endif -#if defined(HAVE_TIDYBUFFIO_H) REGISTER_LONG_CONSTANT("TIDY_TAG_COMMAND", TidyTag_COMMAND, CONST_PERSISTENT); -#endif -#if defined(HAVE_TIDYBUFFIO_H) REGISTER_LONG_CONSTANT("TIDY_TAG_DATALIST", TidyTag_DATALIST, CONST_PERSISTENT); -#endif -#if defined(HAVE_TIDYBUFFIO_H) REGISTER_LONG_CONSTANT("TIDY_TAG_DETAILS", TidyTag_DETAILS, CONST_PERSISTENT); -#endif -#if defined(HAVE_TIDYBUFFIO_H) REGISTER_LONG_CONSTANT("TIDY_TAG_DIALOG", TidyTag_DIALOG, CONST_PERSISTENT); -#endif -#if defined(HAVE_TIDYBUFFIO_H) REGISTER_LONG_CONSTANT("TIDY_TAG_FIGCAPTION", TidyTag_FIGCAPTION, CONST_PERSISTENT); -#endif -#if defined(HAVE_TIDYBUFFIO_H) REGISTER_LONG_CONSTANT("TIDY_TAG_FIGURE", TidyTag_FIGURE, CONST_PERSISTENT); -#endif -#if defined(HAVE_TIDYBUFFIO_H) REGISTER_LONG_CONSTANT("TIDY_TAG_FOOTER", TidyTag_FOOTER, CONST_PERSISTENT); -#endif -#if defined(HAVE_TIDYBUFFIO_H) REGISTER_LONG_CONSTANT("TIDY_TAG_HEADER", TidyTag_HEADER, CONST_PERSISTENT); -#endif -#if defined(HAVE_TIDYBUFFIO_H) REGISTER_LONG_CONSTANT("TIDY_TAG_HGROUP", TidyTag_HGROUP, CONST_PERSISTENT); -#endif -#if defined(HAVE_TIDYBUFFIO_H) REGISTER_LONG_CONSTANT("TIDY_TAG_MAIN", TidyTag_MAIN, CONST_PERSISTENT); -#endif -#if defined(HAVE_TIDYBUFFIO_H) REGISTER_LONG_CONSTANT("TIDY_TAG_MARK", TidyTag_MARK, CONST_PERSISTENT); -#endif -#if defined(HAVE_TIDYBUFFIO_H) REGISTER_LONG_CONSTANT("TIDY_TAG_MENUITEM", TidyTag_MENUITEM, CONST_PERSISTENT); -#endif -#if defined(HAVE_TIDYBUFFIO_H) REGISTER_LONG_CONSTANT("TIDY_TAG_METER", TidyTag_METER, CONST_PERSISTENT); -#endif -#if defined(HAVE_TIDYBUFFIO_H) REGISTER_LONG_CONSTANT("TIDY_TAG_NAV", TidyTag_NAV, CONST_PERSISTENT); -#endif -#if defined(HAVE_TIDYBUFFIO_H) REGISTER_LONG_CONSTANT("TIDY_TAG_OUTPUT", TidyTag_OUTPUT, CONST_PERSISTENT); -#endif -#if defined(HAVE_TIDYBUFFIO_H) REGISTER_LONG_CONSTANT("TIDY_TAG_PROGRESS", TidyTag_PROGRESS, CONST_PERSISTENT); -#endif -#if defined(HAVE_TIDYBUFFIO_H) REGISTER_LONG_CONSTANT("TIDY_TAG_SECTION", TidyTag_SECTION, CONST_PERSISTENT); -#endif -#if defined(HAVE_TIDYBUFFIO_H) REGISTER_LONG_CONSTANT("TIDY_TAG_SOURCE", TidyTag_SOURCE, CONST_PERSISTENT); -#endif -#if defined(HAVE_TIDYBUFFIO_H) REGISTER_LONG_CONSTANT("TIDY_TAG_SUMMARY", TidyTag_SUMMARY, CONST_PERSISTENT); -#endif -#if defined(HAVE_TIDYBUFFIO_H) REGISTER_LONG_CONSTANT("TIDY_TAG_TEMPLATE", TidyTag_TEMPLATE, CONST_PERSISTENT); -#endif -#if defined(HAVE_TIDYBUFFIO_H) REGISTER_LONG_CONSTANT("TIDY_TAG_TIME", TidyTag_TIME, CONST_PERSISTENT); -#endif -#if defined(HAVE_TIDYBUFFIO_H) REGISTER_LONG_CONSTANT("TIDY_TAG_TRACK", TidyTag_TRACK, CONST_PERSISTENT); -#endif -#if defined(HAVE_TIDYBUFFIO_H) REGISTER_LONG_CONSTANT("TIDY_TAG_VIDEO", TidyTag_VIDEO, CONST_PERSISTENT); #endif } diff --git a/ext/xsl/php_xsl_arginfo.h b/ext/xsl/php_xsl_arginfo.h index d040928197f65..72e7ed0b0a99d 100644 --- a/ext/xsl/php_xsl_arginfo.h +++ b/ext/xsl/php_xsl_arginfo.h @@ -106,8 +106,6 @@ static void register_php_xsl_symbols(int module_number) REGISTER_STRING_CONSTANT("LIBXSLT_DOTTED_VERSION", LIBXSLT_DOTTED_VERSION, CONST_PERSISTENT); #if defined(HAVE_XSL_EXSLT) REGISTER_LONG_CONSTANT("LIBEXSLT_VERSION", LIBEXSLT_VERSION, CONST_PERSISTENT); -#endif -#if defined(HAVE_XSL_EXSLT) REGISTER_STRING_CONSTANT("LIBEXSLT_DOTTED_VERSION", LIBEXSLT_DOTTED_VERSION, CONST_PERSISTENT); #endif } diff --git a/ext/zip/php_zip_arginfo.h b/ext/zip/php_zip_arginfo.h index 6166218b2d8dd..c8dab41560e48 100644 --- a/ext/zip/php_zip_arginfo.h +++ b/ext/zip/php_zip_arginfo.h @@ -1103,160 +1103,120 @@ static zend_class_entry *register_class_ZipArchive(zend_class_entry *class_entry zend_string *const_OPSYS_DOS_name = zend_string_init_interned("OPSYS_DOS", sizeof("OPSYS_DOS") - 1, 1); zend_declare_typed_class_constant(class_entry, const_OPSYS_DOS_name, &const_OPSYS_DOS_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_OPSYS_DOS_name); -#endif -#if defined(ZIP_OPSYS_DEFAULT) zval const_OPSYS_AMIGA_value; ZVAL_LONG(&const_OPSYS_AMIGA_value, ZIP_OPSYS_AMIGA); zend_string *const_OPSYS_AMIGA_name = zend_string_init_interned("OPSYS_AMIGA", sizeof("OPSYS_AMIGA") - 1, 1); zend_declare_typed_class_constant(class_entry, const_OPSYS_AMIGA_name, &const_OPSYS_AMIGA_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_OPSYS_AMIGA_name); -#endif -#if defined(ZIP_OPSYS_DEFAULT) zval const_OPSYS_OPENVMS_value; ZVAL_LONG(&const_OPSYS_OPENVMS_value, ZIP_OPSYS_OPENVMS); zend_string *const_OPSYS_OPENVMS_name = zend_string_init_interned("OPSYS_OPENVMS", sizeof("OPSYS_OPENVMS") - 1, 1); zend_declare_typed_class_constant(class_entry, const_OPSYS_OPENVMS_name, &const_OPSYS_OPENVMS_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_OPSYS_OPENVMS_name); -#endif -#if defined(ZIP_OPSYS_DEFAULT) zval const_OPSYS_UNIX_value; ZVAL_LONG(&const_OPSYS_UNIX_value, ZIP_OPSYS_UNIX); zend_string *const_OPSYS_UNIX_name = zend_string_init_interned("OPSYS_UNIX", sizeof("OPSYS_UNIX") - 1, 1); zend_declare_typed_class_constant(class_entry, const_OPSYS_UNIX_name, &const_OPSYS_UNIX_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_OPSYS_UNIX_name); -#endif -#if defined(ZIP_OPSYS_DEFAULT) zval const_OPSYS_VM_CMS_value; ZVAL_LONG(&const_OPSYS_VM_CMS_value, ZIP_OPSYS_VM_CMS); zend_string *const_OPSYS_VM_CMS_name = zend_string_init_interned("OPSYS_VM_CMS", sizeof("OPSYS_VM_CMS") - 1, 1); zend_declare_typed_class_constant(class_entry, const_OPSYS_VM_CMS_name, &const_OPSYS_VM_CMS_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_OPSYS_VM_CMS_name); -#endif -#if defined(ZIP_OPSYS_DEFAULT) zval const_OPSYS_ATARI_ST_value; ZVAL_LONG(&const_OPSYS_ATARI_ST_value, ZIP_OPSYS_ATARI_ST); zend_string *const_OPSYS_ATARI_ST_name = zend_string_init_interned("OPSYS_ATARI_ST", sizeof("OPSYS_ATARI_ST") - 1, 1); zend_declare_typed_class_constant(class_entry, const_OPSYS_ATARI_ST_name, &const_OPSYS_ATARI_ST_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_OPSYS_ATARI_ST_name); -#endif -#if defined(ZIP_OPSYS_DEFAULT) zval const_OPSYS_OS_2_value; ZVAL_LONG(&const_OPSYS_OS_2_value, ZIP_OPSYS_OS_2); zend_string *const_OPSYS_OS_2_name = zend_string_init_interned("OPSYS_OS_2", sizeof("OPSYS_OS_2") - 1, 1); zend_declare_typed_class_constant(class_entry, const_OPSYS_OS_2_name, &const_OPSYS_OS_2_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_OPSYS_OS_2_name); -#endif -#if defined(ZIP_OPSYS_DEFAULT) zval const_OPSYS_MACINTOSH_value; ZVAL_LONG(&const_OPSYS_MACINTOSH_value, ZIP_OPSYS_MACINTOSH); zend_string *const_OPSYS_MACINTOSH_name = zend_string_init_interned("OPSYS_MACINTOSH", sizeof("OPSYS_MACINTOSH") - 1, 1); zend_declare_typed_class_constant(class_entry, const_OPSYS_MACINTOSH_name, &const_OPSYS_MACINTOSH_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_OPSYS_MACINTOSH_name); -#endif -#if defined(ZIP_OPSYS_DEFAULT) zval const_OPSYS_Z_SYSTEM_value; ZVAL_LONG(&const_OPSYS_Z_SYSTEM_value, ZIP_OPSYS_Z_SYSTEM); zend_string *const_OPSYS_Z_SYSTEM_name = zend_string_init_interned("OPSYS_Z_SYSTEM", sizeof("OPSYS_Z_SYSTEM") - 1, 1); zend_declare_typed_class_constant(class_entry, const_OPSYS_Z_SYSTEM_name, &const_OPSYS_Z_SYSTEM_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_OPSYS_Z_SYSTEM_name); -#endif -#if defined(ZIP_OPSYS_DEFAULT) zval const_OPSYS_CPM_value; ZVAL_LONG(&const_OPSYS_CPM_value, ZIP_OPSYS_CPM); zend_string *const_OPSYS_CPM_name = zend_string_init_interned("OPSYS_CPM", sizeof("OPSYS_CPM") - 1, 1); zend_declare_typed_class_constant(class_entry, const_OPSYS_CPM_name, &const_OPSYS_CPM_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_OPSYS_CPM_name); -#endif -#if defined(ZIP_OPSYS_DEFAULT) zval const_OPSYS_WINDOWS_NTFS_value; ZVAL_LONG(&const_OPSYS_WINDOWS_NTFS_value, ZIP_OPSYS_WINDOWS_NTFS); zend_string *const_OPSYS_WINDOWS_NTFS_name = zend_string_init_interned("OPSYS_WINDOWS_NTFS", sizeof("OPSYS_WINDOWS_NTFS") - 1, 1); zend_declare_typed_class_constant(class_entry, const_OPSYS_WINDOWS_NTFS_name, &const_OPSYS_WINDOWS_NTFS_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_OPSYS_WINDOWS_NTFS_name); -#endif -#if defined(ZIP_OPSYS_DEFAULT) zval const_OPSYS_MVS_value; ZVAL_LONG(&const_OPSYS_MVS_value, ZIP_OPSYS_MVS); zend_string *const_OPSYS_MVS_name = zend_string_init_interned("OPSYS_MVS", sizeof("OPSYS_MVS") - 1, 1); zend_declare_typed_class_constant(class_entry, const_OPSYS_MVS_name, &const_OPSYS_MVS_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_OPSYS_MVS_name); -#endif -#if defined(ZIP_OPSYS_DEFAULT) zval const_OPSYS_VSE_value; ZVAL_LONG(&const_OPSYS_VSE_value, ZIP_OPSYS_VSE); zend_string *const_OPSYS_VSE_name = zend_string_init_interned("OPSYS_VSE", sizeof("OPSYS_VSE") - 1, 1); zend_declare_typed_class_constant(class_entry, const_OPSYS_VSE_name, &const_OPSYS_VSE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_OPSYS_VSE_name); -#endif -#if defined(ZIP_OPSYS_DEFAULT) zval const_OPSYS_ACORN_RISC_value; ZVAL_LONG(&const_OPSYS_ACORN_RISC_value, ZIP_OPSYS_ACORN_RISC); zend_string *const_OPSYS_ACORN_RISC_name = zend_string_init_interned("OPSYS_ACORN_RISC", sizeof("OPSYS_ACORN_RISC") - 1, 1); zend_declare_typed_class_constant(class_entry, const_OPSYS_ACORN_RISC_name, &const_OPSYS_ACORN_RISC_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_OPSYS_ACORN_RISC_name); -#endif -#if defined(ZIP_OPSYS_DEFAULT) zval const_OPSYS_VFAT_value; ZVAL_LONG(&const_OPSYS_VFAT_value, ZIP_OPSYS_VFAT); zend_string *const_OPSYS_VFAT_name = zend_string_init_interned("OPSYS_VFAT", sizeof("OPSYS_VFAT") - 1, 1); zend_declare_typed_class_constant(class_entry, const_OPSYS_VFAT_name, &const_OPSYS_VFAT_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_OPSYS_VFAT_name); -#endif -#if defined(ZIP_OPSYS_DEFAULT) zval const_OPSYS_ALTERNATE_MVS_value; ZVAL_LONG(&const_OPSYS_ALTERNATE_MVS_value, ZIP_OPSYS_ALTERNATE_MVS); zend_string *const_OPSYS_ALTERNATE_MVS_name = zend_string_init_interned("OPSYS_ALTERNATE_MVS", sizeof("OPSYS_ALTERNATE_MVS") - 1, 1); zend_declare_typed_class_constant(class_entry, const_OPSYS_ALTERNATE_MVS_name, &const_OPSYS_ALTERNATE_MVS_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_OPSYS_ALTERNATE_MVS_name); -#endif -#if defined(ZIP_OPSYS_DEFAULT) zval const_OPSYS_BEOS_value; ZVAL_LONG(&const_OPSYS_BEOS_value, ZIP_OPSYS_BEOS); zend_string *const_OPSYS_BEOS_name = zend_string_init_interned("OPSYS_BEOS", sizeof("OPSYS_BEOS") - 1, 1); zend_declare_typed_class_constant(class_entry, const_OPSYS_BEOS_name, &const_OPSYS_BEOS_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_OPSYS_BEOS_name); -#endif -#if defined(ZIP_OPSYS_DEFAULT) zval const_OPSYS_TANDEM_value; ZVAL_LONG(&const_OPSYS_TANDEM_value, ZIP_OPSYS_TANDEM); zend_string *const_OPSYS_TANDEM_name = zend_string_init_interned("OPSYS_TANDEM", sizeof("OPSYS_TANDEM") - 1, 1); zend_declare_typed_class_constant(class_entry, const_OPSYS_TANDEM_name, &const_OPSYS_TANDEM_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_OPSYS_TANDEM_name); -#endif -#if defined(ZIP_OPSYS_DEFAULT) zval const_OPSYS_OS_400_value; ZVAL_LONG(&const_OPSYS_OS_400_value, ZIP_OPSYS_OS_400); zend_string *const_OPSYS_OS_400_name = zend_string_init_interned("OPSYS_OS_400", sizeof("OPSYS_OS_400") - 1, 1); zend_declare_typed_class_constant(class_entry, const_OPSYS_OS_400_name, &const_OPSYS_OS_400_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_OPSYS_OS_400_name); -#endif -#if defined(ZIP_OPSYS_DEFAULT) zval const_OPSYS_OS_X_value; ZVAL_LONG(&const_OPSYS_OS_X_value, ZIP_OPSYS_OS_X); zend_string *const_OPSYS_OS_X_name = zend_string_init_interned("OPSYS_OS_X", sizeof("OPSYS_OS_X") - 1, 1); zend_declare_typed_class_constant(class_entry, const_OPSYS_OS_X_name, &const_OPSYS_OS_X_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_OPSYS_OS_X_name); -#endif -#if defined(ZIP_OPSYS_DEFAULT) zval const_OPSYS_DEFAULT_value; ZVAL_LONG(&const_OPSYS_DEFAULT_value, ZIP_OPSYS_DEFAULT); @@ -1283,16 +1243,12 @@ static zend_class_entry *register_class_ZipArchive(zend_class_entry *class_entry zend_string *const_EM_AES_128_name = zend_string_init_interned("EM_AES_128", sizeof("EM_AES_128") - 1, 1); zend_declare_typed_class_constant(class_entry, const_EM_AES_128_name, &const_EM_AES_128_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_EM_AES_128_name); -#endif -#if defined(HAVE_ENCRYPTION) zval const_EM_AES_192_value; ZVAL_LONG(&const_EM_AES_192_value, ZIP_EM_AES_192); zend_string *const_EM_AES_192_name = zend_string_init_interned("EM_AES_192", sizeof("EM_AES_192") - 1, 1); zend_declare_typed_class_constant(class_entry, const_EM_AES_192_name, &const_EM_AES_192_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_EM_AES_192_name); -#endif -#if defined(HAVE_ENCRYPTION) zval const_EM_AES_256_value; ZVAL_LONG(&const_EM_AES_256_value, ZIP_EM_AES_256); diff --git a/main/main_arginfo.h b/main/main_arginfo.h index f0d2599baf473..922af3aff0629 100644 --- a/main/main_arginfo.h +++ b/main/main_arginfo.h @@ -43,35 +43,15 @@ static void register_main_symbols(int module_number) REGISTER_DOUBLE_CONSTANT("PHP_FLOAT_MIN", DBL_MIN, CONST_PERSISTENT); #if defined(PHP_WIN32) REGISTER_LONG_CONSTANT("PHP_WINDOWS_VERSION_MAJOR", EG(windows_version_info).dwMajorVersion, CONST_PERSISTENT); -#endif -#if defined(PHP_WIN32) REGISTER_LONG_CONSTANT("PHP_WINDOWS_VERSION_MINOR", EG(windows_version_info).dwMinorVersion, CONST_PERSISTENT); -#endif -#if defined(PHP_WIN32) REGISTER_LONG_CONSTANT("PHP_WINDOWS_VERSION_BUILD", EG(windows_version_info).dwBuildNumber, CONST_PERSISTENT); -#endif -#if defined(PHP_WIN32) REGISTER_LONG_CONSTANT("PHP_WINDOWS_VERSION_PLATFORM", EG(windows_version_info).dwPlatformId, CONST_PERSISTENT); -#endif -#if defined(PHP_WIN32) REGISTER_LONG_CONSTANT("PHP_WINDOWS_VERSION_SP_MAJOR", EG(windows_version_info).wServicePackMajor, CONST_PERSISTENT); -#endif -#if defined(PHP_WIN32) REGISTER_LONG_CONSTANT("PHP_WINDOWS_VERSION_SP_MINOR", EG(windows_version_info).wServicePackMinor, CONST_PERSISTENT); -#endif -#if defined(PHP_WIN32) REGISTER_LONG_CONSTANT("PHP_WINDOWS_VERSION_SUITEMASK", EG(windows_version_info).wSuiteMask, CONST_PERSISTENT); -#endif -#if defined(PHP_WIN32) REGISTER_LONG_CONSTANT("PHP_WINDOWS_VERSION_PRODUCTTYPE", EG(windows_version_info).wProductType, CONST_PERSISTENT); -#endif -#if defined(PHP_WIN32) REGISTER_LONG_CONSTANT("PHP_WINDOWS_NT_DOMAIN_CONTROLLER", VER_NT_DOMAIN_CONTROLLER, CONST_PERSISTENT); -#endif -#if defined(PHP_WIN32) REGISTER_LONG_CONSTANT("PHP_WINDOWS_NT_SERVER", VER_NT_SERVER, CONST_PERSISTENT); -#endif -#if defined(PHP_WIN32) REGISTER_LONG_CONSTANT("PHP_WINDOWS_NT_WORKSTATION", VER_NT_WORKSTATION, CONST_PERSISTENT); #endif REGISTER_LONG_CONSTANT("PHP_OUTPUT_HANDLER_START", PHP_OUTPUT_HANDLER_START, CONST_PERSISTENT); From e9310171f767d95c34df90eebfbec7d61ad22bbc Mon Sep 17 00:00:00 2001 From: Saki Takamachi <34942839+SakiTakamachi@users.noreply.github.com> Date: Mon, 23 Jun 2025 15:29:20 +0900 Subject: [PATCH 064/120] [skip ci] Add myself to EXTENSIONS (#18918) --- EXTENSIONS | 1 + 1 file changed, 1 insertion(+) diff --git a/EXTENSIONS b/EXTENSIONS index 34e289ffcae2b..d15401f372384 100644 --- a/EXTENSIONS +++ b/EXTENSIONS @@ -238,6 +238,7 @@ SINCE: 5.0 ------------------------------------------------------------------------------- EXTENSION: bcmath PRIMARY MAINTAINER: Andi Gutmans (2000 - 2004) + Saki Takamachi (2024 - 2025) MAINTENANCE: Maintained STATUS: Working ------------------------------------------------------------------------------- From 22bd2ae63f33cfcbd4f2383f4fe8ffa480a1ab42 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sun, 15 Jun 2025 00:04:30 +0100 Subject: [PATCH 065/120] ext/sqlite3: explain statement support addition. similar to what have been done for pdo/sqlite as having statement explain support to simulate how a query would operate or for more advanced users, analysing the VM routines used for possible optimisations. close GH-18853 --- NEWS | 2 + ext/sqlite3/sqlite3.c | 57 ++++ ext/sqlite3/sqlite3.stub.php | 9 + ext/sqlite3/sqlite3_arginfo.h | 43 ++- ext/sqlite3/tests/sqlite3_explain.phpt | 390 +++++++++++++++++++++++++ 5 files changed, 500 insertions(+), 1 deletion(-) create mode 100644 ext/sqlite3/tests/sqlite3_explain.phpt diff --git a/NEWS b/NEWS index dfa90ed08f62c..ccda0d50af84e 100644 --- a/NEWS +++ b/NEWS @@ -247,6 +247,8 @@ PHP NEWS - Sqlite: . Added Sqlite3Stmt::busy to check if a statement is still being executed. (David Carlier) + . Added Sqlite3Stmt::explain to produce a explain query plan from + the statement. (David Carlier) - Standard: . Fixed crypt() tests on musl when using --with-external-libcrypt diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c index 799c77b24a8c8..349d2823bb1e0 100644 --- a/ext/sqlite3/sqlite3.c +++ b/ext/sqlite3/sqlite3.c @@ -26,6 +26,9 @@ #include "SAPI.h" #include +#ifdef __APPLE__ +#include +#endif #include "zend_exceptions.h" #include "sqlite3_arginfo.h" @@ -1500,6 +1503,60 @@ PHP_METHOD(SQLite3Stmt, busy) RETURN_FALSE; } +#if SQLITE_VERSION_NUMBER >= 3043000 +PHP_METHOD(SQLite3Stmt, explain) +{ +#ifdef __APPLE__ + if (__builtin_available(macOS 14.2, *)) { +#endif + php_sqlite3_stmt *stmt_obj; + zval *object = ZEND_THIS; + stmt_obj = Z_SQLITE3_STMT_P(object); + + ZEND_PARSE_PARAMETERS_NONE(); + + SQLITE3_CHECK_INITIALIZED(stmt_obj->db_obj, stmt_obj->initialised, SQLite3); + SQLITE3_CHECK_INITIALIZED_STMT(stmt_obj->stmt, SQLite3Stmt); + + RETURN_LONG((zend_long)sqlite3_stmt_isexplain(stmt_obj->stmt)); +#ifdef __APPLE__ + } else { + zend_throw_error(NULL, "explain statement unsupported"); + } +#endif +} + +PHP_METHOD(SQLite3Stmt, setExplain) +{ +#ifdef __APPLE__ + if (__builtin_available(macOS 14.2, *)) { +#endif + php_sqlite3_stmt *stmt_obj; + zend_long mode; + zval *object = ZEND_THIS; + stmt_obj = Z_SQLITE3_STMT_P(object); + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_LONG(mode) + ZEND_PARSE_PARAMETERS_END(); + + if (mode < 0 || mode > 2) { + zend_argument_value_error(1, "must be one of the SQLite3Stmt::EXPLAIN_MODE_* constants"); + RETURN_THROWS(); + } + + SQLITE3_CHECK_INITIALIZED(stmt_obj->db_obj, stmt_obj->initialised, SQLite3); + SQLITE3_CHECK_INITIALIZED_STMT(stmt_obj->stmt, SQLite3Stmt); + + RETURN_BOOL(sqlite3_stmt_explain(stmt_obj->stmt, (int)mode) == SQLITE_OK); +#ifdef __APPLE__ + } else { + zend_throw_error(NULL, "explain statement unsupported"); + } +#endif +} +#endif + /* bind parameters to a statement before execution */ static int php_sqlite3_bind_params(php_sqlite3_stmt *stmt_obj) /* {{{ */ { diff --git a/ext/sqlite3/sqlite3.stub.php b/ext/sqlite3/sqlite3.stub.php index 8a3d90470767a..55af378b325c5 100644 --- a/ext/sqlite3/sqlite3.stub.php +++ b/ext/sqlite3/sqlite3.stub.php @@ -274,6 +274,15 @@ public function readOnly(): bool {} public function reset(): bool {} public function busy(): bool {} + +#if SQLITE_VERSION_NUMBER >= 3043000 + public const int EXPLAIN_MODE_PREPARED = 0; + public const int EXPLAIN_MODE_EXPLAIN = 1; + public const int EXPLAIN_MODE_EXPLAIN_QUERY_PLAN = 2; + + public function explain(): int {} + public function setExplain(int $mode): bool {} +#endif } /** @not-serializable */ diff --git a/ext/sqlite3/sqlite3_arginfo.h b/ext/sqlite3/sqlite3_arginfo.h index f83188841b43f..e306af04538b3 100644 --- a/ext/sqlite3/sqlite3_arginfo.h +++ b/ext/sqlite3/sqlite3_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 28132e0e4df61f19dc4b23a7c9f79be6b3e40a8e */ + * Stub hash: c3216eada9881743cbd3aa1510f1200b7ce0d942 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_SQLite3___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) @@ -147,6 +147,15 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_SQLite3Stmt_busy, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() +#if SQLITE_VERSION_NUMBER >= 3043000 +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_SQLite3Stmt_explain, 0, 0, IS_LONG, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_SQLite3Stmt_setExplain, 0, 1, _IS_BOOL, 0) + ZEND_ARG_TYPE_INFO(0, mode, IS_LONG, 0) +ZEND_END_ARG_INFO() +#endif + ZEND_BEGIN_ARG_INFO_EX(arginfo_class_SQLite3Result___construct, 0, 0, 0) ZEND_END_ARG_INFO() @@ -206,6 +215,10 @@ ZEND_METHOD(SQLite3Stmt, paramCount); ZEND_METHOD(SQLite3Stmt, readOnly); ZEND_METHOD(SQLite3Stmt, reset); ZEND_METHOD(SQLite3Stmt, busy); +#if SQLITE_VERSION_NUMBER >= 3043000 +ZEND_METHOD(SQLite3Stmt, explain); +ZEND_METHOD(SQLite3Stmt, setExplain); +#endif ZEND_METHOD(SQLite3Result, __construct); ZEND_METHOD(SQLite3Result, numColumns); ZEND_METHOD(SQLite3Result, columnName); @@ -258,6 +271,10 @@ static const zend_function_entry class_SQLite3Stmt_methods[] = { ZEND_ME(SQLite3Stmt, readOnly, arginfo_class_SQLite3Stmt_readOnly, ZEND_ACC_PUBLIC) ZEND_ME(SQLite3Stmt, reset, arginfo_class_SQLite3Stmt_reset, ZEND_ACC_PUBLIC) ZEND_ME(SQLite3Stmt, busy, arginfo_class_SQLite3Stmt_busy, ZEND_ACC_PUBLIC) +#if SQLITE_VERSION_NUMBER >= 3043000 + ZEND_ME(SQLite3Stmt, explain, arginfo_class_SQLite3Stmt_explain, ZEND_ACC_PUBLIC) + ZEND_ME(SQLite3Stmt, setExplain, arginfo_class_SQLite3Stmt_setExplain, ZEND_ACC_PUBLIC) +#endif ZEND_FE_END }; @@ -540,6 +557,30 @@ static zend_class_entry *register_class_SQLite3Stmt(void) INIT_CLASS_ENTRY(ce, "SQLite3Stmt", class_SQLite3Stmt_methods); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_NOT_SERIALIZABLE); +#if SQLITE_VERSION_NUMBER >= 3043000 + + zval const_EXPLAIN_MODE_PREPARED_value; + ZVAL_LONG(&const_EXPLAIN_MODE_PREPARED_value, 0); + zend_string *const_EXPLAIN_MODE_PREPARED_name = zend_string_init_interned("EXPLAIN_MODE_PREPARED", sizeof("EXPLAIN_MODE_PREPARED") - 1, 1); + zend_declare_typed_class_constant(class_entry, const_EXPLAIN_MODE_PREPARED_name, &const_EXPLAIN_MODE_PREPARED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(const_EXPLAIN_MODE_PREPARED_name); +#endif +#if SQLITE_VERSION_NUMBER >= 3043000 + + zval const_EXPLAIN_MODE_EXPLAIN_value; + ZVAL_LONG(&const_EXPLAIN_MODE_EXPLAIN_value, 1); + zend_string *const_EXPLAIN_MODE_EXPLAIN_name = zend_string_init_interned("EXPLAIN_MODE_EXPLAIN", sizeof("EXPLAIN_MODE_EXPLAIN") - 1, 1); + zend_declare_typed_class_constant(class_entry, const_EXPLAIN_MODE_EXPLAIN_name, &const_EXPLAIN_MODE_EXPLAIN_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(const_EXPLAIN_MODE_EXPLAIN_name); +#endif +#if SQLITE_VERSION_NUMBER >= 3043000 + + zval const_EXPLAIN_MODE_EXPLAIN_QUERY_PLAN_value; + ZVAL_LONG(&const_EXPLAIN_MODE_EXPLAIN_QUERY_PLAN_value, 2); + zend_string *const_EXPLAIN_MODE_EXPLAIN_QUERY_PLAN_name = zend_string_init_interned("EXPLAIN_MODE_EXPLAIN_QUERY_PLAN", sizeof("EXPLAIN_MODE_EXPLAIN_QUERY_PLAN") - 1, 1); + zend_declare_typed_class_constant(class_entry, const_EXPLAIN_MODE_EXPLAIN_QUERY_PLAN_name, &const_EXPLAIN_MODE_EXPLAIN_QUERY_PLAN_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(const_EXPLAIN_MODE_EXPLAIN_QUERY_PLAN_name); +#endif return class_entry; } diff --git a/ext/sqlite3/tests/sqlite3_explain.phpt b/ext/sqlite3/tests/sqlite3_explain.phpt new file mode 100644 index 0000000000000..f580783ca1d14 --- /dev/null +++ b/ext/sqlite3/tests/sqlite3_explain.phpt @@ -0,0 +1,390 @@ +--TEST-- +Sqlite3Stmt::explain/setExplain usage +--EXTENSIONS-- +sqlite3 +--SKIPIF-- + +--FILE-- +exec('CREATE TABLE test_explain (a string);'); +$stmt = $db->prepare('INSERT INTO test_explain VALUES ("first insert"), ("second_insert")'); +$stmt->setExplain(Sqlite3Stmt::EXPLAIN_MODE_EXPLAIN); +var_dump($stmt->explain() == Sqlite3Stmt::EXPLAIN_MODE_EXPLAIN); +$r = $stmt->execute(); +$result = []; +while (($arr = $r->fetchArray(SQLITE3_ASSOC)) !== false) $result[] = $arr; +var_dump($result); +$stmts = $db->prepare('SELECT * FROM test_explain'); +$stmts->setExplain(Sqlite3Stmt::EXPLAIN_MODE_EXPLAIN_QUERY_PLAN); +$r = $stmts->execute(); +$result = []; +while (($arr = $r->fetchArray(SQLITE3_ASSOC)) !== false) $result[] = $arr; +var_dump($result); + +$stmt = $db->prepare('INSERT INTO test_explain VALUES ("first insert"), ("second_insert")'); +$stmt->setExplain(Sqlite3Stmt::EXPLAIN_MODE_PREPARED); +$stmt->execute(); +$stmts = $db->prepare('SELECT * FROM test_explain'); +$stmts->setExplain(Sqlite3Stmt::EXPLAIN_MODE_PREPARED); +$r = $stmts->execute(); +$result = []; +while (($arr = $r->fetchArray(SQLITE3_ASSOC)) !== false) $result[] = $arr; +var_dump($result); + +try { + $stmts->setExplain(-1); +} catch (\ValueError $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + $stmts->setExplain(256); +} catch (\ValueError $e) { + echo $e->getMessage(), PHP_EOL; +} + +var_dump($stmts->explain() == Sqlite3Stmt::EXPLAIN_MODE_PREPARED); +?> +--EXPECTF-- +bool(true) +array(%d) { + [0]=> + array(8) { + ["addr"]=> + int(0) + ["opcode"]=> + string(4) "Init" + ["p1"]=> + int(0) + ["p2"]=> + int(%d) + ["p3"]=> + int(0) + ["p4"]=> + NULL + ["p5"]=> + int(0) + ["comment"]=> + %a + } + [1]=> + array(8) { + ["addr"]=> + int(1) + ["opcode"]=> + string(13) "InitCoroutine" + ["p1"]=> + int(3) + ["p2"]=> + int(%d) + ["p3"]=> + int(2) + ["p4"]=> + NULL + ["p5"]=> + int(0) + ["comment"]=> + %a + } + %A + array(8) { + ["addr"]=> + int(%d) + ["opcode"]=> + string(7) "String8" + ["p1"]=> + int(0) + ["p2"]=> + int(2) + ["p3"]=> + int(0) + ["p4"]=> + string(12) "first insert" + ["p5"]=> + int(0) + ["comment"]=> + %a + } + %A + array(8) { + ["addr"]=> + int(%d) + ["opcode"]=> + string(5) "Yield" + ["p1"]=> + int(3) + ["p2"]=> + int(0) + ["p3"]=> + int(0) + ["p4"]=> + NULL + ["p5"]=> + int(0) + ["comment"]=> + %a + } + %A + array(8) { + ["addr"]=> + int(%d) + ["opcode"]=> + string(7) "String8" + ["p1"]=> + int(0) + ["p2"]=> + int(2) + ["p3"]=> + int(0) + ["p4"]=> + string(13) "second_insert" + ["p5"]=> + int(0) + ["comment"]=> + %a + } + [%d]=> + array(8) { + ["addr"]=> + int(%d) + ["opcode"]=> + string(5) "Yield" + ["p1"]=> + int(3) + ["p2"]=> + int(0) + ["p3"]=> + int(0) + ["p4"]=> + NULL + ["p5"]=> + int(0) + ["comment"]=> + %a + } + [%d]=> + array(8) { + ["addr"]=> + int(%d) + ["opcode"]=> + string(12) "EndCoroutine" + ["p1"]=> + int(3) + ["p2"]=> + int(0) + ["p3"]=> + int(0) + ["p4"]=> + NULL + ["p5"]=> + int(0) + ["comment"]=> + %a + } + [%d]=> + array(8) { + ["addr"]=> + int(%d) + ["opcode"]=> + string(9) "OpenWrite" + ["p1"]=> + int(0) + ["p2"]=> + int(2) + ["p3"]=> + int(0) + ["p4"]=> + string(1) "1" + ["p5"]=> + int(0) + ["comment"]=> + %a + } + [%d]=> + array(8) { + ["addr"]=> + int(%d) + ["opcode"]=> + string(5) "Yield" + ["p1"]=> + int(3) + ["p2"]=> + int(%d) + ["p3"]=> + int(0) + ["p4"]=> + NULL + ["p5"]=> + int(0) + ["comment"]=> + %a + } + [%d]=> + array(8) { + ["addr"]=> + int(%d) + ["opcode"]=> + string(8) "NewRowid" + ["p1"]=> + int(0) + ["p2"]=> + int(1) + ["p3"]=> + int(0) + ["p4"]=> + NULL + ["p5"]=> + int(0) + ["comment"]=> + %a + } + [%d]=> + array(8) { + ["addr"]=> + int(%d) + ["opcode"]=> + string(10) "MakeRecord" + ["p1"]=> + int(2) + ["p2"]=> + int(1) + ["p3"]=> + int(4) + ["p4"]=> + string(1) "C" + ["p5"]=> + int(0) + ["comment"]=> + %a + } + [%d]=> + array(8) { + ["addr"]=> + int(%d) + ["opcode"]=> + string(6) "Insert" + ["p1"]=> + int(0) + ["p2"]=> + int(4) + ["p3"]=> + int(1) + ["p4"]=> + string(12) "test_explain" + ["p5"]=> + int(57) + ["comment"]=> + %a + } + [%d]=> + array(8) { + ["addr"]=> + int(%d) + ["opcode"]=> + string(4) "Goto" + ["p1"]=> + int(0) + ["p2"]=> + int(%d) + ["p3"]=> + int(0) + ["p4"]=> + NULL + ["p5"]=> + int(0) + ["comment"]=> + %a + } + [%d]=> + array(8) { + ["addr"]=> + int(%d) + ["opcode"]=> + string(4) "Halt" + ["p1"]=> + int(0) + ["p2"]=> + int(0) + ["p3"]=> + int(0) + ["p4"]=> + NULL + ["p5"]=> + int(0) + ["comment"]=> + %a + } + [%d]=> + array(8) { + ["addr"]=> + int(%d) + ["opcode"]=> + string(11) "Transaction" + ["p1"]=> + int(0) + ["p2"]=> + int(1) + ["p3"]=> + int(1) + ["p4"]=> + string(1) "0" + ["p5"]=> + int(1) + ["comment"]=> + %a + } + [%d]=> + array(8) { + ["addr"]=> + int(%d) + ["opcode"]=> + string(4) "Goto" + ["p1"]=> + int(0) + ["p2"]=> + int(1) + ["p3"]=> + int(0) + ["p4"]=> + NULL + ["p5"]=> + int(0) + ["comment"]=> + %a + } +} +array(1) { + [0]=> + array(4) { + ["id"]=> + int(2) + ["parent"]=> + int(0) + ["notused"]=> + int(0) + ["detail"]=> + string(17) "SCAN test_explain" + } +} +array(2) { + [0]=> + array(1) { + ["a"]=> + string(12) "first insert" + } + [1]=> + array(1) { + ["a"]=> + string(13) "second_insert" + } +} +SQLite3Stmt::setExplain(): Argument #1 ($mode) must be one of the SQLite3Stmt::EXPLAIN_MODE_* constants +SQLite3Stmt::setExplain(): Argument #1 ($mode) must be one of the SQLite3Stmt::EXPLAIN_MODE_* constants +bool(true) From 375316d0e24259077a4709bc21e0c0c628611a18 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Thu, 19 Jun 2025 23:38:51 +0100 Subject: [PATCH 066/120] ext/sqlite3: Sqlite3Result::fetchAll() support associative and indexes arrays for results. close GH-1884 --- NEWS | 2 + UPGRADING | 5 ++ ext/sqlite3/sqlite3.c | 101 ++++++++++++++++----- ext/sqlite3/sqlite3.stub.php | 2 + ext/sqlite3/sqlite3_arginfo.h | 12 +-- ext/sqlite3/tests/sqlite3_fetch_all.phpt | 108 +++++++++++++++++++++++ 6 files changed, 205 insertions(+), 25 deletions(-) create mode 100644 ext/sqlite3/tests/sqlite3_fetch_all.phpt diff --git a/NEWS b/NEWS index ccda0d50af84e..1ce8ce754adc9 100644 --- a/NEWS +++ b/NEWS @@ -249,6 +249,8 @@ PHP NEWS (David Carlier) . Added Sqlite3Stmt::explain to produce a explain query plan from the statement. (David Carlier) + . Added Sqlite3Result::fetchAll to returns all results at once from a query. + (David Carlier) - Standard: . Fixed crypt() tests on musl when using --with-external-libcrypt diff --git a/UPGRADING b/UPGRADING index e551f0c894260..4c6e40cfdebaf 100644 --- a/UPGRADING +++ b/UPGRADING @@ -212,6 +212,11 @@ PHP 8.5 UPGRADE NOTES now have an optional $lang parameter. This support solves compatibility with .NET SOAP clients. +- Sqlite: + . Added class constants Sqlite3Stmt::EXPLAIN_MODE_PREPARED, + Sqlite3Stmt::EXPLAIN_MODE_EXPLAIN and + Sqlite3Stmt::EXPLAIN_MODE_EXPLAIN_QUERY_PLAN. + - XSL: . The $namespace argument of XSLTProcessor::getParameter(), XSLTProcessor::setParameter() and XSLTProcessor::removeParameter() diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c index 349d2823bb1e0..5e402300980bb 100644 --- a/ext/sqlite3/sqlite3.c +++ b/ext/sqlite3/sqlite3.c @@ -39,6 +39,7 @@ static PHP_GINIT_FUNCTION(sqlite3); static int php_sqlite3_authorizer(void *autharg, int action, const char *arg1, const char *arg2, const char *arg3, const char *arg4); static void sqlite3_param_dtor(zval *data); static int php_sqlite3_compare_stmt_free(php_sqlite3_stmt **stmt_obj_ptr, sqlite3_stmt *statement); +static zend_always_inline void php_sqlite3_fetch_one(int n_cols, php_sqlite3_result *result_obj, zend_long mode, zval *result); #define SQLITE3_CHECK_INITIALIZED(db_obj, member, class_name) \ if (!(db_obj) || !(member)) { \ @@ -1991,7 +1992,7 @@ PHP_METHOD(SQLite3Result, fetchArray) { php_sqlite3_result *result_obj; zval *object = ZEND_THIS; - int i, ret; + int ret; zend_long mode = PHP_SQLITE3_BOTH; result_obj = Z_SQLITE3_RESULT_P(object); @@ -2028,26 +2029,8 @@ PHP_METHOD(SQLite3Result, fetchArray) array_init(return_value); - for (i = 0; i < n_cols; i++) { - zval data; - - sqlite_value_to_zval(result_obj->stmt_obj->stmt, i, &data); - - if (mode & PHP_SQLITE3_NUM) { - add_index_zval(return_value, i, &data); - } + php_sqlite3_fetch_one(n_cols, result_obj, mode, return_value); - if (mode & PHP_SQLITE3_ASSOC) { - if (mode & PHP_SQLITE3_NUM) { - if (Z_REFCOUNTED(data)) { - Z_ADDREF(data); - } - } - /* Note: we can't use the "add_new" variant here instead of "update" because - * when the same column name is encountered, the last result should be taken. */ - zend_symtable_update(Z_ARR_P(return_value), result_obj->column_names[i], &data); - } - } break; case SQLITE_DONE: @@ -2071,6 +2054,61 @@ static void sqlite3result_clear_column_names_cache(php_sqlite3_result *result) { result->column_count = -1; } +PHP_METHOD(SQLite3Result, fetchAll) +{ + int i, nb_cols; + bool done = false; + php_sqlite3_result *result_obj; + zval *object = ZEND_THIS; + zend_long mode = PHP_SQLITE3_BOTH; + result_obj = Z_SQLITE3_RESULT_P(object); + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(mode) + ZEND_PARSE_PARAMETERS_END(); + + SQLITE3_CHECK_INITIALIZED(result_obj->db_obj, result_obj->stmt_obj->initialised, SQLite3Result) + + nb_cols = sqlite3_column_count(result_obj->stmt_obj->stmt); + if (mode & PHP_SQLITE3_ASSOC) { + sqlite3result_clear_column_names_cache(result_obj); + result_obj->column_names = emalloc(nb_cols * sizeof(zend_string*)); + + for (i = 0; i < nb_cols; i++) { + const char *column = sqlite3_column_name(result_obj->stmt_obj->stmt, i); + result_obj->column_names[i] = zend_string_init(column, strlen(column), 0); + } + } + result_obj->column_count = nb_cols; + array_init(return_value); + + while (!done) { + int step = sqlite3_step(result_obj->stmt_obj->stmt); + + switch (step) { + case SQLITE_ROW: { + zval result; + array_init_size(&result, result_obj->column_count); + + php_sqlite3_fetch_one(result_obj->column_count, result_obj, mode, &result); + + add_next_index_zval(return_value, &result); + break; + } + case SQLITE_DONE: + done = true; + break; + default: + if (!EG(exception)) { + php_sqlite3_error(result_obj->db_obj, sqlite3_errcode(sqlite3_db_handle(result_obj->stmt_obj->stmt)), "Unable to execute statement: %s", sqlite3_errmsg(sqlite3_db_handle(result_obj->stmt_obj->stmt))); + } + zval_ptr_dtor(return_value); + RETURN_FALSE; + } + } +} + /* {{{ Resets the result set back to the first row. */ PHP_METHOD(SQLite3Result, reset) { @@ -2429,6 +2467,29 @@ static void sqlite3_param_dtor(zval *data) /* {{{ */ } /* }}} */ +static zend_always_inline void php_sqlite3_fetch_one(int n_cols, php_sqlite3_result *result_obj, zend_long mode, zval *result) +{ + for (int i = 0; i < n_cols; i ++) { + zval data; + sqlite_value_to_zval(result_obj->stmt_obj->stmt, i, &data); + + if (mode & PHP_SQLITE3_NUM) { + add_index_zval(result, i, &data); + } + + if (mode & PHP_SQLITE3_ASSOC) { + if (mode & PHP_SQLITE3_NUM) { + if (Z_REFCOUNTED(data)) { + Z_ADDREF(data); + } + } + /* Note: we can't use the "add_new" variant here instead of "update" because + * when the same column name is encountered, the last result should be taken. */ + zend_symtable_update(Z_ARR_P(result), result_obj->column_names[i], &data); + } + } +} + /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(sqlite3) { diff --git a/ext/sqlite3/sqlite3.stub.php b/ext/sqlite3/sqlite3.stub.php index 55af378b325c5..54a7b41ec5576 100644 --- a/ext/sqlite3/sqlite3.stub.php +++ b/ext/sqlite3/sqlite3.stub.php @@ -302,6 +302,8 @@ public function columnType(int $column): int|false {} /** @tentative-return-type */ public function fetchArray(int $mode = SQLITE3_BOTH): array|false {} + public function fetchAll(int $mode = SQLITE3_BOTH): array|false {} + /** @tentative-return-type */ public function reset(): bool {} diff --git a/ext/sqlite3/sqlite3_arginfo.h b/ext/sqlite3/sqlite3_arginfo.h index e306af04538b3..54ca70cad5c53 100644 --- a/ext/sqlite3/sqlite3_arginfo.h +++ b/ext/sqlite3/sqlite3_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: c3216eada9881743cbd3aa1510f1200b7ce0d942 */ + * Stub hash: da91c32c6070c808d6e1b01894b5f8beedda7b45 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_SQLite3___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) @@ -173,6 +173,10 @@ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_MASK_EX(arginfo_class_SQLite3Result_fe ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mode, IS_LONG, 0, "SQLITE3_BOTH") ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_SQLite3Result_fetchAll, 0, 0, MAY_BE_ARRAY|MAY_BE_FALSE) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mode, IS_LONG, 0, "SQLITE3_BOTH") +ZEND_END_ARG_INFO() + #define arginfo_class_SQLite3Result_reset arginfo_class_SQLite3_close #define arginfo_class_SQLite3Result_finalize arginfo_class_SQLite3Stmt_close @@ -224,6 +228,7 @@ ZEND_METHOD(SQLite3Result, numColumns); ZEND_METHOD(SQLite3Result, columnName); ZEND_METHOD(SQLite3Result, columnType); ZEND_METHOD(SQLite3Result, fetchArray); +ZEND_METHOD(SQLite3Result, fetchAll); ZEND_METHOD(SQLite3Result, reset); ZEND_METHOD(SQLite3Result, finalize); @@ -284,6 +289,7 @@ static const zend_function_entry class_SQLite3Result_methods[] = { ZEND_ME(SQLite3Result, columnName, arginfo_class_SQLite3Result_columnName, ZEND_ACC_PUBLIC) ZEND_ME(SQLite3Result, columnType, arginfo_class_SQLite3Result_columnType, ZEND_ACC_PUBLIC) ZEND_ME(SQLite3Result, fetchArray, arginfo_class_SQLite3Result_fetchArray, ZEND_ACC_PUBLIC) + ZEND_ME(SQLite3Result, fetchAll, arginfo_class_SQLite3Result_fetchAll, ZEND_ACC_PUBLIC) ZEND_ME(SQLite3Result, reset, arginfo_class_SQLite3Result_reset, ZEND_ACC_PUBLIC) ZEND_ME(SQLite3Result, finalize, arginfo_class_SQLite3Result_finalize, ZEND_ACC_PUBLIC) ZEND_FE_END @@ -564,16 +570,12 @@ static zend_class_entry *register_class_SQLite3Stmt(void) zend_string *const_EXPLAIN_MODE_PREPARED_name = zend_string_init_interned("EXPLAIN_MODE_PREPARED", sizeof("EXPLAIN_MODE_PREPARED") - 1, 1); zend_declare_typed_class_constant(class_entry, const_EXPLAIN_MODE_PREPARED_name, &const_EXPLAIN_MODE_PREPARED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_EXPLAIN_MODE_PREPARED_name); -#endif -#if SQLITE_VERSION_NUMBER >= 3043000 zval const_EXPLAIN_MODE_EXPLAIN_value; ZVAL_LONG(&const_EXPLAIN_MODE_EXPLAIN_value, 1); zend_string *const_EXPLAIN_MODE_EXPLAIN_name = zend_string_init_interned("EXPLAIN_MODE_EXPLAIN", sizeof("EXPLAIN_MODE_EXPLAIN") - 1, 1); zend_declare_typed_class_constant(class_entry, const_EXPLAIN_MODE_EXPLAIN_name, &const_EXPLAIN_MODE_EXPLAIN_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_EXPLAIN_MODE_EXPLAIN_name); -#endif -#if SQLITE_VERSION_NUMBER >= 3043000 zval const_EXPLAIN_MODE_EXPLAIN_QUERY_PLAN_value; ZVAL_LONG(&const_EXPLAIN_MODE_EXPLAIN_QUERY_PLAN_value, 2); diff --git a/ext/sqlite3/tests/sqlite3_fetch_all.phpt b/ext/sqlite3/tests/sqlite3_fetch_all.phpt new file mode 100644 index 0000000000000..5a318afb12561 --- /dev/null +++ b/ext/sqlite3/tests/sqlite3_fetch_all.phpt @@ -0,0 +1,108 @@ +--TEST-- +SQLite3Result::fetchAll usage +--EXTENSIONS-- +sqlite3 +--FILE-- +query('CREATE TABLE users (id INTEGER NOT NULL, num INTEGER NOT NULL, PRIMARY KEY(id))'); + +$stmt = $conn->query('insert into users (id, num) values (1, 1)'); +$stmt = $conn->query('insert into users (id, num) values (2, 2)'); + +$stmt = $conn->query('SELECT * FROM users'); +$rowall = $stmt->fetchAll(); +var_dump($rowall); +$stmt->reset(); +$rowfetch = []; +while (($row = $stmt->fetchArray())) $rowfetch[] = $row; +var_dump($rowfetch); +var_dump($rowall == $rowfetch); +$stmt->reset(); +var_dump($stmt->fetchAll(SQLITE3_NUM)); +$stmt->reset(); +var_dump($stmt->fetchAll(SQLITE3_ASSOC)); + +?> +--EXPECT-- +array(2) { + [0]=> + array(4) { + [0]=> + int(1) + ["id"]=> + int(1) + [1]=> + int(1) + ["num"]=> + int(1) + } + [1]=> + array(4) { + [0]=> + int(2) + ["id"]=> + int(2) + [1]=> + int(2) + ["num"]=> + int(2) + } +} +array(2) { + [0]=> + array(4) { + [0]=> + int(1) + ["id"]=> + int(1) + [1]=> + int(1) + ["num"]=> + int(1) + } + [1]=> + array(4) { + [0]=> + int(2) + ["id"]=> + int(2) + [1]=> + int(2) + ["num"]=> + int(2) + } +} +bool(true) +array(2) { + [0]=> + array(2) { + [0]=> + int(1) + [1]=> + int(1) + } + [1]=> + array(2) { + [0]=> + int(2) + [1]=> + int(2) + } +} +array(2) { + [0]=> + array(2) { + ["id"]=> + int(1) + ["num"]=> + int(1) + } + [1]=> + array(2) { + ["id"]=> + int(2) + ["num"]=> + int(2) + } +} From 81865ec5bdcba61b1a4bb39158960d547f4424e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Mon, 23 Jun 2025 12:14:00 +0200 Subject: [PATCH 067/120] uri: Improve exceptions for Uri\WhatWg\Url (#18855) A more specific exception message is used, while the code is simplified. --- ext/uri/php_lexbor.c | 65 +++++++++++++++++++++--------------------- ext/uri/tests/004.phpt | 4 +-- ext/uri/tests/007.phpt | 2 +- ext/uri/tests/023.phpt | 4 +-- ext/uri/tests/026.phpt | 4 +-- ext/uri/tests/051.phpt | 2 +- 6 files changed, 40 insertions(+), 41 deletions(-) diff --git a/ext/uri/php_lexbor.c b/ext/uri/php_lexbor.c index 82f3919bb6a97..44bca30f8fda7 100644 --- a/ext/uri/php_lexbor.c +++ b/ext/uri/php_lexbor.c @@ -73,10 +73,10 @@ 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 void fill_errors(zval *errors) +static zend_string *fill_errors(zval *errors) { if (errors == NULL) { - return; + return NULL; } ZEND_ASSERT(Z_ISUNDEF_P(errors)); @@ -84,9 +84,10 @@ static void fill_errors(zval *errors) array_init(errors); if (lexbor_parser.log == NULL) { - return; + return NULL; } + zend_string *result = NULL; lexbor_plog_entry_t *lxb_error; while ((lxb_error = lexbor_array_obj_pop(&lexbor_parser.log->list)) != NULL) { zval error; @@ -223,32 +224,29 @@ static void fill_errors(zval *errors) zend_update_property(uri_whatwg_url_validation_error_ce, Z_OBJ(error), ZEND_STRL("failure"), &failure); + if (Z_TYPE(failure) == IS_TRUE) { + result = error_str; + } + add_next_index_zval(errors, &error); } -} - -static void throw_invalid_url_exception(zval *errors) -{ - ZEND_ASSERT(errors != NULL && Z_TYPE_P(errors) == IS_ARRAY); - - zval exception; - - object_init_ex(&exception, uri_whatwg_invalid_url_exception_ce); - - zval value; - ZVAL_STRING(&value, "URL parsing failed"); - zend_update_property_ex(uri_whatwg_invalid_url_exception_ce, Z_OBJ(exception), ZSTR_KNOWN(ZEND_STR_MESSAGE), &value); - zval_ptr_dtor_str(&value); - - zend_update_property(uri_whatwg_invalid_url_exception_ce, Z_OBJ(exception), ZEND_STRL("errors"), errors); - zend_throw_exception_object(&exception); + return result; } -static void throw_invalid_url_exception_during_write(zval *errors) +static void throw_invalid_url_exception_during_write(zval *errors, const char *component) { - fill_errors(errors); - throw_invalid_url_exception(errors); + zend_string *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 ? ")" : "" + ); + zend_update_property(exception->ce, exception, ZEND_STRL("errors"), errors); } static lxb_status_t lexbor_serialize_callback(const lxb_char_t *data, size_t length, void *ctx) @@ -281,7 +279,7 @@ static zend_result lexbor_write_scheme(struct uri_internal_t *internal_uri, zval zval_string_or_null_to_lexbor_str(value, &str); if (lxb_url_api_protocol_set(lexbor_uri, &lexbor_parser, str.data, str.length) != LXB_STATUS_OK) { - throw_invalid_url_exception_during_write(errors); + throw_invalid_url_exception_during_write(errors, "scheme"); return FAILURE; } @@ -310,7 +308,7 @@ static zend_result lexbor_write_username(uri_internal_t *internal_uri, zval *val zval_string_or_null_to_lexbor_str(value, &str); if (lxb_url_api_username_set(lexbor_uri, str.data, str.length) != LXB_STATUS_OK) { - throw_invalid_url_exception_during_write(errors); + throw_invalid_url_exception_during_write(errors, "username"); return FAILURE; } @@ -339,7 +337,7 @@ static zend_result lexbor_write_password(struct uri_internal_t *internal_uri, zv zval_string_or_null_to_lexbor_str(value, &str); if (lxb_url_api_password_set(lexbor_uri, str.data, str.length) != LXB_STATUS_OK) { - throw_invalid_url_exception_during_write(errors); + throw_invalid_url_exception_during_write(errors, "password"); return FAILURE; } @@ -411,7 +409,7 @@ static zend_result lexbor_write_host(struct uri_internal_t *internal_uri, zval * zval_string_or_null_to_lexbor_str(value, &str); if (lxb_url_api_hostname_set(lexbor_uri, &lexbor_parser, str.data, str.length) != LXB_STATUS_OK) { - throw_invalid_url_exception_during_write(errors); + throw_invalid_url_exception_during_write(errors, "host"); return FAILURE; } @@ -440,7 +438,7 @@ static zend_result lexbor_write_port(struct uri_internal_t *internal_uri, zval * zval_long_or_null_to_lexbor_str(value, &str); if (lxb_url_api_port_set(lexbor_uri, &lexbor_parser, str.data, str.length) != LXB_STATUS_OK) { - throw_invalid_url_exception_during_write(errors); + throw_invalid_url_exception_during_write(errors, "port"); return FAILURE; } @@ -469,7 +467,7 @@ static zend_result lexbor_write_path(struct uri_internal_t *internal_uri, zval * zval_string_or_null_to_lexbor_str(value, &str); if (lxb_url_api_pathname_set(lexbor_uri, &lexbor_parser, str.data, str.length) != LXB_STATUS_OK) { - throw_invalid_url_exception_during_write(errors); + throw_invalid_url_exception_during_write(errors, "path"); return FAILURE; } @@ -498,7 +496,7 @@ static zend_result lexbor_write_query(struct uri_internal_t *internal_uri, zval zval_string_or_null_to_lexbor_str(value, &str); if (lxb_url_api_search_set(lexbor_uri, &lexbor_parser, str.data, str.length) != LXB_STATUS_OK) { - throw_invalid_url_exception_during_write(errors); + throw_invalid_url_exception_during_write(errors, "query string"); return FAILURE; } @@ -527,7 +525,7 @@ static zend_result lexbor_write_fragment(struct uri_internal_t *internal_uri, zv zval_string_or_null_to_lexbor_str(value, &str); if (lxb_url_api_hash_set(lexbor_uri, &lexbor_parser, str.data, str.length) != LXB_STATUS_OK) { - throw_invalid_url_exception_during_write(errors); + throw_invalid_url_exception_during_write(errors, "fragment"); return FAILURE; } @@ -569,10 +567,11 @@ 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)); - fill_errors(errors); + zend_string *reason = fill_errors(errors); if (url == NULL && !silent) { - throw_invalid_url_exception(errors); + 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_update_property(exception->ce, exception, ZEND_STRL("errors"), errors); } return url; diff --git a/ext/uri/tests/004.phpt b/ext/uri/tests/004.phpt index 04127a7ded0d3..abbad59fee2e8 100644 --- a/ext/uri/tests/004.phpt +++ b/ext/uri/tests/004.phpt @@ -18,8 +18,8 @@ var_dump(Uri\WhatWg\Url::parse("192.168/contact.html", null)); var_dump(Uri\WhatWg\Url::parse("http://RuPaul's Drag Race All Stars 7 Winners Cast on This Season's", null)); ?> ---EXPECTF-- -URL parsing failed +--EXPECT-- +The specified URI is malformed (MissingSchemeNonRelativeUrl) NULL NULL NULL diff --git a/ext/uri/tests/007.phpt b/ext/uri/tests/007.phpt index e60e69fc113a3..cb445fcf71a43 100644 --- a/ext/uri/tests/007.phpt +++ b/ext/uri/tests/007.phpt @@ -19,7 +19,7 @@ var_dump($failures); ?> --EXPECTF-- -URL parsing failed +The specified URI is malformed (PortInvalid) array(%d) { [0]=> object(Uri\WhatWg\UrlValidationError)#%d (%d) { diff --git a/ext/uri/tests/023.phpt b/ext/uri/tests/023.phpt index b48e2df838eef..a1ca06bd6f6e5 100644 --- a/ext/uri/tests/023.phpt +++ b/ext/uri/tests/023.phpt @@ -27,5 +27,5 @@ try { --EXPECT-- string(5) "https" string(4) "http" -URL parsing failed -URL parsing failed +The specified scheme is malformed +The specified scheme is malformed diff --git a/ext/uri/tests/026.phpt b/ext/uri/tests/026.phpt index 4640ebebae52d..4763ea9d4406c 100644 --- a/ext/uri/tests/026.phpt +++ b/ext/uri/tests/026.phpt @@ -43,7 +43,7 @@ string(8) "test.com" string(8) "test.com" string(8) "test.com" NULL -URL parsing failed +The specified host is malformed (DomainInvalidCodePoint) object(Uri\WhatWg\Url)#%d (%d) { ["scheme"]=> string(5) "https" @@ -62,6 +62,6 @@ object(Uri\WhatWg\Url)#%d (%d) { ["fragment"]=> NULL } -URL parsing failed +The specified host is malformed (HostMissing) string(7) "foo.com" string(8) "test.com" diff --git a/ext/uri/tests/051.phpt b/ext/uri/tests/051.phpt index 5911f8767567c..ad4751470e23b 100644 --- a/ext/uri/tests/051.phpt +++ b/ext/uri/tests/051.phpt @@ -20,7 +20,7 @@ var_dump($softErrors); ?> --EXPECTF-- -URL parsing failed +The specified URI is malformed (Ipv4TooManyParts) string(23) "https://example.com/foo" array(%d) { [0]=> From 2ccd2b016df2c4cf8ff36a65b5875f1a7e39ac21 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sat, 14 Jun 2025 11:11:38 +0100 Subject: [PATCH 068/120] ext/calendar: jewishtojd overflow on year argument. Upper limit set to the 7th millenium (Messianic Age) in the jewish calendar, around 2239 year in the gregorian calendar. close GH-18849 --- NEWS | 3 +++ ext/calendar/calendar.c | 5 +++++ ext/calendar/jewish.c | 2 +- ext/calendar/tests/gh16234_2.phpt | 11 +++++++++++ ext/calendar/tests/gh16234_2_64.phpt | 21 +++++++++++++++++++++ 5 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 ext/calendar/tests/gh16234_2.phpt create mode 100644 ext/calendar/tests/gh16234_2_64.phpt diff --git a/NEWS b/NEWS index ea77125b205eb..fd344ee94c72e 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,9 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.3.24 +- Calendar: + . Fixed jewishtojd overflow on year argument. (David Carlier) + - Core: . Fixed bug GH-18833 (Use after free with weakmaps dependent on destruction order). (Daniil Gentili) diff --git a/ext/calendar/calendar.c b/ext/calendar/calendar.c index 756ce0e90dc98..6da7e69529e2e 100644 --- a/ext/calendar/calendar.c +++ b/ext/calendar/calendar.c @@ -490,6 +490,11 @@ PHP_FUNCTION(jewishtojd) RETURN_THROWS(); } + if (ZEND_LONG_EXCEEDS_INT(year)) { + zend_argument_value_error(3, "must be between %d and %d", INT_MIN, INT_MAX); + RETURN_THROWS(); + } + RETURN_LONG(JewishToSdn(year, month, day)); } /* }}} */ diff --git a/ext/calendar/jewish.c b/ext/calendar/jewish.c index bdfc9b4f91016..2fbdcb059b096 100644 --- a/ext/calendar/jewish.c +++ b/ext/calendar/jewish.c @@ -714,7 +714,7 @@ zend_long JewishToSdn( int yearLength; int lengthOfAdarIAndII; - if (year <= 0 || day <= 0 || day > 30) { + if (year <= 0 || year >= 6000 || day <= 0 || day > 30) { return (0); } switch (month) { diff --git a/ext/calendar/tests/gh16234_2.phpt b/ext/calendar/tests/gh16234_2.phpt new file mode 100644 index 0000000000000..76db2b9abf269 --- /dev/null +++ b/ext/calendar/tests/gh16234_2.phpt @@ -0,0 +1,11 @@ +--TEST-- +GH-16234 jewishtojd overflow on year argument +--EXTENSIONS-- +calendar +--FILE-- + +--EXPECTF-- +DONE diff --git a/ext/calendar/tests/gh16234_2_64.phpt b/ext/calendar/tests/gh16234_2_64.phpt new file mode 100644 index 0000000000000..7da2546096509 --- /dev/null +++ b/ext/calendar/tests/gh16234_2_64.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-16234 jewishtojd overflow on year argument +--EXTENSIONS-- +calendar +--SKIPIF-- + +--FILE-- +getMessage(), PHP_EOL; +} +?> +--EXPECTF-- +jewishtojd(): Argument #3 ($year) must be between %i and %d + From 67bbf9c9610465e42378b34301505f26045aed8d Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Fri, 20 Jun 2025 15:17:51 +0200 Subject: [PATCH 069/120] ext/filter: Remove ZPP test --- ext/filter/tests/057.phpt | 52 --------------------------------------- 1 file changed, 52 deletions(-) delete mode 100644 ext/filter/tests/057.phpt diff --git a/ext/filter/tests/057.phpt b/ext/filter/tests/057.phpt deleted file mode 100644 index ec8083e2f891d..0000000000000 --- a/ext/filter/tests/057.phpt +++ /dev/null @@ -1,52 +0,0 @@ ---TEST-- -filter_input_array() and filter_var_array() with invalid $definition arguments ---EXTENSIONS-- -filter ---FILE-- -getMessage() . "\n"; - } - - try { - var_dump(filter_var_array(array(), $invalid)); - } catch (TypeError $exception) { - echo $exception->getMessage() . "\n"; - } -} -?> ---EXPECTF-- -Deprecated: filter_input_array(): Passing null to parameter #2 ($options) of type array|int is deprecated in %s on line %d - -Warning: filter_input_array(): Unknown filter with ID 0 in %s on line %d -bool(false) - -Deprecated: filter_var_array(): Passing null to parameter #2 ($options) of type array|int is deprecated in %s on line %d - -Warning: filter_var_array(): Unknown filter with ID 0 in %s on line %d -bool(false) - -Warning: filter_input_array(): Unknown filter with ID 1 in %s on line %d -bool(false) - -Warning: filter_var_array(): Unknown filter with ID 1 in %s on line %d -bool(false) - -Warning: filter_input_array(): Unknown filter with ID 0 in %s on line %d -bool(false) - -Warning: filter_var_array(): Unknown filter with ID 0 in %s on line %d -bool(false) - -Warning: filter_input_array(): Unknown filter with ID 1 in %s on line %d -bool(false) - -Warning: filter_var_array(): Unknown filter with ID 1 in %s on line %d -bool(false) -filter_input_array(): Argument #2 ($options) must be of type array|int, string given -filter_var_array(): Argument #2 ($options) must be of type array|int, string given -filter_input_array(): Argument #2 ($options) must be of type array|int, stdClass given -filter_var_array(): Argument #2 ($options) must be of type array|int, stdClass given From c03f6065fa9be4f898bddc351451ba964f8c75bb Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Fri, 20 Jun 2025 15:20:16 +0200 Subject: [PATCH 070/120] ext/calendar: Remove ZPP test --- ext/calendar/tests/unixtojd_error1.phpt | 2 -- 1 file changed, 2 deletions(-) diff --git a/ext/calendar/tests/unixtojd_error1.phpt b/ext/calendar/tests/unixtojd_error1.phpt index 6b8fad05ebd83..171d400b99e76 100644 --- a/ext/calendar/tests/unixtojd_error1.phpt +++ b/ext/calendar/tests/unixtojd_error1.phpt @@ -15,7 +15,6 @@ try { } catch (ValueError $ex) { echo $ex->getMessage(), PHP_EOL; } -var_dump(unixtojd(false)) . PHP_EOL; var_dump(unixtojd(null)) . PHP_EOL; var_dump(unixtojd(time())) . PHP_EOL; ?> @@ -23,4 +22,3 @@ var_dump(unixtojd(time())) . PHP_EOL; unixtojd(): Argument #1 ($timestamp) must be greater than or equal to 0 int(%d) int(%d) -int(%d) From c7778641dde526cc6024cc2b6aff321452473c34 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Fri, 20 Jun 2025 15:52:30 +0200 Subject: [PATCH 071/120] ext/mbstring: Remove ZPP tests --- ext/mbstring/tests/bug43994.phpt | 59 ++---- ext/mbstring/tests/bug43998.phpt | 42 +---- ext/mbstring/tests/gh16229.phpt | 2 +- .../tests/mb_ereg_replace_variation1.phpt | 65 +------ ...titute_character_variation_weak_types.phpt | 172 ------------------ 5 files changed, 29 insertions(+), 311 deletions(-) delete mode 100644 ext/mbstring/tests/mb_substitute_character_variation_weak_types.phpt diff --git a/ext/mbstring/tests/bug43994.phpt b/ext/mbstring/tests/bug43994.phpt index 26f641f6d3d7e..b4ae29ff40e7f 100644 --- a/ext/mbstring/tests/bug43994.phpt +++ b/ext/mbstring/tests/bug43994.phpt @@ -14,55 +14,24 @@ function_exists('mb_ereg') or die("skip mb_ereg() is not available in this build * pattern is supplied to mb_ereg. Similar error message to ereg(). */ -$inputs = array(false, FALSE, "", ''); +$input = ''; +echo "Without \$regs arg:\n"; +try { + var_dump( mb_ereg($input, 'hello, world') ); +} catch (\ValueError $e) { + echo $e->getMessage() . \PHP_EOL; +} -$iterator = 1; -foreach($inputs as $input) { - if(@is_array($mb_regs)){ - $mb_regs = ''; - } - echo "\n-- Iteration $iterator --\n"; - echo "Without \$regs arg:\n"; - try { - var_dump( mb_ereg($input, 'hello, world') ); - } catch (\ValueError $e) { - echo $e->getMessage() . \PHP_EOL; - } +echo "With \$regs arg:\n"; +try { + var_dump(mb_ereg($input, 'hello, world', $mb_regs)); +} catch (\ValueError $e) { + echo $e->getMessage() . \PHP_EOL; +} - echo "With \$regs arg:\n"; - try { - var_dump(mb_ereg($input, 'hello, world', $mb_regs)); - } catch (\ValueError $e) { - echo $e->getMessage() . \PHP_EOL; - } - - var_dump($mb_regs); - $iterator++; -}; +var_dump($mb_regs); ?> --EXPECT-- --- Iteration 1 -- -Without $regs arg: -mb_ereg(): Argument #1 ($pattern) must not be empty -With $regs arg: -mb_ereg(): Argument #1 ($pattern) must not be empty -NULL - --- Iteration 2 -- -Without $regs arg: -mb_ereg(): Argument #1 ($pattern) must not be empty -With $regs arg: -mb_ereg(): Argument #1 ($pattern) must not be empty -NULL - --- Iteration 3 -- -Without $regs arg: -mb_ereg(): Argument #1 ($pattern) must not be empty -With $regs arg: -mb_ereg(): Argument #1 ($pattern) must not be empty -NULL - --- Iteration 4 -- Without $regs arg: mb_ereg(): Argument #1 ($pattern) must not be empty With $regs arg: diff --git a/ext/mbstring/tests/bug43998.phpt b/ext/mbstring/tests/bug43998.phpt index 112ab88728341..5be1bd2cc9ffd 100644 --- a/ext/mbstring/tests/bug43998.phpt +++ b/ext/mbstring/tests/bug43998.phpt @@ -11,41 +11,19 @@ mbstring $sourcestring = 'Hello, World'; -$inputs = array(12345, 12.3456789000E-10, true, false, ""); -$iterator = 1; -foreach($inputs as $input) { - echo "\n-- Iteration $iterator --\n"; - try { - var_dump( mb_strtolower($sourcestring, $input) ); - } catch (\ValueError $e) { - echo $e->getMessage() . \PHP_EOL; - } - try { - var_dump( mb_strtoupper($sourcestring, $input) ); - } catch (\ValueError $e) { - echo $e->getMessage() . \PHP_EOL; - } - $iterator++; +$input = ""; +try { + var_dump( mb_strtolower($sourcestring, $input) ); +} catch (\ValueError $e) { + echo $e->getMessage() . \PHP_EOL; +} +try { + var_dump( mb_strtoupper($sourcestring, $input) ); +} catch (\ValueError $e) { + echo $e->getMessage() . \PHP_EOL; } ?> --EXPECT-- --- Iteration 1 -- -mb_strtolower(): Argument #2 ($encoding) must be a valid encoding, "12345" given -mb_strtoupper(): Argument #2 ($encoding) must be a valid encoding, "12345" given - --- Iteration 2 -- -mb_strtolower(): Argument #2 ($encoding) must be a valid encoding, "1.23456789E-9" given -mb_strtoupper(): Argument #2 ($encoding) must be a valid encoding, "1.23456789E-9" given - --- Iteration 3 -- -mb_strtolower(): Argument #2 ($encoding) must be a valid encoding, "1" given -mb_strtoupper(): Argument #2 ($encoding) must be a valid encoding, "1" given - --- Iteration 4 -- -mb_strtolower(): Argument #2 ($encoding) must be a valid encoding, "" given -mb_strtoupper(): Argument #2 ($encoding) must be a valid encoding, "" given - --- Iteration 5 -- mb_strtolower(): Argument #2 ($encoding) must be a valid encoding, "" given mb_strtoupper(): Argument #2 ($encoding) must be a valid encoding, "" given diff --git a/ext/mbstring/tests/gh16229.phpt b/ext/mbstring/tests/gh16229.phpt index 1fe558d9b1025..6e4924a091a54 100644 --- a/ext/mbstring/tests/gh16229.phpt +++ b/ext/mbstring/tests/gh16229.phpt @@ -14,7 +14,7 @@ if (!function_exists("mb_send_mail") || !mb_language("japanese")) { --FILE-- ---INI-- -error_reporting=E_ALL & ~E_NOTICE +Test mb_ereg_replace() function : usage variations - different input types --EXTENSIONS-- mbstring --SKIPIF-- @@ -17,22 +15,8 @@ $replacement = 'string_val'; $string = 'string_val'; $option = ''; -// get a class -class classA -{ - public function __toString() { - return "UTF-8"; - } -} - -// heredoc string -$heredoc = << 1, 'two' => 2); - -//array of values to iterate over -$inputs = array( - - // int data - 'int 0' => 0, - 'int 1' => 1, - 'int 12345' => 12345, - 'int -12345' => -2345, - - // float data - 'float 10.5' => 10.5, - 'float -10.5' => -10.5, - 'float 10.0e19' => 10.0e19, // Cannot be represented as int - 'float -10.0e19' => -10.0e19, // Cannot be represented as int - 'float .5' => .5, - - // array data - 'empty array' => array(), - 'int indexed array' => $index_array, - 'associative array' => $assoc_array, - 'nested arrays' => array('foo', $index_array, $assoc_array), - - // null data - 'uppercase NULL' => NULL, - 'lowercase null' => null, - - // boolean data - 'lowercase true' => true, - 'lowercase false' =>false, - 'uppercase TRUE' =>TRUE, - 'uppercase FALSE' =>FALSE, - - // empty data - 'empty string DQ' => "", - 'empty string SQ' => '', - - // string data - 'string DQ' => "string", - 'string SQ' => 'string', - 'mixed case string' => "sTrInG", - 'heredoc' => $heredoc, - - // object data - 'instance of classWithToString' => new classWithToString(), - 'instance of classWithoutToString' => new classWithoutToString(), - - // undefined data - 'undefined var' => @$undefined_var, - - // unset data - 'unset var' => @$unset_var, -); - -// loop through each element of the array for substchar - -mb_internal_encoding('utf-8'); -foreach($inputs as $key =>$value) { - echo "--$key--\n"; - try { - var_dump( mb_substitute_character($value) ); - } catch (\ValueError|\TypeError $e) { - echo get_class($e) . ': ' . $e->getMessage() . \PHP_EOL; - } -} - -fclose($fp); - -?> ---EXPECTF-- -*** Testing mb_substitute_character(): various types in weak typing mode *** ---int 0-- -bool(true) ---int 1-- -bool(true) ---int 12345-- -bool(true) ---int -12345-- -ValueError: mb_substitute_character(): Argument #1 ($substitute_character) is not a valid codepoint ---float 10.5-- - -Deprecated: Implicit conversion from float 10.5 to int loses precision in %s on line %d -bool(true) ---float -10.5-- - -Deprecated: Implicit conversion from float -10.5 to int loses precision in %s on line %d -ValueError: mb_substitute_character(): Argument #1 ($substitute_character) is not a valid codepoint ---float 10.0e19-- -ValueError: mb_substitute_character(): Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint ---float -10.0e19-- -ValueError: mb_substitute_character(): Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint ---float .5-- - -Deprecated: Implicit conversion from float 0.5 to int loses precision in %s on line %d -bool(true) ---empty array-- -TypeError: mb_substitute_character(): Argument #1 ($substitute_character) must be of type string|int|null, array given ---int indexed array-- -TypeError: mb_substitute_character(): Argument #1 ($substitute_character) must be of type string|int|null, array given ---associative array-- -TypeError: mb_substitute_character(): Argument #1 ($substitute_character) must be of type string|int|null, array given ---nested arrays-- -TypeError: mb_substitute_character(): Argument #1 ($substitute_character) must be of type string|int|null, array given ---uppercase NULL-- -int(0) ---lowercase null-- -int(0) ---lowercase true-- -bool(true) ---lowercase false-- -bool(true) ---uppercase TRUE-- -bool(true) ---uppercase FALSE-- -bool(true) ---empty string DQ-- -ValueError: mb_substitute_character(): Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint ---empty string SQ-- -ValueError: mb_substitute_character(): Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint ---string DQ-- -ValueError: mb_substitute_character(): Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint ---string SQ-- -ValueError: mb_substitute_character(): Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint ---mixed case string-- -ValueError: mb_substitute_character(): Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint ---heredoc-- -ValueError: mb_substitute_character(): Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint ---instance of classWithToString-- -ValueError: mb_substitute_character(): Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint ---instance of classWithoutToString-- -TypeError: mb_substitute_character(): Argument #1 ($substitute_character) must be of type string|int|null, classWithoutToString given ---undefined var-- -int(0) ---unset var-- -int(0) From b068bef45dabcb061eef2bea07593676fdb6e1b8 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Mon, 23 Jun 2025 14:08:58 +0200 Subject: [PATCH 072/120] ext/dom: Remove bool type coercions in tests --- ext/dom/tests/bug46849.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/dom/tests/bug46849.phpt b/ext/dom/tests/bug46849.phpt index a26fa2b2311db..a9cdd5bba578b 100644 --- a/ext/dom/tests/bug46849.phpt +++ b/ext/dom/tests/bug46849.phpt @@ -5,7 +5,7 @@ dom --FILE-- formatOutput = 1; +$dom->formatOutput = true; var_dump($dom->formatOutput); $dom2 = clone $dom; From 8cd4f95ea374748bc5e76774097658d27d1e99a8 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Mon, 23 Jun 2025 14:16:28 +0200 Subject: [PATCH 073/120] ext/pcntl: Remove bool type coercions in tests --- ext/pcntl/tests/async_signals.phpt | 2 +- ext/pcntl/tests/async_signals_2.phpt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/pcntl/tests/async_signals.phpt b/ext/pcntl/tests/async_signals.phpt index e9c1c96d4ea9c..dd0f602c25be2 100644 --- a/ext/pcntl/tests/async_signals.phpt +++ b/ext/pcntl/tests/async_signals.phpt @@ -5,7 +5,7 @@ pcntl posix --FILE-- Date: Mon, 23 Jun 2025 14:17:53 +0200 Subject: [PATCH 074/120] ext/posix: Remove ZPP tests --- ext/posix/tests/posix_seteuid_variation2.phpt | 38 ------------------- ext/posix/tests/posix_setgid_variation2.phpt | 38 ------------------- ext/posix/tests/posix_setuid_variation2.phpt | 38 ------------------- 3 files changed, 114 deletions(-) delete mode 100644 ext/posix/tests/posix_seteuid_variation2.phpt delete mode 100644 ext/posix/tests/posix_setgid_variation2.phpt delete mode 100644 ext/posix/tests/posix_setuid_variation2.phpt diff --git a/ext/posix/tests/posix_seteuid_variation2.phpt b/ext/posix/tests/posix_seteuid_variation2.phpt deleted file mode 100644 index 700f44e5c8f22..0000000000000 --- a/ext/posix/tests/posix_seteuid_variation2.phpt +++ /dev/null @@ -1,38 +0,0 @@ ---TEST-- -Test function posix_seteuid() by substituting argument 1 with boolean values. ---EXTENSIONS-- -posix ---SKIPIF-- - ---CREDITS-- -Marco Fabbri mrfabbri@gmail.com -Francesco Fullone ff@ideato.it -#PHPTestFest Cesena Italia on 2009-06-20 ---FILE-- - true, - 'lowercase false' =>false, - 'uppercase TRUE' =>TRUE, - 'uppercase FALSE' =>FALSE, - ); - - -foreach ( $variation_array as $var ) { - var_dump(posix_seteuid( $var ) ); -} -?> ---EXPECT-- -*** Test substituting argument 1 with boolean values *** -bool(false) -bool(false) -bool(false) -bool(false) diff --git a/ext/posix/tests/posix_setgid_variation2.phpt b/ext/posix/tests/posix_setgid_variation2.phpt deleted file mode 100644 index 8504706c54756..0000000000000 --- a/ext/posix/tests/posix_setgid_variation2.phpt +++ /dev/null @@ -1,38 +0,0 @@ ---TEST-- -Test function posix_setgid() by substituting argument 1 with boolean values. ---EXTENSIONS-- -posix ---SKIPIF-- - ---CREDITS-- -Marco Fabbri mrfabbri@gmail.com -Francesco Fullone ff@ideato.it -#PHPTestFest Cesena Italia on 2009-06-20 ---FILE-- - true, - 'lowercase false' =>false, - 'uppercase TRUE' =>TRUE, - 'uppercase FALSE' =>FALSE, - ); - - -foreach ( $variation_array as $var ) { - var_dump(posix_setgid( $var ) ); -} -?> ---EXPECT-- -*** Test substituting argument 1 with boolean values *** -bool(false) -bool(false) -bool(false) -bool(false) diff --git a/ext/posix/tests/posix_setuid_variation2.phpt b/ext/posix/tests/posix_setuid_variation2.phpt deleted file mode 100644 index 5b2f64f7859ef..0000000000000 --- a/ext/posix/tests/posix_setuid_variation2.phpt +++ /dev/null @@ -1,38 +0,0 @@ ---TEST-- -Test function posix_setuid() by substituting argument 1 with boolean values. ---EXTENSIONS-- -posix ---SKIPIF-- - ---CREDITS-- -Marco Fabbri mrfabbri@gmail.com -Francesco Fullone ff@ideato.it -#PHPTestFest Cesena Italia on 2009-06-20 ---FILE-- - true, - 'lowercase false' =>false, - 'uppercase TRUE' =>TRUE, - 'uppercase FALSE' =>FALSE, - ); - - -foreach ( $variation_array as $var ) { - var_dump(posix_setuid( $var ) ); -} -?> ---EXPECT-- -*** Test substituting argument 1 with boolean values *** -bool(false) -bool(false) -bool(false) -bool(false) From 4ff8d9f6b4a1e0fc84e4e5681fde499516e94186 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Mon, 23 Jun 2025 13:49:20 +0100 Subject: [PATCH 075/120] ext/uri: Remove bool type coercions in tests (#18921) --- ext/uri/tests/053.phpt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/uri/tests/053.phpt b/ext/uri/tests/053.phpt index 93ff77b15c0a5..2bd02365b09a0 100644 --- a/ext/uri/tests/053.phpt +++ b/ext/uri/tests/053.phpt @@ -25,13 +25,13 @@ try { } try { - $r->__construct("baz", [], false); + $r->__construct("baz", [], 0); } catch (Error $e) { echo $e->getMessage() . "\n"; } try { - $r->__construct("qax", [], false, null); + $r->__construct("qax", [], 0, null); } catch (Error $e) { echo $e->getMessage() . "\n"; } From 40be5fa99fc25007078f196dd7cdb26e805cc45f Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Mon, 23 Jun 2025 14:43:53 +0200 Subject: [PATCH 076/120] ext/sockets: Remove bool type coercions in tests --- ext/sockets/tests/socket_export_stream-1.phpt | 2 +- ext/sockets/tests/socket_export_stream-3.phpt | 2 +- ext/sockets/tests/socket_export_stream-4.phpt | 2 +- ext/sockets/tests/socket_import_stream-1.phpt | 2 +- ext/sockets/tests/socket_import_stream-3.phpt | 2 +- ext/sockets/tests/socket_import_stream-4.phpt | 5 ++--- 6 files changed, 7 insertions(+), 8 deletions(-) diff --git a/ext/sockets/tests/socket_export_stream-1.phpt b/ext/sockets/tests/socket_export_stream-1.phpt index b2a01ddcca10d..9b832a80aac33 100644 --- a/ext/sockets/tests/socket_export_stream-1.phpt +++ b/ext/sockets/tests/socket_export_stream-1.phpt @@ -5,7 +5,7 @@ sockets --FILE-- diff --git a/ext/sockets/tests/socket_export_stream-4.phpt b/ext/sockets/tests/socket_export_stream-4.phpt index 512a62379e98c..a3879a93b7cd8 100644 --- a/ext/sockets/tests/socket_export_stream-4.phpt +++ b/ext/sockets/tests/socket_export_stream-4.phpt @@ -16,7 +16,7 @@ function test($stream, $sock) { if ($stream !== null) { echo "stream_set_blocking "; try { - print_r(stream_set_blocking($stream, 0)); + print_r(stream_set_blocking($stream, false)); } catch (Error $e) { echo get_class($e), ": ", $e->getMessage(), "\n"; } diff --git a/ext/sockets/tests/socket_import_stream-1.phpt b/ext/sockets/tests/socket_import_stream-1.phpt index 80d3069fc01e7..8d5ec01cd7d01 100644 --- a/ext/sockets/tests/socket_import_stream-1.phpt +++ b/ext/sockets/tests/socket_import_stream-1.phpt @@ -5,7 +5,7 @@ sockets --FILE-- diff --git a/ext/sockets/tests/socket_import_stream-4.phpt b/ext/sockets/tests/socket_import_stream-4.phpt index 25e425961f613..efe987dfdce28 100644 --- a/ext/sockets/tests/socket_import_stream-4.phpt +++ b/ext/sockets/tests/socket_import_stream-4.phpt @@ -4,8 +4,7 @@ socket_import_stream: effects of closing sockets --SKIPIF-- @@ -16,7 +15,7 @@ function test($stream, $sock) { if ($stream !== null) { echo "stream_set_blocking "; try { - print_r(stream_set_blocking($stream, 0)); + print_r(stream_set_blocking($stream, false)); } catch (Error $e) { echo get_class($e), ": ", $e->getMessage(), "\n"; } From 4baecc1d4a2561a96df9f6f57e82d97b32a154dd Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Mon, 23 Jun 2025 14:50:49 +0200 Subject: [PATCH 077/120] ext/simplexml: Remove bool type coercions in tests --- ext/simplexml/tests/profile13.phpt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/simplexml/tests/profile13.phpt b/ext/simplexml/tests/profile13.phpt index 8c441654c8bee..be2b38f30bba4 100644 --- a/ext/simplexml/tests/profile13.phpt +++ b/ext/simplexml/tests/profile13.phpt @@ -21,9 +21,9 @@ xmlns:xsd="http://www.w3.org/2001/XMLSchema" EOF; $sxe = simplexml_load_string($xml); -var_dump($sxe->children('soap', 1)); +var_dump($sxe->children('soap', true)); -$sxe = simplexml_load_string($xml, NULL, 0, 'soap', 1); +$sxe = simplexml_load_string($xml, NULL, 0, 'soap', true); var_dump($sxe->Body); var_dump($sxe->Body->children('')); var_dump($sxe->Body->children('')->businessList); From 7f80d4dc7ddc012a7d4f4ea2ff75c279592408a2 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Mon, 23 Jun 2025 14:56:03 +0200 Subject: [PATCH 078/120] ext/session: Remove bool type coercions in tests --- ext/session/tests/010.phpt | 2 +- ext/session/tests/session_encode_variation8.phpt | 4 ++-- .../user_session_module/session_set_save_handler_basic.phpt | 2 +- .../session_set_save_handler_closures.phpt | 2 +- .../session_set_save_handler_variation1.phpt | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ext/session/tests/010.phpt b/ext/session/tests/010.phpt index 367edcfa61fd4..1a48680106d80 100644 --- a/ext/session/tests/010.phpt +++ b/ext/session/tests/010.phpt @@ -11,7 +11,7 @@ session.cache_limiter= --EXPECT-- diff --git a/ext/session/tests/session_encode_variation8.phpt b/ext/session/tests/session_encode_variation8.phpt index 3571e8c821691..326b03711580d 100644 --- a/ext/session/tests/session_encode_variation8.phpt +++ b/ext/session/tests/session_encode_variation8.phpt @@ -16,7 +16,7 @@ echo "*** Testing session_encode() : variation ***\n"; var_dump(session_start()); $_SESSION["foo"] = 1234567890; $encoded = session_encode(); -var_dump(base64_encode($encoded)); +var_dump($encoded); var_dump(session_destroy()); echo "Done"; @@ -29,7 +29,7 @@ Warning: session_start(): Cannot find session serialization handler "blah" - ses bool(false) Warning: session_encode(): Cannot encode non-existent session in %s on line %d -string(0) "" +bool(false) Warning: session_destroy(): Trying to destroy uninitialized session in %s on line %d bool(false) diff --git a/ext/session/tests/user_session_module/session_set_save_handler_basic.phpt b/ext/session/tests/user_session_module/session_set_save_handler_basic.phpt index b3932b52587a1..b864d50ab7e9f 100644 --- a/ext/session/tests/user_session_module/session_set_save_handler_basic.phpt +++ b/ext/session/tests/user_session_module/session_set_save_handler_basic.phpt @@ -16,7 +16,7 @@ echo "*** Testing session_set_save_handler() : basic functionality ***\n"; require_once "save_handler.inc"; var_dump(session_module_name()); -var_dump(session_module_name(FALSE)); +var_dump(session_module_name('')); var_dump(session_module_name("blah")); var_dump(session_module_name("foo")); diff --git a/ext/session/tests/user_session_module/session_set_save_handler_closures.phpt b/ext/session/tests/user_session_module/session_set_save_handler_closures.phpt index e84bc6fbef6d4..08f533e6cee38 100644 --- a/ext/session/tests/user_session_module/session_set_save_handler_closures.phpt +++ b/ext/session/tests/user_session_module/session_set_save_handler_closures.phpt @@ -15,7 +15,7 @@ echo "*** Testing session_set_save_handler() : using closures as callbacks ***\n require_once "save_handler_closures.inc"; var_dump(session_module_name()); -var_dump(session_module_name(FALSE)); +var_dump(session_module_name('')); var_dump(session_module_name("blah")); var_dump(session_module_name("foo")); diff --git a/ext/session/tests/user_session_module/session_set_save_handler_variation1.phpt b/ext/session/tests/user_session_module/session_set_save_handler_variation1.phpt index 417103b3d1b1c..87996a3314534 100644 --- a/ext/session/tests/user_session_module/session_set_save_handler_variation1.phpt +++ b/ext/session/tests/user_session_module/session_set_save_handler_variation1.phpt @@ -10,7 +10,7 @@ ob_start(); echo "*** Testing session_set_save_handler() : variation ***\n"; var_dump(session_module_name()); -var_dump(session_module_name(FALSE)); +var_dump(session_module_name('')); var_dump(session_module_name()); var_dump(session_module_name("blah")); var_dump(session_module_name()); From c7f0ac1bf942df3b129b558773cace58a72f2b16 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Mon, 23 Jun 2025 13:59:05 +0100 Subject: [PATCH 079/120] ext/random: Remove useless tests (#18920) --- .../tests/01_functions/mt_srand_basic.phpt | 24 ----------------- .../tests/01_functions/srand_basic.phpt | 27 ------------------- 2 files changed, 51 deletions(-) delete mode 100644 ext/random/tests/01_functions/mt_srand_basic.phpt delete mode 100644 ext/random/tests/01_functions/srand_basic.phpt diff --git a/ext/random/tests/01_functions/mt_srand_basic.phpt b/ext/random/tests/01_functions/mt_srand_basic.phpt deleted file mode 100644 index aee012d713fa4..0000000000000 --- a/ext/random/tests/01_functions/mt_srand_basic.phpt +++ /dev/null @@ -1,24 +0,0 @@ ---TEST-- -Test mt_srand() - basic function (return values) mt_srand() ---FILE-- - ---EXPECTF-- -NULL -NULL - -Deprecated: Implicit conversion from float 500.1 to int loses precision in %s on line %d -NULL -NULL -NULL -NULL -NULL diff --git a/ext/random/tests/01_functions/srand_basic.phpt b/ext/random/tests/01_functions/srand_basic.phpt deleted file mode 100644 index 99f43bc502737..0000000000000 --- a/ext/random/tests/01_functions/srand_basic.phpt +++ /dev/null @@ -1,27 +0,0 @@ ---TEST-- -Test srand() - basic function test for srand() ---FILE-- - ---EXPECTF-- -*** Testing srand() : basic functionality *** -NULL -NULL - -Deprecated: Implicit conversion from float 500.1 to int loses precision in %s on line %d -NULL -NULL -NULL -NULL -NULL From fe504d33571f7c21a3529594693460a863dbb5ed Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Mon, 23 Jun 2025 00:05:03 +0200 Subject: [PATCH 080/120] Fix leak when creating cycle in hook This is necessary because the VM frees operands with the nogc variants. We cannot just call gc_possible_root() because the object may no longer exist at that point. Fixes GH-18907 Closes GH-18917 --- NEWS | 1 + Zend/tests/gh18907.phpt | 26 ++++++++++++++++++++++++++ Zend/zend_object_handlers.c | 2 ++ 3 files changed, 29 insertions(+) create mode 100644 Zend/tests/gh18907.phpt diff --git a/NEWS b/NEWS index 94eb74cae5179..80b805983e863 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,7 @@ PHP NEWS - Core: . Fixed bug GH-18833 (Use after free with weakmaps dependent on destruction order). (Daniil Gentili) + . Fixed bug GH-18907 (Leak when creating cycle in hook). (ilutov) - Curl: . Fix memory leaks when returning refcounted value from curl callback. diff --git a/Zend/tests/gh18907.phpt b/Zend/tests/gh18907.phpt new file mode 100644 index 0000000000000..1be881fd4941b --- /dev/null +++ b/Zend/tests/gh18907.phpt @@ -0,0 +1,26 @@ +--TEST-- +GH-18907: Leak when creating cycle inside hook +--FILE-- +prop = $this; + return 1; + } + } +} + +function test() { + var_dump((new Foo)->prop); +} + +/* Call twice to test the ZEND_IS_PROPERTY_HOOK_SIMPLE_GET() path. */ +test(); +test(); + +?> +--EXPECT-- +int(1) +int(1) diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 0def95fc85227..2ddaeae96e999 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -719,7 +719,9 @@ static bool zend_call_get_hook( return false; } + GC_ADDREF(zobj); zend_call_known_instance_method_with_0_params(get, zobj, rv); + OBJ_RELEASE(zobj); return true; } From b50898894d885eb4a95e6ff88f90ab56f9c8c03c Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 22 Jun 2025 16:03:45 +0200 Subject: [PATCH 081/120] Unbreak PRINTF_DEBUG macro usages Clearly nobody has used this in a while given the compile errors and warnings. This patch fixes them so there are no errors nor warnings anymore. Closes GH-18910. --- ext/standard/formatted_print.c | 46 ++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/ext/standard/formatted_print.c b/ext/standard/formatted_print.c index b988422df21ca..00445d3cca7c7 100644 --- a/ext/standard/formatted_print.c +++ b/ext/standard/formatted_print.c @@ -52,10 +52,10 @@ inline static void php_sprintf_appendchar(zend_string **buffer, size_t *pos, char add) { if ((*pos + 1) >= ZSTR_LEN(*buffer)) { - PRINTF_DEBUG(("%s(): ereallocing buffer to %d bytes\n", get_active_function_name(), ZSTR_LEN(*buffer))); + PRINTF_DEBUG(("%s(): ereallocing buffer to %zu bytes\n", get_active_function_name(), ZSTR_LEN(*buffer))); *buffer = zend_string_extend(*buffer, ZSTR_LEN(*buffer) << 1, 0); } - PRINTF_DEBUG(("sprintf: appending '%c', pos=\n", add, *pos)); + PRINTF_DEBUG(("sprintf: appending '%c', pos=%zu\n", add, *pos)); ZSTR_VAL(*buffer)[(*pos)++] = add; } /* }}} */ @@ -67,13 +67,13 @@ php_sprintf_appendchars(zend_string **buffer, size_t *pos, char *add, size_t len if ((*pos + len) >= ZSTR_LEN(*buffer)) { size_t nlen = ZSTR_LEN(*buffer); - PRINTF_DEBUG(("%s(): ereallocing buffer to %d bytes\n", get_active_function_name(), ZSTR_LEN(*buffer))); + PRINTF_DEBUG(("%s(): ereallocing buffer to %zu bytes\n", get_active_function_name(), ZSTR_LEN(*buffer))); do { nlen = nlen << 1; } while ((*pos + len) >= nlen); *buffer = zend_string_extend(*buffer, nlen, 0); } - PRINTF_DEBUG(("sprintf: appending \"%s\", pos=\n", add, *pos)); + PRINTF_DEBUG(("sprintf: appending \"%s\", pos=%zu\n", add, *pos)); memcpy(ZSTR_VAL(*buffer) + (*pos), add, len); *pos += len; } @@ -93,7 +93,7 @@ php_sprintf_appendstring(zend_string **buffer, size_t *pos, char *add, copy_len = (expprec ? MIN(max_width, len) : len); npad = (min_width < copy_len) ? 0 : min_width - copy_len; - PRINTF_DEBUG(("sprintf: appendstring(%x, %d, %d, \"%s\", %d, '%c', %d)\n", + PRINTF_DEBUG(("sprintf: appendstring(%p, %zu, %zu, \"%s\", %zu, '%c', %zu)\n", *buffer, *pos, ZSTR_LEN(*buffer), add, min_width, padding, alignment)); m_width = MAX(min_width, copy_len); @@ -111,7 +111,7 @@ php_sprintf_appendstring(zend_string **buffer, size_t *pos, char *add, } size <<= 1; } - PRINTF_DEBUG(("sprintf ereallocing buffer to %d bytes\n", size)); + PRINTF_DEBUG(("sprintf ereallocing buffer to %zu bytes\n", size)); *buffer = zend_string_extend(*buffer, size, 0); } if (alignment == ALIGN_RIGHT) { @@ -146,8 +146,8 @@ php_sprintf_appendint(zend_string **buffer, size_t *pos, zend_long number, zend_ulong magn, nmagn; unsigned int i = NUM_BUF_SIZE - 1, neg = 0; - PRINTF_DEBUG(("sprintf: appendint(%x, %x, %x, %d, %d, '%c', %d)\n", - *buffer, pos, &ZSTR_LEN(*buffer), number, width, padding, alignment)); + PRINTF_DEBUG(("sprintf: appendint(%p, %zu, %zu, " ZEND_LONG_FMT ", %zu, '%c', %zu)\n", + *buffer, *pos, ZSTR_LEN(*buffer), number, width, padding, alignment)); if (number < 0) { neg = 1; magn = ((zend_ulong) -(number + 1)) + 1; @@ -172,7 +172,7 @@ php_sprintf_appendint(zend_string **buffer, size_t *pos, zend_long number, } else if (always_sign) { numbuf[--i] = '+'; } - PRINTF_DEBUG(("sprintf: appending %d as \"%s\", i=%d\n", + PRINTF_DEBUG(("sprintf: appending " ZEND_LONG_FMT " as \"%s\", i=%u\n", number, &numbuf[i], i)); php_sprintf_appendstring(buffer, pos, &numbuf[i], width, 0, padding, alignment, (NUM_BUF_SIZE - 1) - i, @@ -190,8 +190,8 @@ php_sprintf_appenduint(zend_string **buffer, size_t *pos, zend_ulong magn, nmagn; unsigned int i = NUM_BUF_SIZE - 1; - PRINTF_DEBUG(("sprintf: appenduint(%x, %x, %x, %d, %d, '%c', %d)\n", - *buffer, pos, &ZSTR_LEN(*buffer), number, width, padding, alignment)); + PRINTF_DEBUG(("sprintf: appenduint(%p, %zu, %zu, " ZEND_LONG_FMT ", %zu, '%c', %zu)\n", + *buffer, *pos, ZSTR_LEN(*buffer), number, width, padding, alignment)); magn = (zend_ulong) number; /* Can't right-pad 0's on integers */ @@ -206,7 +206,7 @@ php_sprintf_appenduint(zend_string **buffer, size_t *pos, magn = nmagn; } while (magn > 0 && i > 0); - PRINTF_DEBUG(("sprintf: appending %d as \"%s\", i=%d\n", number, &numbuf[i], i)); + PRINTF_DEBUG(("sprintf: appending " ZEND_LONG_FMT " as \"%s\", i=%d\n", number, &numbuf[i], i)); php_sprintf_appendstring(buffer, pos, &numbuf[i], width, 0, padding, alignment, (NUM_BUF_SIZE - 1) - i, /* neg */ false, 0, 0); } @@ -232,8 +232,8 @@ php_sprintf_appenddouble(zend_string **buffer, size_t *pos, struct lconv *lconv; #endif - PRINTF_DEBUG(("sprintf: appenddouble(%x, %x, %x, %f, %d, '%c', %d, %c)\n", - *buffer, pos, &ZSTR_LEN(*buffer), number, width, padding, alignment, fmt)); + PRINTF_DEBUG(("sprintf: appenddouble(%p, %zu, %zu, %f, %zu, '%c', %zu, %c)\n", + *buffer, *pos, ZSTR_LEN(*buffer), number, width, padding, alignment, fmt)); if ((adjust & ADJ_PRECISION) == 0) { precision = FLOAT_PRECISION; } else if (precision > MAX_FLOAT_PRECISION) { @@ -330,8 +330,8 @@ php_sprintf_append2n(zend_string **buffer, size_t *pos, zend_long number, zend_ulong i = NUM_BUF_SIZE - 1; int andbits = (1 << n) - 1; - PRINTF_DEBUG(("sprintf: append2n(%x, %x, %x, %d, %d, '%c', %d, %d, %x)\n", - *buffer, pos, &ZSTR_LEN(*buffer), number, width, padding, alignment, n, + PRINTF_DEBUG(("sprintf: append2n(%p, %zu, %zu, " ZEND_LONG_FMT ", %zu, '%c', %zu, %d, %p)\n", + *buffer, *pos, ZSTR_LEN(*buffer), number, width, padding, alignment, n, chartable)); PRINTF_DEBUG(("sprintf: append2n 2^%d andbits=%x\n", n, andbits)); @@ -363,7 +363,7 @@ php_sprintf_getnumber(char **buffer, size_t *len) *len -= i; *buffer = endptr; } - PRINTF_DEBUG(("sprintf_getnumber: number was %d bytes long\n", i)); + PRINTF_DEBUG(("sprintf_getnumber: number was %zu bytes long\n", i)); if (num >= INT_MAX || num < 0) { return -1; @@ -431,6 +431,10 @@ php_formatted_print(char *format, size_t format_len, zval *args, int argc, int n int always_sign; int max_missing_argnum = -1; + /* For debugging */ + const char *format_orig = format; + ZEND_IGNORE_VALUE(format_orig); + result = zend_string_alloc(size, 0); currarg = 0; @@ -464,8 +468,8 @@ php_formatted_print(char *format, size_t format_len, zval *args, int argc, int n always_sign = 0; expprec = 0; - PRINTF_DEBUG(("sprintf: first looking at '%c', inpos=%d\n", - *format, format - Z_STRVAL_P(z_format))); + PRINTF_DEBUG(("sprintf: first looking at '%c', inpos=%zu\n", + *format, format - format_orig)); if (isalpha((int)*format)) { width = precision = 0; argnum = ARG_NUM_NEXT; @@ -478,8 +482,8 @@ php_formatted_print(char *format, size_t format_len, zval *args, int argc, int n /* after argnum comes modifiers */ PRINTF_DEBUG(("sprintf: looking for modifiers\n" - "sprintf: now looking at '%c', inpos=%d\n", - *format, format - Z_STRVAL_P(z_format))); + "sprintf: now looking at '%c', inpos=%zu\n", + *format, format - format_orig)); for (;; format++, format_len--) { if (*format == ' ' || *format == '0') { padding = *format; From 799ec7b8c50440f851d823d5c4b68f430234149b Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 22 Jun 2025 16:29:19 +0200 Subject: [PATCH 082/120] Fix misleading errors in printf() The precision and width _can_ be zero. Closes GH-18911. --- NEWS | 3 +++ ext/standard/formatted_print.c | 6 +++--- ext/standard/tests/strings/sprintf_star.phpt | 16 +++++++++++++++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index fd344ee94c72e..1010209696243 100644 --- a/NEWS +++ b/NEWS @@ -20,6 +20,9 @@ PHP NEWS - MbString: . Fixed bug GH-18901 (integer overflow mb_split). (nielsdos) +- Standard: + . Fix misleading errors in printf(). (nielsdos) + - Streams: . Fixed GH-13264 (fgets() and stream_get_line() do not return false on filter fatal error). (Jakub Zelenka) diff --git a/ext/standard/formatted_print.c b/ext/standard/formatted_print.c index 00445d3cca7c7..1ff0f36212bbf 100644 --- a/ext/standard/formatted_print.c +++ b/ext/standard/formatted_print.c @@ -534,7 +534,7 @@ php_formatted_print(char *format, size_t format_len, zval *args, int argc, int n goto fail; } if (Z_LVAL_P(tmp) < 0 || Z_LVAL_P(tmp) > INT_MAX) { - zend_value_error("Width must be greater than zero and less than %d", INT_MAX); + zend_value_error("Width must be between 0 and %d", INT_MAX); goto fail; } width = Z_LVAL_P(tmp); @@ -542,7 +542,7 @@ php_formatted_print(char *format, size_t format_len, zval *args, int argc, int n } else if (isdigit((int)*format)) { PRINTF_DEBUG(("sprintf: getting width\n")); if ((width = php_sprintf_getnumber(&format, &format_len)) < 0) { - zend_value_error("Width must be greater than zero and less than %d", INT_MAX); + zend_value_error("Width must be between 0 and %d", INT_MAX); goto fail; } adjusting |= ADJ_WIDTH; @@ -586,7 +586,7 @@ php_formatted_print(char *format, size_t format_len, zval *args, int argc, int n expprec = 1; } else if (isdigit((int)*format)) { if ((precision = php_sprintf_getnumber(&format, &format_len)) < 0) { - zend_value_error("Precision must be greater than zero and less than %d", INT_MAX); + zend_value_error("Precision must be between 0 and %d", INT_MAX); goto fail; } adjusting |= ADJ_PRECISION; diff --git a/ext/standard/tests/strings/sprintf_star.phpt b/ext/standard/tests/strings/sprintf_star.phpt index 0e3e16c326420..0c8a211e5c437 100644 --- a/ext/standard/tests/strings/sprintf_star.phpt +++ b/ext/standard/tests/strings/sprintf_star.phpt @@ -62,6 +62,18 @@ try { echo $e->getMessage(), "\n"; } +try { + printf("%9999999999999999999999.f\n", $f); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} + +try { + printf("%.9999999999999999999999f\n", $f); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} + ?> --EXPECT-- float(1.2345678901234567) @@ -95,4 +107,6 @@ foo Precision must be an integer Precision must be between -1 and 2147483647 Precision -1 is only supported for %g, %G, %h and %H -Width must be greater than zero and less than 2147483647 +Width must be between 0 and 2147483647 +Width must be between 0 and 2147483647 +Precision must be between 0 and 2147483647 From 8e731ca622bfc2cf26375c950fdd58ccae2f999f Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 22 Jun 2025 20:18:55 +0200 Subject: [PATCH 083/120] Fix GH-18639: Internal class aliases can break preloading + JIT ZEND_FUNC_INFO() can not be used on internal CE's. If preloading makes a CE that's an alias of an internal class, the invalid access happens when setting the FUNC_INFO. While we could check the class type to be of user code, we can just skip aliases altogether anyway which may be faster. Closes GH-18915. --- NEWS | 4 ++++ ext/opcache/jit/zend_jit.c | 10 +++++++++- ext/opcache/tests/gh18639.phpt | 20 ++++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 ext/opcache/tests/gh18639.phpt diff --git a/NEWS b/NEWS index 1010209696243..b453445854f95 100644 --- a/NEWS +++ b/NEWS @@ -20,6 +20,10 @@ PHP NEWS - MbString: . Fixed bug GH-18901 (integer overflow mb_split). (nielsdos) +- Opcache: + . Fixed bug GH-18639 (Internal class aliases can break preloading + JIT). + (nielsdos) + - Standard: . Fix misleading errors in printf(). (nielsdos) diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 9adfe1719f626..7caa3387016e7 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -4628,8 +4628,16 @@ ZEND_EXT_API int zend_jit_script(zend_script *script) || JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { zend_class_entry *ce; zend_op_array *op_array; + zval *zv; + + ZEND_HASH_MAP_FOREACH_VAL(&script->class_table, zv) { + if (Z_TYPE_P(zv) == IS_ALIAS_PTR) { + continue; + } + + ce = Z_PTR_P(zv); + ZEND_ASSERT(ce->type == ZEND_USER_CLASS); - ZEND_HASH_MAP_FOREACH_PTR(&script->class_table, ce) { ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, op_array) { if (!ZEND_FUNC_INFO(op_array)) { void *jit_extension = zend_shared_alloc_get_xlat_entry(op_array->opcodes); diff --git a/ext/opcache/tests/gh18639.phpt b/ext/opcache/tests/gh18639.phpt new file mode 100644 index 0000000000000..28424032931ab --- /dev/null +++ b/ext/opcache/tests/gh18639.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-18639 (Internal class aliases can break preloading + JIT) +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit=1255 +opcache.jit_buffer_size=16M +opcache.preload={PWD}/preload_gh18567.inc +--EXTENSIONS-- +opcache +--SKIPIF-- + +--FILE-- + +--EXPECT-- +ok From 56c4ddfaf62ff3935029847bb6fb44768f4b9452 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 22 Jun 2025 09:43:08 +0200 Subject: [PATCH 084/120] Fix GH-18899: JIT function crash when emitting undefined variable warning and opline is not set yet The crash happens because EX(opline) is attempted to be accessed but it's not set yet. Closes GH-18904. --- NEWS | 2 ++ ext/opcache/jit/zend_jit_ir.c | 2 ++ ext/opcache/tests/jit/gh18899.phpt | 21 +++++++++++++++++++++ 3 files changed, 25 insertions(+) create mode 100644 ext/opcache/tests/jit/gh18899.phpt diff --git a/NEWS b/NEWS index 2e969e0830f41..f71edaedb61c0 100644 --- a/NEWS +++ b/NEWS @@ -24,6 +24,8 @@ PHP NEWS - Opcache: . Fixed bug GH-18639 (Internal class aliases can break preloading + JIT). (nielsdos) + . Fixed bug GH-18899 (JIT function crash when emitting undefined variable + warning and opline is not set yet). (nielsdos) - Standard: . Fix misleading errors in printf(). (nielsdos) diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index 74fad38ffee87..6afd768321cb3 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -5981,6 +5981,7 @@ static int zend_jit_long_math_helper(zend_jit_ctx *jit, ir_IF_FALSE_cold(if_def); // zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))); + jit_SET_EX_OPLINE(jit, opline); ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var)); ref2 = jit_EG(uninitialized_zval); @@ -5997,6 +5998,7 @@ static int zend_jit_long_math_helper(zend_jit_ctx *jit, ir_IF_FALSE_cold(if_def); // zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op2.var))); + jit_SET_EX_OPLINE(jit, opline); ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op2.var)); ref2 = jit_EG(uninitialized_zval); diff --git a/ext/opcache/tests/jit/gh18899.phpt b/ext/opcache/tests/jit/gh18899.phpt new file mode 100644 index 0000000000000..47c9a3e1ae379 --- /dev/null +++ b/ext/opcache/tests/jit/gh18899.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-18899 (JIT function crash when emitting undefined variable warning and opline is not set yet) +--EXTENSIONS-- +opcache +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit=1205 +opcache.jit_buffer_size=8M +--FILE-- +>= 8; + } +} +str_repeat("A",232).ptr2str(); +?> +--EXPECTF-- +Warning: Undefined variable $ptr in %s on line %d From 591b3249da3f7dbad91685b1dc78efa733d28b85 Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Mon, 23 Jun 2025 21:44:58 +0200 Subject: [PATCH 085/120] Do not use RTLD_DEEPBIND if dlmopen is available (#18612) DL_LOAD now doesn't use RTLD_DEEPBIND deepbind anymore on platforms where dlmopen with LM_ID_NEWLM is available: this means shared library symbol isolation (if needed) must be enabled on the user side when requiring libphp.so, by using dlmopen with LM_ID_NEWLM instead of dlopen. RTLD_DEEPBIND is still enabled when the Apache SAPI is in use. Closes GH-10670. --- NEWS | 1 + UPGRADING.INTERNALS | 6 ++++++ Zend/zend_API.c | 7 +++++++ Zend/zend_API.h | 2 ++ Zend/zend_portability.h | 7 ++++++- sapi/apache2handler/sapi_apache2.c | 1 + 6 files changed, 23 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 1ce8ce754adc9..65fb408ddaacf 100644 --- a/NEWS +++ b/NEWS @@ -58,6 +58,7 @@ PHP NEWS . Added the pipe (|>) operator. (crell) . Added support for `final` with constructor property promotion. (DanielEScherzer) + . Do not use RTLD_DEEPBIND if dlmopen is available. (Daniil Gentili) - Curl: . Added curl_multi_get_handles(). (timwolla) diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 432754528f09a..47482d40d0b8d 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -17,6 +17,12 @@ PHP 8.5 INTERNALS UPGRADE NOTES - Core . PG(arg_separator).input and PG(arg_separator).output are now `zend_string*` instead of `char*`. + . DL_LOAD now doesn't use RTLD_DEEPBIND deepbind anymore on platforms + where dlmopen with LM_ID_NEWLM is available: + this means shared library symbol isolation (if needed) must be enabled on + the user side when requiring libphp.so, by using dlmopen with LM_ID_NEWLM + instead of dlopen. + RTLD_DEEPBIND is still enabled when the Apache SAPI is in use. - Zend . Added zend_safe_assign_to_variable_noref() function to safely assign diff --git a/Zend/zend_API.c b/Zend/zend_API.c index e0006e7d7275f..d29fe8ae8e3c3 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -40,6 +40,8 @@ /* these variables are true statics/globals, and have to be mutex'ed on every access */ ZEND_API HashTable module_registry; +ZEND_API bool zend_dl_use_deepbind = false; + static zend_module_entry **module_request_startup_handlers; static zend_module_entry **module_request_shutdown_handlers; static zend_module_entry **module_post_deactivate_handlers; @@ -47,6 +49,11 @@ static zend_module_entry **modules_dl_loaded; static zend_class_entry **class_cleanup_handlers; +ZEND_API void zend_set_dl_use_deepbind(bool use_deepbind) +{ + zend_dl_use_deepbind = use_deepbind; +} + ZEND_API zend_result zend_get_parameters_array_ex(uint32_t param_count, zval *argument_array) /* {{{ */ { zval *param_ptr; diff --git a/Zend/zend_API.h b/Zend/zend_API.h index a644de8e15134..02ec1b18a6b69 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -343,6 +343,8 @@ typedef struct _zend_fcall_info_cache { ZEND_API int zend_next_free_module(void); BEGIN_EXTERN_C() +ZEND_API void zend_set_dl_use_deepbind(bool use_deepbind); + ZEND_API zend_result zend_get_parameters_array_ex(uint32_t param_count, zval *argument_array); /* internal function to efficiently copy parameters when executing __call() */ diff --git a/Zend/zend_portability.h b/Zend/zend_portability.h index 65ce533c753bd..97bd038ecf3d8 100644 --- a/Zend/zend_portability.h +++ b/Zend/zend_portability.h @@ -165,7 +165,12 @@ # if defined(RTLD_GROUP) && defined(RTLD_WORLD) && defined(RTLD_PARENT) # define DL_LOAD(libname) dlopen(libname, PHP_RTLD_MODE | RTLD_GLOBAL | RTLD_GROUP | RTLD_WORLD | RTLD_PARENT) # elif defined(RTLD_DEEPBIND) && !defined(__SANITIZE_ADDRESS__) && !__has_feature(memory_sanitizer) -# define DL_LOAD(libname) dlopen(libname, PHP_RTLD_MODE | RTLD_GLOBAL | RTLD_DEEPBIND) +# if defined(LM_ID_NEWLM) + ZEND_API extern bool zend_dl_use_deepbind; +# define DL_LOAD(libname) dlopen(libname, PHP_RTLD_MODE | RTLD_GLOBAL | (zend_dl_use_deepbind ? RTLD_DEEPBIND : 0)) +# else +# define DL_LOAD(libname) dlopen(libname, PHP_RTLD_MODE | RTLD_GLOBAL | RTLD_DEEPBIND) +# endif # else # define DL_LOAD(libname) dlopen(libname, PHP_RTLD_MODE | RTLD_GLOBAL) # endif diff --git a/sapi/apache2handler/sapi_apache2.c b/sapi/apache2handler/sapi_apache2.c index 1d85a92ebf4d8..e87223b055e12 100644 --- a/sapi/apache2handler/sapi_apache2.c +++ b/sapi/apache2handler/sapi_apache2.c @@ -466,6 +466,7 @@ php_apache_server_startup(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp { void *data = NULL; const char *userdata_key = "apache2hook_post_config"; + zend_set_dl_use_deepbind(true); /* Apache will load, unload and then reload a DSO module. This * prevents us from starting PHP until the second load. */ From 1e3d92f8a95c17d0fb19c11e17a0cd8c13c18309 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 22 Jun 2025 20:28:02 +0200 Subject: [PATCH 086/120] Fix GH-14082: Segmentation fault on unknown address 0x600000000018 in ext/opcache/jit/zend_jit.c During persisting, the JIT may trigger and fill in the call graph. The call graph info is allocated on the arena which will be gone after preloading. To prevent invalid accesses during normal requests, the arena data should be cleared. This has to be done after all scripts have been persisted because shared op arrays between scripts can change the call graph. Closes GH-18916. --- NEWS | 2 + ext/opcache/ZendAccelerator.c | 47 +++++++++++++++++++++++ ext/opcache/tests/jit/gh14082.phpt | 23 +++++++++++ ext/opcache/tests/jit/preload_gh14082.inc | 9 +++++ 4 files changed, 81 insertions(+) create mode 100644 ext/opcache/tests/jit/gh14082.phpt create mode 100644 ext/opcache/tests/jit/preload_gh14082.inc diff --git a/NEWS b/NEWS index b453445854f95..34866abfb21d8 100644 --- a/NEWS +++ b/NEWS @@ -23,6 +23,8 @@ PHP NEWS - Opcache: . Fixed bug GH-18639 (Internal class aliases can break preloading + JIT). (nielsdos) + . Fixed bug GH-14082 (Segmentation fault on unknown address 0x600000000018 + in ext/opcache/jit/zend_jit.c). (nielsdos) - Standard: . Fix misleading errors in printf(). (nielsdos) diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index bd6b323871bcc..1b0101dbfd6cb 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -52,6 +52,8 @@ #ifdef HAVE_JIT # include "jit/zend_jit.h" +# include "Optimizer/zend_func_info.h" +# include "Optimizer/zend_call_graph.h" #endif #ifndef ZEND_WIN32 @@ -4363,6 +4365,39 @@ static void preload_load(void) } } +#if HAVE_JIT +static void zend_accel_clear_call_graph_ptrs(zend_op_array *op_array) +{ + ZEND_ASSERT(ZEND_USER_CODE(op_array->type)); + zend_func_info *info = ZEND_FUNC_INFO(op_array); + if (info) { + info->caller_info = NULL; + info->callee_info = NULL; + } +} + +static void accel_reset_arena_info(zend_persistent_script *script) +{ + zend_op_array *op_array; + zend_class_entry *ce; + + zend_accel_clear_call_graph_ptrs(&script->script.main_op_array); + ZEND_HASH_MAP_FOREACH_PTR(&script->script.function_table, op_array) { + zend_accel_clear_call_graph_ptrs(op_array); + } ZEND_HASH_FOREACH_END(); + ZEND_HASH_MAP_FOREACH_PTR(&script->script.class_table, ce) { + ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, op_array) { + if (op_array->scope == ce + && op_array->type == ZEND_USER_FUNCTION + && !(op_array->fn_flags & ZEND_ACC_ABSTRACT) + && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) { + zend_accel_clear_call_graph_ptrs(op_array); + } + } ZEND_HASH_FOREACH_END(); + } ZEND_HASH_FOREACH_END(); +} +#endif + static zend_result accel_preload(const char *config, bool in_child) { zend_file_handle file_handle; @@ -4568,6 +4603,18 @@ static zend_result accel_preload(const char *config, bool in_child) } ZEND_HASH_FOREACH_END(); ZCSG(saved_scripts)[i] = NULL; +#if HAVE_JIT + /* During persisting, the JIT may trigger and fill in the call graph. + * The call graph info is allocated on the arena which will be gone after preloading. + * To prevent invalid accesses during normal requests, the arena data should be cleared. + * This has to be done after all scripts have been persisted because shared op arrays between + * scripts can change the call graph. */ + accel_reset_arena_info(ZCSG(preload_script)); + for (zend_persistent_script **scripts = ZCSG(saved_scripts); *scripts; scripts++) { + accel_reset_arena_info(*scripts); + } +#endif + zend_shared_alloc_save_state(); accel_interned_strings_save_state(); diff --git a/ext/opcache/tests/jit/gh14082.phpt b/ext/opcache/tests/jit/gh14082.phpt new file mode 100644 index 0000000000000..eba67a096b82c --- /dev/null +++ b/ext/opcache/tests/jit/gh14082.phpt @@ -0,0 +1,23 @@ +--TEST-- +GH-14082 (Segmentation fault on unknown address 0x600000000018 in ext/opcache/jit/zend_jit.c) +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit=1235 +opcache.jit_buffer_size=16M +opcache.preload={PWD}/preload_gh14082.inc +--EXTENSIONS-- +opcache +--SKIPIF-- + +--FILE-- + +--EXPECT-- +int(1) +int(1) +ok diff --git a/ext/opcache/tests/jit/preload_gh14082.inc b/ext/opcache/tests/jit/preload_gh14082.inc new file mode 100644 index 0000000000000..f5b11ac621ebe --- /dev/null +++ b/ext/opcache/tests/jit/preload_gh14082.inc @@ -0,0 +1,9 @@ + Date: Mon, 23 Jun 2025 23:43:52 +0200 Subject: [PATCH 087/120] Autotools: Remove obsole Autoconf macros (#18914) These Autoconf macros have been marked as obsolete in PHP-8.4 and now also removed: - PHP_AP_EXTRACT_VERSION - PHP_BUILD_THREAD_SAFE - PHP_DEF_HAVE - PHP_OUTPUT - PHP_TEST_BUILD --- UPGRADING.INTERNALS | 8 ++++- build/php.m4 | 71 --------------------------------------------- 2 files changed, 7 insertions(+), 72 deletions(-) diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 47482d40d0b8d..f421242dba6c6 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -55,12 +55,18 @@ PHP 8.5 INTERNALS UPGRADE NOTES without duplicate build rules. It is up to the SAPI maintainers to ensure that appropriate build rules are created. -- Linux build system changes +- Unix build system changes . libdir is properly set when --libdir (ex: /usr/lib64) and --with-libdir (ex lib64) configure options are used to ${libdir}/php (ex: /usr/lib64/php) . PHP_ODBC_CFLAGS, PHP_ODBC_LFLAGS, PHP_ODBC_LIBS, PHP_ODBC_TYPE preprocessor macros defined by ext/odbc are now defined in php_config.h instead of the build-defs.h header. + . Autoconf macro PHP_AP_EXTRACT_VERSION has been removed. + . Autoconf macro PHP_BUILD_THREAD_SAFE has been removed (set enable_zts + manually). + . Autoconf macro PHP_DEF_HAVE has been removed (use AC_DEFINE). + . Autoconf macro PHP_OUTPUT has been removed (use AC_CONFIG_FILES). + . Autoconf macro PHP_TEST_BUILD has been removed (use AC_* macros). ======================== 3. Module changes diff --git a/build/php.m4 b/build/php.m4 index aa49766fedd7f..8cdf318083fbb 100644 --- a/build/php.m4 +++ b/build/php.m4 @@ -26,15 +26,6 @@ dnl ---------------------------------------------------------------------------- dnl Build system helper macros. dnl ---------------------------------------------------------------------------- -dnl -dnl PHP_DEF_HAVE(what) -dnl -dnl Generates 'AC_DEFINE(HAVE_WHAT, 1, [ ])'. -dnl -AC_DEFUN([PHP_DEF_HAVE], [m4_warn([obsolete], - [The macro 'PHP_DEF_HAVE' is obsolete. Use AC_DEFINE.]) -AC_DEFINE([HAVE_]translit($1,a-z_.-,A-Z___), 1, [ ])]) - dnl dnl PHP_RUN_ONCE(namespace, variable, code) dnl @@ -89,17 +80,6 @@ AC_DEFUN([PHP_SUBST_OLD],[ PHP_SUBST([$1]) ]) -dnl -dnl PHP_OUTPUT(file) -dnl -dnl Adds "file" to the list of files generated by AC_OUTPUT. This macro can be -dnl used several times. This macro is obsolete as of PHP 8.4 in favor of the -dnl default AC_CONFIG_FILES. -dnl -AC_DEFUN([PHP_OUTPUT], -[m4_warn([obsolete], [The macro 'PHP_OUTPUT' is obsolete. Use AC_CONFIG_FILES.]) -AC_CONFIG_FILES([$1])]) - dnl ---------------------------------------------------------------------------- dnl Build system base macros. dnl ---------------------------------------------------------------------------- @@ -743,13 +723,6 @@ dnl ---------------------------------------------------------------------------- dnl Build macros dnl ---------------------------------------------------------------------------- -dnl -dnl PHP_BUILD_THREAD_SAFE -dnl -AC_DEFUN([PHP_BUILD_THREAD_SAFE], [m4_warn([obsolete], - [The macro 'PHP_BUILD_THREAD_SAFE' is obsolete. Set 'enable_zts' manually.]) - enable_zts=yes]) - dnl dnl PHP_REQUIRE_CXX dnl @@ -1518,31 +1491,6 @@ AC_DEFUN([PHP_CHECK_FUNC],[ esac ]) -dnl -dnl PHP_TEST_BUILD(function, action-if-ok, action-if-not-ok [, extra-libs [, extra-source]]) -dnl -dnl This macro checks whether build works and given function exists. -dnl -AC_DEFUN([PHP_TEST_BUILD], [m4_warn([obsolete], - [The macro 'PHP_TEST_BUILD' is obsolete. Use AC_* macros.]) - old_LIBS=$LIBS - LIBS="$4 $LIBS" - AC_LINK_IFELSE([AC_LANG_SOURCE([ - $5 - char $1(void); - int main(void) { - $1(); - return 0; - } - ])],[ - LIBS=$old_LIBS - $2 - ],[ - LIBS=$old_LIBS - $3 - ]) -]) - dnl ---------------------------------------------------------------------------- dnl Platform characteristics checks. dnl ---------------------------------------------------------------------------- @@ -2039,25 +1987,6 @@ AC_DEFUN([PHP_INSTALL_HEADERS], ]) ]) -dnl -dnl PHP_AP_EXTRACT_VERSION(/path/httpd) -dnl -dnl This macro is used to get a comparable version for Apache. -dnl -AC_DEFUN([PHP_AP_EXTRACT_VERSION], [m4_warn([obsolete], - [The macro 'PHP_AP_EXTRACT_VERSION' is obsolete. Use 'apxs -q HTTPD_VERSION']) -AS_IF([test -x "$1"], [ - ac_output=$($1 -v 2>&1 | grep version | $SED -e 's/Oracle-HTTP-//') - ac_IFS=$IFS -IFS="- /. -" - set $ac_output - IFS=$ac_IFS - - APACHE_VERSION=$(expr [$]4 \* 1000000 + [$]5 \* 1000 + [$]6) -]) -]) - dnl dnl PHP_CONFIG_NICE(filename) dnl From ecc602e3bb5878228cf6b85de790f3f097bbb0fd Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Mon, 23 Jun 2025 23:44:20 +0200 Subject: [PATCH 088/120] Remove non-existing INI directive detect_unicode (#18909) The detect_unicode was removed and zend.detect_unicode was added in PHP 5.4 (bbf3d43c1ee0ad53b03c3821cd630f0746d5e954). --- ext/phar/tests/zip/notphar.phpt | 1 - pear/Makefile.frag | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/ext/phar/tests/zip/notphar.phpt b/ext/phar/tests/zip/notphar.phpt index 10d4d7d8be311..ab4f80e430bba 100644 --- a/ext/phar/tests/zip/notphar.phpt +++ b/ext/phar/tests/zip/notphar.phpt @@ -4,7 +4,6 @@ Phar: a non-executable zip with no stub named .phar.zip phar --INI-- phar.readonly=1 -detect_unicode=0 zend.multibyte=0 --FILE-- /dev/null` FETCH = `which fetch 2>/dev/null` From d6fc7430b95af036386d9910a763708725a1b9bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Tue, 24 Jun 2025 08:50:47 +0200 Subject: [PATCH 089/120] zend_string: Simplify logic in `zend_interned_strings_init()` (#18922) No need to manually init a `zend_string` to then intern it, we can directly intern it while initializing, bypassing some of the safety checks that are redundant in this case. --- Zend/zend_string.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/Zend/zend_string.c b/Zend/zend_string.c index dfe059359aa53..c864a847af39f 100644 --- a/Zend/zend_string.c +++ b/Zend/zend_string.c @@ -86,8 +86,6 @@ static zend_always_inline void zend_init_interned_strings_ht(HashTable *interned ZEND_API void zend_interned_strings_init(void) { char s[2]; - unsigned int i; - zend_string *str; interned_string_request_handler = zend_new_interned_string_request; interned_string_init_request_handler = zend_string_init_interned_request; @@ -103,15 +101,13 @@ ZEND_API void zend_interned_strings_init(void) zend_string_init_existing_interned = zend_string_init_existing_interned_permanent; /* interned empty string */ - str = zend_string_alloc(sizeof("")-1, 1); - ZSTR_VAL(str)[0] = '\000'; - zend_empty_string = zend_new_interned_string_permanent(str); + zend_empty_string = zend_string_init_interned_permanent("", 0, true); GC_ADD_FLAGS(zend_empty_string, IS_STR_VALID_UTF8); s[1] = 0; - for (i = 0; i < 256; i++) { + for (size_t i = 0; i < 256; i++) { s[0] = i; - zend_one_char_string[i] = zend_new_interned_string_permanent(zend_string_init(s, 1, 1)); + zend_one_char_string[i] = zend_string_init_interned_permanent(s, 1, true); if (i < 0x80) { GC_ADD_FLAGS(zend_one_char_string[i], IS_STR_VALID_UTF8); } @@ -119,9 +115,8 @@ ZEND_API void zend_interned_strings_init(void) /* known strings */ zend_known_strings = pemalloc(sizeof(zend_string*) * ((sizeof(known_strings) / sizeof(known_strings[0]) - 1)), 1); - for (i = 0; i < (sizeof(known_strings) / sizeof(known_strings[0])) - 1; i++) { - str = zend_string_init(known_strings[i], strlen(known_strings[i]), 1); - zend_known_strings[i] = zend_new_interned_string_permanent(str); + for (size_t i = 0; i < (sizeof(known_strings) / sizeof(known_strings[0])) - 1; i++) { + zend_known_strings[i] = zend_string_init_interned_permanent(known_strings[i], strlen(known_strings[i]), true); GC_ADD_FLAGS(zend_known_strings[i], IS_STR_VALID_UTF8); } } From c5e7490963a1c53ec12c09264d0dbe1654ec8cfc Mon Sep 17 00:00:00 2001 From: Jesse Hathaway Date: Tue, 3 Jun 2025 10:03:10 -0500 Subject: [PATCH 090/120] mail: fix exit code handling of sendmail cmd Prior to this commit the return code of the pclose function was assumed to be the exit code of the process. However, the returned value as specified in wait(2) is a bit packed integer and must be interpreted with the provided macros. This has no effect in success cases as the integer is still zero, but in failure cases the wrong value is used, since the 8 least significant bits contain the status code. After this commit we use the macros to obtain the status code, which fixes the EX_TEMPFAIL conditional. For WIN32 the TSRM popen_ex and pclose function are used. The return value of TSRM's pclose is not bit packed so we only check if the return value is non-zero, which should solve, #43327, https://bugs.php.net/bug.php?id=43327 --- ext/standard/mail.c | 32 +++++++++++++++++--- ext/standard/tests/mail/mail_variation3.phpt | 22 ++++++++++++++ ext/standard/tests/mail/mail_variation4.phpt | 22 ++++++++++++++ ext/standard/tests/mail/mail_variation5.phpt | 22 ++++++++++++++ 4 files changed, 93 insertions(+), 5 deletions(-) create mode 100644 ext/standard/tests/mail/mail_variation3.phpt create mode 100644 ext/standard/tests/mail/mail_variation4.phpt create mode 100644 ext/standard/tests/mail/mail_variation5.phpt diff --git a/ext/standard/mail.c b/ext/standard/mail.c index 0243ec897a05e..ff0ec13500946 100644 --- a/ext/standard/mail.c +++ b/ext/standard/mail.c @@ -25,6 +25,10 @@ #include "ext/date/php_date.h" #include "zend_smart_str.h" +#ifdef HAVE_SYS_WAIT_H +#include +#endif + #ifdef HAVE_SYSEXITS_H # include #endif @@ -562,6 +566,7 @@ PHPAPI bool php_mail(const char *to, const char *subject, const char *message, c } if (sendmail) { + int ret; #ifndef PHP_WIN32 if (EACCES == errno) { php_error_docref(NULL, E_WARNING, "Permission denied: unable to execute shell to run mail delivery binary '%s'", sendmail_path); @@ -582,24 +587,41 @@ PHPAPI bool php_mail(const char *to, const char *subject, const char *message, c fprintf(sendmail, "%s%s", hdr, line_sep); } fprintf(sendmail, "%s%s%s", line_sep, message, line_sep); - int ret = pclose(sendmail); +#ifdef PHP_WIN32 + ret = pclose(sendmail); #if PHP_SIGCHILD if (sig_handler) { signal(SIGCHLD, sig_handler); } #endif - -#ifdef PHP_WIN32 - if (ret == -1) #else + int wstatus = pclose(sendmail); +#if PHP_SIGCHILD + if (sig_handler) { + signal(SIGCHLD, sig_handler); + } +#endif + /* Determine the wait(2) exit status */ + if (wstatus == -1) { + MAIL_RET(false); + } else if (WIFSIGNALED(wstatus)) { + MAIL_RET(false); + } else { + if (WIFEXITED(wstatus)) { + ret = WEXITSTATUS(wstatus); + } else { + MAIL_RET(false); + } + } +#endif + #if defined(EX_TEMPFAIL) if ((ret != EX_OK)&&(ret != EX_TEMPFAIL)) #elif defined(EX_OK) if (ret != EX_OK) #else if (ret != 0) -#endif #endif { MAIL_RET(false); diff --git a/ext/standard/tests/mail/mail_variation3.phpt b/ext/standard/tests/mail/mail_variation3.phpt new file mode 100644 index 0000000000000..03908242d88e9 --- /dev/null +++ b/ext/standard/tests/mail/mail_variation3.phpt @@ -0,0 +1,22 @@ +--TEST-- +Test mail() function : variation sendmail temp fail +--INI-- +sendmail_path=exit 75 +--SKIPIF-- + +--FILE-- + +--EXPECT-- +*** Testing mail() : variation *** +bool(true) diff --git a/ext/standard/tests/mail/mail_variation4.phpt b/ext/standard/tests/mail/mail_variation4.phpt new file mode 100644 index 0000000000000..8b3b301ac0be4 --- /dev/null +++ b/ext/standard/tests/mail/mail_variation4.phpt @@ -0,0 +1,22 @@ +--TEST-- +Test mail() function : variation sigterm +--INI-- +sendmail_path="kill \$\$" +--SKIPIF-- + +--FILE-- + +--EXPECT-- +*** Testing mail() : variation *** +bool(false) diff --git a/ext/standard/tests/mail/mail_variation5.phpt b/ext/standard/tests/mail/mail_variation5.phpt new file mode 100644 index 0000000000000..a6c25feba5e1d --- /dev/null +++ b/ext/standard/tests/mail/mail_variation5.phpt @@ -0,0 +1,22 @@ +--TEST-- +Test mail() function : variation non-zero exit +--INI-- +sendmail_path="exit 123" +--SKIPIF-- + +--FILE-- + +--EXPECT-- +*** Testing mail() : variation *** +bool(false) From 6a7561203de89031147c0de6fe09cad905f82984 Mon Sep 17 00:00:00 2001 From: Jesse Hathaway Date: Tue, 3 Jun 2025 10:03:10 -0500 Subject: [PATCH 091/120] mail: add logging on errors Prior to this commit the exit code of the sendmail command, called by the mail function was lost, since the mail function only returns true or false. Add additional logging to the mail function to capture the exit code when the sendmail command fails. --- ext/standard/mail.c | 4 ++++ ext/standard/tests/mail/gh10990.phpt | 3 ++- ext/standard/tests/mail/mail_basic5.phpt | 4 +++- ext/standard/tests/mail/mail_variation1.phpt | 4 +++- ext/standard/tests/mail/mail_variation4.phpt | 4 +++- ext/standard/tests/mail/mail_variation5.phpt | 4 +++- 6 files changed, 18 insertions(+), 5 deletions(-) diff --git a/ext/standard/mail.c b/ext/standard/mail.c index ff0ec13500946..41e2a02078e78 100644 --- a/ext/standard/mail.c +++ b/ext/standard/mail.c @@ -604,13 +604,16 @@ PHPAPI bool php_mail(const char *to, const char *subject, const char *message, c #endif /* Determine the wait(2) exit status */ if (wstatus == -1) { + php_error_docref(NULL, E_WARNING, "Sendmail pclose failed %d (%s)", errno, strerror(errno)); MAIL_RET(false); } else if (WIFSIGNALED(wstatus)) { + php_error_docref(NULL, E_WARNING, "Sendmail killed by signal %d (%s)", WTERMSIG(wstatus), strsignal(WTERMSIG(wstatus))); MAIL_RET(false); } else { if (WIFEXITED(wstatus)) { ret = WEXITSTATUS(wstatus); } else { + php_error_docref(NULL, E_WARNING, "Sendmail did not exit"); MAIL_RET(false); } } @@ -624,6 +627,7 @@ PHPAPI bool php_mail(const char *to, const char *subject, const char *message, c if (ret != 0) #endif { + php_error_docref(NULL, E_WARNING, "Sendmail exited with non-zero exit code %d", ret); MAIL_RET(false); } else { MAIL_RET(true); diff --git a/ext/standard/tests/mail/gh10990.phpt b/ext/standard/tests/mail/gh10990.phpt index 4f74c17c22bda..ee28f30313858 100644 --- a/ext/standard/tests/mail/gh10990.phpt +++ b/ext/standard/tests/mail/gh10990.phpt @@ -13,5 +13,6 @@ $from = 'test@example.com'; $headers = ['From' => &$from]; var_dump(mail('test@example.com', 'Test', 'Test', $headers)); ?> ---EXPECT-- +--EXPECTF-- +Warning: mail(): Sendmail exited with non-zero exit code 127 in %sgh10990.php on line %d bool(false) diff --git a/ext/standard/tests/mail/mail_basic5.phpt b/ext/standard/tests/mail/mail_basic5.phpt index b427fbeb670a0..73be1e1eaa1ad 100644 --- a/ext/standard/tests/mail/mail_basic5.phpt +++ b/ext/standard/tests/mail/mail_basic5.phpt @@ -20,7 +20,9 @@ $message = 'A Message'; echo "-- failure --\n"; var_dump( mail($to, $subject, $message) ); ?> ---EXPECT-- +--EXPECTF-- *** Testing mail() : basic functionality *** -- failure -- + +Warning: mail(): Sendmail exited with non-zero exit code 1 in %smail_basic5.php on line %d bool(false) diff --git a/ext/standard/tests/mail/mail_variation1.phpt b/ext/standard/tests/mail/mail_variation1.phpt index 75adc62822358..16779bcf455ee 100644 --- a/ext/standard/tests/mail/mail_variation1.phpt +++ b/ext/standard/tests/mail/mail_variation1.phpt @@ -17,6 +17,8 @@ $subject = 'Test Subject'; $message = 'A Message'; var_dump( mail($to, $subject, $message) ); ?> ---EXPECT-- +--EXPECTF-- *** Testing mail() : variation *** + +Warning: mail(): Sendmail exited with non-zero exit code 127 in %smail_variation1.php on line %d bool(false) diff --git a/ext/standard/tests/mail/mail_variation4.phpt b/ext/standard/tests/mail/mail_variation4.phpt index 8b3b301ac0be4..c761e3bdbd199 100644 --- a/ext/standard/tests/mail/mail_variation4.phpt +++ b/ext/standard/tests/mail/mail_variation4.phpt @@ -17,6 +17,8 @@ $subject = 'Test Subject'; $message = 'A Message'; var_dump(mail($to, $subject, $message)); ?> ---EXPECT-- +--EXPECTF-- *** Testing mail() : variation *** + +Warning: mail(): Sendmail killed by signal %d (%s) in %smail_variation4.php on line %d bool(false) diff --git a/ext/standard/tests/mail/mail_variation5.phpt b/ext/standard/tests/mail/mail_variation5.phpt index a6c25feba5e1d..9e430f40c5dfc 100644 --- a/ext/standard/tests/mail/mail_variation5.phpt +++ b/ext/standard/tests/mail/mail_variation5.phpt @@ -17,6 +17,8 @@ $subject = 'Test Subject'; $message = 'A Message'; var_dump(mail($to, $subject, $message)); ?> ---EXPECT-- +--EXPECTF-- *** Testing mail() : variation *** + +Warning: mail(): Sendmail exited with non-zero exit code 123 in %smail_variation5.php on line %d bool(false) From fc04966c364be62a818e0c7e495ba0bc2d5bfc97 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Tue, 24 Jun 2025 12:30:35 +0200 Subject: [PATCH 092/120] Add NEWS and UPGRADING for sendmail error handling changes --- NEWS | 2 ++ UPGRADING | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/NEWS b/NEWS index 65fb408ddaacf..b3ac9d6b405bf 100644 --- a/NEWS +++ b/NEWS @@ -261,6 +261,8 @@ PHP NEWS . Added array_first() and array_last(). (nielsdos) . Fixed bug GH-18823 (setlocale's 2nd and 3rd argument ignores strict_types). (nielsdos) + . Fixed exit code handling of sendmail cmd and added warnings. + (Jesse Hathaway) - Streams: . Fixed bug GH-16889 (stream_select() timeout useless for pipes on Windows). diff --git a/UPGRADING b/UPGRADING index 4c6e40cfdebaf..1462be95a43fc 100644 --- a/UPGRADING +++ b/UPGRADING @@ -217,6 +217,12 @@ PHP 8.5 UPGRADE NOTES Sqlite3Stmt::EXPLAIN_MODE_EXPLAIN and Sqlite3Stmt::EXPLAIN_MODE_EXPLAIN_QUERY_PLAN. +- Standard: + . mail() now returns the actual sendmail error and detects if the sendmail + process was terminated unexpectedly. In such cases, a warning is emitted + and the function returns false. Previously, these errors were silently + ignored. This change affects only the sendmail transport. + - XSL: . The $namespace argument of XSLTProcessor::getParameter(), XSLTProcessor::setParameter() and XSLTProcessor::removeParameter() From 537ae4f990d35ff6d54d7af31b1d2cfa064c021c Mon Sep 17 00:00:00 2001 From: Saki Takamachi <34942839+SakiTakamachi@users.noreply.github.com> Date: Tue, 24 Jun 2025 20:40:09 +0900 Subject: [PATCH 093/120] removed `ZEND_IS_XDIGIT()` (#18926) --- UPGRADING.INTERNALS | 2 ++ Zend/zend_operators.h | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index f421242dba6c6..acc9612b72e30 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -43,6 +43,8 @@ PHP 8.5 INTERNALS UPGRADE NOTES . Added the zend_update_exception_properties() function for instantiating Exception child classes. It updates the $message, $code, and $previous properties. + . ZEND_IS_XDIGIT() macro was removed because it was unused and its name + did not match its actual behavior. ======================== 2. Build system changes diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h index db86345b69968..a7537d1b3ef33 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -156,7 +156,6 @@ static zend_always_inline zend_long zend_dval_to_lval_safe(double d) } #define ZEND_IS_DIGIT(c) ((c) >= '0' && (c) <= '9') -#define ZEND_IS_XDIGIT(c) (((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f')) static zend_always_inline uint8_t is_numeric_string_ex(const char *str, size_t length, zend_long *lval, double *dval, bool allow_errors, int *oflow_info, bool *trailing_data) From 39cf27689bc13cf94c047675901c3fb43ba44879 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Tue, 24 Jun 2025 15:22:25 +0200 Subject: [PATCH 094/120] php_gdb: Print some numeric fields as hexadecimal (#18925) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * php_gdb: Print `zend_string*`’s `h` field as hexadecimal A decimal representation of a hash value is not particularly meaningful and makes it harder to compare hash values. * php_gdb: Print `HashTable*`’s `nTableMask` field as hexadecimal --- main/debug_gdb_scripts.c | 11 ++++++----- scripts/gdb/php_gdb.py | 11 ++++++----- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/main/debug_gdb_scripts.c b/main/debug_gdb_scripts.c index 3806f6aab60dd..e3c522bc04843 100644 --- a/main/debug_gdb_scripts.c +++ b/main/debug_gdb_scripts.c @@ -719,6 +719,8 @@ asm( ".ascii \" for field in self.val.type.fields():\\n\"\n" ".ascii \" if field.name == 'val':\\n\"\n" ".ascii \" yield ('val', format_zstr(self.val))\\n\"\n" + ".ascii \" elif field.name == 'h':\\n\"\n" + ".ascii \" yield (field.name, \\\"0x%x\\\" % self.val[field.name])\\n\"\n" ".ascii \" else:\\n\"\n" ".ascii \" yield (field.name, format_nested(self.val[field.name]))\\n\"\n" ".ascii \"\\n\"\n" @@ -751,12 +753,11 @@ asm( ".ascii \" def children(self):\\n\"\n" ".ascii \" for field in self.val.type.fields():\\n\"\n" ".ascii \" if field.name is None:\\n\"\n" - ".ascii \" name = ''\\n\"\n" - ".ascii \" val = self.val[field]\\n\"\n" + ".ascii \" yield ('', format_nested(self.val[field]))\\n\"\n" + ".ascii \" elif field.name == 'nTableMask':\\n\"\n" + ".ascii \" yield (field.name, \\\"0x%x\\\" % self.val[field.name])\\n\"\n" ".ascii \" else:\\n\"\n" - ".ascii \" name = field.name\\n\"\n" - ".ascii \" val = self.val[field.name]\\n\"\n" - ".ascii \" yield (name, format_nested(val))\\n\"\n" + ".ascii \" yield (field.name, format_nested(self.val[field.name]))\\n\"\n" ".ascii \"\\n\"\n" ".ascii \"pp_set.add_printer('zend_array', '^_zend_array$', ZendArrayPrettyPrinter)\\n\"\n" ".ascii \"\\n\"\n" diff --git a/scripts/gdb/php_gdb.py b/scripts/gdb/php_gdb.py index ae8396a2ac0c2..1c5da0154aecd 100644 --- a/scripts/gdb/php_gdb.py +++ b/scripts/gdb/php_gdb.py @@ -49,6 +49,8 @@ def children(self): for field in self.val.type.fields(): if field.name == 'val': yield ('val', format_zstr(self.val)) + elif field.name == 'h': + yield (field.name, "0x%x" % self.val[field.name]) else: yield (field.name, format_nested(self.val[field.name])) @@ -81,12 +83,11 @@ def to_string(self): def children(self): for field in self.val.type.fields(): if field.name is None: - name = '' - val = self.val[field] + yield ('', format_nested(self.val[field])) + elif field.name == 'nTableMask': + yield (field.name, "0x%x" % self.val[field.name]) else: - name = field.name - val = self.val[field.name] - yield (name, format_nested(val)) + yield (field.name, format_nested(self.val[field.name])) pp_set.add_printer('zend_array', '^_zend_array$', ZendArrayPrettyPrinter) From 5ed8b2be5533fbd4db95d9724d268eb9c9741f14 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Tue, 24 Jun 2025 19:06:47 +0200 Subject: [PATCH 095/120] Fix GH-18897: printf: empty precision is interpreted as precision 6, not as precision 0 (#18912) Like in other languages, and especially C where printf originates from, a missing precision should be treated as a 0 precision. Because the ADJ_PRECISION flag was not set, the double formatting code resetted the precision to the default float precision of 6. --- NEWS | 2 ++ UPGRADING | 5 +++++ ext/standard/formatted_print.c | 1 + ext/standard/tests/strings/gh18897.phpt | 10 ++++++++++ 4 files changed, 18 insertions(+) create mode 100644 ext/standard/tests/strings/gh18897.phpt diff --git a/NEWS b/NEWS index b3ac9d6b405bf..8f129d715d873 100644 --- a/NEWS +++ b/NEWS @@ -263,6 +263,8 @@ PHP NEWS (nielsdos) . Fixed exit code handling of sendmail cmd and added warnings. (Jesse Hathaway) + . Fixed bug GH-18897 (printf: empty precision is interpreted as precision 6, + not as precision 0). (nielsdos) - Streams: . Fixed bug GH-16889 (stream_select() timeout useless for pipes on Windows). diff --git a/UPGRADING b/UPGRADING index 1462be95a43fc..4dca8f2b2c213 100644 --- a/UPGRADING +++ b/UPGRADING @@ -116,6 +116,11 @@ PHP 8.5 UPGRADE NOTES . SplFileObject::fwrite's parameter $length is now nullable. The default value changed from 0 to null. +- Standard: + . Using a printf-family function with a formatter that did not specify the + precision previously incorrectly reset the precision instead of treating + it as a precision of 0. See GH-18897. + ======================================== 2. New Features ======================================== diff --git a/ext/standard/formatted_print.c b/ext/standard/formatted_print.c index 9a74ae6c877f3..b2c287c02900c 100644 --- a/ext/standard/formatted_print.c +++ b/ext/standard/formatted_print.c @@ -591,6 +591,7 @@ php_formatted_print(char *format, size_t format_len, zval *args, int argc, int n expprec = 1; } else { precision = 0; + adjusting |= ADJ_PRECISION; } } else { precision = 0; diff --git a/ext/standard/tests/strings/gh18897.phpt b/ext/standard/tests/strings/gh18897.phpt new file mode 100644 index 0000000000000..328ea7161e023 --- /dev/null +++ b/ext/standard/tests/strings/gh18897.phpt @@ -0,0 +1,10 @@ +--TEST-- +GH-18897 (printf: empty precision is interpreted as precision 6, not as precision 0) +--FILE-- + +--EXPECT-- +3 +3 From ca49a7bec2a0a8d77bfa4b6d375ca0ffa4edc5ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Tue, 24 Jun 2025 20:14:40 +0200 Subject: [PATCH 096/120] RFC: Turn `clone()` into a function (#18919) RFC: https://wiki.php.net/rfc/clone_with_v2 Co-authored-by: Volker Dusch --- NEWS | 1 + UPGRADING | 2 + Zend/Optimizer/zend_func_infos.h | 1 + Zend/tests/assert/expect_015.phpt | 2 +- Zend/tests/clone/ast.phpt | 31 +++++++++++++++ Zend/tests/clone/bug36071.phpt | 14 +++---- Zend/tests/clone/bug42817.phpt | 14 +++---- Zend/tests/clone/bug42818.phpt | 13 +++--- Zend/tests/clone/clone_001.phpt | 13 +++--- Zend/tests/clone/clone_003.phpt | 12 +++--- Zend/tests/clone/clone_005.phpt | 55 ++++++++++++++++++++++++++ Zend/tests/magic_methods/bug73288.phpt | 1 + Zend/zend_API.c | 1 + Zend/zend_ast.c | 2 - Zend/zend_ast.h | 1 - Zend/zend_builtin_functions.c | 43 ++++++++++++++++++++ Zend/zend_builtin_functions.stub.php | 3 ++ Zend/zend_builtin_functions_arginfo.h | 8 +++- Zend/zend_compile.c | 30 +++++++------- Zend/zend_language_parser.y | 11 +++++- Zend/zend_string.h | 1 + Zend/zend_vm_def.h | 4 +- Zend/zend_vm_execute.h | 16 ++++++-- build/gen_stub.php | 4 ++ ext/opcache/tests/func_info.phpt | 2 +- 25 files changed, 227 insertions(+), 58 deletions(-) create mode 100644 Zend/tests/clone/ast.phpt create mode 100644 Zend/tests/clone/clone_005.phpt diff --git a/NEWS b/NEWS index 8f129d715d873..930dbec180221 100644 --- a/NEWS +++ b/NEWS @@ -59,6 +59,7 @@ PHP NEWS . Added support for `final` with constructor property promotion. (DanielEScherzer) . Do not use RTLD_DEEPBIND if dlmopen is available. (Daniil Gentili) + . Make `clone() a function. (timwolla, edorian) - Curl: . Added curl_multi_get_handles(). (timwolla) diff --git a/UPGRADING b/UPGRADING index 4dca8f2b2c213..98537007f65cd 100644 --- a/UPGRADING +++ b/UPGRADING @@ -374,6 +374,8 @@ PHP 8.5 UPGRADE NOTES . get_exception_handler() allows retrieving the current user-defined exception handler function. RFC: https://wiki.php.net/rfc/get-error-exception-handler + . The clone language construct is now a function. + RFC: https://wiki.php.net/rfc/clone_with_v2 - Curl: . curl_multi_get_handles() allows retrieving all CurlHandles current diff --git a/Zend/Optimizer/zend_func_infos.h b/Zend/Optimizer/zend_func_infos.h index 3655e5fd21c35..c36b7490de62c 100644 --- a/Zend/Optimizer/zend_func_infos.h +++ b/Zend/Optimizer/zend_func_infos.h @@ -1,6 +1,7 @@ /* This is a generated file, edit the .stub.php files instead. */ static const func_info_t func_infos[] = { + F1("clone", MAY_BE_OBJECT), F1("zend_version", MAY_BE_STRING), FN("func_get_args", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_ANY), F1("get_class_vars", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF), diff --git a/Zend/tests/assert/expect_015.phpt b/Zend/tests/assert/expect_015.phpt index 695c4c166a83c..9f8e9b77003bc 100644 --- a/Zend/tests/assert/expect_015.phpt +++ b/Zend/tests/assert/expect_015.phpt @@ -183,7 +183,7 @@ assert(0 && ($a = function () { $x = $a ?? $b; [$a, $b, $c] = [1, 2 => 'x', 'z' => 'c']; @foo(); - $y = clone $x; + $y = \clone($x); yield 1 => 2; yield from $x; })) diff --git a/Zend/tests/clone/ast.phpt b/Zend/tests/clone/ast.phpt new file mode 100644 index 0000000000000..89a1a0a481000 --- /dev/null +++ b/Zend/tests/clone/ast.phpt @@ -0,0 +1,31 @@ +--TEST-- +Ast Printing +--FILE-- +getMessage(), PHP_EOL; +} + +try { + assert(false && $y = clone($x)); +} catch (Error $e) { + echo $e->getMessage(), PHP_EOL; +} + +try { + assert(false && $y = clone(...)); +} catch (Error $e) { + echo $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +assert(false && ($y = \clone($x))) +assert(false && ($y = \clone($x))) +assert(false && ($y = \clone(...))) diff --git a/Zend/tests/clone/bug36071.phpt b/Zend/tests/clone/bug36071.phpt index 945118fef3754..e1a4baa7226ee 100644 --- a/Zend/tests/clone/bug36071.phpt +++ b/Zend/tests/clone/bug36071.phpt @@ -4,11 +4,11 @@ Bug #36071 (Engine Crash related with 'clone') error_reporting=4095 --FILE-- b = 0; +try { + $a = clone 0; +} catch (Error $e) { + echo $e::class, ": ", $e->getMessage(), PHP_EOL; +} ?> ---EXPECTF-- -Fatal error: Uncaught Error: __clone method called on non-object in %sbug36071.php:2 -Stack trace: -#0 {main} - thrown in %sbug36071.php on line 2 +--EXPECT-- +TypeError: clone(): Argument #1 ($object) must be of type object, int given diff --git a/Zend/tests/clone/bug42817.phpt b/Zend/tests/clone/bug42817.phpt index a681d861d0c8f..b5f53222d7ee5 100644 --- a/Zend/tests/clone/bug42817.phpt +++ b/Zend/tests/clone/bug42817.phpt @@ -2,11 +2,11 @@ Bug #42817 (clone() on a non-object does not result in a fatal error) --FILE-- b, $c); +try { + $a = clone(null); +} catch (Error $e) { + echo $e::class, ": ", $e->getMessage(), PHP_EOL; +} ?> ---EXPECTF-- -Fatal error: Uncaught Error: __clone method called on non-object in %sbug42817.php:2 -Stack trace: -#0 {main} - thrown in %sbug42817.php on line 2 +--EXPECT-- +TypeError: clone(): Argument #1 ($object) must be of type object, null given diff --git a/Zend/tests/clone/bug42818.phpt b/Zend/tests/clone/bug42818.phpt index b37ce13fd174a..08ba05fcfaa22 100644 --- a/Zend/tests/clone/bug42818.phpt +++ b/Zend/tests/clone/bug42818.phpt @@ -2,10 +2,11 @@ Bug #42818 ($foo = clone(array()); leaks memory) --FILE-- getMessage(), PHP_EOL; +} ?> ---EXPECTF-- -Fatal error: Uncaught Error: __clone method called on non-object in %sbug42818.php:2 -Stack trace: -#0 {main} - thrown in %sbug42818.php on line 2 +--EXPECT-- +TypeError: clone(): Argument #1 ($object) must be of type object, array given diff --git a/Zend/tests/clone/clone_001.phpt b/Zend/tests/clone/clone_001.phpt index 87024c3cd5614..91fa6f551176d 100644 --- a/Zend/tests/clone/clone_001.phpt +++ b/Zend/tests/clone/clone_001.phpt @@ -3,11 +3,12 @@ Using clone statement on non-object --FILE-- getMessage(), PHP_EOL; +} ?> ---EXPECTF-- -Fatal error: Uncaught Error: __clone method called on non-object in %s:%d -Stack trace: -#0 {main} - thrown in %s on line %d +--EXPECT-- +TypeError: clone(): Argument #1 ($object) must be of type object, array given diff --git a/Zend/tests/clone/clone_003.phpt b/Zend/tests/clone/clone_003.phpt index f163616a876dc..b8bb2833dc257 100644 --- a/Zend/tests/clone/clone_003.phpt +++ b/Zend/tests/clone/clone_003.phpt @@ -3,13 +3,13 @@ Using clone statement on undefined variable --FILE-- getMessage(), PHP_EOL; +} ?> --EXPECTF-- Warning: Undefined variable $b in %s on line %d - -Fatal error: Uncaught Error: __clone method called on non-object in %s:%d -Stack trace: -#0 {main} - thrown in %s on line %d +TypeError: clone(): Argument #1 ($object) must be of type object, null given diff --git a/Zend/tests/clone/clone_005.phpt b/Zend/tests/clone/clone_005.phpt new file mode 100644 index 0000000000000..e0366cae67cb5 --- /dev/null +++ b/Zend/tests/clone/clone_005.phpt @@ -0,0 +1,55 @@ +--TEST-- +Clone as a function. +--FILE-- +clone_me()[0]; + +var_dump($f !== $clone); + +?> +--EXPECTF-- +object(stdClass)#%d (0) { +} +array(3) { + [0]=> + object(stdClass)#%d (0) { + } + [1]=> + object(stdClass)#%d (0) { + } + [2]=> + object(stdClass)#%d (0) { + } +} +array(3) { + [0]=> + object(stdClass)#%d (0) { + } + [1]=> + object(stdClass)#%d (0) { + } + [2]=> + object(stdClass)#%d (0) { + } +} +bool(true) diff --git a/Zend/tests/magic_methods/bug73288.phpt b/Zend/tests/magic_methods/bug73288.phpt index 52e8eedeaf013..5e1334cacd07c 100644 --- a/Zend/tests/magic_methods/bug73288.phpt +++ b/Zend/tests/magic_methods/bug73288.phpt @@ -23,6 +23,7 @@ function test_clone() { $b = clone $c->x; } +// No catch, because we want to test Exception::__toString(). test_clone(); ?> --EXPECTF-- diff --git a/Zend/zend_API.c b/Zend/zend_API.c index d29fe8ae8e3c3..df8b4252c42ad 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -3648,6 +3648,7 @@ static void zend_disable_function(const char *function_name, size_t function_nam if (UNEXPECTED( (function_name_length == strlen("exit") && !memcmp(function_name, "exit", strlen("exit"))) || (function_name_length == strlen("die") && !memcmp(function_name, "die", strlen("die"))) + || (function_name_length == strlen("clone") && !memcmp(function_name, "clone", strlen("clone"))) )) { zend_error(E_WARNING, "Cannot disable function %s()", function_name); return; diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index cdc86faa95aa3..728695bd9e930 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -2345,8 +2345,6 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio } smart_str_appendc(str, '`'); break; - case ZEND_AST_CLONE: - PREFIX_OP("clone ", 270, 271); case ZEND_AST_PRINT: PREFIX_OP("print ", 60, 61); case ZEND_AST_INCLUDE_OR_EVAL: diff --git a/Zend/zend_ast.h b/Zend/zend_ast.h index c82ca66c9f573..08400cff5dd8e 100644 --- a/Zend/zend_ast.h +++ b/Zend/zend_ast.h @@ -89,7 +89,6 @@ enum _zend_ast_kind { ZEND_AST_ISSET, ZEND_AST_SILENCE, ZEND_AST_SHELL_EXEC, - ZEND_AST_CLONE, ZEND_AST_PRINT, ZEND_AST_INCLUDE_OR_EVAL, ZEND_AST_UNARY_OP, diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 7a07ceadce2e2..48e5c70897294 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -69,6 +69,49 @@ zend_result zend_startup_builtin_functions(void) /* {{{ */ } /* }}} */ +ZEND_FUNCTION(clone) +{ + zend_object *zobj; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_OBJ(zobj) + ZEND_PARSE_PARAMETERS_END(); + + /* clone() also exists as the ZEND_CLONE OPcode and both implementations must be kept in sync. */ + + zend_class_entry *scope = zend_get_executed_scope(); + + zend_class_entry *ce = zobj->ce; + zend_function *clone = ce->clone; + + if (UNEXPECTED(zobj->handlers->clone_obj == NULL)) { + zend_throw_error(NULL, "Trying to clone an uncloneable object of class %s", ZSTR_VAL(ce->name)); + RETURN_THROWS(); + } + + if (clone && !(clone->common.fn_flags & ZEND_ACC_PUBLIC)) { + if (clone->common.scope != scope) { + if (UNEXPECTED(clone->common.fn_flags & ZEND_ACC_PRIVATE) + || UNEXPECTED(!zend_check_protected(zend_get_function_root_class(clone), scope))) { + zend_throw_error(NULL, "Call to %s %s::__clone() from %s%s", + zend_visibility_string(clone->common.fn_flags), ZSTR_VAL(clone->common.scope->name), + scope ? "scope " : "global scope", + scope ? ZSTR_VAL(scope->name) : "" + ); + RETURN_THROWS(); + } + } + } + + zend_object *cloned; + cloned = zobj->handlers->clone_obj(zobj); + + ZEND_ASSERT(cloned || EG(exception)); + if (EXPECTED(cloned)) { + RETURN_OBJ(cloned); + } +} + ZEND_FUNCTION(exit) { zend_string *str = NULL; diff --git a/Zend/zend_builtin_functions.stub.php b/Zend/zend_builtin_functions.stub.php index 7f316835aea6b..256c405c71c28 100644 --- a/Zend/zend_builtin_functions.stub.php +++ b/Zend/zend_builtin_functions.stub.php @@ -7,6 +7,9 @@ class stdClass { } +/** @refcount 1 */ +function _clone(object $object): object {} + function exit(string|int $status = 0): never {} /** @alias exit */ diff --git a/Zend/zend_builtin_functions_arginfo.h b/Zend/zend_builtin_functions_arginfo.h index 9498b8292f892..1c595ecd5777c 100644 --- a/Zend/zend_builtin_functions_arginfo.h +++ b/Zend/zend_builtin_functions_arginfo.h @@ -1,5 +1,9 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: a24761186f1ddf758e648b0a764826537cbd33b9 */ + * Stub hash: 12327caa3fe940ccef68ed99f9278982dc0173a5 */ + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_clone, 0, 1, IS_OBJECT, 0) + ZEND_ARG_TYPE_INFO(0, object, IS_OBJECT, 0) +ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_exit, 0, 0, IS_NEVER, 0) ZEND_ARG_TYPE_MASK(0, status, MAY_BE_STRING|MAY_BE_LONG, "0") @@ -243,6 +247,7 @@ static const zend_frameless_function_info frameless_function_infos_class_exists[ { 0 }, }; +ZEND_FUNCTION(clone); ZEND_FUNCTION(exit); ZEND_FUNCTION(zend_version); ZEND_FUNCTION(func_num_args); @@ -306,6 +311,7 @@ ZEND_FUNCTION(gc_disable); ZEND_FUNCTION(gc_status); static const zend_function_entry ext_functions[] = { + ZEND_FE(clone, arginfo_clone) ZEND_FE(exit, arginfo_exit) ZEND_RAW_FENTRY("die", zif_exit, arginfo_die, 0, NULL, NULL) ZEND_FE(zend_version, arginfo_zend_version) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 28bea1a21d759..f3f6d1b75aec1 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -4930,6 +4930,20 @@ static zend_result zend_compile_func_sprintf(znode *result, zend_ast_list *args) return SUCCESS; } +static zend_result zend_compile_func_clone(znode *result, zend_ast_list *args) +{ + znode arg_node; + + if (args->children != 1) { + return FAILURE; + } + + zend_compile_expr(&arg_node, args->child[0]); + zend_emit_op_tmp(result, ZEND_CLONE, &arg_node, NULL); + + return SUCCESS; +} + static zend_result zend_try_compile_special_func_ex(znode *result, zend_string *lcname, zend_ast_list *args, zend_function *fbc, uint32_t type) /* {{{ */ { if (zend_string_equals_literal(lcname, "strlen")) { @@ -4998,6 +5012,8 @@ static zend_result zend_try_compile_special_func_ex(znode *result, zend_string * return zend_compile_func_array_key_exists(result, args); } else if (zend_string_equals_literal(lcname, "sprintf")) { return zend_compile_func_sprintf(result, args); + } else if (zend_string_equals(lcname, ZSTR_KNOWN(ZEND_STR_CLONE))) { + return zend_compile_func_clone(result, args); } else { return FAILURE; } @@ -5391,17 +5407,6 @@ static void zend_compile_new(znode *result, zend_ast *ast) /* {{{ */ } /* }}} */ -static void zend_compile_clone(znode *result, zend_ast *ast) /* {{{ */ -{ - zend_ast *obj_ast = ast->child[0]; - - znode obj_node; - zend_compile_expr(&obj_node, obj_ast); - - zend_emit_op_tmp(result, ZEND_CLONE, &obj_node, NULL); -} -/* }}} */ - static void zend_compile_global_var(zend_ast *ast) /* {{{ */ { zend_ast *var_ast = ast->child[0]; @@ -11717,9 +11722,6 @@ static void zend_compile_expr_inner(znode *result, zend_ast *ast) /* {{{ */ case ZEND_AST_NEW: zend_compile_new(result, ast); return; - case ZEND_AST_CLONE: - zend_compile_clone(result, ast); - return; case ZEND_AST_ASSIGN_OP: zend_compile_compound_assign(result, ast); return; diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 816b8126cbf25..016c6e5c9d098 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -1228,7 +1228,16 @@ expr: { $$ = zend_ast_create(ZEND_AST_ASSIGN, $1, $3); } | variable '=' ampersand variable { $$ = zend_ast_create(ZEND_AST_ASSIGN_REF, $1, $4); } - | T_CLONE expr { $$ = zend_ast_create(ZEND_AST_CLONE, $2); } + | T_CLONE '(' T_ELLIPSIS ')' { + zend_ast *name = zend_ast_create_zval_from_str(ZSTR_KNOWN(ZEND_STR_CLONE)); + name->attr = ZEND_NAME_FQ; + $$ = zend_ast_create(ZEND_AST_CALL, name, zend_ast_create_fcc()); + } + | T_CLONE expr { + zend_ast *name = zend_ast_create_zval_from_str(ZSTR_KNOWN(ZEND_STR_CLONE)); + name->attr = ZEND_NAME_FQ; + $$ = zend_ast_create(ZEND_AST_CALL, name, zend_ast_create_list(1, ZEND_AST_ARG_LIST, $2)); + } | variable T_PLUS_EQUAL expr { $$ = zend_ast_create_assign_op(ZEND_ADD, $1, $3); } | variable T_MINUS_EQUAL expr diff --git a/Zend/zend_string.h b/Zend/zend_string.h index 0b2a484016ec3..f60e4dec4e71f 100644 --- a/Zend/zend_string.h +++ b/Zend/zend_string.h @@ -575,6 +575,7 @@ EMPTY_SWITCH_DEFAULT_CASE() _(ZEND_STR_UNKNOWN, "unknown") \ _(ZEND_STR_UNKNOWN_CAPITALIZED, "Unknown") \ _(ZEND_STR_EXIT, "exit") \ + _(ZEND_STR_CLONE, "clone") \ _(ZEND_STR_EVAL, "eval") \ _(ZEND_STR_INCLUDE, "include") \ _(ZEND_STR_REQUIRE, "require") \ diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 617e114dd05db..be7bc8b37b7dd 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -6006,6 +6006,8 @@ ZEND_VM_COLD_CONST_HANDLER(110, ZEND_CLONE, CONST|TMPVAR|UNUSED|THIS|CV, ANY) SAVE_OPLINE(); obj = GET_OP1_OBJ_ZVAL_PTR_UNDEF(BP_VAR_R); + /* ZEND_CLONE also exists as the clone() function and both implementations must be kept in sync. */ + do { if (OP1_TYPE == IS_CONST || (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(obj) != IS_OBJECT))) { @@ -6022,7 +6024,7 @@ ZEND_VM_COLD_CONST_HANDLER(110, ZEND_CLONE, CONST|TMPVAR|UNUSED|THIS|CV, ANY) HANDLE_EXCEPTION(); } } - zend_throw_error(NULL, "__clone method called on non-object"); + zend_type_error("clone(): Argument #1 ($object) must be of type object, %s given", zend_zval_value_name(obj)); FREE_OP1(); HANDLE_EXCEPTION(); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 791e4b4e88437..3a13f4244d361 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -5180,6 +5180,8 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_CONST_ SAVE_OPLINE(); obj = RT_CONSTANT(opline, opline->op1); + /* ZEND_CLONE also exists as the clone() function and both implementations must be kept in sync. */ + do { if (IS_CONST == IS_CONST || (IS_CONST != IS_UNUSED && UNEXPECTED(Z_TYPE_P(obj) != IS_OBJECT))) { @@ -5196,7 +5198,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_CONST_ HANDLE_EXCEPTION(); } } - zend_throw_error(NULL, "__clone method called on non-object"); + zend_type_error("clone(): Argument #1 ($object) must be of type object, %s given", zend_zval_value_name(obj)); HANDLE_EXCEPTION(); } @@ -15428,6 +15430,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_TMPVAR_HANDLER(ZEND SAVE_OPLINE(); obj = _get_zval_ptr_var(opline->op1.var EXECUTE_DATA_CC); + /* ZEND_CLONE also exists as the clone() function and both implementations must be kept in sync. */ + do { if ((IS_TMP_VAR|IS_VAR) == IS_CONST || ((IS_TMP_VAR|IS_VAR) != IS_UNUSED && UNEXPECTED(Z_TYPE_P(obj) != IS_OBJECT))) { @@ -15444,7 +15448,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_TMPVAR_HANDLER(ZEND HANDLE_EXCEPTION(); } } - zend_throw_error(NULL, "__clone method called on non-object"); + zend_type_error("clone(): Argument #1 ($object) must be of type object, %s given", zend_zval_value_name(obj)); zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); HANDLE_EXCEPTION(); } @@ -33523,6 +33527,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_UNUSED_HANDLER(ZEND SAVE_OPLINE(); obj = &EX(This); + /* ZEND_CLONE also exists as the clone() function and both implementations must be kept in sync. */ + do { if (IS_UNUSED == IS_CONST || (IS_UNUSED != IS_UNUSED && UNEXPECTED(Z_TYPE_P(obj) != IS_OBJECT))) { @@ -33539,7 +33545,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_UNUSED_HANDLER(ZEND HANDLE_EXCEPTION(); } } - zend_throw_error(NULL, "__clone method called on non-object"); + zend_type_error("clone(): Argument #1 ($object) must be of type object, %s given", zend_zval_value_name(obj)); HANDLE_EXCEPTION(); } @@ -41042,6 +41048,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_CV_HANDLER(ZEND_OPC SAVE_OPLINE(); obj = EX_VAR(opline->op1.var); + /* ZEND_CLONE also exists as the clone() function and both implementations must be kept in sync. */ + do { if (IS_CV == IS_CONST || (IS_CV != IS_UNUSED && UNEXPECTED(Z_TYPE_P(obj) != IS_OBJECT))) { @@ -41058,7 +41066,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_CV_HANDLER(ZEND_OPC HANDLE_EXCEPTION(); } } - zend_throw_error(NULL, "__clone method called on non-object"); + zend_type_error("clone(): Argument #1 ($object) must be of type object, %s given", zend_zval_value_name(obj)); HANDLE_EXCEPTION(); } diff --git a/build/gen_stub.php b/build/gen_stub.php index fcef8213d0b55..d9327b67d042f 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -1009,6 +1009,9 @@ class FunctionName implements FunctionOrMethodName { private /* readonly */ Name $name; public function __construct(Name $name) { + if ($name->name === '_clone') { + $name = new Name('clone', $name->getAttributes()); + } $this->name = $name; } @@ -3049,6 +3052,7 @@ class PropertyInfo extends VariableLike "parent" => "ZEND_STR_PARENT", "username" => "ZEND_STR_USERNAME", "password" => "ZEND_STR_PASSWORD", + "clone" => "ZEND_STR_CLONE", ]; /** diff --git a/ext/opcache/tests/func_info.phpt b/ext/opcache/tests/func_info.phpt index 8b1f9ef436c4b..9596aa23199d2 100644 --- a/ext/opcache/tests/func_info.phpt +++ b/ext/opcache/tests/func_info.phpt @@ -16,7 +16,7 @@ foreach (get_defined_functions()["internal"] as $function) { if (in_array($function, ["extract", "compact", "get_defined_vars"])) { continue; } - $contents .= " \$result = {$function}();\n"; + $contents .= " \$result = \\{$function}();\n"; } $contents .= "}\n"; From aea3ade74fdaf5e764061858fdc1d3e5378b862b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladimir=20Vrzi=C4=87?= Date: Mon, 16 Sep 2024 17:59:40 +0200 Subject: [PATCH 097/120] ext/pcntl: Added rusage parameter to pcntl_waitid This functionality is not part of the POSIX interface. - On FreeBSD, the wait6 system call provides it - On Linux, the raw waitid system call provides it (glibc does not) close GH-15921 --- NEWS | 3 + UPGRADING | 2 + ext/pcntl/config.m4 | 5 ++ ext/pcntl/pcntl.c | 46 +++++++++++++-- ext/pcntl/pcntl.stub.php | 7 ++- ext/pcntl/pcntl_arginfo.h | 3 +- ext/pcntl/tests/pcntl_waitid.phpt | 10 ++-- ext/pcntl/tests/pcntl_waitid_rusage.phpt | 72 ++++++++++++++++++++++++ 8 files changed, 137 insertions(+), 11 deletions(-) create mode 100644 ext/pcntl/tests/pcntl_waitid_rusage.phpt diff --git a/NEWS b/NEWS index 930dbec180221..6ff942f86b2b7 100644 --- a/NEWS +++ b/NEWS @@ -134,6 +134,9 @@ PHP NEWS - Output: . Fixed calculation of aligned buffer size. (cmb) +- PCNTL: + . Extend pcntl_waitid with rusage parameter. (vrza) + - PCRE: . Upgraded to pre2lib from 10.44 to 10.45. (nielsdos) . Remove PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK from pcre compile options. diff --git a/UPGRADING b/UPGRADING index 98537007f65cd..4d968ef4daf80 100644 --- a/UPGRADING +++ b/UPGRADING @@ -289,6 +289,8 @@ PHP 8.5 UPGRADE NOTES - PCNTL: . pcntl_exec() now has a formal return type of false. + . pcntl_waitid() takes an additional resource_usage argument to + gather various platform specific metrics about the child process. - PDO_PGSQL: . PDO::pgsqlCopyFromArray also supports inputs as Iterable. diff --git a/ext/pcntl/config.m4 b/ext/pcntl/config.m4 index ce26a6efd2ead..3efa8a53cad1e 100644 --- a/ext/pcntl/config.m4 +++ b/ext/pcntl/config.m4 @@ -25,6 +25,8 @@ if test "$PHP_PCNTL" != "no"; then wait3 wait4 waitid + wait6 + syscall ])) AC_CHECK_FUNCS([WIFCONTINUED],, @@ -43,6 +45,9 @@ if test "$PHP_PCNTL" != "no"; then ]),,, [#include ]) + AC_CHECK_DECLS([SYS_waitid],,, + [#include ]) + dnl if unsupported, -1 means automatically ENOSYS in this context AC_CACHE_CHECK([if sched_getcpu is supported], [php_cv_func_sched_getcpu], [AC_RUN_IFELSE([AC_LANG_SOURCE([ diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c index 0481c0966c87a..1f061870ed453 100644 --- a/ext/pcntl/pcntl.c +++ b/ext/pcntl/pcntl.c @@ -125,7 +125,15 @@ typedef psetid_t cpu_set_t; #include #endif -#ifdef HAVE_PIDFD_OPEN +#if defined(__linux__) && defined(HAVE_DECL_SYS_WAITID) && HAVE_DECL_SYS_WAITID == 1 && defined(HAVE_SYSCALL) +#define HAVE_LINUX_RAW_SYSCALL_WAITID 1 +#endif + +#if defined(HAVE_LINUX_RAW_SYSCALL_WAITID) +#include +#endif + +#if defined(HAVE_PIDFD_OPEN) || defined(HAVE_LINUX_RAW_SYSCALL_WAITID) #include #endif @@ -401,19 +409,49 @@ PHP_FUNCTION(pcntl_waitid) bool id_is_null = 1; zval *user_siginfo = NULL; zend_long options = WEXITED; + zval *z_rusage = NULL; - ZEND_PARSE_PARAMETERS_START(0, 4) + siginfo_t siginfo; + int status; + + ZEND_PARSE_PARAMETERS_START(0, 5) Z_PARAM_OPTIONAL Z_PARAM_LONG(idtype) Z_PARAM_LONG_OR_NULL(id, id_is_null) Z_PARAM_ZVAL(user_siginfo) Z_PARAM_LONG(options) + Z_PARAM_ZVAL(z_rusage) ZEND_PARSE_PARAMETERS_END(); errno = 0; - siginfo_t siginfo; + memset(&siginfo, 0, sizeof(siginfo_t)); - int status = waitid((idtype_t) idtype, (id_t) id, &siginfo, (int) options); +#if defined(HAVE_WAIT6) || defined(HAVE_LINUX_RAW_SYSCALL_WAITID) + if (z_rusage) { + z_rusage = zend_try_array_init(z_rusage); + if (!z_rusage) { + RETURN_THROWS(); + } + struct rusage rusage; +# if defined(HAVE_WAIT6) /* FreeBSD */ + struct __wrusage wrusage; + memset(&wrusage, 0, sizeof(struct __wrusage)); + pid_t pid = wait6((idtype_t) idtype, (id_t) id, &status, (int) options, &wrusage, &siginfo); + status = pid > 0 ? 0 : pid; + memcpy(&rusage, &wrusage.wru_self, sizeof(struct rusage)); +# else /* Linux */ + memset(&rusage, 0, sizeof(struct rusage)); + status = syscall(SYS_waitid, (idtype_t) idtype, (id_t) id, &siginfo, (int) options, &rusage); +# endif + if (status == 0) { + PHP_RUSAGE_TO_ARRAY(rusage, z_rusage); + } + } else { /* POSIX */ + status = waitid((idtype_t) idtype, (id_t) id, &siginfo, (int) options); + } +#else /* POSIX */ + status = waitid((idtype_t) idtype, (id_t) id, &siginfo, (int) options); +#endif if (status == -1) { PCNTL_G(last_error) = errno; diff --git a/ext/pcntl/pcntl.stub.php b/ext/pcntl/pcntl.stub.php index c62a40139d9ed..3f3800c50abe5 100644 --- a/ext/pcntl/pcntl.stub.php +++ b/ext/pcntl/pcntl.stub.php @@ -1006,8 +1006,11 @@ function pcntl_fork(): int {} function pcntl_waitpid(int $process_id, &$status, int $flags = 0, &$resource_usage = []): int {} #if defined (HAVE_WAITID) && defined (HAVE_POSIX_IDTYPES) && defined (HAVE_DECL_WEXITED) && HAVE_DECL_WEXITED == 1 - /** @param array $info */ - function pcntl_waitid(int $idtype = P_ALL, ?int $id = null, &$info = [], int $flags = WEXITED): bool {} + /** + * @param array $info + * @param array $resource_usage + */ + function pcntl_waitid(int $idtype = P_ALL, ?int $id = null, &$info = [], int $flags = WEXITED, &$resource_usage = []): bool {} #endif /** diff --git a/ext/pcntl/pcntl_arginfo.h b/ext/pcntl/pcntl_arginfo.h index bc6581d41e17e..8b2367a7c7042 100644 --- a/ext/pcntl/pcntl_arginfo.h +++ b/ext/pcntl/pcntl_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: c637fe2de641cfd8f0ff83a908ac59bf63a68e44 */ + * Stub hash: 5e4b066d70fa264c7de3ba4b2113369c34c33e43 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pcntl_fork, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() @@ -17,6 +17,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pcntl_waitid, 0, 0, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, id, IS_LONG, 1, "null") ZEND_ARG_INFO_WITH_DEFAULT_VALUE(1, info, "[]") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "WEXITED") + ZEND_ARG_INFO_WITH_DEFAULT_VALUE(1, resource_usage, "[]") ZEND_END_ARG_INFO() #endif diff --git a/ext/pcntl/tests/pcntl_waitid.phpt b/ext/pcntl/tests/pcntl_waitid.phpt index b00f26f81fa2e..e297cd107a473 100644 --- a/ext/pcntl/tests/pcntl_waitid.phpt +++ b/ext/pcntl/tests/pcntl_waitid.phpt @@ -26,10 +26,12 @@ if ($pid == -1) { } else { pcntl_signal(SIGUSR1, function ($_signo, $_siginfo) { exit(42); }); posix_kill(posix_getpid(), SIGSTOP); - pcntl_signal_dispatch(); - sleep(42); - pcntl_signal_dispatch(); - exit(6); + $nanoseconds = 100; + while (true) { + pcntl_signal_dispatch(); + time_nanosleep(0, $nanoseconds); + $nanoseconds *= 2; + } } ?> --EXPECTF-- diff --git a/ext/pcntl/tests/pcntl_waitid_rusage.phpt b/ext/pcntl/tests/pcntl_waitid_rusage.phpt new file mode 100644 index 0000000000000..8df148357d1c8 --- /dev/null +++ b/ext/pcntl/tests/pcntl_waitid_rusage.phpt @@ -0,0 +1,72 @@ +--TEST-- +pcntl_waitid() and rusage +--EXTENSIONS-- +pcntl +posix +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +bool(true) +int(%d) +int(%d) +bool(true) +int(%d) +int(%d) +bool(true) +int(%d) +int(42) +bool(false) +string(5) "array" +int(0) +bool(false) +string(5) "array" +int(0) +END From 41d3440658ed22193597239f3526ca099703e5ec Mon Sep 17 00:00:00 2001 From: DanielEScherzer Date: Tue, 24 Jun 2025 13:05:52 -0700 Subject: [PATCH 098/120] NEWS: add a missing backtick [skip ci] --- NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 6ff942f86b2b7..fe91a1f30ef74 100644 --- a/NEWS +++ b/NEWS @@ -59,7 +59,7 @@ PHP NEWS . Added support for `final` with constructor property promotion. (DanielEScherzer) . Do not use RTLD_DEEPBIND if dlmopen is available. (Daniil Gentili) - . Make `clone() a function. (timwolla, edorian) + . Make `clone()` a function. (timwolla, edorian) - Curl: . Added curl_multi_get_handles(). (timwolla) From e7678cdaa4f11897d5d0afd10414c37a76abcb89 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Tue, 24 Jun 2025 19:38:00 +0200 Subject: [PATCH 099/120] sqlite3: Use Z_TRY_ADDREF --- ext/sqlite3/sqlite3.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c index 5e402300980bb..99c4bea5105ee 100644 --- a/ext/sqlite3/sqlite3.c +++ b/ext/sqlite3/sqlite3.c @@ -2479,9 +2479,7 @@ static zend_always_inline void php_sqlite3_fetch_one(int n_cols, php_sqlite3_res if (mode & PHP_SQLITE3_ASSOC) { if (mode & PHP_SQLITE3_NUM) { - if (Z_REFCOUNTED(data)) { - Z_ADDREF(data); - } + Z_TRY_ADDREF(data); } /* Note: we can't use the "add_new" variant here instead of "update" because * when the same column name is encountered, the last result should be taken. */ From 6d154758150d1a2f62fe33c3927fe5ad84de30b8 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Tue, 24 Jun 2025 19:41:14 +0200 Subject: [PATCH 100/120] sqlite3: Split off column name cache generation Also no need to reset the cache unconditionally in fetchAll(). --- ext/sqlite3/sqlite3.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c index 99c4bea5105ee..21b6840a8d1b2 100644 --- a/ext/sqlite3/sqlite3.c +++ b/ext/sqlite3/sqlite3.c @@ -1987,6 +1987,16 @@ PHP_METHOD(SQLite3Result, columnType) } /* }}} */ +static void sqlite3result_fill_column_names_cache(php_sqlite3_result *result_obj, int nb_cols) +{ + result_obj->column_names = safe_emalloc(nb_cols, sizeof(zend_string*), 0); + + for (int i = 0; i < nb_cols; i++) { + const char *column = sqlite3_column_name(result_obj->stmt_obj->stmt, i); + result_obj->column_names[i] = zend_string_init(column, strlen(column), 0); + } +} + /* {{{ Fetch a result row as both an associative or numerically indexed array or both. */ PHP_METHOD(SQLite3Result, fetchArray) { @@ -2019,12 +2029,7 @@ PHP_METHOD(SQLite3Result, fetchArray) /* Cache column names to speed up repeated fetchArray calls. */ if (mode & PHP_SQLITE3_ASSOC && !result_obj->column_names) { - result_obj->column_names = emalloc(n_cols * sizeof(zend_string*)); - - for (int i = 0; i < n_cols; i++) { - const char *column = sqlite3_column_name(result_obj->stmt_obj->stmt, i); - result_obj->column_names[i] = zend_string_init(column, strlen(column), 0); - } + sqlite3result_fill_column_names_cache(result_obj, n_cols); } array_init(return_value); @@ -2056,7 +2061,7 @@ static void sqlite3result_clear_column_names_cache(php_sqlite3_result *result) { PHP_METHOD(SQLite3Result, fetchAll) { - int i, nb_cols; + int nb_cols; bool done = false; php_sqlite3_result *result_obj; zval *object = ZEND_THIS; @@ -2071,14 +2076,8 @@ PHP_METHOD(SQLite3Result, fetchAll) SQLITE3_CHECK_INITIALIZED(result_obj->db_obj, result_obj->stmt_obj->initialised, SQLite3Result) nb_cols = sqlite3_column_count(result_obj->stmt_obj->stmt); - if (mode & PHP_SQLITE3_ASSOC) { - sqlite3result_clear_column_names_cache(result_obj); - result_obj->column_names = emalloc(nb_cols * sizeof(zend_string*)); - - for (i = 0; i < nb_cols; i++) { - const char *column = sqlite3_column_name(result_obj->stmt_obj->stmt, i); - result_obj->column_names[i] = zend_string_init(column, strlen(column), 0); - } + if (mode & PHP_SQLITE3_ASSOC && !result_obj->column_names) { + sqlite3result_fill_column_names_cache(result_obj, nb_cols); } result_obj->column_count = nb_cols; array_init(return_value); From 6233dc6210b159762a97b7759ea0883d027feac1 Mon Sep 17 00:00:00 2001 From: Shivam Mathur Date: Wed, 25 Jun 2025 01:57:07 +0530 Subject: [PATCH 101/120] Switch to windows-2022 in CI (#18927) * Switch to windows-2022 in CI windows-2019 runner will be dropped by GitHub on 2025-06-30. * xfail test cases that fail on windows-2022 --- .github/scripts/windows/build.bat | 4 +- .github/scripts/windows/find-vs-toolset.bat | 49 +++++++++++++++++++++ .github/scripts/windows/test.bat | 3 +- .github/workflows/push.yml | 2 +- .github/workflows/root.yml | 2 +- Zend/tests/bug70258.phpt | 3 ++ Zend/tests/gh11189.phpt | 3 ++ Zend/tests/gh11189_1.phpt | 3 ++ 8 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 .github/scripts/windows/find-vs-toolset.bat diff --git a/.github/scripts/windows/build.bat b/.github/scripts/windows/build.bat index ebe08c86b5ea9..139cce8be816e 100644 --- a/.github/scripts/windows/build.bat +++ b/.github/scripts/windows/build.bat @@ -43,7 +43,9 @@ if not exist "%SDK_RUNNER%" ( exit /b 3 ) -cmd /c %SDK_RUNNER% -t .github\scripts\windows\build_task.bat +for /f "delims=" %%T in ('call .github\scripts\windows\find-vs-toolset.bat %PHP_BUILD_CRT%') do set "VS_TOOLSET=%%T" +echo Got VS Toolset %VS_TOOLSET% +cmd /c %SDK_RUNNER% -s %VS_TOOLSET% -t .github\scripts\windows\build_task.bat if %errorlevel% neq 0 exit /b 3 exit /b 0 diff --git a/.github/scripts/windows/find-vs-toolset.bat b/.github/scripts/windows/find-vs-toolset.bat new file mode 100644 index 0000000000000..2d9e68e730318 --- /dev/null +++ b/.github/scripts/windows/find-vs-toolset.bat @@ -0,0 +1,49 @@ +@echo off + +setlocal enabledelayedexpansion + +if "%~1"=="" ( + echo ERROR: Usage: %~nx0 [vc14^|vc15^|vs16^|vs17] + exit /b 1 +) + +set "toolsets_vc14=14.0" +set "toolsets_vc15=" +set "toolsets_vs16=" +set "toolsets_vs17=" + + +for /f "usebackq tokens=*" %%I in (`vswhere.exe -latest -find "VC\Tools\MSVC"`) do set "MSVCDIR=%%I" + +if not defined MSVCDIR ( + echo ERROR: could not locate VC\Tools\MSVC + exit /b 1 +) + +for /f "delims=" %%D in ('dir /b /ad "%MSVCDIR%"') do ( + for /f "tokens=1,2 delims=." %%A in ("%%D") do ( + set "maj=%%A" & set "min=%%B" + if "!maj!"=="14" ( + if !min! LEQ 9 ( + set "toolsets_vc14=%%D" + ) else if !min! LEQ 19 ( + set "toolsets_vc15=%%D" + ) else if !min! LEQ 29 ( + set "toolsets_vs16=%%D" + ) else ( + set "toolsets_vs17=%%D" + ) + ) + ) +) + +set "KEY=%~1" +set "VAR=toolsets_%KEY%" +call set "RESULT=%%%VAR%%%" +if defined RESULT ( + echo %RESULT% + exit /b 0 +) else ( + echo ERROR: no toolset found for %KEY% + exit /b 1 +) diff --git a/.github/scripts/windows/test.bat b/.github/scripts/windows/test.bat index 510e9bc78f4ed..7ef60534cc780 100644 --- a/.github/scripts/windows/test.bat +++ b/.github/scripts/windows/test.bat @@ -11,7 +11,8 @@ if not exist "%SDK_RUNNER%" ( exit /b 3 ) -cmd /c %SDK_RUNNER% -t .github\scripts\windows\test_task.bat +for /f "delims=" %%T in ('call .github\scripts\windows\find-vs-toolset.bat %PHP_BUILD_CRT%') do set "VS_TOOLSET=%%T" +cmd /c %SDK_RUNNER% -s %VS_TOOLSET% -t .github\scripts\windows\test_task.bat if %errorlevel% neq 0 exit /b 3 exit /b 0 diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 214798af62b5c..5353ef7d0ea44 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -147,7 +147,7 @@ jobs: WINDOWS: if: github.repository == 'php/php-src' || github.event_name == 'pull_request' name: WINDOWS_X64_ZTS - runs-on: windows-2019 + runs-on: windows-2022 env: PHP_BUILD_CACHE_BASE_DIR: C:\build-cache PHP_BUILD_OBJ_DIR: C:\obj diff --git a/.github/workflows/root.yml b/.github/workflows/root.yml index a98bb39ba0d92..78e0d47aa1d15 100644 --- a/.github/workflows/root.yml +++ b/.github/workflows/root.yml @@ -58,7 +58,7 @@ jobs: ubuntu_version: ${{ (((matrix.branch.version[0] == 8 && matrix.branch.version[1] >= 5) || matrix.branch.version[0] >= 9) && '24.04') || '22.04' }} - windows_version: ${{ ((matrix.branch.version[0] == 8 && matrix.branch.version[1] >= 4) || matrix.branch.version[0] >= 9) && '2022' || '2019' }} + windows_version: '2022' skip_laravel: ${{ matrix.branch.version[0] == 8 && matrix.branch.version[1] == 1 }} skip_symfony: ${{ matrix.branch.version[0] == 8 && matrix.branch.version[1] == 1 }} skip_wordpress: ${{ matrix.branch.version[0] == 8 && matrix.branch.version[1] == 1 }} diff --git a/Zend/tests/bug70258.phpt b/Zend/tests/bug70258.phpt index 40915a286ef9e..d346dbdf3a35b 100644 --- a/Zend/tests/bug70258.phpt +++ b/Zend/tests/bug70258.phpt @@ -4,6 +4,9 @@ Bug #70258 (Segfault if do_resize fails to allocated memory) memory_limit=2M --SKIPIF-- --INI-- diff --git a/Zend/tests/gh11189_1.phpt b/Zend/tests/gh11189_1.phpt index 53727908e5e2a..17b9967bc3182 100644 --- a/Zend/tests/gh11189_1.phpt +++ b/Zend/tests/gh11189_1.phpt @@ -2,6 +2,9 @@ GH-11189: Exceeding memory limit in zend_hash_do_resize leaves the array in an invalid state (not packed array) --SKIPIF-- --INI-- From 2965fb843d732ff014000c8c293d515d17684bd5 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Tue, 24 Jun 2025 21:55:00 +0100 Subject: [PATCH 102/120] ext/pcntl: following up #15921 rework SYS_pidfd_open configure detection. (#18931) --- ext/pcntl/config.m4 | 4 +++- ext/pcntl/pcntl.c | 16 +++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/ext/pcntl/config.m4 b/ext/pcntl/config.m4 index 3efa8a53cad1e..cfe6e80ca1103 100644 --- a/ext/pcntl/config.m4 +++ b/ext/pcntl/config.m4 @@ -13,7 +13,6 @@ if test "$PHP_PCNTL" != "no"; then forkx getcpuid getpriority - pidfd_open pset_bind pthread_set_qos_class_self_np rfork @@ -48,6 +47,9 @@ if test "$PHP_PCNTL" != "no"; then AC_CHECK_DECLS([SYS_waitid],,, [#include ]) + AC_CHECK_DECLS([SYS_pidfd_open],,, + [#include ]) + dnl if unsupported, -1 means automatically ENOSYS in this context AC_CACHE_CHECK([if sched_getcpu is supported], [php_cv_func_sched_getcpu], [AC_RUN_IFELSE([AC_LANG_SOURCE([ diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c index 1f061870ed453..886d4b6b595ff 100644 --- a/ext/pcntl/pcntl.c +++ b/ext/pcntl/pcntl.c @@ -125,18 +125,20 @@ typedef psetid_t cpu_set_t; #include #endif -#if defined(__linux__) && defined(HAVE_DECL_SYS_WAITID) && HAVE_DECL_SYS_WAITID == 1 && defined(HAVE_SYSCALL) -#define HAVE_LINUX_RAW_SYSCALL_WAITID 1 +#if defined(__linux__) && defined(HAVE_SYSCALL) +# include +# if defined(HAVE_DECL_SYS_WAITID) && HAVE_DECL_SYS_WAITID == 1 +# define HAVE_LINUX_RAW_SYSCALL_WAITID 1 +# endif +# if defined(HAVE_DECL_SYS_PIDFD_OPEN) && HAVE_DECL_SYS_PIDFD_OPEN == 1 +# define HAVE_LINUX_RAW_SYSCALL_PIDFD_OPEN 1 +# endif #endif #if defined(HAVE_LINUX_RAW_SYSCALL_WAITID) #include #endif -#if defined(HAVE_PIDFD_OPEN) || defined(HAVE_LINUX_RAW_SYSCALL_WAITID) -#include -#endif - #ifdef HAVE_FORKX #include #endif @@ -1607,7 +1609,7 @@ PHP_FUNCTION(pcntl_forkx) #endif /* }}} */ -#ifdef HAVE_PIDFD_OPEN +#ifdef HAVE_LINUX_RAW_SYSCALL_PIDFD_OPEN // The `pidfd_open` syscall is available since 5.3 // and `setns` since 3.0. PHP_FUNCTION(pcntl_setns) From 359a21f102b5ca9e517253281228da68a053b3ae Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Tue, 24 Jun 2025 18:55:11 +0200 Subject: [PATCH 103/120] Fix RCN violations in array functions When the array functions perform their operation in-place, the `@refcount 1` annotation is wrong and causes a failure under `ZEND_VERIFY_FUNC_INFO`. The test file tests all functions that have the in-place optimization, even those that didn't have the refcount annotation, just to prevent future regressions. Closes GH-18929. --- NEWS | 1 + Zend/Optimizer/zend_func_infos.h | 7 --- ext/standard/basic_functions.stub.php | 7 --- ext/standard/basic_functions_arginfo.h | 2 +- ext/standard/tests/array/rcn_in_place.phpt | 57 ++++++++++++++++++++++ 5 files changed, 59 insertions(+), 15 deletions(-) create mode 100644 ext/standard/tests/array/rcn_in_place.phpt diff --git a/NEWS b/NEWS index 34866abfb21d8..624bcda9bdf44 100644 --- a/NEWS +++ b/NEWS @@ -28,6 +28,7 @@ PHP NEWS - Standard: . Fix misleading errors in printf(). (nielsdos) + . Fix RCN violations in array functions. (nielsdos) - Streams: . Fixed GH-13264 (fgets() and stream_get_line() do not return false on filter diff --git a/Zend/Optimizer/zend_func_infos.h b/Zend/Optimizer/zend_func_infos.h index 125212d2292e6..c9229d638f433 100644 --- a/Zend/Optimizer/zend_func_infos.h +++ b/Zend/Optimizer/zend_func_infos.h @@ -450,8 +450,6 @@ static const func_info_t func_infos[] = { F1("compact", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF), FN("array_fill", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_ANY), F1("array_fill_keys", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF), - F1("array_replace", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF), - F1("array_replace_recursive", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF), FN("array_keys", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_LONG|MAY_BE_ARRAY_OF_STRING), FN("array_values", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF), F1("array_count_values", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_LONG), @@ -460,13 +458,8 @@ static const func_info_t func_infos[] = { F1("array_flip", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_LONG|MAY_BE_ARRAY_OF_STRING), F1("array_change_key_case", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF), F1("array_intersect_key", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF), - F1("array_intersect_ukey", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF), - F1("array_intersect", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF), - F1("array_uintersect", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF), F1("array_intersect_assoc", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF), F1("array_uintersect_assoc", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF), - F1("array_intersect_uassoc", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF), - F1("array_uintersect_uassoc", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF), F1("array_diff_key", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF), F1("array_diff_ukey", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF), F1("array_udiff", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF), diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index 3bdc3827b4d36..0bbdeeb72a2c3 100755 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -1678,13 +1678,11 @@ function array_merge_recursive(array ...$arrays): array {} /** * @compile-time-eval - * @refcount 1 */ function array_replace(array $array, array ...$replacements): array {} /** * @compile-time-eval - * @refcount 1 */ function array_replace_recursive(array $array, array ...$replacements): array {} @@ -1757,19 +1755,16 @@ function array_intersect_key(array $array, array ...$arrays): array {} /** * @param array|callable $rest - * @refcount 1 */ function array_intersect_ukey(array $array, ...$rest): array {} /** * @compile-time-eval - * @refcount 1 */ function array_intersect(array $array, array ...$arrays): array {} /** * @param array|callable $rest - * @refcount 1 */ function array_uintersect(array $array, ...$rest): array {} @@ -1787,13 +1782,11 @@ function array_uintersect_assoc(array $array, ...$rest): array {} /** * @param array|callable $rest - * @refcount 1 */ function array_intersect_uassoc(array $array, ...$rest): array {} /** * @param array|callable $rest - * @refcount 1 */ function array_uintersect_uassoc(array $array, ...$rest): array {} diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index 1361cf6062797..23ee75fe18dc3 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 2a3d8da0b92134dcca74f2ac70454bd27768f20e */ + * Stub hash: 60960e59f6310521a958b6fb0917650854d19612 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0) diff --git a/ext/standard/tests/array/rcn_in_place.phpt b/ext/standard/tests/array/rcn_in_place.phpt new file mode 100644 index 0000000000000..e6a7b5b6d695f --- /dev/null +++ b/ext/standard/tests/array/rcn_in_place.phpt @@ -0,0 +1,57 @@ +--TEST-- +RCN check for in-place array modifications +--FILE-- + 0)); +var_dump(array_intersect(range(0, 1), [])); +var_dump(array_uintersect(range(0, 1), [], fn () => 0)); +var_dump(array_intersect_uassoc(range(0, 1), [], fn () => 0)); +var_dump(array_uintersect_uassoc(range(0, 1), [], fn () => 0, fn () => 0)); +?> +--EXPECT-- +array(2) { + [0]=> + int(0) + [1]=> + int(1) +} +array(2) { + [0]=> + int(0) + [1]=> + int(1) +} +array(2) { + [0]=> + int(0) + [1]=> + int(1) +} +array(2) { + [0]=> + int(0) + [1]=> + int(1) +} +array(2) { + [0]=> + int(0) + [1]=> + int(1) +} +array(0) { +} +array(0) { +} +array(0) { +} +array(0) { +} +array(0) { +} From ea6a7a97255b939539cf92d43ce4c5c8b24b3199 Mon Sep 17 00:00:00 2001 From: Shivam Mathur Date: Wed, 25 Jun 2025 03:15:10 +0530 Subject: [PATCH 104/120] Fix CI for windows-2022 This is a continuation of GH-18927 to fix CI for windows-2022 --- Zend/tests/bug40770.phpt | 3 +++ Zend/tests/gh12073.phpt | 3 +++ tests/basic/timeout_variation_0.phpt | 3 +++ tests/basic/timeout_variation_7.phpt | 3 +++ tests/func/005a.phpt | 3 +++ tests/lang/bug45392.phpt | 3 +++ 6 files changed, 18 insertions(+) diff --git a/Zend/tests/bug40770.phpt b/Zend/tests/bug40770.phpt index f37d96d5ff333..bdbae4cf8f1a2 100644 --- a/Zend/tests/bug40770.phpt +++ b/Zend/tests/bug40770.phpt @@ -4,6 +4,9 @@ Bug #40770 (Apache child exits when PHP memory limit reached) memory_limit=8M --SKIPIF-- --FILE-- diff --git a/tests/basic/timeout_variation_7.phpt b/tests/basic/timeout_variation_7.phpt index 0401240ba953d..3d40b540677db 100644 --- a/tests/basic/timeout_variation_7.phpt +++ b/tests/basic/timeout_variation_7.phpt @@ -2,6 +2,9 @@ Timeout within for loop --SKIPIF-- --FILE-- diff --git a/tests/func/005a.phpt b/tests/func/005a.phpt index cf1e5713770a9..2f527d773adbe 100644 --- a/tests/func/005a.phpt +++ b/tests/func/005a.phpt @@ -2,6 +2,9 @@ Testing register_shutdown_function() with timeout. (Bug: #21513) --SKIPIF-- --FILE-- diff --git a/tests/lang/bug45392.phpt b/tests/lang/bug45392.phpt index 692fa0cdcf6fd..1a01bac3261a9 100644 --- a/tests/lang/bug45392.phpt +++ b/tests/lang/bug45392.phpt @@ -2,6 +2,9 @@ Bug #45392 (ob_start()/ob_end_clean() and memory_limit) --SKIPIF-- Date: Wed, 25 Jun 2025 03:15:10 +0530 Subject: [PATCH 105/120] Fix CI for windows-2022 This is a continuation of GH-18927 to fix CI for windows-2022 --- Zend/tests/bug40770.phpt | 3 +++ Zend/tests/gh12073.phpt | 3 +++ Zend/tests/traits/bugs/gh13177.phpt | 6 ++++++ tests/basic/timeout_variation_0.phpt | 3 +++ tests/basic/timeout_variation_7.phpt | 3 +++ tests/func/005a.phpt | 3 +++ tests/lang/bug45392.phpt | 3 +++ 7 files changed, 24 insertions(+) diff --git a/Zend/tests/bug40770.phpt b/Zend/tests/bug40770.phpt index f37d96d5ff333..bdbae4cf8f1a2 100644 --- a/Zend/tests/bug40770.phpt +++ b/Zend/tests/bug40770.phpt @@ -4,6 +4,9 @@ Bug #40770 (Apache child exits when PHP memory limit reached) memory_limit=8M --SKIPIF-- --FILE-- --FILE-- diff --git a/tests/basic/timeout_variation_7.phpt b/tests/basic/timeout_variation_7.phpt index 0401240ba953d..3d40b540677db 100644 --- a/tests/basic/timeout_variation_7.phpt +++ b/tests/basic/timeout_variation_7.phpt @@ -2,6 +2,9 @@ Timeout within for loop --SKIPIF-- --FILE-- diff --git a/tests/func/005a.phpt b/tests/func/005a.phpt index cf1e5713770a9..2f527d773adbe 100644 --- a/tests/func/005a.phpt +++ b/tests/func/005a.phpt @@ -2,6 +2,9 @@ Testing register_shutdown_function() with timeout. (Bug: #21513) --SKIPIF-- --FILE-- diff --git a/tests/lang/bug45392.phpt b/tests/lang/bug45392.phpt index 692fa0cdcf6fd..1a01bac3261a9 100644 --- a/tests/lang/bug45392.phpt +++ b/tests/lang/bug45392.phpt @@ -2,6 +2,9 @@ Bug #45392 (ob_start()/ob_end_clean() and memory_limit) --SKIPIF-- Date: Wed, 25 Jun 2025 18:36:20 +0900 Subject: [PATCH 106/120] Allowed the use of formats like `@param array<>` (#18924) --- build/gen_stub.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/gen_stub.php b/build/gen_stub.php index d9327b67d042f..a3dd14a562346 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -4533,7 +4533,7 @@ public function getVariableName(): string { if ($this->name === "param") { // Allow for parsing extended types like callable(string):mixed in docblocks - preg_match('/^\s*(?[\w\|\\\\]+(?\((?(?:(?&parens)|[^(){}[\]]*+))++\)|\{(?&inparens)\}|\[(?&inparens)\])*+(?::(?&type))?)\s*\$(?\w+).*$/', $value, $matches); + preg_match('/^\s*(?[\w\|\\\\]+(?\((?(?:(?&parens)|[^(){}[\]<>]*+))++\)|\{(?&inparens)\}|\[(?&inparens)\]|<(?&inparens)>)*+(?::(?&type))?)\s*\$(?\w+).*$/', $value, $matches); } elseif ($this->name === "prefer-ref") { preg_match('/^\s*\$(?\w+).*$/', $value, $matches); } From cc8ae131a23fcb1aead561a548a1097dcd64a3bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Wed, 11 Jun 2025 19:49:39 +0200 Subject: [PATCH 107/120] Add Uri\Rfc3986\Uri class to ext/uri Relates to #14461 and https://wiki.php.net/rfc/url_parsing_api --- Zend/zend_string.h | 1 + build/gen_stub.php | 1 + ext/uri/config.m4 | 3 +- ext/uri/php_uri.c | 397 ++++++++++++---- ext/uri/php_uri.stub.php | 64 +++ ext/uri/php_uri_arginfo.h | 195 ++++++-- ext/uri/php_uri_common.h | 3 + ext/uri/php_uriparser.c | 525 ++++++++++++++++++++++ ext/uri/php_uriparser.h | 38 ++ ext/uri/tests/003.phpt | 21 + ext/uri/tests/004.phpt | 33 +- ext/uri/tests/005.phpt | 3 + ext/uri/tests/006.phpt | 21 + ext/uri/tests/007.phpt | 7 + ext/uri/tests/008.phpt | 44 ++ ext/uri/tests/009.phpt | 19 + ext/uri/tests/010.phpt | 38 ++ ext/uri/tests/011.phpt | 11 + ext/uri/tests/012.phpt | 38 ++ ext/uri/tests/013.phpt | 44 ++ ext/uri/tests/014.phpt | 3 + ext/uri/tests/015.phpt | 8 + ext/uri/tests/018.phpt | 45 +- ext/uri/tests/019.phpt | 8 + ext/uri/tests/021.phpt | 14 + ext/uri/tests/031.phpt | 82 ++++ ext/uri/tests/032.phpt | 4 + ext/uri/tests/033.phpt | 6 + ext/uri/tests/034.phpt | 5 + ext/uri/tests/035.phpt | 7 + ext/uri/tests/036.phpt | 15 + ext/uri/tests/038.phpt | 16 + ext/uri/tests/039.phpt | 44 ++ ext/uri/tests/040.phpt | 23 + ext/uri/tests/041.phpt | 21 + ext/uri/tests/042.phpt | 21 + ext/uri/tests/043.phpt | 86 ++++ ext/uri/tests/045.phpt | 9 + ext/uri/tests/046.phpt | 43 ++ ext/uri/tests/047.phpt | 20 + ext/uri/tests/048.phpt | 17 + ext/uri/tests/049.phpt | 6 + ext/uri/tests/050.phpt | 7 + ext/uri/tests/051.phpt | 9 + ext/uri/uriparser/include/uriparser/Uri.h | 7 + ext/uri/uriparser/src/UriCommon.h | 1 - 46 files changed, 1900 insertions(+), 133 deletions(-) create mode 100644 ext/uri/php_uriparser.c create mode 100644 ext/uri/php_uriparser.h create mode 100644 ext/uri/tests/021.phpt create mode 100644 ext/uri/tests/048.phpt diff --git a/Zend/zend_string.h b/Zend/zend_string.h index f60e4dec4e71f..cc7789269bec5 100644 --- a/Zend/zend_string.h +++ b/Zend/zend_string.h @@ -597,6 +597,7 @@ EMPTY_SWITCH_DEFAULT_CASE() _(ZEND_STR_SCHEME, "scheme") \ _(ZEND_STR_HOST, "host") \ _(ZEND_STR_PORT, "port") \ + _(ZEND_STR_USERINFO, "userinfo") \ _(ZEND_STR_USER, "user") \ _(ZEND_STR_USERNAME, "username") \ _(ZEND_STR_PASS, "pass") \ diff --git a/build/gen_stub.php b/build/gen_stub.php index a3dd14a562346..c281ee76505f8 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -3050,6 +3050,7 @@ class PropertyInfo extends VariableLike private const PHP_85_KNOWN = [ "self" => "ZEND_STR_SELF", "parent" => "ZEND_STR_PARENT", + "userinfo" => "ZEND_STR_USERINFO", "username" => "ZEND_STR_USERNAME", "password" => "ZEND_STR_PASSWORD", "clone" => "ZEND_STR_CLONE", diff --git a/ext/uri/config.m4 b/ext/uri/config.m4 index 08dc044d8d29f..25e2f34b62eaf 100644 --- a/ext/uri/config.m4 +++ b/ext/uri/config.m4 @@ -5,6 +5,7 @@ PHP_INSTALL_HEADERS([ext/uri], m4_normalize([ php_lexbor.h php_uri.h php_uri_common.h + php_uriparser.h ])) AC_DEFINE([URI_ENABLE_ANSI], [1], [Define to 1 for enabling ANSI support of uriparser.]) @@ -17,6 +18,6 @@ $URIPARSER_DIR/src/UriMemory.c $URIPARSER_DIR/src/UriNormalize.c $URIPARSER_DIR/ $URIPARSER_DIR/src/UriParse.c $URIPARSER_DIR/src/UriParseBase.c $URIPARSER_DIR/src/UriQuery.c \ $URIPARSER_DIR/src/UriRecompose.c $URIPARSER_DIR/src/UriResolve.c $URIPARSER_DIR/src/UriShorten.c" -PHP_NEW_EXTENSION(uri, [php_lexbor.c php_uri.c php_uri_common.c $URIPARSER_SOURCES], [no],,[-I$ext_srcdir/$URIPARSER_DIR/include -DURI_STATIC_BUILD -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1]) +PHP_NEW_EXTENSION(uri, [php_lexbor.c php_uri.c php_uri_common.c php_uriparser.c $URIPARSER_SOURCES], [no],,[-I$ext_srcdir/$URIPARSER_DIR/include -DURI_STATIC_BUILD -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1]) PHP_ADD_EXTENSION_DEP(uri, lexbor) PHP_ADD_BUILD_DIR($ext_builddir/$URIPARSER_DIR/src $ext_builddir/$URIPARSER_DIR/include) diff --git a/ext/uri/php_uri.c b/ext/uri/php_uri.c index 5b2e21b1625a3..24b010ffa3ccc 100644 --- a/ext/uri/php_uri.c +++ b/ext/uri/php_uri.c @@ -25,12 +25,14 @@ #include "Zend/zend_enum.h" #include "ext/standard/info.h" -#include "php_uri.h" #include "php_uri_common.h" #include "php_lexbor.h" +#include "php_uriparser.h" #include "php_uri_arginfo.h" #include "uriparser/src/UriConfig.h" +zend_class_entry *uri_rfc3986_uri_ce; +zend_object_handlers uri_rfc3986_uri_object_handlers; zend_class_entry *uri_whatwg_url_ce; zend_object_handlers uri_whatwg_uri_object_handlers; zend_class_entry *uri_comparison_mode_ce; @@ -104,67 +106,6 @@ static HashTable *uri_get_debug_properties(zend_object *object) return result; } -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(uri_whatwg_invalid_url_exception_ce, Z_OBJ_P(ZEND_THIS), ZEND_STRL("errors"), &tmp); - } else { - zend_update_property(uri_whatwg_invalid_url_exception_ce, 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, uri_whatwg_url_validation_error_type_ce) - Z_PARAM_BOOL(failure) - ZEND_PARSE_PARAMETERS_END(); - - zend_update_property_str(uri_whatwg_url_validation_error_ce, Z_OBJ_P(ZEND_THIS), ZEND_STRL("context"), context); - if (EG(exception)) { - RETURN_THROWS(); - } - - zend_update_property_ex(uri_whatwg_url_validation_error_ce, 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(uri_whatwg_url_validation_error_ce, Z_OBJ_P(ZEND_THIS), ZEND_STRL("failure"), &failure_zv); - if (EG(exception)) { - RETURN_THROWS(); - } -} - /** * Pass the errors parameter by ref to errors_zv for userland, and frees it if * it is not not needed anymore. @@ -242,6 +183,91 @@ PHPAPI void php_uri_instantiate_uri( uri_object->internal.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, uri_rfc3986_uri_ce) + ZEND_PARSE_PARAMETERS_END(); + + php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, &uriparser_uri_handler, uri_str, base_url_object, is_constructor, is_constructor, NULL); +} + +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(uri_whatwg_invalid_url_exception_ce, Z_OBJ_P(ZEND_THIS), ZEND_STRL("errors"), &tmp); + } else { + zend_update_property(uri_whatwg_invalid_url_exception_ce, 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, uri_whatwg_url_validation_error_type_ce) + Z_PARAM_BOOL(failure) + ZEND_PARSE_PARAMETERS_END(); + + zend_update_property_str(uri_whatwg_url_validation_error_ce, Z_OBJ_P(ZEND_THIS), ZEND_STRL("context"), context); + if (EG(exception)) { + RETURN_THROWS(); + } + + zend_update_property_ex(uri_whatwg_url_validation_error_ce, 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(uri_whatwg_url_validation_error_ce, 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; @@ -268,6 +294,105 @@ PHP_METHOD(Uri_WhatWg_Url, __construct) create_whatwg_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, true); } +PHP_METHOD(Uri_Rfc3986_Uri, getScheme) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_SCHEME, URI_COMPONENT_READ_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getRawScheme) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_SCHEME, URI_COMPONENT_READ_RAW); +} + +static void read_uriparser_userinfo(INTERNAL_FUNCTION_PARAMETERS, uri_component_read_mode_t read_mode) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + uri_internal_t *internal_uri = Z_URI_INTERNAL_P(ZEND_THIS); + URI_ASSERT_INITIALIZATION(internal_uri); + + if (UNEXPECTED(uriparser_read_userinfo(internal_uri, read_mode, return_value) == FAILURE)) { + zend_throw_error(NULL, "%s::$%s property cannot be retrieved", ZSTR_VAL(Z_OBJ_P(ZEND_THIS)->ce->name), + ZSTR_VAL(ZSTR_KNOWN(ZEND_STR_USERINFO))); + RETURN_THROWS(); + } +} + +PHP_METHOD(Uri_Rfc3986_Uri, getUserInfo) +{ + read_uriparser_userinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_COMPONENT_READ_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getRawUserInfo) +{ + read_uriparser_userinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_COMPONENT_READ_RAW); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getUsername) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_USERNAME, URI_COMPONENT_READ_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getRawUsername) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_USERNAME, URI_COMPONENT_READ_RAW); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getPassword) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PASSWORD, URI_COMPONENT_READ_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getRawPassword) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PASSWORD, URI_COMPONENT_READ_RAW); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getHost) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_HOST, URI_COMPONENT_READ_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getRawHost) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_HOST, URI_COMPONENT_READ_RAW); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getPort) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PORT, URI_COMPONENT_READ_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getPath) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PATH, URI_COMPONENT_READ_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getRawPath) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PATH, URI_COMPONENT_READ_RAW); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getQuery) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_QUERY, URI_COMPONENT_READ_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getRawQuery) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_QUERY, URI_COMPONENT_READ_RAW); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getFragment) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_FRAGMENT, URI_COMPONENT_READ_NORMALIZED_ASCII); +} + +PHP_METHOD(Uri_Rfc3986_Uri, getRawFragment) +{ + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_FRAGMENT, URI_COMPONENT_READ_RAW); +} + static void uri_equals(INTERNAL_FUNCTION_PARAMETERS, zend_object *that_object, zend_object *comparison_mode) { zend_object *this_object = Z_OBJ_P(ZEND_THIS); @@ -311,6 +436,99 @@ static void uri_equals(INTERNAL_FUNCTION_PARAMETERS, zend_object *that_object, z 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, uri_rfc3986_uri_ce) + Z_PARAM_OPTIONAL + Z_PARAM_OBJ_OF_CLASS(comparison_mode, uri_comparison_mode_ce); + ZEND_PARSE_PARAMETERS_END(); + + uri_equals(INTERNAL_FUNCTION_PARAM_PASSTHRU, that_object, comparison_mode); +} + +PHP_METHOD(Uri_Rfc3986_Uri, toRawString) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zend_object *this_object = Z_OBJ_P(ZEND_THIS); + uri_internal_t *internal_uri = uri_internal_from_obj(this_object); + URI_ASSERT_INITIALIZATION(internal_uri); + + zend_string *uri_str = internal_uri->handler->uri_to_string(internal_uri->uri, URI_RECOMPOSITION_RAW_ASCII, false); + if (uri_str == NULL) { + zend_throw_exception_ex(NULL, 0, "Cannot recompose %s to string", ZSTR_VAL(this_object->ce->name)); + RETURN_THROWS(); + } + + RETURN_STR(uri_str); +} + +PHP_METHOD(Uri_Rfc3986_Uri, toString) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zend_object *this_object = Z_OBJ_P(ZEND_THIS); + uri_internal_t *internal_uri = uri_internal_from_obj(this_object); + URI_ASSERT_INITIALIZATION(internal_uri); + + zend_string *uri_str = internal_uri->handler->uri_to_string(internal_uri->uri, URI_RECOMPOSITION_NORMALIZED_ASCII, false); + if (uri_str == NULL) { + zend_throw_exception_ex(NULL, 0, "Cannot recompose %s to string", ZSTR_VAL(this_object->ce->name)); + 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(); \ + + zend_object *this_object = Z_OBJ_P(ZEND_THIS); + uri_internal_t *internal_uri = uri_internal_from_obj(this_object); + URI_ASSERT_INITIALIZATION(internal_uri); + + php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, internal_uri->handler, uri_str, this_object, true, false, NULL); +} + +PHP_METHOD(Uri_Rfc3986_Uri, __serialize) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zend_object *this_object = Z_OBJ_P(ZEND_THIS); + uri_internal_t *internal_uri = uri_internal_from_obj(this_object); + URI_ASSERT_INITIALIZATION(internal_uri); + + /* Serialize state: "uri" key in the first array */ + zend_string *uri_str = internal_uri->handler->uri_to_string(internal_uri->uri, URI_RECOMPOSITION_RAW_ASCII, false); + if (uri_str == NULL) { + zend_throw_exception_ex(NULL, 0, "Cannot recompose %s to string", ZSTR_VAL(this_object->ce->name)); + 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), URI_SERIALIZED_PROPERTY_NAME, sizeof(URI_SERIALIZED_PROPERTY_NAME) - 1, &tmp); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &arr); + + /* Serialize regular properties: second array */ + ZVAL_ARR(&arr, this_object->handlers->get_properties(this_object)); + Z_TRY_ADDREF(arr); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &arr); +} + static void uri_unserialize(INTERNAL_FUNCTION_PARAMETERS, const char *handler_name) { HashTable *data; @@ -371,29 +589,33 @@ static void uri_unserialize(INTERNAL_FUNCTION_PARAMETERS, const char *handler_na } } -PHP_METHOD(Uri_WhatWg_Url, getScheme) +PHP_METHOD(Uri_Rfc3986_Uri, __unserialize) { - uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_SCHEME, URI_COMPONENT_READ_NORMALIZED_ASCII); + uri_unserialize(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PARSER_RFC3986); } -PHP_METHOD(Uri_WhatWg_Url, withScheme) +PHP_METHOD(Uri_Rfc3986_Uri, __debugInfo) { - uri_write_component_str(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_SCHEME); + ZEND_PARSE_PARAMETERS_NONE(); + + zend_object *object = Z_OBJ_P(ZEND_THIS); + + RETURN_ARR(uri_get_debug_properties(object)); } -PHP_METHOD(Uri_WhatWg_Url, getUsername) +PHP_METHOD(Uri_WhatWg_Url, getScheme) { - uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_USERNAME, URI_COMPONENT_READ_NORMALIZED_ASCII); + uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_SCHEME, URI_COMPONENT_READ_NORMALIZED_ASCII); } -PHP_METHOD(Uri_WhatWg_Url, withUsername) +PHP_METHOD(Uri_WhatWg_Url, withScheme) { - uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_USERNAME); + uri_write_component_str(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_SCHEME); } -PHP_METHOD(Uri_WhatWg_Url, getPassword) +PHP_METHOD(Uri_WhatWg_Url, withUsername) { - uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PASSWORD, URI_COMPONENT_READ_NORMALIZED_ASCII); + uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_USERNAME); } PHP_METHOD(Uri_WhatWg_Url, withPassword) @@ -416,41 +638,21 @@ PHP_METHOD(Uri_WhatWg_Url, withHost) uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_HOST); } -PHP_METHOD(Uri_WhatWg_Url, getPort) -{ - uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PORT, URI_COMPONENT_READ_NORMALIZED_ASCII); -} - PHP_METHOD(Uri_WhatWg_Url, withPort) { uri_write_component_long_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PORT); } -PHP_METHOD(Uri_WhatWg_Url, getPath) -{ - uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PATH, URI_COMPONENT_READ_NORMALIZED_ASCII); -} - PHP_METHOD(Uri_WhatWg_Url, withPath) { uri_write_component_str(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PATH); } -PHP_METHOD(Uri_WhatWg_Url, getQuery) -{ - uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_QUERY, URI_COMPONENT_READ_NORMALIZED_ASCII); -} - PHP_METHOD(Uri_WhatWg_Url, withQuery) { uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_QUERY); } -PHP_METHOD(Uri_WhatWg_Url, getFragment) -{ - uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_FRAGMENT, URI_COMPONENT_READ_NORMALIZED_ASCII); -} - PHP_METHOD(Uri_WhatWg_Url, withFragment) { uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_FRAGMENT); @@ -629,6 +831,9 @@ zend_result uri_handler_register(const uri_handler_t *uri_handler) static PHP_MINIT_FUNCTION(uri) { + uri_rfc3986_uri_ce = register_class_Uri_Rfc3986_Uri(); + php_uri_implementation_set_object_handlers(uri_rfc3986_uri_ce, &uri_rfc3986_uri_object_handlers); + uri_whatwg_url_ce = register_class_Uri_WhatWg_Url(); php_uri_implementation_set_object_handlers(uri_whatwg_url_ce, &uri_whatwg_uri_object_handlers); @@ -641,6 +846,10 @@ static PHP_MINIT_FUNCTION(uri) zend_hash_init(&uri_handlers, 4, NULL, NULL, true); + if (uri_handler_register(&uriparser_uri_handler) == FAILURE) { + return FAILURE; + } + if (uri_handler_register(&lexbor_uri_handler) == FAILURE) { return FAILURE; } @@ -665,6 +874,10 @@ static PHP_MSHUTDOWN_FUNCTION(uri) PHP_RINIT_FUNCTION(uri) { + if (uriparser_request_init() == FAILURE) { + return FAILURE; + } + if (lexbor_request_init() == FAILURE) { return FAILURE; } diff --git a/ext/uri/php_uri.stub.php b/ext/uri/php_uri.stub.php index ef49e4ba6f968..9fbd40d98e5e9 100644 --- a/ext/uri/php_uri.stub.php +++ b/ext/uri/php_uri.stub.php @@ -20,6 +20,64 @@ enum UriComparisonMode } } +namespace Uri\Rfc3986 { + /** @strict-properties */ + final readonly class Uri + { + public static function parse(string $uri, ?\Uri\Rfc3986\Uri $baseUrl = null): ?static {} + + public function __construct(string $uri, ?\Uri\Rfc3986\Uri $baseUrl = null) {} + + public function getScheme(): ?string {} + + public function getRawScheme(): ?string {} + + public function getUserInfo(): ?string {} + + public function getRawUserInfo(): ?string {} + + public function getUsername(): ?string {} + + public function getRawUsername(): ?string {} + + public function getPassword(): ?string {} + + public function getRawPassword(): ?string {} + + public function getHost(): ?string {} + + public function getRawHost(): ?string {} + + public function getPort(): ?int {} + + public function getPath(): string {} + + public function getRawPath(): string {} + + public function getQuery(): ?string {} + + public function getRawQuery(): ?string {} + + public function getFragment(): ?string {} + + public function getRawFragment(): ?string {} + + public function equals(\Uri\Rfc3986\Uri $uri, \Uri\UriComparisonMode $comparisonMode = \Uri\UriComparisonMode::ExcludeFragment): bool {} + + public function toString(): string {} + + public function toRawString(): string {} + + public function resolve(string $uri): static {} + + public function __serialize(): array {} + + public function __unserialize(array $data): void {} + + public function __debugInfo(): array {} + } +} + namespace Uri\WhatWg { /** @strict-properties */ class InvalidUrlException extends \Uri\InvalidUriException @@ -85,10 +143,12 @@ public function getScheme(): string {} public function withScheme(string $scheme): static {} + /** @implementation-alias Uri\Rfc3986\Uri::getUsername */ public function getUsername(): ?string {} public function withUsername(?string $username): static {} + /** @implementation-alias Uri\Rfc3986\Uri::getPassword */ public function getPassword(): ?string {} public function withPassword(#[\SensitiveParameter] ?string $password): static {} @@ -99,18 +159,22 @@ public function getUnicodeHost(): ?string {} public function withHost(?string $host): static {} + /** @implementation-alias Uri\Rfc3986\Uri::getPort */ public function getPort(): ?int {} public function withPort(?int $port): static {} + /** @implementation-alias Uri\Rfc3986\Uri::getPath */ public function getPath(): string {} public function withPath(string $path): static {} + /** @implementation-alias Uri\Rfc3986\Uri::getQuery */ public function getQuery(): ?string {} public function withQuery(?string $query): static {} + /** @implementation-alias Uri\Rfc3986\Uri::getFragment */ public function getFragment(): ?string {} public function withFragment(?string $fragment): static {} diff --git a/ext/uri/php_uri_arginfo.h b/ext/uri/php_uri_arginfo.h index 0ae755a9f70dc..65630f113a3d3 100644 --- a/ext/uri/php_uri_arginfo.h +++ b/ext/uri/php_uri_arginfo.h @@ -1,5 +1,74 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 1945c28deef13c2af552b18c2a5a6c7798d4aeec */ + * Stub hash: e2c448000b1e00485bc988f073ea61dfc984e953 */ + +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) + ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, baseUrl, Uri\\Rfc3986\\\125ri, 1, "null") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Uri_Rfc3986_Uri___construct, 0, 0, 1) + ZEND_ARG_TYPE_INFO(0, uri, IS_STRING, 0) + ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, baseUrl, Uri\\Rfc3986\\\125ri, 1, "null") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_getScheme, 0, 0, IS_STRING, 1) +ZEND_END_ARG_INFO() + +#define arginfo_class_Uri_Rfc3986_Uri_getRawScheme arginfo_class_Uri_Rfc3986_Uri_getScheme + +#define arginfo_class_Uri_Rfc3986_Uri_getUserInfo arginfo_class_Uri_Rfc3986_Uri_getScheme + +#define arginfo_class_Uri_Rfc3986_Uri_getRawUserInfo arginfo_class_Uri_Rfc3986_Uri_getScheme + +#define arginfo_class_Uri_Rfc3986_Uri_getUsername arginfo_class_Uri_Rfc3986_Uri_getScheme + +#define arginfo_class_Uri_Rfc3986_Uri_getRawUsername arginfo_class_Uri_Rfc3986_Uri_getScheme + +#define arginfo_class_Uri_Rfc3986_Uri_getPassword arginfo_class_Uri_Rfc3986_Uri_getScheme + +#define arginfo_class_Uri_Rfc3986_Uri_getRawPassword arginfo_class_Uri_Rfc3986_Uri_getScheme + +#define arginfo_class_Uri_Rfc3986_Uri_getHost arginfo_class_Uri_Rfc3986_Uri_getScheme + +#define arginfo_class_Uri_Rfc3986_Uri_getRawHost arginfo_class_Uri_Rfc3986_Uri_getScheme + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_getPort, 0, 0, IS_LONG, 1) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_getPath, 0, 0, IS_STRING, 0) +ZEND_END_ARG_INFO() + +#define arginfo_class_Uri_Rfc3986_Uri_getRawPath arginfo_class_Uri_Rfc3986_Uri_getPath + +#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 + +#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 + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_equals, 0, 1, _IS_BOOL, 0) + ZEND_ARG_OBJ_INFO(0, uri, Uri\\Rfc3986\\\125ri, 0) + ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, comparisonMode, Uri\\\125riComparisonMode, 0, "Uri\\UriComparisonMode::ExcludeFragment") +ZEND_END_ARG_INFO() + +#define arginfo_class_Uri_Rfc3986_Uri_toString arginfo_class_Uri_Rfc3986_Uri_getPath + +#define arginfo_class_Uri_Rfc3986_Uri_toRawString arginfo_class_Uri_Rfc3986_Uri_getPath + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_resolve, 0, 1, IS_STATIC, 0) + ZEND_ARG_TYPE_INFO(0, uri, IS_STRING, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri___serialize, 0, 0, IS_ARRAY, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri___unserialize, 0, 1, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) +ZEND_END_ARG_INFO() + +#define arginfo_class_Uri_Rfc3986_Uri___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, "\"\"") @@ -26,54 +95,51 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Uri_WhatWg_Url___construct, 0, 0, 1) ZEND_ARG_INFO_WITH_DEFAULT_VALUE(1, softErrors, "null") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_getScheme, 0, 0, IS_STRING, 0) -ZEND_END_ARG_INFO() +#define arginfo_class_Uri_WhatWg_Url_getScheme arginfo_class_Uri_Rfc3986_Uri_getPath ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_withScheme, 0, 1, IS_STATIC, 0) 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_getUsername, 0, 0, IS_STRING, 1) -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) ZEND_ARG_TYPE_INFO(0, username, IS_STRING, 1) ZEND_END_ARG_INFO() -#define arginfo_class_Uri_WhatWg_Url_getPassword arginfo_class_Uri_WhatWg_Url_getUsername +#define arginfo_class_Uri_WhatWg_Url_getPassword arginfo_class_Uri_Rfc3986_Uri_getScheme ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_withPassword, 0, 1, IS_STATIC, 0) ZEND_ARG_TYPE_INFO(0, password, IS_STRING, 1) ZEND_END_ARG_INFO() -#define arginfo_class_Uri_WhatWg_Url_getAsciiHost arginfo_class_Uri_WhatWg_Url_getUsername +#define arginfo_class_Uri_WhatWg_Url_getAsciiHost arginfo_class_Uri_Rfc3986_Uri_getScheme -#define arginfo_class_Uri_WhatWg_Url_getUnicodeHost arginfo_class_Uri_WhatWg_Url_getUsername +#define arginfo_class_Uri_WhatWg_Url_getUnicodeHost arginfo_class_Uri_Rfc3986_Uri_getScheme ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_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_WhatWg_Url_getPort, 0, 0, IS_LONG, 1) -ZEND_END_ARG_INFO() +#define arginfo_class_Uri_WhatWg_Url_getPort arginfo_class_Uri_Rfc3986_Uri_getPort ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_withPort, 0, 1, IS_STATIC, 0) ZEND_ARG_TYPE_INFO(0, port, IS_LONG, 1) ZEND_END_ARG_INFO() -#define arginfo_class_Uri_WhatWg_Url_getPath arginfo_class_Uri_WhatWg_Url_getScheme +#define arginfo_class_Uri_WhatWg_Url_getPath arginfo_class_Uri_Rfc3986_Uri_getPath ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_withPath, 0, 1, IS_STATIC, 0) ZEND_ARG_TYPE_INFO(0, path, IS_STRING, 0) ZEND_END_ARG_INFO() -#define arginfo_class_Uri_WhatWg_Url_getQuery arginfo_class_Uri_WhatWg_Url_getUsername +#define arginfo_class_Uri_WhatWg_Url_getQuery arginfo_class_Uri_Rfc3986_Uri_getScheme ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_withQuery, 0, 1, IS_STATIC, 0) ZEND_ARG_TYPE_INFO(0, query, IS_STRING, 1) ZEND_END_ARG_INFO() -#define arginfo_class_Uri_WhatWg_Url_getFragment arginfo_class_Uri_WhatWg_Url_getUsername +#define arginfo_class_Uri_WhatWg_Url_getFragment arginfo_class_Uri_Rfc3986_Uri_getScheme ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_withFragment, 0, 1, IS_STATIC, 0) ZEND_ARG_TYPE_INFO(0, fragment, IS_STRING, 1) @@ -84,44 +150,61 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_equals, 0, ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, comparisonMode, Uri\\\125riComparisonMode, 0, "Uri\\UriComparisonMode::ExcludeFragment") ZEND_END_ARG_INFO() -#define arginfo_class_Uri_WhatWg_Url_toAsciiString arginfo_class_Uri_WhatWg_Url_getScheme +#define arginfo_class_Uri_WhatWg_Url_toAsciiString arginfo_class_Uri_Rfc3986_Uri_getPath -#define arginfo_class_Uri_WhatWg_Url_toUnicodeString arginfo_class_Uri_WhatWg_Url_getScheme +#define arginfo_class_Uri_WhatWg_Url_toUnicodeString arginfo_class_Uri_Rfc3986_Uri_getPath ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_resolve, 0, 1, IS_STATIC, 0) ZEND_ARG_TYPE_INFO(0, uri, IS_STRING, 0) ZEND_ARG_INFO_WITH_DEFAULT_VALUE(1, softErrors, "null") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url___serialize, 0, 0, IS_ARRAY, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url___unserialize, 0, 1, IS_VOID, 0) - ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) -ZEND_END_ARG_INFO() - -#define arginfo_class_Uri_WhatWg_Url___debugInfo arginfo_class_Uri_WhatWg_Url___serialize - +#define arginfo_class_Uri_WhatWg_Url___serialize arginfo_class_Uri_Rfc3986_Uri___serialize + +#define arginfo_class_Uri_WhatWg_Url___unserialize arginfo_class_Uri_Rfc3986_Uri___unserialize + +#define arginfo_class_Uri_WhatWg_Url___debugInfo arginfo_class_Uri_Rfc3986_Uri___serialize + +ZEND_METHOD(Uri_Rfc3986_Uri, parse); +ZEND_METHOD(Uri_Rfc3986_Uri, __construct); +ZEND_METHOD(Uri_Rfc3986_Uri, getScheme); +ZEND_METHOD(Uri_Rfc3986_Uri, getRawScheme); +ZEND_METHOD(Uri_Rfc3986_Uri, getUserInfo); +ZEND_METHOD(Uri_Rfc3986_Uri, getRawUserInfo); +ZEND_METHOD(Uri_Rfc3986_Uri, getUsername); +ZEND_METHOD(Uri_Rfc3986_Uri, getRawUsername); +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, getPort); +ZEND_METHOD(Uri_Rfc3986_Uri, getPath); +ZEND_METHOD(Uri_Rfc3986_Uri, getRawPath); +ZEND_METHOD(Uri_Rfc3986_Uri, getQuery); +ZEND_METHOD(Uri_Rfc3986_Uri, getRawQuery); +ZEND_METHOD(Uri_Rfc3986_Uri, getFragment); +ZEND_METHOD(Uri_Rfc3986_Uri, getRawFragment); +ZEND_METHOD(Uri_Rfc3986_Uri, equals); +ZEND_METHOD(Uri_Rfc3986_Uri, toString); +ZEND_METHOD(Uri_Rfc3986_Uri, toRawString); +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_WhatWg_InvalidUrlException, __construct); ZEND_METHOD(Uri_WhatWg_UrlValidationError, __construct); 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, getUsername); ZEND_METHOD(Uri_WhatWg_Url, withUsername); -ZEND_METHOD(Uri_WhatWg_Url, getPassword); ZEND_METHOD(Uri_WhatWg_Url, withPassword); ZEND_METHOD(Uri_WhatWg_Url, getAsciiHost); ZEND_METHOD(Uri_WhatWg_Url, getUnicodeHost); ZEND_METHOD(Uri_WhatWg_Url, withHost); -ZEND_METHOD(Uri_WhatWg_Url, getPort); ZEND_METHOD(Uri_WhatWg_Url, withPort); -ZEND_METHOD(Uri_WhatWg_Url, getPath); ZEND_METHOD(Uri_WhatWg_Url, withPath); -ZEND_METHOD(Uri_WhatWg_Url, getQuery); ZEND_METHOD(Uri_WhatWg_Url, withQuery); -ZEND_METHOD(Uri_WhatWg_Url, getFragment); ZEND_METHOD(Uri_WhatWg_Url, withFragment); ZEND_METHOD(Uri_WhatWg_Url, equals); ZEND_METHOD(Uri_WhatWg_Url, toAsciiString); @@ -131,6 +214,36 @@ ZEND_METHOD(Uri_WhatWg_Url, __serialize); ZEND_METHOD(Uri_WhatWg_Url, __unserialize); ZEND_METHOD(Uri_WhatWg_Url, __debugInfo); +static const zend_function_entry class_Uri_Rfc3986_Uri_methods[] = { + 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) + ZEND_ME(Uri_Rfc3986_Uri, getRawScheme, arginfo_class_Uri_Rfc3986_Uri_getRawScheme, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, getUserInfo, arginfo_class_Uri_Rfc3986_Uri_getUserInfo, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, getRawUserInfo, arginfo_class_Uri_Rfc3986_Uri_getRawUserInfo, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, getUsername, arginfo_class_Uri_Rfc3986_Uri_getUsername, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, getRawUsername, arginfo_class_Uri_Rfc3986_Uri_getRawUsername, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, getPassword, arginfo_class_Uri_Rfc3986_Uri_getPassword, ZEND_ACC_PUBLIC) + 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, getPort, arginfo_class_Uri_Rfc3986_Uri_getPort, 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, 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, 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, equals, arginfo_class_Uri_Rfc3986_Uri_equals, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, toString, arginfo_class_Uri_Rfc3986_Uri_toString, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, toRawString, arginfo_class_Uri_Rfc3986_Uri_toRawString, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, resolve, arginfo_class_Uri_Rfc3986_Uri_resolve, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, __serialize, arginfo_class_Uri_Rfc3986_Uri___serialize, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, __unserialize, arginfo_class_Uri_Rfc3986_Uri___unserialize, ZEND_ACC_PUBLIC) + ZEND_ME(Uri_Rfc3986_Uri, __debugInfo, arginfo_class_Uri_Rfc3986_Uri___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 @@ -146,20 +259,20 @@ static const zend_function_entry class_Uri_WhatWg_Url_methods[] = { 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, getUsername, arginfo_class_Uri_WhatWg_Url_getUsername, 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_ME(Uri_WhatWg_Url, getPassword, arginfo_class_Uri_WhatWg_Url_getPassword, 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, withHost, arginfo_class_Uri_WhatWg_Url_withHost, ZEND_ACC_PUBLIC) - ZEND_ME(Uri_WhatWg_Url, getPort, arginfo_class_Uri_WhatWg_Url_getPort, ZEND_ACC_PUBLIC) + ZEND_RAW_FENTRY("getPort", zim_Uri_Rfc3986_Uri_getPort, arginfo_class_Uri_WhatWg_Url_getPort, ZEND_ACC_PUBLIC, NULL, NULL) ZEND_ME(Uri_WhatWg_Url, withPort, arginfo_class_Uri_WhatWg_Url_withPort, ZEND_ACC_PUBLIC) - ZEND_ME(Uri_WhatWg_Url, getPath, arginfo_class_Uri_WhatWg_Url_getPath, ZEND_ACC_PUBLIC) + 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, withPath, arginfo_class_Uri_WhatWg_Url_withPath, ZEND_ACC_PUBLIC) - ZEND_ME(Uri_WhatWg_Url, getQuery, arginfo_class_Uri_WhatWg_Url_getQuery, ZEND_ACC_PUBLIC) + 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, withQuery, arginfo_class_Uri_WhatWg_Url_withQuery, ZEND_ACC_PUBLIC) - ZEND_ME(Uri_WhatWg_Url, getFragment, arginfo_class_Uri_WhatWg_Url_getFragment, ZEND_ACC_PUBLIC) + ZEND_RAW_FENTRY("getFragment", zim_Uri_Rfc3986_Uri_getFragment, arginfo_class_Uri_WhatWg_Url_getFragment, ZEND_ACC_PUBLIC, NULL, NULL) ZEND_ME(Uri_WhatWg_Url, withFragment, arginfo_class_Uri_WhatWg_Url_withFragment, ZEND_ACC_PUBLIC) ZEND_ME(Uri_WhatWg_Url, equals, arginfo_class_Uri_WhatWg_Url_equals, ZEND_ACC_PUBLIC) ZEND_ME(Uri_WhatWg_Url, toAsciiString, arginfo_class_Uri_WhatWg_Url_toAsciiString, ZEND_ACC_PUBLIC) @@ -202,6 +315,16 @@ static zend_class_entry *register_class_Uri_UriComparisonMode(void) return class_entry; } +static zend_class_entry *register_class_Uri_Rfc3986_Uri(void) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "Uri\\Rfc3986", "Uri", class_Uri_Rfc3986_Uri_methods); + class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_READONLY_CLASS); + + return class_entry; +} + static zend_class_entry *register_class_Uri_WhatWg_InvalidUrlException(zend_class_entry *class_entry_Uri_InvalidUriException) { zend_class_entry ce, *class_entry; diff --git a/ext/uri/php_uri_common.h b/ext/uri/php_uri_common.h index 1aee1cd512472..8e5b0c2d2279f 100644 --- a/ext/uri/php_uri_common.h +++ b/ext/uri/php_uri_common.h @@ -17,6 +17,8 @@ #ifndef PHP_URI_COMMON_H #define PHP_URI_COMMON_H +extern zend_class_entry *uri_rfc3986_uri_ce; +extern zend_object_handlers uri_rfc3986_uri_object_handlers; extern zend_class_entry *uri_whatwg_url_ce; extern zend_object_handlers uri_whatwg_uri_object_handlers; extern zend_class_entry *uri_comparison_mode_ce; @@ -121,6 +123,7 @@ static inline uri_internal_t *uri_internal_from_obj(const zend_object *object) { #define Z_URI_OBJECT_P(zv) uri_object_from_obj(Z_OBJ_P((zv))) #define Z_URI_INTERNAL_P(zv) uri_internal_from_obj(Z_OBJ_P((zv))) +#define URI_PARSER_RFC3986 "Uri\\Rfc3986\\Uri" #define URI_PARSER_WHATWG "Uri\\WhatWg\\Url" #define URI_SERIALIZED_PROPERTY_NAME "uri" diff --git a/ext/uri/php_uriparser.c b/ext/uri/php_uriparser.c new file mode 100644 index 0000000000000..e707d6194d684 --- /dev/null +++ b/ext/uri/php_uriparser.c @@ -0,0 +1,525 @@ +/* + +----------------------------------------------------------------------+ + | 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 "php.h" +#include "php_uriparser.h" +#include "php_uri_common.h" +#include "Zend/zend_smart_str.h" +#include "Zend/zend_exceptions.h" + +void *uriparser_parse_uri(const zend_string *uri_str, const void *base_url, zval *errors, bool silent); +static void uriparser_free_uri(void *uri); +static void throw_invalid_uri_exception(void); + +HashTable uriparser_property_handlers; +UriMemoryManager uriparser_memory_manager; + +static void uriparser_copy_text_range(UriTextRangeA *text_range, UriTextRangeA *new_text_range, bool use_safe) +{ + if (text_range->first == NULL || text_range->afterLast == NULL || (text_range->first > text_range->afterLast && !use_safe)) { + new_text_range->first = NULL; + new_text_range->afterLast = NULL; + } else if (text_range->first >= text_range->afterLast && use_safe) { + new_text_range->first = uriSafeToPointToA; + new_text_range->afterLast = uriSafeToPointToA; + } else { + size_t length = (size_t) (text_range->afterLast - text_range->first); + char *dup = emalloc(length); + memcpy(dup, text_range->first, length); + + new_text_range->first = dup; + new_text_range->afterLast = dup + length; + } +} + +static UriUriA *uriparser_copy_uri(UriUriA *uriparser_uri) // TODO add to uriparser +{ + UriUriA *new_uriparser_uri = emalloc(sizeof(UriUriA)); + + uriparser_copy_text_range(&uriparser_uri->scheme, &new_uriparser_uri->scheme, false); + uriparser_copy_text_range(&uriparser_uri->userInfo, &new_uriparser_uri->userInfo, false); + uriparser_copy_text_range(&uriparser_uri->hostText, &new_uriparser_uri->hostText, true); + if (uriparser_uri->hostData.ip4 == NULL) { + new_uriparser_uri->hostData.ip4 = NULL; + } else { + new_uriparser_uri->hostData.ip4 = emalloc(sizeof(UriIp4)); + *(new_uriparser_uri->hostData.ip4) = *(uriparser_uri->hostData.ip4); + } + if (uriparser_uri->hostData.ip6 == NULL) { + new_uriparser_uri->hostData.ip6 = NULL; + } else { + new_uriparser_uri->hostData.ip6 = emalloc(sizeof(UriIp6)); + *(new_uriparser_uri->hostData.ip6) = *(uriparser_uri->hostData.ip6); + } + uriparser_copy_text_range(&uriparser_uri->hostData.ipFuture, &new_uriparser_uri->hostData.ipFuture, false); + uriparser_copy_text_range(&uriparser_uri->portText, &new_uriparser_uri->portText, false); + + if (uriparser_uri->pathHead != NULL && uriparser_uri->pathTail != NULL) { + new_uriparser_uri->pathHead = emalloc(sizeof(UriPathSegmentA)); + uriparser_copy_text_range(&uriparser_uri->pathHead->text, &new_uriparser_uri->pathHead->text, true); + new_uriparser_uri->pathHead->reserved = NULL; + + UriPathSegmentA *p = uriparser_uri->pathHead->next; + UriPathSegmentA *new_p = new_uriparser_uri->pathHead; + while (p != NULL && (p->text.first != p->text.afterLast || p->text.first == uriSafeToPointToA)) { + new_p->next = emalloc(sizeof(UriPathSegmentA)); + new_p = new_p->next; + uriparser_copy_text_range(&p->text, &new_p->text, true); + new_p->reserved = NULL; + p = p->next; + } + new_p->next = NULL; + new_uriparser_uri->pathTail = new_p; + } else { + new_uriparser_uri->pathHead = NULL; + new_uriparser_uri->pathTail = NULL; + } + + uriparser_copy_text_range(&uriparser_uri->query, &new_uriparser_uri->query, false); + uriparser_copy_text_range(&uriparser_uri->fragment, &new_uriparser_uri->fragment, false); + new_uriparser_uri->absolutePath = uriparser_uri->absolutePath; + new_uriparser_uri->owner = true; + new_uriparser_uri->reserved = NULL; + + return new_uriparser_uri; +} + +static zend_result uriparser_normalize_uri(UriUriA *uriparser_uri) +{ + if (uriNormalizeSyntaxExMmA(uriparser_uri, (unsigned int)-1, &uriparser_memory_manager) != URI_SUCCESS) { + return FAILURE; + } + + return SUCCESS; +} + +#define URIPARSER_READ_URI(uriparser_uri, uriparser_uris, read_mode) do { \ + if (read_mode == URI_COMPONENT_READ_RAW) { \ + uriparser_uri = (UriUriA *) uriparser_uris->uri; \ + } else if (read_mode == URI_COMPONENT_READ_NORMALIZED_UNICODE || read_mode == URI_COMPONENT_READ_NORMALIZED_ASCII) { \ + if (uriparser_uris->normalized_uri == NULL) { \ + uriparser_uris->normalized_uri = uriparser_copy_uri(uriparser_uris->uri); \ + if (uriparser_normalize_uri(uriparser_uris->normalized_uri) == FAILURE) { \ + return FAILURE; \ + } \ + } \ + uriparser_uri = uriparser_uris->normalized_uri; \ + } else { \ + ZEND_UNREACHABLE(); \ + } \ +} while (0) + +static zend_result uriparser_read_scheme(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + uriparser_uris_t *uriparser_uris = (uriparser_uris_t *) internal_uri->uri; + UriUriA *uriparser_uri; + URIPARSER_READ_URI(uriparser_uri, uriparser_uris, read_mode); + + if (uriparser_uri->scheme.first != NULL && uriparser_uri->scheme.afterLast != NULL) { + zend_string *str = zend_string_init(uriparser_uri->scheme.first, uriparser_uri->scheme.afterLast - uriparser_uri->scheme.first, false); + ZVAL_STR(retval, str); + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +zend_result uriparser_read_userinfo(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + uriparser_uris_t *uriparser_uris = (uriparser_uris_t *) internal_uri->uri; + UriUriA *uriparser_uri; + URIPARSER_READ_URI(uriparser_uri, uriparser_uris, read_mode); + + if (uriparser_uri->userInfo.first != NULL && uriparser_uri->userInfo.afterLast != NULL) { + ZVAL_STRINGL(retval, uriparser_uri->userInfo.first, uriparser_uri->userInfo.afterLast - uriparser_uri->userInfo.first); + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +static zend_result uriparser_read_username(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + uriparser_uris_t *uriparser_uris = (uriparser_uris_t *) internal_uri->uri; + UriUriA *uriparser_uri; + URIPARSER_READ_URI(uriparser_uri, uriparser_uris, read_mode); + + if (uriparser_uri->userInfo.first != NULL && uriparser_uri->userInfo.afterLast != NULL) { + char *c = strchr(uriparser_uri->userInfo.first, ':'); + if (c == NULL && uriparser_uri->userInfo.afterLast - uriparser_uri->userInfo.first > 0) { + ZVAL_STRINGL(retval, uriparser_uri->userInfo.first, uriparser_uri->userInfo.afterLast - uriparser_uri->userInfo.first); + } else if (c != NULL && c - uriparser_uri->userInfo.first > 0) { + ZVAL_STRINGL(retval, uriparser_uri->userInfo.first, c - uriparser_uri->userInfo.first); + } else { + ZVAL_NULL(retval); + } + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +static zend_result uriparser_read_password(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + uriparser_uris_t *uriparser_uris = (uriparser_uris_t *) internal_uri->uri; + UriUriA *uriparser_uri; + URIPARSER_READ_URI(uriparser_uri, uriparser_uris, read_mode); + + if (uriparser_uri->userInfo.first != NULL && uriparser_uri->userInfo.afterLast != NULL) { + char *c = strchr(uriparser_uri->userInfo.first, ':'); + if (c != NULL && uriparser_uri->userInfo.afterLast - c - 1 > 0) { + ZVAL_STRINGL(retval, c + 1, uriparser_uri->userInfo.afterLast - c - 1); + } else { + ZVAL_NULL(retval); + } + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +static zend_result uriparser_read_host(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + uriparser_uris_t *uriparser_uris = (uriparser_uris_t *) internal_uri->uri; + UriUriA *uriparser_uri; + URIPARSER_READ_URI(uriparser_uri, uriparser_uris, read_mode); + + if (uriparser_uri->hostText.first != NULL && uriparser_uri->hostText.afterLast != NULL && uriparser_uri->hostText.afterLast - uriparser_uri->hostText.first > 0) { + if (uriparser_uri->hostData.ip6 != NULL) { + smart_str host_str = {0}; + + smart_str_appendc(&host_str, '['); + smart_str_appendl(&host_str, uriparser_uri->hostText.first, uriparser_uri->hostText.afterLast - uriparser_uri->hostText.first); + smart_str_appendc(&host_str, ']'); + + ZVAL_STR(retval, smart_str_extract(&host_str)); + } else { + ZVAL_STRINGL(retval, uriparser_uri->hostText.first, uriparser_uri->hostText.afterLast - uriparser_uri->hostText.first); + } + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +static zend_result uriparser_read_port(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + uriparser_uris_t *uriparser_uris = (uriparser_uris_t *) internal_uri->uri; + UriUriA *uriparser_uri = uriparser_uris->uri; + + if (uriparser_uri->portText.first != NULL && uriparser_uri->portText.afterLast != NULL) { + ZVAL_LONG(retval, strtol(uriparser_uri->portText.first, NULL, 10)); + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +static zend_result uriparser_read_path(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + uriparser_uris_t *uriparser_uris = (uriparser_uris_t *) internal_uri->uri; + UriUriA *uriparser_uri; + URIPARSER_READ_URI(uriparser_uri, uriparser_uris, read_mode); + + if (uriparser_uri->pathHead != NULL) { + const UriPathSegmentA *p; + smart_str str = {0}; + + if (uriparser_uri->absolutePath || uriIsHostSetA(uriparser_uri)) { + smart_str_appends(&str, "/"); + } + + smart_str_appendl(&str, uriparser_uri->pathHead->text.first, (int) ((uriparser_uri->pathHead->text).afterLast - (uriparser_uri->pathHead->text).first)); + + for (p = uriparser_uri->pathHead->next; p != NULL; p = p->next) { + smart_str_appends(&str, "/"); + smart_str_appendl(&str, p->text.first, (int) ((p->text).afterLast - (p->text).first)); + } + + ZVAL_STR(retval, smart_str_extract(&str)); + } else if (uriparser_uri->absolutePath) { + ZVAL_CHAR(retval, '/'); + } else { + ZVAL_EMPTY_STRING(retval); + } + + return SUCCESS; +} + +static zend_result uriparser_read_query(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + uriparser_uris_t *uriparser_uris = (uriparser_uris_t *) internal_uri->uri; + UriUriA *uriparser_uri; + URIPARSER_READ_URI(uriparser_uri, uriparser_uris, read_mode); + + if (uriparser_uri->query.first != NULL && uriparser_uri->query.afterLast != NULL) { + ZVAL_STRINGL(retval, uriparser_uri->query.first, uriparser_uri->query.afterLast - uriparser_uri->query.first); + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +static zend_result uriparser_read_fragment(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + uriparser_uris_t *uriparser_uris = (uriparser_uris_t *) internal_uri->uri; + UriUriA *uriparser_uri; + URIPARSER_READ_URI(uriparser_uri, uriparser_uris, read_mode); + + if (uriparser_uri->fragment.first != NULL && uriparser_uri->fragment.afterLast != NULL) { + ZVAL_STRINGL(retval, uriparser_uri->fragment.first, uriparser_uri->fragment.afterLast - uriparser_uri->fragment.first); + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +static void *uriparser_malloc(UriMemoryManager *memory_manager, size_t size) +{ + return emalloc(size); +} + +static void *uriparser_calloc(UriMemoryManager *memory_manager, size_t nmemb, size_t size) +{ + return ecalloc(nmemb, size); +} + +static void *uriparser_realloc(UriMemoryManager *memory_manager, void *ptr, size_t size) +{ + return realloc(ptr, size); +} + +static void *uriparser_reallocarray(UriMemoryManager *memory_manager, void *ptr, size_t nmemb, size_t size) +{ + const size_t total_size = nmemb * size; + + /* check for unsigned overflow */ + if ((nmemb != 0) && (total_size / nmemb != size)) { + errno = ENOMEM; + return NULL; + } + + return erealloc(ptr, total_size); +} + +static void uriparser_free(UriMemoryManager *memory_manager, void *ptr) +{ + efree(ptr); +} + +zend_result uriparser_request_init(void) +{ + uriparser_memory_manager.calloc = uriparser_calloc; + uriparser_memory_manager.malloc = uriparser_malloc; + uriparser_memory_manager.realloc = uriparser_realloc; + uriparser_memory_manager.reallocarray = uriparser_reallocarray; + uriparser_memory_manager.free = uriparser_free; + + zend_hash_init(&uriparser_property_handlers, 8, NULL, NULL, true); + + return SUCCESS; +} + +static uriparser_uris_t *uriparser_create_uris( + UriUriA *uri, zend_string *uri_str, + UriUriA *normalized_uri, zend_string *normalized_uri_str +) { + uriparser_uris_t *uriparser_uris = emalloc(sizeof(uriparser_uris_t)); + + uriparser_uris->uri = uri; + uriparser_uris->uri_str = uri_str; + uriparser_uris->normalized_uri = normalized_uri; + uriparser_uris->normalized_uri_str = normalized_uri_str; + + return uriparser_uris; +} + +static void throw_invalid_uri_exception(void) +{ + zval exception; + + object_init_ex(&exception, uri_invalid_uri_exception_ce); + + zval value; + ZVAL_STRING(&value, "URI parsing failed"); + zend_update_property_ex(uri_whatwg_invalid_url_exception_ce, Z_OBJ(exception), ZSTR_KNOWN(ZEND_STR_MESSAGE), &value); + zval_ptr_dtor_str(&value); + + zend_throw_exception_object(&exception); +} + +void *uriparser_parse_uri_ex(const zend_string *uri_str, const uriparser_uris_t *uriparser_base_urls, bool silent) +{ + UriUriA *uriparser_uri = emalloc(sizeof(UriUriA)); + + /* uriparser keeps the originally passed in string, while lexbor may allocate a new one. */ + zend_string *original_uri_str = zend_string_init(ZSTR_VAL(uri_str), ZSTR_LEN(uri_str), false); + if (ZSTR_LEN(original_uri_str) == 0 || + uriParseSingleUriExMmA(uriparser_uri, ZSTR_VAL(original_uri_str), ZSTR_VAL(original_uri_str) + ZSTR_LEN(original_uri_str), NULL, &uriparser_memory_manager) != URI_SUCCESS + ) { + efree(uriparser_uri); + zend_string_release_ex(original_uri_str, false); + if (!silent) { + throw_invalid_uri_exception(); + } + + return NULL; + } + + if (uriparser_base_urls == NULL) { + return uriparser_create_uris(uriparser_uri, original_uri_str, NULL, NULL); + } + + UriUriA *uriparser_base_url = uriparser_copy_uri(uriparser_base_urls->uri); + + UriUriA *absolute_uri = emalloc(sizeof(UriUriA)); + + if (uriAddBaseUriExMmA(absolute_uri, uriparser_uri, uriparser_base_url, URI_RESOLVE_STRICTLY, &uriparser_memory_manager) != URI_SUCCESS) { + zend_string_release_ex(original_uri_str, false); + uriFreeUriMembersMmA(uriparser_uri, &uriparser_memory_manager); + efree(uriparser_uri); + uriFreeUriMembersMmA(uriparser_base_url, &uriparser_memory_manager); + efree(uriparser_base_url); + efree(absolute_uri); + + if (!silent) { + throw_invalid_uri_exception(); + } + + return NULL; + } + + /* TODO fix freeing: if the following code runs, then we'll have use-after-free-s because uriparser doesn't + copy the input. If we don't run the following code, then we'll have memory leaks... + uriFreeUriMembersMmA(uriparser_base_url, &uriparser_memory_manager); + efree(uriparser_base_url); + uriFreeUriMembersMmA(uriparser_uri, &uriparser_memory_manager); + efree(uriparser_uri); + */ + + return uriparser_create_uris(absolute_uri, original_uri_str, NULL, NULL); +} + +void *uriparser_parse_uri(const zend_string *uri_str, const void *base_url, zval *errors, bool silent) +{ + return uriparser_parse_uri_ex(uri_str, base_url, silent); +} + +static void *uriparser_clone_uri(void *uri) +{ + uriparser_uris_t *uriparser_uris = (uriparser_uris_t *) uri; + + return uriparser_create_uris( + uriparser_copy_uri(uriparser_uris->uri), + zend_string_copy(uriparser_uris->uri_str), + uriparser_uris->normalized_uri != NULL ? uriparser_copy_uri(uriparser_uris->normalized_uri) : NULL, + uriparser_uris->normalized_uri_str != NULL ? zend_string_copy(uriparser_uris->normalized_uri_str) : NULL + ); +} + +static zend_string *uriparser_uri_to_string(void *uri, uri_recomposition_mode_t recomposition_mode, bool exclude_fragment) +{ + uriparser_uris_t *uriparser_uris = (uriparser_uris_t *) uri; + UriUriA *uriparser_uri = uriparser_uris->uri; + + if ((recomposition_mode == URI_RECOMPOSITION_NORMALIZED_UNICODE || recomposition_mode == URI_RECOMPOSITION_NORMALIZED_ASCII) && + uriparser_uris->normalized_uri == NULL + ) { + uriparser_uris->normalized_uri = uriparser_copy_uri(uriparser_uris->uri); + if (uriparser_normalize_uri(uriparser_uris->normalized_uri) == FAILURE) { + return NULL; + } + uriparser_uri = uriparser_uris->normalized_uri; + } + + int charsRequired; + if (uriToStringCharsRequiredA(uriparser_uri, &charsRequired) != URI_SUCCESS) { + return NULL; + } + + charsRequired++; + + zend_string *uri_string = zend_string_alloc(charsRequired - 1, false); + if (uriToStringA(ZSTR_VAL(uri_string), uriparser_uri, charsRequired, NULL) != URI_SUCCESS) { + zend_string_release(uri_string); + return NULL; + } + + if (exclude_fragment) { + char *pos = strrchr(ZSTR_VAL(uri_string), '#'); + if (pos != NULL) { + uri_string = zend_string_truncate(uri_string, (pos - ZSTR_VAL(uri_string)), false); + } + } + + return uri_string; +} + +static void uriparser_free_uri(void *uri) +{ + uriparser_uris_t *uriparser_uris = (uriparser_uris_t *) uri; + + if (uriparser_uris->uri != NULL) { + if (uriparser_uris->uri_str != NULL) { // TODO can this double free? should we check uriparser_uris->uri->owner? + zend_string_release(uriparser_uris->uri_str); + uriparser_uris->uri_str = NULL; + } + + uriFreeUriMembersMmA(uriparser_uris->uri, &uriparser_memory_manager); + efree(uriparser_uris->uri); + uriparser_uris->uri = NULL; + } + + if (uriparser_uris->normalized_uri != NULL) { + ZEND_ASSERT(uriparser_uris->normalized_uri->owner); + if (uriparser_uris->normalized_uri_str != NULL) { + zend_string_release(uriparser_uris->normalized_uri_str); + uriparser_uris->normalized_uri_str = NULL; + } + + uriFreeUriMembersMmA(uriparser_uris->normalized_uri, &uriparser_memory_manager); + efree(uriparser_uris->normalized_uri); + uriparser_uris->normalized_uri = NULL; + } + + efree(uriparser_uris); +} + +const uri_handler_t uriparser_uri_handler = { + .name = URI_PARSER_RFC3986, + .parse_uri = uriparser_parse_uri, + .clone_uri = uriparser_clone_uri, + .uri_to_string = uriparser_uri_to_string, + .free_uri = uriparser_free_uri, + { + .scheme = {.read_func = uriparser_read_scheme, .write_func = NULL}, + .username = {.read_func = uriparser_read_username, .write_func = NULL}, + .password = {.read_func = uriparser_read_password, .write_func = NULL}, + .host = {.read_func = uriparser_read_host, .write_func = NULL}, + .port = {.read_func = uriparser_read_port, .write_func = NULL}, + .path = {.read_func = uriparser_read_path, .write_func = NULL}, + .query = {.read_func = uriparser_read_query, .write_func = NULL}, + .fragment = {.read_func = uriparser_read_fragment, .write_func = NULL}, + } +}; diff --git a/ext/uri/php_uriparser.h b/ext/uri/php_uriparser.h new file mode 100644 index 0000000000000..3ea27cf1a8b91 --- /dev/null +++ b/ext/uri/php_uriparser.h @@ -0,0 +1,38 @@ +/* + +----------------------------------------------------------------------+ + | 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_URIPARSER_H +#define PHP_URIPARSER_H + +#include +#include + +extern const uri_handler_t uriparser_uri_handler; + +typedef struct uriparser_uris_t { + UriUriA *uri; + zend_string *uri_str; + UriUriA *normalized_uri; + zend_string *normalized_uri_str; +} uriparser_uris_t; + +zend_result uriparser_request_init(void); + +zend_result uriparser_read_userinfo(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval); + +void *uriparser_parse_uri_ex(const zend_string *uri_str, const uriparser_uris_t *uriparser_base_url, bool silent); + +#endif diff --git a/ext/uri/tests/003.phpt b/ext/uri/tests/003.phpt index bcd6e417441c2..be607fd6cacef 100644 --- a/ext/uri/tests/003.phpt +++ b/ext/uri/tests/003.phpt @@ -5,12 +5,15 @@ uri --FILE-- --EXPECTF-- +NULL object(Uri\WhatWg\Url)#%d (%d) { ["scheme"]=> string(4) "http" @@ -29,4 +32,22 @@ object(Uri\WhatWg\Url)#%d (%d) { ["fragment"]=> string(6) "anchor" } +object(Uri\Rfc3986\Uri)#%d (%d) { + ["scheme"]=> + NULL + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + NULL + ["port"]=> + NULL + ["path"]=> + string(7) "/page:1" + ["query"]=> + NULL + ["fragment"]=> + NULL +} NULL diff --git a/ext/uri/tests/004.phpt b/ext/uri/tests/004.phpt index abbad59fee2e8..783ac4048ac26 100644 --- a/ext/uri/tests/004.phpt +++ b/ext/uri/tests/004.phpt @@ -5,6 +5,14 @@ uri --FILE-- getMessage() . "\n"; +} + +var_dump(Uri\Rfc3986\Uri::parse("")); + try { new Uri\WhatWg\Url(""); } catch (Uri\WhatWg\InvalidUrlException $e) { @@ -13,13 +21,36 @@ try { var_dump(Uri\WhatWg\Url::parse("")); +var_dump(Uri\Rfc3986\Uri::parse("192.168/contact.html")); var_dump(Uri\WhatWg\Url::parse("192.168/contact.html", null)); +var_dump(Uri\Rfc3986\Uri::parse("http://RuPaul's Drag Race All Stars 7 Winners Cast on This Season's")); var_dump(Uri\WhatWg\Url::parse("http://RuPaul's Drag Race All Stars 7 Winners Cast on This Season's", null)); ?> ---EXPECT-- +--EXPECTF-- The specified URI is malformed (MissingSchemeNonRelativeUrl) NULL +The specified URI is malformed (MissingSchemeNonRelativeUrl) +NULL +object(Uri\Rfc3986\Uri)#%d (%d) { + ["scheme"]=> + NULL + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + NULL + ["port"]=> + NULL + ["path"]=> + string(20) "192.168/contact.html" + ["query"]=> + NULL + ["fragment"]=> + NULL +} +NULL NULL NULL diff --git a/ext/uri/tests/005.phpt b/ext/uri/tests/005.phpt index 262d43a75406b..6db6c4a56ee5a 100644 --- a/ext/uri/tests/005.phpt +++ b/ext/uri/tests/005.phpt @@ -5,6 +5,8 @@ uri --FILE-- getAsciiHost()); @@ -14,6 +16,7 @@ var_dump($url->toUnicodeString()); ?> --EXPECTF-- +NULL object(Uri\WhatWg\Url)#%d (%d) { ["scheme"]=> string(4) "http" diff --git a/ext/uri/tests/006.phpt b/ext/uri/tests/006.phpt index 0aba3e9e46b5e..c4da9db905c82 100644 --- a/ext/uri/tests/006.phpt +++ b/ext/uri/tests/006.phpt @@ -5,11 +5,32 @@ uri --FILE-- --EXPECTF-- +object(Uri\Rfc3986\Uri)#%d (%d) { + ["scheme"]=> + string(5) "https" + ["username"]=> + string(8) "username" + ["password"]=> + string(8) "password" + ["host"]=> + string(11) "example.com" + ["port"]=> + int(8080) + ["path"]=> + string(5) "/path" + ["query"]=> + string(3) "q=r" + ["fragment"]=> + string(8) "fragment" +} object(Uri\WhatWg\Url)#%d (%d) { ["scheme"]=> string(5) "https" diff --git a/ext/uri/tests/007.phpt b/ext/uri/tests/007.phpt index cb445fcf71a43..7a25239eeb51a 100644 --- a/ext/uri/tests/007.phpt +++ b/ext/uri/tests/007.phpt @@ -5,6 +5,12 @@ uri --FILE-- getMessage() . "\n"; +} + try { new Uri\WhatWg\Url("https://example.com:8080@username:password/path?q=r#fragment"); } catch (Uri\WhatWg\InvalidUrlException $e) { @@ -20,6 +26,7 @@ var_dump($failures); ?> --EXPECTF-- The specified URI is malformed (PortInvalid) +The specified URI is malformed (PortInvalid) array(%d) { [0]=> object(Uri\WhatWg\UrlValidationError)#%d (%d) { diff --git a/ext/uri/tests/008.phpt b/ext/uri/tests/008.phpt index f4fddcd8eb777..e13130bb4c466 100644 --- a/ext/uri/tests/008.phpt +++ b/ext/uri/tests/008.phpt @@ -5,6 +5,27 @@ uri --FILE-- getScheme()); + var_dump($uri->getRawScheme()); + var_dump($uri->getUsername()); + var_dump($uri->getRawUsername()); + var_dump($uri->getPassword()); + var_dump($uri->getRawPassword()); + var_dump($uri->getUserInfo()); + var_dump($uri->getRawUserInfo()); + var_dump($uri->getHost()); + var_dump($uri->getRawHost()); + var_dump($uri->getPort()); + var_dump($uri->getPath()); + var_dump($uri->getRawPath()); + var_dump($uri->getQuery()); + var_dump($uri->getRawQuery()); + var_dump($uri->getFragment()); + var_dump($uri->getRawFragment()); +} + function callWhatWgGetters($url) { var_dump($url->getScheme()); @@ -18,11 +39,34 @@ function callWhatWgGetters($url) var_dump($url->getFragment()); } +$uri = Uri\Rfc3986\Uri::parse("https://username:password@www.google.com:8080/pathname1/pathname2/pathname3?query=true#hash-exists"); +callRfc3986Getters($uri); + +echo "\n"; + $url = Uri\WhatWg\Url::parse("https://username:password@www.google.com:8080/pathname1/pathname2/pathname3?query=true#hash-exists"); callWhatWgGetters($url); ?> --EXPECT-- +string(5) "https" +string(5) "https" +string(8) "username" +string(8) "username" +string(8) "password" +string(8) "password" +string(17) "username:password" +string(17) "username:password" +string(14) "www.google.com" +string(14) "www.google.com" +int(8080) +string(30) "/pathname1/pathname2/pathname3" +string(30) "/pathname1/pathname2/pathname3" +string(10) "query=true" +string(10) "query=true" +string(11) "hash-exists" +string(11) "hash-exists" + string(5) "https" string(8) "username" string(8) "password" diff --git a/ext/uri/tests/009.phpt b/ext/uri/tests/009.phpt index 1b279588c0167..05f2820bb3fcf 100644 --- a/ext/uri/tests/009.phpt +++ b/ext/uri/tests/009.phpt @@ -5,10 +5,29 @@ uri --FILE-- --EXPECTF-- +object(Uri\Rfc3986\Uri)#%d (%d) { + ["scheme"]=> + string(16) "chrome-extension" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(0) "" + ["query"]=> + NULL + ["fragment"]=> + NULL +} object(Uri\WhatWg\Url)#%d (%d) { ["scheme"]=> string(16) "chrome-extension" diff --git a/ext/uri/tests/010.phpt b/ext/uri/tests/010.phpt index 4ec13f652f60c..2ca071eb2ca33 100644 --- a/ext/uri/tests/010.phpt +++ b/ext/uri/tests/010.phpt @@ -5,11 +5,49 @@ uri --FILE-- --EXPECTF-- +object(Uri\Rfc3986\Uri)#%d (%d) { + ["scheme"]=> + string(4) "http" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(14) "/path/to/file2" + ["query"]=> + NULL + ["fragment"]=> + NULL +} +object(Uri\Rfc3986\Uri)#%d (%d) { + ["scheme"]=> + string(5) "https" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(8) "test.com" + ["port"]=> + NULL + ["path"]=> + string(14) "/path/to/file2" + ["query"]=> + NULL + ["fragment"]=> + NULL +} object(Uri\WhatWg\Url)#%d (%d) { ["scheme"]=> string(4) "http" diff --git a/ext/uri/tests/011.phpt b/ext/uri/tests/011.phpt index 283886fb34fbb..49b915fa22a31 100644 --- a/ext/uri/tests/011.phpt +++ b/ext/uri/tests/011.phpt @@ -5,6 +5,12 @@ uri --FILE-- toRawString()); +var_dump(Uri\Rfc3986\Uri::parse("https://www.example.com/dir1/../dir2")->toRawString()); +var_dump(Uri\Rfc3986\Uri::parse("https://你好你好")); +var_dump(Uri\Rfc3986\Uri::parse("https://0Xc0.0250.01")); +var_dump(Uri\Rfc3986\Uri::parse("HttPs://0300.0250.0000.0001/path?query=foo%20bar")->toRawString()); + var_dump(Uri\WhatWg\Url::parse("http://////www.EXAMPLE.com:80")->toAsciiString()); var_dump(Uri\WhatWg\Url::parse("https://www.example.com:443/dir1/../dir2")->toAsciiString()); var_dump(Uri\WhatWg\Url::parse("https://你好你好")->toAsciiString()); @@ -14,6 +20,11 @@ var_dump(Uri\WhatWg\Url::parse("HttPs://0300.0250.0000.0001/path?query=foo%20bar ?> --EXPECT-- +string(29) "http://////www.EXAMPLE.com:80" +string(36) "https://www.example.com/dir1/../dir2" +NULL +NULL +string(48) "HttPs://0300.0250.0000.0001/path?query=foo%20bar" string(23) "http://www.example.com/" string(28) "https://www.example.com/dir2" string(23) "https://xn--6qqa088eba/" diff --git a/ext/uri/tests/012.phpt b/ext/uri/tests/012.phpt index 0784a74e625f0..7c14014fb3519 100644 --- a/ext/uri/tests/012.phpt +++ b/ext/uri/tests/012.phpt @@ -5,12 +5,32 @@ uri --FILE-- --EXPECTF-- +object(Uri\Rfc3986\Uri)#%d (%d) { + ["scheme"]=> + string(6) "mailto" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + NULL + ["port"]=> + NULL + ["path"]=> + string(15) "Joe@Example.COM" + ["query"]=> + NULL + ["fragment"]=> + NULL +} object(Uri\WhatWg\Url)#%d (%d) { ["scheme"]=> string(6) "mailto" @@ -29,6 +49,24 @@ object(Uri\WhatWg\Url)#%d (%d) { ["fragment"]=> NULL } +object(Uri\Rfc3986\Uri)#%d (%d) { + ["scheme"]=> + string(4) "file" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + NULL + ["port"]=> + NULL + ["path"]=> + string(30) "/E:/Documents%20and%20Settings" + ["query"]=> + NULL + ["fragment"]=> + NULL +} object(Uri\WhatWg\Url)#%d (%d) { ["scheme"]=> string(4) "file" diff --git a/ext/uri/tests/013.phpt b/ext/uri/tests/013.phpt index 016fe6632782c..6a5bb31870fb1 100644 --- a/ext/uri/tests/013.phpt +++ b/ext/uri/tests/013.phpt @@ -5,14 +5,39 @@ uri --FILE-- + @")); + var_dump(Uri\WhatWg\Url::parse("http://example.com?foobar=%27%3Cscript%3E+%2B+%40")); var_dump(Uri\WhatWg\Url::parse("http://example.com?foobar='