diff --git a/.github/scripts/windows/build.bat b/.github/scripts/windows/build.bat index 65f40fb9462a7..b7beb3a7ef4ba 100644 --- a/.github/scripts/windows/build.bat +++ b/.github/scripts/windows/build.bat @@ -41,7 +41,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 1a24564697219..b8cc501e0cf3f 100644 --- a/.github/scripts/windows/test.bat +++ b/.github/scripts/windows/test.bat @@ -9,7 +9,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/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/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 ------------------------------------------------------------------------------- diff --git a/NEWS b/NEWS index b1100f7672226..fe91a1f30ef74 100644 --- a/NEWS +++ b/NEWS @@ -54,7 +54,12 @@ 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) + . 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) @@ -129,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. @@ -147,6 +155,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 @@ -198,6 +209,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. @@ -236,12 +249,26 @@ 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) + . 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 (Michael Orlitzky). . 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) + . 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 7025c9778e7ac..4d968ef4daf80 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 ======================================== @@ -146,6 +151,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 @@ -198,9 +205,28 @@ 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(). + . 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. + +- Sqlite: + . Added class constants Sqlite3Stmt::EXPLAIN_MODE_PREPARED, + 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(), @@ -263,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. @@ -348,6 +376,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 @@ -390,6 +420,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 @@ -582,6 +616,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/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 574d5f0827ff7..acc9612b72e30 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 @@ -34,6 +40,11 @@ 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. + . ZEND_IS_XDIGIT() macro was removed because it was unused and its name + did not match its actual behavior. ======================== 2. Build system changes @@ -46,9 +57,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/Zend/Optimizer/zend_func_infos.h b/Zend/Optimizer/zend_func_infos.h index 3655e5fd21c35..e6a8cea559bc8 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), @@ -394,8 +395,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), @@ -404,13 +403,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/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/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-- 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/closures/gh12073.phpt b/Zend/tests/closures/gh12073.phpt index ef115685ce7d4..811da788d03fc 100644 --- a/Zend/tests/closures/gh12073.phpt +++ b/Zend/tests/closures/gh12073.phpt @@ -2,6 +2,9 @@ GH-12073: Freeing of non-ZMM pointer of incompletely allocated closure --SKIPIF-- 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/gh11189.phpt b/Zend/tests/gh11189.phpt index f1c877f20ee47..adbc3ce487c95 100644 --- a/Zend/tests/gh11189.phpt +++ b/Zend/tests/gh11189.phpt @@ -2,6 +2,9 @@ GH-11189: Exceeding memory limit in zend_hash_do_resize leaves the array in an invalid state (packed array) --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-- 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/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/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/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/tests/traits/bugs/gh13177.phpt b/Zend/tests/traits/bugs/gh13177.phpt index 42ef0ae9d60d7..1787b3c6bd7c2 100644 --- a/Zend/tests/traits/bugs/gh13177.phpt +++ b/Zend/tests/traits/bugs/gh13177.phpt @@ -1,5 +1,11 @@ --TEST-- GH-13177 (PHP 8.3.2: final private constructor not allowed when used in trait) +--SKIPIF-- + --FILE-- field; + } +} + +echo new MyClass; + +?> +--EXPECT-- +my string diff --git a/Zend/zend_API.c b/Zend/zend_API.c index e0006e7d7275f..df8b4252c42ad 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; @@ -3641,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_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_alloc.c b/Zend/zend_alloc.c index 5a1c19e09d19d..f2f801db63396 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -2432,6 +2432,7 @@ ZEND_API void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent) } #if ZEND_MM_STAT heap->size = 0; + heap->real_size = 0; #endif } @@ -2999,6 +3000,7 @@ static void *tracked_malloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC tracked_add(heap, ptr, size); #if ZEND_MM_STAT heap->size += size; + heap->real_size = heap->size; #endif return ptr; } @@ -3012,6 +3014,7 @@ static void tracked_free(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) { zval *size_zv = tracked_get_size_zv(heap, ptr); #if ZEND_MM_STAT heap->size -= Z_LVAL_P(size_zv); + heap->real_size = heap->size; #endif zend_hash_del_bucket(heap->tracked_allocs, (Bucket *) size_zv); free(ptr); @@ -3039,6 +3042,7 @@ static void *tracked_realloc(void *ptr, size_t new_size ZEND_FILE_LINE_DC ZEND_F tracked_add(heap, ptr, new_size); #if ZEND_MM_STAT heap->size += new_size - old_size; + heap->real_size = heap->size; #endif return ptr; } diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index beecf51216a94..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: @@ -2795,6 +2793,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_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 2bc0cf7b703d9..f3f6d1b75aec1 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; @@ -4936,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")) { @@ -5004,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; } @@ -5397,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]; @@ -7681,7 +7680,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; @@ -11723,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_exceptions.c b/Zend/zend_exceptions.c index 7777c5fa62e48..212fe3cb7ab66 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); @@ -980,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_exceptions.h b/Zend/zend_exceptions.h index d0138021d1ea3..35f6699559421 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(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); ZEND_NORETURN void zend_exception_uncaught_error(const char *prefix, ...) ZEND_ATTRIBUTE_FORMAT(printf, 1, 2); 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_object_handlers.c b/Zend/zend_object_handlers.c index f79023ade1c25..3d782b03fe174 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -722,7 +722,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; } @@ -2440,8 +2442,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/Zend/zend_objects_API.c b/Zend/zend_objects_API.c index 9b1b6dd4fcbb4..c19873cf3be30 100644 --- a/Zend/zend_objects_API.c +++ b/Zend/zend_objects_API.c @@ -100,7 +100,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); } diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index 140734d1b9602..712a6039dfb14 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))) { - zend_string_release(op1_string); - zend_string_release(op2_string); + op2_string = zval_try_get_string_func(op2); + if (UNEXPECTED(!op2_string)) { + zend_string_release_ex(op1_string, false); if (orig_op1 != result) { ZVAL_UNDEF(result); } @@ -2071,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); @@ -2095,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; @@ -2114,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; } 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) 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/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); } } diff --git a/Zend/zend_string.h b/Zend/zend_string.h index e9e2b947a6c91..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") \ @@ -597,7 +598,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/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 13ef9e60f334d..a3dd14a562346 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; } @@ -2749,23 +2752,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; } @@ -3055,6 +3050,9 @@ 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", + "clone" => "ZEND_STR_CLONE", ]; /** @@ -3554,9 +3552,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); @@ -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); } @@ -5190,9 +5190,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"; @@ -5311,6 +5313,8 @@ function generateGlobalConstantAttributeInitialization( $constInfos, "", static function (ConstInfo $constInfo) use ($allConstInfos, $phpVersionIdMinimumCompatibility) { + $code = ""; + if ($constInfo->attributes === []) { return null; } 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 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. */ 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)); diff --git a/ext/calendar/calendar.c b/ext/calendar/calendar.c index 0f9a4b99a37bc..4cb6a2fa9a08a 100644 --- a/ext/calendar/calendar.c +++ b/ext/calendar/calendar.c @@ -493,6 +493,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 d86cb57067368..19b87316eb143 100644 --- a/ext/calendar/jewish.c +++ b/ext/calendar/jewish.c @@ -710,7 +710,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 + 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) 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/curl/curl_private.h b/ext/curl/curl_private.h index dc23b5910cfbc..df6fd691a2a75 100644 --- a/ext/curl/curl_private.h +++ b/ext/curl/curl_private.h @@ -150,6 +150,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 a5adcb05b4339..710f98a13fbb0 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -624,7 +624,7 @@ static size_t curl_write(char *data, size_t size, size_t nmemb, void *ctx) if (!Z_ISUNDEF(retval)) { _php_curl_verify_handlers(ch, /* reporterror */ true); /* TODO Check callback returns an int or something castable to int */ - length = zval_get_long(&retval); + length = php_curl_get_long(&retval); } zval_ptr_dtor(&argv[0]); @@ -657,7 +657,7 @@ static int curl_fnmatch(void *ctx, const char *pattern, const char *string) if (!Z_ISUNDEF(retval)) { _php_curl_verify_handlers(ch, /* reporterror */ true); /* TODO Check callback returns an int or something castable to int */ - rval = zval_get_long(&retval); + rval = php_curl_get_long(&retval); } zval_ptr_dtor(&argv[0]); zval_ptr_dtor(&argv[1]); @@ -694,7 +694,7 @@ static size_t curl_progress(void *clientp, double dltotal, double dlnow, double if (!Z_ISUNDEF(retval)) { _php_curl_verify_handlers(ch, /* reporterror */ true); /* TODO Check callback returns an int or something castable to int */ - if (0 != zval_get_long(&retval)) { + if (0 != php_curl_get_long(&retval)) { rval = 1; } } @@ -732,7 +732,7 @@ static size_t curl_xferinfo(void *clientp, curl_off_t dltotal, curl_off_t dlnow, if (!Z_ISUNDEF(retval)) { _php_curl_verify_handlers(ch, /* reporterror */ true); /* TODO Check callback returns an int or something castable to int */ - if (0 != zval_get_long(&retval)) { + if (0 != php_curl_get_long(&retval)) { rval = 1; } } @@ -831,6 +831,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); } } @@ -925,7 +926,7 @@ static size_t curl_write_header(char *data, size_t size, size_t nmemb, void *ctx if (!Z_ISUNDEF(retval)) { // TODO: Check for valid int type for return value _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]); @@ -1343,6 +1344,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; + } +} + static size_t read_cb(char *buffer, size_t size, size_t nitems, void *arg) /* {{{ */ { struct mime_data_cb_arg *cb_arg = (struct mime_data_cb_arg *) arg; diff --git a/ext/curl/multi.c b/ext/curl/multi.c index f664bc05e0e89..a16155759aed4 100644 --- a/ext/curl/multi.c +++ b/ext/curl/multi.c @@ -435,7 +435,7 @@ static int _php_server_push_callback(CURL *parent_ch, CURL *easy, size_t num_hea zval_ptr_dtor_nogc(&headers); 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/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/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 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/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 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..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, XML_ENTITY_NODE, intern, entityht, NULL, NULL); + 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, XML_NOTATION_NODE, intern, notationht, NULL, NULL); + 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 a0797967d1e76..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; @@ -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..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, 0, namednode, NULL, name, NULL); + 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, 0, namednode, NULL, name, uri); + 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/html_document.c b/ext/dom/html_document.c index 41624bfe172fd..19d7faef0dbb2 100644 --- a/ext/dom/html_document.c +++ b/ext/dom/html_document.c @@ -776,7 +776,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, " diff --git a/ext/dom/namednodemap.c b/ext/dom/namednodemap.c index 73f1f09e9dae8..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" /* @@ -33,24 +34,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,50 +55,6 @@ 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) -{ - xmlNodePtr itemnode = php_dom_named_node_map_get_named_item(objmap, named, true); - 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: */ @@ -122,45 +67,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_obj_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 +87,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 +96,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 +112,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_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 c9bf45e887db8..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, XML_ELEMENT_NODE, intern, NULL, NULL, NULL); + 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, XML_ATTRIBUTE_NODE, intern, NULL, NULL, NULL); + 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 819b7396b69c7..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" @@ -32,24 +33,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 +43,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 @@ -135,98 +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) -{ - 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; - } - } - - RETVAL_NULL(); -} - /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#ID-844377136 Since: */ @@ -240,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 */ @@ -291,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 new file mode 100644 index 0000000000000..fe71a6f47a38a --- /dev/null +++ b/ext/dom/obj_map.c @@ -0,0 +1,468 @@ +/* + +----------------------------------------------------------------------+ + | 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) +{ + return zend_hash_num_elements(map->array); +} + +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) +{ + zval *entry = zend_hash_index_find(map->array, 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 void dom_map_get_attributes_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_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_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 : 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); + if (itemnode) { + dom_map_cache_obj(map, itemnode, index, return_value); + } +} + +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; +} + +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); + + GC_ADDREF(&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 === * + **********************/ + +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 = false, + .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..e1de9addd98f2 --- /dev/null +++ b/ext/dom/obj_map.h @@ -0,0 +1,66 @@ +/* + +----------------------------------------------------------------------+ + | 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; + +typedef struct dom_nnodemap_object { + dom_object *baseobj; + zend_long cached_length; + union { + xmlHashTable *ht; + HashTable *array; + struct { + 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; + 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); +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; +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..4f77359835ce5 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" @@ -248,8 +249,9 @@ 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->nodetype = DOM_NODESET; + 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 f2c1ec2c62b8b..6e85ea887e4ec 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,49 +1457,6 @@ 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) /* {{{ */ -{ - 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->baseobj = basenode; - mapptr->nodetype = ntype; - 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; @@ -1587,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); @@ -1603,26 +1564,11 @@ 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; + objmap->handler = &php_dom_obj_map_noop; return &intern->std; } @@ -2308,7 +2254,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; } @@ -2396,7 +2342,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_obj_map_get_named_item_into_zval(php_dom_obj_from_obj(object)->ptr, Z_STR_P(offset), NULL, rv); return rv; } @@ -2406,7 +2352,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; } @@ -2420,7 +2367,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)); @@ -2439,14 +2387,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_obj_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; @@ -2469,7 +2417,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..0ff8692c4cc74 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" + /* 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; @@ -77,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 nodetype; - 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; - bool release_local : 1; - bool release_ns : 1; -} dom_nnodemap_object; - typedef struct { zend_object_iterator intern; zval curobj; @@ -146,9 +128,8 @@ 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); 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 +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 */ -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); -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/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; 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" 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..21baa59ffed0b 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 @@ -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->nodetype = DOM_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; } 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-- 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 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/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); 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([ diff --git a/ext/hash/hash_xxhash.c b/ext/hash/hash_xxhash.c index 203f3c7d2d9eb..1c1315afd4b28 100644 --- a/ext/hash/hash_xxhash.c +++ b/ext/hash/hash_xxhash.c @@ -158,7 +158,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 097f887be9e7f..259371a3addd6 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)); 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 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..3a2afa2d1c2d9 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; @@ -49,21 +59,27 @@ 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 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; @@ -71,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/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 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.c b/ext/ldap/ldap.c index 8ce1987ba56fe..0e9f953a2a2a4 100644 --- a/ext/ldap/ldap.c +++ b/ext/ldap/ldap.c @@ -4041,6 +4041,11 @@ static void php_ldap_exop(INTERNAL_FUNCTION_PARAMETERS, bool force_sync) { RETURN_THROWS(); } + if (ZSTR_LEN(reqoid) == 0) { + zend_argument_must_not_be_empty_error(2); + RETURN_THROWS(); + } + ld = Z_LDAP_LINK_P(link); VERIFY_LDAP_LINK_CONNECTED(ld); 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/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 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; diff --git a/ext/mbstring/php_mbregex.c b/ext/mbstring/php_mbregex.c index 08db861f564ec..26eeb78a3cbfc 100644 --- a/ext/mbstring/php_mbregex.c +++ b/ext/mbstring/php_mbregex.c @@ -1178,7 +1178,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/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-- +--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" +} diff --git a/ext/mbstring/tests/mb_ereg_replace_variation1.phpt b/ext/mbstring/tests/mb_ereg_replace_variation1.phpt index 7996d89734f5d..d251efbb01939 100644 --- a/ext/mbstring/tests/mb_ereg_replace_variation1.phpt +++ b/ext/mbstring/tests/mb_ereg_replace_variation1.phpt @@ -1,7 +1,5 @@ --TEST-- -Test mb_ereg_replace() function : usage variations - ---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) 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/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/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index a2b2d0fde8b42..0f1f1c986985b 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -57,6 +57,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 @@ -4537,6 +4539,39 @@ static void preload_load(size_t orig_map_ptr_static_last) } } +#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; @@ -4749,6 +4784,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/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 355178d9d51ed..bdf8ce2b007f4 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -3449,8 +3449,16 @@ 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/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index 01a252a15d4fa..6aa7896554920 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -5944,6 +5944,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); @@ -5960,6 +5961,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/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"; 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 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/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 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 @@ + --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 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; - } } /* }}} */ 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/config.m4 b/ext/pcntl/config.m4 index ce26a6efd2ead..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 @@ -25,6 +24,8 @@ if test "$PHP_PCNTL" != "no"; then wait3 wait4 waitid + wait6 + syscall ])) AC_CHECK_FUNCS([WIFCONTINUED],, @@ -43,6 +44,12 @@ if test "$PHP_PCNTL" != "no"; then ]),,, [#include ]) + 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 0481c0966c87a..886d4b6b595ff 100644 --- a/ext/pcntl/pcntl.c +++ b/ext/pcntl/pcntl.c @@ -125,8 +125,18 @@ typedef psetid_t cpu_set_t; #include #endif -#ifdef HAVE_PIDFD_OPEN -#include +#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 #ifdef HAVE_FORKX @@ -401,19 +411,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; @@ -1569,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) 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 8da7cb70a6aa7..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 @@ -317,11 +318,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 +326,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 +387,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 +403,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 +426,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 +585,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/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-- --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 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]) 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.stub.php b/ext/pdo_sqlite/pdo_sqlite.stub.php index 4cb6c14eae0a4..4af2d8c55260b 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 >= 3043000 + 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..e2cd71723706e 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: 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) @@ -116,6 +116,32 @@ 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 >= 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); + + 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); + + 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..e9e7a0cc78609 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,63 @@ 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 >= 3043000 +#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; + } + + return 1; +} + +static int pdo_sqlite_stmt_set_attribute(pdo_stmt_t *stmt, zend_long attr, zval *zval) +{ + switch (attr) { + case PDO_SQLITE_ATTR_EXPLAIN_STATEMENT: +#if SQLITE_VERSION_NUMBER >= 3043000 +#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 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; + } +#endif +#else + zend_value_error("explain statement unsupported"); + return 0; +#endif default: return 0; } @@ -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..383457f3a79e8 --- /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); +?> +--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 + } +} +bool(false) +array(1) { + [0]=> + array(4) { + ["id"]=> + int(2) + ["parent"]=> + int(0) + ["notused"]=> + int(%d) + ["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 Pdo\Sqlite::EXPLAIN_MODE_* constants +explain mode must be one of the Pdo\Sqlite::EXPLAIN_MODE_* constants +bool(true) 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-- ---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) 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 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) 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()); 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); 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/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(); 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 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/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"; } 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/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) ); ?> diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c index 1396e693d9955..21b6840a8d1b2 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" @@ -36,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)) { \ @@ -1153,6 +1157,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 { @@ -1164,6 +1169,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; } } @@ -1176,6 +1182,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: @@ -1191,6 +1198,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: @@ -1479,6 +1487,77 @@ 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; +} + +#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) /* {{{ */ { @@ -1908,12 +1987,22 @@ 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) { 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); @@ -1940,36 +2029,13 @@ 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); - for (i = 0; i < n_cols; i++) { - zval data; - - sqlite_value_to_zval(result_obj->stmt_obj->stmt, i, &data); + php_sqlite3_fetch_one(n_cols, result_obj, mode, return_value); - if (mode & PHP_SQLITE3_NUM) { - add_index_zval(return_value, 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(return_value), result_obj->column_names[i], &data); - } - } break; case SQLITE_DONE: @@ -1993,6 +2059,55 @@ static void sqlite3result_clear_column_names_cache(php_sqlite3_result *result) { result->column_count = -1; } +PHP_METHOD(SQLite3Result, fetchAll) +{ + int 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 && !result_obj->column_names) { + sqlite3result_fill_column_names_cache(result_obj, nb_cols); + } + 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) { @@ -2351,6 +2466,27 @@ 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) { + 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. */ + 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 3545da36acfcd..54a7b41ec5576 100644 --- a/ext/sqlite3/sqlite3.stub.php +++ b/ext/sqlite3/sqlite3.stub.php @@ -272,6 +272,17 @@ public function readOnly(): bool {} /** @tentative-return-type */ 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 */ @@ -291,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 654e25edead6c..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: edf910997672a2b8d8b5c25e8a7a4ff1c135e7b1 */ + * Stub hash: da91c32c6070c808d6e1b01894b5f8beedda7b45 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_SQLite3___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) @@ -144,6 +144,18 @@ 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() + +#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() @@ -161,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 @@ -202,11 +218,17 @@ ZEND_METHOD(SQLite3Stmt, getSQL); 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); ZEND_METHOD(SQLite3Result, columnType); ZEND_METHOD(SQLite3Result, fetchArray); +ZEND_METHOD(SQLite3Result, fetchAll); ZEND_METHOD(SQLite3Result, reset); ZEND_METHOD(SQLite3Result, finalize); @@ -253,6 +275,11 @@ 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) +#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 }; @@ -262,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 @@ -535,6 +563,26 @@ 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); + + 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); + + 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) 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) + } +} 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) diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index 09f63860f1163..18dc66dcc7648 100644 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -1686,13 +1686,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 {} @@ -1775,19 +1773,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 {} @@ -1805,13 +1800,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 d221a221f4132..f831e5bdc9b72 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: dfd7d2cfd31312f7f6c5074c10cab54e9d1fbccc */ + * Stub hash: 0ed546c180da5fe4af917086bee80259def15a78 */ 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) @@ -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/formatted_print.c b/ext/standard/formatted_print.c index 9471ad3c7ba23..b2c287c02900c 100644 --- a/ext/standard/formatted_print.c +++ b/ext/standard/formatted_print.c @@ -49,10 +49,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; } /* }}} */ @@ -64,13 +64,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; } @@ -90,7 +90,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); @@ -108,7 +108,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) { @@ -143,8 +143,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; @@ -169,7 +169,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, @@ -187,8 +187,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 */ @@ -203,7 +203,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); } @@ -229,8 +229,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) { @@ -328,8 +328,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)); @@ -361,7 +361,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; @@ -429,6 +429,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; @@ -462,8 +466,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; @@ -476,8 +480,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; @@ -528,7 +532,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); @@ -536,7 +540,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; @@ -580,13 +584,14 @@ 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; expprec = 1; } else { precision = 0; + adjusting |= ADJ_PRECISION; } } else { precision = 0; diff --git a/ext/standard/mail.c b/ext/standard/mail.c index 0243ec897a05e..41e2a02078e78 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,26 +587,47 @@ 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) { + 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); + } + } +#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 { + 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/pack.c b/ext/standard/pack.c index ec30be436741d..d4c5cc1f04cfa 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)) { \ @@ -274,7 +254,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 +360,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 +443,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 +612,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 +622,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 +632,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); } @@ -737,7 +717,6 @@ PHP_FUNCTION(unpack) while (formatlen-- > 0) { char type = *(format++); - char c; int repetitions = 1, argb; char *name; int namelen; @@ -745,7 +724,7 @@ PHP_FUNCTION(unpack) /* Handle format arguments if any */ if (formatlen > 0) { - c = *format; + char c = *format; if (c >= '0' && c <= '9') { errno = 0; @@ -784,7 +763,7 @@ PHP_FUNCTION(unpack) if (namelen > 200) namelen = 200; - switch ((int) type) { + switch (type) { /* Never use any input */ case 'X': size = -1; @@ -885,12 +864,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]; @@ -899,7 +881,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 */ @@ -912,12 +894,10 @@ 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': { /* 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 */ @@ -929,23 +909,21 @@ 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; } 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 */ case 'Z': { /* Z will strip everything after the first null character */ - char pad = '\0'; zend_long s, len = inputlen - inputpos; /* Remaining string */ @@ -958,13 +936,12 @@ 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; ZVAL_STRINGL(&val, &input[inputpos], len); - zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); break; } @@ -979,7 +956,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 +995,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 +1004,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 +1023,6 @@ PHP_FUNCTION(unpack) } ZVAL_LONG(&val, v); - zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); break; } @@ -1062,7 +1038,6 @@ PHP_FUNCTION(unpack) } ZVAL_LONG(&val, v); - zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); break; } @@ -1082,8 +1057,6 @@ PHP_FUNCTION(unpack) } ZVAL_LONG(&val, v); - zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); - break; } @@ -1104,7 +1077,6 @@ PHP_FUNCTION(unpack) } ZVAL_LONG(&val, v); - zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); break; } #endif @@ -1124,7 +1096,6 @@ PHP_FUNCTION(unpack) } ZVAL_DOUBLE(&val, v); - zend_symtable_update(Z_ARRVAL_P(return_value), real_name, &val); break; } @@ -1143,13 +1114,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 +1130,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 +1140,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) { 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/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/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) { +} 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/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_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..c761e3bdbd199 --- /dev/null +++ b/ext/standard/tests/mail/mail_variation4.phpt @@ -0,0 +1,24 @@ +--TEST-- +Test mail() function : variation sigterm +--INI-- +sendmail_path="kill \$\$" +--SKIPIF-- + +--FILE-- + +--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 new file mode 100644 index 0000000000000..9e430f40c5dfc --- /dev/null +++ b/ext/standard/tests/mail/mail_variation5.phpt @@ -0,0 +1,24 @@ +--TEST-- +Test mail() function : variation non-zero exit +--INI-- +sendmail_path="exit 123" +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +*** Testing mail() : variation *** + +Warning: mail(): Sendmail exited with non-zero exit code 123 in %smail_variation5.php on line %d +bool(false) diff --git a/ext/standard/tests/streams/bug61371-unix.phpt b/ext/standard/tests/streams/bug61371-unix.phpt deleted file mode 100644 index fe8df41f8cfbf..0000000000000 --- a/ext/standard/tests/streams/bug61371-unix.phpt +++ /dev/null @@ -1,46 +0,0 @@ ---TEST-- -Bug #61371: stream_context_create() causes memory leaks on use streams_socket_create ---SKIPIF-- - ---FILE-- - ---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 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/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 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(). 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 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()); 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/uri/config.m4 b/ext/uri/config.m4 index f29bbe58bd32e..2f5a7a489b5ae 100644 --- a/ext/uri/config.m4 +++ b/ext/uri/config.m4 @@ -2,19 +2,22 @@ dnl Configure options dnl 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.]) AC_DEFINE([URI_NO_UNICODE], [1], [Define to 1 for disabling unicode support of uriparser.]) URIPARSER_DIR="uriparser" -URIPARSER_SOURCES="$URIPARSER_DIR/src/UriCommon.c $URIPARSER_DIR/src/UriCompare.c $URIPARSER_DIR/src/UriEscape.c \ -$URIPARSER_DIR/src/UriFile.c $URIPARSER_DIR/src/UriIp4.c $URIPARSER_DIR/src/UriIp4Base.c \ +URIPARSER_SOURCES="$URIPARSER_DIR/src/UriCommon.c $URIPARSER_DIR/src/UriCompare.c $URIPARSER_DIR/src/UriCopy.c \ +$URIPARSER_DIR/src/UriEscape.c $URIPARSER_DIR/src/UriFile.c $URIPARSER_DIR/src/UriIp4.c $URIPARSER_DIR/src/UriIp4Base.c \ $URIPARSER_DIR/src/UriMemory.c $URIPARSER_DIR/src/UriNormalize.c $URIPARSER_DIR/src/UriNormalizeBase.c \ $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 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/config.w32 b/ext/uri/config.w32 index 962f7bee0660e..6954ca06af555 100644 --- a/ext/uri/config.w32 +++ b/ext/uri/config.w32 @@ -1,9 +1,9 @@ -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 php_uriparser.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.") 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"); +ADD_SOURCES("ext/uri/uriparser/src", "UriCommon.c UriCompare.c UriCopy.c UriEscape.c UriFile.c UriIp4.c UriIp4Base.c UriMemory.c UriNormalize.c UriNormalizeBase.c UriParse.c UriParseBase.c UriQuery.c UriRecompose.c UriResolve.c UriShorten.c", "uri"); +PHP_INSTALL_HEADERS("ext/uri", "php_lexbor.h php_uri.h php_uri_common.h php_uriparser.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..44bca30f8fda7 --- /dev/null +++ b/ext/uri/php_lexbor.c @@ -0,0 +1,638 @@ +/* + +----------------------------------------------------------------------+ + | 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 zend_string *fill_errors(zval *errors) +{ + if (errors == NULL) { + return NULL; + } + + ZEND_ASSERT(Z_ISUNDEF_P(errors)); + + array_init(errors); + + if (lexbor_parser.log == NULL) { + 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; + 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); + + if (Z_TYPE(failure) == IS_TRUE) { + result = error_str; + } + + add_next_index_zval(errors, &error); + } + + return result; +} + +static void throw_invalid_url_exception_during_write(zval *errors, const char *component) +{ + 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) +{ + 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, "scheme"); + + 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, "username"); + + 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, "password"); + + 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, "host"); + + 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, "port"); + + 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, "path"); + + 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, "query string"); + + 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, "fragment"); + + 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)); + zend_string *reason = fill_errors(errors); + + if (url == NULL && !silent) { + zend_object *exception = zend_throw_exception_ex(uri_whatwg_invalid_url_exception_ce, 0, "The specified URI is malformed%s%s%s", reason ? " (" : "", reason ? ZSTR_VAL(reason) : "", reason ? ")" : ""); + zend_update_property(exception->ce, exception, ZEND_STRL("errors"), 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..f5a5b160bba06 100644 --- a/ext/uri/php_uri.c +++ b/ext/uri/php_uri.c @@ -22,16 +22,25 @@ #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_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; 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 +49,814 @@ 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; +} + +/** + * 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_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; + 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); +} + +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, "The userinfo component cannot be retrieved"); + 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 throw_cannot_recompose_uri_to_string(zend_object *object) +{ + zend_throw_exception_ex(NULL, 0, "Cannot recompose %s to a string", ZSTR_VAL(object->ce->name)); +} + +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) { + throw_cannot_recompose_uri_to_string(this_object); + 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); + throw_cannot_recompose_uri_to_string(that_object); + RETURN_THROWS(); + } + + RETVAL_BOOL(zend_string_equals(this_str, that_str)); + + zend_string_release(this_str); + 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) { + throw_cannot_recompose_uri_to_string(this_object); + 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) { + throw_cannot_recompose_uri_to_string(this_object); + 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) { + throw_cannot_recompose_uri_to_string(this_object); + 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; + + 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_Rfc3986_Uri, __unserialize) +{ + uri_unserialize(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PARSER_RFC3986); +} + +PHP_METHOD(Uri_Rfc3986_Uri, __debugInfo) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zend_object *object = Z_OBJ_P(ZEND_THIS); + + RETURN_ARR(uri_get_debug_properties(object)); +} + +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, withUsername) +{ + uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_USERNAME); +} + +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, withPort) +{ + uri_write_component_long_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PORT); +} + +PHP_METHOD(Uri_WhatWg_Url, withPath) +{ + uri_write_component_str(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PATH); +} + +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, 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) { + throw_cannot_recompose_uri_to_string(this_object); + 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_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); + + 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 (PHP_MINIT(uri_uriparser)(INIT_FUNC_ARGS_PASSTHRU) == FAILURE) { + return FAILURE; + } + + if (uri_handler_register(&lexbor_uri_handler) == FAILURE) { + return FAILURE; + } return SUCCESS; } @@ -60,18 +871,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..9fbd40d98e5e9 100644 --- a/ext/uri/php_uri.stub.php +++ b/ext/uri/php_uri.stub.php @@ -12,6 +12,70 @@ class UriException extends \Exception class InvalidUriException extends \Uri\UriException { } + + enum UriComparisonMode + { + case IncludeFragment; + case ExcludeFragment; + } +} + +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 { @@ -19,5 +83,115 @@ 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 {} + + /** @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 {} + + public function getAsciiHost(): ?string {} + + 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 {} + + 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..65630f113a3d3 100644 --- a/ext/uri/php_uri_arginfo.h +++ b/ext/uri/php_uri_arginfo.h @@ -1,5 +1,288 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 35460b24cf237585dabdc9813212c343034cf591 */ + * 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, "\"\"") + 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() + +#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() + +#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_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_Rfc3986_Uri_getScheme + +#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() + +#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_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_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_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) +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_Rfc3986_Uri_getPath + +#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() + +#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, withUsername); +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, withPort); +ZEND_METHOD(Uri_WhatWg_Url, withPath); +ZEND_METHOD(Uri_WhatWg_Url, withQuery); +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_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 +}; + +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_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_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_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_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_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_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) + 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 +304,32 @@ 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_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; - 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 +340,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..29de370bd56b6 --- /dev/null +++ b/ext/uri/php_uri_common.c @@ -0,0 +1,165 @@ +/* + +----------------------------------------------------------------------+ + | 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, "The %s component cannot be retrieved", ZSTR_VAL(get_known_string_by_property_name(property_name))); + RETURN_THROWS(); + } +} + +static void uri_write_component_ex(INTERNAL_FUNCTION_PARAMETERS, uri_property_name_t property_name, zval *property_zv) +{ + uri_internal_t *internal_uri = Z_URI_INTERNAL_P(ZEND_THIS); + URI_ASSERT_INITIALIZATION(internal_uri); + + const uri_property_handler_t *property_handler = uri_property_handler_from_internal_uri(internal_uri, property_name); + ZEND_ASSERT(property_handler != NULL); + + zend_object *new_object = uri_clone_obj_handler(Z_OBJ_P(ZEND_THIS)); + ZEND_ASSERT(new_object != NULL); + + uri_internal_t *new_internal_uri = uri_internal_from_obj(new_object); + URI_ASSERT_INITIALIZATION(new_internal_uri); + if (UNEXPECTED(property_handler->write_func == NULL)) { + zend_readonly_property_modification_error_ex(ZSTR_VAL(Z_OBJ_P(ZEND_THIS)->ce->name), + ZSTR_VAL(get_known_string_by_property_name(property_name))); + zend_object_release(new_object); + RETURN_THROWS(); + } + + zval errors; + ZVAL_UNDEF(&errors); + if (UNEXPECTED(property_handler->write_func(new_internal_uri, property_zv, &errors) == FAILURE)) { + zval_ptr_dtor(&errors); + zend_object_release(new_object); + RETURN_THROWS(); + } + + ZEND_ASSERT(Z_ISUNDEF(errors)); + RETVAL_OBJ(new_object); +} + +void uri_write_component_str(INTERNAL_FUNCTION_PARAMETERS, uri_property_name_t property_name) +{ + zend_string *value; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_PATH_STR(value) + ZEND_PARSE_PARAMETERS_END(); + + zval zv; + ZVAL_STR(&zv, value); + + uri_write_component_ex(INTERNAL_FUNCTION_PARAM_PASSTHRU, property_name, &zv); +} + +void uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAMETERS, uri_property_name_t property_name) +{ + zend_string *value; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_PATH_STR_OR_NULL(value) + ZEND_PARSE_PARAMETERS_END(); + + zval zv; + if (value == NULL) { + ZVAL_NULL(&zv); + } else { + ZVAL_STR(&zv, value); + } + + uri_write_component_ex(INTERNAL_FUNCTION_PARAM_PASSTHRU, property_name, &zv); +} + +void uri_write_component_long_or_null(INTERNAL_FUNCTION_PARAMETERS, uri_property_name_t property_name) +{ + zend_long value; + bool value_is_null; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_LONG_OR_NULL(value, value_is_null) + ZEND_PARSE_PARAMETERS_END(); + + zval zv; + if (value_is_null) { + ZVAL_NULL(&zv); + } else { + ZVAL_LONG(&zv, value); + } + + uri_write_component_ex(INTERNAL_FUNCTION_PARAM_PASSTHRU, property_name, &zv); +} diff --git a/ext/uri/php_uri_common.h b/ext/uri/php_uri_common.h new file mode 100644 index 0000000000000..8e5b0c2d2279f --- /dev/null +++ b/ext/uri/php_uri_common.h @@ -0,0 +1,141 @@ +/* + +----------------------------------------------------------------------+ + | 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_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; +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_RFC3986 "Uri\\Rfc3986\\Uri" +#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/php_uriparser.c b/ext/uri/php_uriparser.c new file mode 100644 index 0000000000000..93011442da42e --- /dev/null +++ b/ext/uri/php_uriparser.c @@ -0,0 +1,427 @@ +/* + +----------------------------------------------------------------------+ + | 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" + +static void uriparser_free_uri(void *uri); +static void throw_invalid_uri_exception(void); + +static inline size_t get_text_range_length(const UriTextRangeA *range) +{ + return range->afterLast - range->first; +} + +static void uriparser_copy_uri(UriUriA *new_uriparser_uri, UriUriA *uriparser_uri) +{ + ZEND_ASSERT(new_uriparser_uri != NULL && uriparser_uri != NULL); + + int result = uriCopyUriA(new_uriparser_uri, uriparser_uri); + ZEND_ASSERT(result == URI_SUCCESS && new_uriparser_uri != NULL); +} + +static void uriparser_normalize_uri(UriUriA *uriparser_uri) +{ + int result = uriNormalizeSyntaxExA(uriparser_uri, (unsigned int)-1); + ZEND_ASSERT(result == URI_SUCCESS); +} + +static void normalize_uri_if_needed(uriparser_uris_t *uriparser_uris) +{ + if (uriparser_uris->normalized_uri_initialized == false) { + uriparser_copy_uri(&uriparser_uris->normalized_uri, &uriparser_uris->uri); + uriparser_normalize_uri(&uriparser_uris->normalized_uri); + uriparser_uris->normalized_uri_initialized = true; + } +} + +static UriUriA *uriparser_read_uri(uriparser_uris_t *uriparser_uris, uri_component_read_mode_t read_mode) +{ + switch (read_mode) { + case URI_COMPONENT_READ_RAW: + return &uriparser_uris->uri; + case URI_COMPONENT_READ_NORMALIZED_ASCII: + ZEND_FALLTHROUGH; + case URI_COMPONENT_READ_NORMALIZED_UNICODE: + normalize_uri_if_needed(uriparser_uris); + + return &uriparser_uris->normalized_uri; + EMPTY_SWITCH_DEFAULT_CASE() + } +} + +static zend_result uriparser_read_scheme(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + ZEND_ASSERT(uriparser_uri != NULL); + + if (uriparser_uri->scheme.first != NULL && uriparser_uri->scheme.afterLast != NULL) { + zend_string *str = zend_string_init(uriparser_uri->scheme.first, get_text_range_length(&uriparser_uri->scheme), false); + ZVAL_NEW_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) +{ + UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + ZEND_ASSERT(uriparser_uri != NULL); + + if (uriparser_uri->userInfo.first != NULL && uriparser_uri->userInfo.afterLast != NULL) { + ZVAL_STRINGL(retval, uriparser_uri->userInfo.first, get_text_range_length(&uriparser_uri->userInfo)); + } 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) +{ + UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + ZEND_ASSERT(uriparser_uri != NULL); + + if (uriparser_uri->userInfo.first != NULL && uriparser_uri->userInfo.afterLast != NULL) { + size_t length = get_text_range_length(&uriparser_uri->userInfo); + char *c = memchr(uriparser_uri->userInfo.first, ':', length); + + if (c == NULL && length > 0) { + ZVAL_STRINGL(retval, uriparser_uri->userInfo.first, length); + } 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) +{ + UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + ZEND_ASSERT(uriparser_uri != NULL); + + if (uriparser_uri->userInfo.first != NULL && uriparser_uri->userInfo.afterLast != NULL) { + const char *c = memchr(uriparser_uri->userInfo.first, ':', get_text_range_length(&uriparser_uri->userInfo)); + + 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) +{ + UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + ZEND_ASSERT(uriparser_uri != NULL); + + if (uriparser_uri->hostText.first != NULL && uriparser_uri->hostText.afterLast != NULL && get_text_range_length(&uriparser_uri->hostText) > 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, get_text_range_length(&uriparser_uri->hostText)); + smart_str_appendc(&host_str, ']'); + + ZVAL_NEW_STR(retval, smart_str_extract(&host_str)); + } else { + ZVAL_STRINGL(retval, uriparser_uri->hostText.first, get_text_range_length(&uriparser_uri->hostText)); + } + } else { + ZVAL_NULL(retval); + } + + return SUCCESS; +} + +static int str_to_int(const char *str, int len) +{ + int result = 0; + + for (int i = 0; i < len; ++i) { + result = result * 10 + (str[i] - '0'); + } + + return result; +} + +static zend_result uriparser_read_port(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval) +{ + UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + ZEND_ASSERT(uriparser_uri != NULL); + + if (uriparser_uri->portText.first != NULL && uriparser_uri->portText.afterLast != NULL) { + ZVAL_LONG(retval, str_to_int(uriparser_uri->portText.first, get_text_range_length(&uriparser_uri->portText))); + } 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) +{ + UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + ZEND_ASSERT(uriparser_uri != NULL); + + if (uriparser_uri->pathHead != NULL) { + const UriPathSegmentA *p; + smart_str str = {0}; + + if (uriparser_uri->absolutePath || uriIsHostSetA(uriparser_uri)) { + smart_str_appendc(&str, '/'); + } + + smart_str_appendl(&str, uriparser_uri->pathHead->text.first, get_text_range_length(&uriparser_uri->pathHead->text)); + + for (p = uriparser_uri->pathHead->next; p != NULL; p = p->next) { + smart_str_appendc(&str, '/'); + smart_str_appendl(&str, p->text.first, get_text_range_length(&p->text)); + } + + ZVAL_NEW_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) +{ + UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + ZEND_ASSERT(uriparser_uri != NULL); + + if (uriparser_uri->query.first != NULL && uriparser_uri->query.afterLast != NULL) { + ZVAL_STRINGL(retval, uriparser_uri->query.first, get_text_range_length(&uriparser_uri->query)); + } 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) +{ + UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode); + ZEND_ASSERT(uriparser_uri != NULL); + + if (uriparser_uri->fragment.first != NULL && uriparser_uri->fragment.afterLast != NULL) { + ZVAL_STRINGL(retval, uriparser_uri->fragment.first, get_text_range_length(&uriparser_uri->fragment)); + } 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 erealloc(ptr, size); +} + +static void *uriparser_reallocarray(UriMemoryManager *memory_manager, void *ptr, size_t nmemb, size_t size) +{ + return safe_erealloc(ptr, nmemb, size, 0); +} + +static void uriparser_free(UriMemoryManager *memory_manager, void *ptr) +{ + efree(ptr); +} + +PHP_MINIT_FUNCTION(uri_uriparser) +{ + if (uri_handler_register(&uriparser_uri_handler) == FAILURE) { + return FAILURE; + } + + defaultMemoryManager.malloc = uriparser_malloc; + defaultMemoryManager.calloc = uriparser_calloc; + defaultMemoryManager.realloc = uriparser_realloc; + defaultMemoryManager.reallocarray = uriparser_reallocarray; + defaultMemoryManager.free = uriparser_free; + + return SUCCESS; +} + +static uriparser_uris_t *uriparser_create_uris(void) +{ + uriparser_uris_t *uriparser_uris = emalloc(sizeof(uriparser_uris_t)); + uriparser_uris->normalized_uri_initialized = false; + + return uriparser_uris; +} + +static void throw_invalid_uri_exception(void) +{ + zend_throw_exception(uri_invalid_uri_exception_ce, "The specified URI is malformed", 0); +} + +#define PARSE_URI(dest_uri, uri_str, uriparser_uris, silent) \ + do { \ + if (ZSTR_LEN(uri_str) == 0 || \ + uriParseSingleUriExA(dest_uri, ZSTR_VAL(uri_str), ZSTR_VAL(uri_str) + ZSTR_LEN(uri_str), NULL) != URI_SUCCESS \ + ) { \ + efree(uriparser_uris); \ + if (!silent) { \ + throw_invalid_uri_exception(); \ + } \ + return NULL; \ + } \ + } while (0) + +void *uriparser_parse_uri_ex(const zend_string *uri_str, const uriparser_uris_t *uriparser_base_urls, bool silent) +{ + uriparser_uris_t *uriparser_uris = uriparser_create_uris(); + + if (uriparser_base_urls == NULL) { + PARSE_URI(&uriparser_uris->uri, uri_str, uriparser_uris, silent); + } else { + UriUriA uri; + + PARSE_URI(&uri, uri_str, uriparser_uris, silent); + + if (uriAddBaseUriA(&uriparser_uris->uri, &uri, &uriparser_base_urls->uri) != URI_SUCCESS) { + efree(uriparser_uris); + if (!silent) { + throw_invalid_uri_exception(); + } + + return NULL; + } + } + + uriMakeOwnerA(&uriparser_uris->uri); + + return uriparser_uris; +} + +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); +} + +/* TODO make the clone handler accept a flag to distingish between clone() calls and withers. + * When calling a wither successfully, the normalized URI is surely invalidated, therefore + * it doesn't make sense to copy it. In case of failure, an exeption is thrown, and the URI object + * is discarded altogether. */ +static void *uriparser_clone_uri(void *uri) +{ + uriparser_uris_t *uriparser_uris = (uriparser_uris_t *) uri; + + uriparser_uris_t *new_uriparser_uris = uriparser_create_uris(); + uriparser_copy_uri(&new_uriparser_uris->uri, &uriparser_uris->uri); + if (uriparser_uris->normalized_uri_initialized) { + uriparser_copy_uri(&new_uriparser_uris->normalized_uri, &uriparser_uris->normalized_uri); + new_uriparser_uris->normalized_uri_initialized = true; + } + + return new_uriparser_uris; +} + +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; + + if (recomposition_mode == URI_RECOMPOSITION_RAW_ASCII || recomposition_mode == URI_RECOMPOSITION_RAW_UNICODE) { + uriparser_uri = &uriparser_uris->uri; + } else { + normalize_uri_if_needed(uriparser_uris); + + uriparser_uri = &uriparser_uris->normalized_uri; + } + + int charsRequired = 0; + int result = uriToStringCharsRequiredA(uriparser_uri, &charsRequired); + ZEND_ASSERT(result == URI_SUCCESS); + + charsRequired++; + + zend_string *uri_string = zend_string_alloc(charsRequired - 1, false); + result = uriToStringA(ZSTR_VAL(uri_string), uriparser_uri, charsRequired, NULL); + ZEND_ASSERT(result == URI_SUCCESS); + + if (exclude_fragment) { + const char *pos = zend_memrchr(ZSTR_VAL(uri_string), '#', ZSTR_LEN(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; + + uriFreeUriMembersA(&uriparser_uris->uri); + + if (uriparser_uris->normalized_uri_initialized) { + ZEND_ASSERT(uriparser_uris->normalized_uri.owner); + + uriFreeUriMembersA(&uriparser_uris->normalized_uri); + } + + 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..5f1cc04570697 --- /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 "uriparser/src/UriMemory.h" +#include "php_uri_common.h" + +extern const uri_handler_t uriparser_uri_handler; + +typedef struct uriparser_uris_t { + UriUriA uri; + UriUriA normalized_uri; + bool normalized_uri_initialized; +} uriparser_uris_t; + +PHP_MINIT_FUNCTION(uri_uriparser); + +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/001.phpt b/ext/uri/tests/001.phpt new file mode 100644 index 0000000000000..0b97b7d57c187 --- /dev/null +++ b/ext/uri/tests/001.phpt @@ -0,0 +1,95 @@ +--TEST-- +Parse URL +--EXTENSIONS-- +uri +--FILE-- + +--EXPECTF-- +RFC 3986 parser: https://example.com/ +float(0.0032325) +object(Uri\Rfc3986\Uri)#%d (%d) { + ["scheme"]=> + string(5) "https" + ["userinfo"]=> + NULL + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(1) "/" + ["query"]=> + NULL + ["fragment"]=> + NULL +} +------------------------ +WHATWG parser: https://example.com/ +float(0.004510875) +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 +} +------------------------ +PHP parser: https://example.com/ +float(0.004519541) +array(%d) { + ["scheme"]=> + string(5) "https" + ["host"]=> + string(11) "example.com" +} +------------------------ diff --git a/ext/uri/tests/002.phpt b/ext/uri/tests/002.phpt new file mode 100644 index 0000000000000..206ea2b0c75a7 --- /dev/null +++ b/ext/uri/tests/002.phpt @@ -0,0 +1,107 @@ +--TEST-- +Parse URL +--EXTENSIONS-- +uri +--FILE-- + +--EXPECTF-- +RFC 3986 parser: +float(0.004389959) +object(Uri\Rfc3986\Uri)#%d (%d) { + ["scheme"]=> + string(5) "https" + ["userinfo"]=> + string(17) "username:password" + ["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" +} +------------------------ +WHATWG parser: +float(0.007400166) +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" +} +------------------------ +parse_url: +float(0.007400166) +array(%d) { + ["scheme"]=> + string(5) "https" + ["host"]=> + string(14) "www.google.com" + ["port"]=> + int(8080) + ["user"]=> + string(8) "username" + ["pass"]=> + string(8) "password" + ["path"]=> + string(30) "/pathname1/pathname2/pathname3" + ["query"]=> + string(10) "query=true" + ["fragment"]=> + string(11) "hash-exists" +} +------------------------ diff --git a/ext/uri/tests/003.phpt b/ext/uri/tests/003.phpt new file mode 100644 index 0000000000000..be607fd6cacef --- /dev/null +++ b/ext/uri/tests/003.phpt @@ -0,0 +1,53 @@ +--TEST-- +Parse URL exotic URLs +--EXTENSIONS-- +uri +--FILE-- + +--EXPECTF-- +NULL +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" +} +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 new file mode 100644 index 0000000000000..10e90dc584a8d --- /dev/null +++ b/ext/uri/tests/004.phpt @@ -0,0 +1,56 @@ +--TEST-- +Parse invalid URLs +--EXTENSIONS-- +uri +--FILE-- +getMessage() . "\n"; +} + +var_dump(Uri\Rfc3986\Uri::parse("")); + +try { + new Uri\WhatWg\Url(""); +} catch (Uri\WhatWg\InvalidUrlException $e) { + echo $e->getMessage() . "\n"; +} + +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)); + +?> +--EXPECTF-- +The specified URI is malformed +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 new file mode 100644 index 0000000000000..6db6c4a56ee5a --- /dev/null +++ b/ext/uri/tests/005.phpt @@ -0,0 +1,41 @@ +--TEST-- +Parse multibyte URLs +--EXTENSIONS-- +uri +--FILE-- +getAsciiHost()); +var_dump($url->getUnicodeHost()); +var_dump($url->toAsciiString()); +var_dump($url->toUnicodeString()); + +?> +--EXPECTF-- +NULL +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..c4da9db905c82 --- /dev/null +++ b/ext/uri/tests/006.phpt @@ -0,0 +1,51 @@ +--TEST-- +Test successful manual Uri child instance creation +--EXTENSIONS-- +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" + ["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..54151f2dfcb1c --- /dev/null +++ b/ext/uri/tests/007.phpt @@ -0,0 +1,70 @@ +--TEST-- +Test URI creation errors +--EXTENSIONS-- +uri +--FILE-- +getMessage() . "\n"; +} + +try { + new Uri\WhatWg\Url("https://example.com:8080@username:password/path?q=r#fragment"); +} catch (Uri\WhatWg\InvalidUrlException $e) { + echo $e->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-- +The specified URI is malformed +The specified URI is malformed (PortInvalid) +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..e13130bb4c466 --- /dev/null +++ b/ext/uri/tests/008.phpt @@ -0,0 +1,78 @@ +--TEST-- +Test Uri getters +--EXTENSIONS-- +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()); + 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()); +} + +$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" +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..05f2820bb3fcf --- /dev/null +++ b/ext/uri/tests/009.phpt @@ -0,0 +1,48 @@ +--TEST-- +Test parsing with IANA schemes +--EXTENSIONS-- +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" + ["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..2ca071eb2ca33 --- /dev/null +++ b/ext/uri/tests/010.phpt @@ -0,0 +1,86 @@ +--TEST-- +Test parsing URIs when a base URI is present +--EXTENSIONS-- +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" + ["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..49b915fa22a31 --- /dev/null +++ b/ext/uri/tests/011.phpt @@ -0,0 +1,33 @@ +--TEST-- +Test encoding and normalization +--EXTENSIONS-- +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()); +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(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/" +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..7c14014fb3519 --- /dev/null +++ b/ext/uri/tests/012.phpt @@ -0,0 +1,87 @@ +--TEST-- +Test parsing of various schemes +--EXTENSIONS-- +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" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + NULL + ["port"]=> + NULL + ["path"]=> + string(15) "Joe@Example.COM" + ["query"]=> + NULL + ["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" + ["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..6a5bb31870fb1 --- /dev/null +++ b/ext/uri/tests/013.phpt @@ -0,0 +1,131 @@ +--TEST-- +Test parsing of query strings +--EXTENSIONS-- +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='