summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--failed.txt16
-rw-r--r--macros.php4
-rw-r--r--php-7.0.7-curl.patch15
-rw-r--r--php-7.2.0-includedir.patch2
-rw-r--r--php-7.2.0-libdb.patch4
-rw-r--r--php-7.2.0-oci8conf.patch26
-rw-r--r--php-7.3.3-systzdata-v19.patch3
-rw-r--r--php-7.4.26-openssl3.patch229
-rw-r--r--php-7.4.33-gcc14.patch201
-rw-r--r--php-7.4.33-icu.patch35
-rw-r--r--php-7.4.33-libxml212.patch661
-rw-r--r--php-7.4.33-pcretests.patch43
-rw-r--r--php-7.4.33-proto.patch392
-rw-r--r--php-7.4.33-tests.patch26
-rw-r--r--php-7.4.33-zlib-tests.patch462
-rw-r--r--php-7.4.8-phpinfo.patch6
-rw-r--r--php-cve-2022-31631.patch84
-rw-r--r--php-cve-2023-0567.patch188
-rw-r--r--php-cve-2023-0568.patch98
-rw-r--r--php-cve-2023-0662.patch143
-rw-r--r--php-cve-2023-3247.patch152
-rw-r--r--php-cve-2023-3823.patch89
-rw-r--r--php-cve-2023-3824.patch644
-rw-r--r--php-cve-2024-11233.patch68
-rw-r--r--php-cve-2024-11234.patch95
-rw-r--r--php-cve-2024-11236.patch119
-rw-r--r--php-cve-2024-2756.patch193
-rw-r--r--php-cve-2024-3096.patch81
-rw-r--r--php-cve-2024-5458.patch180
-rw-r--r--php-cve-2024-8925.patch227
-rw-r--r--php-cve-2024-8926.patch210
-rw-r--r--php-cve-2024-8927.patch57
-rw-r--r--php-cve-2024-8929.patch2714
-rw-r--r--php-cve-2024-8932.patch139
-rw-r--r--php-cve-2024-9026.patch245
-rw-r--r--php-cve-2025-1217.patch917
-rw-r--r--php-cve-2025-1219.patch1906
-rw-r--r--php-cve-2025-1220.patch154
-rw-r--r--php-cve-2025-1734.patch314
-rw-r--r--php-cve-2025-1735.patch492
-rw-r--r--php-cve-2025-1736.patch242
-rw-r--r--php-cve-2025-1861.patch349
-rw-r--r--php-cve-2025-6491.patch103
-rw-r--r--php-fpm.service2
-rw-r--r--php-ghsa-4w77-75f9-2c8w.patch135
-rw-r--r--php-keyring.gpg1189
-rw-r--r--php.spec351
47 files changed, 13400 insertions, 605 deletions
diff --git a/failed.txt b/failed.txt
index 030ff14..41e59fd 100644
--- a/failed.txt
+++ b/failed.txt
@@ -1,13 +1,19 @@
-===== 7.4.28 (2022-02-17)
+===== 7.4.33-24 (2025-07-03)
$ grep -ar 'Tests failed' /var/lib/mock/*/build.log
-/var/lib/mock/scl74el7x/build.log:Tests failed : 0
+/var/lib/mock/scl74el8a/build.log:Tests failed : 0
/var/lib/mock/scl74el8x/build.log:Tests failed : 0
+/var/lib/mock/scl74el9a/build.log:Tests failed : 0
/var/lib/mock/scl74el9x/build.log:Tests failed : 0
-/var/lib/mock/scl74fc34x/build.log:Tests failed : 0
-/var/lib/mock/scl74fc35x/build.log:Tests failed : 0
-/var/lib/mock/scl74fc36x/build.log:Tests failed : 0
+/var/lib/mock/scl74el10a/build.log:Tests failed : 0
+/var/lib/mock/scl74el10x/build.log:Tests failed : 0
+/var/lib/mock/scl80fc40a/build.log:Tests failed : 0
+/var/lib/mock/scl80fc40x/build.log:Tests failed : 0
+/var/lib/mock/scl80fc41a/build.log:Tests failed : 0
+/var/lib/mock/scl80fc41x/build.log:Tests failed : 0
+/var/lib/mock/scl74fc42a/build.log:Tests failed : 0
+/var/lib/mock/scl74fc42x/build.log:Tests failed : 0
diff --git a/macros.php b/macros.php
index 3943a74..d3e937f 100644
--- a/macros.php
+++ b/macros.php
@@ -14,3 +14,7 @@
%@SCL@__php @BINDIR@/php
+%@SCL@__phpize @BINDIR@/phpize
+
+%@SCL@__phpconfig @BINDIR@/php-config
+
diff --git a/php-7.0.7-curl.patch b/php-7.0.7-curl.patch
deleted file mode 100644
index 218db98..0000000
--- a/php-7.0.7-curl.patch
+++ /dev/null
@@ -1,15 +0,0 @@
-diff -up php-7.0.7RC1/ext/curl/interface.c.curltls php-7.0.7RC1/ext/curl/interface.c
---- php-7.0.7RC1/ext/curl/interface.c.curltls 2016-05-10 17:28:33.000000000 +0200
-+++ php-7.0.7RC1/ext/curl/interface.c 2016-05-12 07:43:00.900419946 +0200
-@@ -1257,7 +1257,11 @@ PHP_MINIT_FUNCTION(curl)
-
- #if LIBCURL_VERSION_NUM >= 0x072200 /* Available since 7.34.0 */
- REGISTER_CURL_CONSTANT(CURLOPT_LOGIN_OPTIONS);
-+#endif
-
-+#if LIBCURL_VERSION_NUM >= 0x071300 /* Available since 7.19.0 (in upstream curl 7.34)
-+ backported in RHEL-7 curl-7.29.0-16.el7 rhbz#1012136
-+ backported in RHEL-6 curl-7.19.7-43.el6 rhbz#1036789 */
- REGISTER_CURL_CONSTANT(CURL_SSLVERSION_TLSv1_0);
- REGISTER_CURL_CONSTANT(CURL_SSLVERSION_TLSv1_1);
- REGISTER_CURL_CONSTANT(CURL_SSLVERSION_TLSv1_2);
diff --git a/php-7.2.0-includedir.patch b/php-7.2.0-includedir.patch
index 7a42cd6..2202026 100644
--- a/php-7.2.0-includedir.patch
+++ b/php-7.2.0-includedir.patch
@@ -1,6 +1,6 @@
--- php-7.2.0/configure.ac.includedir
+++ php-7.2.0/configure.ac
-@@ -1230,7 +1230,7 @@
+@@ -1283,7 +1283,7 @@
EXPANDED_DATADIR=$datadir
EXPANDED_PHP_CONFIG_FILE_PATH=`eval echo "$PHP_CONFIG_FILE_PATH"`
EXPANDED_PHP_CONFIG_FILE_SCAN_DIR=`eval echo "$PHP_CONFIG_FILE_SCAN_DIR"`
diff --git a/php-7.2.0-libdb.patch b/php-7.2.0-libdb.patch
index ca36d1a..11acd17 100644
--- a/php-7.2.0-libdb.patch
+++ b/php-7.2.0-libdb.patch
@@ -1,7 +1,7 @@
diff -up php-7.2.0alpha0/ext/dba/config.m4.libdb php-7.2.0alpha0/ext/dba/config.m4
--- php-7.2.0alpha0/ext/dba/config.m4.libdb 2017-05-29 08:56:06.000000000 +0200
+++ php-7.2.0alpha0/ext/dba/config.m4 2017-05-29 09:13:52.014823282 +0200
-@@ -346,61 +346,13 @@ if test "$PHP_DB4" != "no"; then
+@@ -375,61 +375,13 @@ if test "$PHP_DB4" != "no"; then
dbdp4="/usr/local/BerkeleyDB.4."
dbdp5="/usr/local/BerkeleyDB.5."
for i in $PHP_DB4 ${dbdp5}1 ${dbdp5}0 ${dbdp4}8 ${dbdp4}7 ${dbdp4}6 ${dbdp4}5 ${dbdp4}4 ${dbdp4}3 ${dbdp4}2 ${dbdp4}1 ${dbdp}0 /usr/local /usr; do
@@ -68,7 +68,7 @@ diff -up php-7.2.0alpha0/ext/dba/config.m4.libdb php-7.2.0alpha0/ext/dba/config.
diff -up php-7.2.0alpha0/ext/dba/dba.c.libdb php-7.2.0alpha0/ext/dba/dba.c
--- php-7.2.0alpha0/ext/dba/dba.c.libdb 2017-05-29 09:16:15.736628202 +0200
+++ php-7.2.0alpha0/ext/dba/dba.c 2017-05-29 09:16:20.494654746 +0200
-@@ -53,6 +53,10 @@
+@@ -51,6 +51,10 @@
#include "php_tcadb.h"
#include "php_lmdb.h"
diff --git a/php-7.2.0-oci8conf.patch b/php-7.2.0-oci8conf.patch
index 0ad16a1..3bf1c2e 100644
--- a/php-7.2.0-oci8conf.patch
+++ b/php-7.2.0-oci8conf.patch
@@ -1,7 +1,7 @@
diff -up ./ext/ldap/php_ldap.h.remi-oci8 ./ext/ldap/php_ldap.h
--- ./ext/ldap/php_ldap.h.remi-oci8 2017-06-20 15:45:35.000000000 +0200
+++ ./ext/ldap/php_ldap.h 2017-06-20 16:55:01.640203868 +0200
-@@ -27,7 +27,7 @@
+@@ -25,7 +25,7 @@
#include <lber.h>
#endif
@@ -10,26 +10,4 @@ diff -up ./ext/ldap/php_ldap.h.remi-oci8 ./ext/ldap/php_ldap.h
extern zend_module_entry ldap_module_entry;
#define ldap_module_ptr &ldap_module_entry
-diff -up ./ext/oci8/config.m4.remi-oci8 ./ext/oci8/config.m4
---- ./ext/oci8/config.m4.remi-oci8 2017-06-20 15:45:39.000000000 +0200
-+++ ./ext/oci8/config.m4 2017-06-20 16:55:01.640203868 +0200
-@@ -372,6 +372,7 @@ if test "$PHP_OCI8" != "no"; then
-
- dnl Header directory for Instant Client SDK RPM install
- OCISDKRPMINC=`echo "$PHP_OCI8_INSTANT_CLIENT" | $PHP_OCI8_SED -e 's!^/usr/lib/oracle/\(.*\)/client\('${PHP_OCI8_IC_LIBDIR_SUFFIX}'\)*/lib[/]*$!/usr/include/oracle/\1/client\2!'`
-+ OCISDKRPMINC=`echo "$PHP_OCI8_INSTANT_CLIENT" | $PHP_OCI8_SED -e 's!^/usr/\(lib64\|lib\)/oracle/\(.*\)/\(client64\|client\)/lib[/]*$!/usr/include/oracle/\2/\3!'`
-
- dnl Header directory for Instant Client SDK zip file install
- OCISDKZIPINC=$PHP_OCI8_INSTANT_CLIENT/sdk/include
-diff -up ./ext/pdo_oci/config.m4.remi-oci8 ./ext/pdo_oci/config.m4
---- ./ext/pdo_oci/config.m4.remi-oci8 2017-06-20 16:55:01.640203868 +0200
-+++ ./ext/pdo_oci/config.m4 2017-06-20 17:16:03.053538358 +0200
-@@ -93,7 +93,7 @@ if test "$PHP_PDO_OCI" != "no"; then
-
- AC_MSG_CHECKING([for oci.h])
- dnl Header directory for Instant Client SDK RPM install
-- OCISDKRPMINC=`echo "$PDO_OCI_LIB_DIR" | $PHP_PDO_OCI_SED -e 's!^\(.*\)/lib/oracle/\(.*\)/\('${PDO_OCI_CLIENT_DIR}'\)/lib[/]*$!\1/include/oracle/\2/\3!'`
-+ OCISDKRPMINC=`echo "$PDO_OCI_LIB_DIR" | $PHP_PDO_OCI_SED -e 's!^\(.*\)/\(lib64\|lib\)/oracle/\(.*\)/\('${PDO_OCI_CLIENT_DIR}'\)/lib[/]*$!\1/include/oracle/\3/\4!'`
-
- dnl Header directory for manual installation
- OCISDKMANINC=`echo "$PDO_OCI_LIB_DIR" | $PHP_PDO_OCI_SED -e 's!^\(.*\)/lib[/]*$!\1/include!'`
+
diff --git a/php-7.3.3-systzdata-v19.patch b/php-7.3.3-systzdata-v19.patch
index 866729b..9dde92f 100644
--- a/php-7.3.3-systzdata-v19.patch
+++ b/php-7.3.3-systzdata-v19.patch
@@ -5,6 +5,7 @@ Add support for use of the system timezone database, rather
than embedding a copy. Discussed upstream but was not desired.
History:
+r20: fix possible buffer overflow
r19: retrieve tzdata version from /usr/share/zoneinfo/tzdata.zi
r18: adapt for autotool change in 7.3.3RC1
r17: adapt for timelib 2018.01 (in 7.3.2RC1)
@@ -452,7 +453,7 @@ index 020da3135e..12e68ef043 100644
+ size_t n;
+ char *data, *p;
+
-+ data = malloc(3 * sysdb->index_size + 7);
++ data = malloc(3 * sysdb->index_size + sizeof(FAKE_HEADER) - 1);
+
+ p = mempcpy(data, FAKE_HEADER, sizeof(FAKE_HEADER) - 1);
+
diff --git a/php-7.4.26-openssl3.patch b/php-7.4.26-openssl3.patch
index 9952f34..aec6b96 100644
--- a/php-7.4.26-openssl3.patch
+++ b/php-7.4.26-openssl3.patch
@@ -1,7 +1,7 @@
-From f7da6fd2d5d2160ef67e0bee3ad76f28d7b71983 Mon Sep 17 00:00:00 2001
+From d040474c7c9d6d94e10c6757e5f100ecacabf19f Mon Sep 17 00:00:00 2001
From: Remi Collet <remi@php.net>
Date: Sun, 8 Aug 2021 17:38:30 +0200
-Subject: [PATCH 01/26] minimal fix for openssl 3.0 (#7002)
+Subject: [PATCH 01/27] minimal fix for openssl 3.0 (#7002)
(cherry picked from commit a0972deb0f441fc7991001cb51efc994b70a3b51)
---
@@ -23,12 +23,12 @@ index aa819be422..9cb643601c 100644
REGISTER_LONG_CONSTANT("OPENSSL_PKCS1_OAEP_PADDING", RSA_PKCS1_OAEP_PADDING, CONST_CS|CONST_PERSISTENT);
--
-2.31.1
+2.41.0
-From 557f613efc86158ef65200f2c994c28bad257850 Mon Sep 17 00:00:00 2001
+From ef7710bd3a3ce04ddada7221bf7ba9410d1a0fe8 Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Wed, 4 Aug 2021 09:41:39 +0200
-Subject: [PATCH 02/26] ignore deprecated
+Subject: [PATCH 02/27] ignore deprecated
---
ext/openssl/openssl.c | 2 ++
@@ -73,12 +73,12 @@ index 348831189b..b2cb6164bd 100644
--EXPECT--
bool(true)
--
-2.31.1
+2.41.0
-From c83d7444d35e4b246f84c1adc1353f75fbd4b44c Mon Sep 17 00:00:00 2001
+From c421e4e98b35c1744f784c05ffd34583fbe96c37 Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Wed, 4 Aug 2021 09:46:07 +0200
-Subject: [PATCH 03/26] Reduce security level in some OpenSSL tests
+Subject: [PATCH 03/27] Reduce security level in some OpenSSL tests
This allows tests using older protocols and algorithms to work
under OpenSSL 3.
@@ -345,12 +345,12 @@ index c1aaa04919..84a137b5f4 100644
phpt_wait();
--
-2.31.1
+2.41.0
-From c9a9ef0d62c19bd2b3f89772c5a800781b88d53c Mon Sep 17 00:00:00 2001
+From dfbbf02d413db19dd3337b5b60c55eb974ebb2b7 Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Wed, 4 Aug 2021 09:57:40 +0200
-Subject: [PATCH 04/26] Adjust some tests for whitespace differences in OpenSSL
+Subject: [PATCH 04/27] Adjust some tests for whitespace differences in OpenSSL
3
A trailing newline is no longer present in OpenSSL 3.
@@ -453,12 +453,12 @@ index b80c1f71f1..38915157f3 100644
string(7) "CA:TRUE"
}
--
-2.31.1
+2.41.0
-From dabea364207985e67e138e70106b6977952c2729 Mon Sep 17 00:00:00 2001
+From a8e511110696e83f728faee9294798351c84fb85 Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Wed, 4 Aug 2021 11:55:47 +0200
-Subject: [PATCH 05/26] Use different cipher in openssl_seal() test
+Subject: [PATCH 05/27] Use different cipher in openssl_seal() test
RC4 is insecure and not supported in newer versions.
@@ -518,12 +518,12 @@ index 111bf6f094..588efa707b 100644
Warning: openssl_seal(): not a public key (2th member of pubkeys) in %s on line %d
bool(false)
--
-2.31.1
+2.41.0
-From 55123a11413921e991929fdd3cdab3b855617d11 Mon Sep 17 00:00:00 2001
+From 54f6bd9814a09d57b80933b1cedfd4266286bb9a Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Wed, 4 Aug 2021 11:58:46 +0200
-Subject: [PATCH 06/26] Don't test legacy algorithms in SPKI tests
+Subject: [PATCH 06/27] Don't test legacy algorithms in SPKI tests
MD4 and RMD160 may not be available on newer OpenSSL versions.
@@ -659,12 +659,12 @@ index c760d0cb83..35badcda37 100644
-bool(true)
-bool(false)
--
-2.31.1
+2.41.0
-From dace8e9ff28889d110cc4617b91caca0d722238f Mon Sep 17 00:00:00 2001
+From 9f5fa8ab4e8d5ba1e9e12eac956ba658e2047b93 Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Wed, 4 Aug 2021 12:48:02 +0200
-Subject: [PATCH 07/26] Only report provided ciphers in
+Subject: [PATCH 07/27] Only report provided ciphers in
openssl_get_cipher_methods()
With OpenSSL 3 ciphers may be registered, but not provided. Make
@@ -749,12 +749,12 @@ index 7926b475e7..29d64171d9 100644
#endif
--
-2.31.1
+2.41.0
-From 514a7e50e1bdc5d409c3d66c1593f0ce1a859b8e Mon Sep 17 00:00:00 2001
+From d03ccc6933b4e585980458455b17cb384a3e5ab6 Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Wed, 4 Aug 2021 12:05:02 +0200
-Subject: [PATCH 08/26] Avoid RC4 use in another test
+Subject: [PATCH 08/27] Avoid RC4 use in another test
(cherry picked from commit 503146aa87e48f075f47a093ed7868e323814a66)
---
@@ -788,12 +788,12 @@ index d564bcf8e8..e19f07e7b1 100644
?>
--EXPECTF--
--
-2.31.1
+2.41.0
-From bcc416e4449c78361eefec90c6339839cc198bde Mon Sep 17 00:00:00 2001
+From cafc815c45cdc12ab559c2e9e1c1af0500ca0ca5 Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Thu, 5 Aug 2021 11:50:11 +0200
-Subject: [PATCH 09/26] Relax error check
+Subject: [PATCH 09/27] Relax error check
The precise error is version-dependent, just check that there
is some kind of error reported.
@@ -823,12 +823,12 @@ index 327c916688..3f319b4b24 100644
-error:%s:key size too small
+bool(true)
--
-2.31.1
+2.41.0
-From 269c9b3cff4808d7cb62dde957429c26b7d2ac46 Mon Sep 17 00:00:00 2001
+From 736d5d5eac86df2e5710111f90a0196ce9335c60 Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Thu, 5 Aug 2021 14:59:16 +0200
-Subject: [PATCH 10/26] Add test for openssl_dh_compute_key()
+Subject: [PATCH 10/27] Add test for openssl_dh_compute_key()
This function was not tested at all :(
@@ -874,12 +874,12 @@ index 0000000000..8730f4b57d
+--EXPECT--
+b0049944fa5d36f364dd02e675dde50f8c2d67481c5cf0fe2f248d383eec1d38c23d5ed2644fbef2676bcd6ce148361ca82619c8f93e10506cb89d0a1bdaa0f0bc6f68cef0f7cb6d97d43e8dda3c7a5c5a98ebd2342a605ce530fd46a0602d28d4afc48e92088d0bc42194ca8682a85317f812d81b86cd284eed405df2f76aae84ccd560856e8a3d0ce4f591394bca02eb8a1984ebb41bb19714fb8b579bcafd36a9051d51d075f66229893289d8a0c918bfd222f17803cc532d2cf93bb2a567953323ca409beb3237faae9c6fdfc671594324953badd07dd4770ee09fd19f90045654c5709e92aa614b83594c2f62a8bc3c7e786e54bc1259a0a737c70dd4cc
--
-2.31.1
+2.41.0
-From 6f81d18232ee8e17c2f299dc3008727b420ce114 Mon Sep 17 00:00:00 2001
+From 95ede22356cdcfb4053850437eb3bb59f8190e5c Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Wed, 4 Aug 2021 14:54:59 +0200
-Subject: [PATCH 11/26] Use different algorithm in pkcs7 tests
+Subject: [PATCH 11/27] Use different algorithm in pkcs7 tests
The default of OPENSSL_CIPHER_RC2_40 is no longer (non-legacy)
supported in OpenSSL 3, specify a newer cipher instead.
@@ -965,12 +965,12 @@ index f823462f9e..e38a006d0c 100644
bool(true)
true
--
-2.31.1
+2.41.0
-From 9f9df4446699cd09cd70046f8bee66272aca2dac Mon Sep 17 00:00:00 2001
+From 1942dc87aaa0e473ec74d5be68866b327a2dd62b Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Thu, 5 Aug 2021 17:07:44 +0200
-Subject: [PATCH 12/26] Use larger key size for DSA/DH tests
+Subject: [PATCH 12/27] Use larger key size for DSA/DH tests
OpenSSL 3 validates allowed sizes strictly, pick minimum sizes
that are supported.
@@ -1014,12 +1014,12 @@ index c5f5575e2c..7beb020a4c 100644
?>
--EXPECTF--
--
-2.31.1
+2.41.0
-From 261db4fde8b2de3d0b39cac5d376ef425aad7ef2 Mon Sep 17 00:00:00 2001
+From b8904668632df0eadb5f24b365f1b2189f6694c7 Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Wed, 4 Aug 2021 13:54:26 +0200
-Subject: [PATCH 13/26] Skip some tests if cipher not available
+Subject: [PATCH 13/27] Skip some tests if cipher not available
(cherry picked from commit d23a8b33abc3cd7e516563877a3f698b7a94ac10)
---
@@ -1084,22 +1084,20 @@ index 4175e703d2..e846b42e78 100644
+bool(true)
NULL
--
-2.31.1
+2.41.0
-From 93c0873333a8b257edb082d3f106fdef67495c44 Mon Sep 17 00:00:00 2001
+From 1f611e84806818b53cda70708f7eb6d1915b2887 Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Fri, 6 Aug 2021 10:35:49 +0200
-Subject: [PATCH 14/26] Generate pkcs12_read test inputs on the fly
+Subject: [PATCH 14/27] Generate pkcs12_read test inputs on the fly
The old p12_with_extra_certs.p12 file uses an unsupported something.
(cherry picked from commit 5843ba518cfb9ac6ae6d6a69629239cbf77d4cfb)
---
- ext/openssl/tests/bug74022_2.phpt | 10 ++--
- .../tests/openssl_pkcs12_read_basic.phpt | 46 ++++++++++--------
- ext/openssl/tests/p12_with_extra_certs.p12 | Bin 3205 -> 0 bytes
- 3 files changed, 31 insertions(+), 25 deletions(-)
- delete mode 100644 ext/openssl/tests/p12_with_extra_certs.p12
+ ext/openssl/tests/bug74022_2.phpt | 10 ++--
+ .../tests/openssl_pkcs12_read_basic.phpt | 46 ++++++++++---------
+ 2 files changed, 31 insertions(+), 25 deletions(-)
diff --git a/ext/openssl/tests/bug74022_2.phpt b/ext/openssl/tests/bug74022_2.phpt
index 07cb683274..4220149db2 100644
@@ -1188,14 +1186,13 @@ index b81b4d9dac..8cb2b41fd7 100644
-----END CERTIFICATE-----
"
}
-
--
-2.31.1
+2.41.0
-From 64bedf19c7caa47193c22f6fbb134574eb0cf2dd Mon Sep 17 00:00:00 2001
+From 770edaa92bbf183455a60b902b12fc33ff56e95a Mon Sep 17 00:00:00 2001
From: Jakub Zelenka <bukka@php.net>
Date: Sun, 8 Aug 2021 20:54:46 +0100
-Subject: [PATCH 15/26] Make CertificateGenerator not dependent on external
+Subject: [PATCH 15/27] Make CertificateGenerator not dependent on external
config in OpenSSL 3.0
(cherry picked from commit c90c9c7545427d9d35cbac45c4ec896f54619744)
@@ -1248,12 +1245,12 @@ index b409376058..6fe9b4e9a8 100644
file_put_contents($file, $certText . PHP_EOL . $keyText);
} finally {
--
-2.31.1
+2.41.0
-From f2c252b9a083c01eff3f665a406efe5b44f323a3 Mon Sep 17 00:00:00 2001
+From 1234e56683d3f040eb98f7aabf745cf7baccc0e4 Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Tue, 10 Aug 2021 11:50:18 +0200
-Subject: [PATCH 16/26] Fork openssl_error_string() test for OpenSSL
+Subject: [PATCH 16/27] Fork openssl_error_string() test for OpenSSL
The used error code differ signficantly, so use a separate test
file.
@@ -1284,12 +1281,12 @@ index cdf558e9a5..f9f0e7062f 100644
<?php
// helper function to check openssl errors
--
-2.31.1
+2.41.0
-From dc1751ad95ebb04e756809e837feb9aac7a2fefe Mon Sep 17 00:00:00 2001
+From 49c081a3d22d621a3024d7ea4c32f0350228c60b Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Sun, 8 Aug 2021 17:39:06 +0200
-Subject: [PATCH 17/26] Use OpenSSL NCONF APIs (#7337)
+Subject: [PATCH 17/27] Use OpenSSL NCONF APIs (#7337)
(cherry picked from commit 94bc5fce261a4a56a545bdfb25d5c2452a07de08)
---
@@ -1462,12 +1459,12 @@ index e0b3772a29..666616e7c5 100644
{
php_openssl_store_errors();
--
-2.31.1
+2.41.0
-From df4e7dcc8121c444ff315e31d06182f164e686ed Mon Sep 17 00:00:00 2001
+From 95dd07c54542ac48cf7d43392f61b0423b04fe63 Mon Sep 17 00:00:00 2001
From: Jakub Zelenka <bukka@php.net>
Date: Sun, 12 Sep 2021 20:30:02 +0100
-Subject: [PATCH 18/26] Make OpenSSL tests less dependent on system config
+Subject: [PATCH 18/27] Make OpenSSL tests less dependent on system config
It fixes dependencies on system config if running tests with OpenSSL 3.0
@@ -1559,12 +1556,12 @@ index 41567e9b32..6c09238003 100644
$keyFailed = openssl_pkey_new($argsFailed);
--
-2.31.1
+2.41.0
-From 03f65a015256933426d2c87b399a4c4620b4c85c Mon Sep 17 00:00:00 2001
+From 6167fdd70654ff63a6a759cffbbdb5468e5c517a Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Fri, 6 Aug 2021 11:15:18 +0200
-Subject: [PATCH 19/26] Do not special case export of EC keys
+Subject: [PATCH 19/27] Do not special case export of EC keys
All other private keys are exported in PKCS#8 format, while EC
keys use traditional format. Switch them to use PKCS#8 format as
@@ -1578,10 +1575,9 @@ As the OpenSSL docs say:
(cherry picked from commit f2d3e75933fa155a5281c824263780dbc660ecb1)
---
- UPGRADING | 4 +++
ext/openssl/openssl.c | 36 ++++---------------
.../tests/openssl_pkey_export_basic.phpt | 6 +++-
- 3 files changed, 15 insertions(+), 31 deletions(-)
+ 2 files changed, 11 insertions(+), 31 deletions(-)
diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c
index 666616e7c5..4af0942209 100644
@@ -1655,12 +1651,12 @@ index d71f8da9a3..47a82d7873 100644
bool(true)
resource(%d) of type (OpenSSL key)
--
-2.31.1
+2.41.0
-From 038c33feab7e6138f7977224897118dbb8059a55 Mon Sep 17 00:00:00 2001
+From 94c952911ba9b53470056f0e679c842311e601e5 Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Thu, 5 Aug 2021 10:29:50 +0200
-Subject: [PATCH 20/26] Use EVP_PKEY APIs for key generation
+Subject: [PATCH 20/27] Use EVP_PKEY APIs for key generation
Use high level API instead of deprecated low level API.
@@ -1915,12 +1911,12 @@ index 4af0942209..588aa3902f 100644
/* }}} */
--
-2.31.1
+2.41.0
-From cc5ad532e6672ac74007caa83f2fb7796f69510b Mon Sep 17 00:00:00 2001
+From 3e896d255c644a0d1c27a6c19e074b43bfc4c5ac Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Mon, 9 Aug 2021 10:26:12 +0200
-Subject: [PATCH 21/26] Extract EC key initialization
+Subject: [PATCH 21/27] Extract EC key initialization
(cherry picked from commit 14d7c7e9aee5ab55a92ddc626b7b81c130ea7618)
---
@@ -2186,12 +2182,12 @@ index 588aa3902f..5671311508 100644
}
}
--
-2.31.1
+2.41.0
-From 7c3f98fb5000b95419848b3b2519b677e8852f3f Mon Sep 17 00:00:00 2001
+From 9ac7bdc3d7eb104d7d95e2b1aa4e2b631f45051b Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Mon, 9 Aug 2021 12:01:35 +0200
-Subject: [PATCH 22/26] Test calculation of EC public key from private key
+Subject: [PATCH 22/27] Test calculation of EC public key from private key
(cherry picked from commit 246698671f941b2034518ab04f35009b2da77bb1)
---
@@ -2229,12 +2225,12 @@ index 6c09238003..ecc34a3330 100644
NULL
resource(%d) of type (OpenSSL key)
--
-2.31.1
+2.41.0
-From 3b17fa3a6a34fd169c34e3d1dbb315c4c691c649 Mon Sep 17 00:00:00 2001
+From d8ffb2117e6b986cb4a5b8e5c0cf5c74af8a32fc Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Mon, 9 Aug 2021 11:12:20 +0200
-Subject: [PATCH 23/26] Use param API for creating EC keys
+Subject: [PATCH 23/27] Use param API for creating EC keys
Rather than the deprecated low level APIs.
@@ -2386,12 +2382,12 @@ index 5671311508..5a76057c5f 100644
#endif
--
-2.31.1
+2.41.0
-From 76efdaf49ccfb4462ce9493c04b5542570f72907 Mon Sep 17 00:00:00 2001
+From c1047e5c4bf6919ab9600318721d4fa6cbebb40b Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Mon, 9 Aug 2021 14:19:33 +0200
-Subject: [PATCH 24/26] Extract public key portion via PEM roundtrip
+Subject: [PATCH 24/27] Extract public key portion via PEM roundtrip
The workaround with cloning the X509_REQ no longer works in
OpenSSL 3. Instead extract the public key portion by round
@@ -2476,12 +2472,12 @@ index 5a76057c5f..00ab6dc73a 100644
if (tpubkey == NULL) {
--
-2.31.1
+2.41.0
-From 134c4303f6ddca2553dadfe4e56808ef00ba39dd Mon Sep 17 00:00:00 2001
+From ee274b8bb13e8f9a3df79550be2ea3e4538c6326 Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Tue, 10 Aug 2021 12:17:17 +0200
-Subject: [PATCH 25/26] Switch dh_param handling to EVP_PKEY API
+Subject: [PATCH 25/27] Switch dh_param handling to EVP_PKEY API
(cherry picked from commit ef787bae242fdd2e72625bbce6ab4ca466b1ef59)
---
@@ -2546,12 +2542,12 @@ index 9710e44a07..f130bdee66 100644
return SUCCESS;
}
--
-2.31.1
+2.41.0
-From 7557896fc206bd318851b3810b55bb51dc43336f Mon Sep 17 00:00:00 2001
+From 6bb3f5d83ea5a108018b22b5e5b3b7dff77a66de Mon Sep 17 00:00:00 2001
From: Remi Collet <remi@remirepo.net>
Date: Thu, 18 Nov 2021 15:08:19 +0100
-Subject: [PATCH 26/26] ignore remaining warnings
+Subject: [PATCH 26/27] ignore remaining warnings
---
ext/openssl/openssl.c | 3 ++-
@@ -2579,5 +2575,66 @@ index 00ab6dc73a..b136729cb5 100644
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
OSSL_PARAM *params = NULL;
--
-2.31.1
+2.41.0
+
+From 5019534853051a3cb3cce9811e98e583e568e112 Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@remirepo.net>
+Date: Mon, 26 Jun 2023 07:59:18 +0200
+Subject: [PATCH 27/27] don't use true
+
+---
+ ext/openssl/openssl.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c
+index b136729cb5..d0fd976376 100644
+--- a/ext/openssl/openssl.c
++++ b/ext/openssl/openssl.c
+@@ -4454,7 +4454,7 @@ static int php_openssl_pkey_init_legacy_ec(EC_KEY *eckey, zval *data, int *is_pr
+ }
+
+ if (!EC_KEY_check_key(eckey)) {
+- *is_private = true;
++ *is_private = 1;
+ PHP_OPENSSL_RAND_ADD_TIME();
+ EC_KEY_generate_key(eckey);
+ php_openssl_store_errors();
+--
+2.41.0
+
+From 74f75db0c3665677ec006cd379fd561feacffdc6 Mon Sep 17 00:00:00 2001
+From: Jakub Zelenka <bukka@php.net>
+Date: Sun, 15 May 2022 13:49:17 +0100
+Subject: [PATCH] Fix bug #79589: ssl3_read_n:unexpected eof while reading
+The unexpected EOF failure was introduced in OpenSSL 3.0 to prevent
+truncation attack. However there are many non complaint servers and
+it is causing break for many users including potential majority
+of those where the truncation attack is not applicable. For that reason
+we try to keep behavior consitent with older OpenSSL versions which is
+also the path chosen by some other languages and web servers.
+
+Closes GH-8369
+---
+ NEWS | 4 ++++
+ ext/openssl/tests/bug79589.phpt | 21 +++++++++++++++++++++
+ ext/openssl/xp_ssl.c | 5 +++++
+ 3 files changed, 30 insertions(+)
+ create mode 100644 ext/openssl/tests/bug79589.phpt
+
+diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c
+index 918b3ca5b21df..ce23fb29f4296 100644
+--- a/ext/openssl/xp_ssl.c
++++ b/ext/openssl/xp_ssl.c
+@@ -1652,6 +1652,11 @@ int php_openssl_setup_crypto(php_stream *stream,
+
+ ssl_ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
+
++#ifdef SSL_OP_IGNORE_UNEXPECTED_EOF
++ /* Only for OpenSSL 3+ to keep OpenSSL 1.1.1 behavior */
++ ssl_ctx_options |= SSL_OP_IGNORE_UNEXPECTED_EOF;
++#endif
++
+ if (!GET_VER_OPT("disable_compression") || zend_is_true(val)) {
+ ssl_ctx_options |= SSL_OP_NO_COMPRESSION;
+ }
diff --git a/php-7.4.33-gcc14.patch b/php-7.4.33-gcc14.patch
new file mode 100644
index 0000000..eef34ad
--- /dev/null
+++ b/php-7.4.33-gcc14.patch
@@ -0,0 +1,201 @@
+diff -up php-7.4.33/ext/pdo_oci/oci_statement.c.gcc14 php-7.4.33/ext/pdo_oci/oci_statement.c
+--- php-7.4.33/ext/pdo_oci/oci_statement.c.gcc14 2022-10-31 11:36:05.000000000 +0100
++++ php-7.4.33/ext/pdo_oci/oci_statement.c 2024-02-14 15:05:34.224568567 +0100
+@@ -654,7 +654,7 @@ static ssize_t oci_blob_write(php_stream
+ return amt;
+ }
+
+-static size_t oci_blob_read(php_stream *stream, char *buf, size_t count)
++static ssize_t oci_blob_read(php_stream *stream, char *buf, size_t count)
+ {
+ struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
+ ub4 amt;
+@@ -666,7 +666,7 @@ static size_t oci_blob_read(php_stream *
+ NULL, NULL, 0, SQLCS_IMPLICIT);
+
+ if (r != OCI_SUCCESS && r != OCI_NEED_DATA) {
+- return (size_t)-1;
++ return -1;
+ }
+
+ self->offset += amt;
+diff -up php-7.4.33/sapi/litespeed/lsapi_main.c.gcc14 php-7.4.33/sapi/litespeed/lsapi_main.c
+--- php-7.4.33/sapi/litespeed/lsapi_main.c.gcc14 2024-02-14 15:09:59.523706463 +0100
++++ php-7.4.33/sapi/litespeed/lsapi_main.c 2024-02-14 15:10:13.979258854 +0100
+@@ -25,6 +25,7 @@
+ #include "zend.h"
+ #include "ext/standard/basic_functions.h"
+ #include "ext/standard/info.h"
++#include "ext/standard/head.h"
+ #include "lsapilib.h"
+
+ #include <stdio.h>
+
+
+Adapted for 7.4 from:
+
+From aeaab8ee3e52f74c042a861e394437d6554b36be Mon Sep 17 00:00:00 2001
+From: Florian Weimer <fweimer@redhat.com>
+Date: Mon, 9 Sep 2019 21:29:03 +0200
+Subject: [PATCH] Port various autoconf bits to C99 compilers
+
+C99 no longer has implicit function declarations and implicit ints.
+Current GCC versions enable them as an extension, but this will
+change in a future GCC version.
+---
+ Zend/Zend.m4 | 2 ++
+ build/libtool.m4 | 5 +----
+ build/php.m4 | 17 ++++++++++-------
+ configure.ac | 2 ++
+ ext/standard/config.m4 | 22 ++++++++++++++++++++++
+ 5 files changed, 37 insertions(+), 11 deletions(-)
+
+diff --git a/Zend/Zend.m4 b/Zend/Zend.m4
+index 054e2621a4057..57a12ac36ba60 100644
+--- a/Zend/Zend.m4
++++ b/Zend/Zend.m4
+@@ -157,6 +157,7 @@ AC_MSG_CHECKING(whether double cast to long preserves least significant bits)
+
+ AC_RUN_IFELSE([AC_LANG_SOURCE([[
+ #include <limits.h>
++#include <stdlib.h>
+
+ int main()
+ {
+@@ -256,6 +257,7 @@ AC_MSG_CHECKING(for MM alignment and log values)
+
+ AC_RUN_IFELSE([AC_LANG_SOURCE([[
+ #include <stdio.h>
++#include <stdlib.h>
+
+ typedef union _mm_align_test {
+ void *ptr;
+diff --git a/build/libtool.m4 b/build/libtool.m4
+index f7f51642920f9..577dad4cbe313 100644
+--- a/build/libtool.m4
++++ b/build/libtool.m4
+@@ -945,6 +945,7 @@ else
+ #endif
+
+ #include <stdio.h>
++#include <stdlib.h>
+
+ #ifdef RTLD_GLOBAL
+ # define LT_DLGLOBAL RTLD_GLOBAL
+diff --git a/build/php.m4 b/build/php.m4
+index 25f5aa762b892..529876b6b67c6 100644
+--- a/build/php.m4
++++ b/build/php.m4
+@@ -1120,7 +1120,7 @@ AC_CACHE_CHECK(for type of reentrant time-related functions, ac_cv_time_r_type,[
+ AC_RUN_IFELSE([AC_LANG_SOURCE([[
+ #include <time.h>
+
+-main() {
++int main() {
+ char buf[27];
+ struct tm t;
+ time_t old = 0;
+@@ -1136,7 +1136,7 @@ return (1);
+ ],[
+ AC_RUN_IFELSE([AC_LANG_SOURCE([[
+ #include <time.h>
+-main() {
++int main() {
+ struct tm t, *s;
+ time_t old = 0;
+ char buf[27], *p;
+@@ -1597,7 +1600,7 @@ AC_DEFUN([PHP_CHECK_FUNC_LIB],[
+ if test "$found" = "yes"; then
+ ac_libs=$LIBS
+ LIBS="$LIBS -l$2"
+- AC_RUN_IFELSE([AC_LANG_SOURCE([[main() { return (0); }]])],[found=yes],[found=no],[found=no])
++ AC_RUN_IFELSE([AC_LANG_SOURCE([[int main() { return (0); }]])],[found=yes],[found=no],[found=no])
+ LIBS=$ac_libs
+ fi
+
+@@ -2285,7 +2288,7 @@ AC_DEFUN([PHP_TEST_WRITE_STDOUT],[
+
+ #define TEXT "This is the test message -- "
+
+-main()
++int main()
+ {
+ int n;
+
+diff --git a/configure.ac b/configure.ac
+index d759b027517e5..e15b83ca25296 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -665,6 +665,8 @@
+ #include <string.h>
+ #include <netdb.h>
+ #include <sys/types.h>
++#include <string.h>
++#include <stdlib.h>
+ #ifndef AF_INET
+ # include <sys/socket.h>
+ #endif
+diff --git a/ext/standard/config.m4 b/ext/standard/config.m4
+index 9f85ec2b7080d..5b49e5d661f3c 100644
+--- a/ext/standard/config.m4
++++ b/ext/standard/config.m4
+@@ -71,6 +71,9 @@ AC_CACHE_CHECK(for standard DES crypt, ac_cv_crypt_des,[
+ #include <crypt.h>
+ #endif
+
++#include <stdlib.h>
++#include <string.h>
++
+ int main() {
+ #if HAVE_CRYPT
+ char *encrypted = crypt("rasmuslerdorf","rl");
+@@ -98,6 +101,9 @@ AC_CACHE_CHECK(for extended DES crypt, ac_cv_crypt_ext_des,[
+ #include <crypt.h>
+ #endif
+
++#include <stdlib.h>
++#include <string.h>
++
+ int main() {
+ #if HAVE_CRYPT
+ char *encrypted = crypt("rasmuslerdorf","_J9..rasm");
+@@ -125,6 +131,9 @@ AC_RUN_IFELSE([AC_LANG_SOURCE([[
+ #include <crypt.h>
+ #endif
+
++#include <stdlib.h>
++#include <string.h>
++
+ int main() {
+ #if HAVE_CRYPT
+ char salt[15], answer[40];
+@@ -162,6 +171,9 @@ AC_RUN_IFELSE([AC_LANG_SOURCE([[
+ #include <crypt.h>
+ #endif
+
++#include <stdlib.h>
++#include <string.h>
++
+ int main() {
+ #if HAVE_CRYPT
+ char salt[30], answer[70];
+@@ -196,6 +208,9 @@ AC_RUN_IFELSE([AC_LANG_SOURCE([[
+ #include <crypt.h>
+ #endif
+
++#include <stdlib.h>
++#include <string.h>
++
+ int main() {
+ #if HAVE_CRYPT
+ char salt[21], answer[21+86];
+@@ -229,6 +244,9 @@ AC_RUN_IFELSE([AC_LANG_SOURCE([[
+ #include <crypt.h>
+ #endif
+
++#include <stdlib.h>
++#include <string.h>
++
+ int main() {
+ #if HAVE_CRYPT
+ char salt[21], answer[21+43];
diff --git a/php-7.4.33-icu.patch b/php-7.4.33-icu.patch
new file mode 100644
index 0000000..48940fd
--- /dev/null
+++ b/php-7.4.33-icu.patch
@@ -0,0 +1,35 @@
+From cc46a4e6b5a413bab3e264c1dcaaf7052f54fbc4 Mon Sep 17 00:00:00 2001
+From: David Carlier <devnexen@gmail.com>
+Date: Sat, 17 Feb 2024 21:38:21 +0000
+Subject: [PATCH] ext/intl: level up c++ runtime std for icu 74 and onwards.
+
+to align with what is required to build icu 74 itself.
+
+Close GH-14002
+---
+ NEWS | 3 +++
+ ext/intl/config.m4 | 11 ++++++++++-
+ 2 files changed, 13 insertions(+), 1 deletion(-)
+
+diff --git a/ext/intl/config.m4 b/ext/intl/config.m4
+index dd687bcd97de3..48f5147ca7bbf 100644
+--- a/ext/intl/config.m4
++++ b/ext/intl/config.m4
+@@ -83,7 +83,16 @@ if test "$PHP_INTL" != "no"; then
+ breakiterator/codepointiterator_methods.cpp"
+
+ PHP_REQUIRE_CXX()
+- PHP_CXX_COMPILE_STDCXX(11, mandatory, PHP_INTL_STDCXX)
++
++ AC_MSG_CHECKING([if intl requires -std=gnu++17])
++ AS_IF([test "$PKG_CONFIG icu-uc --atleast-version=74"],[
++ AC_MSG_RESULT([yes])
++ PHP_CXX_COMPILE_STDCXX(17, mandatory, PHP_INTL_STDCXX)
++ ],[
++ AC_MSG_RESULT([no])
++ PHP_CXX_COMPILE_STDCXX(11, mandatory, PHP_INTL_STDCXX)
++ ])
++
+ PHP_INTL_CXX_FLAGS="$INTL_COMMON_FLAGS $PHP_INTL_STDCXX $ICU_CXXFLAGS"
+ if test "$ext_shared" = "no"; then
+ PHP_ADD_SOURCES(PHP_EXT_DIR(intl), $PHP_INTL_CXX_SOURCES, $PHP_INTL_CXX_FLAGS)
diff --git a/php-7.4.33-libxml212.patch b/php-7.4.33-libxml212.patch
new file mode 100644
index 0000000..2de8abb
--- /dev/null
+++ b/php-7.4.33-libxml212.patch
@@ -0,0 +1,661 @@
+From 1fa2356f4f580d2df4068809a4aba6d5356a22e6 Mon Sep 17 00:00:00 2001
+From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
+Date: Fri, 17 Nov 2023 19:45:40 +0100
+Subject: [PATCH 1/4] Fix GH-12702: libxml2 2.12.0 issue building from src
+
+Fixes GH-12702.
+
+Co-authored-by: nono303 <github@nono303.net>
+---
+ ext/dom/document.c | 1 +
+ ext/libxml/php_libxml.h | 1 +
+ 2 files changed, 2 insertions(+)
+
+diff --git a/ext/dom/document.c b/ext/dom/document.c
+index b478e1a1aa..707a1fbb20 100644
+--- a/ext/dom/document.c
++++ b/ext/dom/document.c
+@@ -25,6 +25,7 @@
+ #if HAVE_LIBXML && HAVE_DOM
+ #include "php_dom.h"
+ #include <libxml/SAX.h>
++#include <libxml/xmlsave.h>
+ #ifdef LIBXML_SCHEMAS_ENABLED
+ #include <libxml/relaxng.h>
+ #include <libxml/xmlschemas.h>
+diff --git a/ext/libxml/php_libxml.h b/ext/libxml/php_libxml.h
+index cf936e95de..9bbcbf6783 100644
+--- a/ext/libxml/php_libxml.h
++++ b/ext/libxml/php_libxml.h
+@@ -37,6 +37,7 @@ extern zend_module_entry libxml_module_entry;
+
+ #include "zend_smart_str.h"
+ #include <libxml/tree.h>
++#include <libxml/parser.h>
+
+ #define LIBXML_SAVE_NOEMPTYTAG 1<<2
+
+--
+2.43.0
+
+From c2a134e08fe4ac4a2ed753548a18fc27da8ae2e1 Mon Sep 17 00:00:00 2001
+From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
+Date: Fri, 1 Dec 2023 18:03:35 +0100
+Subject: [PATCH 2/4] Fix libxml2 2.12 build due to API breaks
+
+See https://github.com/php/php-src/actions/runs/7062192818/job/19225478601
+---
+ ext/libxml/libxml.c | 14 ++++++++++----
+ ext/soap/php_sdl.c | 2 +-
+ 2 files changed, 11 insertions(+), 5 deletions(-)
+
+diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c
+index d343135b98..b54ab40953 100644
+--- a/ext/libxml/libxml.c
++++ b/ext/libxml/libxml.c
+@@ -530,7 +530,11 @@ static int _php_libxml_free_error(xmlErrorPtr error)
+ return 1;
+ }
+
+-static void _php_list_set_error_structure(xmlErrorPtr error, const char *msg)
++#if LIBXML_VERSION >= 21200
++static void _php_list_set_error_structure(const xmlError *error, const char *msg)
++#else
++static void _php_list_set_error_structure(xmlError *error, const char *msg)
++#endif
+ {
+ xmlError error_copy;
+ int ret;
+@@ -782,7 +786,11 @@ PHP_LIBXML_API void php_libxml_ctx_warning(void *ctx, const char *msg, ...)
+ va_end(args);
+ }
+
++#if LIBXML_VERSION >= 21200
++PHP_LIBXML_API void php_libxml_structured_error_handler(void *userData, const xmlError *error)
++#else
+ PHP_LIBXML_API void php_libxml_structured_error_handler(void *userData, xmlErrorPtr error)
++#endif
+ {
+ _php_list_set_error_structure(error, NULL);
+
+@@ -1061,9 +1069,7 @@ static PHP_FUNCTION(libxml_use_internal_errors)
+ Retrieve last error from libxml */
+ static PHP_FUNCTION(libxml_get_last_error)
+ {
+- xmlErrorPtr error;
+-
+- error = xmlGetLastError();
++ const xmlError *error = xmlGetLastError();
+
+ if (error) {
+ object_init_ex(return_value, libxmlerror_class_entry);
+diff --git a/ext/soap/php_sdl.c b/ext/soap/php_sdl.c
+index 26a23f57db..3df532a2d6 100644
+--- a/ext/soap/php_sdl.c
++++ b/ext/soap/php_sdl.c
+@@ -333,7 +333,7 @@ static void load_wsdl_ex(zval *this_ptr, char *struri, sdlCtx *ctx, int include)
+ sdl_restore_uri_credentials(ctx);
+
+ if (!wsdl) {
+- xmlErrorPtr xmlErrorPtr = xmlGetLastError();
++ const xmlError *xmlErrorPtr = xmlGetLastError();
+
+ if (xmlErrorPtr) {
+ soap_error2(E_ERROR, "Parsing WSDL: Couldn't load from '%s' : %s", struri, xmlErrorPtr->message);
+--
+2.43.0
+
+From f9da49aa0a5b033c4b1e8072b9c0915d7672f34e Mon Sep 17 00:00:00 2001
+From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
+Date: Sat, 29 Apr 2023 21:07:50 +0200
+Subject: [PATCH 3/4] Fix GH-11160: Few tests failed building with new libxml
+ 2.11.0
+
+It's possible to categorise the failures into 2 categories:
+ - Changed error message. In this case we either duplicate the test and
+ modify the error message. Or if the change in error message is
+ small, we use the EXPECTF matchers to make the test compatible with both
+ old and new versions of libxml2.
+ - Missing warnings. This is caused by a change in libxml2 where the
+ parser started using SAX APIs internally [1]. In this case the
+ error_type passed to php_libxml_internal_error_handler() changed from
+ PHP_LIBXML_ERROR to PHP_LIBXML_CTX_WARNING because it internally
+ started to use the SAX handlers instead of the generic handlers.
+ However, for the SAX handlers the current input stack is empty, so
+ nothing is actually printed. I fixed this by falling back to a
+ regular warning without a filename & line number reference, which
+ mimicks the old behaviour. Furthermore, this change now also shows
+ an additional warning in a test which was previously hidden.
+
+[1] https://gitlab.gnome.org/GNOME/libxml2/-/commit/9a82b94a94bd310db426edd453b0f38c6c8f69f5
+
+Closes GH-11162.
+---
+ .../DOMDocument_loadXML_error2_gte2_11.phpt | 34 +++++++
+ ...> DOMDocument_loadXML_error2_pre2_11.phpt} | 4 +
+ .../DOMDocument_load_error2_gte2_11.phpt | 34 +++++++
+ ...t => DOMDocument_load_error2_pre2_11.phpt} | 4 +
+ ext/libxml/libxml.c | 2 +
+ ext/libxml/tests/bug61367-read_2.phpt | 2 +-
+ .../tests/libxml_disable_entity_loader_2.phpt | 2 +-
+ ...set_external_entity_loader_variation2.phpt | 2 +
+ ext/xml/tests/bug26614_libxml_gte2_11.phpt | 95 +++++++++++++++++++
+ ...bxml.phpt => bug26614_libxml_pre2_11.phpt} | 1 +
+ 10 files changed, 178 insertions(+), 2 deletions(-)
+ create mode 100644 ext/dom/tests/DOMDocument_loadXML_error2_gte2_11.phpt
+ rename ext/dom/tests/{DOMDocument_loadXML_error2.phpt => DOMDocument_loadXML_error2_pre2_11.phpt} (90%)
+ create mode 100644 ext/dom/tests/DOMDocument_load_error2_gte2_11.phpt
+ rename ext/dom/tests/{DOMDocument_load_error2.phpt => DOMDocument_load_error2_pre2_11.phpt} (90%)
+ create mode 100644 ext/xml/tests/bug26614_libxml_gte2_11.phpt
+ rename ext/xml/tests/{bug26614_libxml.phpt => bug26614_libxml_pre2_11.phpt} (96%)
+
+diff --git a/ext/dom/tests/DOMDocument_loadXML_error2_gte2_11.phpt b/ext/dom/tests/DOMDocument_loadXML_error2_gte2_11.phpt
+new file mode 100644
+index 0000000000..ff5ceb3fbe
+--- /dev/null
++++ b/ext/dom/tests/DOMDocument_loadXML_error2_gte2_11.phpt
+@@ -0,0 +1,34 @@
++--TEST--
++Test DOMDocument::loadXML() detects not-well formed XML
++--SKIPIF--
++<?php
++if (LIBXML_VERSION < 21100) die('skip libxml2 test variant for version >= 2.11');
++?>
++--DESCRIPTION--
++This test verifies the method detects attributes values not closed between " or '
++Environment variables used in the test:
++- XML_FILE: the xml file to load
++- LOAD_OPTIONS: the second parameter to pass to the method
++- EXPECTED_RESULT: the expected result
++--CREDITS--
++Antonio Diaz Ruiz <dejalatele@gmail.com>
++--INI--
++assert.bail=true
++--EXTENSIONS--
++dom
++--ENV--
++XML_FILE=/not_well_formed2.xml
++LOAD_OPTIONS=0
++EXPECTED_RESULT=0
++--FILE_EXTERNAL--
++domdocumentloadxml_test_method.inc
++--EXPECTF--
++Warning: DOMDocument::loadXML(): AttValue: " or ' expected in Entity, line: 4 in %s on line %d
++
++Warning: DOMDocument::loadXML(): internal error: xmlParseStartTag: problem parsing attributes in Entity, line: 4 in %s on line %d
++
++Warning: DOMDocument::loadXML(): Couldn't find end of Start Tag book line 4 in Entity, line: 4 in %s on line %d
++
++Warning: DOMDocument::loadXML(): Opening and ending tag mismatch: books line 3 and book in Entity, line: 7 in %s on line %d
++
++Warning: DOMDocument::loadXML(): Extra content at the end of the document in Entity, line: 8 in %s on line %d
+diff --git a/ext/dom/tests/DOMDocument_loadXML_error2.phpt b/ext/dom/tests/DOMDocument_loadXML_error2_pre2_11.phpt
+similarity index 90%
+rename from ext/dom/tests/DOMDocument_loadXML_error2.phpt
+rename to ext/dom/tests/DOMDocument_loadXML_error2_pre2_11.phpt
+index 6d56a317ed..0e36d20905 100644
+--- a/ext/dom/tests/DOMDocument_loadXML_error2.phpt
++++ b/ext/dom/tests/DOMDocument_loadXML_error2_pre2_11.phpt
+@@ -1,5 +1,9 @@
+ --TEST--
+ Test DOMDocument::loadXML() detects not-well formed XML
++--SKIPIF--
++<?php
++if (LIBXML_VERSION >= 21100) die('skip libxml2 test variant for version < 2.11');
++?>
+ --DESCRIPTION--
+ This test verifies the method detects attributes values not closed between " or '
+ Environment variables used in the test:
+diff --git a/ext/dom/tests/DOMDocument_load_error2_gte2_11.phpt b/ext/dom/tests/DOMDocument_load_error2_gte2_11.phpt
+new file mode 100644
+index 0000000000..32b6bf1611
+--- /dev/null
++++ b/ext/dom/tests/DOMDocument_load_error2_gte2_11.phpt
+@@ -0,0 +1,34 @@
++--TEST--
++Test DOMDocument::load() detects not-well formed
++--SKIPIF--
++<?php
++if (LIBXML_VERSION < 21100) die('skip libxml2 test variant for version >= 2.11');
++?>
++--DESCRIPTION--
++This test verifies the method detects attributes values not closed between " or '
++Environment variables used in the test:
++- XML_FILE: the xml file to load
++- LOAD_OPTIONS: the second parameter to pass to the method
++- EXPECTED_RESULT: the expected result
++--CREDITS--
++Antonio Diaz Ruiz <dejalatele@gmail.com>
++--INI--
++assert.bail=true
++--EXTENSIONS--
++dom
++--ENV--
++XML_FILE=/not_well_formed2.xml
++LOAD_OPTIONS=0
++EXPECTED_RESULT=0
++--FILE_EXTERNAL--
++domdocumentload_test_method.inc
++--EXPECTF--
++Warning: DOMDocument::load(): AttValue: " or ' expected in %s on line %d
++
++Warning: DOMDocument::load(): internal error: xmlParseStartTag: problem parsing attributes in %s on line %d
++
++Warning: DOMDocument::load(): Couldn't find end of Start Tag book line 4 in %s on line %d
++
++Warning: DOMDocument::load(): Opening and ending tag mismatch: books line 3 and book in %s on line %d
++
++Warning: DOMDocument::load(): Extra content at the end of the document in %s on line %d
+diff --git a/ext/dom/tests/DOMDocument_load_error2.phpt b/ext/dom/tests/DOMDocument_load_error2_pre2_11.phpt
+similarity index 90%
+rename from ext/dom/tests/DOMDocument_load_error2.phpt
+rename to ext/dom/tests/DOMDocument_load_error2_pre2_11.phpt
+index f450cf1654..b97fff9d2f 100644
+--- a/ext/dom/tests/DOMDocument_load_error2.phpt
++++ b/ext/dom/tests/DOMDocument_load_error2_pre2_11.phpt
+@@ -1,5 +1,9 @@
+ --TEST--
+ Test DOMDocument::load() detects not-well formed XML
++--SKIPIF--
++<?php
++if (LIBXML_VERSION >= 21100) die('skip libxml2 test variant for version < 2.11');
++?>
+ --DESCRIPTION--
+ This test verifies the method detects attributes values not closed between " or '
+ Environment variables used in the test:
+diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c
+index b54ab40953..7917f636a9 100644
+--- a/ext/libxml/libxml.c
++++ b/ext/libxml/libxml.c
+@@ -578,6 +578,8 @@ static void php_libxml_ctx_error_level(int level, void *ctx, const char *msg)
+ } else {
+ php_error_docref(NULL, level, "%s in Entity, line: %d", msg, parser->input->line);
+ }
++ } else {
++ php_error_docref(NULL, E_WARNING, "%s", msg);
+ }
+ }
+
+diff --git a/ext/libxml/tests/bug61367-read_2.phpt b/ext/libxml/tests/bug61367-read_2.phpt
+index 8cc0b50144..12743adab1 100644
+--- a/ext/libxml/tests/bug61367-read_2.phpt
++++ b/ext/libxml/tests/bug61367-read_2.phpt
+@@ -55,6 +55,6 @@ bool(true)
+ int(4)
+ bool(true)
+
+-Warning: DOMDocument::loadXML(): I/O warning : failed to load external entity "file:///%s/test_bug_61367-read/bad" in %s on line %d
++Warning: DOMDocument::loadXML(): %Sfailed to load external entity "file:///%s/test_bug_61367-read/bad" in %s on line %d
+
+ Notice: Trying to get property 'nodeValue' of non-object in %s on line %d
+diff --git a/ext/libxml/tests/libxml_disable_entity_loader_2.phpt b/ext/libxml/tests/libxml_disable_entity_loader_2.phpt
+index 845bd4bbe3..55d8e61ee0 100644
+--- a/ext/libxml/tests/libxml_disable_entity_loader_2.phpt
++++ b/ext/libxml/tests/libxml_disable_entity_loader_2.phpt
+@@ -36,6 +36,6 @@ echo "Done\n";
+ bool(true)
+ bool(false)
+
+-Warning: DOMDocument::loadXML(): I/O warning : failed to load external entity "%s" in %s on line %d
++Warning: DOMDocument::loadXML(): %Sfailed to load external entity "%s" in %s on line %d
+ bool(true)
+ Done
+diff --git a/ext/libxml/tests/libxml_set_external_entity_loader_variation2.phpt b/ext/libxml/tests/libxml_set_external_entity_loader_variation2.phpt
+index e51869cf47..0664de1ea6 100644
+--- a/ext/libxml/tests/libxml_set_external_entity_loader_variation2.phpt
++++ b/ext/libxml/tests/libxml_set_external_entity_loader_variation2.phpt
+@@ -38,6 +38,8 @@ echo "Done.\n";
+ string(10) "-//FOO/BAR"
+ string(%d) "%sfoobar.dtd"
+
++Warning: DOMDocument::validate(): Failed to load external entity "-//FOO/BAR" in %s on line %d
++
+ Warning: DOMDocument::validate(): Could not load the external subset "foobar.dtd" in %s on line %d
+ bool(false)
+ bool(true)
+diff --git a/ext/xml/tests/bug26614_libxml_gte2_11.phpt b/ext/xml/tests/bug26614_libxml_gte2_11.phpt
+new file mode 100644
+index 0000000000..9a81b67686
+--- /dev/null
++++ b/ext/xml/tests/bug26614_libxml_gte2_11.phpt
+@@ -0,0 +1,95 @@
++--TEST--
++Bug #26614 (CDATA sections skipped on line count)
++--EXTENSIONS--
++xml
++--SKIPIF--
++<?php
++if (!defined("LIBXML_VERSION")) die('skip libxml2 test');
++if (LIBXML_VERSION < 21100) die('skip libxml2 test variant for version >= 2.11');
++?>
++--FILE--
++<?php
++/*
++this test works fine with Expat but fails with libxml
++which we now use as default
++
++further investigation has shown that not only line count
++is skipped on CDATA sections but that libxml does also
++show different column numbers and byte positions depending
++on context and in opposition to what one would expect to
++see and what good old Expat reported just fine ...
++*/
++
++$xmls = array();
++
++// Case 1: CDATA Sections
++$xmls["CDATA"] ='<?xml version="1.0" encoding="iso-8859-1" ?>
++<data>
++<![CDATA[
++multi
++line
++CDATA
++block
++]]>
++</data>';
++
++// Case 2: replace some characters so that we get comments instead
++$xmls["Comment"] ='<?xml version="1.0" encoding="iso-8859-1" ?>
++<data>
++<!-- ATA[
++multi
++line
++CDATA
++block
++-->
++</data>';
++
++// Case 3: replace even more characters so that only textual data is left
++$xmls["Text"] ='<?xml version="1.0" encoding="iso-8859-1" ?>
++<data>
++-!-- ATA[
++multi
++line
++CDATA
++block
++---
++</data>';
++
++function startElement($parser, $name, $attrs) {
++ printf("<$name> at line %d, col %d (byte %d)\n",
++ xml_get_current_line_number($parser),
++ xml_get_current_column_number($parser),
++ xml_get_current_byte_index($parser));
++}
++
++function endElement($parser, $name) {
++ printf("</$name> at line %d, col %d (byte %d)\n",
++ xml_get_current_line_number($parser),
++ xml_get_current_column_number($parser),
++ xml_get_current_byte_index($parser));
++}
++
++function characterData($parser, $data) {
++ // dummy
++}
++
++foreach ($xmls as $desc => $xml) {
++ echo "$desc\n";
++ $xml_parser = xml_parser_create();
++ xml_set_element_handler($xml_parser, "startElement", "endElement");
++ xml_set_character_data_handler($xml_parser, "characterData");
++ if (!xml_parse($xml_parser, $xml, true))
++ echo "Error: ".xml_error_string(xml_get_error_code($xml_parser))."\n";
++ xml_parser_free($xml_parser);
++}
++?>
++--EXPECTF--
++CDATA
++<DATA> at line 2, col %d (byte 50)
++</DATA> at line 9, col %d (byte 96)
++Comment
++<DATA> at line 2, col %d (byte 50)
++</DATA> at line 9, col %d (byte 96)
++Text
++<DATA> at line 2, col %d (byte 50)
++</DATA> at line 9, col %d (byte 96)
+diff --git a/ext/xml/tests/bug26614_libxml.phpt b/ext/xml/tests/bug26614_libxml_pre2_11.phpt
+similarity index 96%
+rename from ext/xml/tests/bug26614_libxml.phpt
+rename to ext/xml/tests/bug26614_libxml_pre2_11.phpt
+index 3ddd35ed0e..afacaa1c59 100644
+--- a/ext/xml/tests/bug26614_libxml.phpt
++++ b/ext/xml/tests/bug26614_libxml_pre2_11.phpt
+@@ -4,6 +4,7 @@ Bug #26614 (CDATA sections skipped on line count)
+ <?php
+ require_once("skipif.inc");
+ if (!defined("LIBXML_VERSION")) die('skip libxml2 test');
++if (LIBXML_VERSION >= 21100) die('skip libxml2 test variant for version < 2.11');
+ ?>
+ --FILE--
+ <?php
+--
+2.43.0
+
+From b2ac6c4fe4213258e7e9489ef50fe3afb2fdf4be Mon Sep 17 00:00:00 2001
+From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
+Date: Wed, 29 Nov 2023 20:49:29 +0100
+Subject: [PATCH 4/4] Test fixes for libxml2 2.12.0
+
+---
+ ext/dom/tests/DOMDocument_loadXML_error1.phpt | 4 +++
+ .../DOMDocument_loadXML_error1_gte2_12.phpt | 26 ++++++++++++++++
+ .../DOMDocument_loadXML_error2_gte2_11.phpt | 2 +-
+ .../DOMDocument_loadXML_error2_gte2_12.phpt | 30 +++++++++++++++++++
+ ext/dom/tests/DOMDocument_load_error1.phpt | 4 +++
+ .../DOMDocument_load_error1_gte2_12.phpt | 26 ++++++++++++++++
+ .../DOMDocument_load_error2_gte2_11.phpt | 2 +-
+ .../DOMDocument_load_error2_gte2_12.phpt | 30 +++++++++++++++++++
+ ext/xml/tests/bug81351.phpt | 4 +--
+ 9 files changed, 124 insertions(+), 4 deletions(-)
+ create mode 100644 ext/dom/tests/DOMDocument_loadXML_error1_gte2_12.phpt
+ create mode 100644 ext/dom/tests/DOMDocument_loadXML_error2_gte2_12.phpt
+ create mode 100644 ext/dom/tests/DOMDocument_load_error1_gte2_12.phpt
+ create mode 100644 ext/dom/tests/DOMDocument_load_error2_gte2_12.phpt
+
+diff --git a/ext/dom/tests/DOMDocument_loadXML_error1.phpt b/ext/dom/tests/DOMDocument_loadXML_error1.phpt
+index 4d3b81db79..0549d67630 100644
+--- a/ext/dom/tests/DOMDocument_loadXML_error1.phpt
++++ b/ext/dom/tests/DOMDocument_loadXML_error1.phpt
+@@ -1,5 +1,9 @@
+ --TEST--
+ Test DOMDocument::loadXML() detects not-well formed XML
++--SKIPIF--
++<?php
++if (LIBXML_VERSION >= 21200) die('skip libxml2 test variant for version < 2.12');
++?>
+ --DESCRIPTION--
+ This test verifies the method detects an opening and ending tag mismatch
+ Environment variables used in the test:
+diff --git a/ext/dom/tests/DOMDocument_loadXML_error1_gte2_12.phpt b/ext/dom/tests/DOMDocument_loadXML_error1_gte2_12.phpt
+new file mode 100644
+index 0000000000..e1ded0ffad
+--- /dev/null
++++ b/ext/dom/tests/DOMDocument_loadXML_error1_gte2_12.phpt
+@@ -0,0 +1,26 @@
++--TEST--
++Test DOMDocument::loadXML() detects not-well formed XML
++--SKIPIF--
++<?php
++if (LIBXML_VERSION < 21200) die('skip libxml2 test variant for version >= 2.12');
++?>
++--DESCRIPTION--
++This test verifies the method detects an opening and ending tag mismatch
++Environment variables used in the test:
++- XML_FILE: the xml file to load
++- LOAD_OPTIONS: the second parameter to pass to the method
++- EXPECTED_RESULT: the expected result
++--CREDITS--
++Antonio Diaz Ruiz <dejalatele@gmail.com>
++--EXTENSIONS--
++dom
++--ENV--
++XML_FILE=/not_well_formed.xml
++LOAD_OPTIONS=0
++EXPECTED_RESULT=0
++--FILE_EXTERNAL--
++domdocumentloadxml_test_method.inc
++--EXPECTF--
++Warning: DOMDocument::load%r(XML){0,1}%r(): Opening and ending tag mismatch: title line 5 and book %s
++
++Warning: DOMDocument::load%r(XML){0,1}%r(): %rexpected '>'|Opening and ending tag mismatch: book line (4|5) and books%r %s
+diff --git a/ext/dom/tests/DOMDocument_loadXML_error2_gte2_11.phpt b/ext/dom/tests/DOMDocument_loadXML_error2_gte2_11.phpt
+index ff5ceb3fbe..f52d334813 100644
+--- a/ext/dom/tests/DOMDocument_loadXML_error2_gte2_11.phpt
++++ b/ext/dom/tests/DOMDocument_loadXML_error2_gte2_11.phpt
+@@ -2,7 +2,7 @@
+ Test DOMDocument::loadXML() detects not-well formed XML
+ --SKIPIF--
+ <?php
+-if (LIBXML_VERSION < 21100) die('skip libxml2 test variant for version >= 2.11');
++if (LIBXML_VERSION < 21100 || LIBXML_VERSION >= 21200) die('skip libxml2 test variant for version >= 2.11 && <= 2.12');
+ ?>
+ --DESCRIPTION--
+ This test verifies the method detects attributes values not closed between " or '
+diff --git a/ext/dom/tests/DOMDocument_loadXML_error2_gte2_12.phpt b/ext/dom/tests/DOMDocument_loadXML_error2_gte2_12.phpt
+new file mode 100644
+index 0000000000..6a3ff5841f
+--- /dev/null
++++ b/ext/dom/tests/DOMDocument_loadXML_error2_gte2_12.phpt
+@@ -0,0 +1,30 @@
++--TEST--
++Test DOMDocument::loadXML() detects not-well formed XML
++--SKIPIF--
++<?php
++if (LIBXML_VERSION < 21200) die('skip libxml2 test variant for version >= 2.12');
++?>
++--DESCRIPTION--
++This test verifies the method detects attributes values not closed between " or '
++Environment variables used in the test:
++- XML_FILE: the xml file to load
++- LOAD_OPTIONS: the second parameter to pass to the method
++- EXPECTED_RESULT: the expected result
++--CREDITS--
++Antonio Diaz Ruiz <dejalatele@gmail.com>
++--EXTENSIONS--
++dom
++--ENV--
++XML_FILE=/not_well_formed2.xml
++LOAD_OPTIONS=0
++EXPECTED_RESULT=0
++--FILE_EXTERNAL--
++domdocumentloadxml_test_method.inc
++--EXPECTF--
++Warning: DOMDocument::loadXML(): AttValue: " or ' expected in Entity, line: 4 in %s on line %d
++
++Warning: DOMDocument::loadXML(): internal error: xmlParseStartTag: problem parsing attributes in Entity, line: 4 in %s on line %d
++
++Warning: DOMDocument::loadXML(): Couldn't find end of Start Tag book line 4 in Entity, line: 4 in %s on line %d
++
++Warning: DOMDocument::loadXML(): Opening and ending tag mismatch: books line 3 and book in Entity, line: 7 in %s on line %d
+diff --git a/ext/dom/tests/DOMDocument_load_error1.phpt b/ext/dom/tests/DOMDocument_load_error1.phpt
+index 8ac181d769..4416f5f6fe 100644
+--- a/ext/dom/tests/DOMDocument_load_error1.phpt
++++ b/ext/dom/tests/DOMDocument_load_error1.phpt
+@@ -1,5 +1,9 @@
+ --TEST--
+ Test DOMDocument::load() detects not-well formed XML
++--SKIPIF--
++<?php
++if (LIBXML_VERSION >= 21200) die('skip libxml2 test variant for version < 2.12');
++?>
+ --DESCRIPTION--
+ This test verifies the method detects an opening and ending tag mismatch
+ Environment variables used in the test:
+diff --git a/ext/dom/tests/DOMDocument_load_error1_gte2_12.phpt b/ext/dom/tests/DOMDocument_load_error1_gte2_12.phpt
+new file mode 100644
+index 0000000000..183c8406fd
+--- /dev/null
++++ b/ext/dom/tests/DOMDocument_load_error1_gte2_12.phpt
+@@ -0,0 +1,26 @@
++--TEST--
++Test DOMDocument::load() detects not-well formed XML
++--SKIPIF--
++<?php
++if (LIBXML_VERSION < 21200) die('skip libxml2 test variant for version >= 2.12');
++?>
++--DESCRIPTION--
++This test verifies the method detects an opening and ending tag mismatch
++Environment variables used in the test:
++- XML_FILE: the xml file to load
++- LOAD_OPTIONS: the second parameter to pass to the method
++- EXPECTED_RESULT: the expected result
++--CREDITS--
++Antonio Diaz Ruiz <dejalatele@gmail.com>
++--EXTENSIONS--
++dom
++--ENV--
++XML_FILE=/not_well_formed.xml
++LOAD_OPTIONS=0
++EXPECTED_RESULT=0
++--FILE_EXTERNAL--
++domdocumentload_test_method.inc
++--EXPECTF--
++Warning: DOMDocument::load%r(XML){0,1}%r(): Opening and ending tag mismatch: title line 5 and book %s
++
++Warning: DOMDocument::load%r(XML){0,1}%r(): %rexpected '>'|Opening and ending tag mismatch: book line (4|5) and books%r %s
+diff --git a/ext/dom/tests/DOMDocument_load_error2_gte2_11.phpt b/ext/dom/tests/DOMDocument_load_error2_gte2_11.phpt
+index 32b6bf1611..4d9f992b3b 100644
+--- a/ext/dom/tests/DOMDocument_load_error2_gte2_11.phpt
++++ b/ext/dom/tests/DOMDocument_load_error2_gte2_11.phpt
+@@ -2,7 +2,7 @@
+ Test DOMDocument::load() detects not-well formed
+ --SKIPIF--
+ <?php
+-if (LIBXML_VERSION < 21100) die('skip libxml2 test variant for version >= 2.11');
++if (LIBXML_VERSION < 21100 || LIBXML_VERSION >= 21200) die('skip libxml2 test variant for version >= 2.11 && <= 2.12');
+ ?>
+ --DESCRIPTION--
+ This test verifies the method detects attributes values not closed between " or '
+diff --git a/ext/dom/tests/DOMDocument_load_error2_gte2_12.phpt b/ext/dom/tests/DOMDocument_load_error2_gte2_12.phpt
+new file mode 100644
+index 0000000000..4fadf41736
+--- /dev/null
++++ b/ext/dom/tests/DOMDocument_load_error2_gte2_12.phpt
+@@ -0,0 +1,30 @@
++--TEST--
++Test DOMDocument::load() detects not-well formed
++--SKIPIF--
++<?php
++if (LIBXML_VERSION < 21200) die('skip libxml2 test variant for version >= 2.12');
++?>
++--DESCRIPTION--
++This test verifies the method detects attributes values not closed between " or '
++Environment variables used in the test:
++- XML_FILE: the xml file to load
++- LOAD_OPTIONS: the second parameter to pass to the method
++- EXPECTED_RESULT: the expected result
++--CREDITS--
++Antonio Diaz Ruiz <dejalatele@gmail.com>
++--EXTENSIONS--
++dom
++--ENV--
++XML_FILE=/not_well_formed2.xml
++LOAD_OPTIONS=0
++EXPECTED_RESULT=0
++--FILE_EXTERNAL--
++domdocumentload_test_method.inc
++--EXPECTF--
++Warning: DOMDocument::load(): AttValue: " or ' expected in %s on line %d
++
++Warning: DOMDocument::load(): internal error: xmlParseStartTag: problem parsing attributes in %s on line %d
++
++Warning: DOMDocument::load(): Couldn't find end of Start Tag book line 4 in %s on line %d
++
++Warning: DOMDocument::load(): Opening and ending tag mismatch: books line 3 and book in %s on line %d
+diff --git a/ext/xml/tests/bug81351.phpt b/ext/xml/tests/bug81351.phpt
+index 19e4ca590b..dc934001be 100644
+--- a/ext/xml/tests/bug81351.phpt
++++ b/ext/xml/tests/bug81351.phpt
+@@ -23,6 +23,6 @@ $code = xml_get_error_code($parser);
+ $error = xml_error_string($code);
+ echo "xml_parse returned $success, xml_get_error_code = $code, xml_error_string = $error\r\n";
+ ?>
+---EXPECT--
++--EXPECTF--
+ xml_parse returned 1, xml_get_error_code = 0, xml_error_string = No error
+-xml_parse returned 0, xml_get_error_code = 5, xml_error_string = Invalid document end
++%rxml_parse returned 0, xml_get_error_code = 5, xml_error_string = Invalid document end|xml_parse returned 0, xml_get_error_code = 77, xml_error_string = Tag not finished%r
+--
+2.43.0
+
diff --git a/php-7.4.33-pcretests.patch b/php-7.4.33-pcretests.patch
new file mode 100644
index 0000000..c226661
--- /dev/null
+++ b/php-7.4.33-pcretests.patch
@@ -0,0 +1,43 @@
+From c3150fcc89825f50d476b1b1971870aeb71f167d Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@remirepo.net>
+Date: Wed, 12 Mar 2025 07:48:05 +0100
+Subject: [PATCH 1/2] Relax test expectation for pcre2lib 10.45 Using
+ e92848789acd8aa5cf32fedb519ba9378ac64e02
+
+---
+ ext/pcre/tests/bug75457.phpt | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/ext/pcre/tests/bug75457.phpt b/ext/pcre/tests/bug75457.phpt
+index ee5ab162f8a6c..87dc12a1ad056 100644
+--- a/ext/pcre/tests/bug75457.phpt
++++ b/ext/pcre/tests/bug75457.phpt
+@@ -6,5 +6,5 @@ $pattern = "/(((?(?C)0?=))(?!()0|.(?0)0)())/";
+ var_dump(preg_match($pattern, "hello"));
+ ?>
+ --EXPECTF--
+-Warning: preg_match(): Compilation failed: assertion expected after (?( or (?(?C) at offset 8 in %sbug75457.php on line %d
++Warning: preg_match(): Compilation failed: %r(atomic|)%r assertion expected after (?( or (?(?C) at offset 8 in %sbug75457.php on line %d
+ bool(false)
+
+From 126095700a02b9aa1f33764a63c93a70e8373ad8 Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@famillecollet.com>
+Date: Wed, 12 Mar 2025 09:36:33 +0100
+Subject: [PATCH 2/2] Update ext/pcre/tests/bug75457.phpt
+
+Co-authored-by: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
+---
+ ext/pcre/tests/bug75457.phpt | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/ext/pcre/tests/bug75457.phpt b/ext/pcre/tests/bug75457.phpt
+index 87dc12a1ad056..1401b25ff6fb7 100644
+--- a/ext/pcre/tests/bug75457.phpt
++++ b/ext/pcre/tests/bug75457.phpt
+@@ -6,5 +6,5 @@ $pattern = "/(((?(?C)0?=))(?!()0|.(?0)0)())/";
+ var_dump(preg_match($pattern, "hello"));
+ ?>
+ --EXPECTF--
+-Warning: preg_match(): Compilation failed: %r(atomic|)%r assertion expected after (?( or (?(?C) at offset 8 in %sbug75457.php on line %d
++Warning: preg_match(): Compilation failed:%r( atomic|)%r assertion expected after (?( or (?(?C) at offset 8 in %sbug75457.php on line %d
+ bool(false)
diff --git a/php-7.4.33-proto.patch b/php-7.4.33-proto.patch
new file mode 100644
index 0000000..2e20717
--- /dev/null
+++ b/php-7.4.33-proto.patch
@@ -0,0 +1,392 @@
+From f566cba0bb6bd53b1d44d5097e68201412b00f7a Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@php.net>
+Date: Thu, 25 Nov 2021 13:16:26 +0100
+Subject: [PATCH] fix [-Wstrict-prototypes] build warnings in ext/gd
+
+---
+ ext/gd/config.m4 | 2 --
+ ext/gd/gd.c | 58 ++++++++++++++++++++++++------------------------
+ 2 files changed, 29 insertions(+), 31 deletions(-)
+
+diff -up a/ext/gd/gd.c.proto b/ext/gd/gd.c
+--- a/ext/gd/gd.c.proto 2022-10-31 11:36:07.000000000 +0100
++++ b/ext/gd/gd.c 2025-02-13 12:04:07.860118321 +0100
+@@ -138,9 +138,9 @@ static void php_image_filter_pixelate(IN
+ static void php_image_filter_scatter(INTERNAL_FUNCTION_PARAMETERS);
+
+ /* End Section filters declarations */
+-static gdImagePtr _php_image_create_from_string (zval *Data, char *tn, gdImagePtr (*ioctx_func_p)());
+-static void _php_image_create_from(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, gdImagePtr (*func_p)(), gdImagePtr (*ioctx_func_p)());
+-static void _php_image_output(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, void (*func_p)());
++static gdImagePtr _php_image_create_from_string (zval *Data, char *tn, gdImagePtr (*ioctx_func_p)(gdIOCtxPtr));
++static void _php_image_create_from(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, gdImagePtr (*func_p)(FILE *), gdImagePtr (*ioctx_func_p)(gdIOCtxPtr));
++static void _php_image_output(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn);
+ static int _php_image_type(char data[12]);
+ static void _php_image_convert(INTERNAL_FUNCTION_PARAMETERS, int image_type);
+
+@@ -2330,7 +2330,7 @@ static int _php_image_type (char data[12
+
+ /* {{{ _php_image_create_from_string
+ */
+-gdImagePtr _php_image_create_from_string(zval *data, char *tn, gdImagePtr (*ioctx_func_p)())
++gdImagePtr _php_image_create_from_string(zval *data, char *tn, gdImagePtr (*ioctx_func_p)(gdIOCtxPtr))
+ {
+ gdImagePtr im;
+ gdIOCtx *io_ctx;
+@@ -2440,7 +2440,7 @@ PHP_FUNCTION(imagecreatefromstring)
+
+ /* {{{ _php_image_create_from
+ */
+-static void _php_image_create_from(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, gdImagePtr (*func_p)(), gdImagePtr (*ioctx_func_p)())
++static void _php_image_create_from(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, gdImagePtr (*func_p)(FILE *), gdImagePtr (*ioctx_func_p)(gdIOCtxPtr))
+ {
+ char *file;
+ size_t file_len;
+@@ -2477,7 +2477,7 @@ static void _php_image_create_from(INTER
+ if (FAILURE == php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void**)&fp, REPORT_ERRORS)) {
+ goto out_err;
+ }
+- } else if (ioctx_func_p) {
++ } else if (ioctx_func_p || image_type == PHP_GDIMG_TYPE_GD2PART) {
+ /* we can create an io context */
+ gdIOCtx* io_ctx;
+ zend_string *buff;
+@@ -2501,7 +2501,7 @@ static void _php_image_create_from(INTER
+ }
+
+ if (image_type == PHP_GDIMG_TYPE_GD2PART) {
+- im = (*ioctx_func_p)(io_ctx, srcx, srcy, width, height);
++ im = gdImageCreateFromGd2PartCtx(io_ctx, srcx, srcy, width, height);
+ } else {
+ im = (*ioctx_func_p)(io_ctx);
+ }
+@@ -2519,7 +2519,7 @@ static void _php_image_create_from(INTER
+ if (!im && fp) {
+ switch (image_type) {
+ case PHP_GDIMG_TYPE_GD2PART:
+- im = (*func_p)(fp, srcx, srcy, width, height);
++ im = gdImageCreateFromGd2Part(fp, srcx, srcy, width, height);
+ break;
+ #if defined(HAVE_GD_XPM)
+ case PHP_GDIMG_TYPE_XPM:
+@@ -2608,7 +2608,7 @@ PHP_FUNCTION(imagecreatefromxbm)
+ Create a new image from XPM file or URL */
+ PHP_FUNCTION(imagecreatefromxpm)
+ {
+- _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_XPM, "XPM", gdImageCreateFromXpm, NULL);
++ _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_XPM, "XPM", NULL, NULL);
+ }
+ /* }}} */
+ #endif
+@@ -2641,7 +2641,7 @@ PHP_FUNCTION(imagecreatefromgd2)
+ Create a new image from a given part of GD2 file or URL */
+ PHP_FUNCTION(imagecreatefromgd2part)
+ {
+- _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GD2PART, "GD2", gdImageCreateFromGd2Part, gdImageCreateFromGd2PartCtx);
++ _php_image_create_from(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GD2PART, "GD2", NULL, NULL);
+ }
+ /* }}} */
+
+@@ -2667,7 +2667,7 @@ PHP_FUNCTION(imagecreatefromtga)
+
+ /* {{{ _php_image_output
+ */
+-static void _php_image_output(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, void (*func_p)())
++static void _php_image_output(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn)
+ {
+ zval *imgind;
+ char *file = NULL;
+@@ -2720,13 +2720,13 @@ static void _php_image_output(INTERNAL_F
+ gdImageWBMP(im, q, fp);
+ break;
+ case PHP_GDIMG_TYPE_GD:
+- (*func_p)(im, fp);
++ gdImageGd(im, fp);
+ break;
+ case PHP_GDIMG_TYPE_GD2:
+ if (q == -1) {
+ q = 128;
+ }
+- (*func_p)(im, fp, q, t);
++ gdImageGd2(im, fp, q, t);
+ break;
+ default:
+ ZEND_ASSERT(0);
+@@ -2756,13 +2756,13 @@ static void _php_image_output(INTERNAL_F
+ gdImageWBMP(im, q, tmp);
+ break;
+ case PHP_GDIMG_TYPE_GD:
+- (*func_p)(im, tmp);
++ gdImageGd(im, tmp);
+ break;
+ case PHP_GDIMG_TYPE_GD2:
+ if (q == -1) {
+ q = 128;
+ }
+- (*func_p)(im, tmp, q, t);
++ gdImageGd2(im, tmp, q, t);
+ break;
+ default:
+ ZEND_ASSERT(0);
+@@ -2786,7 +2786,7 @@ static void _php_image_output(INTERNAL_F
+ Output XBM image to browser or file */
+ PHP_FUNCTION(imagexbm)
+ {
+- _php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_XBM, "XBM", gdImageXbmCtx);
++ _php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_XBM, "XBM");
+ }
+ /* }}} */
+
+@@ -2794,7 +2794,7 @@ PHP_FUNCTION(imagexbm)
+ Output GIF image to browser or file */
+ PHP_FUNCTION(imagegif)
+ {
+- _php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GIF, "GIF", gdImageGifCtx);
++ _php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GIF, "GIF");
+ }
+ /* }}} */
+
+@@ -2803,7 +2803,7 @@ PHP_FUNCTION(imagegif)
+ Output PNG image to browser or file */
+ PHP_FUNCTION(imagepng)
+ {
+- _php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_PNG, "PNG", gdImagePngCtxEx);
++ _php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_PNG, "PNG");
+ }
+ /* }}} */
+ #endif /* HAVE_GD_PNG */
+@@ -2814,7 +2814,7 @@ PHP_FUNCTION(imagepng)
+ Output WEBP image to browser or file */
+ PHP_FUNCTION(imagewebp)
+ {
+- _php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_WEBP, "WEBP", gdImageWebpCtx);
++ _php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_WEBP, "WEBP");
+ }
+ /* }}} */
+ #endif /* HAVE_GD_WEBP */
+@@ -2825,7 +2825,7 @@ PHP_FUNCTION(imagewebp)
+ Output JPEG image to browser or file */
+ PHP_FUNCTION(imagejpeg)
+ {
+- _php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_JPG, "JPEG", gdImageJpegCtx);
++ _php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_JPG, "JPEG");
+ }
+ /* }}} */
+ #endif /* HAVE_GD_JPG */
+@@ -2834,7 +2834,7 @@ PHP_FUNCTION(imagejpeg)
+ Output WBMP image to browser or file */
+ PHP_FUNCTION(imagewbmp)
+ {
+- _php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_WBM, "WBMP", gdImageWBMPCtx);
++ _php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_WBM, "WBMP");
+ }
+ /* }}} */
+
+@@ -2842,7 +2842,7 @@ PHP_FUNCTION(imagewbmp)
+ Output GD image to browser or file */
+ PHP_FUNCTION(imagegd)
+ {
+- _php_image_output(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GD, "GD", gdImageGd);
++ _php_image_output(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GD, "GD");
+ }
+ /* }}} */
+
+@@ -2850,7 +2850,7 @@ PHP_FUNCTION(imagegd)
+ Output GD2 image to browser or file */
+ PHP_FUNCTION(imagegd2)
+ {
+- _php_image_output(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GD2, "GD2", gdImageGd2);
++ _php_image_output(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_GD2, "GD2");
+ }
+ /* }}} */
+
+@@ -2859,7 +2859,7 @@ PHP_FUNCTION(imagegd2)
+ Output BMP image to browser or file */
+ PHP_FUNCTION(imagebmp)
+ {
+- _php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_BMP, "BMP", gdImageBmpCtx);
++ _php_image_output_ctx(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_TYPE_BMP, "BMP");
+ }
+ /* }}} */
+ #endif
+@@ -4146,7 +4146,7 @@ static void php_imagettftext_common(INTE
+ Output WBMP image to browser or file */
+ PHP_FUNCTION(image2wbmp)
+ {
+- _php_image_output(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_CONVERT_WBM, "WBMP", NULL);
++ _php_image_output(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_GDIMG_CONVERT_WBM, "WBMP");
+ }
+ /* }}} */
+
+diff -up a/ext/gd/gd_ctx.c.proto b/ext/gd/gd_ctx.c
+--- a/ext/gd/gd_ctx.c.proto 2025-02-13 11:42:48.478248591 +0100
++++ b/ext/gd/gd_ctx.c 2025-02-13 11:52:48.325740296 +0100
+@@ -77,7 +77,7 @@ static void _php_image_stream_ctxfreeand
+ } /* }}} */
+
+ /* {{{ _php_image_output_ctx */
+-static void _php_image_output_ctx(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, void (*func_p)())
++static void _php_image_output_ctx(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn)
+ {
+ zval *imgind;
+ char *file = NULL;
+@@ -177,16 +177,20 @@ static void _php_image_output_ctx(INTERN
+
+ switch(image_type) {
+ case PHP_GDIMG_TYPE_JPG:
+- (*func_p)(im, ctx, q);
++ gdImageJpegCtx(im, ctx, q);
+ break;
+ case PHP_GDIMG_TYPE_WEBP:
+ if (q == -1) {
+ q = 80;
+ }
+- (*func_p)(im, ctx, q);
++ gdImageWebpCtx(im, ctx, q);
+ break;
+ case PHP_GDIMG_TYPE_PNG:
+- (*func_p)(im, ctx, q, f);
++#ifdef HAVE_GD_BUNDLED
++ gdImagePngCtxEx(im, ctx, q, f);
++#else
++ gdImagePngCtxEx(im, ctx, q);
++#endif
+ break;
+ case PHP_GDIMG_TYPE_XBM:
+ case PHP_GDIMG_TYPE_WBM:
+@@ -197,16 +201,16 @@ static void _php_image_output_ctx(INTERN
+ q = i;
+ }
+ if (image_type == PHP_GDIMG_TYPE_XBM) {
+- (*func_p)(im, file ? file : "", q, ctx);
++ gdImageXbmCtx(im, file ? file : "", q, ctx);
+ } else {
+- (*func_p)(im, q, ctx);
++ gdImageWBMPCtx(im, q, ctx);
+ }
+ break;
+ case PHP_GDIMG_TYPE_BMP:
+- (*func_p)(im, ctx, (int) compressed);
++ gdImageBmpCtx(im, ctx, (int) compressed);
+ break;
+- default:
+- (*func_p)(im, ctx);
++ case PHP_GDIMG_TYPE_GIF:
++ gdImageGifCtx(im, ctx);
+ break;
+ }
+
+From b7356692f69f4ac0a07ea54e83debdd04b426dcb Mon Sep 17 00:00:00 2001
+From: George Peter Banyard <girgias@php.net>
+Date: Wed, 12 May 2021 14:41:11 +0100
+Subject: [PATCH] Specify function pointer signature for scanf implementation
+
+Fix [-Wstrict-prototypes] warnings in standard/scanf.c
+---
+ ext/standard/scanf.c | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+diff --git a/ext/standard/scanf.c b/ext/standard/scanf.c
+index f58b4195cc599..78ecc1642cf92 100644
+--- a/ext/standard/scanf.c
++++ b/ext/standard/scanf.c
+@@ -108,6 +108,8 @@ typedef struct CharSet {
+ } *ranges;
+ } CharSet;
+
++typedef zend_long (*int_string_formater)(const char*, char**, int);
++
+ /*
+ * Declarations for functions used only in this file.
+ */
+@@ -585,7 +587,7 @@ PHPAPI int php_sscanf_internal( char *string, char *format,
+ int base = 0;
+ int underflow = 0;
+ size_t width;
+- zend_long (*fn)() = NULL;
++ int_string_formater fn = NULL;
+ char *ch, sch;
+ int flags;
+ char buf[64]; /* Temporary buffer to hold scanned number
+@@ -750,29 +752,29 @@ PHPAPI int php_sscanf_internal( char *string, char *format,
+ case 'D':
+ op = 'i';
+ base = 10;
+- fn = (zend_long (*)())ZEND_STRTOL_PTR;
++ fn = (int_string_formater)ZEND_STRTOL_PTR;
+ break;
+ case 'i':
+ op = 'i';
+ base = 0;
+- fn = (zend_long (*)())ZEND_STRTOL_PTR;
++ fn = (int_string_formater)ZEND_STRTOL_PTR;
+ break;
+ case 'o':
+ op = 'i';
+ base = 8;
+- fn = (zend_long (*)())ZEND_STRTOL_PTR;
++ fn = (int_string_formater)ZEND_STRTOL_PTR;
+ break;
+ case 'x':
+ case 'X':
+ op = 'i';
+ base = 16;
+- fn = (zend_long (*)())ZEND_STRTOL_PTR;
++ fn = (int_string_formater)ZEND_STRTOL_PTR;
+ break;
+ case 'u':
+ op = 'i';
+ base = 10;
+ flags |= SCAN_UNSIGNED;
+- fn = (zend_long (*)())ZEND_STRTOUL_PTR;
++ fn = (int_string_formater)ZEND_STRTOUL_PTR;
+ break;
+
+ case 'f':
+From 2068d230d981d7b06b41b87ebc37ab2581b79852 Mon Sep 17 00:00:00 2001
+From: George Peter Banyard <girgias@php.net>
+Date: Wed, 12 May 2021 18:54:57 +0100
+Subject: [PATCH] Fix [-Wstrict-prototypes] warning in PCNTL extension
+
+To achieve this we need to introduce a new wrapper function with
+dummy arguments which calls pcntl_signal_dispatch() to respect
+the function pointer signature for a tick function.
+---
+ ext/pcntl/pcntl.c | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c
+index 1e8690ae75144..c116eff7d034a 100644
+--- a/ext/pcntl/pcntl.c
++++ b/ext/pcntl/pcntl.c
+@@ -252,7 +252,8 @@ static void pcntl_siginfo_to_zval(int, s
+ #else
+ static void pcntl_signal_handler(int);
+ #endif
+-static void pcntl_signal_dispatch();
++static void pcntl_signal_dispatch(void);
++static void pcntl_signal_dispatch_tick_function(int dummy_int, void *dummy_pointer);
+ static void pcntl_interrupt_function(zend_execute_data *execute_data);
+
+ void php_register_signal_constants(INIT_FUNC_ARGS)
+@@ -587,7 +588,7 @@ static PHP_GINIT_FUNCTION(pcntl)
+
+ PHP_RINIT_FUNCTION(pcntl)
+ {
+- php_add_tick_function(pcntl_signal_dispatch, NULL);
++ php_add_tick_function(pcntl_signal_dispatch_tick_function, NULL);
+ zend_hash_init(&PCNTL_G(php_signal_table), 16, NULL, ZVAL_PTR_DTOR, 0);
+ PCNTL_G(head) = PCNTL_G(tail) = PCNTL_G(spares) = NULL;
+ PCNTL_G(async_signals) = 0;
+@@ -1549,6 +1550,11 @@ void pcntl_signal_dispatch()
+ sigprocmask(SIG_SETMASK, &old_mask, NULL);
+ }
+
++static void pcntl_signal_dispatch_tick_function(int dummy_int, void *dummy_pointer)
++{
++ return pcntl_signal_dispatch();
++}
++
+ /* {{{ proto bool pcntl_async_signals([bool on[)
+ Enable/disable asynchronous signal handling and return the old setting. */
+ PHP_FUNCTION(pcntl_async_signals)
diff --git a/php-7.4.33-tests.patch b/php-7.4.33-tests.patch
new file mode 100644
index 0000000..aa8f1d9
--- /dev/null
+++ b/php-7.4.33-tests.patch
@@ -0,0 +1,26 @@
+From 6974372fbbea4279e1e4f5c24425581208f5553a Mon Sep 17 00:00:00 2001
+From: Nikita Popov <nikita.ppv@gmail.com>
+Date: Mon, 18 Oct 2021 12:45:26 +0200
+Subject: [PATCH] Fix bug #81510
+
+Make the used arrays larger, because the previous sizes were not
+slow enough on some hardware.
+---
+ Zend/tests/bug74093.phpt | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/Zend/tests/bug74093.phpt b/Zend/tests/bug74093.phpt
+index 7f20285805bf..c5fc9da8cbbf 100644
+--- a/Zend/tests/bug74093.phpt
++++ b/Zend/tests/bug74093.phpt
+@@ -12,8 +12,8 @@ max_execution_time=1
+ hard_timeout=1
+ --FILE--
+ <?php
+-$a1 = range(1, 1000000);
+-$a2 = range(100000, 1999999);
++$a1 = range(1, 2000000);
++$a2 = range(100000, 2999999);
+ array_intersect($a1, $a2);
+ ?>
+ --EXPECTF--
diff --git a/php-7.4.33-zlib-tests.patch b/php-7.4.33-zlib-tests.patch
new file mode 100644
index 0000000..5f2e3fe
--- /dev/null
+++ b/php-7.4.33-zlib-tests.patch
@@ -0,0 +1,462 @@
+Adapted for 7.4 from
+
+
+From 5e12844d4d0053f3c3f1b20635efdb6f30e85190 Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@remirepo.net>
+Date: Thu, 29 Feb 2024 10:52:54 +0100
+Subject: [PATCH] Fix GH-13217 Test failure with zlib-ng
+
+As compressed result may be different
+- drop or relax expectations on compressed data
+- rely on uncompressed result of compressed data
+---
+ ext/zlib/tests/bug48725_2.phpt | 4 +-
+ ext/zlib/tests/bug71417.phpt | 2 +-
+ ext/zlib/tests/gzcompress_basic1.phpt | 29 +---------
+ ext/zlib/tests/gzcompress_variation1.phpt | 10 ++--
+ ext/zlib/tests/gzdeflate_basic1.phpt | 29 +---------
+ ext/zlib/tests/gzdeflate_variation1.phpt | 10 ++--
+ ext/zlib/tests/gzencode_basic1.phpt | 67 ++++++++++-------------
+ ext/zlib/tests/gzencode_variation1.phpt | 4 +-
+ ext/zlib/tests/gzinflate-bug42663.phpt | 2 +-
+ ext/zlib/tests/zlib_filter_deflate.phpt | 4 +-
+ 10 files changed, 54 insertions(+), 107 deletions(-)
+
+
+diff --git a/ext/zlib/tests/bug48725_2.phpt b/ext/zlib/tests/bug48725_2.phpt
+index 168afd8d3d..6e92a43115 100644
+--- a/ext/zlib/tests/bug48725_2.phpt
++++ b/ext/zlib/tests/bug48725_2.phpt
+@@ -9,7 +9,7 @@ if (!extension_loaded('zlib')) die('skip zlib extension not available');
+ $stream = fopen('data://text/plain;base64,' . base64_encode('Foo bar baz'),
+ 'r');
+ stream_filter_append($stream, 'zlib.deflate', STREAM_FILTER_READ);
+-print bin2hex(stream_get_contents($stream));
++print gzinflate(stream_get_contents($stream));
+ ?>
+ --EXPECT--
+-72cbcf57484a2c02e22a00000000ffff0300
++Foo bar baz
+diff --git a/ext/zlib/tests/bug71417.phpt b/ext/zlib/tests/bug71417.phpt
+index ae1390134e..53c2d82443 100644
+--- a/ext/zlib/tests/bug71417.phpt
++++ b/ext/zlib/tests/bug71417.phpt
+@@ -73,7 +73,7 @@ read: bool(false)
+ gzdecode():
+ Warning: gzdecode(): data error in %s on line %d
+
+-read: string(32) "The quick brown fox jumps over t"
++read: string(3%d) "The quick brown fox jumps over%s"
+ gzdecode():
+ Warning: gzdecode(): data error in %s on line %d
+
+diff --git a/ext/zlib/tests/gzcompress_basic1.phpt b/ext/zlib/tests/gzcompress_basic1.phpt
+index 882fd87fad..5115ff86aa 100644
+--- a/ext/zlib/tests/gzcompress_basic1.phpt
++++ b/ext/zlib/tests/gzcompress_basic1.phpt
+@@ -33,7 +33,6 @@ $smallstring = "A small string to compress\n";
+ for($i = -1; $i < 10; $i++) {
+ echo "-- Compression level $i --\n";
+ $output = gzcompress($data, $i);
+- var_dump(md5($output));
+ var_dump(strcmp(gzuncompress($output), $data));
+ }
+
+@@ -41,85 +40,63 @@ for($i = -1; $i < 10; $i++) {
+ for($i = -1; $i < 10; $i++) {
+ echo "-- Compression level $i --\n";
+ $output = gzcompress($smallstring, $i);
+- var_dump(bin2hex($output));
+ var_dump(strcmp(gzuncompress($output), $smallstring));
+ }
+
+ // Calling gzcompress() with mandatory arguments
+ echo "\n-- Testing with no specified compression level --\n";
+-var_dump( bin2hex(gzcompress($smallstring) ));
++$output = gzcompress($smallstring);
++var_dump(strcmp(gzuncompress($output), $smallstring));
+
+ ?>
+ ===Done===
+ --EXPECT--
+ *** Testing gzcompress() : basic functionality ***
+ -- Compression level -1 --
+-string(32) "764809aef15bb34cb73ad49ecb600d99"
+ int(0)
+ -- Compression level 0 --
+-string(32) "d0136b3fb5424142c0eb26dfec8f56fe"
+ int(0)
+ -- Compression level 1 --
+-string(32) "c2e070f4320d1f674965eaab95b53d9c"
+ int(0)
+ -- Compression level 2 --
+-string(32) "36922f486410d08209d0d0d21b26030e"
+ int(0)
+ -- Compression level 3 --
+-string(32) "a441a2f5169bb303cd45b860a5a9dbf9"
+ int(0)
+ -- Compression level 4 --
+-string(32) "d5b7451e9de2864beccc9de1fc55eb87"
+ int(0)
+ -- Compression level 5 --
+-string(32) "32ba4a01120449ec25508cabfad41f56"
+ int(0)
+ -- Compression level 6 --
+-string(32) "764809aef15bb34cb73ad49ecb600d99"
+ int(0)
+ -- Compression level 7 --
+-string(32) "e083e7e8d05471fed3c2182b9cd0d9eb"
+ int(0)
+ -- Compression level 8 --
+-string(32) "e083e7e8d05471fed3c2182b9cd0d9eb"
+ int(0)
+ -- Compression level 9 --
+-string(32) "e083e7e8d05471fed3c2182b9cd0d9eb"
+ int(0)
+ -- Compression level -1 --
+-string(70) "789c735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee6020087a509cb"
+ int(0)
+ -- Compression level 0 --
+-string(76) "7801011b00e4ff4120736d616c6c20737472696e6720746f20636f6d70726573730a87a509cb"
+ int(0)
+ -- Compression level 1 --
+-string(70) "7801735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee6020087a509cb"
+ int(0)
+ -- Compression level 2 --
+-string(70) "785e735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee6020087a509cb"
+ int(0)
+ -- Compression level 3 --
+-string(70) "785e735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee6020087a509cb"
+ int(0)
+ -- Compression level 4 --
+-string(70) "785e735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee6020087a509cb"
+ int(0)
+ -- Compression level 5 --
+-string(70) "785e735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee6020087a509cb"
+ int(0)
+ -- Compression level 6 --
+-string(70) "789c735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee6020087a509cb"
+ int(0)
+ -- Compression level 7 --
+-string(70) "78da735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee6020087a509cb"
+ int(0)
+ -- Compression level 8 --
+-string(70) "78da735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee6020087a509cb"
+ int(0)
+ -- Compression level 9 --
+-string(70) "78da735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee6020087a509cb"
+ int(0)
+
+ -- Testing with no specified compression level --
+-string(70) "789c735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee6020087a509cb"
++int(0)
+ ===Done===
+diff --git a/ext/zlib/tests/gzcompress_variation1.phpt b/ext/zlib/tests/gzcompress_variation1.phpt
+index c4bc0a1ff5..818c8443b2 100644
+--- a/ext/zlib/tests/gzcompress_variation1.phpt
++++ b/ext/zlib/tests/gzcompress_variation1.phpt
+@@ -20,15 +20,15 @@ echo "*** Testing gzcompress() : variation ***\n";
+
+ echo "\n-- Testing multiple compression --\n";
+ $output = gzcompress($data);
+-var_dump( md5($output));
+-var_dump(md5(gzcompress($output)));
++var_dump(strlen($output));
++var_dump(strlen(gzcompress($output)));
+
+ ?>
+ ===Done===
+---EXPECT--
++--EXPECTF--
+ *** Testing gzcompress() : variation ***
+
+ -- Testing multiple compression --
+-string(32) "764809aef15bb34cb73ad49ecb600d99"
+-string(32) "eba942bc2061f23ea8688cc5101872a4"
++int(1%d)
++int(1%d)
+ ===Done===
+diff --git a/ext/zlib/tests/gzdeflate_basic1.phpt b/ext/zlib/tests/gzdeflate_basic1.phpt
+index 8ab0ee6243..59de23603e 100644
+--- a/ext/zlib/tests/gzdeflate_basic1.phpt
++++ b/ext/zlib/tests/gzdeflate_basic1.phpt
+@@ -33,7 +33,6 @@ $smallstring = "A small string to compress\n";
+ for($i = -1; $i < 10; $i++) {
+ echo "-- Compression level $i --\n";
+ $output = gzdeflate($data, $i);
+- var_dump(md5($output));
+ var_dump(strcmp(gzinflate($output), $data));
+ }
+
+@@ -41,85 +40,63 @@ for($i = -1; $i < 10; $i++) {
+ for($i = -1; $i < 10; $i++) {
+ echo "-- Compression level $i --\n";
+ $output = gzdeflate($smallstring, $i);
+- var_dump(bin2hex($output));
+ var_dump(strcmp(gzinflate($output), $smallstring));
+ }
+
+ // Calling gzdeflate() with just mandatory arguments
+ echo "\n-- Testing with no specified compression level --\n";
+-var_dump( bin2hex(gzdeflate($smallstring) ));
++$output = gzdeflate($smallstring);
++var_dump(strcmp(gzinflate($output), $smallstring));
+
+ ?>
+ ===Done===
+ --EXPECT--
+ *** Testing gzdeflate() : basic functionality ***
+ -- Compression level -1 --
+-string(32) "078554fe65e06f6ff01eab51cfc7ae9b"
+ int(0)
+ -- Compression level 0 --
+-string(32) "a71e54d2499aff9e48643cb1c260b60c"
+ int(0)
+ -- Compression level 1 --
+-string(32) "05e80f4dc0d422e1f333cbed555d381f"
+ int(0)
+ -- Compression level 2 --
+-string(32) "0fb33656e4ed0750f977df83246fce7a"
+ int(0)
+ -- Compression level 3 --
+-string(32) "bc6e9c1dccc3e951e006315ee669ee08"
+ int(0)
+ -- Compression level 4 --
+-string(32) "a61727d7a28c634470eb6e97a4a81b24"
+ int(0)
+ -- Compression level 5 --
+-string(32) "a2a1a14b7542c82e8943200d093d5f27"
+ int(0)
+ -- Compression level 6 --
+-string(32) "078554fe65e06f6ff01eab51cfc7ae9b"
+ int(0)
+ -- Compression level 7 --
+-string(32) "078554fe65e06f6ff01eab51cfc7ae9b"
+ int(0)
+ -- Compression level 8 --
+-string(32) "078554fe65e06f6ff01eab51cfc7ae9b"
+ int(0)
+ -- Compression level 9 --
+-string(32) "078554fe65e06f6ff01eab51cfc7ae9b"
+ int(0)
+ -- Compression level -1 --
+-string(58) "735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee60200"
+ int(0)
+ -- Compression level 0 --
+-string(64) "011b00e4ff4120736d616c6c20737472696e6720746f20636f6d70726573730a"
+ int(0)
+ -- Compression level 1 --
+-string(58) "735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee60200"
+ int(0)
+ -- Compression level 2 --
+-string(58) "735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee60200"
+ int(0)
+ -- Compression level 3 --
+-string(58) "735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee60200"
+ int(0)
+ -- Compression level 4 --
+-string(58) "735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee60200"
+ int(0)
+ -- Compression level 5 --
+-string(58) "735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee60200"
+ int(0)
+ -- Compression level 6 --
+-string(58) "735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee60200"
+ int(0)
+ -- Compression level 7 --
+-string(58) "735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee60200"
+ int(0)
+ -- Compression level 8 --
+-string(58) "735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee60200"
+ int(0)
+ -- Compression level 9 --
+-string(58) "735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee60200"
+ int(0)
+
+ -- Testing with no specified compression level --
+-string(58) "735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee60200"
++int(0)
+ ===Done===
+diff --git a/ext/zlib/tests/gzdeflate_variation1.phpt b/ext/zlib/tests/gzdeflate_variation1.phpt
+index 7993abb529..42bfaa1033 100644
+--- a/ext/zlib/tests/gzdeflate_variation1.phpt
++++ b/ext/zlib/tests/gzdeflate_variation1.phpt
+@@ -22,15 +22,15 @@ echo "*** Testing gzdeflate() : variation ***\n";
+
+ echo "\n-- Testing multiple compression --\n";
+ $output = gzdeflate($data);
+-var_dump( md5($output));
+-var_dump(md5(gzdeflate($output)));
++var_dump(strlen($output));
++var_dump(strlen(gzdeflate($output)));
+
+ ?>
+ ===Done===
+---EXPECT--
++--EXPECTF--
+ *** Testing gzdeflate() : variation ***
+
+ -- Testing multiple compression --
+-string(32) "078554fe65e06f6ff01eab51cfc7ae9b"
+-string(32) "86b9f895ef1377da5269ec3cb2729f71"
++int(17%d)
++int(17%d)
+ ===Done===
+diff --git a/ext/zlib/tests/gzencode_basic1.phpt b/ext/zlib/tests/gzencode_basic1.phpt
+index dfb09cc2ed..fe1ec593bd 100644
+--- a/ext/zlib/tests/gzencode_basic1.phpt
++++ b/ext/zlib/tests/gzencode_basic1.phpt
+@@ -34,10 +34,7 @@ for($i = -1; $i < 10; $i++) {
+ echo "-- Compression level $i --\n";
+ $output = gzencode($data, $i);
+
+- // Clear OS byte before encode
+- $output[9] = "\x00";
+-
+- var_dump(md5($output));
++ var_dump(strcmp(gzdecode($output), $data)===0);
+ }
+
+ // Compressing a smaller string
+@@ -45,71 +42,70 @@ for($i = -1; $i < 10; $i++) {
+ echo "-- Compression level $i --\n";
+ $output = gzencode($smallstring, $i);
+
+- // Clear OS byte before encode
+- $output[9] = "\x00";
+-
+- var_dump(md5($output));
++ var_dump(strcmp(gzdecode($output), $smallstring)===0);
+ }
+
+ // Calling gzencode() with mandatory arguments
+ echo "\n-- Testing with no specified compression level --\n";
+-var_dump(bin2hex(gzencode($smallstring)));
++$output = gzencode($smallstring);
++var_dump(strcmp(gzdecode($output), $smallstring)===0);
+
+ echo "\n-- Testing gzencode with mode specified --\n";
+-var_dump(bin2hex(gzencode($smallstring, -1, FORCE_GZIP)));
++$outupt = gzencode($smallstring, -1, FORCE_GZIP);
++var_dump(strcmp(gzdecode($output), $smallstring)===0);
+
+ ?>
+ ===Done===
+ --EXPECTF--
+ *** Testing gzencode() : basic functionality ***
+ -- Compression level -1 --
+-string(32) "d9ede02415ce91d21e5a94274e2b9c42"
++bool(true)
+ -- Compression level 0 --
+-string(32) "bbf32d5508e5f1f4e6d42790489dae15"
++bool(true)
+ -- Compression level 1 --
+-string(32) "0bfaaa7a5a57f8fb533074fca6c85eeb"
++bool(true)
+ -- Compression level 2 --
+-string(32) "7ddbfed63a76c42808722b66f1c133fc"
++bool(true)
+ -- Compression level 3 --
+-string(32) "ca2b85d194dfa2a4e8a162b646c99265"
++bool(true)
+ -- Compression level 4 --
+-string(32) "cfe28033eaf260bc33ddc04b53d3ba39"
++bool(true)
+ -- Compression level 5 --
+-string(32) "ae357fada2b515422f8bea0aa3bcc48f"
++bool(true)
+ -- Compression level 6 --
+-string(32) "d9ede02415ce91d21e5a94274e2b9c42"
++bool(true)
+ -- Compression level 7 --
+-string(32) "d9ede02415ce91d21e5a94274e2b9c42"
++bool(true)
+ -- Compression level 8 --
+-string(32) "d9ede02415ce91d21e5a94274e2b9c42"
++bool(true)
+ -- Compression level 9 --
+-string(32) "0f220a09e9895bcb3a1308d2bc99cfdf"
++bool(true)
+ -- Compression level -1 --
+-string(32) "f77bd31e1e4dd11d12828fb661a08010"
++bool(true)
+ -- Compression level 0 --
+-string(32) "9c5005db88490d6fe102ea2c233b2872"
++bool(true)
+ -- Compression level 1 --
+-string(32) "d24ff7c4c20cef69b9c3abd603368db9"
++bool(true)
+ -- Compression level 2 --
+-string(32) "f77bd31e1e4dd11d12828fb661a08010"
++bool(true)
+ -- Compression level 3 --
+-string(32) "f77bd31e1e4dd11d12828fb661a08010"
++bool(true)
+ -- Compression level 4 --
+-string(32) "f77bd31e1e4dd11d12828fb661a08010"
++bool(true)
+ -- Compression level 5 --
+-string(32) "f77bd31e1e4dd11d12828fb661a08010"
++bool(true)
+ -- Compression level 6 --
+-string(32) "f77bd31e1e4dd11d12828fb661a08010"
++bool(true)
+ -- Compression level 7 --
+-string(32) "f77bd31e1e4dd11d12828fb661a08010"
++bool(true)
+ -- Compression level 8 --
+-string(32) "f77bd31e1e4dd11d12828fb661a08010"
++bool(true)
+ -- Compression level 9 --
+-string(32) "8849e9a1543c04b3f882b5ce20839ed2"
++bool(true)
+
+ -- Testing with no specified compression level --
+-string(94) "1f8b08000000000000%c%c735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee60200edc4e40b1b000000"
++bool(true)
+
+ -- Testing gzencode with mode specified --
+-string(94) "1f8b08000000000000%c%c735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee60200edc4e40b1b000000"
++bool(true)
+ ===Done===
+diff --git a/ext/zlib/tests/gzencode_variation1.phpt b/ext/zlib/tests/gzencode_variation1.phpt
+index 2f953168fa..4cd7f61849 100644
+--- a/ext/zlib/tests/gzencode_variation1.phpt
++++ b/ext/zlib/tests/gzencode_variation1.phpt
+@@ -33,9 +33,9 @@ var_dump(bin2hex(gzencode($output)));
+
+ ?>
+ ===Done===
+---EXPECT--
++--EXPECTF--
+ *** Testing gzencode() : variation ***
+
+ -- Testing multiple compression --
+-string(3658) "1f8b0800000000000003010e07f1f81f8b08000000000000036d574d6fe4c80dbdeb57d4ad2f3dfe01eb83e1ec22980e309b4562c067b64449159754dafab0b6e7d7e73d96da1e4c72184c4b2ab2c8f7c847fa25baabba98dc1a8b2b7c38bb324b713ee37f757f56cdc5c7f5b17b9d152f923b157c5ae335e0b75fedd0e2d781c6b98ea3a6ee05affe1dfc3a6527f8f09c52dcb38ba38bb5249934d6ecfe1e53a9ab76ff4c342cf2a64ed2028349fc9a8b139755685352acb82b9fbb67f8bade5cdcb698e1fcec94b7ceba3cb897e806cfc8114350dd1ebbdfa35b62d2478b0056d23ed809b9b95d696d91ce2aa97c911e3fa539c43f84c887554a4d125c9e63ff96711cc08c0866263cb37a0bbe2122ae8f6baecb2284abfb4ddf916db8354cddeef37c1afe5fa02fc7afb3db34f5b3acbdf2eb905490d8f38d7468d253a323d5ebb903760d7944d3b2024e834a99ddce77669bdd823cfbb8e899d4ad4c799677452e6029e80023a03b2374005590641f7d3877df2ad09f3c0e82a54d6a5644fd63049a37ed4bc362016fd9f51264f1e5c630727421ae930b7ed416e93e47b7c71a400390361ffbecb7561bb98f69b5da289e91becc27f08b3b724cb8704f9144d366431d0cb870c56b205deaa2e17636063761a911039fb7e4bf9f06c4f0aecd2ec80e8b41831ca7515e31286166458ea3ef71f2ce7cde2ae269c96d60525724a9c9170b713ed5750758f3cd2a361fc8b288fc92358ce884692e8ea0fe59bd969a0da2eed5831b715749eaae7178f3ebd30fb88c92105f367cce2c882955dc6bf8eca0d5d57540b3092894743ba0fd5b2dad021836191f1afc0bba14dde1642cb0b1aa6879c38907dcefa0720082b801bec61417469219175267dfa047df35b0bd1332001c28cdfafd3bcabe91e74368cdd8d8478e494c190e7ee90c67f2bde288e68ab6b15e883c995be4f8feb6c6dda4278e4f38578ddbdc7be36788daf0c3cb1d1819c73822f7000a0d1813fa94153b572315e51343b536bc64977dff163cebfd8418773261f524017e251fccc60ae29a5770ae097594d52e9c1229d87ce967a36401c46b69945afb249d101c9d420ffa9a123e232c20e76467d5d169202a2dd4c582949e013e745df7958d4b0cc4fd4377a737cd4feea7974070000f314d423e0634cb9a618fdf5dc64fd422181fd59c9230c9f6f9d18dc8fc23e9cccbc7188733b04aa57de83ebea0be3633cff5fa1ff83269be7f44f5a8d84550cc703255fd345dd402034d0b3e11a73ec6e3d4a77f4f685b614329f1b3132ae7af33d02e1e55e291fa6574b758d1f0200e7423dbc852211818043a7c9ce80aa9d59fce0401959f5ea2cf71fde90824f8c9192dbe9d329db143794675ddcf257dd7755273b67340414e3ccad12e3f661f8aad9cf9957dc1275d10a51d3934fa81e68dc6768fb8ee23e373936c8e13feab8b0f50d227f7af76f561fb0950f3d099bbc316c3892a42fb36806d8660e800fa4f43fd4b962d2097d71933a54b77ff948677848eb17bb3a88b621682cfb3bbb49cf42fed6b3944124ad8358ca688aa44dd5f2144c7c9ab16f25b9aca9654ef357ec9ad55c40d324d6cc3d9e3920b863c231d31a95d937fb5520f9c816c79b7dcecc593fb9593cc05a51ebb1eeddd5b49eb437769738d0f64adc579d372b8b7f7c0208487ee3915ebf5766e148ebd77cf4e01f3ec285047011e55838968b6494d517fe29224777b24dd3ddf933101695b102e87db805eef291b74dcfd91628fb2a53f93dbd2968ef2e598746c9204f89fba1f0246fc671610a0591806e46a1346f77c40d910a47c5e20ffb23f003c04b648327a4ed98032c1965bd35bb0044f5344248f56fdb99aa61d6451d68e33489a83bffbe6573541b2da5f64681ea12090f778b2075374778810f73965fa3626a9d41f4df2f83f7c34658cec921b5a9bde49dd5007ec882b02adc514f81aa85898b5cc98e1b137733c0a8789b7f5648d2d231b80bf74978f25d61ce08a8abd11801fd8f995e066676307192ff7641f1cc6e0dee68565b8b22ac3889cd067bf732754a6b270af1044c6a8776811a4f6d8bd0477a9f516064201b920b92d7cd4dc7eee13e6b3eb3528a82f9abb3f388ebe6a8f871393461b73816ec54c99d604174bc5a6801de13908f86aea6a7d0fea107d682bcf1ec348b83872e6b8a316ecd02eb8f8dc86a609bf59a2dd03f1dfa4079436d55e24617be1a2854d008b2b2b1705e2078a7f3946318df1c24f6bf70d4b456eca286ec2b585b28262cc048a098c3e2d5f325a92bb36f691afdc14c822da1b116c9c1c07bb362eb0a04b78834c812134230ebf2044ac2e3c0e3ad00f848dc5010f3bf917ec2fc700b7bf26dacea8440620e04f90f4d97d6dd77cfde8a05c7d3930f1e5811fb8ec5c70964dcc8187ec90e32fdd6b64eec7586413b7d55bed65c4cce39a9b6c15e70e9da94e53fc904e6286f01f5b5562c94211befbc23507e01b2a3865e2f45b5d7b591f290087a5605b82495b4e393f31aa5b37211ec40241a746d903c5eebf117a4d3ddb0d00007b64cbc70e070000"
++string(36%d) "%s"
+ ===Done===
+diff --git a/ext/zlib/tests/gzinflate-bug42663.phpt b/ext/zlib/tests/gzinflate-bug42663.phpt
+index 4f0ca9fa7f..7127eccfdb 100644
+--- a/ext/zlib/tests/gzinflate-bug42663.phpt
++++ b/ext/zlib/tests/gzinflate-bug42663.phpt
+@@ -19,7 +19,7 @@ var_dump(gzinflate($truncated));
+ ?>
+ --EXPECTF--
+ int(168890)
+-int(66743)
++int(667%d)
+ int(65535)
+
+ Warning: gzinflate(): data error in %s on line %d
+diff --git a/ext/zlib/tests/zlib_filter_deflate.phpt b/ext/zlib/tests/zlib_filter_deflate.phpt
+index c8e54cb551..9cfa6bb889 100644
+--- a/ext/zlib/tests/zlib_filter_deflate.phpt
++++ b/ext/zlib/tests/zlib_filter_deflate.phpt
+@@ -13,5 +13,5 @@ fwrite($fp, $text);
+ fclose($fp);
+
+ ?>
+---EXPECT--
+-HctBDoAgDETRq8zOjfEeHKOGATG0TRpC4u1Vdn/xX4IoxkVMxgP1zA4vkJVhULk9UGkM6TvSNolmxUNlNLePVQ45O3eINf0fsQxtCxwv
++--EXPECTF--
++HctB%s
diff --git a/php-7.4.8-phpinfo.patch b/php-7.4.8-phpinfo.patch
index 9b7175e..fa0fff0 100644
--- a/php-7.4.8-phpinfo.patch
+++ b/php-7.4.8-phpinfo.patch
@@ -6,7 +6,7 @@ The available extensions are not related to this command.
diff -up a/ext/standard/info.c.phpinfo v/ext/standard/info.c
--- a/ext/standard/info.c.phpinfo 2015-08-18 23:39:24.000000000 +0200
+++ b/ext/standard/info.c 2015-08-22 07:56:18.344761928 +0200
-@@ -809,9 +809,6 @@ PHPAPI void php_print_info(int flag)
+@@ -810,9 +810,6 @@ PHPAPI void php_print_info(int flag)
#ifdef ARCHITECTURE
php_info_print_table_row(2, "Architecture", ARCHITECTURE);
#endif
@@ -45,7 +45,7 @@ diff --git a/configure.ac b/configure.ac
index d9e6329314a3..77f12a55569a 100644
--- a/configure.ac
+++ b/configure.ac
-@@ -1328,6 +1328,11 @@ PHP_UNAME=${PHP_UNAME:-$UNAME}
+@@ -1329,6 +1329,11 @@ PHP_UNAME=${PHP_UNAME:-$UNAME}
AC_DEFINE_UNQUOTED(PHP_UNAME,"$PHP_UNAME",[uname -a output])
PHP_OS=`uname | xargs`
AC_DEFINE_UNQUOTED(PHP_OS,"$PHP_OS",[uname output])
@@ -61,7 +61,7 @@ diff --git a/ext/standard/info.c b/ext/standard/info.c
index 262e95ae2731..f652efd23657 100644
--- a/ext/standard/info.c
+++ b/ext/standard/info.c
-@@ -803,6 +803,12 @@ PHPAPI ZEND_COLD void php_print_info(int flag)
+@@ -804,6 +804,12 @@ PHPAPI ZEND_COLD void php_print_info(int flag)
php_info_print_table_start();
php_info_print_table_row(2, "System", ZSTR_VAL(php_uname));
php_info_print_table_row(2, "Build Date", __DATE__ " " __TIME__);
diff --git a/php-cve-2022-31631.patch b/php-cve-2022-31631.patch
new file mode 100644
index 0000000..4826efc
--- /dev/null
+++ b/php-cve-2022-31631.patch
@@ -0,0 +1,84 @@
+From 7cb160efe19d3dfb8b92629805733ea186b55050 Mon Sep 17 00:00:00 2001
+From: "Christoph M. Becker" <cmbecker69@gmx.de>
+Date: Mon, 31 Oct 2022 17:20:23 +0100
+Subject: [PATCH 1/2] Fix #81740: PDO::quote() may return unquoted string
+
+`sqlite3_snprintf()` expects its first parameter to be `int`; we need
+to avoid overflow.
+
+(cherry picked from commit 921b6813da3237a83e908998483f46ae3d8bacba)
+---
+ ext/pdo_sqlite/sqlite_driver.c | 3 +++
+ ext/pdo_sqlite/tests/bug81740.phpt | 17 +++++++++++++++++
+ 2 files changed, 20 insertions(+)
+ create mode 100644 ext/pdo_sqlite/tests/bug81740.phpt
+
+diff --git a/ext/pdo_sqlite/sqlite_driver.c b/ext/pdo_sqlite/sqlite_driver.c
+index 0595bd09feb..54f9d05e1e2 100644
+--- a/ext/pdo_sqlite/sqlite_driver.c
++++ b/ext/pdo_sqlite/sqlite_driver.c
+@@ -233,6 +233,9 @@ static char *pdo_sqlite_last_insert_id(pdo_dbh_t *dbh, const char *name, size_t
+ /* NB: doesn't handle binary strings... use prepared stmts for that */
+ static int sqlite_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, size_t unquotedlen, char **quoted, size_t *quotedlen, enum pdo_param_type paramtype )
+ {
++ if (unquotedlen > (INT_MAX - 3) / 2) {
++ return 0;
++ }
+ *quoted = safe_emalloc(2, unquotedlen, 3);
+ sqlite3_snprintf(2*unquotedlen + 3, *quoted, "'%q'", unquoted);
+ *quotedlen = strlen(*quoted);
+diff --git a/ext/pdo_sqlite/tests/bug81740.phpt b/ext/pdo_sqlite/tests/bug81740.phpt
+new file mode 100644
+index 00000000000..99fb07c3048
+--- /dev/null
++++ b/ext/pdo_sqlite/tests/bug81740.phpt
+@@ -0,0 +1,17 @@
++--TEST--
++Bug #81740 (PDO::quote() may return unquoted string)
++--SKIPIF--
++<?php
++if (!extension_loaded('pdo_sqlite')) print 'skip not loaded';
++if (getenv("SKIP_SLOW_TESTS")) die("skip slow test");
++?>
++--INI--
++memory_limit=-1
++--FILE--
++<?php
++$pdo = new PDO("sqlite::memory:");
++$string = str_repeat("a", 0x80000000);
++var_dump($pdo->quote($string));
++?>
++--EXPECT--
++bool(false)
+--
+2.38.1
+
+From 7328f3a0344806b846bd05657bdce96e47810bf0 Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@remirepo.net>
+Date: Mon, 19 Dec 2022 09:24:02 +0100
+Subject: [PATCH 2/2] NEWS
+
+---
+ NEWS | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/NEWS b/NEWS
+index 8a8c0c9285d..03e8c839c77 100644
+--- a/NEWS
++++ b/NEWS
+@@ -1,5 +1,12 @@
+ PHP NEWS
+ |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
++
++Backported from 8.0.27
++
++- PDO/SQLite:
++ . Fixed bug #81740 (PDO::quote() may return unquoted string).
++ (CVE-2022-31631) (cmb)
++
+ 03 Nov 2022, PHP 7.4.33
+
+ - GD:
+--
+2.38.1
+
diff --git a/php-cve-2023-0567.patch b/php-cve-2023-0567.patch
new file mode 100644
index 0000000..62296ce
--- /dev/null
+++ b/php-cve-2023-0567.patch
@@ -0,0 +1,188 @@
+From 7437aaae38cf4b3357e7580f9e22fd4a403b6c23 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= <tim@bastelstu.be>
+Date: Mon, 23 Jan 2023 21:15:24 +0100
+Subject: [PATCH 1/7] crypt: Fix validation of malformed BCrypt hashes
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+PHP’s implementation of crypt_blowfish differs from the upstream Openwall
+version by adding a “PHP Hack”, which allows one to cut short the BCrypt salt
+by including a `$` character within the characters that represent the salt.
+
+Hashes that are affected by the “PHP Hack” may erroneously validate any
+password as valid when used with `password_verify` and when comparing the
+return value of `crypt()` against the input.
+
+The PHP Hack exists since the first version of PHP’s own crypt_blowfish
+implementation that was added in 1e820eca02dcf322b41fd2fe4ed2a6b8309f8ab5.
+
+No clear reason is given for the PHP Hack’s existence. This commit removes it,
+because BCrypt hashes containing a `$` character in their salt are not valid
+BCrypt hashes.
+
+(cherry picked from commit c840f71524067aa474c00c3eacfb83bd860bfc8a)
+---
+ ext/standard/crypt_blowfish.c | 8 --
+ .../tests/crypt/bcrypt_salt_dollar.phpt | 82 +++++++++++++++++++
+ 2 files changed, 82 insertions(+), 8 deletions(-)
+ create mode 100644 ext/standard/tests/crypt/bcrypt_salt_dollar.phpt
+
+diff --git a/ext/standard/crypt_blowfish.c b/ext/standard/crypt_blowfish.c
+index c1f945f29ed..aa7e1bc2e68 100644
+--- a/ext/standard/crypt_blowfish.c
++++ b/ext/standard/crypt_blowfish.c
+@@ -376,7 +376,6 @@ static unsigned char BF_atoi64[0x60] = {
+ #define BF_safe_atoi64(dst, src) \
+ { \
+ tmp = (unsigned char)(src); \
+- if (tmp == '$') break; /* PHP hack */ \
+ if ((unsigned int)(tmp -= 0x20) >= 0x60) return -1; \
+ tmp = BF_atoi64[tmp]; \
+ if (tmp > 63) return -1; \
+@@ -404,13 +403,6 @@ static int BF_decode(BF_word *dst, const char *src, int size)
+ *dptr++ = ((c3 & 0x03) << 6) | c4;
+ } while (dptr < end);
+
+- if (end - dptr == size) {
+- return -1;
+- }
+-
+- while (dptr < end) /* PHP hack */
+- *dptr++ = 0;
+-
+ return 0;
+ }
+
+diff --git a/ext/standard/tests/crypt/bcrypt_salt_dollar.phpt b/ext/standard/tests/crypt/bcrypt_salt_dollar.phpt
+new file mode 100644
+index 00000000000..32e335f4b08
+--- /dev/null
++++ b/ext/standard/tests/crypt/bcrypt_salt_dollar.phpt
+@@ -0,0 +1,82 @@
++--TEST--
++bcrypt correctly rejects salts containing $
++--FILE--
++<?php
++for ($i = 0; $i < 23; $i++) {
++ $salt = '$2y$04$' . str_repeat('0', $i) . '$';
++ $result = crypt("foo", $salt);
++ var_dump($salt);
++ var_dump($result);
++ var_dump($result === $salt);
++}
++?>
++--EXPECT--
++string(8) "$2y$04$$"
++string(2) "*0"
++bool(false)
++string(9) "$2y$04$0$"
++string(2) "*0"
++bool(false)
++string(10) "$2y$04$00$"
++string(2) "*0"
++bool(false)
++string(11) "$2y$04$000$"
++string(2) "*0"
++bool(false)
++string(12) "$2y$04$0000$"
++string(2) "*0"
++bool(false)
++string(13) "$2y$04$00000$"
++string(2) "*0"
++bool(false)
++string(14) "$2y$04$000000$"
++string(2) "*0"
++bool(false)
++string(15) "$2y$04$0000000$"
++string(2) "*0"
++bool(false)
++string(16) "$2y$04$00000000$"
++string(2) "*0"
++bool(false)
++string(17) "$2y$04$000000000$"
++string(2) "*0"
++bool(false)
++string(18) "$2y$04$0000000000$"
++string(2) "*0"
++bool(false)
++string(19) "$2y$04$00000000000$"
++string(2) "*0"
++bool(false)
++string(20) "$2y$04$000000000000$"
++string(2) "*0"
++bool(false)
++string(21) "$2y$04$0000000000000$"
++string(2) "*0"
++bool(false)
++string(22) "$2y$04$00000000000000$"
++string(2) "*0"
++bool(false)
++string(23) "$2y$04$000000000000000$"
++string(2) "*0"
++bool(false)
++string(24) "$2y$04$0000000000000000$"
++string(2) "*0"
++bool(false)
++string(25) "$2y$04$00000000000000000$"
++string(2) "*0"
++bool(false)
++string(26) "$2y$04$000000000000000000$"
++string(2) "*0"
++bool(false)
++string(27) "$2y$04$0000000000000000000$"
++string(2) "*0"
++bool(false)
++string(28) "$2y$04$00000000000000000000$"
++string(2) "*0"
++bool(false)
++string(29) "$2y$04$000000000000000000000$"
++string(2) "*0"
++bool(false)
++string(30) "$2y$04$0000000000000000000000$"
++string(60) "$2y$04$000000000000000000000u2a2UpVexIt9k3FMJeAVr3c04F5tcI8K"
++bool(false)
+--
+2.39.1
+
+From ed0281b588a6840cb95f3134a4e68847a3be5bb7 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= <tim@bastelstu.be>
+Date: Mon, 23 Jan 2023 22:13:57 +0100
+Subject: [PATCH 2/7] crypt: Fix possible buffer overread in php_crypt()
+
+(cherry picked from commit a92acbad873a05470af1a47cb785a18eadd827b5)
+---
+ ext/standard/crypt.c | 1 +
+ ext/standard/tests/password/password_bcrypt_short.phpt | 8 ++++++++
+ 2 files changed, 9 insertions(+)
+ create mode 100644 ext/standard/tests/password/password_bcrypt_short.phpt
+
+diff --git a/ext/standard/crypt.c b/ext/standard/crypt.c
+index 92430b69f77..04487f3fe5a 100644
+--- a/ext/standard/crypt.c
++++ b/ext/standard/crypt.c
+@@ -151,6 +151,7 @@ PHPAPI zend_string *php_crypt(const char *password, const int pass_len, const ch
+ } else if (
+ salt[0] == '$' &&
+ salt[1] == '2' &&
++ salt[2] != 0 &&
+ salt[3] == '$') {
+ char output[PHP_MAX_SALT_LEN + 1];
+
+diff --git a/ext/standard/tests/password/password_bcrypt_short.phpt b/ext/standard/tests/password/password_bcrypt_short.phpt
+new file mode 100644
+index 00000000000..085bc8a2390
+--- /dev/null
++++ b/ext/standard/tests/password/password_bcrypt_short.phpt
+@@ -0,0 +1,8 @@
++--TEST--
++Test that password_hash() does not overread buffers when a short hash is passed
++--FILE--
++<?php
++var_dump(password_verify("foo", '$2'));
++?>
++--EXPECT--
++bool(false)
+--
+2.39.1
+
diff --git a/php-cve-2023-0568.patch b/php-cve-2023-0568.patch
new file mode 100644
index 0000000..6e2ba19
--- /dev/null
+++ b/php-cve-2023-0568.patch
@@ -0,0 +1,98 @@
+From 887cd0710ad856a0d22c329b6ea6c71ebd8621ae Mon Sep 17 00:00:00 2001
+From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
+Date: Fri, 27 Jan 2023 19:28:27 +0100
+Subject: [PATCH 3/7] Fix array overrun when appending slash to paths
+
+Fix it by extending the array sizes by one character. As the input is
+limited to the maximum path length, there will always be place to append
+the slash. As the php_check_specific_open_basedir() simply uses the
+strings to compare against each other, no new failures related to too
+long paths are introduced.
+We'll let the DOM and XML case handle a potentially too long path in the
+library code.
+
+(cherry picked from commit ec10b28d64decbc54aa1e585dce580f0bd7a5953)
+---
+ ext/dom/document.c | 2 +-
+ ext/xmlreader/php_xmlreader.c | 2 +-
+ main/fopen_wrappers.c | 6 +++---
+ 3 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/ext/dom/document.c b/ext/dom/document.c
+index b478e1a1aab..e683eb8f701 100644
+--- a/ext/dom/document.c
++++ b/ext/dom/document.c
+@@ -1380,7 +1380,7 @@ static xmlDocPtr dom_document_parser(zval *id, int mode, char *source, size_t so
+ int validate, recover, resolve_externals, keep_blanks, substitute_ent;
+ int resolved_path_len;
+ int old_error_reporting = 0;
+- char *directory=NULL, resolved_path[MAXPATHLEN];
++ char *directory=NULL, resolved_path[MAXPATHLEN + 1];
+
+ if (id != NULL) {
+ intern = Z_DOMOBJ_P(id);
+diff --git a/ext/xmlreader/php_xmlreader.c b/ext/xmlreader/php_xmlreader.c
+index 06f569949ce..ecc81ad1470 100644
+--- a/ext/xmlreader/php_xmlreader.c
++++ b/ext/xmlreader/php_xmlreader.c
+@@ -1038,7 +1038,7 @@ PHP_METHOD(xmlreader, XML)
+ xmlreader_object *intern = NULL;
+ char *source, *uri = NULL, *encoding = NULL;
+ int resolved_path_len, ret = 0;
+- char *directory=NULL, resolved_path[MAXPATHLEN];
++ char *directory=NULL, resolved_path[MAXPATHLEN + 1];
+ xmlParserInputBufferPtr inputbfr;
+ xmlTextReaderPtr reader;
+
+diff --git a/main/fopen_wrappers.c b/main/fopen_wrappers.c
+index 27135020fa3..90de040a218 100644
+--- a/main/fopen_wrappers.c
++++ b/main/fopen_wrappers.c
+@@ -138,10 +138,10 @@ PHPAPI ZEND_INI_MH(OnUpdateBaseDir)
+ */
+ PHPAPI int php_check_specific_open_basedir(const char *basedir, const char *path)
+ {
+- char resolved_name[MAXPATHLEN];
+- char resolved_basedir[MAXPATHLEN];
++ char resolved_name[MAXPATHLEN + 1];
++ char resolved_basedir[MAXPATHLEN + 1];
+ char local_open_basedir[MAXPATHLEN];
+- char path_tmp[MAXPATHLEN];
++ char path_tmp[MAXPATHLEN + 1];
+ char *path_file;
+ size_t resolved_basedir_len;
+ size_t resolved_name_len;
+--
+2.39.1
+
+From 614468ce4056c0ef93aae09532dcffdf65b594b5 Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@remirepo.net>
+Date: Mon, 13 Feb 2023 11:46:47 +0100
+Subject: [PATCH 4/7] NEWS
+
+---
+ NEWS | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/NEWS b/NEWS
+index 03e8c839c77..8157a20d4b3 100644
+--- a/NEWS
++++ b/NEWS
+@@ -1,6 +1,14 @@
+ PHP NEWS
+ |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+
++Backported from 8.0.28
++
++- Core:
++ . Fixed bug #81744 (Password_verify() always return true with some hash).
++ (CVE-2023-0567). (Tim Düsterhus)
++ . Fixed bug #81746 (1-byte array overrun in common path resolve code).
++ (CVE-2023-0568). (Niels Dossche)
++
+ Backported from 8.0.27
+
+ - PDO/SQLite:
+--
+2.39.1
+
diff --git a/php-cve-2023-0662.patch b/php-cve-2023-0662.patch
new file mode 100644
index 0000000..0a18a88
--- /dev/null
+++ b/php-cve-2023-0662.patch
@@ -0,0 +1,143 @@
+From 3a2fdef1ae38881110006616ee1f0534b082ca45 Mon Sep 17 00:00:00 2001
+From: Jakub Zelenka <bukka@php.net>
+Date: Thu, 19 Jan 2023 14:11:18 +0000
+Subject: [PATCH 5/7] Fix repeated warning for file uploads limit exceeding
+
+---
+ main/rfc1867.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/main/rfc1867.c b/main/rfc1867.c
+index edef19c16d6..4931b9aeefb 100644
+--- a/main/rfc1867.c
++++ b/main/rfc1867.c
+@@ -922,7 +922,10 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */
+ skip_upload = 1;
+ } else if (upload_cnt <= 0) {
+ skip_upload = 1;
+- sapi_module.sapi_error(E_WARNING, "Maximum number of allowable file uploads has been exceeded");
++ if (upload_cnt == 0) {
++ --upload_cnt;
++ sapi_module.sapi_error(E_WARNING, "Maximum number of allowable file uploads has been exceeded");
++ }
+ }
+
+ /* Return with an error if the posted data is garbled */
+--
+2.39.1
+
+From 8ec78d28d20c82c75c4747f44c52601cfdb22516 Mon Sep 17 00:00:00 2001
+From: Jakub Zelenka <bukka@php.net>
+Date: Thu, 19 Jan 2023 14:31:25 +0000
+Subject: [PATCH 6/7] Introduce max_multipart_body_parts INI
+
+This fixes GHSA-54hq-v5wp-fqgv DOS vulnerabality by limitting number of
+parsed multipart body parts as currently all parts were always parsed.
+---
+ main/main.c | 1 +
+ main/rfc1867.c | 11 +++++++++++
+ 2 files changed, 12 insertions(+)
+
+diff --git a/main/main.c b/main/main.c
+index 0b33b2b56c9..d8c465988cc 100644
+--- a/main/main.c
++++ b/main/main.c
+@@ -836,6 +836,7 @@ PHP_INI_BEGIN()
+ PHP_INI_ENTRY("disable_functions", "", PHP_INI_SYSTEM, NULL)
+ PHP_INI_ENTRY("disable_classes", "", PHP_INI_SYSTEM, NULL)
+ PHP_INI_ENTRY("max_file_uploads", "20", PHP_INI_SYSTEM|PHP_INI_PERDIR, NULL)
++ PHP_INI_ENTRY("max_multipart_body_parts", "-1", PHP_INI_SYSTEM|PHP_INI_PERDIR, NULL)
+
+ STD_PHP_INI_BOOLEAN("allow_url_fopen", "1", PHP_INI_SYSTEM, OnUpdateBool, allow_url_fopen, php_core_globals, core_globals)
+ STD_PHP_INI_BOOLEAN("allow_url_include", "0", PHP_INI_SYSTEM, OnUpdateBool, allow_url_include, php_core_globals, core_globals)
+diff --git a/main/rfc1867.c b/main/rfc1867.c
+index 4931b9aeefb..1b212c93325 100644
+--- a/main/rfc1867.c
++++ b/main/rfc1867.c
+@@ -694,6 +694,7 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */
+ void *event_extra_data = NULL;
+ unsigned int llen = 0;
+ int upload_cnt = INI_INT("max_file_uploads");
++ int body_parts_cnt = INI_INT("max_multipart_body_parts");
+ const zend_encoding *internal_encoding = zend_multibyte_get_internal_encoding();
+ php_rfc1867_getword_t getword;
+ php_rfc1867_getword_conf_t getword_conf;
+@@ -715,6 +716,11 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */
+ return;
+ }
+
++ if (body_parts_cnt < 0) {
++ body_parts_cnt = PG(max_input_vars) + upload_cnt;
++ }
++ int body_parts_limit = body_parts_cnt;
++
+ /* Get the boundary */
+ boundary = strstr(content_type_dup, "boundary");
+ if (!boundary) {
+@@ -799,6 +805,11 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */
+ char *pair = NULL;
+ int end = 0;
+
++ if (--body_parts_cnt < 0) {
++ php_error_docref(NULL, E_WARNING, "Multipart body parts limit exceeded %d. To increase the limit change max_multipart_body_parts in php.ini.", body_parts_limit);
++ goto fileupload_done;
++ }
++
+ while (isspace(*cd)) {
+ ++cd;
+ }
+--
+2.39.1
+
+From 472db3ee3a00ac00d36019eee0b3b7362334481c Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@remirepo.net>
+Date: Tue, 14 Feb 2023 09:14:47 +0100
+Subject: [PATCH 7/7] NEWS
+
+---
+ NEWS | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/NEWS b/NEWS
+index 8157a20d4b3..c1668368818 100644
+--- a/NEWS
++++ b/NEWS
+@@ -9,6 +9,10 @@ Backported from 8.0.28
+ . Fixed bug #81746 (1-byte array overrun in common path resolve code).
+ (CVE-2023-0568). (Niels Dossche)
+
++- FPM:
++ . Fixed bug GHSA-54hq-v5wp-fqgv (DOS vulnerability when parsing multipart
++ request body). (CVE-2023-0662) (Jakub Zelenka)
++
+ Backported from 8.0.27
+
+ - PDO/SQLite:
+--
+2.39.1
+
+From c04f310440a906fc4ca885f4ecf6e3e4cd36edc7 Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@remirepo.net>
+Date: Tue, 14 Feb 2023 11:47:22 +0100
+Subject: [PATCH] fix NEWS, not FPM specific
+
+---
+ NEWS | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/NEWS b/NEWS
+index c1668368818..3f8739eae78 100644
+--- a/NEWS
++++ b/NEWS
+@@ -8,8 +8,6 @@ Backported from 8.0.28
+ (CVE-2023-0567). (Tim Düsterhus)
+ . Fixed bug #81746 (1-byte array overrun in common path resolve code).
+ (CVE-2023-0568). (Niels Dossche)
+-
+-- FPM:
+ . Fixed bug GHSA-54hq-v5wp-fqgv (DOS vulnerability when parsing multipart
+ request body). (CVE-2023-0662) (Jakub Zelenka)
+
+--
+2.39.1
+
diff --git a/php-cve-2023-3247.patch b/php-cve-2023-3247.patch
new file mode 100644
index 0000000..e23aebf
--- /dev/null
+++ b/php-cve-2023-3247.patch
@@ -0,0 +1,152 @@
+From 0cfca9aa1395271833848daec0bace51d965531d Mon Sep 17 00:00:00 2001
+From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
+Date: Sun, 16 Apr 2023 15:05:03 +0200
+Subject: [PATCH] Fix missing randomness check and insufficient random bytes
+ for SOAP HTTP Digest
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+If php_random_bytes_throw fails, the nonce will be uninitialized, but
+still sent to the server. The client nonce is intended to protect
+against a malicious server. See section 5.10 and 5.12 of RFC 7616 [1],
+and bullet point 2 below.
+
+Tim pointed out that even though it's the MD5 of the nonce that gets sent,
+enumerating 31 bits is trivial. So we have still a stack information leak
+of 31 bits.
+
+Furthermore, Tim found the following issues:
+* The small size of cnonce might cause the server to erroneously reject
+ a request due to a repeated (cnonce, nc) pair. As per the birthday
+ problem 31 bits of randomness will return a duplication with 50%
+ chance after less than 55000 requests and nc always starts counting at 1.
+* The cnonce is intended to protect the client and password against a
+ malicious server that returns a constant server nonce where the server
+ precomputed a rainbow table between passwords and correct client response.
+ As storage is fairly cheap, a server could precompute the client responses
+ for (a subset of) client nonces and still have a chance of reversing the
+ client response with the same probability as the cnonce duplication.
+
+ Precomputing the rainbow table for all 2^31 cnonces increases the rainbow
+ table size by factor 2 billion, which is infeasible. But precomputing it
+ for 2^14 cnonces only increases the table size by factor 16k and the server
+ would still have a 10% chance of successfully reversing a password with a
+ single client request.
+
+This patch fixes the issues by increasing the nonce size, and checking
+the return value of php_random_bytes_throw(). In the process we also get
+rid of the MD5 hashing of the nonce.
+
+[1] RFC 7616: https://www.rfc-editor.org/rfc/rfc7616
+
+Co-authored-by: Tim Düsterhus <timwolla@php.net>
+(cherry picked from commit 126d517ce240e9f638d9a5eaa509eaca49ef562a)
+---
+ NEWS | 6 ++++++
+ ext/soap/php_http.c | 21 +++++++++++++--------
+ 2 files changed, 19 insertions(+), 8 deletions(-)
+
+diff --git a/NEWS b/NEWS
+index 3f8739eae7..7c07635cad 100644
+--- a/NEWS
++++ b/NEWS
+@@ -1,6 +1,12 @@
+ PHP NEWS
+ |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+
++Backported from 8.0.29
++
++- Soap:
++ . Fixed bug GHSA-76gg-c692-v2mw (Missing error check and insufficient random
++ bytes in HTTP Digest authentication for SOAP). (nielsdos, timwolla)
++
+ Backported from 8.0.28
+
+ - Core:
+diff --git a/ext/soap/php_http.c b/ext/soap/php_http.c
+index ee3dcbdc9a..e3a9afdbe9 100644
+--- a/ext/soap/php_http.c
++++ b/ext/soap/php_http.c
+@@ -666,18 +666,23 @@ int make_http_soap_request(zval *this_ptr,
+ if ((digest = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_digest", sizeof("_digest")-1)) != NULL) {
+ if (Z_TYPE_P(digest) == IS_ARRAY) {
+ char HA1[33], HA2[33], response[33], cnonce[33], nc[9];
+- zend_long nonce;
++ unsigned char nonce[16];
+ PHP_MD5_CTX md5ctx;
+ unsigned char hash[16];
+
+- php_random_bytes_throw(&nonce, sizeof(nonce));
+- nonce &= 0x7fffffff;
++ if (UNEXPECTED(php_random_bytes_throw(&nonce, sizeof(nonce)) != SUCCESS)) {
++ ZEND_ASSERT(EG(exception));
++ php_stream_close(stream);
++ zend_hash_str_del(Z_OBJPROP_P(this_ptr), "httpurl", sizeof("httpurl")-1);
++ zend_hash_str_del(Z_OBJPROP_P(this_ptr), "httpsocket", sizeof("httpsocket")-1);
++ zend_hash_str_del(Z_OBJPROP_P(this_ptr), "_use_proxy", sizeof("_use_proxy")-1);
++ smart_str_free(&soap_headers_z);
++ smart_str_free(&soap_headers);
++ return FALSE;
++ }
+
+- PHP_MD5Init(&md5ctx);
+- snprintf(cnonce, sizeof(cnonce), ZEND_LONG_FMT, nonce);
+- PHP_MD5Update(&md5ctx, (unsigned char*)cnonce, strlen(cnonce));
+- PHP_MD5Final(hash, &md5ctx);
+- make_digest(cnonce, hash);
++ php_hash_bin2hex(cnonce, nonce, sizeof(nonce));
++ cnonce[32] = 0;
+
+ if ((tmp = zend_hash_str_find(Z_ARRVAL_P(digest), "nc", sizeof("nc")-1)) != NULL &&
+ Z_TYPE_P(tmp) == IS_LONG) {
+From 40439039c224bb8cdebd1b7b3d03b8cc11e7cce7 Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@remirepo.net>
+Date: Tue, 6 Jun 2023 18:05:22 +0200
+Subject: [PATCH] Fix GH-11382 add missing hash header for bin2hex
+
+---
+ ext/soap/php_http.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/ext/soap/php_http.c b/ext/soap/php_http.c
+index e3a9afdbe9f..912b8e341d8 100644
+--- a/ext/soap/php_http.c
++++ b/ext/soap/php_http.c
+@@ -22,6 +22,7 @@
+ #include "ext/standard/base64.h"
+ #include "ext/standard/md5.h"
+ #include "ext/standard/php_random.h"
++#include "ext/hash/php_hash.h"
+
+ static char *get_http_header_value_nodup(char *headers, char *type, size_t *len);
+ static char *get_http_header_value(char *headers, char *type);
+--
+2.40.1
+
+From f3021d66d7bb42d2578530cc94f9bde47e58eb10 Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@remirepo.net>
+Date: Thu, 15 Jun 2023 08:47:55 +0200
+Subject: [PATCH] add cve
+
+---
+ NEWS | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/NEWS b/NEWS
+index 7c07635cade..899644b3d63 100644
+--- a/NEWS
++++ b/NEWS
+@@ -5,7 +5,8 @@ Backported from 8.0.29
+
+ - Soap:
+ . Fixed bug GHSA-76gg-c692-v2mw (Missing error check and insufficient random
+- bytes in HTTP Digest authentication for SOAP). (nielsdos, timwolla)
++ bytes in HTTP Digest authentication for SOAP).
++ (CVE-2023-3247) (nielsdos, timwolla)
+
+ Backported from 8.0.28
+
+--
+2.40.1
+
diff --git a/php-cve-2023-3823.patch b/php-cve-2023-3823.patch
new file mode 100644
index 0000000..a795564
--- /dev/null
+++ b/php-cve-2023-3823.patch
@@ -0,0 +1,89 @@
+From c398fe98c044c8e7c23135acdc38d4ef7bedc983 Mon Sep 17 00:00:00 2001
+From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
+Date: Mon, 10 Jul 2023 13:25:34 +0200
+Subject: [PATCH 1/4] Fix buffer mismanagement in phar_dir_read()
+
+Fixes GHSA-jqcx-ccgc-xwhv.
+
+(cherry picked from commit 80316123f3e9dcce8ac419bd9dd43546e2ccb5ef)
+---
+ ext/phar/dirstream.c | 15 ++++++++------
+ ext/phar/tests/GHSA-jqcx-ccgc-xwhv.phpt | 27 +++++++++++++++++++++++++
+ 2 files changed, 36 insertions(+), 6 deletions(-)
+ create mode 100644 ext/phar/tests/GHSA-jqcx-ccgc-xwhv.phpt
+
+diff --git a/ext/phar/dirstream.c b/ext/phar/dirstream.c
+index 4710703c70e..490b14528f1 100644
+--- a/ext/phar/dirstream.c
++++ b/ext/phar/dirstream.c
+@@ -91,25 +91,28 @@ static int phar_dir_seek(php_stream *stream, zend_off_t offset, int whence, zend
+ */
+ static ssize_t phar_dir_read(php_stream *stream, char *buf, size_t count) /* {{{ */
+ {
+- size_t to_read;
+ HashTable *data = (HashTable *)stream->abstract;
+ zend_string *str_key;
+ zend_ulong unused;
+
++ if (count != sizeof(php_stream_dirent)) {
++ return -1;
++ }
++
+ if (HASH_KEY_NON_EXISTENT == zend_hash_get_current_key(data, &str_key, &unused)) {
+ return 0;
+ }
+
+ zend_hash_move_forward(data);
+- to_read = MIN(ZSTR_LEN(str_key), count);
+
+- if (to_read == 0 || count < ZSTR_LEN(str_key)) {
++ php_stream_dirent *dirent = (php_stream_dirent *) buf;
++
++ if (sizeof(dirent->d_name) <= ZSTR_LEN(str_key)) {
+ return 0;
+ }
+
+- memset(buf, 0, sizeof(php_stream_dirent));
+- memcpy(((php_stream_dirent *) buf)->d_name, ZSTR_VAL(str_key), to_read);
+- ((php_stream_dirent *) buf)->d_name[to_read + 1] = '\0';
++ memset(dirent, 0, sizeof(php_stream_dirent));
++ PHP_STRLCPY(dirent->d_name, ZSTR_VAL(str_key), sizeof(dirent->d_name), ZSTR_LEN(str_key));
+
+ return sizeof(php_stream_dirent);
+ }
+diff --git a/ext/phar/tests/GHSA-jqcx-ccgc-xwhv.phpt b/ext/phar/tests/GHSA-jqcx-ccgc-xwhv.phpt
+new file mode 100644
+index 00000000000..4e12f05fb62
+--- /dev/null
++++ b/ext/phar/tests/GHSA-jqcx-ccgc-xwhv.phpt
+@@ -0,0 +1,27 @@
++--TEST--
++GHSA-jqcx-ccgc-xwhv (Buffer overflow and overread in phar_dir_read())
++--SKIPIF--
++<?php if (!extension_loaded("phar")) die("skip"); ?>
++--INI--
++phar.readonly=0
++--FILE--
++<?php
++$phar = new Phar(__DIR__. '/GHSA-jqcx-ccgc-xwhv.phar');
++$phar->startBuffering();
++$phar->addFromString(str_repeat('A', PHP_MAXPATHLEN - 1), 'This is the content of file 1.');
++$phar->addFromString(str_repeat('B', PHP_MAXPATHLEN - 1).'C', 'This is the content of file 2.');
++$phar->stopBuffering();
++
++$handle = opendir('phar://' . __DIR__ . '/GHSA-jqcx-ccgc-xwhv.phar');
++var_dump(strlen(readdir($handle)));
++// Must not be a string of length PHP_MAXPATHLEN+1
++var_dump(readdir($handle));
++closedir($handle);
++?>
++--CLEAN--
++<?php
++unlink(__DIR__. '/GHSA-jqcx-ccgc-xwhv.phar');
++?>
++--EXPECTF--
++int(%d)
++bool(false)
+--
+2.41.0
+
diff --git a/php-cve-2023-3824.patch b/php-cve-2023-3824.patch
new file mode 100644
index 0000000..9b8b9c4
--- /dev/null
+++ b/php-cve-2023-3824.patch
@@ -0,0 +1,644 @@
+From b3758bd21223b97c042cae7bd26a66cde081ea98 Mon Sep 17 00:00:00 2001
+From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
+Date: Sat, 15 Jul 2023 17:33:52 +0200
+Subject: [PATCH 2/4] Sanitize libxml2 globals before parsing
+
+Fixes GHSA-3qrf-m4j2-pcrr.
+
+To parse a document with libxml2, you first need to create a parsing context.
+The parsing context contains parsing options (e.g. XML_NOENT to substitute
+entities) that the application (in this case PHP) can set.
+Unfortunately, libxml2 also supports providing default set options.
+For example, if you call xmlSubstituteEntitiesDefault(1) then the XML_NOENT
+option will be added to the parsing options every time you create a parsing
+context **even if the application never requested XML_NOENT**.
+
+Third party extensions can override these globals, in particular the
+substitute entity global. This causes entity substitution to be
+unexpectedly active.
+
+Fix it by setting the parsing options to a sane known value.
+For API calls that depend on global state we introduce
+PHP_LIBXML_SANITIZE_GLOBALS() and PHP_LIBXML_RESTORE_GLOBALS().
+For other APIs that work directly with a context we introduce
+php_libxml_sanitize_parse_ctxt_options().
+
+(cherry picked from commit c283c3ab0ba45d21b2b8745c1f9c7cbfe771c975)
+---
+ ext/dom/document.c | 15 ++++++++
+ ext/dom/documentfragment.c | 2 ++
+ ...xml_global_state_entity_loader_bypass.phpt | 36 +++++++++++++++++++
+ ext/libxml/php_libxml.h | 36 +++++++++++++++++++
+ ext/simplexml/simplexml.c | 6 ++++
+ ...xml_global_state_entity_loader_bypass.phpt | 36 +++++++++++++++++++
+ ext/soap/php_xml.c | 2 ++
+ ext/xml/compat.c | 2 ++
+ ext/xmlreader/php_xmlreader.c | 9 +++++
+ ...xml_global_state_entity_loader_bypass.phpt | 35 ++++++++++++++++++
+ ext/xsl/xsltprocessor.c | 9 +++--
+ 11 files changed, 183 insertions(+), 5 deletions(-)
+ create mode 100644 ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt
+ create mode 100644 ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt
+ create mode 100644 ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt
+
+diff --git a/ext/dom/document.c b/ext/dom/document.c
+index e683eb8f701..989b5b3dd24 100644
+--- a/ext/dom/document.c
++++ b/ext/dom/document.c
+@@ -1459,6 +1459,7 @@ static xmlDocPtr dom_document_parser(zval *id, int mode, char *source, size_t so
+ options |= XML_PARSE_NOBLANKS;
+ }
+
++ php_libxml_sanitize_parse_ctxt_options(ctxt);
+ xmlCtxtUseOptions(ctxt, options);
+
+ ctxt->recovery = recover;
+@@ -1759,7 +1760,9 @@ PHP_FUNCTION(dom_document_xinclude)
+
+ DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
+
++ PHP_LIBXML_SANITIZE_GLOBALS(xinclude);
+ err = xmlXIncludeProcessFlags(docp, (int)flags);
++ PHP_LIBXML_RESTORE_GLOBALS(xinclude);
+
+ /* XML_XINCLUDE_START and XML_XINCLUDE_END nodes need to be removed as these
+ are added via xmlXIncludeProcess to mark beginning and ending of xincluded document
+@@ -1799,6 +1802,7 @@ PHP_FUNCTION(dom_document_validate)
+
+ DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
+
++ PHP_LIBXML_SANITIZE_GLOBALS(validate);
+ cvp = xmlNewValidCtxt();
+
+ cvp->userData = NULL;
+@@ -1810,6 +1814,7 @@ PHP_FUNCTION(dom_document_validate)
+ } else {
+ RETVAL_FALSE;
+ }
++ PHP_LIBXML_RESTORE_GLOBALS(validate);
+
+ xmlFreeValidCtxt(cvp);
+
+@@ -1844,14 +1849,18 @@ static void _dom_document_schema_validate(INTERNAL_FUNCTION_PARAMETERS, int type
+
+ DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
+
++ PHP_LIBXML_SANITIZE_GLOBALS(new_parser_ctxt);
++
+ switch (type) {
+ case DOM_LOAD_FILE:
+ if (CHECK_NULL_PATH(source, source_len)) {
++ PHP_LIBXML_RESTORE_GLOBALS(new_parser_ctxt);
+ php_error_docref(NULL, E_WARNING, "Invalid Schema file source");
+ RETURN_FALSE;
+ }
+ valid_file = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN);
+ if (!valid_file) {
++ PHP_LIBXML_RESTORE_GLOBALS(new_parser_ctxt);
+ php_error_docref(NULL, E_WARNING, "Invalid Schema file source");
+ RETURN_FALSE;
+ }
+@@ -1872,6 +1881,7 @@ static void _dom_document_schema_validate(INTERNAL_FUNCTION_PARAMETERS, int type
+ parser);
+ sptr = xmlSchemaParse(parser);
+ xmlSchemaFreeParserCtxt(parser);
++ PHP_LIBXML_RESTORE_GLOBALS(new_parser_ctxt);
+ if (!sptr) {
+ php_error_docref(NULL, E_WARNING, "Invalid Schema");
+ RETURN_FALSE;
+@@ -1890,11 +1900,13 @@ static void _dom_document_schema_validate(INTERNAL_FUNCTION_PARAMETERS, int type
+ valid_opts |= XML_SCHEMA_VAL_VC_I_CREATE;
+ }
+
++ PHP_LIBXML_SANITIZE_GLOBALS(validate);
+ xmlSchemaSetValidOptions(vptr, valid_opts);
+ xmlSchemaSetValidErrors(vptr, php_libxml_error_handler, php_libxml_error_handler, vptr);
+ is_valid = xmlSchemaValidateDoc(vptr, docp);
+ xmlSchemaFree(sptr);
+ xmlSchemaFreeValidCtxt(vptr);
++ PHP_LIBXML_RESTORE_GLOBALS(validate);
+
+ if (is_valid == 0) {
+ RETURN_TRUE;
+@@ -1965,12 +1977,14 @@ static void _dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAMETERS, int typ
+ return;
+ }
+
++ PHP_LIBXML_SANITIZE_GLOBALS(parse);
+ xmlRelaxNGSetParserErrors(parser,
+ (xmlRelaxNGValidityErrorFunc) php_libxml_error_handler,
+ (xmlRelaxNGValidityWarningFunc) php_libxml_error_handler,
+ parser);
+ sptr = xmlRelaxNGParse(parser);
+ xmlRelaxNGFreeParserCtxt(parser);
++ PHP_LIBXML_RESTORE_GLOBALS(parse);
+ if (!sptr) {
+ php_error_docref(NULL, E_WARNING, "Invalid RelaxNG");
+ RETURN_FALSE;
+@@ -2069,6 +2083,7 @@ static void dom_load_html(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ */
+ ctxt->sax->error = php_libxml_ctx_error;
+ ctxt->sax->warning = php_libxml_ctx_warning;
+ }
++ php_libxml_sanitize_parse_ctxt_options(ctxt);
+ if (options) {
+ htmlCtxtUseOptions(ctxt, (int)options);
+ }
+diff --git a/ext/dom/documentfragment.c b/ext/dom/documentfragment.c
+index 9b222586ac5..711c42f939d 100644
+--- a/ext/dom/documentfragment.c
++++ b/ext/dom/documentfragment.c
+@@ -131,7 +131,9 @@ PHP_METHOD(domdocumentfragment, appendXML) {
+ }
+
+ if (data) {
++ PHP_LIBXML_SANITIZE_GLOBALS(parse);
+ err = xmlParseBalancedChunkMemory(nodep->doc, NULL, NULL, 0, (xmlChar *) data, &lst);
++ PHP_LIBXML_RESTORE_GLOBALS(parse);
+ if (err != 0) {
+ RETURN_FALSE;
+ }
+diff --git a/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt b/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt
+new file mode 100644
+index 00000000000..b28afd4694e
+--- /dev/null
++++ b/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt
+@@ -0,0 +1,36 @@
++--TEST--
++GHSA-3qrf-m4j2-pcrr (libxml global state entity loader bypass)
++--SKIPIF--
++<?php
++if (!extension_loaded('libxml')) die('skip libxml extension not available');
++if (!extension_loaded('dom')) die('skip dom extension not available');
++if (!extension_loaded('zend-test')) die('skip zend-test extension not available');
++?>
++--FILE--
++<?php
++
++$xml = "<?xml version='1.0'?><!DOCTYPE root [<!ENTITY % bork SYSTEM \"php://nope\"> %bork;]><nothing/>";
++
++libxml_use_internal_errors(true);
++
++function parseXML($xml) {
++ $doc = new DOMDocument();
++ @$doc->loadXML($xml);
++ $doc->createDocumentFragment()->appendXML("&bork;");
++ foreach (libxml_get_errors() as $error) {
++ var_dump(trim($error->message));
++ }
++}
++
++parseXML($xml);
++zend_test_override_libxml_global_state();
++parseXML($xml);
++
++echo "Done\n";
++
++?>
++--EXPECT--
++string(25) "Entity 'bork' not defined"
++string(25) "Entity 'bork' not defined"
++string(25) "Entity 'bork' not defined"
++Done
+diff --git a/ext/libxml/php_libxml.h b/ext/libxml/php_libxml.h
+index cf936e95de1..92028d5703e 100644
+--- a/ext/libxml/php_libxml.h
++++ b/ext/libxml/php_libxml.h
+@@ -121,6 +121,42 @@ PHP_LIBXML_API void php_libxml_shutdown(void);
+ ZEND_TSRMLS_CACHE_EXTERN()
+ #endif
+
++/* Other extension may override the global state options, these global options
++ * are copied initially to ctxt->options. Set the options to a known good value.
++ * See libxml2 globals.c and parserInternals.c.
++ * The unique_name argument allows multiple sanitizes and restores within the
++ * same function, even nested is necessary. */
++#define PHP_LIBXML_SANITIZE_GLOBALS(unique_name) \
++ int xml_old_loadsubset_##unique_name = xmlLoadExtDtdDefaultValue; \
++ xmlLoadExtDtdDefaultValue = 0; \
++ int xml_old_validate_##unique_name = xmlDoValidityCheckingDefaultValue; \
++ xmlDoValidityCheckingDefaultValue = 0; \
++ int xml_old_pedantic_##unique_name = xmlPedanticParserDefault(0); \
++ int xml_old_substitute_##unique_name = xmlSubstituteEntitiesDefault(0); \
++ int xml_old_linenrs_##unique_name = xmlLineNumbersDefault(0); \
++ int xml_old_blanks_##unique_name = xmlKeepBlanksDefault(1);
++
++#define PHP_LIBXML_RESTORE_GLOBALS(unique_name) \
++ xmlLoadExtDtdDefaultValue = xml_old_loadsubset_##unique_name; \
++ xmlDoValidityCheckingDefaultValue = xml_old_validate_##unique_name; \
++ (void) xmlPedanticParserDefault(xml_old_pedantic_##unique_name); \
++ (void) xmlSubstituteEntitiesDefault(xml_old_substitute_##unique_name); \
++ (void) xmlLineNumbersDefault(xml_old_linenrs_##unique_name); \
++ (void) xmlKeepBlanksDefault(xml_old_blanks_##unique_name);
++
++/* Alternative for above, working directly on the context and not setting globals.
++ * Generally faster because no locking is involved, and this has the advantage that it sets the options to a known good value. */
++static zend_always_inline void php_libxml_sanitize_parse_ctxt_options(xmlParserCtxtPtr ctxt)
++{
++ ctxt->loadsubset = 0;
++ ctxt->validate = 0;
++ ctxt->pedantic = 0;
++ ctxt->replaceEntities = 0;
++ ctxt->linenumbers = 0;
++ ctxt->keepBlanks = 1;
++ ctxt->options = 0;
++}
++
+ #else /* HAVE_LIBXML */
+ #define libxml_module_ptr NULL
+ #endif
+diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c
+index 2cdff0e648d..101a9d8fd8c 100644
+--- a/ext/simplexml/simplexml.c
++++ b/ext/simplexml/simplexml.c
+@@ -2194,7 +2194,9 @@ PHP_FUNCTION(simplexml_load_file)
+ RETURN_FALSE;
+ }
+
++ PHP_LIBXML_SANITIZE_GLOBALS(read_file);
+ docp = xmlReadFile(filename, NULL, (int)options);
++ PHP_LIBXML_RESTORE_GLOBALS(read_file);
+
+ if (!docp) {
+ RETURN_FALSE;
+@@ -2248,7 +2250,9 @@ PHP_FUNCTION(simplexml_load_string)
+ RETURN_FALSE;
+ }
+
++ PHP_LIBXML_SANITIZE_GLOBALS(read_memory);
+ docp = xmlReadMemory(data, (int)data_len, NULL, NULL, (int)options);
++ PHP_LIBXML_RESTORE_GLOBALS(read_memory);
+
+ if (!docp) {
+ RETURN_FALSE;
+@@ -2298,7 +2302,9 @@ SXE_METHOD(__construct)
+ return;
+ }
+
++ PHP_LIBXML_SANITIZE_GLOBALS(read_file_or_memory);
+ docp = is_url ? xmlReadFile(data, NULL, (int)options) : xmlReadMemory(data, (int)data_len, NULL, NULL, (int)options);
++ PHP_LIBXML_RESTORE_GLOBALS(read_file_or_memory);
+
+ if (!docp) {
+ ((php_libxml_node_object *)sxe)->document = NULL;
+diff --git a/ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt b/ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt
+new file mode 100644
+index 00000000000..2152e012328
+--- /dev/null
++++ b/ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt
+@@ -0,0 +1,36 @@
++--TEST--
++GHSA-3qrf-m4j2-pcrr (libxml global state entity loader bypass)
++--SKIPIF--
++<?php
++if (!extension_loaded('libxml')) die('skip libxml extension not available');
++if (!extension_loaded('simplexml')) die('skip simplexml extension not available');
++if (!extension_loaded('zend-test')) die('skip zend-test extension not available');
++?>
++--FILE--
++<?php
++
++$xml = "<?xml version='1.0'?><!DOCTYPE root [<!ENTITY % bork SYSTEM \"php://nope\"> %bork;]><nothing/>";
++
++libxml_use_internal_errors(true);
++zend_test_override_libxml_global_state();
++
++echo "--- String test ---\n";
++simplexml_load_string($xml);
++echo "--- Constructor test ---\n";
++new SimpleXMLElement($xml);
++echo "--- File test ---\n";
++file_put_contents("libxml_global_state_entity_loader_bypass.tmp", $xml);
++simplexml_load_file("libxml_global_state_entity_loader_bypass.tmp");
++
++echo "Done\n";
++
++?>
++--CLEAN--
++<?php
++@unlink("libxml_global_state_entity_loader_bypass.tmp");
++?>
++--EXPECT--
++--- String test ---
++--- Constructor test ---
++--- File test ---
++Done
+diff --git a/ext/soap/php_xml.c b/ext/soap/php_xml.c
+index 18a266179b7..1bb7fa00a37 100644
+--- a/ext/soap/php_xml.c
++++ b/ext/soap/php_xml.c
+@@ -93,6 +93,7 @@ xmlDocPtr soap_xmlParseFile(const char *filename)
+ if (ctxt) {
+ zend_bool old;
+
++ php_libxml_sanitize_parse_ctxt_options(ctxt);
+ ctxt->keepBlanks = 0;
+ ctxt->sax->ignorableWhitespace = soap_ignorableWhitespace;
+ ctxt->sax->comment = soap_Comment;
+@@ -141,6 +142,7 @@ xmlDocPtr soap_xmlParseMemory(const void *buf, size_t buf_size)
+ if (ctxt) {
+ zend_bool old;
+
++ php_libxml_sanitize_parse_ctxt_options(ctxt);
+ ctxt->sax->ignorableWhitespace = soap_ignorableWhitespace;
+ ctxt->sax->comment = soap_Comment;
+ ctxt->sax->warning = NULL;
+diff --git a/ext/xml/compat.c b/ext/xml/compat.c
+index fc4525650fc..57eb00dd429 100644
+--- a/ext/xml/compat.c
++++ b/ext/xml/compat.c
+@@ -19,6 +19,7 @@
+ #include "php.h"
+ #if defined(HAVE_LIBXML) && (defined(HAVE_XML) || defined(HAVE_XMLRPC)) && !defined(HAVE_LIBEXPAT)
+ #include "expat_compat.h"
++#include "ext/libxml/php_libxml.h"
+
+ typedef struct _php_xml_ns {
+ xmlNsPtr nsptr;
+@@ -471,6 +472,7 @@ XML_ParserCreate_MM(const XML_Char *encoding, const XML_Memory_Handling_Suite *m
+ return NULL;
+ }
+
++ php_libxml_sanitize_parse_ctxt_options(parser->parser);
+ xmlCtxtUseOptions(parser->parser, XML_PARSE_OLDSAX);
+
+ parser->parser->replaceEntities = 1;
+diff --git a/ext/xmlreader/php_xmlreader.c b/ext/xmlreader/php_xmlreader.c
+index ecc81ad1470..51d6bb9c9f2 100644
+--- a/ext/xmlreader/php_xmlreader.c
++++ b/ext/xmlreader/php_xmlreader.c
+@@ -304,6 +304,7 @@ static xmlRelaxNGPtr _xmlreader_get_relaxNG(char *source, size_t source_len, siz
+ return NULL;
+ }
+
++ PHP_LIBXML_SANITIZE_GLOBALS(parse);
+ if (error_func || warn_func) {
+ xmlRelaxNGSetParserErrors(parser,
+ (xmlRelaxNGValidityErrorFunc) error_func,
+@@ -312,6 +313,7 @@ static xmlRelaxNGPtr _xmlreader_get_relaxNG(char *source, size_t source_len, siz
+ }
+ sptr = xmlRelaxNGParse(parser);
+ xmlRelaxNGFreeParserCtxt(parser);
++ PHP_LIBXML_RESTORE_GLOBALS(parse);
+
+ return sptr;
+ }
+@@ -881,7 +883,9 @@ PHP_METHOD(xmlreader, open)
+ valid_file = _xmlreader_get_valid_file_path(source, resolved_path, MAXPATHLEN );
+
+ if (valid_file) {
++ PHP_LIBXML_SANITIZE_GLOBALS(reader_for_file);
+ reader = xmlReaderForFile(valid_file, encoding, options);
++ PHP_LIBXML_RESTORE_GLOBALS(reader_for_file);
+ }
+
+ if (reader == NULL) {
+@@ -958,7 +962,9 @@ PHP_METHOD(xmlreader, setSchema)
+
+ intern = Z_XMLREADER_P(id);
+ if (intern && intern->ptr) {
++ PHP_LIBXML_SANITIZE_GLOBALS(schema);
+ retval = xmlTextReaderSchemaValidate(intern->ptr, source);
++ PHP_LIBXML_RESTORE_GLOBALS(schema);
+
+ if (retval == 0) {
+ RETURN_TRUE;
+@@ -1082,6 +1088,7 @@ PHP_METHOD(xmlreader, XML)
+ }
+ uri = (char *) xmlCanonicPath((const xmlChar *) resolved_path);
+ }
++ PHP_LIBXML_SANITIZE_GLOBALS(text_reader);
+ reader = xmlNewTextReader(inputbfr, uri);
+
+ if (reader != NULL) {
+@@ -1100,9 +1107,11 @@ PHP_METHOD(xmlreader, XML)
+ xmlFree(uri);
+ }
+
++ PHP_LIBXML_RESTORE_GLOBALS(text_reader);
+ return;
+ }
+ }
++ PHP_LIBXML_RESTORE_GLOBALS(text_reader);
+ }
+
+ if (uri) {
+diff --git a/ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt b/ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt
+new file mode 100644
+index 00000000000..e9ffb04c2bb
+--- /dev/null
++++ b/ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt
+@@ -0,0 +1,35 @@
++--TEST--
++GHSA-3qrf-m4j2-pcrr (libxml global state entity loader bypass)
++--SKIPIF--
++<?php
++if (!extension_loaded('libxml')) die('skip libxml extension not available');
++if (!extension_loaded('xmlreader')) die('skip xmlreader extension not available');
++if (!extension_loaded('zend-test')) die('skip zend-test extension not available');
++?>
++--FILE--
++<?php
++
++$xml = "<?xml version='1.0'?><!DOCTYPE root [<!ENTITY % bork SYSTEM \"php://nope\"> %bork;]><nothing/>";
++
++libxml_use_internal_errors(true);
++zend_test_override_libxml_global_state();
++
++echo "--- String test ---\n";
++$reader = XMLReader::xml($xml);
++$reader->read();
++echo "--- File test ---\n";
++file_put_contents("libxml_global_state_entity_loader_bypass.tmp", $xml);
++$reader = XMLReader::open("libxml_global_state_entity_loader_bypass.tmp");
++$reader->read();
++
++echo "Done\n";
++
++?>
++--CLEAN--
++<?php
++@unlink("libxml_global_state_entity_loader_bypass.tmp");
++?>
++--EXPECT--
++--- String test ---
++--- File test ---
++Done
+diff --git a/ext/xsl/xsltprocessor.c b/ext/xsl/xsltprocessor.c
+index 079920d0ffa..2d95b2ff4bb 100644
+--- a/ext/xsl/xsltprocessor.c
++++ b/ext/xsl/xsltprocessor.c
+@@ -398,7 +398,7 @@ PHP_FUNCTION(xsl_xsltprocessor_import_stylesheet)
+ xmlDoc *doc = NULL, *newdoc = NULL;
+ xsltStylesheetPtr sheetp, oldsheetp;
+ xsl_object *intern;
+- int prevSubstValue, prevExtDtdValue, clone_docu = 0;
++ int clone_docu = 0;
+ xmlNode *nodep = NULL;
+ zval *cloneDocu, member, rv;
+
+@@ -421,13 +421,12 @@ PHP_FUNCTION(xsl_xsltprocessor_import_stylesheet)
+ stylesheet document otherwise the node proxies will be a mess */
+ newdoc = xmlCopyDoc(doc, 1);
+ xmlNodeSetBase((xmlNodePtr) newdoc, (xmlChar *)doc->URL);
+- prevSubstValue = xmlSubstituteEntitiesDefault(1);
+- prevExtDtdValue = xmlLoadExtDtdDefaultValue;
++ PHP_LIBXML_SANITIZE_GLOBALS(parse);
++ xmlSubstituteEntitiesDefault(1);
+ xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
+
+ sheetp = xsltParseStylesheetDoc(newdoc);
+- xmlSubstituteEntitiesDefault(prevSubstValue);
+- xmlLoadExtDtdDefaultValue = prevExtDtdValue;
++ PHP_LIBXML_RESTORE_GLOBALS(parse);
+
+ if (!sheetp) {
+ xmlFreeDoc(newdoc);
+--
+2.41.0
+
+From ef1d507acf7be23d7624dc3c891683b2218feb51 Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@remirepo.net>
+Date: Tue, 1 Aug 2023 07:22:33 +0200
+Subject: [PATCH 3/4] NEWS
+
+---
+ NEWS | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/NEWS b/NEWS
+index 899644b3d63..4f88029a7d6 100644
+--- a/NEWS
++++ b/NEWS
+@@ -1,6 +1,16 @@
+ PHP NEWS
+ |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+
++Backported from 8.0.30
++
++- Libxml:
++ . Fixed bug GHSA-3qrf-m4j2-pcrr (Security issue with external entity loading
++ in XML without enabling it). (CVE-2023-3823) (nielsdos, ilutov)
++
++- Phar:
++ . Fixed bug GHSA-jqcx-ccgc-xwhv (Buffer mismanagement in phar_dir_read()).
++ (CVE-2023-3824) (nielsdos)
++
+ Backported from 8.0.29
+
+ - Soap:
+--
+2.41.0
+
+From 24e669e790e6aebd219c9a9fa19017455c8646b4 Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@remirepo.net>
+Date: Tue, 1 Aug 2023 07:37:25 +0200
+Subject: [PATCH 4/4] backport zend_test changes
+ (zend_test_override_libxml_global_state)
+
+---
+ ...xml_global_state_entity_loader_bypass.phpt | 1 +
+ ...xml_global_state_entity_loader_bypass.phpt | 1 +
+ ...xml_global_state_entity_loader_bypass.phpt | 5 +++--
+ ext/zend_test/test.c | 22 +++++++++++++++++++
+ 4 files changed, 27 insertions(+), 2 deletions(-)
+
+diff --git a/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt b/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt
+index b28afd4694e..7fc2a249ac7 100644
+--- a/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt
++++ b/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt
+@@ -5,6 +5,7 @@ GHSA-3qrf-m4j2-pcrr (libxml global state entity loader bypass)
+ if (!extension_loaded('libxml')) die('skip libxml extension not available');
+ if (!extension_loaded('dom')) die('skip dom extension not available');
+ if (!extension_loaded('zend-test')) die('skip zend-test extension not available');
++if (!function_exists('zend_test_override_libxml_global_state')) die('skip not for Windows');
+ ?>
+ --FILE--
+ <?php
+diff --git a/ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt b/ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt
+index 2152e012328..54f9d4941eb 100644
+--- a/ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt
++++ b/ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt
+@@ -5,6 +5,7 @@ GHSA-3qrf-m4j2-pcrr (libxml global state entity loader bypass)
+ if (!extension_loaded('libxml')) die('skip libxml extension not available');
+ if (!extension_loaded('simplexml')) die('skip simplexml extension not available');
+ if (!extension_loaded('zend-test')) die('skip zend-test extension not available');
++if (!function_exists('zend_test_override_libxml_global_state')) die('skip not for Windows');
+ ?>
+ --FILE--
+ <?php
+diff --git a/ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt b/ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt
+index e9ffb04c2bb..b0120b325ef 100644
+--- a/ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt
++++ b/ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt
+@@ -5,6 +5,7 @@ GHSA-3qrf-m4j2-pcrr (libxml global state entity loader bypass)
+ if (!extension_loaded('libxml')) die('skip libxml extension not available');
+ if (!extension_loaded('xmlreader')) die('skip xmlreader extension not available');
+ if (!extension_loaded('zend-test')) die('skip zend-test extension not available');
++if (!function_exists('zend_test_override_libxml_global_state')) die('skip not for Windows');
+ ?>
+ --FILE--
+ <?php
+@@ -15,11 +16,11 @@ libxml_use_internal_errors(true);
+ zend_test_override_libxml_global_state();
+
+ echo "--- String test ---\n";
+-$reader = XMLReader::xml($xml);
++$reader = @XMLReader::xml($xml);
+ $reader->read();
+ echo "--- File test ---\n";
+ file_put_contents("libxml_global_state_entity_loader_bypass.tmp", $xml);
+-$reader = XMLReader::open("libxml_global_state_entity_loader_bypass.tmp");
++$reader = @XMLReader::open("libxml_global_state_entity_loader_bypass.tmp");
+ $reader->read();
+
+ echo "Done\n";
+diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c
+index 4f81adc6ac1..cdfc15571c0 100644
+--- a/ext/zend_test/test.c
++++ b/ext/zend_test/test.c
+@@ -25,6 +25,11 @@
+ #include "ext/standard/info.h"
+ #include "php_test.h"
+
++#if defined(HAVE_LIBXML) && !defined(PHP_WIN32)
++# include <libxml/globals.h>
++# include <libxml/parser.h>
++#endif
++
+ static zend_class_entry *zend_test_interface;
+ static zend_class_entry *zend_test_class;
+ static zend_class_entry *zend_test_child_class;
+@@ -48,6 +53,20 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_zend_leak_variable, 0, 0, 1)
+ ZEND_ARG_INFO(0, variable)
+ ZEND_END_ARG_INFO()
+
++#if defined(HAVE_LIBXML) && !defined(PHP_WIN32)
++static ZEND_FUNCTION(zend_test_override_libxml_global_state)
++{
++ ZEND_PARSE_PARAMETERS_NONE();
++
++ xmlLoadExtDtdDefaultValue = 1;
++ xmlDoValidityCheckingDefaultValue = 1;
++ (void) xmlPedanticParserDefault(1);
++ (void) xmlSubstituteEntitiesDefault(1);
++ (void) xmlLineNumbersDefault(1);
++ (void) xmlKeepBlanksDefault(0);
++}
++#endif
++
+ ZEND_FUNCTION(zend_test_func)
+ {
+ /* dummy */
+@@ -297,6 +316,9 @@ static const zend_function_entry zend_test_functions[] = {
+ ZEND_FE(zend_terminate_string, arginfo_zend_terminate_string)
+ ZEND_FE(zend_leak_bytes, NULL)
+ ZEND_FE(zend_leak_variable, arginfo_zend_leak_variable)
++#if defined(HAVE_LIBXML) && !defined(PHP_WIN32)
++ ZEND_FE(zend_test_override_libxml_global_state, NULL)
++#endif
+ ZEND_FE_END
+ };
+
+--
+2.41.0
+
diff --git a/php-cve-2024-11233.patch b/php-cve-2024-11233.patch
new file mode 100644
index 0000000..d6c29ae
--- /dev/null
+++ b/php-cve-2024-11233.patch
@@ -0,0 +1,68 @@
+From 44a5975f83a02eb8169d12af912e6222b28216d0 Mon Sep 17 00:00:00 2001
+From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
+Date: Fri, 8 Nov 2024 22:04:21 +0100
+Subject: [PATCH 5/7] Fix GHSA-r977-prxv-hc43
+
+Move the bound check upwards. Since this doesn't generate output we can
+check the bound first.
+
+(cherry picked from commit 81030c9bbb5cd2e740b8398bb7212df9709f0274)
+(cherry picked from commit 2cee10a1206f5bc7724232d3988be2cfcb0bc9df)
+---
+ ext/standard/filters.c | 7 ++++---
+ ext/standard/tests/filters/ghsa-r977-prxv-hc43.phpt | 12 ++++++++++++
+ 2 files changed, 16 insertions(+), 3 deletions(-)
+ create mode 100644 ext/standard/tests/filters/ghsa-r977-prxv-hc43.phpt
+
+diff --git a/ext/standard/filters.c b/ext/standard/filters.c
+index 018270c730d..5d5745c6bec 100644
+--- a/ext/standard/filters.c
++++ b/ext/standard/filters.c
+@@ -1128,6 +1128,9 @@ static php_conv_err_t php_conv_qprint_decode_convert(php_conv_qprint_decode *ins
+ } break;
+
+ case 5: {
++ if (icnt == 0) {
++ goto out;
++ }
+ if (!inst->lbchars && lb_cnt == 1 && *ps == '\n') {
+ /* auto-detect soft line breaks, found network line break */
+ lb_cnt = lb_ptr = 0;
+@@ -1141,15 +1144,13 @@ static php_conv_err_t php_conv_qprint_decode_convert(php_conv_qprint_decode *ins
+ /* soft line break */
+ lb_cnt = lb_ptr = 0;
+ scan_stat = 0;
+- } else if (icnt > 0) {
++ } else {
+ if (*ps == (unsigned char)inst->lbchars[lb_cnt]) {
+ lb_cnt++;
+ ps++, icnt--;
+ } else {
+ scan_stat = 6; /* no break for short-cut */
+ }
+- } else {
+- goto out;
+ }
+ } break;
+
+diff --git a/ext/standard/tests/filters/ghsa-r977-prxv-hc43.phpt b/ext/standard/tests/filters/ghsa-r977-prxv-hc43.phpt
+new file mode 100644
+index 00000000000..8fdcce8ff22
+--- /dev/null
++++ b/ext/standard/tests/filters/ghsa-r977-prxv-hc43.phpt
+@@ -0,0 +1,12 @@
++--TEST--
++GHSA-r977-prxv-hc43: Single byte overread with convert.quoted-printable-decode filter
++--FILE--
++<?php
++
++$input_data = str_repeat('A', 8189)."X=\r";
++$filter_url = "php://filter/convert.quoted-printable-decode/resource=data:," . urlencode($input_data);
++var_dump(file_get_contents($filter_url));
++
++?>
++--EXPECT--
++string(8190) "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX"
+--
+2.47.0
+
diff --git a/php-cve-2024-11234.patch b/php-cve-2024-11234.patch
new file mode 100644
index 0000000..0fd31f3
--- /dev/null
+++ b/php-cve-2024-11234.patch
@@ -0,0 +1,95 @@
+From 494de65139592da0e5e5b6fdf198c2f9c762f4d6 Mon Sep 17 00:00:00 2001
+From: Jakub Zelenka <bukka@php.net>
+Date: Fri, 8 Nov 2024 23:43:47 +0100
+Subject: [PATCH 3/7] Fix GHSA-c5f2-jwm7-mmq2: stream HTTP fulluri CRLF
+ injection
+
+(cherry picked from commit 426a6d4539ebee34879ac5de857036bb6ff0e732)
+(cherry picked from commit bc1f192102dd8cbda028e40aa31604c4885d387c)
+(cherry picked from commit 8d130e16fbfda7d154fedfa0f1ff1d5ad5e26815)
+---
+ ext/standard/http_fopen_wrapper.c | 18 ++++++++----
+ .../tests/http/ghsa-c5f2-jwm7-mmq2.phpt | 28 +++++++++++++++++++
+ 2 files changed, 40 insertions(+), 6 deletions(-)
+ create mode 100644 ext/standard/tests/http/ghsa-c5f2-jwm7-mmq2.phpt
+
+diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c
+index 4d918b21e65..aeeb438f0f9 100644
+--- a/ext/standard/http_fopen_wrapper.c
++++ b/ext/standard/http_fopen_wrapper.c
+@@ -186,6 +186,11 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
+ return NULL;
+ }
+
++ /* Should we send the entire path in the request line, default to no. */
++ if (context && (tmpzval = php_stream_context_get_option(context, "http", "request_fulluri")) != NULL) {
++ request_fulluri = zend_is_true(tmpzval);
++ }
++
+ use_ssl = resource->scheme && (ZSTR_LEN(resource->scheme) > 4) && ZSTR_VAL(resource->scheme)[4] == 's';
+ /* choose default ports */
+ if (use_ssl && resource->port == 0)
+@@ -205,6 +210,13 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
+ }
+ }
+
++ if (request_fulluri && (strchr(path, '\n') != NULL || strchr(path, '\r') != NULL)) {
++ php_stream_wrapper_log_error(wrapper, options, "HTTP wrapper full URI path does not allow CR or LF characters");
++ php_url_free(resource);
++ efree(transport_string);
++ return NULL;
++ }
++
+ if (context && (tmpzval = php_stream_context_get_option(context, wrapper->wops->label, "timeout")) != NULL) {
+ double d = zval_get_double(tmpzval);
+ #ifndef PHP_WIN32
+@@ -385,12 +397,6 @@ finish:
+ smart_str_appends(&req_buf, "GET ");
+ }
+
+- /* Should we send the entire path in the request line, default to no. */
+- if (!request_fulluri && context &&
+- (tmpzval = php_stream_context_get_option(context, "http", "request_fulluri")) != NULL) {
+- request_fulluri = zend_is_true(tmpzval);
+- }
+-
+ if (request_fulluri) {
+ /* Ask for everything */
+ smart_str_appends(&req_buf, path);
+diff --git a/ext/standard/tests/http/ghsa-c5f2-jwm7-mmq2.phpt b/ext/standard/tests/http/ghsa-c5f2-jwm7-mmq2.phpt
+new file mode 100644
+index 00000000000..5b2e04f94f2
+--- /dev/null
++++ b/ext/standard/tests/http/ghsa-c5f2-jwm7-mmq2.phpt
+@@ -0,0 +1,28 @@
++--TEST--
++GHSA-c5f2-jwm7-mmq2 (Configuring a proxy in a stream context might allow for CRLF injection in URIs)
++--INI--
++allow_url_fopen=1
++--CONFLICTS--
++server
++--FILE--
++<?php
++$serverCode = <<<'CODE'
++echo $_SERVER['REQUEST_URI'];
++CODE;
++
++include __DIR__."/../../../../sapi/cli/tests/php_cli_server.inc";
++php_cli_server_start($serverCode, null, []);
++
++$host = PHP_CLI_SERVER_ADDRESS;
++$userinput = "index.php HTTP/1.1\r\nHost: $host\r\n\r\nGET /index2.php HTTP/1.1\r\nHost: $host\r\n\r\nGET /index.php";
++$context = stream_context_create(['http' => ['proxy' => 'tcp://' . $host, 'request_fulluri' => true]]);
++echo file_get_contents("http://$host/$userinput", false, $context);
++?>
++--EXPECTF--
++Warning: file_get_contents(http://localhost:%d/index.php HTTP/1.1
++Host: localhost:%d
++
++GET /index2.php HTTP/1.1
++Host: localhost:%d
++
++GET /index.php): failed to open stream: HTTP wrapper full URI path does not allow CR or LF characters in %s on line %d
+--
+2.47.0
+
diff --git a/php-cve-2024-11236.patch b/php-cve-2024-11236.patch
new file mode 100644
index 0000000..e917cfc
--- /dev/null
+++ b/php-cve-2024-11236.patch
@@ -0,0 +1,119 @@
+From 97546df8d6900b115536c17af9213f1da837b82e Mon Sep 17 00:00:00 2001
+From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
+Date: Thu, 24 Oct 2024 22:02:17 +0200
+Subject: [PATCH 1/7] Fix GHSA-5hqh-c84r-qjcv: Integer overflow in the dblib
+ quoter causing OOB writes
+
+(cherry picked from commit d9baa9fed8c3ba692a36b388c0c7762e5102e2e0)
+(cherry picked from commit 5d9e54065ed18c51e4f25d8900635f90810c7394)
+---
+ ext/pdo_dblib/dblib_driver.c | 8 ++++++-
+ ext/pdo_dblib/tests/GHSA-5hqh-c84r-qjcv.phpt | 24 ++++++++++++++++++++
+ 2 files changed, 31 insertions(+), 1 deletion(-)
+ create mode 100644 ext/pdo_dblib/tests/GHSA-5hqh-c84r-qjcv.phpt
+
+diff --git a/ext/pdo_dblib/dblib_driver.c b/ext/pdo_dblib/dblib_driver.c
+index f36451afeeb..1dc75a4d2e3 100644
+--- a/ext/pdo_dblib/dblib_driver.c
++++ b/ext/pdo_dblib/dblib_driver.c
+@@ -154,6 +154,7 @@ static int dblib_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, size_t unqu
+
+ size_t i;
+ char * q;
++ size_t extralen = 0;
+ *quotedlen = 0;
+
+ if (H->assume_national_character_set_strings) {
+@@ -168,7 +169,7 @@ static int dblib_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, size_t unqu
+
+ /* Detect quoted length, adding extra char for doubled single quotes */
+ for (i = 0; i < unquotedlen; i++) {
+- if (unquoted[i] == '\'') ++*quotedlen;
++ if (unquoted[i] == '\'') ++extralen;
+ ++*quotedlen;
+ }
+
+@@ -176,6 +177,11 @@ static int dblib_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, size_t unqu
+ if (use_national_character_set) {
+ ++*quotedlen; /* N prefix */
+ }
++ if (UNEXPECTED(*quotedlen > ZSTR_MAX_LEN - extralen)) {
++ return 0;
++ }
++
++ *quotedlen += extralen;
+ q = *quoted = emalloc(*quotedlen + 1); /* Add byte for terminal null */
+ if (use_national_character_set) {
+ *q++ = 'N';
+diff --git a/ext/pdo_dblib/tests/GHSA-5hqh-c84r-qjcv.phpt b/ext/pdo_dblib/tests/GHSA-5hqh-c84r-qjcv.phpt
+new file mode 100644
+index 00000000000..431c61951ee
+--- /dev/null
++++ b/ext/pdo_dblib/tests/GHSA-5hqh-c84r-qjcv.phpt
+@@ -0,0 +1,24 @@
++--TEST--
++GHSA-5hqh-c84r-qjcv (Integer overflow in the dblib quoter causing OOB writes)
++--EXTENSIONS--
++pdo_dblib
++--SKIPIF--
++<?php
++if (PHP_INT_SIZE != 4) die("skip for 32bit platforms only");
++if (PHP_OS_FAMILY === "Windows") die("skip not for Windows because the virtual address space for application is only 2GiB");
++if (getenv("SKIP_SLOW_TESTS")) die("skip slow test");
++require __DIR__ . '/config.inc';
++getDbConnection();
++?>
++--INI--
++memory_limit=-1
++--FILE--
++<?php
++
++require __DIR__ . '/config.inc';
++$db = getDbConnection();
++var_dump($db->quote(str_repeat("'", 2147483646)));
++
++?>
++--EXPECT--
++bool(false)
+--
+2.47.0
+
+From 0530cbfe5c3044537de52d8382eba5d69dbac726 Mon Sep 17 00:00:00 2001
+From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
+Date: Thu, 24 Oct 2024 22:02:36 +0200
+Subject: [PATCH 2/7] Fix GHSA-5hqh-c84r-qjcv: Integer overflow in the firebird
+ quoter causing OOB writes
+
+(cherry picked from commit 69c5f68fdc3deed9ebce2cc44b4bf5e0c47cd28f)
+(cherry picked from commit b4f73be75dbdde970a18cc7a636898b10400fb3f)
+---
+ ext/pdo_firebird/firebird_driver.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/ext/pdo_firebird/firebird_driver.c b/ext/pdo_firebird/firebird_driver.c
+index 3e403afd368..5b74290abcc 100644
+--- a/ext/pdo_firebird/firebird_driver.c
++++ b/ext/pdo_firebird/firebird_driver.c
+@@ -243,7 +243,7 @@ free_statement:
+ static int firebird_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, size_t unquotedlen, /* {{{ */
+ char **quoted, size_t *quotedlen, enum pdo_param_type paramtype)
+ {
+- int qcount = 0;
++ size_t qcount = 0;
+ char const *co, *l, *r;
+ char *c;
+
+@@ -258,6 +258,10 @@ static int firebird_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, size_t u
+ /* count the number of ' characters */
+ for (co = unquoted; (co = strchr(co,'\'')); qcount++, co++);
+
++ if (UNEXPECTED(unquotedlen + 2 > ZSTR_MAX_LEN - qcount)) {
++ return 0;
++ }
++
+ *quotedlen = unquotedlen + qcount + 2;
+ *quoted = c = emalloc(*quotedlen+1);
+ *c++ = '\'';
+--
+2.47.0
+
diff --git a/php-cve-2024-2756.patch b/php-cve-2024-2756.patch
new file mode 100644
index 0000000..d927518
--- /dev/null
+++ b/php-cve-2024-2756.patch
@@ -0,0 +1,193 @@
+From a6c1c62a25ac23b08a86af11d68f0e2eaafc102b Mon Sep 17 00:00:00 2001
+From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
+Date: Sun, 17 Mar 2024 21:04:47 +0100
+Subject: [PATCH 1/4] Fix GHSA-wpj3-hf5j-x4v4: __Host-/__Secure- cookie bypass
+ due to partial CVE-2022-31629 fix
+
+The check happened too early as later code paths may perform more
+mangling rules. Move the check downwards right before adding the actual
+variable.
+
+(cherry picked from commit 093c08af25fb323efa0c8e6154aa9fdeae3d3b53)
+(cherry picked from commit 2e07a3acd7a6b53c55325b94bed97748d7697b53)
+---
+ ext/standard/tests/ghsa-wpj3-hf5j-x4v4.phpt | 63 +++++++++++++++++++++
+ main/php_variables.c | 41 +++++++++-----
+ 2 files changed, 90 insertions(+), 14 deletions(-)
+ create mode 100644 ext/standard/tests/ghsa-wpj3-hf5j-x4v4.phpt
+
+diff --git a/ext/standard/tests/ghsa-wpj3-hf5j-x4v4.phpt b/ext/standard/tests/ghsa-wpj3-hf5j-x4v4.phpt
+new file mode 100644
+index 00000000000..77fcb680894
+--- /dev/null
++++ b/ext/standard/tests/ghsa-wpj3-hf5j-x4v4.phpt
+@@ -0,0 +1,63 @@
++--TEST--
++ghsa-wpj3-hf5j-x4v4 (__Host-/__Secure- cookie bypass due to partial CVE-2022-31629 fix)
++--COOKIE--
++..Host-test=ignore_1;
++._Host-test=ignore_2;
++.[Host-test=ignore_3;
++_.Host-test=ignore_4;
++__Host-test=ignore_5;
++_[Host-test=ignore_6;
++[.Host-test=ignore_7;
++[_Host-test=ignore_8;
++[[Host-test=ignore_9;
++..Host-test[]=ignore_10;
++._Host-test[]=ignore_11;
++.[Host-test[]=ignore_12;
++_.Host-test[]=ignore_13;
++__Host-test[]=legitimate_14;
++_[Host-test[]=legitimate_15;
++[.Host-test[]=ignore_16;
++[_Host-test[]=ignore_17;
++[[Host-test[]=ignore_18;
++..Secure-test=ignore_1;
++._Secure-test=ignore_2;
++.[Secure-test=ignore_3;
++_.Secure-test=ignore_4;
++__Secure-test=ignore_5;
++_[Secure-test=ignore_6;
++[.Secure-test=ignore_7;
++[_Secure-test=ignore_8;
++[[Secure-test=ignore_9;
++..Secure-test[]=ignore_10;
++._Secure-test[]=ignore_11;
++.[Secure-test[]=ignore_12;
++_.Secure-test[]=ignore_13;
++__Secure-test[]=legitimate_14;
++_[Secure-test[]=legitimate_15;
++[.Secure-test[]=ignore_16;
++[_Secure-test[]=ignore_17;
++[[Secure-test[]=ignore_18;
++--FILE--
++<?php
++var_dump($_COOKIE);
++?>
++--EXPECT--
++array(3) {
++ ["__Host-test"]=>
++ array(1) {
++ [0]=>
++ string(13) "legitimate_14"
++ }
++ ["_"]=>
++ array(2) {
++ ["Host-test["]=>
++ string(13) "legitimate_15"
++ ["Secure-test["]=>
++ string(13) "legitimate_15"
++ }
++ ["__Secure-test"]=>
++ array(1) {
++ [0]=>
++ string(13) "legitimate_14"
++ }
++}
+diff --git a/main/php_variables.c b/main/php_variables.c
+index 18f6b65a6c5..e971d497337 100644
+--- a/main/php_variables.c
++++ b/main/php_variables.c
+@@ -65,6 +65,21 @@ static zend_always_inline void php_register_variable_quick(const char *name, siz
+ zend_string_release_ex(key, 0);
+ }
+
++/* Discard variable if mangling made it start with __Host-, where pre-mangling it did not start with __Host-
++ * Discard variable if mangling made it start with __Secure-, where pre-mangling it did not start with __Secure- */
++static zend_bool php_is_forbidden_variable_name(const char *mangled_name, size_t mangled_name_len, const char *pre_mangled_name)
++{
++ if (mangled_name_len >= sizeof("__Host-")-1 && strncmp(mangled_name, "__Host-", sizeof("__Host-")-1) == 0 && strncmp(pre_mangled_name, "__Host-", sizeof("__Host-")-1) != 0) {
++ return 1;
++ }
++
++ if (mangled_name_len >= sizeof("__Secure-")-1 && strncmp(mangled_name, "__Secure-", sizeof("__Secure-")-1) == 0 && strncmp(pre_mangled_name, "__Secure-", sizeof("__Secure-")-1) != 0) {
++ return 1;
++ }
++
++ return 0;
++}
++
+ PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars_array)
+ {
+ char *p = NULL;
+@@ -115,20 +130,6 @@ PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars
+ }
+ var_len = p - var;
+
+- /* Discard variable if mangling made it start with __Host-, where pre-mangling it did not start with __Host- */
+- if (strncmp(var, "__Host-", sizeof("__Host-")-1) == 0 && strncmp(var_name, "__Host-", sizeof("__Host-")-1) != 0) {
+- zval_ptr_dtor_nogc(val);
+- free_alloca(var_orig, use_heap);
+- return;
+- }
+-
+- /* Discard variable if mangling made it start with __Secure-, where pre-mangling it did not start with __Secure- */
+- if (strncmp(var, "__Secure-", sizeof("__Secure-")-1) == 0 && strncmp(var_name, "__Secure-", sizeof("__Secure-")-1) != 0) {
+- zval_ptr_dtor_nogc(val);
+- free_alloca(var_orig, use_heap);
+- return;
+- }
+-
+ if (var_len==0) { /* empty variable name, or variable name with a space in it */
+ zval_ptr_dtor_nogc(val);
+ free_alloca(var_orig, use_heap);
+@@ -226,6 +227,12 @@ PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars
+ return;
+ }
+ } else {
++ if (php_is_forbidden_variable_name(index, index_len, var_name)) {
++ zval_ptr_dtor_nogc(val);
++ free_alloca(var_orig, use_heap);
++ return;
++ }
++
+ gpc_element_p = zend_symtable_str_find(symtable1, index, index_len);
+ if (!gpc_element_p) {
+ zval tmp;
+@@ -263,6 +270,12 @@ plain_var:
+ zval_ptr_dtor_nogc(val);
+ }
+ } else {
++ if (php_is_forbidden_variable_name(index, index_len, var_name)) {
++ zval_ptr_dtor_nogc(val);
++ free_alloca(var_orig, use_heap);
++ return;
++ }
++
+ zend_ulong idx;
+
+ /*
+--
+2.44.0
+
+From dcdd49ef3bfbd8ccc778850d6a0f9b98adf625d4 Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@remirepo.net>
+Date: Wed, 10 Apr 2024 08:59:32 +0200
+Subject: [PATCH 2/4] NEWS
+
+(cherry picked from commit 366cc249b7d54707572beb7096e8f6c65ee79719)
+---
+ NEWS | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/NEWS b/NEWS
+index 4f88029a7d6..d63aadc6851 100644
+--- a/NEWS
++++ b/NEWS
+@@ -1,6 +1,12 @@
+ PHP NEWS
+ |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+
++Backported from 8.1.28
++
++- Standard:
++ . Fixed bug GHSA-wpj3-hf5j-x4v4 (__Host-/__Secure- cookie bypass due to
++ partial CVE-2022-31629 fix). (CVE-2024-2756) (nielsdos)
++
+ Backported from 8.0.30
+
+ - Libxml:
+--
+2.44.0
+
diff --git a/php-cve-2024-3096.patch b/php-cve-2024-3096.patch
new file mode 100644
index 0000000..5a1f20a
--- /dev/null
+++ b/php-cve-2024-3096.patch
@@ -0,0 +1,81 @@
+From 4a7ceb9d6427f8d368f1a8739267b1f8310ec201 Mon Sep 17 00:00:00 2001
+From: Jakub Zelenka <bukka@php.net>
+Date: Fri, 29 Mar 2024 15:27:59 +0000
+Subject: [PATCH 3/4] Fix bug GHSA-q6x7-frmf-grcw: password_verify can
+ erroneously return true
+
+Disallow null character in bcrypt password
+
+(cherry picked from commit 0ba5229a3f7572846e91c8f5382e87785f543826)
+(cherry picked from commit 81794c73068d9a44bf109bbcc9793e7b56a1c051)
+---
+ ext/standard/password.c | 5 +++++
+ ext/standard/tests/password/password_bcrypt_errors.phpt | 6 ++++++
+ 2 files changed, 11 insertions(+)
+
+diff --git a/ext/standard/password.c b/ext/standard/password.c
+index 9fe7fb1a422..af80670246a 100644
+--- a/ext/standard/password.c
++++ b/ext/standard/password.c
+@@ -260,6 +260,11 @@ static zend_string* php_password_bcrypt_hash(const zend_string *password, zend_a
+ zval *zcost;
+ zend_long cost = PHP_PASSWORD_BCRYPT_COST;
+
++ if (memchr(ZSTR_VAL(password), '\0', ZSTR_LEN(password))) {
++ php_error_docref(NULL, E_WARNING, "Bcrypt password must not contain null character");
++ return NULL;
++ }
++
+ if (options && (zcost = zend_hash_str_find(options, "cost", sizeof("cost")-1)) != NULL) {
+ cost = zval_get_long(zcost);
+ }
+diff --git a/ext/standard/tests/password/password_bcrypt_errors.phpt b/ext/standard/tests/password/password_bcrypt_errors.phpt
+index a0826080e62..f95b72670ae 100644
+--- a/ext/standard/tests/password/password_bcrypt_errors.phpt
++++ b/ext/standard/tests/password/password_bcrypt_errors.phpt
+@@ -16,6 +16,8 @@ var_dump(password_hash("foo", PASSWORD_BCRYPT, array("salt" => 123)));
+
+ var_dump(password_hash("foo", PASSWORD_BCRYPT, array("cost" => "foo")));
+
++var_dump(password_hash("null\0password", PASSWORD_BCRYPT));
++
+ ?>
+ --EXPECTF--
+ Warning: password_hash(): Invalid bcrypt cost parameter specified: 3 in %s on line %d
+@@ -41,3 +43,7 @@ NULL
+
+ Warning: password_hash(): Invalid bcrypt cost parameter specified: 0 in %s on line %d
+ NULL
++
++Warning: password_hash(): Bcrypt password must not contain null character in %s on line %d
++NULL
++
+--
+2.44.0
+
+From 027bdbc636632be49ecfad8d4191509faacb34ac Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@remirepo.net>
+Date: Wed, 10 Apr 2024 09:01:09 +0200
+Subject: [PATCH 4/4] NEWS
+
+(cherry picked from commit 24f77904ee2259d722559f129f96a1f145a2367b)
+---
+ NEWS | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/NEWS b/NEWS
+index d63aadc6851..96a33c21637 100644
+--- a/NEWS
++++ b/NEWS
+@@ -6,6 +6,8 @@ Backported from 8.1.28
+ - Standard:
+ . Fixed bug GHSA-wpj3-hf5j-x4v4 (__Host-/__Secure- cookie bypass due to
+ partial CVE-2022-31629 fix). (CVE-2024-2756) (nielsdos)
++ . Fixed bug GHSA-h746-cjrr-wfmr (password_verify can erroneously return true,
++ opening ATO risk). (CVE-2024-3096) (Jakub Zelenka)
+
+ Backported from 8.0.30
+
+--
+2.44.0
+
diff --git a/php-cve-2024-5458.patch b/php-cve-2024-5458.patch
new file mode 100644
index 0000000..64a1a78
--- /dev/null
+++ b/php-cve-2024-5458.patch
@@ -0,0 +1,180 @@
+From 08be64e40197fc12dca5f802d16748d9c3cb4cb4 Mon Sep 17 00:00:00 2001
+From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
+Date: Wed, 22 May 2024 22:25:02 +0200
+Subject: [PATCH 1/2] Fix GHSA-w8qr-v226-r27w
+
+We should not early-out with success status if we found an ipv6
+hostname, we should keep checking the rest of the conditions.
+Because integrating the if-check of the ipv6 hostname in the
+"Validate domain" if-check made the code hard to read, I extracted the
+condition out to a separate function. This also required to make
+a few pointers const in order to have some clean code.
+
+(cherry picked from commit 4066610b47e22c24cbee91be434a94357056a479)
+---
+ ext/filter/logical_filters.c | 35 ++++++++++---------
+ ext/filter/tests/ghsa-w8qr-v226-r27w.phpt | 41 +++++++++++++++++++++++
+ 2 files changed, 61 insertions(+), 15 deletions(-)
+ create mode 100644 ext/filter/tests/ghsa-w8qr-v226-r27w.phpt
+
+diff --git a/ext/filter/logical_filters.c b/ext/filter/logical_filters.c
+index e5e87c01568..9c86ad072cc 100644
+--- a/ext/filter/logical_filters.c
++++ b/ext/filter/logical_filters.c
+@@ -91,7 +91,7 @@
+ #define FORMAT_IPV4 4
+ #define FORMAT_IPV6 6
+
+-static int _php_filter_validate_ipv6(char *str, size_t str_len, int ip[8]);
++static int _php_filter_validate_ipv6(const char *str, size_t str_len, int ip[8]);
+
+ static int php_filter_parse_int(const char *str, size_t str_len, zend_long *ret) { /* {{{ */
+ zend_long ctx_value;
+@@ -571,6 +571,14 @@ static int is_userinfo_valid(zend_string *str)
+ return 1;
+ }
+
++static zend_bool php_filter_is_valid_ipv6_hostname(const char *s, size_t l)
++{
++ const char *e = s + l;
++ const char *t = e - 1;
++
++ return *s == '[' && *t == ']' && _php_filter_validate_ipv6(s + 1, l - 2, NULL);
++}
++
+ void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
+ {
+ php_url *url;
+@@ -596,7 +604,7 @@ void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
+
+ if (url->scheme != NULL &&
+ (zend_string_equals_literal_ci(url->scheme, "http") || zend_string_equals_literal_ci(url->scheme, "https"))) {
+- char *e, *s, *t;
++ const char *s;
+ size_t l;
+
+ if (url->host == NULL) {
+@@ -605,17 +613,14 @@ void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
+
+ s = ZSTR_VAL(url->host);
+ l = ZSTR_LEN(url->host);
+- e = s + l;
+- t = e - 1;
+-
+- /* An IPv6 enclosed by square brackets is a valid hostname */
+- if (*s == '[' && *t == ']' && _php_filter_validate_ipv6((s + 1), l - 2, NULL)) {
+- php_url_free(url);
+- return;
+- }
+
+- // Validate domain
+- if (!_php_filter_validate_domain(ZSTR_VAL(url->host), l, FILTER_FLAG_HOSTNAME)) {
++ if (
++ /* An IPv6 enclosed by square brackets is a valid hostname.*/
++ !php_filter_is_valid_ipv6_hostname(s, l) &&
++ /* Validate domain.
++ * This includes a loose check for an IPv4 address. */
++ !_php_filter_validate_domain(ZSTR_VAL(url->host), l, FILTER_FLAG_HOSTNAME)
++ ) {
+ php_url_free(url);
+ RETURN_VALIDATION_FAILED
+ }
+@@ -749,15 +754,15 @@ static int _php_filter_validate_ipv4(char *str, size_t str_len, int *ip) /* {{{
+ }
+ /* }}} */
+
+-static int _php_filter_validate_ipv6(char *str, size_t str_len, int ip[8]) /* {{{ */
++static int _php_filter_validate_ipv6(const char *str, size_t str_len, int ip[8]) /* {{{ */
+ {
+ int compressed_pos = -1;
+ int blocks = 0;
+ int num, n, i;
+ char *ipv4;
+- char *end;
++ const char *end;
+ int ip4elm[4];
+- char *s = str;
++ const char *s = str;
+
+ if (!memchr(str, ':', str_len)) {
+ return 0;
+diff --git a/ext/filter/tests/ghsa-w8qr-v226-r27w.phpt b/ext/filter/tests/ghsa-w8qr-v226-r27w.phpt
+new file mode 100644
+index 00000000000..0092408ee5a
+--- /dev/null
++++ b/ext/filter/tests/ghsa-w8qr-v226-r27w.phpt
+@@ -0,0 +1,41 @@
++--TEST--
++GHSA-w8qr-v226-r27w
++--EXTENSIONS--
++filter
++--FILE--
++<?php
++
++function test(string $input) {
++ var_dump(filter_var($input, FILTER_VALIDATE_URL));
++}
++
++echo "--- These ones should fail ---\n";
++test("http://t[est@127.0.0.1");
++test("http://t[est@[::1]");
++test("http://t[est@[::1");
++test("http://t[est@::1]");
++test("http://php.net\\@aliyun.com/aaa.do");
++test("http://test[@2001:db8:3333:4444:5555:6666:1.2.3.4]");
++test("http://te[st@2001:db8:3333:4444:5555:6666:1.2.3.4]");
++test("http://te[st@2001:db8:3333:4444:5555:6666:1.2.3.4");
++
++echo "--- These ones should work ---\n";
++test("http://test@127.0.0.1");
++test("http://test@[2001:db8:3333:4444:5555:6666:1.2.3.4]");
++test("http://test@[::1]");
++
++?>
++--EXPECT--
++--- These ones should fail ---
++bool(false)
++bool(false)
++bool(false)
++bool(false)
++bool(false)
++bool(false)
++bool(false)
++bool(false)
++--- These ones should work ---
++string(21) "http://test@127.0.0.1"
++string(50) "http://test@[2001:db8:3333:4444:5555:6666:1.2.3.4]"
++string(17) "http://test@[::1]"
+--
+2.45.1
+
+From ec1d5e6468479e64acc7fb8cb955f053b64ea9a0 Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@remirepo.net>
+Date: Tue, 4 Jun 2024 16:48:08 +0200
+Subject: [PATCH 2/2] NEWS
+
+(cherry picked from commit a1ff81b786bd519597e770795be114f5171f0648)
+---
+ NEWS | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/NEWS b/NEWS
+index 8058eff0256..34ad33cf5c4 100644
+--- a/NEWS
++++ b/NEWS
+@@ -1,6 +1,12 @@
+ PHP NEWS
+ |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+
++Backported from 8.1.29
++
++- Filter:
++ . Fixed bug GHSA-w8qr-v226-r27w (Filter bypass in filter_var FILTER_VALIDATE_URL).
++ (CVE-2024-5458) (nielsdos)
++
+ Backported from 8.1.28
+
+ - Standard:
+--
+2.45.1
+
diff --git a/php-cve-2024-8925.patch b/php-cve-2024-8925.patch
new file mode 100644
index 0000000..f219a24
--- /dev/null
+++ b/php-cve-2024-8925.patch
@@ -0,0 +1,227 @@
+From a24ac172f52e75101913f3946cfa5515f723c99f Mon Sep 17 00:00:00 2001
+From: Arnaud Le Blanc <arnaud.lb@gmail.com>
+Date: Mon, 9 Sep 2024 15:22:07 +0200
+Subject: [PATCH 04/11] Fix GHSA-9pqp-7h25-4f32
+
+multipart/form-data boundaries larger than the read buffer result in erroneous
+parsing, which violates data integrity.
+
+Limit boundary size, as allowed by RFC 1521:
+
+ Encapsulation boundaries [...] must be no longer than 70 characters, not
+ counting the two leading hyphens.
+
+We correctly parse payloads with boundaries of length up to
+FILLUNIT-strlen("\r\n--") bytes, so allow this for BC.
+
+(cherry picked from commit 19b49258d0c5a61398d395d8afde1123e8d161e0)
+(cherry picked from commit 2b0daf421c162376892832588eccdfa9a286ed09)
+---
+ main/rfc1867.c | 7 ++
+ tests/basic/GHSA-9pqp-7h25-4f32.inc | 3 +
+ tests/basic/GHSA-9pqp-7h25-4f32.phpt | 100 +++++++++++++++++++++++++++
+ 3 files changed, 110 insertions(+)
+ create mode 100644 tests/basic/GHSA-9pqp-7h25-4f32.inc
+ create mode 100644 tests/basic/GHSA-9pqp-7h25-4f32.phpt
+
+diff --git a/main/rfc1867.c b/main/rfc1867.c
+index 1b212c93325..43ccce120c3 100644
+--- a/main/rfc1867.c
++++ b/main/rfc1867.c
+@@ -759,6 +759,13 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */
+ boundary_len = boundary_end-boundary;
+ }
+
++ /* Boundaries larger than FILLUNIT-strlen("\r\n--") characters lead to
++ * erroneous parsing */
++ if (boundary_len > FILLUNIT-strlen("\r\n--")) {
++ sapi_module.sapi_error(E_WARNING, "Boundary too large in multipart/form-data POST data");
++ return;
++ }
++
+ /* Initialize the buffer */
+ if (!(mbuff = multipart_buffer_new(boundary, boundary_len))) {
+ sapi_module.sapi_error(E_WARNING, "Unable to initialize the input buffer");
+diff --git a/tests/basic/GHSA-9pqp-7h25-4f32.inc b/tests/basic/GHSA-9pqp-7h25-4f32.inc
+new file mode 100644
+index 00000000000..adf72a361a2
+--- /dev/null
++++ b/tests/basic/GHSA-9pqp-7h25-4f32.inc
+@@ -0,0 +1,3 @@
++<?php
++print "Hello world\n";
++var_dump($_POST);
+diff --git a/tests/basic/GHSA-9pqp-7h25-4f32.phpt b/tests/basic/GHSA-9pqp-7h25-4f32.phpt
+new file mode 100644
+index 00000000000..af819163705
+--- /dev/null
++++ b/tests/basic/GHSA-9pqp-7h25-4f32.phpt
+@@ -0,0 +1,100 @@
++--TEST--
++GHSA-9pqp-7h25-4f32
++--SKIPIF--
++<?php
++if (!getenv('TEST_PHP_CGI_EXECUTABLE')) {
++ die("skip php-cgi not available");
++}
++?>
++--FILE--
++<?php
++
++const FILLUNIT = 5 * 1024;
++
++function test($boundaryLen) {
++ printf("Boundary len: %d\n", $boundaryLen);
++
++ $cmd = [
++ getenv('TEST_PHP_CGI_EXECUTABLE'),
++ '-C',
++ '-n',
++ __DIR__ . '/GHSA-9pqp-7h25-4f32.inc',
++ ];
++
++ $boundary = str_repeat('A', $boundaryLen);
++ $body = ""
++ . "--$boundary\r\n"
++ . "Content-Disposition: form-data; name=\"koko\"\r\n"
++ . "\r\n"
++ . "BBB\r\n--" . substr($boundary, 0, -1) . "CCC\r\n"
++ . "--$boundary--\r\n"
++ ;
++
++ $env = array_merge($_ENV, [
++ 'REDIRECT_STATUS' => '1',
++ 'CONTENT_TYPE' => "multipart/form-data; boundary=$boundary",
++ 'CONTENT_LENGTH' => strlen($body),
++ 'REQUEST_METHOD' => 'POST',
++ 'SCRIPT_FILENAME' => __DIR__ . '/GHSA-9pqp-7h25-4f32.inc',
++ ]);
++
++ $spec = [
++ 0 => ['pipe', 'r'],
++ 1 => STDOUT,
++ 2 => STDOUT,
++ ];
++
++ $pipes = [];
++
++ print "Starting...\n";
++
++ $handle = proc_open($cmd, $spec, $pipes, getcwd(), $env);
++
++ fwrite($pipes[0], $body);
++
++ $status = proc_close($handle);
++
++ print "\n";
++}
++
++for ($offset = -1; $offset <= 1; $offset++) {
++ test(FILLUNIT - strlen("\r\n--") + $offset);
++}
++
++?>
++--EXPECTF--
++Boundary len: 5115
++Starting...
++X-Powered-By: %s
++Content-type: text/html; charset=UTF-8
++
++Hello world
++array(1) {
++ ["koko"]=>
++ string(5124) "BBB
++--AAA%sCCC"
++}
++
++Boundary len: 5116
++Starting...
++X-Powered-By: %s
++Content-type: text/html; charset=UTF-8
++
++Hello world
++array(1) {
++ ["koko"]=>
++ string(5125) "BBB
++--AAA%sCCC"
++}
++
++Boundary len: 5117
++Starting...
++X-Powered-By: %s
++Content-type: text/html; charset=UTF-8
++
++<br />
++<b>Warning</b>: Boundary too large in multipart/form-data POST data in <b>Unknown</b> on line <b>0</b><br />
++Hello world
++array(0) {
++}
++
+--
+2.46.1
+
+From 2fd1b83817d20523e72bef3ad524cd5797f51acf Mon Sep 17 00:00:00 2001
+From: Jakub Zelenka <bukka@php.net>
+Date: Mon, 23 Sep 2024 18:54:31 +0100
+Subject: [PATCH 08/11] Skip GHSA-9pqp-7h25-4f32 test on Windows
+
+(cherry picked from commit c70e25630832fa10d421328eed2b8e1a36af7a64)
+(cherry picked from commit c75683864f6e4188439e8ca2adbb05824918be12)
+---
+ tests/basic/GHSA-9pqp-7h25-4f32.phpt | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/tests/basic/GHSA-9pqp-7h25-4f32.phpt b/tests/basic/GHSA-9pqp-7h25-4f32.phpt
+index af819163705..29bcb6557d5 100644
+--- a/tests/basic/GHSA-9pqp-7h25-4f32.phpt
++++ b/tests/basic/GHSA-9pqp-7h25-4f32.phpt
+@@ -5,6 +5,9 @@ GHSA-9pqp-7h25-4f32
+ if (!getenv('TEST_PHP_CGI_EXECUTABLE')) {
+ die("skip php-cgi not available");
+ }
++if (substr(PHP_OS, 0, 3) == 'WIN') {
++ die("skip not for Windows in CI - probably resource issue");
++}
+ ?>
+ --FILE--
+ <?php
+--
+2.46.1
+
+From 29065f33f37f99ba33254cb23c941647bcd7372c Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@remirepo.net>
+Date: Thu, 26 Sep 2024 15:49:03 +0200
+Subject: [PATCH 11/11] adapt GHSA-9pqp-7h25-4f32 test for 7.x
+
+---
+ tests/basic/GHSA-9pqp-7h25-4f32.phpt | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/tests/basic/GHSA-9pqp-7h25-4f32.phpt b/tests/basic/GHSA-9pqp-7h25-4f32.phpt
+index 29bcb6557d5..a1ead918ff3 100644
+--- a/tests/basic/GHSA-9pqp-7h25-4f32.phpt
++++ b/tests/basic/GHSA-9pqp-7h25-4f32.phpt
+@@ -21,6 +21,7 @@ function test($boundaryLen) {
+ getenv('TEST_PHP_CGI_EXECUTABLE'),
+ '-C',
+ '-n',
++ '-dlog_errors=1',
+ __DIR__ . '/GHSA-9pqp-7h25-4f32.inc',
+ ];
+
+@@ -92,11 +93,10 @@ array(1) {
+
+ Boundary len: 5117
+ Starting...
++PHP Warning: Boundary too large in multipart/form-data POST data in Unknown on line 0
+ X-Powered-By: %s
+ Content-type: text/html; charset=UTF-8
+
+-<br />
+-<b>Warning</b>: Boundary too large in multipart/form-data POST data in <b>Unknown</b> on line <b>0</b><br />
+ Hello world
+ array(0) {
+ }
+--
+2.46.1
+
diff --git a/php-cve-2024-8926.patch b/php-cve-2024-8926.patch
new file mode 100644
index 0000000..b5baaa8
--- /dev/null
+++ b/php-cve-2024-8926.patch
@@ -0,0 +1,210 @@
+From fb718aa6f2117933566bb7bb2f70b2b0d9a9c08f Mon Sep 17 00:00:00 2001
+From: Jan Ehrhardt <github@ehrhardt.nl>
+Date: Wed, 5 Jun 2024 20:24:52 +0200
+Subject: [PATCH 01/11] Fix GHSA-3qgc-jrrr-25jv
+
+---
+ sapi/cgi/cgi_main.c | 23 ++++++++++++++-
+ sapi/cgi/tests/ghsa-3qgc-jrrr-25jv.phpt | 38 +++++++++++++++++++++++++
+ 2 files changed, 60 insertions(+), 1 deletion(-)
+ create mode 100644 sapi/cgi/tests/ghsa-3qgc-jrrr-25jv.phpt
+
+diff --git a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c
+index a36f426d266..8d1342727dc 100644
+--- a/sapi/cgi/cgi_main.c
++++ b/sapi/cgi/cgi_main.c
+@@ -1827,8 +1827,13 @@ int main(int argc, char *argv[])
+ }
+ }
+
++ /* Apache CGI will pass the query string to the command line if it doesn't contain a '='.
++ * This can create an issue where a malicious request can pass command line arguments to
++ * the executable. Ideally we skip argument parsing when we're in cgi or fastcgi mode,
++ * but that breaks PHP scripts on Linux with a hashbang: `#!/php-cgi -d option=value`.
++ * Therefore, this code only prevents passing arguments if the query string starts with a '-'.
++ * Similarly, scripts spawned in subprocesses on Windows may have the same issue. */
+ if((query_string = getenv("QUERY_STRING")) != NULL && strchr(query_string, '=') == NULL) {
+- /* we've got query string that has no = - apache CGI will pass it to command line */
+ unsigned char *p;
+ decoded_query_string = strdup(query_string);
+ php_url_decode(decoded_query_string, strlen(decoded_query_string));
+@@ -1838,6 +1843,22 @@ int main(int argc, char *argv[])
+ if(*p == '-') {
+ skip_getopt = 1;
+ }
++
++ /* On Windows we have to take into account the "best fit" mapping behaviour. */
++#ifdef PHP_WIN32
++ if (*p >= 0x80) {
++ wchar_t wide_buf[1];
++ wide_buf[0] = *p;
++ char char_buf[4];
++ size_t wide_buf_len = sizeof(wide_buf) / sizeof(wide_buf[0]);
++ size_t char_buf_len = sizeof(char_buf) / sizeof(char_buf[0]);
++ if (WideCharToMultiByte(CP_ACP, 0, wide_buf, wide_buf_len, char_buf, char_buf_len, NULL, NULL) == 0
++ || char_buf[0] == '-') {
++ skip_getopt = 1;
++ }
++ }
++#endif
++
+ free(decoded_query_string);
+ }
+
+diff --git a/sapi/cgi/tests/ghsa-3qgc-jrrr-25jv.phpt b/sapi/cgi/tests/ghsa-3qgc-jrrr-25jv.phpt
+new file mode 100644
+index 00000000000..fd2fcdfbf89
+--- /dev/null
++++ b/sapi/cgi/tests/ghsa-3qgc-jrrr-25jv.phpt
+@@ -0,0 +1,38 @@
++--TEST--
++GHSA-3qgc-jrrr-25jv
++--SKIPIF--
++<?php
++include 'skipif.inc';
++if (PHP_OS_FAMILY !== "Windows") die("skip Only for Windows");
++
++$codepage = trim(shell_exec("powershell Get-ItemPropertyValue HKLM:\\SYSTEM\\CurrentControlSet\\Control\\Nls\\CodePage ACP"));
++if ($codepage !== '932' && $codepage !== '936' && $codepage !== '950') die("skip Wrong codepage");
++?>
++--FILE--
++<?php
++include 'include.inc';
++
++$filename = __DIR__."/GHSA-3qgc-jrrr-25jv_tmp.php";
++$script = '<?php echo "hello "; echo "world"; ?>';
++file_put_contents($filename, $script);
++
++$php = get_cgi_path();
++reset_env_vars();
++
++putenv("SERVER_NAME=Test");
++putenv("SCRIPT_FILENAME=$filename");
++putenv("QUERY_STRING=%ads");
++putenv("REDIRECT_STATUS=1");
++
++passthru("$php -s");
++
++?>
++--CLEAN--
++<?php
++@unlink(__DIR__."/GHSA-3qgc-jrrr-25jv_tmp.php");
++?>
++--EXPECTF--
++X-Powered-By: PHP/%s
++Content-type: %s
++
++hello world
+--
+2.46.1
+
+From a634d3f5169c884715d9e26ac213ecf2a25c3666 Mon Sep 17 00:00:00 2001
+From: Jan Ehrhardt <github@ehrhardt.nl>
+Date: Sun, 9 Jun 2024 20:09:02 +0200
+Subject: [PATCH 03/11] NEWS: Add backports from 8.1.29
+
+---
+ NEWS | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/NEWS b/NEWS
+index 34ad33cf5c4..a96518695fb 100644
+--- a/NEWS
++++ b/NEWS
+@@ -3,10 +3,18 @@ PHP NEWS
+
+ Backported from 8.1.29
+
++- CGI:
++ . Fixed bug GHSA-3qgc-jrrr-25jv (Bypass of CVE-2012-1823, Argument Injection
++ in PHP-CGI). (CVE-2024-4577) (nielsdos)
++
+ - Filter:
+ . Fixed bug GHSA-w8qr-v226-r27w (Filter bypass in filter_var FILTER_VALIDATE_URL).
+ (CVE-2024-5458) (nielsdos)
+
++- Standard:
++ . Fixed bug GHSA-9fcc-425m-g385 (Bypass of CVE-2024-1874).
++ (CVE-2024-5585) (nielsdos)
++
+ Backported from 8.1.28
+
+ - Standard:
+--
+2.46.1
+
+From 1158d06f0b20532ab7309cb20f0be843f9662e3c Mon Sep 17 00:00:00 2001
+From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
+Date: Fri, 14 Jun 2024 19:49:22 +0200
+Subject: [PATCH 05/11] Fix GHSA-p99j-rfp4-xqvq
+
+It's no use trying to work around whatever the operating system and Apache
+do because we'll be fighting that until eternity.
+Change the skip_getopt condition such that when we're running in
+CGI or FastCGI mode we always skip the argument parsing.
+This is a BC break, but this seems to be the only way to get rid of this
+class of issues.
+
+(cherry picked from commit abcfd980bfa03298792fd3aba051c78d52f10642)
+(cherry picked from commit 2d2552e092b6ff32cd823692d512f126ee629842)
+---
+ sapi/cgi/cgi_main.c | 26 ++++++++------------------
+ 1 file changed, 8 insertions(+), 18 deletions(-)
+
+diff --git a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c
+index 8d1342727dc..a2761aafd7b 100644
+--- a/sapi/cgi/cgi_main.c
++++ b/sapi/cgi/cgi_main.c
+@@ -1777,7 +1777,6 @@ int main(int argc, char *argv[])
+ int status = 0;
+ #endif
+ char *query_string;
+- char *decoded_query_string;
+ int skip_getopt = 0;
+
+ #if defined(SIGPIPE) && defined(SIG_IGN)
+@@ -1832,10 +1831,15 @@ int main(int argc, char *argv[])
+ * the executable. Ideally we skip argument parsing when we're in cgi or fastcgi mode,
+ * but that breaks PHP scripts on Linux with a hashbang: `#!/php-cgi -d option=value`.
+ * Therefore, this code only prevents passing arguments if the query string starts with a '-'.
+- * Similarly, scripts spawned in subprocesses on Windows may have the same issue. */
++ * Similarly, scripts spawned in subprocesses on Windows may have the same issue.
++ * However, Windows has lots of conversion rules and command line parsing rules that
++ * are too difficult and dangerous to reliably emulate. */
+ if((query_string = getenv("QUERY_STRING")) != NULL && strchr(query_string, '=') == NULL) {
++#ifdef PHP_WIN32
++ skip_getopt = cgi || fastcgi;
++#else
+ unsigned char *p;
+- decoded_query_string = strdup(query_string);
++ char *decoded_query_string = strdup(query_string);
+ php_url_decode(decoded_query_string, strlen(decoded_query_string));
+ for (p = (unsigned char *)decoded_query_string; *p && *p <= ' '; p++) {
+ /* skip all leading spaces */
+@@ -1844,22 +1848,8 @@ int main(int argc, char *argv[])
+ skip_getopt = 1;
+ }
+
+- /* On Windows we have to take into account the "best fit" mapping behaviour. */
+-#ifdef PHP_WIN32
+- if (*p >= 0x80) {
+- wchar_t wide_buf[1];
+- wide_buf[0] = *p;
+- char char_buf[4];
+- size_t wide_buf_len = sizeof(wide_buf) / sizeof(wide_buf[0]);
+- size_t char_buf_len = sizeof(char_buf) / sizeof(char_buf[0]);
+- if (WideCharToMultiByte(CP_ACP, 0, wide_buf, wide_buf_len, char_buf, char_buf_len, NULL, NULL) == 0
+- || char_buf[0] == '-') {
+- skip_getopt = 1;
+- }
+- }
+-#endif
+-
+ free(decoded_query_string);
++#endif
+ }
+
+ while (!skip_getopt && (c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {
+--
+2.46.1
+
diff --git a/php-cve-2024-8927.patch b/php-cve-2024-8927.patch
new file mode 100644
index 0000000..ed1e4cf
--- /dev/null
+++ b/php-cve-2024-8927.patch
@@ -0,0 +1,57 @@
+From c7308ba7cd0533501b40eba255602bb5e085550f Mon Sep 17 00:00:00 2001
+From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
+Date: Tue, 18 Jun 2024 21:28:26 +0200
+Subject: [PATCH 06/11] Fix GHSA-94p6-54jq-9mwp
+
+Apache only generates REDIRECT_STATUS, so explicitly check for that
+if the server name is Apache, don't allow other variable names.
+Furthermore, redirect.so and Netscape no longer exist, so
+remove those entries as we can't check their server name anymore.
+
+We now also check for the configuration override *first* such that it
+always take precedence. This would allow for a mitigation path if
+something like this happens in the future.
+
+(cherry picked from commit 48808d98f4fc2a05193cdcc1aedd6c66816450f1)
+(cherry picked from commit 8aa748ee0657cdee8d883ba50d04b68bc450f686)
+---
+ sapi/cgi/cgi_main.c | 23 +++++++++++------------
+ 1 file changed, 11 insertions(+), 12 deletions(-)
+
+diff --git a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c
+index a2761aafd7b..ebce6302b93 100644
+--- a/sapi/cgi/cgi_main.c
++++ b/sapi/cgi/cgi_main.c
+@@ -1939,18 +1939,17 @@ int main(int argc, char *argv[])
+
+ /* check force_cgi after startup, so we have proper output */
+ if (cgi && CGIG(force_redirect)) {
+- /* Apache will generate REDIRECT_STATUS,
+- * Netscape and redirect.so will generate HTTP_REDIRECT_STATUS.
+- * redirect.so and installation instructions available from
+- * http://www.koehntopp.de/php.
+- * -- kk@netuse.de
+- */
+- if (!getenv("REDIRECT_STATUS") &&
+- !getenv ("HTTP_REDIRECT_STATUS") &&
+- /* this is to allow a different env var to be configured
+- * in case some server does something different than above */
+- (!CGIG(redirect_status_env) || !getenv(CGIG(redirect_status_env)))
+- ) {
++ /* This is to allow a different environment variable to be configured
++ * in case the we cannot auto-detect which environment variable to use.
++ * Checking this first to allow user overrides in case the environment
++ * variable can be set by an untrusted party. */
++ const char *redirect_status_env = CGIG(redirect_status_env);
++ if (!redirect_status_env) {
++ /* Apache will generate REDIRECT_STATUS. */
++ redirect_status_env = "REDIRECT_STATUS";
++ }
++
++ if (!getenv(redirect_status_env)) {
+ zend_try {
+ SG(sapi_headers).http_response_code = 400;
+ PUTS("<b>Security Alert!</b> The PHP CGI cannot be accessed directly.\n\n\
+--
+2.46.1
+
diff --git a/php-cve-2024-8929.patch b/php-cve-2024-8929.patch
new file mode 100644
index 0000000..fdc844d
--- /dev/null
+++ b/php-cve-2024-8929.patch
@@ -0,0 +1,2714 @@
+From e8bc357123ea19c4e2390374f088c9d4941f19e6 Mon Sep 17 00:00:00 2001
+From: Jakub Zelenka <bukka@php.net>
+Date: Tue, 8 Oct 2024 16:17:53 +0100
+Subject: [PATCH 1/6] Fix GHSA-h35g-vwh6-m678: Mysqlnd - various heap buffer
+ over-reads
+
+This fixes issues causing buffer over-read that leak heap content:
+- RESP packet field default left over for COM_LIST
+- RESP packet upsert filename
+- OK packet message
+- RESP packet for stmt row data
+ - ps_fetch_from_1_to_8_bytes
+ - ps_fetch_float
+ - ps_fetch_double
+ - ps_fetch_time
+ - ps_fetch_date
+ - ps_fetch_datetime
+ - ps_fetch_string
+ - ps_fetch_bit
+- RESP packet for query row data (just possible overflow on 32bit)
+
+It also adds various protocol tests using a new fake server.
+
+(cherry picked from commit 2f5aa9f9d150ca56e356f3ca9acf9d530108cb08)
+(cherry picked from commit 0d3ccf4cc54d3844bc9d1c8f6bdcd36180752a2c)
+
+adapt for 7.x
+---
+ ext/mysqli/tests/fake_server.inc | 856 ++++++++++++++++++
+ .../ghsa-h35g-vwh6-m678-auth-message.phpt | 38 +
+ ext/mysqli/tests/ghsa-h35g-vwh6-m678-def.phpt | 47 +
+ .../tests/ghsa-h35g-vwh6-m678-filename.phpt | 43 +
+ ...hsa-h35g-vwh6-m678-query-len-overflow.phpt | 48 +
+ .../ghsa-h35g-vwh6-m678-stmt-row-bit.phpt | 53 ++
+ .../ghsa-h35g-vwh6-m678-stmt-row-date.phpt | 53 ++
+ ...ghsa-h35g-vwh6-m678-stmt-row-datetime.phpt | 53 ++
+ .../ghsa-h35g-vwh6-m678-stmt-row-double.phpt | 53 ++
+ .../ghsa-h35g-vwh6-m678-stmt-row-float.phpt | 53 ++
+ .../ghsa-h35g-vwh6-m678-stmt-row-int.phpt | 53 ++
+ ...ghsa-h35g-vwh6-m678-stmt-row-no-space.phpt | 53 ++
+ .../ghsa-h35g-vwh6-m678-stmt-row-string.phpt | 53 ++
+ .../ghsa-h35g-vwh6-m678-stmt-row-time.phpt | 53 ++
+ .../tests/protocol_query_row_fetch_data.phpt | 74 ++
+ .../tests/protocol_stmt_row_fetch_data.phpt | 91 ++
+ ext/mysqlnd/mysqlnd_ps_codec.c | 69 ++
+ ext/mysqlnd/mysqlnd_result.c | 2 +-
+ ext/mysqlnd/mysqlnd_wireprotocol.c | 71 +-
+ 19 files changed, 1794 insertions(+), 22 deletions(-)
+ create mode 100644 ext/mysqli/tests/fake_server.inc
+ create mode 100644 ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt
+ create mode 100644 ext/mysqli/tests/ghsa-h35g-vwh6-m678-def.phpt
+ create mode 100644 ext/mysqli/tests/ghsa-h35g-vwh6-m678-filename.phpt
+ create mode 100644 ext/mysqli/tests/ghsa-h35g-vwh6-m678-query-len-overflow.phpt
+ create mode 100644 ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-bit.phpt
+ create mode 100644 ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-date.phpt
+ create mode 100644 ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-datetime.phpt
+ create mode 100644 ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-double.phpt
+ create mode 100644 ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-float.phpt
+ create mode 100644 ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-int.phpt
+ create mode 100644 ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-no-space.phpt
+ create mode 100644 ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-string.phpt
+ create mode 100644 ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-time.phpt
+ create mode 100644 ext/mysqli/tests/protocol_query_row_fetch_data.phpt
+ create mode 100644 ext/mysqli/tests/protocol_stmt_row_fetch_data.phpt
+
+diff --git a/ext/mysqli/tests/fake_server.inc b/ext/mysqli/tests/fake_server.inc
+new file mode 100644
+index 00000000000..b02fabc584c
+--- /dev/null
++++ b/ext/mysqli/tests/fake_server.inc
+@@ -0,0 +1,856 @@
++<?php
++
++function my_mysqli_data_fields(): array
++{
++ return [
++ 'intval' => [
++ 'type' => '03',
++ 'charset' => '3f00',
++ 'length' => '0b000000',
++ 'flags' => '0110',
++ 'decimal' => '00',
++ 'query_data_packet_length' => '080000',
++ 'query_data_value' => '023134',
++ 'stmt_data_packet_length' => '0b0000',
++ 'stmt_data_value' => '0e000000'
++ ],
++ 'fltval' => [
++ 'type' => '04',
++ 'charset' => '3f00',
++ 'length' => '0c000000',
++ 'flags' => '0110',
++ 'decimal' => '1f',
++ 'query_data_packet_length' => '090000',
++ 'query_data_value' => '03322e33',
++ 'stmt_data_packet_length' => '0b0000',
++ 'stmt_data_value' => '33331340',
++ ],
++ 'dblval' => [
++ 'type' => '05',
++ 'charset' => '3f00',
++ 'length' => '16000000',
++ 'flags' => '0110',
++ 'decimal' => '1f',
++ 'query_data_packet_length' => '090000',
++ 'query_data_value' => '03312e32',
++ 'stmt_data_packet_length' => '0f0000',
++ 'stmt_data_value' => '333333333333f33f'
++ ],
++ 'datval' => [
++ 'type' => '0a',
++ 'charset' => '3f00',
++ 'length' => '0a000000',
++ 'flags' => '8110',
++ 'decimal' => '00',
++ 'query_data_packet_length' => '100000',
++ 'query_data_value' => '0a323031342d31322d3135',
++ 'stmt_data_packet_length' => '0c0000',
++ 'stmt_data_value' => '04de070c0f'
++ ],
++ 'timval' => [
++ 'type' => '0b',
++ 'charset' => '3f00',
++ 'length' => '0a000000',
++ 'flags' => '8110',
++ 'decimal' => '00',
++ 'query_data_packet_length' => '0e0000',
++ 'query_data_value' => '0831333a30303a3032',
++ 'stmt_data_packet_length' => '100000',
++ 'stmt_data_value' => '080000000000150801'
++ ],
++ 'dtival' => [
++ 'type' => '0c',
++ 'charset' => '3f00',
++ 'length' => '13000000',
++ 'flags' => '8110',
++ 'decimal' => '00',
++ 'query_data_packet_length' => '190000',
++ 'query_data_value' => '13323031342d31322d31362031333a30303a3031',
++ 'stmt_data_packet_length' => '0f0000',
++ 'stmt_data_value' => '07de070c100d0001'
++ ],
++ 'bitval' => [
++ 'type' => '10',
++ 'charset' => '3f00',
++ 'length' => '40000000',
++ 'flags' => '2110',
++ 'decimal' => '00',
++ 'query_data_packet_length' => '0e0000',
++ 'query_data_value' => '080808080808080808',
++ 'stmt_data_packet_length' => '100000',
++ 'stmt_data_value' => '080808080808080808'
++ ],
++ 'strval' => [
++ 'type' => 'fd',
++ 'charset' => 'e000',
++ 'length' => 'c8000000',
++ 'flags' => '0110',
++ 'decimal' => '00',
++ 'query_data_packet_length' => '0a0000',
++ 'query_data_value' => '0474657374',
++ 'stmt_data_packet_length' => '0c0000',
++ 'stmt_data_value' => '0474657374'
++ ],
++ ];
++}
++
++function my_mysqli_data_field(string $field): array
++{
++ $fields = my_mysqli_data_fields();
++ if (!isset($fields[$field])) {
++ throw new Exception("Unknown field $field");
++ }
++ return $fields[$field];
++}
++
++
++
++class my_mysqli_fake_packet_item
++{
++ public function __construct(public string|null $name, public string $value, public bool $is_hex = true)
++ {
++ }
++}
++
++class my_mysqli_fake_packet
++{
++ private array $data = array();
++
++ public function __get(string $name)
++ {
++ foreach ($this->data as $item) {
++ if ($item->name === $name) {
++ return $item->value;
++ }
++ }
++ return null;
++ }
++
++ public function __set(string $name, string|my_mysqli_fake_packet_item $value)
++ {
++ if ($value instanceof my_mysqli_fake_packet_item) {
++ if ($value->name === null) {
++ $value->name = $name;
++ }
++ } else {
++ $value = new my_mysqli_fake_packet_item($name, $value, true);
++ }
++
++ for ($i = 0; $i < count($this->data); $i++) {
++ if ($this->data[$i]->name === $name) {
++ $this->data[$i] = $value;
++ return;
++ }
++ }
++
++ $this->data[] = $value;
++ }
++
++ public function to_bytes(): string
++ {
++ $bytes = '';
++ foreach ($this->data as $item) {
++ $bytes .= $item->is_hex ? hex2bin($item->value) : $item->value;
++ }
++ return $bytes;
++ }
++}
++
++class my_mysqli_fake_packet_generator
++{
++ public static function create_packet_item(int|string $value, bool $is_hex = false, string $format = 'v'): my_mysqli_fake_packet_item
++ {
++ if (is_string($value)) {
++ $packed_value = $value;
++ } else {
++ $packed_value = pack($format, $value);
++ }
++ return new my_mysqli_fake_packet_item(null, $packed_value, $is_hex);
++ }
++
++ public function server_ok(): my_mysqli_fake_packet
++ {
++ $packet = new my_mysqli_fake_packet();
++ $packet->packet_length = "070000";
++ $packet->packet_number = "02";
++ $packet->header = "00"; // OK
++ $packet->affected_rows = "00";
++ $packet->last_insert_id = "00";
++ $packet->server_status = "0200";
++ $packet->warning_count = "0000";
++ return $packet;
++ }
++
++ public function server_greetings(): my_mysqli_fake_packet
++ {
++ $packet = new my_mysqli_fake_packet();
++ $packet->packet_length = "580000";
++ $packet->packet_number = "00";
++ $packet->proto_version = "0a";
++ $packet->version = self::create_packet_item('5.5.5-10.5.18-MariaDB' . chr(0));
++ $packet->thread_id = "03000000";
++ $packet->salt = "473e3f6047257c67";
++ $packet->filler = "00";
++ $packet->server_capabilities = self::create_packet_item(0b1111011111111110);
++ $packet->server_character_set = "08";
++ $packet->server_status = self::create_packet_item(0b000000000000010);
++ $packet->extended_server_capabilities = self::create_packet_item(0b1000000111111111);
++ $packet->auth_plugin = "15";
++ $packet->unused = "000000000000";
++ $packet->mariadb_extended_server_capabilities = self::create_packet_item(0b1111, false, 'V');
++ $packet->mariadb_extended_server_capabilities_salt = "6c6b55463f49335f686c643100";
++ $packet->mariadb_extended_server_capabilities_auth_plugin = self::create_packet_item('mysql_native_password');
++
++ return $packet;
++ }
++
++ public function server_tabular_query_response(): array
++ {
++ $qr1 = new my_mysqli_fake_packet();
++ $qr1->packet_length = "010000";
++ $qr1->packet_number = "01";
++ $qr1->field_count = "01";
++
++ $qr2 = new my_mysqli_fake_packet();
++ $qr2->packet_length = "190000";
++ $qr2->packet_number = "02";
++ $qr2->catalog_length_plus_name = "0164";
++ $qr2->db_length_plus_name = "0164";
++ $qr2->table_length_plus_name = "0164";
++ $qr2->original_t = "0164";
++ $qr2->name_length_plus_name = "0164";
++ $qr2->original_n = "0164";
++ $qr2->canary = "0c";
++ $qr2->charset = "3f00";
++ $qr2->length = "0b000000";
++ $qr2->type = "03";
++ $qr2->flags = "0350";
++ $qr2->decimals = "000000";
++
++ $qr3 = new my_mysqli_fake_packet();
++ $qr3->full = "05000003fe00002200";
++
++ $qr4 = new my_mysqli_fake_packet();
++ $qr4->full = "0400000401350174";
++
++ $qr5 = new my_mysqli_fake_packet();
++ $qr5->full = "05000005fe00002200";
++
++ return [$qr1, $qr2, $qr3, $qr4, $qr5];
++ }
++
++ public function server_upsert_query_response(): array
++ {
++ $qr1 = new my_mysqli_fake_packet();
++ $qr1->packet_length = "010000";
++ $qr1->packet_number = "01";
++ $qr1->field_count = "00"; // UPSERT
++ $qr1->affected_rows = "00";
++ $qr1->affected_rows = "00";
++ $qr1->last_insert_id = "00";
++ $qr1->server_status = "0000";
++ $qr1->warning_count = "0000";
++ $qr1->len = "01";
++ $qr1->filename = "65";
++ $qr1->packet_length = sprintf("%02x0000", strlen($qr1->to_bytes())-4);
++
++ return [$qr1];
++ }
++
++ public function server_stmt_prepare_response_start($num_field): my_mysqli_fake_packet
++ {
++ $pr1 = new my_mysqli_fake_packet();
++ $pr1->packet_length = "0c0000";
++ $pr1->packet_number = "01";
++ $pr1->response_code = '00'; // OK
++ $pr1->statement_id = '01000000';
++ $pr1->num_fields = $num_field;
++ $pr1->num_params = '0000';
++ $pr1->filler = '00';
++ $pr1->warnings = '0000';
++
++ return $pr1;
++ }
++
++ public function server_stmt_prepare_response_end($packer_number): my_mysqli_fake_packet
++ {
++ $pr3 = new my_mysqli_fake_packet();
++ $pr3->packet_length = "050000";
++ $pr3->packet_number = $packer_number;
++ $pr3->packet_type = 'fe'; // EOF
++ $pr3->warnings = '0000';
++ $pr3->server_status = '0200';
++
++ return $pr3;
++ }
++
++ public function server_stmt_prepare_items_response(): array
++ {
++ $pr1 = $this->server_stmt_prepare_response_start('0100');
++
++ $pr2 = new my_mysqli_fake_packet();
++ $pr2->packet_length = "300000";
++ $pr2->packet_number = "02";
++ $pr2->catalogue_len = '03';
++ $pr2->catalogue = '646566'; // def
++ $pr2->db_len = '08';
++ $pr2->db = '7068705f74657374'; // php_test
++ $pr2->table_len = '05';
++ $pr2->table = '6974656d73'; // items
++ $pr2->orig_table_len = '05';
++ $pr2->orig_table = '6974656d73'; // items
++ $pr2->name_len = '04';
++ $pr2->name = '6974656d';
++ $pr2->orig_name_len = '04';
++ $pr2->orig_name = '6974656d';
++ $pr2->something = '0c';
++ $pr2->charset = 'e000';
++ $pr2->length = 'c8000000';
++ $pr2->field_type = 'fd'; // FIELD_TYPE_VAR_STRING
++ $pr2->flags = '0110';
++ $pr2->decimal = '00';
++ $pr2->padding = '0000';
++
++ $pr3 = $this->server_stmt_prepare_response_end('03');
++
++ return [$pr1, $pr2, $pr3];
++ }
++
++ public function server_stmt_prepare_data_response_field($packet_number, $field_name): my_mysqli_fake_packet
++ {
++ if (strlen($field_name) != 6) {
++ throw new Exception("Invalid field length - only 6 is allowed");
++ }
++
++ $field = my_mysqli_data_field($field_name);
++
++ $pr = new my_mysqli_fake_packet();
++ $pr->packet_length = "320000";
++ $pr->packet_number = $packet_number;
++ $pr->catalogue_len = '03';
++ $pr->catalogue = bin2hex('def');
++ $pr->db_len = '08';
++ $pr->db = bin2hex('php_test');
++ $pr->table_len = '04';
++ $pr->table = bin2hex('data');
++ $pr->orig_table_len = '04';
++ $pr->orig_table = bin2hex('data');
++ $pr->name_len = '06';
++ $pr->name = bin2hex($field_name);
++ $pr->orig_name_len = '06';
++ $pr->orig_name = bin2hex($field_name);
++ $pr->something = '0c';
++ $pr->charset = $field['charset'];
++ $pr->length = $field['length'];
++ $pr->field_type = $field['type'];
++ $pr->flags = $field['flags'];
++ $pr->decimal = $field['decimal'];
++ $pr->padding = '0000';
++
++ return $pr;
++ }
++
++ public function server_stmt_prepare_data_response(string $field_name): array
++ {
++ $pr1 = $this->server_stmt_prepare_response_start('0200');
++
++ $pr2 = $this->server_stmt_prepare_data_response_field('02', 'strval');
++ $pr3 = $this->server_stmt_prepare_data_response_field('03', $field_name);
++
++ $pr4 = $this->server_stmt_prepare_response_end('04');
++
++ return [$pr1, $pr2, $pr3, $pr4];
++ }
++
++ public function server_stmt_execute_items_response(): array
++ {
++ $pr1 = new my_mysqli_fake_packet();
++ $pr1->packet_length = "010000";
++ $pr1->packet_number = "01";
++ $pr1->num_fields = '01';
++
++ $pr2 = new my_mysqli_fake_packet();
++ $pr2->packet_length = "300000";
++ $pr2->packet_number = "02";
++ $pr2->catalogue_len = '03';
++ $pr2->catalogue = '646566'; // def
++ $pr2->db_len = '08';
++ $pr2->db = '7068705f74657374'; // php_test
++ $pr2->table_len = '05';
++ $pr2->table = '6974656d73'; // items
++ $pr2->orig_table_len = '05';
++ $pr2->orig_table = '6974656d73'; // items
++ $pr2->name_len = '04';
++ $pr2->name = '6974656d';
++ $pr2->orig_name_len = '04';
++ $pr2->orig_name = '6974656d';
++ $pr2->something = '0c';
++ $pr2->charset = 'e000';
++ $pr2->length = 'c8000000';
++ $pr2->field_type = 'fd'; // FIELD_TYPE_VAR_STRING
++ $pr2->flags = '0110';
++ $pr2->decimal = '00';
++ $pr2->padding = '0000';
++
++ $pr3 = new my_mysqli_fake_packet();
++ $pr3->packet_length = "050000";
++ $pr3->packet_number = "03";
++ $pr3->packet_type = 'fe'; // EOF
++ $pr3->warnings = '0000';
++ $pr3->server_status = '2200';
++
++ $pr4 = new my_mysqli_fake_packet();
++ $pr4->packet_length = "070000";
++ $pr4->packet_number = "04";
++ $pr4->packet_type = '00'; // OK
++ $pr4->affected_rows = '00';
++ $pr4->row_data_len = '04';
++ $pr4->row_data = '74657374'; // item
++
++ $pr5 = new my_mysqli_fake_packet();
++ $pr5->full = '05000005fe00002200';
++
++ return [$pr1, $pr2, $pr3, $pr4, $pr5];
++ }
++
++ private function server_execute_data_response_start(string $field_name): array
++ {
++ $pr1 = new my_mysqli_fake_packet();
++ $pr1->packet_length = "010000";
++ $pr1->packet_number = "01";
++ $pr1->num_fields = '02';
++
++ $pr2 = new my_mysqli_fake_packet();
++ $pr2->packet_length = "320000";
++ $pr2->packet_number = "02";
++ $pr2->catalogue_len = '03';
++ $pr2->catalogue = '646566'; // def
++ $pr2->db_len = '08';
++ $pr2->db = '7068705f74657374'; // php_test
++ $pr2->table_len = '04';
++ $pr2->table = bin2hex('data');
++ $pr2->orig_table_len = '04';
++ $pr2->orig_table = bin2hex('data');
++ $pr2->name_len = '06';
++ $pr2->name = bin2hex('strval');
++ $pr2->orig_name_len = '06';
++ $pr2->orig_name = bin2hex('strval');
++ $pr2->something = '0c';
++ $pr2->charset = 'e000';
++ $pr2->length = 'c8000000';
++ $pr2->field_type = 'fd'; // FIELD_TYPE_VAR_STRING
++ $pr2->flags = '0110';
++ $pr2->decimal = '00';
++ $pr2->padding = '0000';
++
++ $field = my_mysqli_data_field($field_name);
++
++ $pr3 = new my_mysqli_fake_packet();
++ $pr3->packet_length = "320000";
++ $pr3->packet_number = "03";
++ $pr3->catalogue_len = '03';
++ $pr3->catalogue = '646566'; // def
++ $pr3->db_len = '08';
++ $pr3->db = '7068705f74657374'; // php_test
++ $pr3->table_len = '04';
++ $pr3->table = bin2hex('data');
++ $pr3->orig_table_len = '04';
++ $pr3->orig_table = bin2hex('data');
++ $pr3->name_len = '06';
++ $pr3->name = bin2hex($field_name);
++ $pr3->orig_name_len = '06';
++ $pr3->orig_name = bin2hex($field_name);
++ $pr3->something = '0c';
++ $pr3->charset = $field['charset'];
++ $pr3->length = $field['length'];
++ $pr3->field_type = $field['type'];
++ $pr3->flags = $field['flags'];
++ $pr3->decimal = $field['decimal'];
++ $pr3->padding = '0000';
++
++ $pr4 = new my_mysqli_fake_packet();
++ $pr4->packet_length = "050000";
++ $pr4->packet_number = "04";
++ $pr4->packet_type = 'fe'; // EOF
++ $pr4->warnings = '0000';
++ $pr4->server_status = '2200';
++
++ return [$field, $pr1, $pr2, $pr3, $pr4];
++ }
++
++ private function server_execute_data_response_end(): my_mysqli_fake_packet
++ {
++ $pr6 = new my_mysqli_fake_packet();
++ $pr6->packet_length = '050000';
++ $pr6->packet_number = "06";
++ $pr6->packet_type = 'fe'; // EOF
++ $pr6->warnings = '0000';
++ $pr6->server_status = '2200';
++
++ return $pr6;
++ }
++
++ public function server_stmt_execute_data_response(string $field_name): array
++ {
++ [$field, $pr1, $pr2, $pr3, $pr4] = $this->server_execute_data_response_start($field_name);
++
++ $pr5 = new my_mysqli_fake_packet();
++ $pr5->packet_length = $field['stmt_data_packet_length'];
++ $pr5->packet_number = "05";
++ $pr5->packet_type = '00'; // OK
++ $pr5->affected_rows = '00';
++ $pr5->row_field1_len = '04';
++ $pr5->row_field1_data = '74657374'; // test
++ $pr5->row_field2 = $field['stmt_data_value'];
++
++ return [$pr1, $pr2, $pr3, $pr4, $pr5, $this->server_execute_data_response_end()];
++ }
++
++ public function server_query_execute_data_response(string $field_name): array
++ {
++ [$field, $pr1, $pr2, $pr3, $pr4] = $this->server_execute_data_response_start($field_name);
++
++ $pr5 = new my_mysqli_fake_packet();
++ $pr5->packet_length = $field['query_data_packet_length'];
++ $pr5->packet_number = "05";
++ $pr5->row_field1_len = '04';
++ $pr5->row_field1_data = '74657374'; // test
++ $pr5->row_field2 = $field['query_data_value'];
++
++ return [$pr1, $pr2, $pr3, $pr4, $pr5, $this->server_execute_data_response_end()];
++ }
++}
++
++class my_mysqli_fake_server_conn
++{
++ private $conn;
++ public $packet_generator;
++
++ public function __construct($socket)
++ {
++ $this->packet_generator = new my_mysqli_fake_packet_generator();
++ $this->conn = stream_socket_accept($socket);
++ if ($this->conn) {
++ fprintf(STDERR, "[*] Connection established\n");
++ } else {
++ fprintf(STDERR, "[*] Failed to establish connection\n");
++ }
++ }
++
++ public function packets_to_bytes(array $packets): string
++ {
++ return implode('', array_map(fn($s) => $s->to_bytes(), $packets));
++ }
++
++ public function send($payload, $message = null): void
++ {
++ if ($message) {
++ fprintf(STDERR, "[*] Sending - %s: %s\n", $message, bin2hex($payload));
++ }
++ fwrite($this->conn, $payload);
++ }
++
++ public function read($bytes_len = 1024)
++ {
++ // wait 10ms to fill the buffer
++ usleep(10000);
++ $data = fread($this->conn, $bytes_len);
++ if ($data) {
++ fprintf(STDERR, "[*] Received: %s\n", bin2hex($data));
++ }
++ }
++
++ public function close()
++ {
++ fclose($this->conn);
++ }
++
++ public function send_server_greetings()
++ {
++ $this->send($this->packet_generator->server_greetings()->to_bytes(), "Server Greeting");
++ }
++
++ public function send_server_ok()
++ {
++ $this->send($this->packet_generator->server_ok()->to_bytes(), "Server OK");
++ }
++
++ public function send_server_tabular_query_response(): void
++ {
++ $packets = $this->packet_generator->server_tabular_query_response();
++ $this->send($this->packets_to_bytes($packets), "Tabular response");
++ }
++
++ public function send_server_stmt_prepare_items_response(): void
++ {
++ $packets = $this->packet_generator->server_stmt_prepare_items_response();
++ $this->send($this->packets_to_bytes($packets), "Stmt prepare items");
++ }
++
++
++ public function send_server_stmt_prepare_data_response(string $field_name): void
++ {
++ $packets = $this->packet_generator->server_stmt_prepare_data_response($field_name);
++ $this->send($this->packets_to_bytes($packets), "Stmt prepare data $field_name");
++ }
++
++ public function send_server_stmt_execute_items_response(): void
++ {
++ $packets = $this->packet_generator->server_stmt_execute_items_response();
++ $this->send($this->packets_to_bytes($packets), "Stmt execute items");
++ }
++
++ public function send_server_stmt_execute_data_response(string $field_name): void
++ {
++ $packets = $this->packet_generator->server_stmt_execute_data_response($field_name);
++ $this->send($this->packets_to_bytes($packets), "Stmt execute data $field_name");
++ }
++
++ public function send_server_query_execute_data_response(string $field_name): void
++ {
++ $packets = $this->packet_generator->server_query_execute_data_response($field_name);
++ $this->send($this->packets_to_bytes($packets), "Query execute data $field_name");
++ }
++}
++
++class my_mysqli_fake_server_process
++{
++ public function __construct(private $process, private array $pipes) {}
++
++ public function terminate(bool $wait = false)
++ {
++ if ($wait) {
++ $this->wait();
++ }
++ proc_terminate($this->process);
++ }
++
++ public function wait()
++ {
++ echo fgets($this->pipes[1]);
++ }
++}
++
++function my_mysqli_test_tabular_response_def_over_read(my_mysqli_fake_server_conn $conn): void
++{
++ $rh = $conn->packet_generator->server_tabular_query_response();
++
++ // Length of the packet is modified to include the next added data
++ $rh[1]->packet_length = "1e0000";
++
++ // We add a length field encoded on 4 bytes which evaluates to 65536. If the process crashes because
++ // the heap has been overread, lower this value.
++ $rh[1]->extra_def_size = "fd000001"; # 65536
++
++ // Filler
++ $rh[1]->extra_def_data = "aa";
++
++ $trrh = $conn->packets_to_bytes($rh);
++
++ $conn->send_server_greetings();
++ $conn->read();
++ $conn->send_server_ok();
++ $conn->read();
++ $conn->send($trrh, "Malicious Tabular Response [Extract heap through buffer over-read]");
++ $conn->read(65536);
++}
++
++function my_mysqli_test_upsert_response_filename_over_read(my_mysqli_fake_server_conn $conn): void
++{
++ $rh = $conn->packet_generator->server_upsert_query_response();
++
++ // Set extra length to overread
++ $rh[0]->len = "fa";
++
++ $trrh = $conn->packets_to_bytes($rh);
++
++ $conn->send_server_greetings();
++ $conn->read();
++ $conn->send_server_ok();
++ $conn->read();
++ $conn->send($trrh, "Malicious Tabular Response [Extract heap through buffer over-read]");
++ $conn->read(65536);
++}
++
++function my_mysqli_test_auth_response_message_over_read(my_mysqli_fake_server_conn $conn): void
++{
++ $p = $conn->packet_generator->server_ok();
++ $p->packet_length = "090000";
++ $p->message_len = "fcff";
++
++ $conn->send_server_greetings();
++ $conn->read();
++ $conn->send($p->to_bytes(), "Malicious OK Auth Response [Extract heap through buffer over-read]");
++ $conn->read();
++}
++
++function my_mysqli_test_stmt_response_row_over_read_string(my_mysqli_fake_server_conn $conn): void
++{
++ $rh = $conn->packet_generator->server_stmt_execute_items_response();
++
++ // Set extra length to overread
++ $rh[3]->row_data_len = "fa";
++
++ $conn->send_server_greetings();
++ $conn->read();
++ $conn->send_server_ok();
++ $conn->read();
++ $conn->send_server_stmt_prepare_items_response();
++ $conn->read();
++ $conn->send($conn->packets_to_bytes($rh), "Malicious Stmt Response for items [Extract heap through buffer over-read]");
++ $conn->read(65536);
++}
++
++function my_mysqli_test_stmt_response_row_over_read_two_fields(
++ my_mysqli_fake_server_conn $conn,
++ string $field_name,
++ string $row_field1_len = '06'
++): void {
++ $rh = $conn->packet_generator->server_stmt_execute_data_response($field_name);
++
++ // Set extra length to overread by two bytes
++ $rh[4]->row_field1_len = $row_field1_len;
++
++ $conn->send_server_greetings();
++ $conn->read();
++ $conn->send_server_ok();
++ $conn->read();
++ $conn->send_server_stmt_prepare_data_response($field_name);
++ $conn->read();
++ $conn->send(
++ $conn->packets_to_bytes($rh),
++ "Malicious Stmt Response for data $field_name [Extract heap through buffer over-read]"
++ );
++ $conn->read(65536);
++}
++
++function my_mysqli_test_stmt_response_row_over_read_int(my_mysqli_fake_server_conn $conn): void
++{
++ my_mysqli_test_stmt_response_row_over_read_two_fields($conn, 'intval');
++}
++
++function my_mysqli_test_stmt_response_row_over_read_float(my_mysqli_fake_server_conn $conn): void
++{
++ my_mysqli_test_stmt_response_row_over_read_two_fields($conn, 'fltval');
++}
++
++function my_mysqli_test_stmt_response_row_over_read_double(my_mysqli_fake_server_conn $conn): void
++{
++ my_mysqli_test_stmt_response_row_over_read_two_fields($conn, 'dblval');
++}
++
++function my_mysqli_test_stmt_response_row_over_read_date(my_mysqli_fake_server_conn $conn): void
++{
++ my_mysqli_test_stmt_response_row_over_read_two_fields($conn, 'datval');
++}
++
++function my_mysqli_test_stmt_response_row_over_read_time(my_mysqli_fake_server_conn $conn): void
++{
++ my_mysqli_test_stmt_response_row_over_read_two_fields($conn, 'timval', '0c');
++}
++
++function my_mysqli_test_stmt_response_row_over_read_datetime(my_mysqli_fake_server_conn $conn): void
++{
++ my_mysqli_test_stmt_response_row_over_read_two_fields($conn, 'dtival');
++}
++
++function my_mysqli_test_stmt_response_row_no_space(my_mysqli_fake_server_conn $conn): void
++{
++ my_mysqli_test_stmt_response_row_over_read_two_fields($conn, 'strval', '09');
++}
++
++function my_mysqli_test_stmt_response_row_over_read_bit(my_mysqli_fake_server_conn $conn): void
++{
++ my_mysqli_test_stmt_response_row_over_read_two_fields($conn, 'bitval');
++}
++
++function my_mysqli_test_stmt_response_row_read_two_fields(my_mysqli_fake_server_conn $conn): void
++{
++ $conn->send_server_greetings();
++ $conn->read();
++ $conn->send_server_ok();
++ $conn->read();
++ $field_names = array_keys(my_mysqli_data_fields());
++ foreach ($field_names as $field_name) {
++ $conn->send_server_stmt_prepare_data_response($field_name);
++ $conn->read(65536);
++ $conn->send_server_stmt_execute_data_response($field_name);
++ $conn->read(65536);
++ }
++}
++
++function my_mysqli_test_query_response_row_length_overflow(my_mysqli_fake_server_conn $conn): void
++{
++ $rh = $conn->packet_generator->server_query_execute_data_response('strval');
++
++ // Set extra length to overread by two bytes
++ $rh[4]->row_field2 = 'fefefefefe';
++
++ $conn->send_server_greetings();
++ $conn->read();
++ $conn->send_server_ok();
++ $conn->read();
++ $conn->send($conn->packets_to_bytes($rh), "Malicious Query Response for data strval field [length overflow]");
++ $conn->read(65536);
++}
++
++function my_mysqli_test_query_response_row_read_two_fields(my_mysqli_fake_server_conn $conn): void
++{
++ $conn->send_server_greetings();
++ $conn->read();
++ $conn->send_server_ok();
++ $conn->read();
++ $field_names = array_keys(my_mysqli_data_fields());
++ foreach ($field_names as $field_name) {
++ $conn->send_server_query_execute_data_response($field_name);
++ $conn->read();
++ }
++}
++
++function run_fake_server(string $test_function, $port = 33305): void
++{
++ $address = '127.0.0.1';
++
++ $socket = @stream_socket_server("tcp://$address:$port", $errno, $errstr);
++ if (!$socket) {
++ die("Failed to create socket: $errstr ($errno)\n");
++ }
++ echo "[*] Server started\n";
++
++ try {
++ $conn = new my_mysqli_fake_server_conn($socket);
++ $test_function_name = 'my_mysqli_test_' . $test_function;
++ call_user_func($test_function_name, $conn);
++ $conn->close();
++ } catch (Exception $e) {
++ fprintf(STDERR, "[!] Exception: " . $e->getMessage() . "\n");
++ }
++
++ fclose($socket);
++
++ echo "[*] Server finished\n";
++}
++
++
++function run_fake_server_in_background($test_function, $port = 33305): my_mysqli_fake_server_process
++{
++ $command = [PHP_BINARY, '-n', __FILE__, 'mysqli_fake_server', $test_function, $port];
++
++ $descriptorspec = array(
++ 0 => array("pipe", "r"),
++ 1 => array("pipe", "w"),
++ 2 => STDERR,
++ );
++
++ $process = proc_open($command, $descriptorspec, $pipes);
++
++ if (is_resource($process)) {
++ return new my_mysqli_fake_server_process($process, $pipes);
++ } else {
++ throw new Exception("Failed to start server process");
++ }
++}
++
++if (isset($argv) && $argc > 2 && $argv[1] == 'mysqli_fake_server') {
++ run_fake_server($argv[2], $argv[3] ?? '33305');
++}
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt
+new file mode 100644
+index 00000000000..db54a6c0177
+--- /dev/null
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt
+@@ -0,0 +1,38 @@
++--TEST--
++GHSA-h35g-vwh6-m678 (mysqlnd leaks partial content of the heap - auth message buffer over-read)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++$port = 50001;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('auth_response_message_over_read', $port);
++$process->wait();
++
++try {
++ $conn = new mysqli( $servername, $username, $password, "", $port );
++ $info = mysqli_info($conn);
++ var_dump($info);
++} catch (Exception $e) {
++ echo $e->getMessage() . PHP_EOL;
++}
++
++$process->terminate();
++
++print "done!";
++?>
++--EXPECTF--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Malicious OK Auth Response [Extract heap through buffer over-read]: 0900000200000002000000fcff
++
++Warning: mysqli::__construct(): OK packet message length is past the packet size in %s on line %d
++Unknown error while trying to connect via tcp://127.0.0.1:50001
++done!
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-def.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-def.phpt
+new file mode 100644
+index 00000000000..77f2232eca6
+--- /dev/null
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-def.phpt
+@@ -0,0 +1,47 @@
++--TEST--
++GHSA-h35g-vwh6-m678 (mysqlnd leaks partial content of the heap - tabular default)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++
++$port = 33305;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('tabular_response_def_over_read', $port);
++$process->wait();
++
++$conn = new mysqli($servername, $username, $password, "", $port);
++
++echo "[*] Running query on the fake server...\n";
++
++$result = $conn->query("SELECT * from users");
++
++if ($result) {
++ $all_fields = $result->fetch_fields();
++ var_dump($result->fetch_all(MYSQLI_ASSOC));
++ var_dump(get_object_vars($all_fields[0])["def"]);
++}
++
++$conn->close();
++
++$process->terminate();
++
++print "done!";
++?>
++--EXPECTF--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Server OK: 0700000200000002000000
++[*] Running query on the fake server...
++[*] Received: 140000000353454c454354202a2066726f6d207573657273
++[*] Sending - Malicious Tabular Response [Extract heap through buffer over-read]: 01000001011e0000020164016401640164016401640c3f000b000000030350000000fd000001aa05000003fe00002200040000040135017405000005fe00002200
++
++Warning: mysqli::query(): Protocol error. Server sent default for unsupported field list (mysqlnd_wireprotocol.c:%d) in %s on line %d
++done!
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-filename.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-filename.phpt
+new file mode 100644
+index 00000000000..0b4db8ccece
+--- /dev/null
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-filename.phpt
+@@ -0,0 +1,43 @@
++--TEST--
++GHSA-h35g-vwh6-m678 (mysqlnd leaks partial content of the heap - upsert filename buffer over-read)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++$port = 33305;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('upsert_response_filename_over_read', $port);
++$process->wait();
++
++$conn = new mysqli($servername, $username, $password, "", $port);
++echo "[*] Running query on the fake server...\n";
++
++$result = $conn->query("SELECT * from users");
++$info = mysqli_info($conn);
++
++var_dump($info);
++
++$process->terminate();
++
++print "done!";
++?>
++--EXPECTF--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Server OK: 0700000200000002000000
++[*] Running query on the fake server...
++[*] Received: 140000000353454c454354202a2066726f6d207573657273
++[*] Sending - Malicious Tabular Response [Extract heap through buffer over-read]: 0900000100000000000000fa65
++
++Warning: mysqli::query(): RSET_HEADER packet additional data length is past 249 bytes the packet size in %s on line %d
++
++Warning: mysqli::query(): Error reading result set's header in %s on line %d
++NULL
++done!
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-query-len-overflow.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-query-len-overflow.phpt
+new file mode 100644
+index 00000000000..f141a79bdaa
+--- /dev/null
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-query-len-overflow.phpt
+@@ -0,0 +1,48 @@
++--TEST--
++GHSA-h35g-vwh6-m678 (mysqlnd leaks partial content of the heap - stmt row no space for the field)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++$port = 33305;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('query_response_row_length_overflow', $port);
++$process->wait();
++
++$conn = new mysqli($servername, $username, $password, "", $port);
++
++echo "[*] Query the fake server...\n";
++$sql = "SELECT strval, strval FROM data";
++
++$result = $conn->query($sql);
++
++if ($result->num_rows > 0) {
++ while ($row = $result->fetch_assoc()) {
++ var_dump($row['strval']);
++ }
++}
++$conn->close();
++
++$process->terminate(true);
++
++print "done!";
++?>
++--EXPECTF--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Server OK: 0700000200000002000000
++[*] Query the fake server...
++[*] Received: 200000000353454c4543542073747276616c2c2073747276616c2046524f4d2064617461
++[*] Sending - Malicious Query Response for data strval field [length overflow]: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd011000000005000004fe000022000a0000050474657374fefefefefe05000006fe00002200
++
++Warning: mysqli_result::fetch_assoc(): Malformed server packet. Field length pointing after end of packet in %s on line %d
++[*] Received: 0100000001
++[*] Server finished
++done!
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-bit.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-bit.phpt
+new file mode 100644
+index 00000000000..e43518217eb
+--- /dev/null
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-bit.phpt
+@@ -0,0 +1,53 @@
++--TEST--
++GHSA-h35g-vwh6-m678 (mysqlnd leaks partial content of the heap - stmt row bit buffer over-read)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++$port = 33305;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('stmt_response_row_over_read_bit', $port);
++$process->wait();
++
++$conn = new mysqli($servername, $username, $password, "", $port);
++
++echo "[*] Preparing statement on the fake server...\n";
++$stmt = $conn->prepare("SELECT bitval, timval FROM data");
++
++$stmt->execute();
++$result = $stmt->get_result();
++
++// Fetch and display the results
++if ($result->num_rows > 0) {
++ while ($row = $result->fetch_assoc()) {
++ var_dump($row["bitval"]);
++ }
++}
++$stmt->close();
++$conn->close();
++
++$process->terminate(true);
++
++print "done!";
++?>
++--EXPECTF--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Server OK: 0700000200000002000000
++[*] Preparing statement on the fake server...
++[*] Received: 200000001653454c4543542062697476616c2c2074696d76616c2046524f4d2064617461
++[*] Sending - Stmt prepare data bitval: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610662697476616c0662697476616c0c3f004000000010211000000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Malicious Stmt Response for data bitval [Extract heap through buffer over-read]: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610662697476616c0662697476616c0c3f004000000010211000000005000004fe00002200100000050000067465737408080808080808080805000006fe00002200
++
++Warning: mysqli_result::fetch_assoc(): Malformed server packet. Field length pointing after the end of packet in %s on line %d
++[*] Received: 0500000019010000000100000001
++[*] Server finished
++done!
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-date.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-date.phpt
+new file mode 100644
+index 00000000000..76158e940d0
+--- /dev/null
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-date.phpt
+@@ -0,0 +1,53 @@
++--TEST--
++GHSA-h35g-vwh6-m678 (mysqlnd leaks partial content of the heap - stmt row date buffer over-read)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++$port = 33305;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('stmt_response_row_over_read_date', $port);
++$process->wait();
++
++$conn = new mysqli($servername, $username, $password, "", $port);
++
++echo "[*] Preparing statement on the fake server...\n";
++$stmt = $conn->prepare("SELECT strval, datval FROM data");
++
++$stmt->execute();
++$result = $stmt->get_result();
++
++// Fetch and display the results
++if ($result->num_rows > 0) {
++ while ($row = $result->fetch_assoc()) {
++ var_dump($row["datval"]);
++ }
++}
++$stmt->close();
++$conn->close();
++
++$process->terminate(true);
++
++print "done!";
++?>
++--EXPECTF--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Server OK: 0700000200000002000000
++[*] Preparing statement on the fake server...
++[*] Received: 200000001653454c4543542073747276616c2c2064617476616c2046524f4d2064617461
++[*] Sending - Stmt prepare data datval: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664617476616c0664617476616c0c3f000a0000000a811000000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Malicious Stmt Response for data datval [Extract heap through buffer over-read]: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664617476616c0664617476616c0c3f000a0000000a811000000005000004fe000022000c0000050000067465737404de070c0f05000006fe00002200
++
++Warning: mysqli_result::fetch_assoc(): Malformed server packet. Field length pointing after the end of packet in %s on line %d
++[*] Received: 0500000019010000000100000001
++[*] Server finished
++done!
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-datetime.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-datetime.phpt
+new file mode 100644
+index 00000000000..f53d5b83bd4
+--- /dev/null
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-datetime.phpt
+@@ -0,0 +1,53 @@
++--TEST--
++GHSA-h35g-vwh6-m678 (mysqlnd leaks partial content of the heap - stmt row datetime buffer over-read)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++$port = 33305;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('stmt_response_row_over_read_datetime', $port);
++$process->wait();
++
++$conn = new mysqli($servername, $username, $password, "", $port);
++
++echo "[*] Preparing statement on the fake server...\n";
++$stmt = $conn->prepare("SELECT strval, dtival FROM data");
++
++$stmt->execute();
++$result = $stmt->get_result();
++
++// Fetch and display the results
++if ($result->num_rows > 0) {
++ while ($row = $result->fetch_assoc()) {
++ var_dump($row["dtival"]);
++ }
++}
++$stmt->close();
++$conn->close();
++
++$process->terminate(true);
++
++print "done!";
++?>
++--EXPECTF--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Server OK: 0700000200000002000000
++[*] Preparing statement on the fake server...
++[*] Received: 200000001653454c4543542073747276616c2c2064746976616c2046524f4d2064617461
++[*] Sending - Stmt prepare data dtival: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664746976616c0664746976616c0c3f00130000000c811000000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Malicious Stmt Response for data dtival [Extract heap through buffer over-read]: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664746976616c0664746976616c0c3f00130000000c811000000005000004fe000022000f0000050000067465737407de070c100d000105000006fe00002200
++
++Warning: mysqli_result::fetch_assoc(): Malformed server packet. Field length pointing after the end of packet in %s on line %d
++[*] Received: 0500000019010000000100000001
++[*] Server finished
++done!
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-double.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-double.phpt
+new file mode 100644
+index 00000000000..03c9b045d73
+--- /dev/null
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-double.phpt
+@@ -0,0 +1,53 @@
++--TEST--
++GHSA-h35g-vwh6-m678 (mysqlnd leaks partial content of the heap - stmt row double buffer over-read)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++$port = 33305;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('stmt_response_row_over_read_double', $port);
++$process->wait();
++
++$conn = new mysqli($servername, $username, $password, "", $port);
++
++echo "[*] Preparing statement on the fake server...\n";
++$stmt = $conn->prepare("SELECT strval, dblval FROM data");
++
++$stmt->execute();
++$result = $stmt->get_result();
++
++// Fetch and display the results
++if ($result->num_rows > 0) {
++ while ($row = $result->fetch_assoc()) {
++ var_dump($row["dblval"]);
++ }
++}
++$stmt->close();
++$conn->close();
++
++$process->terminate(true);
++
++print "done!";
++?>
++--EXPECTF--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Server OK: 0700000200000002000000
++[*] Preparing statement on the fake server...
++[*] Received: 200000001653454c4543542073747276616c2c2064626c76616c2046524f4d2064617461
++[*] Sending - Stmt prepare data dblval: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664626c76616c0664626c76616c0c3f00160000000501101f000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Malicious Stmt Response for data dblval [Extract heap through buffer over-read]: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664626c76616c0664626c76616c0c3f00160000000501101f000005000004fe000022000f00000500000674657374333333333333f33f05000006fe00002200
++
++Warning: mysqli_result::fetch_assoc(): Malformed server packet. Field length pointing after the end of packet in %s on line %d
++[*] Received: 0500000019010000000100000001
++[*] Server finished
++done!
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-float.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-float.phpt
+new file mode 100644
+index 00000000000..b1ec9aa51ec
+--- /dev/null
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-float.phpt
+@@ -0,0 +1,53 @@
++--TEST--
++GHSA-h35g-vwh6-m678 (mysqlnd leaks partial content of the heap - stmt row int buffer over-read)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++$port = 33305;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('stmt_response_row_over_read_float', $port);
++$process->wait();
++
++$conn = new mysqli($servername, $username, $password, "", $port);
++
++echo "[*] Preparing statement on the fake server...\n";
++$stmt = $conn->prepare("SELECT strval, fltval FROM data");
++
++$stmt->execute();
++$result = $stmt->get_result();
++
++// Fetch and display the results
++if ($result->num_rows > 0) {
++ while ($row = $result->fetch_assoc()) {
++ var_dump($row["fltval"]);
++ }
++}
++$stmt->close();
++$conn->close();
++
++$process->terminate(true);
++
++print "done!";
++?>
++--EXPECTF--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Server OK: 0700000200000002000000
++[*] Preparing statement on the fake server...
++[*] Received: 200000001653454c4543542073747276616c2c20666c7476616c2046524f4d2064617461
++[*] Sending - Stmt prepare data fltval: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f746573740464617461046461746106666c7476616c06666c7476616c0c3f000c0000000401101f000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Malicious Stmt Response for data fltval [Extract heap through buffer over-read]: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f746573740464617461046461746106666c7476616c06666c7476616c0c3f000c0000000401101f000005000004fe000022000b000005000006746573743333134005000006fe00002200
++
++Warning: mysqli_result::fetch_assoc(): Malformed server packet. Field length pointing after the end of packet in %s on line %d
++[*] Received: 0500000019010000000100000001
++[*] Server finished
++done!
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-int.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-int.phpt
+new file mode 100644
+index 00000000000..426d9ea7b3f
+--- /dev/null
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-int.phpt
+@@ -0,0 +1,53 @@
++--TEST--
++GHSA-h35g-vwh6-m678 (mysqlnd leaks partial content of the heap - stmt row int buffer over-read)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++$port = 33305;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('stmt_response_row_over_read_int', $port);
++$process->wait();
++
++$conn = new mysqli($servername, $username, $password, "", $port);
++
++echo "[*] Preparing statement on the fake server...\n";
++$stmt = $conn->prepare("SELECT strval, intval FROM data");
++
++$stmt->execute();
++$result = $stmt->get_result();
++
++// Fetch and display the results
++if ($result->num_rows > 0) {
++ while ($row = $result->fetch_assoc()) {
++ var_dump($row["intval"]);
++ }
++}
++$stmt->close();
++$conn->close();
++
++$process->terminate(true);
++
++print "done!";
++?>
++--EXPECTF--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Server OK: 0700000200000002000000
++[*] Preparing statement on the fake server...
++[*] Received: 200000001653454c4543542073747276616c2c20696e7476616c2046524f4d2064617461
++[*] Sending - Stmt prepare data intval: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f746573740464617461046461746106696e7476616c06696e7476616c0c3f000b00000003011000000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Malicious Stmt Response for data intval [Extract heap through buffer over-read]: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f746573740464617461046461746106696e7476616c06696e7476616c0c3f000b00000003011000000005000004fe000022000b000005000006746573740e00000005000006fe00002200
++
++Warning: mysqli_result::fetch_assoc(): Malformed server packet. Field length pointing after the end of packet in %s on line %d
++[*] Received: 0500000019010000000100000001
++[*] Server finished
++done!
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-no-space.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-no-space.phpt
+new file mode 100644
+index 00000000000..6db6952d42a
+--- /dev/null
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-no-space.phpt
+@@ -0,0 +1,53 @@
++--TEST--
++GHSA-h35g-vwh6-m678 (mysqlnd leaks partial content of the heap - stmt row no space for the field)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++$port = 33305;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('stmt_response_row_no_space', $port);
++$process->wait();
++
++$conn = new mysqli($servername, $username, $password, "", $port);
++
++echo "[*] Preparing statement on the fake server...\n";
++$stmt = $conn->prepare("SELECT strval, strval FROM data");
++
++$stmt->execute();
++$result = $stmt->get_result();
++
++// Fetch and display the results
++if ($result->num_rows > 0) {
++ while ($row = $result->fetch_assoc()) {
++ var_dump($row["strval"]);
++ }
++}
++$stmt->close();
++$conn->close();
++
++$process->terminate(true);
++
++print "done!";
++?>
++--EXPECTF--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Server OK: 0700000200000002000000
++[*] Preparing statement on the fake server...
++[*] Received: 200000001653454c4543542073747276616c2c2073747276616c2046524f4d2064617461
++[*] Sending - Stmt prepare data strval: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd011000000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Malicious Stmt Response for data strval [Extract heap through buffer over-read]: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd011000000005000004fe000022000c00000500000974657374047465737405000006fe00002200
++
++Warning: mysqli_result::fetch_assoc(): Malformed server packet. No packet space left for the field in %s on line %d
++[*] Received: 0500000019010000000100000001
++[*] Server finished
++done!
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-string.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-string.phpt
+new file mode 100644
+index 00000000000..55bad4cc544
+--- /dev/null
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-string.phpt
+@@ -0,0 +1,53 @@
++--TEST--
++GHSA-h35g-vwh6-m678 (mysqlnd leaks partial content of the heap - stmt row string buffer over-read)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++$port = 33305;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('stmt_response_row_over_read_string', $port);
++$process->wait();
++
++$conn = new mysqli($servername, $username, $password, "", $port);
++
++echo "[*] Preparing statement on the fake server...\n";
++$stmt = $conn->prepare("SELECT item FROM items");
++
++$stmt->execute();
++$result = $stmt->get_result();
++
++// Fetch and display the results
++if ($result->num_rows > 0) {
++ while ($row = $result->fetch_assoc()) {
++ var_dump($row["item"]);
++ }
++}
++$stmt->close();
++$conn->close();
++
++$process->terminate(true);
++
++print "done!";
++?>
++--EXPECTF--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Server OK: 0700000200000002000000
++[*] Preparing statement on the fake server...
++[*] Received: 170000001653454c454354206974656d2046524f4d206974656d73
++[*] Sending - Stmt prepare items: 0c0000010001000000010000000000003000000203646566087068705f74657374056974656d73056974656d73046974656d046974656d0ce000c8000000fd011000000005000003fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Malicious Stmt Response for items [Extract heap through buffer over-read]: 01000001013000000203646566087068705f74657374056974656d73056974656d73046974656d046974656d0ce000c8000000fd011000000005000003fe00002200070000040000fa7465737405000005fe00002200
++
++Warning: mysqli_result::fetch_assoc(): Malformed server packet. Field length pointing after the end of packet in %s on line %d
++[*] Received: 0500000019010000000100000001
++[*] Server finished
++done!
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-time.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-time.phpt
+new file mode 100644
+index 00000000000..06918c375f3
+--- /dev/null
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-stmt-row-time.phpt
+@@ -0,0 +1,53 @@
++--TEST--
++GHSA-h35g-vwh6-m678 (mysqlnd leaks partial content of the heap - stmt row time buffer over-read)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++$port = 33305;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('stmt_response_row_over_read_time', $port);
++$process->wait();
++
++$conn = new mysqli($servername, $username, $password, "", $port);
++
++echo "[*] Preparing statement on the fake server...\n";
++$stmt = $conn->prepare("SELECT strval, timval FROM data");
++
++$stmt->execute();
++$result = $stmt->get_result();
++
++// Fetch and display the results
++if ($result->num_rows > 0) {
++ while ($row = $result->fetch_assoc()) {
++ var_dump($row["timval"]);
++ }
++}
++$stmt->close();
++$conn->close();
++
++$process->terminate(true);
++
++print "done!";
++?>
++--EXPECTF--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Server OK: 0700000200000002000000
++[*] Preparing statement on the fake server...
++[*] Received: 200000001653454c4543542073747276616c2c2074696d76616c2046524f4d2064617461
++[*] Sending - Stmt prepare data timval: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610674696d76616c0674696d76616c0c3f000a0000000b811000000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Malicious Stmt Response for data timval [Extract heap through buffer over-read]: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610674696d76616c0674696d76616c0c3f000a0000000b811000000005000004fe000022001000000500000c7465737408000000000015080105000006fe00002200
++
++Warning: mysqli_result::fetch_assoc(): Malformed server packet. Field length pointing after the end of packet in %s on line %d
++[*] Received: 0500000019010000000100000001
++[*] Server finished
++done!
+diff --git a/ext/mysqli/tests/protocol_query_row_fetch_data.phpt b/ext/mysqli/tests/protocol_query_row_fetch_data.phpt
+new file mode 100644
+index 00000000000..524fe5e587c
+--- /dev/null
++++ b/ext/mysqli/tests/protocol_query_row_fetch_data.phpt
+@@ -0,0 +1,74 @@
++--TEST--
++MySQL protocol - statement row data fetch)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++$port = 33305;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('query_response_row_read_two_fields', $port);
++$process->wait();
++
++$conn = new mysqli($servername, $username, $password, "", $port);
++
++function my_query($conn, $field)
++{
++ $sql = "SELECT strval, $field FROM data";
++
++ $result = $conn->query($sql);
++
++ if ($result->num_rows > 0) {
++ while ($row = $result->fetch_assoc()) {
++ var_dump($row[$field]);
++ }
++ }
++}
++
++foreach (my_mysqli_data_fields() as $field_name => $field) {
++ my_query($conn, $field_name);
++}
++
++$conn->close();
++
++$process->terminate(true);
++
++print "done!";
++?>
++--EXPECT--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Server OK: 0700000200000002000000
++[*] Received: 200000000353454c4543542073747276616c2c20696e7476616c2046524f4d2064617461
++[*] Sending - Query execute data intval: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f746573740464617461046461746106696e7476616c06696e7476616c0c3f000b00000003011000000005000004fe0000220008000005047465737402313405000006fe00002200
++string(2) "14"
++[*] Received: 200000000353454c4543542073747276616c2c20666c7476616c2046524f4d2064617461
++[*] Sending - Query execute data fltval: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f746573740464617461046461746106666c7476616c06666c7476616c0c3f000c0000000401101f000005000004fe0000220009000005047465737403322e3305000006fe00002200
++string(3) "2.3"
++[*] Received: 200000000353454c4543542073747276616c2c2064626c76616c2046524f4d2064617461
++[*] Sending - Query execute data dblval: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664626c76616c0664626c76616c0c3f00160000000501101f000005000004fe0000220009000005047465737403312e3205000006fe00002200
++string(3) "1.2"
++[*] Received: 200000000353454c4543542073747276616c2c2064617476616c2046524f4d2064617461
++[*] Sending - Query execute data datval: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664617476616c0664617476616c0c3f000a0000000a811000000005000004fe000022001000000504746573740a323031342d31322d313505000006fe00002200
++string(10) "2014-12-15"
++[*] Received: 200000000353454c4543542073747276616c2c2074696d76616c2046524f4d2064617461
++[*] Sending - Query execute data timval: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610674696d76616c0674696d76616c0c3f000a0000000b811000000005000004fe000022000e00000504746573740831333a30303a303205000006fe00002200
++string(8) "13:00:02"
++[*] Received: 200000000353454c4543542073747276616c2c2064746976616c2046524f4d2064617461
++[*] Sending - Query execute data dtival: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664746976616c0664746976616c0c3f00130000000c811000000005000004fe0000220019000005047465737413323031342d31322d31362031333a30303a303105000006fe00002200
++string(19) "2014-12-16 13:00:01"
++[*] Received: 200000000353454c4543542073747276616c2c2062697476616c2046524f4d2064617461
++[*] Sending - Query execute data bitval: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610662697476616c0662697476616c0c3f004000000010211000000005000004fe000022000e000005047465737408080808080808080805000006fe00002200
++string(18) "578721382704613384"
++[*] Received: 200000000353454c4543542073747276616c2c2073747276616c2046524f4d2064617461
++[*] Sending - Query execute data strval: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd011000000005000004fe000022000a0000050474657374047465737405000006fe00002200
++string(4) "test"
++[*] Received: 0100000001
++[*] Server finished
++done!
+diff --git a/ext/mysqli/tests/protocol_stmt_row_fetch_data.phpt b/ext/mysqli/tests/protocol_stmt_row_fetch_data.phpt
+new file mode 100644
+index 00000000000..d461ec24b8c
+--- /dev/null
++++ b/ext/mysqli/tests/protocol_stmt_row_fetch_data.phpt
+@@ -0,0 +1,91 @@
++--TEST--
++MySQL protocol - statement row data fetch)
++--EXTENSIONS--
++mysqli
++--FILE--
++<?php
++require_once 'fake_server.inc';
++
++$port = 33305;
++$servername = "127.0.0.1";
++$username = "root";
++$password = "";
++
++$process = run_fake_server_in_background('stmt_response_row_read_two_fields', $port);
++$process->wait();
++
++$conn = new mysqli($servername, $username, $password, "", $port);
++
++function my_query($conn, $field)
++{
++ $stmt = $conn->prepare("SELECT strval, $field FROM data");
++
++ $stmt->execute();
++ $result = $stmt->get_result();
++
++ if ($result->num_rows > 0) {
++ while ($row = $result->fetch_assoc()) {
++ var_dump($row[$field]);
++ }
++ }
++}
++
++foreach (my_mysqli_data_fields() as $field_name => $field) {
++ my_query($conn, $field_name);
++}
++
++$conn->close();
++
++$process->terminate(true);
++
++print "done!";
++?>
++--EXPECT--
++[*] Server started
++[*] Connection established
++[*] Sending - Server Greeting: 580000000a352e352e352d31302e352e31382d4d6172696144420003000000473e3f6047257c6700fef7080200ff81150000000000000f0000006c6b55463f49335f686c6431006d7973716c5f6e61746976655f70617373776f7264
++[*] Received: 6900000185a21a00000000c0080000000000000000000000000000000000000000000000726f6f7400006d7973716c5f6e61746976655f70617373776f7264002c0c5f636c69656e745f6e616d65076d7973716c6e640c5f7365727665725f686f7374093132372e302e302e31
++[*] Sending - Server OK: 0700000200000002000000
++[*] Received: 200000001653454c4543542073747276616c2c20696e7476616c2046524f4d2064617461
++[*] Sending - Stmt prepare data intval: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f746573740464617461046461746106696e7476616c06696e7476616c0c3f000b00000003011000000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Stmt execute data intval: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f746573740464617461046461746106696e7476616c06696e7476616c0c3f000b00000003011000000005000004fe000022000b000005000004746573740e00000005000006fe00002200
++int(14)
++[*] Received: 050000001901000000200000001653454c4543542073747276616c2c20666c7476616c2046524f4d2064617461
++[*] Sending - Stmt prepare data fltval: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f746573740464617461046461746106666c7476616c06666c7476616c0c3f000c0000000401101f000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Stmt execute data fltval: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f746573740464617461046461746106666c7476616c06666c7476616c0c3f000c0000000401101f000005000004fe000022000b000005000004746573743333134005000006fe00002200
++float(2.3)
++[*] Received: 050000001901000000200000001653454c4543542073747276616c2c2064626c76616c2046524f4d2064617461
++[*] Sending - Stmt prepare data dblval: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664626c76616c0664626c76616c0c3f00160000000501101f000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Stmt execute data dblval: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664626c76616c0664626c76616c0c3f00160000000501101f000005000004fe000022000f00000500000474657374333333333333f33f05000006fe00002200
++float(1.2)
++[*] Received: 050000001901000000200000001653454c4543542073747276616c2c2064617476616c2046524f4d2064617461
++[*] Sending - Stmt prepare data datval: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664617476616c0664617476616c0c3f000a0000000a811000000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Stmt execute data datval: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664617476616c0664617476616c0c3f000a0000000a811000000005000004fe000022000c0000050000047465737404de070c0f05000006fe00002200
++string(10) "2014-12-15"
++[*] Received: 050000001901000000200000001653454c4543542073747276616c2c2074696d76616c2046524f4d2064617461
++[*] Sending - Stmt prepare data timval: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610674696d76616c0674696d76616c0c3f000a0000000b811000000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Stmt execute data timval: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610674696d76616c0674696d76616c0c3f000a0000000b811000000005000004fe00002200100000050000047465737408000000000015080105000006fe00002200
++string(8) "21:08:01"
++[*] Received: 050000001901000000200000001653454c4543542073747276616c2c2064746976616c2046524f4d2064617461
++[*] Sending - Stmt prepare data dtival: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664746976616c0664746976616c0c3f00130000000c811000000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Stmt execute data dtival: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610664746976616c0664746976616c0c3f00130000000c811000000005000004fe000022000f0000050000047465737407de070c100d000105000006fe00002200
++string(19) "2014-12-16 13:00:01"
++[*] Received: 050000001901000000200000001653454c4543542073747276616c2c2062697476616c2046524f4d2064617461
++[*] Sending - Stmt prepare data bitval: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610662697476616c0662697476616c0c3f004000000010211000000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Stmt execute data bitval: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610662697476616c0662697476616c0c3f004000000010211000000005000004fe00002200100000050000047465737408080808080808080805000006fe00002200
++int(578721382704613384)
++[*] Received: 050000001901000000200000001653454c4543542073747276616c2c2073747276616c2046524f4d2064617461
++[*] Sending - Stmt prepare data strval: 0c0000010001000000020000000000003200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd011000000005000004fe00000200
++[*] Received: 0a00000017010000000001000000
++[*] Sending - Stmt execute data strval: 01000001023200000203646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd01100000003200000303646566087068705f74657374046461746104646174610673747276616c0673747276616c0ce000c8000000fd011000000005000004fe000022000c00000500000474657374047465737405000006fe00002200
++string(4) "test"
++[*] Received: 0500000019010000000100000001
++[*] Server finished
++done!
+diff --git a/ext/mysqlnd/mysqlnd_ps_codec.c b/ext/mysqlnd/mysqlnd_ps_codec.c
+index 12edd9a2849..976143cb471 100644
+--- a/ext/mysqlnd/mysqlnd_ps_codec.c
++++ b/ext/mysqlnd/mysqlnd_ps_codec.c
+@@ -52,6 +52,37 @@ struct st_mysqlnd_perm_bind mysqlnd_ps_fetch_functions[MYSQL_TYPE_LAST + 1];
+ #define MYSQLND_PS_SKIP_RESULT_W_LEN -1
+ #define MYSQLND_PS_SKIP_RESULT_STR -2
+
++static inline void ps_fetch_over_read_error(const zend_uchar ** row)
++{
++ php_error_docref(NULL, E_WARNING, "Malformed server packet. Field length pointing after the end of packet");
++ *row = NULL;
++}
++
++static inline zend_bool ps_fetch_is_packet_over_read_with_variable_length(const unsigned int pack_len,
++ const zend_uchar ** row, const zend_uchar *p, unsigned int length)
++{
++ if (pack_len == 0) {
++ return 0;
++ }
++ size_t length_len = *row - p;
++ if (length_len > pack_len || length > pack_len - length_len) {
++ ps_fetch_over_read_error(row);
++ return 1;
++ }
++ return 0;
++}
++
++static inline zend_bool ps_fetch_is_packet_over_read_with_static_length(const unsigned int pack_len,
++ const zend_uchar ** row, unsigned int length)
++{
++ if (pack_len > 0 && length > pack_len) {
++ ps_fetch_over_read_error(row);
++ return 1;
++ }
++ return 0;
++}
++
++
+ /* {{{ ps_fetch_from_1_to_8_bytes */
+ void
+ ps_fetch_from_1_to_8_bytes(zval * zv, const MYSQLND_FIELD * const field, const unsigned int pack_len,
+@@ -60,6 +91,11 @@ ps_fetch_from_1_to_8_bytes(zval * zv, const MYSQLND_FIELD * const field, const u
+ char tmp[22];
+ size_t tmp_len = 0;
+ zend_bool is_bit = field->type == MYSQL_TYPE_BIT;
++
++ if (UNEXPECTED(ps_fetch_is_packet_over_read_with_static_length(pack_len, row, byte_count))) {
++ return;
++ }
++
+ DBG_ENTER("ps_fetch_from_1_to_8_bytes");
+ DBG_INF_FMT("zv=%p byte_count=%u", zv, byte_count);
+ if (field->flags & UNSIGNED_FLAG) {
+@@ -178,6 +214,11 @@ ps_fetch_float(zval * zv, const MYSQLND_FIELD * const field, const unsigned int
+ float fval;
+ double dval;
+ DBG_ENTER("ps_fetch_float");
++
++ if (UNEXPECTED(ps_fetch_is_packet_over_read_with_static_length(pack_len, row, 4))) {
++ return;
++ }
++
+ float4get(fval, *row);
+ (*row)+= 4;
+ DBG_INF_FMT("value=%f", fval);
+@@ -200,6 +241,11 @@ ps_fetch_double(zval * zv, const MYSQLND_FIELD * const field, const unsigned int
+ {
+ double value;
+ DBG_ENTER("ps_fetch_double");
++
++ if (UNEXPECTED(ps_fetch_is_packet_over_read_with_static_length(pack_len, row, 8))) {
++ return;
++ }
++
+ float8get(value, *row);
+ ZVAL_DOUBLE(zv, value);
+ (*row)+= 8;
+@@ -216,9 +262,14 @@ ps_fetch_time(zval * zv, const MYSQLND_FIELD * const field, const unsigned int p
+ struct st_mysqlnd_time t;
+ zend_ulong length; /* First byte encodes the length*/
+ char * value;
++ const zend_uchar *p = *row;
+ DBG_ENTER("ps_fetch_time");
+
+ if ((length = php_mysqlnd_net_field_length(row))) {
++ if (UNEXPECTED(ps_fetch_is_packet_over_read_with_variable_length(pack_len, row, p, length))) {
++ return;
++ }
++
+ const zend_uchar * to = *row;
+
+ t.time_type = MYSQLND_TIMESTAMP_TIME;
+@@ -273,9 +324,14 @@ ps_fetch_date(zval * zv, const MYSQLND_FIELD * const field, const unsigned int p
+ struct st_mysqlnd_time t = {0};
+ zend_ulong length; /* First byte encodes the length*/
+ char * value;
++ const zend_uchar *p = *row;
+ DBG_ENTER("ps_fetch_date");
+
+ if ((length = php_mysqlnd_net_field_length(row))) {
++ if (UNEXPECTED(ps_fetch_is_packet_over_read_with_variable_length(pack_len, row, p, length))) {
++ return;
++ }
++
+ const zend_uchar * to = *row;
+
+ t.time_type = MYSQLND_TIMESTAMP_DATE;
+@@ -310,9 +366,14 @@ ps_fetch_datetime(zval * zv, const MYSQLND_FIELD * const field, const unsigned i
+ struct st_mysqlnd_time t;
+ zend_ulong length; /* First byte encodes the length*/
+ char * value;
++ const zend_uchar *p = *row;
+ DBG_ENTER("ps_fetch_datetime");
+
+ if ((length = php_mysqlnd_net_field_length(row))) {
++ if (UNEXPECTED(ps_fetch_is_packet_over_read_with_variable_length(pack_len, row, p, length))) {
++ return;
++ }
++
+ const zend_uchar * to = *row;
+
+ t.time_type = MYSQLND_TIMESTAMP_DATETIME;
+@@ -371,7 +432,11 @@ ps_fetch_string(zval * zv, const MYSQLND_FIELD * const field, const unsigned int
+ For now just copy, before we make it possible
+ to write \0 to the row buffer
+ */
++ const zend_uchar *p = *row;
+ const zend_ulong length = php_mysqlnd_net_field_length(row);
++ if (UNEXPECTED(ps_fetch_is_packet_over_read_with_variable_length(pack_len, row, p, length))) {
++ return;
++ }
+ DBG_ENTER("ps_fetch_string");
+ DBG_INF_FMT("len = %lu", length);
+ DBG_INF("copying from the row buffer");
+@@ -387,7 +452,11 @@ ps_fetch_string(zval * zv, const MYSQLND_FIELD * const field, const unsigned int
+ static void
+ ps_fetch_bit(zval * zv, const MYSQLND_FIELD * const field, const unsigned int pack_len, const zend_uchar ** row)
+ {
++ const zend_uchar *p = *row;
+ const zend_ulong length = php_mysqlnd_net_field_length(row);
++ if (UNEXPECTED(ps_fetch_is_packet_over_read_with_variable_length(pack_len, row, p, length))) {
++ return;
++ }
+ ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, length);
+ }
+ /* }}} */
+diff --git a/ext/mysqlnd/mysqlnd_result.c b/ext/mysqlnd/mysqlnd_result.c
+index 4dcaf121fb7..c0f65f854ac 100644
+--- a/ext/mysqlnd/mysqlnd_result.c
++++ b/ext/mysqlnd/mysqlnd_result.c
+@@ -505,7 +505,7 @@ mysqlnd_query_read_result_set_header(MYSQLND_CONN_DATA * conn, MYSQLND_STMT * s)
+ if (FAIL == (ret = result->m.read_result_metadata(result, conn))) {
+ /* For PS, we leave them in Prepared state */
+ if (!stmt && conn->current_result) {
+- mnd_efree(conn->current_result);
++ conn->current_result->m.free_result(conn->current_result, TRUE);
+ conn->current_result = NULL;
+ }
+ DBG_ERR("Error occurred while reading metadata");
+diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.c b/ext/mysqlnd/mysqlnd_wireprotocol.c
+index e4a298adaea..844b90c5704 100644
+--- a/ext/mysqlnd/mysqlnd_wireprotocol.c
++++ b/ext/mysqlnd/mysqlnd_wireprotocol.c
+@@ -715,7 +715,14 @@ php_mysqlnd_auth_response_read(MYSQLND_CONN_DATA * conn, void * _packet)
+
+ /* There is a message */
+ if (packet->header.size > (size_t) (p - buf) && (net_len = php_mysqlnd_net_field_length(&p))) {
+- packet->message_len = MIN(net_len, buf_len - (p - begin));
++ /* p can get past packet size when getting field length so it needs to be checked first
++ * and after that it can be checked that the net_len is not greater than the packet size */
++ if ((p - buf) > packet->header.size || packet->header.size - (p - buf) < net_len) {
++ DBG_ERR_FMT("OK packet message length is past the packet size");
++ php_error_docref(NULL, E_WARNING, "OK packet message length is past the packet size");
++ DBG_RETURN(FAIL);
++ }
++ packet->message_len = net_len;
+ packet->message = mnd_pestrndup((char *)p, packet->message_len, FALSE);
+ } else {
+ packet->message = NULL;
+@@ -1113,6 +1120,17 @@ php_mysqlnd_rset_header_read(MYSQLND_CONN_DATA * conn, void * _packet)
+ BAIL_IF_NO_MORE_DATA;
+ /* Check for additional textual data */
+ if (packet->header.size > (size_t) (p - buf) && (len = php_mysqlnd_net_field_length(&p))) {
++ /* p can get past packet size when getting field length so it needs to be checked first
++ * and after that it can be checked that the len is not greater than the packet size */
++ if ((p - buf) > packet->header.size || packet->header.size - (p - buf) < len) {
++ size_t local_file_name_over_read = ((p - buf) - packet->header.size) + len;
++ DBG_ERR_FMT("RSET_HEADER packet additional data length is past %zu bytes the packet size",
++ local_file_name_over_read);
++ php_error_docref(NULL, E_WARNING,
++ "RSET_HEADER packet additional data length is past %zu bytes the packet size",
++ local_file_name_over_read);
++ DBG_RETURN(FAIL);
++ }
+ packet->info_or_local_file.s = mnd_emalloc(len + 1);
+ if (packet->info_or_local_file.s) {
+ memcpy(packet->info_or_local_file.s, p, len);
+@@ -1271,23 +1289,16 @@ php_mysqlnd_rset_field_read(MYSQLND_CONN_DATA * conn, void * _packet)
+ meta->flags |= NUM_FLAG;
+ }
+
+-
+- /*
+- def could be empty, thus don't allocate on the root.
+- NULL_LENGTH (0xFB) comes from COM_FIELD_LIST when the default value is NULL.
+- Otherwise the string is length encoded.
+- */
++ /* COM_FIELD_LIST is no longer supported so def should not be present */
+ if (packet->header.size > (size_t) (p - buf) &&
+ (len = php_mysqlnd_net_field_length(&p)) &&
+ len != MYSQLND_NULL_LENGTH)
+ {
+- BAIL_IF_NO_MORE_DATA;
+- DBG_INF_FMT("Def found, length %lu", len);
+- meta->def = packet->memory_pool->get_chunk(packet->memory_pool, len + 1);
+- memcpy(meta->def, p, len);
+- meta->def[len] = '\0';
+- meta->def_length = len;
+- p += len;
++ DBG_ERR_FMT("Protocol error. Server sent default for unsupported field list");
++ php_error_docref(NULL, E_WARNING,
++ "Protocol error. Server sent default for unsupported field list (mysqlnd_wireprotocol.c:%u)",
++ __LINE__);
++ DBG_RETURN(FAIL);
+ }
+
+ root_ptr = meta->root = packet->memory_pool->get_chunk(packet->memory_pool, total_len);
+@@ -1462,8 +1473,10 @@ php_mysqlnd_rowp_read_binary_protocol(MYSQLND_ROW_BUFFER * row_buffer, zval * fi
+ const unsigned int field_count, const MYSQLND_FIELD * const fields_metadata,
+ const zend_bool as_int_or_float, MYSQLND_STATS * const stats)
+ {
+- unsigned int i;
+- const zend_uchar * p = row_buffer->ptr;
++ unsigned int i, j;
++ size_t rbs = row_buffer->size;
++ const zend_uchar * rbp = row_buffer->ptr;
++ const zend_uchar * p = rbp;
+ const zend_uchar * null_ptr;
+ zend_uchar bit;
+ zval *current_field, *end_field, *start_field;
+@@ -1496,7 +1509,21 @@ php_mysqlnd_rowp_read_binary_protocol(MYSQLND_ROW_BUFFER * row_buffer, zval * fi
+ statistic = STAT_BINARY_TYPE_FETCHED_NULL;
+ } else {
+ enum_mysqlnd_field_types type = fields_metadata[i].type;
+- mysqlnd_ps_fetch_functions[type].func(current_field, &fields_metadata[i], 0, &p);
++ size_t row_position = p - rbp;
++ if (rbs <= row_position) {
++ for (j = 0, current_field = start_field; j < i; current_field++, j++) {
++ zval_ptr_dtor(current_field);
++ }
++ php_error_docref(NULL, E_WARNING, "Malformed server packet. No packet space left for the field");
++ DBG_RETURN(FAIL);
++ }
++ mysqlnd_ps_fetch_functions[type].func(current_field, &fields_metadata[i], rbs - row_position, &p);
++ if (p == NULL) {
++ for (j = 0, current_field = start_field; j < i; current_field++, j++) {
++ zval_ptr_dtor(current_field);
++ }
++ DBG_RETURN(FAIL);
++ }
+
+ if (MYSQLND_G(collect_statistics)) {
+ switch (fields_metadata[i].type) {
+@@ -1553,7 +1580,7 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_ROW_BUFFER * row_buffer, zval *
+ unsigned int field_count, const MYSQLND_FIELD * fields_metadata,
+ zend_bool as_int_or_float, MYSQLND_STATS * stats)
+ {
+- unsigned int i;
++ unsigned int i, j;
+ zval *current_field, *end_field, *start_field;
+ zend_uchar * p = row_buffer->ptr;
+ const size_t data_size = row_buffer->size;
+@@ -1574,9 +1601,11 @@ php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_ROW_BUFFER * row_buffer, zval *
+ /* NULL or NOT NULL, this is the question! */
+ if (len == MYSQLND_NULL_LENGTH) {
+ ZVAL_NULL(current_field);
+- } else if ((p + len) > packet_end) {
+- php_error_docref(NULL, E_WARNING, "Malformed server packet. Field length pointing "MYSQLND_SZ_T_SPEC
+- " bytes after end of packet", (p + len) - packet_end - 1);
++ } else if (p > packet_end || len > packet_end - p) {
++ php_error_docref(NULL, E_WARNING, "Malformed server packet. Field length pointing after end of packet");
++ for (j = 0, current_field = start_field; j < i; current_field++, j++) {
++ zval_ptr_dtor(current_field);
++ }
+ DBG_RETURN(FAIL);
+ } else {
+ #if defined(MYSQLND_STRING_TO_INT_CONVERSION)
+--
+2.47.0
+
+From aaeb9549a1bdfa787fc3d3a2d499b418d09a5387 Mon Sep 17 00:00:00 2001
+From: Jakub Zelenka <bukka@php.net>
+Date: Mon, 18 Nov 2024 15:54:30 +0100
+Subject: [PATCH 2/6] Fix MySQLnd possible buffer over read in auth_protocol
+
+(cherry picked from commit 32f905f1d689aaa8eacd6331a18c0dd45972c3c1)
+(cherry picked from commit d5f9da0d6af72ae21b0a9f4c94c59dfdd409e3e2)
+---
+ ext/mysqlnd/mysqlnd_wireprotocol.c | 27 +++++++++++++++++++++++++--
+ 1 file changed, 25 insertions(+), 2 deletions(-)
+
+diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.c b/ext/mysqlnd/mysqlnd_wireprotocol.c
+index 844b90c5704..e75c859bab7 100644
+--- a/ext/mysqlnd/mysqlnd_wireprotocol.c
++++ b/ext/mysqlnd/mysqlnd_wireprotocol.c
+@@ -441,8 +441,31 @@ php_mysqlnd_greet_read(MYSQLND_CONN_DATA * conn, void * _packet)
+ if (packet->server_capabilities & CLIENT_PLUGIN_AUTH) {
+ BAIL_IF_NO_MORE_DATA;
+ /* The server is 5.5.x and supports authentication plugins */
+- packet->auth_protocol = estrdup((char *)p);
+- p+= strlen(packet->auth_protocol) + 1; /* eat the '\0' */
++ size_t remaining_size = packet->header.size - (size_t)(p - buf);
++ if (remaining_size == 0) {
++ /* Might be better to fail but this will fail anyway */
++ packet->auth_protocol = estrdup("");
++ } else {
++ /* Check if NUL present */
++ char *null_terminator = memchr(p, '\0', remaining_size);
++ size_t auth_protocol_len;
++ if (null_terminator) {
++ /* If present, do basically estrdup */
++ auth_protocol_len = null_terminator - (char *)p;
++ } else {
++ /* If not present, copy the rest of the buffer */
++ auth_protocol_len = remaining_size;
++ }
++ char *auth_protocol = emalloc(auth_protocol_len + 1);
++ memcpy(auth_protocol, p, auth_protocol_len);
++ auth_protocol[auth_protocol_len] = '\0';
++ packet->auth_protocol = auth_protocol;
++
++ p += auth_protocol_len;
++ if (null_terminator) {
++ p++;
++ }
++ }
+ }
+
+ DBG_INF_FMT("proto=%u server=%s thread_id=%u",
+--
+2.47.0
+
+From 83a0d005d51a44bbe77a178c387e2c9f042a335d Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@remirepo.net>
+Date: Wed, 27 Nov 2024 10:54:10 +0100
+Subject: [PATCH 3/6] Avoid using uninitialised struct
+
+ (cherry picked from commit 7e7817bc2f82570bbc510a2bf5e4e0ec09dbc774)
+
+(cherry picked from commit 69853e12b73a989e2383452356cdc07172427ae3)
+---
+ ext/mysqlnd/mysqlnd_result.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/ext/mysqlnd/mysqlnd_result.c b/ext/mysqlnd/mysqlnd_result.c
+index c0f65f854ac..9f19adb0ce9 100644
+--- a/ext/mysqlnd/mysqlnd_result.c
++++ b/ext/mysqlnd/mysqlnd_result.c
+@@ -549,8 +549,8 @@ mysqlnd_query_read_result_set_header(MYSQLND_CONN_DATA * conn, MYSQLND_STMT * s)
+ }
+ MYSQLND_INC_CONN_STATISTIC(conn->stats, statistic);
+ }
++ PACKET_FREE(&fields_eof);
+ } while (0);
+- PACKET_FREE(&fields_eof);
+ break; /* switch break */
+ }
+ } while (0);
+--
+2.47.0
+
+From 606322b7f3475fb5980f7785789adfb9c381abbc Mon Sep 17 00:00:00 2001
+From: Jakub Zelenka <bukka@php.net>
+Date: Sun, 24 Nov 2024 20:13:47 +0100
+Subject: [PATCH 4/6] Change port for mysqli fake server auth message test
+
+(cherry picked from commit 51f5539914ae62ef8568ea1ed302dceda897c439)
+(cherry picked from commit 7e6af9c78d84d15880cfbc7867501f25ab982f5f)
+---
+ ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt
+index db54a6c0177..279aec6a2cb 100644
+--- a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt
+@@ -6,7 +6,7 @@ mysqli
+ <?php
+ require_once 'fake_server.inc';
+
+-$port = 50001;
++$port = 33305;
+ $servername = "127.0.0.1";
+ $username = "root";
+ $password = "";
+@@ -34,5 +34,5 @@ print "done!";
+ [*] Sending - Malicious OK Auth Response [Extract heap through buffer over-read]: 0900000200000002000000fcff
+
+ Warning: mysqli::__construct(): OK packet message length is past the packet size in %s on line %d
+-Unknown error while trying to connect via tcp://127.0.0.1:50001
++Unknown error while trying to connect via tcp://127.0.0.1:33305
+ done!
+--
+2.47.0
+
+From c308c94eefdbddb041ed3cf502ef5dd6969e14f1 Mon Sep 17 00:00:00 2001
+From: Jakub Zelenka <bukka@php.net>
+Date: Sun, 24 Nov 2024 23:48:27 +0100
+Subject: [PATCH 5/6] Increase MySQLi fake server read timeout for ASAN job
+
+(cherry picked from commit eb951b3d11109aa16982a2132f8d1fd5129edc9e)
+(cherry picked from commit cae38b1c749d27dc3a65f7d65fdf238439e2676c)
+---
+ ext/mysqli/tests/fake_server.inc | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/ext/mysqli/tests/fake_server.inc b/ext/mysqli/tests/fake_server.inc
+index b02fabc584c..1127f6c00e3 100644
+--- a/ext/mysqli/tests/fake_server.inc
++++ b/ext/mysqli/tests/fake_server.inc
+@@ -552,8 +552,8 @@ class my_mysqli_fake_server_conn
+
+ public function read($bytes_len = 1024)
+ {
+- // wait 10ms to fill the buffer
+- usleep(10000);
++ // wait 20ms to fill the buffer
++ usleep(20000);
+ $data = fread($this->conn, $bytes_len);
+ if ($data) {
+ fprintf(STDERR, "[*] Received: %s\n", bin2hex($data));
+--
+2.47.0
+
+From 016ffd6131a6174fe5ca5f4af3c66ad9f59ed879 Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@remirepo.net>
+Date: Wed, 27 Nov 2024 11:17:48 +0100
+Subject: [PATCH 6/6] adapt test + NEWS
+
+---
+ NEWS | 4 +
+ ext/mysqli/tests/fake_server.inc | 99 ++++++++++---------
+ .../ghsa-h35g-vwh6-m678-auth-message.phpt | 3 +-
+ ext/mysqli/tests/mysqli_change_user_new.phpt | 3 +
+ 4 files changed, 61 insertions(+), 48 deletions(-)
+
+diff --git a/NEWS b/NEWS
+index f600d6aea65..09cf2cfa0bb 100644
+--- a/NEWS
++++ b/NEWS
+@@ -11,6 +11,10 @@ Backported from 8.1.31
+ . Fixed bug GHSA-g665-fm4p-vhff (OOB access in ldap_escape). (CVE-2024-8932)
+ (nielsdos)
+
++- MySQLnd:
++ . Fixed bug GHSA-h35g-vwh6-m678 (Leak partial content of the heap through
++ heap buffer over-read). (CVE-2024-8929) (Jakub Zelenka)
++
+ - PDO DBLIB:
+ . Fixed bug GHSA-5hqh-c84r-qjcv (Integer overflow in the dblib quoter causing
+ OOB writes). (CVE-2024-11236) (nielsdos)
+diff --git a/ext/mysqli/tests/fake_server.inc b/ext/mysqli/tests/fake_server.inc
+index 1127f6c00e3..18b77cb1a76 100644
+--- a/ext/mysqli/tests/fake_server.inc
++++ b/ext/mysqli/tests/fake_server.inc
+@@ -1,6 +1,6 @@
+ <?php
+
+-function my_mysqli_data_fields(): array
++function my_mysqli_data_fields()
+ {
+ return [
+ 'intval' => [
+@@ -107,8 +107,11 @@ function my_mysqli_data_field(string $field): array
+
+ class my_mysqli_fake_packet_item
+ {
+- public function __construct(public string|null $name, public string $value, public bool $is_hex = true)
++ public function __construct($name, string $value, bool $is_hex = true)
+ {
++ $this->name = $name;
++ $this->value = $value;
++ $this->is_hex = $is_hex;
+ }
+ }
+
+@@ -126,7 +129,7 @@ class my_mysqli_fake_packet
+ return null;
+ }
+
+- public function __set(string $name, string|my_mysqli_fake_packet_item $value)
++ public function __set(string $name, $value)
+ {
+ if ($value instanceof my_mysqli_fake_packet_item) {
+ if ($value->name === null) {
+@@ -146,7 +149,7 @@ class my_mysqli_fake_packet
+ $this->data[] = $value;
+ }
+
+- public function to_bytes(): string
++ public function to_bytes()
+ {
+ $bytes = '';
+ foreach ($this->data as $item) {
+@@ -158,7 +161,7 @@ class my_mysqli_fake_packet
+
+ class my_mysqli_fake_packet_generator
+ {
+- public static function create_packet_item(int|string $value, bool $is_hex = false, string $format = 'v'): my_mysqli_fake_packet_item
++ public static function create_packet_item($value, bool $is_hex = false, string $format = 'v')
+ {
+ if (is_string($value)) {
+ $packed_value = $value;
+@@ -168,7 +171,7 @@ class my_mysqli_fake_packet_generator
+ return new my_mysqli_fake_packet_item(null, $packed_value, $is_hex);
+ }
+
+- public function server_ok(): my_mysqli_fake_packet
++ public function server_ok()
+ {
+ $packet = new my_mysqli_fake_packet();
+ $packet->packet_length = "070000";
+@@ -181,7 +184,7 @@ class my_mysqli_fake_packet_generator
+ return $packet;
+ }
+
+- public function server_greetings(): my_mysqli_fake_packet
++ public function server_greetings()
+ {
+ $packet = new my_mysqli_fake_packet();
+ $packet->packet_length = "580000";
+@@ -204,7 +207,7 @@ class my_mysqli_fake_packet_generator
+ return $packet;
+ }
+
+- public function server_tabular_query_response(): array
++ public function server_tabular_query_response()
+ {
+ $qr1 = new my_mysqli_fake_packet();
+ $qr1->packet_length = "010000";
+@@ -239,7 +242,7 @@ class my_mysqli_fake_packet_generator
+ return [$qr1, $qr2, $qr3, $qr4, $qr5];
+ }
+
+- public function server_upsert_query_response(): array
++ public function server_upsert_query_response()
+ {
+ $qr1 = new my_mysqli_fake_packet();
+ $qr1->packet_length = "010000";
+@@ -257,7 +260,7 @@ class my_mysqli_fake_packet_generator
+ return [$qr1];
+ }
+
+- public function server_stmt_prepare_response_start($num_field): my_mysqli_fake_packet
++ public function server_stmt_prepare_response_start($num_field)
+ {
+ $pr1 = new my_mysqli_fake_packet();
+ $pr1->packet_length = "0c0000";
+@@ -272,7 +275,7 @@ class my_mysqli_fake_packet_generator
+ return $pr1;
+ }
+
+- public function server_stmt_prepare_response_end($packer_number): my_mysqli_fake_packet
++ public function server_stmt_prepare_response_end($packer_number)
+ {
+ $pr3 = new my_mysqli_fake_packet();
+ $pr3->packet_length = "050000";
+@@ -284,7 +287,7 @@ class my_mysqli_fake_packet_generator
+ return $pr3;
+ }
+
+- public function server_stmt_prepare_items_response(): array
++ public function server_stmt_prepare_items_response()
+ {
+ $pr1 = $this->server_stmt_prepare_response_start('0100');
+
+@@ -316,7 +319,7 @@ class my_mysqli_fake_packet_generator
+ return [$pr1, $pr2, $pr3];
+ }
+
+- public function server_stmt_prepare_data_response_field($packet_number, $field_name): my_mysqli_fake_packet
++ public function server_stmt_prepare_data_response_field($packet_number, $field_name)
+ {
+ if (strlen($field_name) != 6) {
+ throw new Exception("Invalid field length - only 6 is allowed");
+@@ -350,7 +353,7 @@ class my_mysqli_fake_packet_generator
+ return $pr;
+ }
+
+- public function server_stmt_prepare_data_response(string $field_name): array
++ public function server_stmt_prepare_data_response(string $field_name)
+ {
+ $pr1 = $this->server_stmt_prepare_response_start('0200');
+
+@@ -362,7 +365,7 @@ class my_mysqli_fake_packet_generator
+ return [$pr1, $pr2, $pr3, $pr4];
+ }
+
+- public function server_stmt_execute_items_response(): array
++ public function server_stmt_execute_items_response()
+ {
+ $pr1 = new my_mysqli_fake_packet();
+ $pr1->packet_length = "010000";
+@@ -413,7 +416,7 @@ class my_mysqli_fake_packet_generator
+ return [$pr1, $pr2, $pr3, $pr4, $pr5];
+ }
+
+- private function server_execute_data_response_start(string $field_name): array
++ private function server_execute_data_response_start(string $field_name)
+ {
+ $pr1 = new my_mysqli_fake_packet();
+ $pr1->packet_length = "010000";
+@@ -478,7 +481,7 @@ class my_mysqli_fake_packet_generator
+ return [$field, $pr1, $pr2, $pr3, $pr4];
+ }
+
+- private function server_execute_data_response_end(): my_mysqli_fake_packet
++ private function server_execute_data_response_end()
+ {
+ $pr6 = new my_mysqli_fake_packet();
+ $pr6->packet_length = '050000';
+@@ -490,7 +493,7 @@ class my_mysqli_fake_packet_generator
+ return $pr6;
+ }
+
+- public function server_stmt_execute_data_response(string $field_name): array
++ public function server_stmt_execute_data_response(string $field_name)
+ {
+ [$field, $pr1, $pr2, $pr3, $pr4] = $this->server_execute_data_response_start($field_name);
+
+@@ -506,7 +509,7 @@ class my_mysqli_fake_packet_generator
+ return [$pr1, $pr2, $pr3, $pr4, $pr5, $this->server_execute_data_response_end()];
+ }
+
+- public function server_query_execute_data_response(string $field_name): array
++ public function server_query_execute_data_response(string $field_name)
+ {
+ [$field, $pr1, $pr2, $pr3, $pr4] = $this->server_execute_data_response_start($field_name);
+
+@@ -537,12 +540,12 @@ class my_mysqli_fake_server_conn
+ }
+ }
+
+- public function packets_to_bytes(array $packets): string
++ public function packets_to_bytes(array $packets)
+ {
+ return implode('', array_map(fn($s) => $s->to_bytes(), $packets));
+ }
+
+- public function send($payload, $message = null): void
++ public function send($payload, $message = null)
+ {
+ if ($message) {
+ fprintf(STDERR, "[*] Sending - %s: %s\n", $message, bin2hex($payload));
+@@ -575,38 +578,38 @@ class my_mysqli_fake_server_conn
+ $this->send($this->packet_generator->server_ok()->to_bytes(), "Server OK");
+ }
+
+- public function send_server_tabular_query_response(): void
++ public function send_server_tabular_query_response()
+ {
+ $packets = $this->packet_generator->server_tabular_query_response();
+ $this->send($this->packets_to_bytes($packets), "Tabular response");
+ }
+
+- public function send_server_stmt_prepare_items_response(): void
++ public function send_server_stmt_prepare_items_response()
+ {
+ $packets = $this->packet_generator->server_stmt_prepare_items_response();
+ $this->send($this->packets_to_bytes($packets), "Stmt prepare items");
+ }
+
+
+- public function send_server_stmt_prepare_data_response(string $field_name): void
++ public function send_server_stmt_prepare_data_response(string $field_name)
+ {
+ $packets = $this->packet_generator->server_stmt_prepare_data_response($field_name);
+ $this->send($this->packets_to_bytes($packets), "Stmt prepare data $field_name");
+ }
+
+- public function send_server_stmt_execute_items_response(): void
++ public function send_server_stmt_execute_items_response()
+ {
+ $packets = $this->packet_generator->server_stmt_execute_items_response();
+ $this->send($this->packets_to_bytes($packets), "Stmt execute items");
+ }
+
+- public function send_server_stmt_execute_data_response(string $field_name): void
++ public function send_server_stmt_execute_data_response(string $field_name)
+ {
+ $packets = $this->packet_generator->server_stmt_execute_data_response($field_name);
+ $this->send($this->packets_to_bytes($packets), "Stmt execute data $field_name");
+ }
+
+- public function send_server_query_execute_data_response(string $field_name): void
++ public function send_server_query_execute_data_response(string $field_name)
+ {
+ $packets = $this->packet_generator->server_query_execute_data_response($field_name);
+ $this->send($this->packets_to_bytes($packets), "Query execute data $field_name");
+@@ -615,7 +618,11 @@ class my_mysqli_fake_server_conn
+
+ class my_mysqli_fake_server_process
+ {
+- public function __construct(private $process, private array $pipes) {}
++ public function __construct($process, array $pipes)
++ {
++ $this->process = $process;
++ $this->pipes = $pipes;
++ }
+
+ public function terminate(bool $wait = false)
+ {
+@@ -631,7 +638,7 @@ class my_mysqli_fake_server_process
+ }
+ }
+
+-function my_mysqli_test_tabular_response_def_over_read(my_mysqli_fake_server_conn $conn): void
++function my_mysqli_test_tabular_response_def_over_read(my_mysqli_fake_server_conn $conn)
+ {
+ $rh = $conn->packet_generator->server_tabular_query_response();
+
+@@ -655,7 +662,7 @@ function my_mysqli_test_tabular_response_def_over_read(my_mysqli_fake_server_con
+ $conn->read(65536);
+ }
+
+-function my_mysqli_test_upsert_response_filename_over_read(my_mysqli_fake_server_conn $conn): void
++function my_mysqli_test_upsert_response_filename_over_read(my_mysqli_fake_server_conn $conn)
+ {
+ $rh = $conn->packet_generator->server_upsert_query_response();
+
+@@ -672,7 +679,7 @@ function my_mysqli_test_upsert_response_filename_over_read(my_mysqli_fake_server
+ $conn->read(65536);
+ }
+
+-function my_mysqli_test_auth_response_message_over_read(my_mysqli_fake_server_conn $conn): void
++function my_mysqli_test_auth_response_message_over_read(my_mysqli_fake_server_conn $conn)
+ {
+ $p = $conn->packet_generator->server_ok();
+ $p->packet_length = "090000";
+@@ -684,7 +691,7 @@ function my_mysqli_test_auth_response_message_over_read(my_mysqli_fake_server_co
+ $conn->read();
+ }
+
+-function my_mysqli_test_stmt_response_row_over_read_string(my_mysqli_fake_server_conn $conn): void
++function my_mysqli_test_stmt_response_row_over_read_string(my_mysqli_fake_server_conn $conn)
+ {
+ $rh = $conn->packet_generator->server_stmt_execute_items_response();
+
+@@ -705,7 +712,7 @@ function my_mysqli_test_stmt_response_row_over_read_two_fields(
+ my_mysqli_fake_server_conn $conn,
+ string $field_name,
+ string $row_field1_len = '06'
+-): void {
++) {
+ $rh = $conn->packet_generator->server_stmt_execute_data_response($field_name);
+
+ // Set extra length to overread by two bytes
+@@ -724,47 +731,47 @@ function my_mysqli_test_stmt_response_row_over_read_two_fields(
+ $conn->read(65536);
+ }
+
+-function my_mysqli_test_stmt_response_row_over_read_int(my_mysqli_fake_server_conn $conn): void
++function my_mysqli_test_stmt_response_row_over_read_int(my_mysqli_fake_server_conn $conn)
+ {
+ my_mysqli_test_stmt_response_row_over_read_two_fields($conn, 'intval');
+ }
+
+-function my_mysqli_test_stmt_response_row_over_read_float(my_mysqli_fake_server_conn $conn): void
++function my_mysqli_test_stmt_response_row_over_read_float(my_mysqli_fake_server_conn $conn)
+ {
+ my_mysqli_test_stmt_response_row_over_read_two_fields($conn, 'fltval');
+ }
+
+-function my_mysqli_test_stmt_response_row_over_read_double(my_mysqli_fake_server_conn $conn): void
++function my_mysqli_test_stmt_response_row_over_read_double(my_mysqli_fake_server_conn $conn)
+ {
+ my_mysqli_test_stmt_response_row_over_read_two_fields($conn, 'dblval');
+ }
+
+-function my_mysqli_test_stmt_response_row_over_read_date(my_mysqli_fake_server_conn $conn): void
++function my_mysqli_test_stmt_response_row_over_read_date(my_mysqli_fake_server_conn $conn)
+ {
+ my_mysqli_test_stmt_response_row_over_read_two_fields($conn, 'datval');
+ }
+
+-function my_mysqli_test_stmt_response_row_over_read_time(my_mysqli_fake_server_conn $conn): void
++function my_mysqli_test_stmt_response_row_over_read_time(my_mysqli_fake_server_conn $conn)
+ {
+ my_mysqli_test_stmt_response_row_over_read_two_fields($conn, 'timval', '0c');
+ }
+
+-function my_mysqli_test_stmt_response_row_over_read_datetime(my_mysqli_fake_server_conn $conn): void
++function my_mysqli_test_stmt_response_row_over_read_datetime(my_mysqli_fake_server_conn $conn)
+ {
+ my_mysqli_test_stmt_response_row_over_read_two_fields($conn, 'dtival');
+ }
+
+-function my_mysqli_test_stmt_response_row_no_space(my_mysqli_fake_server_conn $conn): void
++function my_mysqli_test_stmt_response_row_no_space(my_mysqli_fake_server_conn $conn)
+ {
+ my_mysqli_test_stmt_response_row_over_read_two_fields($conn, 'strval', '09');
+ }
+
+-function my_mysqli_test_stmt_response_row_over_read_bit(my_mysqli_fake_server_conn $conn): void
++function my_mysqli_test_stmt_response_row_over_read_bit(my_mysqli_fake_server_conn $conn)
+ {
+ my_mysqli_test_stmt_response_row_over_read_two_fields($conn, 'bitval');
+ }
+
+-function my_mysqli_test_stmt_response_row_read_two_fields(my_mysqli_fake_server_conn $conn): void
++function my_mysqli_test_stmt_response_row_read_two_fields(my_mysqli_fake_server_conn $conn)
+ {
+ $conn->send_server_greetings();
+ $conn->read();
+@@ -779,7 +786,7 @@ function my_mysqli_test_stmt_response_row_read_two_fields(my_mysqli_fake_server_
+ }
+ }
+
+-function my_mysqli_test_query_response_row_length_overflow(my_mysqli_fake_server_conn $conn): void
++function my_mysqli_test_query_response_row_length_overflow(my_mysqli_fake_server_conn $conn)
+ {
+ $rh = $conn->packet_generator->server_query_execute_data_response('strval');
+
+@@ -794,7 +801,7 @@ function my_mysqli_test_query_response_row_length_overflow(my_mysqli_fake_server
+ $conn->read(65536);
+ }
+
+-function my_mysqli_test_query_response_row_read_two_fields(my_mysqli_fake_server_conn $conn): void
++function my_mysqli_test_query_response_row_read_two_fields(my_mysqli_fake_server_conn $conn)
+ {
+ $conn->send_server_greetings();
+ $conn->read();
+@@ -807,7 +814,7 @@ function my_mysqli_test_query_response_row_read_two_fields(my_mysqli_fake_server
+ }
+ }
+
+-function run_fake_server(string $test_function, $port = 33305): void
++function run_fake_server(string $test_function, $port = 33305)
+ {
+ $address = '127.0.0.1';
+
+@@ -832,7 +839,7 @@ function run_fake_server(string $test_function, $port = 33305): void
+ }
+
+
+-function run_fake_server_in_background($test_function, $port = 33305): my_mysqli_fake_server_process
++function run_fake_server_in_background($test_function, $port = 33305)
+ {
+ $command = [PHP_BINARY, '-n', __FILE__, 'mysqli_fake_server', $test_function, $port];
+
+diff --git a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt
+index 279aec6a2cb..161c9a5b8e6 100644
+--- a/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt
++++ b/ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt
+@@ -34,5 +34,4 @@ print "done!";
+ [*] Sending - Malicious OK Auth Response [Extract heap through buffer over-read]: 0900000200000002000000fcff
+
+ Warning: mysqli::__construct(): OK packet message length is past the packet size in %s on line %d
+-Unknown error while trying to connect via tcp://127.0.0.1:33305
+-done!
++%A
+diff --git a/ext/mysqli/tests/mysqli_change_user_new.phpt b/ext/mysqli/tests/mysqli_change_user_new.phpt
+index 2b8993fc20d..d8fed6dfaee 100644
+--- a/ext/mysqli/tests/mysqli_change_user_new.phpt
++++ b/ext/mysqli/tests/mysqli_change_user_new.phpt
+@@ -12,6 +12,9 @@ if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
+
+ if (mysqli_get_server_version($link) < 50600)
+ die("SKIP For MySQL >= 5.6.0");
++
++if (mysqli_get_server_version($link) >= 10_00_00)
++ die("SKIP Not applicable for MariaDB");
+ ?>
+ --FILE--
+ <?php
+--
+2.47.0
+
diff --git a/php-cve-2024-8932.patch b/php-cve-2024-8932.patch
new file mode 100644
index 0000000..1efcff9
--- /dev/null
+++ b/php-cve-2024-8932.patch
@@ -0,0 +1,139 @@
+From 50e9e72530a4805980384b8ea6672877af816145 Mon Sep 17 00:00:00 2001
+From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
+Date: Thu, 26 Sep 2024 22:22:27 +0200
+Subject: [PATCH 4/7] Fix GHSA-g665-fm4p-vhff: OOB access in ldap_escape
+
+(cherry picked from commit f9ecf90070a11dad09ca7671a712f81cc2a7d52f)
+(cherry picked from commit 9f367d847989b339c33369737daf573e30bab5f1)
+---
+ ext/ldap/ldap.c | 21 ++++++++++++++--
+ ext/ldap/tests/GHSA-g665-fm4p-vhff-1.phpt | 28 ++++++++++++++++++++++
+ ext/ldap/tests/GHSA-g665-fm4p-vhff-2.phpt | 29 +++++++++++++++++++++++
+ 3 files changed, 76 insertions(+), 2 deletions(-)
+ create mode 100644 ext/ldap/tests/GHSA-g665-fm4p-vhff-1.phpt
+ create mode 100644 ext/ldap/tests/GHSA-g665-fm4p-vhff-2.phpt
+
+diff --git a/ext/ldap/ldap.c b/ext/ldap/ldap.c
+index 72a39bd93df..75adf1b5df2 100644
+--- a/ext/ldap/ldap.c
++++ b/ext/ldap/ldap.c
+@@ -49,6 +49,7 @@
+
+ #include "ext/standard/php_string.h"
+ #include "ext/standard/info.h"
++#include "Zend/zend_exceptions.h"
+
+ #ifdef HAVE_LDAP_SASL
+ #include <sasl/sasl.h>
+@@ -3836,13 +3837,23 @@ static zend_string* php_ldap_do_escape(const zend_bool *map, const char *value,
+ zend_string *ret;
+
+ for (i = 0; i < valuelen; i++) {
+- len += (map[(unsigned char) value[i]]) ? 3 : 1;
++ size_t addend = (map[(unsigned char) value[i]]) ? 3 : 1;
++ if (len > ZSTR_MAX_LEN - addend) {
++ return NULL;
++ }
++ len += addend;
+ }
+ /* Per RFC 4514, a leading and trailing space must be escaped */
+ if ((flags & PHP_LDAP_ESCAPE_DN) && (value[0] == ' ')) {
++ if (len > ZSTR_MAX_LEN - 2) {
++ return NULL;
++ }
+ len += 2;
+ }
+ if ((flags & PHP_LDAP_ESCAPE_DN) && ((valuelen > 1) && (value[valuelen - 1] == ' '))) {
++ if (len > ZSTR_MAX_LEN - 2) {
++ return NULL;
++ }
+ len += 2;
+ }
+
+@@ -3909,7 +3920,13 @@ PHP_FUNCTION(ldap_escape)
+ php_ldap_escape_map_set_chars(map, ignores, ignoreslen, 0);
+ }
+
+- RETURN_NEW_STR(php_ldap_do_escape(map, value, valuelen, flags));
++ zend_string *result = php_ldap_do_escape(map, value, valuelen, flags);
++ if (UNEXPECTED(!result)) {
++ zend_throw_exception(NULL, "Argument #1 ($value) is too long", 0);
++ return;
++ }
++
++ RETURN_NEW_STR(result);
+ }
+
+ #ifdef STR_TRANSLATION
+diff --git a/ext/ldap/tests/GHSA-g665-fm4p-vhff-1.phpt b/ext/ldap/tests/GHSA-g665-fm4p-vhff-1.phpt
+new file mode 100644
+index 00000000000..734bbe91d42
+--- /dev/null
++++ b/ext/ldap/tests/GHSA-g665-fm4p-vhff-1.phpt
+@@ -0,0 +1,28 @@
++--TEST--
++GHSA-g665-fm4p-vhff (OOB access in ldap_escape)
++--EXTENSIONS--
++ldap
++--INI--
++memory_limit=-1
++--SKIPIF--
++<?php
++if (PHP_INT_SIZE !== 4) die("skip only for 32-bit");
++if (getenv("SKIP_SLOW_TESTS")) die("skip slow test");
++?>
++--FILE--
++<?php
++try {
++ ldap_escape(' '.str_repeat("#", 1431655758), "", LDAP_ESCAPE_DN);
++} catch (Exception $e) {
++ echo $e->getMessage(), "\n";
++}
++
++try {
++ ldap_escape(str_repeat("#", 1431655758).' ', "", LDAP_ESCAPE_DN);
++} catch (Exception $e) {
++ echo $e->getMessage(), "\n";
++}
++?>
++--EXPECT--
++ldap_escape(): Argument #1 ($value) is too long
++ldap_escape(): Argument #1 ($value) is too long
+diff --git a/ext/ldap/tests/GHSA-g665-fm4p-vhff-2.phpt b/ext/ldap/tests/GHSA-g665-fm4p-vhff-2.phpt
+new file mode 100644
+index 00000000000..5c1b0fb6611
+--- /dev/null
++++ b/ext/ldap/tests/GHSA-g665-fm4p-vhff-2.phpt
+@@ -0,0 +1,29 @@
++--TEST--
++GHSA-g665-fm4p-vhff (OOB access in ldap_escape)
++--EXTENSIONS--
++ldap
++--INI--
++memory_limit=-1
++--SKIPIF--
++<?php
++if (PHP_INT_SIZE !== 4) die("skip only for 32-bit");
++if (getenv("SKIP_SLOW_TESTS")) die("skip slow test");
++?>
++--FILE--
++<?php
++try {
++ ldap_escape(str_repeat("*", 1431655759), "", LDAP_ESCAPE_FILTER);
++} catch (Exception $e) {
++ echo $e->getMessage(), "\n";
++}
++
++// would allocate a string of length 2
++try {
++ ldap_escape(str_repeat("*", 1431655766), "", LDAP_ESCAPE_FILTER);
++} catch (Exception $e) {
++ echo $e->getMessage(), "\n";
++}
++?>
++--EXPECT--
++ldap_escape(): Argument #1 ($value) is too long
++ldap_escape(): Argument #1 ($value) is too long
+--
+2.47.0
+
diff --git a/php-cve-2024-9026.patch b/php-cve-2024-9026.patch
new file mode 100644
index 0000000..997917b
--- /dev/null
+++ b/php-cve-2024-9026.patch
@@ -0,0 +1,245 @@
+From 4a8b8fa2592bd8862adeacb5b2faacb30500b9f9 Mon Sep 17 00:00:00 2001
+From: Jakub Zelenka <bukka@php.net>
+Date: Thu, 12 Sep 2024 13:11:11 +0100
+Subject: [PATCH 07/11] Fix GHSA-865w-9rf3-2wh5: FPM: Logs from childrens may
+ be altered
+
+(cherry picked from commit 1f8e16172c7961045c2b0f34ba7613e3f21cdee8)
+(cherry picked from commit 22f4d3504d7613ce78bb96aa53cbfe7d672fa036)
+---
+ sapi/fpm/fpm/fpm_stdio.c | 2 +-
+ .../log-bwp-msg-flush-split-sep-pos-end.phpt | 47 +++++++++++++++++++
+ ...log-bwp-msg-flush-split-sep-pos-start.phpt | 47 +++++++++++++++++++
+ 3 files changed, 95 insertions(+), 1 deletion(-)
+ create mode 100644 sapi/fpm/tests/log-bwp-msg-flush-split-sep-pos-end.phpt
+ create mode 100644 sapi/fpm/tests/log-bwp-msg-flush-split-sep-pos-start.phpt
+
+diff --git a/sapi/fpm/fpm/fpm_stdio.c b/sapi/fpm/fpm/fpm_stdio.c
+index ddedfb48c7c..9d87273314a 100644
+--- a/sapi/fpm/fpm/fpm_stdio.c
++++ b/sapi/fpm/fpm/fpm_stdio.c
+@@ -177,7 +177,7 @@ stdio_read:
+ if ((sizeof(FPM_STDIO_CMD_FLUSH) - cmd_pos) <= in_buf &&
+ !memcmp(buf, &FPM_STDIO_CMD_FLUSH[cmd_pos], sizeof(FPM_STDIO_CMD_FLUSH) - cmd_pos)) {
+ zlog_stream_finish(log_stream);
+- start = cmd_pos;
++ start = sizeof(FPM_STDIO_CMD_FLUSH) - cmd_pos;
+ } else {
+ zlog_stream_str(log_stream, &FPM_STDIO_CMD_FLUSH[0], cmd_pos);
+ }
+diff --git a/sapi/fpm/tests/log-bwp-msg-flush-split-sep-pos-end.phpt b/sapi/fpm/tests/log-bwp-msg-flush-split-sep-pos-end.phpt
+new file mode 100644
+index 00000000000..52826320080
+--- /dev/null
++++ b/sapi/fpm/tests/log-bwp-msg-flush-split-sep-pos-end.phpt
+@@ -0,0 +1,47 @@
++--TEST--
++FPM: Buffered worker output plain log with msg with flush split position towards separator end
++--SKIPIF--
++<?php include "skipif.inc"; ?>
++--FILE--
++<?php
++
++require_once "tester.inc";
++
++$cfg = <<<EOT
++[global]
++error_log = {{FILE:LOG}}
++[unconfined]
++listen = {{ADDR}}
++pm = dynamic
++pm.max_children = 5
++pm.start_servers = 1
++pm.min_spare_servers = 1
++pm.max_spare_servers = 3
++catch_workers_output = yes
++decorate_workers_output = no
++EOT;
++
++$code = <<<EOT
++<?php
++file_put_contents('php://stderr', str_repeat('a', 1013) . "Quarkslab\0fscf\0Quarkslab");
++EOT;
++
++$tester = new FPM\Tester($cfg, $code);
++$tester->start();
++$tester->expectLogStartNotices();
++$tester->request()->expectEmptyBody();
++$tester->expectLogLine(str_repeat('a', 1013) . "Quarkslab", decorated: false);
++$tester->expectLogLine("Quarkslab", decorated: false);
++$tester->terminate();
++$tester->expectLogTerminatingNotices();
++$tester->close();
++
++?>
++Done
++--EXPECT--
++Done
++--CLEAN--
++<?php
++require_once "tester.inc";
++FPM\Tester::clean();
++?>
+diff --git a/sapi/fpm/tests/log-bwp-msg-flush-split-sep-pos-start.phpt b/sapi/fpm/tests/log-bwp-msg-flush-split-sep-pos-start.phpt
+new file mode 100644
+index 00000000000..34905938553
+--- /dev/null
++++ b/sapi/fpm/tests/log-bwp-msg-flush-split-sep-pos-start.phpt
+@@ -0,0 +1,47 @@
++--TEST--
++FPM: Buffered worker output plain log with msg with flush split position towards separator start
++--SKIPIF--
++<?php include "skipif.inc"; ?>
++--FILE--
++<?php
++
++require_once "tester.inc";
++
++$cfg = <<<EOT
++[global]
++error_log = {{FILE:LOG}}
++[unconfined]
++listen = {{ADDR}}
++pm = dynamic
++pm.max_children = 5
++pm.start_servers = 1
++pm.min_spare_servers = 1
++pm.max_spare_servers = 3
++catch_workers_output = yes
++decorate_workers_output = no
++EOT;
++
++$code = <<<EOT
++<?php
++file_put_contents('php://stderr', str_repeat('a', 1009) . "Quarkslab\0fscf\0Quarkslab");
++EOT;
++
++$tester = new FPM\Tester($cfg, $code);
++$tester->start();
++$tester->expectLogStartNotices();
++$tester->request()->expectEmptyBody();
++$tester->expectLogLine(str_repeat('a', 1009) . "Quarkslab", decorated: false);
++$tester->expectLogLine("Quarkslab", decorated: false);
++$tester->terminate();
++$tester->expectLogTerminatingNotices();
++$tester->close();
++
++?>
++Done
++--EXPECT--
++Done
++--CLEAN--
++<?php
++require_once "tester.inc";
++FPM\Tester::clean();
++?>
+--
+2.46.1
+
+From 1154fbd3ddfa418bf2492c5366adaefb47c47737 Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@remirepo.net>
+Date: Thu, 26 Sep 2024 11:50:54 +0200
+Subject: [PATCH 09/11] NEWS for 8.1.30 backports
+
+(cherry picked from commit af3fb385e7b328ab89db26ec712d89c7096f0743)
+---
+ NEWS | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+diff --git a/NEWS b/NEWS
+index a96518695fb..62616d6312d 100644
+--- a/NEWS
++++ b/NEWS
+@@ -1,6 +1,23 @@
+ PHP NEWS
+ |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+
++Backported from 8.1.30
++
++- CGI:
++ . Fixed bug GHSA-p99j-rfp4-xqvq (Bypass of CVE-2024-4577, Parameter Injection
++ Vulnerability). (CVE-2024-8926) (nielsdos)
++ . Fixed bug GHSA-94p6-54jq-9mwp (cgi.force_redirect configuration is
++ bypassable due to the environment variable collision). (CVE-2024-8927)
++ (nielsdos)
++
++- FPM:
++ . Fixed bug GHSA-865w-9rf3-2wh5 (Logs from childrens may be altered).
++ (CVE-2024-9026) (Jakub Zelenka)
++
++- SAPI:
++ . Fixed bug GHSA-9pqp-7h25-4f32 (Erroneous parsing of multipart form data).
++ (CVE-2024-8925) (Arnaud)
++
+ Backported from 8.1.29
+
+ - CGI:
+--
+2.46.1
+
+From bc574c256596abc4966e7f0e3e0913839092151e Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@remirepo.net>
+Date: Thu, 26 Sep 2024 15:48:11 +0200
+Subject: [PATCH 10/11] adapt GHSA-865w-9rf3-2wh5 test for 7.x
+
+---
+ sapi/fpm/tests/log-bwp-msg-flush-split-sep-pos-end.phpt | 4 ++--
+ sapi/fpm/tests/log-bwp-msg-flush-split-sep-pos-start.phpt | 4 ++--
+ sapi/fpm/tests/tester.inc | 4 ++--
+ 3 files changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/sapi/fpm/tests/log-bwp-msg-flush-split-sep-pos-end.phpt b/sapi/fpm/tests/log-bwp-msg-flush-split-sep-pos-end.phpt
+index 52826320080..bdd61782bfa 100644
+--- a/sapi/fpm/tests/log-bwp-msg-flush-split-sep-pos-end.phpt
++++ b/sapi/fpm/tests/log-bwp-msg-flush-split-sep-pos-end.phpt
+@@ -30,8 +30,8 @@ $tester = new FPM\Tester($cfg, $code);
+ $tester->start();
+ $tester->expectLogStartNotices();
+ $tester->request()->expectEmptyBody();
+-$tester->expectLogLine(str_repeat('a', 1013) . "Quarkslab", decorated: false);
+-$tester->expectLogLine("Quarkslab", decorated: false);
++$tester->expectLogLine(str_repeat('a', 1013) . "Quarkslab", true, false);
++$tester->expectLogLine("Quarkslab", true, false);
+ $tester->terminate();
+ $tester->expectLogTerminatingNotices();
+ $tester->close();
+diff --git a/sapi/fpm/tests/log-bwp-msg-flush-split-sep-pos-start.phpt b/sapi/fpm/tests/log-bwp-msg-flush-split-sep-pos-start.phpt
+index 34905938553..f3461e4a0c8 100644
+--- a/sapi/fpm/tests/log-bwp-msg-flush-split-sep-pos-start.phpt
++++ b/sapi/fpm/tests/log-bwp-msg-flush-split-sep-pos-start.phpt
+@@ -30,8 +30,8 @@ $tester = new FPM\Tester($cfg, $code);
+ $tester->start();
+ $tester->expectLogStartNotices();
+ $tester->request()->expectEmptyBody();
+-$tester->expectLogLine(str_repeat('a', 1009) . "Quarkslab", decorated: false);
+-$tester->expectLogLine("Quarkslab", decorated: false);
++$tester->expectLogLine(str_repeat('a', 1009) . "Quarkslab", true, false);
++$tester->expectLogLine("Quarkslab", true, false);
+ $tester->terminate();
+ $tester->expectLogTerminatingNotices();
+ $tester->close();
+diff --git a/sapi/fpm/tests/tester.inc b/sapi/fpm/tests/tester.inc
+index 7868afc4ac1..fe5f0c2fde7 100644
+--- a/sapi/fpm/tests/tester.inc
++++ b/sapi/fpm/tests/tester.inc
+@@ -1315,7 +1315,7 @@ class Tester
+ * @param string $message
+ * @return bool
+ */
+- public function expectLogLine(string $message, bool $is_stderr = true)
++ public function expectLogLine(string $message, bool $is_stderr = true, bool $decorated = true)
+ {
+ $messageLen = strlen($message);
+ $limit = $messageLen > 1024 ? $messageLen + 16 : 1024;
+@@ -1325,7 +1325,7 @@ class Tester
+ $this->message("LOG LINE: " . ($logLines[0] ?? ''));
+ }
+
+- return $this->logTool->checkWrappedMessage($logLines, false, true, $is_stderr);
++ return $this->logTool->checkWrappedMessage($logLines, false, $decorated, $is_stderr);
+ }
+
+ /**
+--
+2.46.1
+
diff --git a/php-cve-2025-1217.patch b/php-cve-2025-1217.patch
new file mode 100644
index 0000000..23d8b04
--- /dev/null
+++ b/php-cve-2025-1217.patch
@@ -0,0 +1,917 @@
+From bf4a8df2b3972118c87b05450e9062d3926f6be8 Mon Sep 17 00:00:00 2001
+From: Jakub Zelenka <bukka@php.net>
+Date: Tue, 31 Dec 2024 18:57:02 +0100
+Subject: [PATCH 01/11] Fix GHSA-ghsa-v8xr-gpvj-cx9g: http header folding
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This adds HTTP header folding support for HTTP wrapper response
+headers.
+
+Reviewed-by: Tim Düsterhus <tim@tideways-gmbh.com>
+(cherry picked from commit d20b4c97a9f883b62b65b82d939c5af9a2028ef1)
+(cherry picked from commit 4fec08542748c25573063ffc53ea89cd5de1edf0)
+---
+ ext/openssl/tests/ServerClientTestCase.inc | 65 +++-
+ ext/standard/http_fopen_wrapper.c | 347 ++++++++++++------
+ .../tests/http/ghsa-v8xr-gpvj-cx9g-001.phpt | 49 +++
+ .../tests/http/ghsa-v8xr-gpvj-cx9g-002.phpt | 51 +++
+ .../tests/http/ghsa-v8xr-gpvj-cx9g-003.phpt | 49 +++
+ .../tests/http/ghsa-v8xr-gpvj-cx9g-004.phpt | 48 +++
+ .../tests/http/ghsa-v8xr-gpvj-cx9g-005.phpt | 48 +++
+ .../tests/http/http_response_header_05.phpt | 35 --
+ 8 files changed, 537 insertions(+), 155 deletions(-)
+ create mode 100644 ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-001.phpt
+ create mode 100644 ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-002.phpt
+ create mode 100644 ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-003.phpt
+ create mode 100644 ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-004.phpt
+ create mode 100644 ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-005.phpt
+ delete mode 100644 ext/standard/tests/http/http_response_header_05.phpt
+
+diff --git a/ext/openssl/tests/ServerClientTestCase.inc b/ext/openssl/tests/ServerClientTestCase.inc
+index 753366df6f4..c74da444102 100644
+--- a/ext/openssl/tests/ServerClientTestCase.inc
++++ b/ext/openssl/tests/ServerClientTestCase.inc
+@@ -4,14 +4,19 @@ const WORKER_ARGV_VALUE = 'RUN_WORKER';
+
+ const WORKER_DEFAULT_NAME = 'server';
+
+-function phpt_notify($worker = WORKER_DEFAULT_NAME)
++function phpt_notify(string $worker = WORKER_DEFAULT_NAME, string $message = ""): void
+ {
+- ServerClientTestCase::getInstance()->notify($worker);
++ ServerClientTestCase::getInstance()->notify($worker, $message);
+ }
+
+-function phpt_wait($worker = WORKER_DEFAULT_NAME, $timeout = null)
++function phpt_wait($worker = WORKER_DEFAULT_NAME, $timeout = null): ?string
+ {
+- ServerClientTestCase::getInstance()->wait($worker, $timeout);
++ return ServerClientTestCase::getInstance()->wait($worker, $timeout);
++}
++
++function phpt_notify_server_start($server): void
++{
++ ServerClientTestCase::getInstance()->notify_server_start($server);
+ }
+
+ function phpt_has_sslv3() {
+@@ -119,43 +124,73 @@ class ServerClientTestCase
+ eval($code);
+ }
+
+- public function run($masterCode, $workerCode)
++ /**
++ * Run client and all workers
++ *
++ * @param string $clientCode The client PHP code
++ * @param string|array $workerCode
++ * @param bool $ephemeral Select whether automatic port selection and automatic awaiting is used
++ * @return void
++ * @throws Exception
++ */
++ public function run(string $clientCode, $workerCode, bool $ephemeral = true): void
+ {
+ if (!is_array($workerCode)) {
+ $workerCode = [WORKER_DEFAULT_NAME => $workerCode];
+ }
+- foreach ($workerCode as $worker => $code) {
++ reset($workerCode);
++ $code = current($workerCode);
++ $worker = key($workerCode);
++ while ($worker != null) {
+ $this->spawnWorkerProcess($worker, $this->stripPhpTagsFromCode($code));
++ $code = next($workerCode);
++ if ($ephemeral) {
++ $addr = trim($this->wait($worker));
++ if (empty($addr)) {
++ throw new \Exception("Failed server start");
++ }
++ if ($code === false) {
++ $clientCode = preg_replace('/{{\s*ADDR\s*}}/', $addr, $clientCode);
++ } else {
++ $code = preg_replace('/{{\s*ADDR\s*}}/', $addr, $code);
++ }
++ }
++ $worker = key($workerCode);
+ }
+- eval($this->stripPhpTagsFromCode($masterCode));
++
++ eval($this->stripPhpTagsFromCode($clientCode));
+ foreach ($workerCode as $worker => $code) {
+ $this->cleanupWorkerProcess($worker);
+ }
+ }
+
+- public function wait($worker, $timeout = null)
++ public function wait($worker, $timeout = null): ?string
+ {
+ $handle = $this->isWorker ? STDIN : $this->workerStdOut[$worker];
+ if ($timeout === null) {
+- fgets($handle);
+- return true;
++ return fgets($handle);
+ }
+
+ stream_set_blocking($handle, false);
+ $read = [$handle];
+ $result = stream_select($read, $write, $except, $timeout);
+ if (!$result) {
+- return false;
++ return null;
+ }
+
+- fgets($handle);
++ $result = fgets($handle);
+ stream_set_blocking($handle, true);
+- return true;
++ return $result;
++ }
++
++ public function notify(string $worker, string $message = ""): void
++ {
++ fwrite($this->isWorker ? STDOUT : $this->workerStdIn[$worker], "$message\n");
+ }
+
+- public function notify($worker)
++ public function notify_server_start($server): void
+ {
+- fwrite($this->isWorker ? STDOUT : $this->workerStdIn[$worker], "\n");
++ echo stream_socket_get_name($server, false) . "\n";
+ }
+ }
+
+diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c
+index aeeb438f0f9..08386cfafcd 100644
+--- a/ext/standard/http_fopen_wrapper.c
++++ b/ext/standard/http_fopen_wrapper.c
+@@ -116,6 +116,172 @@ static zend_bool check_has_header(const char *headers, const char *header) {
+ return 0;
+ }
+
++typedef struct _php_stream_http_response_header_info {
++ php_stream_filter *transfer_encoding;
++ size_t file_size;
++ zend_bool follow_location;
++ char location[HTTP_HEADER_BLOCK_SIZE];
++} php_stream_http_response_header_info;
++
++static void php_stream_http_response_header_info_init(
++ php_stream_http_response_header_info *header_info)
++{
++ header_info->transfer_encoding = NULL;
++ header_info->file_size = 0;
++ header_info->follow_location = 1;
++ header_info->location[0] = '\0';
++}
++
++/* Trim white spaces from response header line and update its length */
++static zend_bool php_stream_http_response_header_trim(char *http_header_line,
++ size_t *http_header_line_length)
++{
++ char *http_header_line_end = http_header_line + *http_header_line_length - 1;
++ while (http_header_line_end >= http_header_line &&
++ (*http_header_line_end == '\n' || *http_header_line_end == '\r')) {
++ http_header_line_end--;
++ }
++
++ /* The primary definition of an HTTP header in RFC 7230 states:
++ * > Each header field consists of a case-insensitive field name followed
++ * > by a colon (":"), optional leading whitespace, the field value, and
++ * > optional trailing whitespace. */
++
++ /* Strip trailing whitespace */
++ zend_bool space_trim = (*http_header_line_end == ' ' || *http_header_line_end == '\t');
++ if (space_trim) {
++ do {
++ http_header_line_end--;
++ } while (http_header_line_end >= http_header_line &&
++ (*http_header_line_end == ' ' || *http_header_line_end == '\t'));
++ }
++ http_header_line_end++;
++ *http_header_line_end = '\0';
++ *http_header_line_length = http_header_line_end - http_header_line;
++
++ return space_trim;
++}
++
++/* Process folding headers of the current line and if there are none, parse last full response
++ * header line. It returns NULL if the last header is finished, otherwise it returns updated
++ * last header line. */
++static zend_string *php_stream_http_response_headers_parse(php_stream *stream,
++ php_stream_context *context, int options, zend_string *last_header_line_str,
++ char *header_line, size_t *header_line_length, int response_code,
++ zval *response_header, php_stream_http_response_header_info *header_info)
++{
++ char *last_header_line = ZSTR_VAL(last_header_line_str);
++ size_t last_header_line_length = ZSTR_LEN(last_header_line_str);
++ char *last_header_line_end = ZSTR_VAL(last_header_line_str) + ZSTR_LEN(last_header_line_str) - 1;
++
++ /* Process non empty header line. */
++ if (header_line && (*header_line != '\n' && *header_line != '\r')) {
++ /* Removing trailing white spaces. */
++ if (php_stream_http_response_header_trim(header_line, header_line_length) &&
++ *header_line_length == 0) {
++ /* Only spaces so treat as an empty folding header. */
++ return last_header_line_str;
++ }
++
++ /* Process folding headers if starting with a space or a tab. */
++ if (header_line && (*header_line == ' ' || *header_line == '\t')) {
++ char *http_folded_header_line = header_line;
++ size_t http_folded_header_line_length = *header_line_length;
++ /* Remove the leading white spaces. */
++ while (*http_folded_header_line == ' ' || *http_folded_header_line == '\t') {
++ http_folded_header_line++;
++ http_folded_header_line_length--;
++ }
++ /* It has to have some characters because it would get returned after the call
++ * php_stream_http_response_header_trim above. */
++ ZEND_ASSERT(http_folded_header_line_length > 0);
++ /* Concatenate last header line, space and current header line. */
++ zend_string *extended_header_str = zend_string_alloc(last_header_line_length + 1 + http_folded_header_line_length, 0);
++ memcpy(ZSTR_VAL(extended_header_str), last_header_line, last_header_line_length);
++ ZSTR_VAL(extended_header_str)[last_header_line_length] = ' ';
++ memcpy(ZSTR_VAL(extended_header_str) + last_header_line_length + 1, http_folded_header_line, http_folded_header_line_length);
++ ZSTR_VAL(extended_header_str)[ZSTR_LEN(extended_header_str)] = 0;
++ zend_string_efree(last_header_line_str);
++ last_header_line_str = extended_header_str;
++ /* Return new header line. */
++ return last_header_line_str;
++ }
++ }
++
++ /* Find header separator position. */
++ char *last_header_value = memchr(last_header_line, ':', last_header_line_length);
++ if (last_header_value) {
++ last_header_value++; /* Skip ':'. */
++
++ /* Strip leading whitespace. */
++ while (last_header_value < last_header_line_end
++ && (*last_header_value == ' ' || *last_header_value == '\t')) {
++ last_header_value++;
++ }
++ } else {
++ /* There is no colon. Set the value to the end of the header line, which is effectively
++ * an empty string. */
++ last_header_value = last_header_line_end;
++ }
++
++ zend_bool store_header = 1;
++ zval *tmpzval = NULL;
++
++ if (!strncasecmp(last_header_line, "Location:", sizeof("Location:")-1)) {
++ /* Check if the location should be followed. */
++ if (context && (tmpzval = php_stream_context_get_option(context, "http", "follow_location")) != NULL) {
++ header_info->follow_location = zval_is_true(tmpzval);
++ } else if (!((response_code >= 300 && response_code < 304)
++ || 307 == response_code || 308 == response_code)) {
++ /* The redirection should not be automatic if follow_location is not set and
++ * response_code not in (300, 301, 302, 303 and 307)
++ * see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.1
++ * RFC 7238 defines 308: http://tools.ietf.org/html/rfc7238 */
++ header_info->follow_location = 0;
++ }
++ strlcpy(header_info->location, last_header_value, sizeof(header_info->location));
++ } else if (!strncasecmp(last_header_line, "Content-Type:", sizeof("Content-Type:")-1)) {
++ php_stream_notify_info(context, PHP_STREAM_NOTIFY_MIME_TYPE_IS, last_header_value, 0);
++ } else if (!strncasecmp(last_header_line, "Content-Length:", sizeof("Content-Length:")-1)) {
++ header_info->file_size = atoi(last_header_value);
++ php_stream_notify_file_size(context, header_info->file_size, last_header_line, 0);
++ } else if (
++ !strncasecmp(last_header_line, "Transfer-Encoding:", sizeof("Transfer-Encoding:")-1)
++ && !strncasecmp(last_header_value, "Chunked", sizeof("Chunked")-1)
++ ) {
++ /* Create filter to decode response body. */
++ if (!(options & STREAM_ONLY_GET_HEADERS)) {
++ zend_long decode = 1;
++
++ if (context && (tmpzval = php_stream_context_get_option(context, "http", "auto_decode")) != NULL) {
++ decode = zend_is_true(tmpzval);
++ }
++ if (decode) {
++ if (header_info->transfer_encoding != NULL) {
++ /* Prevent a memory leak in case there are more transfer-encoding headers. */
++ php_stream_filter_free(header_info->transfer_encoding);
++ }
++ header_info->transfer_encoding = php_stream_filter_create(
++ "dechunk", NULL, php_stream_is_persistent(stream));
++ if (header_info->transfer_encoding != NULL) {
++ /* Do not store transfer-encoding header. */
++ store_header = 0;
++ }
++ }
++ }
++ }
++
++ if (store_header) {
++ zval http_header;
++ ZVAL_NEW_STR(&http_header, last_header_line_str);
++ zend_hash_next_index_insert(Z_ARRVAL_P(response_header), &http_header);
++ } else {
++ zend_string_efree(last_header_line_str);
++ }
++
++ return NULL;
++}
++
+ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
+ const char *path, const char *mode, int options, zend_string **opened_path,
+ php_stream_context *context, int redirect_max, int flags,
+@@ -128,11 +294,12 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
+ zend_string *tmp = NULL;
+ char *ua_str = NULL;
+ zval *ua_zval = NULL, *tmpzval = NULL, ssl_proxy_peer_name;
+- char location[HTTP_HEADER_BLOCK_SIZE];
+ int reqok = 0;
+ char *http_header_line = NULL;
++ zend_string *last_header_line_str = NULL;
++ php_stream_http_response_header_info header_info;
+ char tmp_line[128];
+- size_t chunk_size = 0, file_size = 0;
++ size_t chunk_size = 0;
+ int eol_detect = 0;
+ char *transport_string;
+ zend_string *errstr = NULL;
+@@ -143,8 +310,6 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
+ char *user_headers = NULL;
+ int header_init = ((flags & HTTP_WRAPPER_HEADER_INIT) != 0);
+ int redirected = ((flags & HTTP_WRAPPER_REDIRECTED) != 0);
+- zend_bool follow_location = 1;
+- php_stream_filter *transfer_encoding = NULL;
+ int response_code;
+ smart_str req_buf = {0};
+ zend_bool custom_request_method;
+@@ -657,8 +822,6 @@ finish:
+ /* send it */
+ php_stream_write(stream, ZSTR_VAL(req_buf.s), ZSTR_LEN(req_buf.s));
+
+- location[0] = '\0';
+-
+ if (Z_ISUNDEF_P(response_header)) {
+ array_init(response_header);
+ }
+@@ -736,125 +899,101 @@ finish:
+ }
+ }
+
+- /* read past HTTP headers */
++ php_stream_http_response_header_info_init(&header_info);
+
++ /* read past HTTP headers */
+ while (!php_stream_eof(stream)) {
+ size_t http_header_line_length;
+
+ if (http_header_line != NULL) {
+ efree(http_header_line);
+ }
+- if ((http_header_line = php_stream_get_line(stream, NULL, 0, &http_header_line_length)) && *http_header_line != '\n' && *http_header_line != '\r') {
+- char *e = http_header_line + http_header_line_length - 1;
+- char *http_header_value;
+-
+- while (e >= http_header_line && (*e == '\n' || *e == '\r')) {
+- e--;
+- }
+-
+- /* The primary definition of an HTTP header in RFC 7230 states:
+- * > Each header field consists of a case-insensitive field name followed
+- * > by a colon (":"), optional leading whitespace, the field value, and
+- * > optional trailing whitespace. */
+-
+- /* Strip trailing whitespace */
+- while (e >= http_header_line && (*e == ' ' || *e == '\t')) {
+- e--;
+- }
+-
+- /* Terminate header line */
+- e++;
+- *e = '\0';
+- http_header_line_length = e - http_header_line;
+-
+- http_header_value = memchr(http_header_line, ':', http_header_line_length);
+- if (http_header_value) {
+- http_header_value++; /* Skip ':' */
+-
+- /* Strip leading whitespace */
+- while (http_header_value < e
+- && (*http_header_value == ' ' || *http_header_value == '\t')) {
+- http_header_value++;
++ if ((http_header_line = php_stream_get_line(stream, NULL, 0, &http_header_line_length))) {
++ zend_bool last_line;
++ if (*http_header_line == '\r') {
++ if (http_header_line[1] != '\n') {
++ php_stream_close(stream);
++ stream = NULL;
++ php_stream_wrapper_log_error(wrapper, options,
++ "HTTP invalid header name (cannot start with CR character)!");
++ goto out;
+ }
++ last_line = 1;
++ } else if (*http_header_line == '\n') {
++ last_line = 1;
+ } else {
+- /* There is no colon. Set the value to the end of the header line, which is
+- * effectively an empty string. */
+- http_header_value = e;
++ last_line = 0;
+ }
+-
+- if (!strncasecmp(http_header_line, "Location:", sizeof("Location:")-1)) {
+- if (context && (tmpzval = php_stream_context_get_option(context, "http", "follow_location")) != NULL) {
+- follow_location = zval_is_true(tmpzval);
+- } else if (!((response_code >= 300 && response_code < 304)
+- || 307 == response_code || 308 == response_code)) {
+- /* we shouldn't redirect automatically
+- if follow_location isn't set and response_code not in (300, 301, 302, 303 and 307)
+- see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.1
+- RFC 7238 defines 308: http://tools.ietf.org/html/rfc7238 */
+- follow_location = 0;
++
++ if (last_header_line_str != NULL) {
++ /* Parse last header line. */
++ last_header_line_str = php_stream_http_response_headers_parse(stream, context,
++ options, last_header_line_str, http_header_line, &http_header_line_length,
++ response_code, response_header, &header_info);
++ if (last_header_line_str != NULL) {
++ /* Folding header present so continue. */
++ continue;
+ }
+- strlcpy(location, http_header_value, sizeof(location));
+- } else if (!strncasecmp(http_header_line, "Content-Type:", sizeof("Content-Type:")-1)) {
+- php_stream_notify_info(context, PHP_STREAM_NOTIFY_MIME_TYPE_IS, http_header_value, 0);
+- } else if (!strncasecmp(http_header_line, "Content-Length:", sizeof("Content-Length:")-1)) {
+- file_size = atoi(http_header_value);
+- php_stream_notify_file_size(context, file_size, http_header_line, 0);
+- } else if (
+- !strncasecmp(http_header_line, "Transfer-Encoding:", sizeof("Transfer-Encoding:")-1)
+- && !strncasecmp(http_header_value, "Chunked", sizeof("Chunked")-1)
+- ) {
+-
+- /* create filter to decode response body */
+- if (!(options & STREAM_ONLY_GET_HEADERS)) {
+- zend_long decode = 1;
+-
+- if (context && (tmpzval = php_stream_context_get_option(context, "http", "auto_decode")) != NULL) {
+- decode = zend_is_true(tmpzval);
+- }
+- if (decode) {
+- transfer_encoding = php_stream_filter_create("dechunk", NULL, php_stream_is_persistent(stream));
+- if (transfer_encoding) {
+- /* don't store transfer-encodeing header */
+- continue;
+- }
+- }
++ } else if (!last_line) {
++ /* The first line cannot start with spaces. */
++ if (*http_header_line == ' ' || *http_header_line == '\t') {
++ php_stream_close(stream);
++ stream = NULL;
++ php_stream_wrapper_log_error(wrapper, options,
++ "HTTP invalid response format (folding header at the start)!");
++ goto out;
+ }
++ /* Trim the first line if it is not the last line. */
++ php_stream_http_response_header_trim(http_header_line, &http_header_line_length);
+ }
+-
+- {
+- zval http_header;
+- ZVAL_STRINGL(&http_header, http_header_line, http_header_line_length);
+- zend_hash_next_index_insert(Z_ARRVAL_P(response_header), &http_header);
++ if (last_line) {
++ /* For the last line the last header line must be NULL. */
++ ZEND_ASSERT(last_header_line_str == NULL);
++ break;
+ }
++ /* Save current line as the last line so it gets parsed in the next round. */
++ last_header_line_str = zend_string_init(http_header_line, http_header_line_length, 0);
+ } else {
+ break;
+ }
+ }
+
+- if (!reqok || (location[0] != '\0' && follow_location)) {
+- if (!follow_location || (((options & STREAM_ONLY_GET_HEADERS) || ignore_errors) && redirect_max <= 1)) {
++ /* If the stream was closed early, we still want to process the last line to keep BC. */
++ if (last_header_line_str != NULL) {
++ php_stream_http_response_headers_parse(stream, context, options, last_header_line_str,
++ NULL, NULL, response_code, response_header, &header_info);
++ }
++
++ if (!reqok || (header_info.location[0] != '\0' && header_info.follow_location)) {
++ if (!header_info.follow_location || (((options & STREAM_ONLY_GET_HEADERS) || ignore_errors) && redirect_max <= 1)) {
+ goto out;
+ }
+
+- if (location[0] != '\0')
+- php_stream_notify_info(context, PHP_STREAM_NOTIFY_REDIRECTED, location, 0);
++ if (header_info.location[0] != '\0')
++ php_stream_notify_info(context, PHP_STREAM_NOTIFY_REDIRECTED, header_info.location, 0);
+
+ php_stream_close(stream);
+ stream = NULL;
+
+- if (location[0] != '\0') {
++ if (header_info.transfer_encoding) {
++ php_stream_filter_free(header_info.transfer_encoding);
++ header_info.transfer_encoding = NULL;
++ }
++
++ if (header_info.location[0] != '\0') {
+
+ char new_path[HTTP_HEADER_BLOCK_SIZE];
+ char loc_path[HTTP_HEADER_BLOCK_SIZE];
+
+ *new_path='\0';
+- if (strlen(location)<8 || (strncasecmp(location, "http://", sizeof("http://")-1) &&
+- strncasecmp(location, "https://", sizeof("https://")-1) &&
+- strncasecmp(location, "ftp://", sizeof("ftp://")-1) &&
+- strncasecmp(location, "ftps://", sizeof("ftps://")-1)))
++ if (strlen(header_info.location) < 8 ||
++ (strncasecmp(header_info.location, "http://", sizeof("http://")-1) &&
++ strncasecmp(header_info.location, "https://", sizeof("https://")-1) &&
++ strncasecmp(header_info.location, "ftp://", sizeof("ftp://")-1) &&
++ strncasecmp(header_info.location, "ftps://", sizeof("ftps://")-1)))
+ {
+- if (*location != '/') {
+- if (*(location+1) != '\0' && resource->path) {
++ if (*header_info.location != '/') {
++ if (*(header_info.location+1) != '\0' && resource->path) {
+ char *s = strrchr(ZSTR_VAL(resource->path), '/');
+ if (!s) {
+ s = ZSTR_VAL(resource->path);
+@@ -870,15 +1009,17 @@ finish:
+ if (resource->path &&
+ ZSTR_VAL(resource->path)[0] == '/' &&
+ ZSTR_VAL(resource->path)[1] == '\0') {
+- snprintf(loc_path, sizeof(loc_path) - 1, "%s%s", ZSTR_VAL(resource->path), location);
++ snprintf(loc_path, sizeof(loc_path) - 1, "%s%s",
++ ZSTR_VAL(resource->path), header_info.location);
+ } else {
+- snprintf(loc_path, sizeof(loc_path) - 1, "%s/%s", ZSTR_VAL(resource->path), location);
++ snprintf(loc_path, sizeof(loc_path) - 1, "%s/%s",
++ ZSTR_VAL(resource->path), header_info.location);
+ }
+ } else {
+- snprintf(loc_path, sizeof(loc_path) - 1, "/%s", location);
++ snprintf(loc_path, sizeof(loc_path) - 1, "/%s", header_info.location);
+ }
+ } else {
+- strlcpy(loc_path, location, sizeof(loc_path));
++ strlcpy(loc_path, header_info.location, sizeof(loc_path));
+ }
+ if ((use_ssl && resource->port != 443) || (!use_ssl && resource->port != 80)) {
+ snprintf(new_path, sizeof(new_path) - 1, "%s://%s:%d%s", ZSTR_VAL(resource->scheme), ZSTR_VAL(resource->host), resource->port, loc_path);
+@@ -886,7 +1027,7 @@ finish:
+ snprintf(new_path, sizeof(new_path) - 1, "%s://%s%s", ZSTR_VAL(resource->scheme), ZSTR_VAL(resource->host), loc_path);
+ }
+ } else {
+- strlcpy(new_path, location, sizeof(new_path));
++ strlcpy(new_path, header_info.location, sizeof(new_path));
+ }
+
+ php_url_free(resource);
+@@ -939,7 +1080,7 @@ out:
+ if (header_init) {
+ ZVAL_COPY(&stream->wrapperdata, response_header);
+ }
+- php_stream_notify_progress_init(context, 0, file_size);
++ php_stream_notify_progress_init(context, 0, header_info.file_size);
+
+ /* Restore original chunk size now that we're done with headers */
+ if (options & STREAM_WILL_CAST)
+@@ -955,12 +1096,8 @@ out:
+ /* restore mode */
+ strlcpy(stream->mode, mode, sizeof(stream->mode));
+
+- if (transfer_encoding) {
+- php_stream_filter_append(&stream->readfilters, transfer_encoding);
+- }
+- } else {
+- if (transfer_encoding) {
+- php_stream_filter_free(transfer_encoding);
++ if (header_info.transfer_encoding) {
++ php_stream_filter_append(&stream->readfilters, header_info.transfer_encoding);
+ }
+ }
+
+diff --git a/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-001.phpt b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-001.phpt
+new file mode 100644
+index 00000000000..64904bfcd1d
+--- /dev/null
++++ b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-001.phpt
+@@ -0,0 +1,49 @@
++--TEST--
++GHSA-v8xr-gpvj-cx9g: Header parser of http stream wrapper does not handle folded headers (single)
++--FILE--
++<?php
++$serverCode = <<<'CODE'
++ $ctxt = stream_context_create([
++ "socket" => [
++ "tcp_nodelay" => true
++ ]
++ ]);
++
++ $server = stream_socket_server(
++ "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt);
++ phpt_notify_server_start($server);
++
++ $conn = stream_socket_accept($server);
++
++ phpt_notify(WORKER_DEFAULT_NAME, "server-accepted");
++
++ fwrite($conn, "HTTP/1.0 200 Ok\r\nContent-Type: text/html;\r\n charset=utf-8\r\n\r\nbody\r\n");
++CODE;
++
++$clientCode = <<<'CODE'
++ function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) {
++ switch($notification_code) {
++ case STREAM_NOTIFY_MIME_TYPE_IS:
++ echo "Found the mime-type: ", $message, PHP_EOL;
++ break;
++ }
++ }
++
++ $ctx = stream_context_create();
++ stream_context_set_params($ctx, array("notification" => "stream_notification_callback"));
++ var_dump(trim(file_get_contents("http://{{ ADDR }}", false, $ctx)));
++ var_dump($http_response_header);
++CODE;
++
++include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
++ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
++?>
++--EXPECTF--
++Found the mime-type: text/html; charset=utf-8
++string(4) "body"
++array(2) {
++ [0]=>
++ string(15) "HTTP/1.0 200 Ok"
++ [1]=>
++ string(38) "Content-Type: text/html; charset=utf-8"
++}
+diff --git a/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-002.phpt b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-002.phpt
+new file mode 100644
+index 00000000000..a6d9d00fd58
+--- /dev/null
++++ b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-002.phpt
+@@ -0,0 +1,51 @@
++--TEST--
++GHSA-v8xr-gpvj-cx9g: Header parser of http stream wrapper does not handle folded headers (multiple)
++--FILE--
++<?php
++$serverCode = <<<'CODE'
++ $ctxt = stream_context_create([
++ "socket" => [
++ "tcp_nodelay" => true
++ ]
++ ]);
++
++ $server = stream_socket_server(
++ "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt);
++ phpt_notify_server_start($server);
++
++ $conn = stream_socket_accept($server);
++
++ phpt_notify(WORKER_DEFAULT_NAME, "server-accepted");
++
++ fwrite($conn, "HTTP/1.0 200 Ok\r\nContent-Type: text/html;\r\nCustom-Header: somevalue;\r\n param1=value1; \r\n param2=value2\r\n\r\nbody\r\n");
++CODE;
++
++$clientCode = <<<'CODE'
++ function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) {
++ switch($notification_code) {
++ case STREAM_NOTIFY_MIME_TYPE_IS:
++ echo "Found the mime-type: ", $message, PHP_EOL;
++ break;
++ }
++ }
++
++ $ctx = stream_context_create();
++ stream_context_set_params($ctx, array("notification" => "stream_notification_callback"));
++ var_dump(trim(file_get_contents("http://{{ ADDR }}", false, $ctx)));
++ var_dump($http_response_header);
++CODE;
++
++include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
++ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
++?>
++--EXPECTF--
++Found the mime-type: text/html;
++string(4) "body"
++array(3) {
++ [0]=>
++ string(15) "HTTP/1.0 200 Ok"
++ [1]=>
++ string(24) "Content-Type: text/html;"
++ [2]=>
++ string(54) "Custom-Header: somevalue; param1=value1; param2=value2"
++}
+diff --git a/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-003.phpt b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-003.phpt
+new file mode 100644
+index 00000000000..4eff7fc63f3
+--- /dev/null
++++ b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-003.phpt
+@@ -0,0 +1,49 @@
++--TEST--
++GHSA-v8xr-gpvj-cx9g: Header parser of http stream wrapper does not handle folded headers (empty)
++--FILE--
++<?php
++$serverCode = <<<'CODE'
++ $ctxt = stream_context_create([
++ "socket" => [
++ "tcp_nodelay" => true
++ ]
++ ]);
++
++ $server = stream_socket_server(
++ "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt);
++ phpt_notify_server_start($server);
++
++ $conn = stream_socket_accept($server);
++
++ phpt_notify(WORKER_DEFAULT_NAME, "server-accepted");
++
++ fwrite($conn, "HTTP/1.0 200 Ok\r\nContent-Type: text/html;\r\n \r\n charset=utf-8\r\n\r\nbody\r\n");
++CODE;
++
++$clientCode = <<<'CODE'
++ function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) {
++ switch($notification_code) {
++ case STREAM_NOTIFY_MIME_TYPE_IS:
++ echo "Found the mime-type: ", $message, PHP_EOL;
++ break;
++ }
++ }
++
++ $ctx = stream_context_create();
++ stream_context_set_params($ctx, array("notification" => "stream_notification_callback"));
++ var_dump(trim(file_get_contents("http://{{ ADDR }}", false, $ctx)));
++ var_dump($http_response_header);
++CODE;
++
++include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
++ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
++?>
++--EXPECTF--
++Found the mime-type: text/html; charset=utf-8
++string(4) "body"
++array(2) {
++ [0]=>
++ string(15) "HTTP/1.0 200 Ok"
++ [1]=>
++ string(38) "Content-Type: text/html; charset=utf-8"
++}
+diff --git a/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-004.phpt b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-004.phpt
+new file mode 100644
+index 00000000000..71aed2fa2e8
+--- /dev/null
++++ b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-004.phpt
+@@ -0,0 +1,48 @@
++--TEST--
++GHSA-v8xr-gpvj-cx9g: Header parser of http stream wrapper does not handle folded headers (first line)
++--FILE--
++<?php
++$serverCode = <<<'CODE'
++ $ctxt = stream_context_create([
++ "socket" => [
++ "tcp_nodelay" => true
++ ]
++ ]);
++
++ $server = stream_socket_server(
++ "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt);
++ phpt_notify_server_start($server);
++
++ $conn = stream_socket_accept($server);
++
++ phpt_notify(WORKER_DEFAULT_NAME, "server-accepted");
++
++ fwrite($conn, "HTTP/1.0 200 Ok\r\n Content-Type: text/html;\r\n \r\n charset=utf-8\r\n\r\nbody\r\n");
++CODE;
++
++$clientCode = <<<'CODE'
++ function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) {
++ switch($notification_code) {
++ case STREAM_NOTIFY_MIME_TYPE_IS:
++ echo "Found the mime-type: ", $message, PHP_EOL;
++ break;
++ }
++ }
++
++ $ctx = stream_context_create();
++ stream_context_set_params($ctx, array("notification" => "stream_notification_callback"));
++ var_dump(file_get_contents("http://{{ ADDR }}", false, $ctx));
++ var_dump($http_response_header);
++CODE;
++
++include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
++ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
++?>
++--EXPECTF--
++
++Warning: file_get_contents(http://127.0.0.1:%d): failed to open stream: HTTP invalid response format (folding header at the start)! in %s
++bool(false)
++array(1) {
++ [0]=>
++ string(15) "HTTP/1.0 200 Ok"
++}
+diff --git a/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-005.phpt b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-005.phpt
+new file mode 100644
+index 00000000000..49d845d84b4
+--- /dev/null
++++ b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-005.phpt
+@@ -0,0 +1,48 @@
++--TEST--
++GHSA-v8xr-gpvj-cx9g: Header parser of http stream wrapper does not handle folded headers (CR before header name)
++--FILE--
++<?php
++$serverCode = <<<'CODE'
++ $ctxt = stream_context_create([
++ "socket" => [
++ "tcp_nodelay" => true
++ ]
++ ]);
++
++ $server = stream_socket_server(
++ "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt);
++ phpt_notify_server_start($server);
++
++ $conn = stream_socket_accept($server);
++
++ phpt_notify(WORKER_DEFAULT_NAME, "server-accepted");
++
++ fwrite($conn, "HTTP/1.0 200 Ok\r\n\rIgnored: ignored\r\n\r\nbody\r\n");
++CODE;
++
++$clientCode = <<<'CODE'
++ function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) {
++ switch($notification_code) {
++ case STREAM_NOTIFY_MIME_TYPE_IS:
++ echo "Found the mime-type: ", $message, PHP_EOL;
++ break;
++ }
++ }
++
++ $ctx = stream_context_create();
++ stream_context_set_params($ctx, array("notification" => "stream_notification_callback"));
++ var_dump(file_get_contents("http://{{ ADDR }}", false, $ctx));
++ var_dump($http_response_header);
++CODE;
++
++include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
++ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
++?>
++--EXPECTF--
++
++Warning: file_get_contents(http://127.0.0.1:%d): failed to open stream: HTTP invalid header name (cannot start with CR character)! in %s
++bool(false)
++array(1) {
++ [0]=>
++ string(15) "HTTP/1.0 200 Ok"
++}
+diff --git a/ext/standard/tests/http/http_response_header_05.phpt b/ext/standard/tests/http/http_response_header_05.phpt
+deleted file mode 100644
+index dbdd7b8b1a0..00000000000
+--- a/ext/standard/tests/http/http_response_header_05.phpt
++++ /dev/null
+@@ -1,35 +0,0 @@
+---TEST--
+-$http_reponse_header (whitespace-only "header")
+---SKIPIF--
+-<?php require 'server.inc'; http_server_skipif('tcp://127.0.0.1:22350'); ?>
+---INI--
+-allow_url_fopen=1
+---FILE--
+-<?php
+-require 'server.inc';
+-
+-$responses = array(
+- "data://text/plain,HTTP/1.0 200 Ok\r\n \r\n\r\nBody",
+-);
+-
+-$pid = http_server("tcp://127.0.0.1:22350", $responses, $output);
+-
+-function test() {
+- $f = file_get_contents('http://127.0.0.1:22350/');
+- var_dump($f);
+- var_dump($http_response_header);
+-}
+-test();
+-
+-http_server_kill($pid);
+-?>
+-==DONE==
+---EXPECT--
+-string(4) "Body"
+-array(2) {
+- [0]=>
+- string(15) "HTTP/1.0 200 Ok"
+- [1]=>
+- string(0) ""
+-}
+-==DONE==
+--
+2.48.1
+
diff --git a/php-cve-2025-1219.patch b/php-cve-2025-1219.patch
new file mode 100644
index 0000000..5d164b6
--- /dev/null
+++ b/php-cve-2025-1219.patch
@@ -0,0 +1,1906 @@
+From 8a2195d2c64e0323d05656238c5c72414e8ad340 Mon Sep 17 00:00:00 2001
+From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
+Date: Sat, 29 Apr 2023 21:07:50 +0200
+Subject: [PATCH 05/11] Fix GH-11160: Few tests failed building with new libxml
+ 2.11.0
+
+It's possible to categorise the failures into 2 categories:
+ - Changed error message. In this case we either duplicate the test and
+ modify the error message. Or if the change in error message is
+ small, we use the EXPECTF matchers to make the test compatible with both
+ old and new versions of libxml2.
+ - Missing warnings. This is caused by a change in libxml2 where the
+ parser started using SAX APIs internally [1]. In this case the
+ error_type passed to php_libxml_internal_error_handler() changed from
+ PHP_LIBXML_ERROR to PHP_LIBXML_CTX_WARNING because it internally
+ started to use the SAX handlers instead of the generic handlers.
+ However, for the SAX handlers the current input stack is empty, so
+ nothing is actually printed. I fixed this by falling back to a
+ regular warning without a filename & line number reference, which
+ mimicks the old behaviour. Furthermore, this change now also shows
+ an additional warning in a test which was previously hidden.
+
+[1] https://gitlab.gnome.org/GNOME/libxml2/-/commit/9a82b94a94bd310db426edd453b0f38c6c8f69f5
+
+Closes GH-11162.
+
+(cherry picked from commit 7c0dfc5cf58d3c445b935fa14ea8f5f13568c419)
+(cherry picked from commit 78ae0886bd1a3e42c53c9ba65764b6e6357640b5)
+---
+ .../DOMDocument_loadXML_error2_gte2_11.phpt | 34 +++
+ ...> DOMDocument_loadXML_error2_pre2_11.phpt} | 7 +-
+ .../DOMDocument_load_error2_gte2_11.phpt | 34 +++
+ ...t => DOMDocument_load_error2_pre2_11.phpt} | 7 +-
+ ext/libxml/libxml.c | 2 +
+ ext/libxml/tests/bug61367-read_2.phpt | 2 +-
+ .../tests/libxml_disable_entity_loader_2.phpt | 2 +-
+ ...xml_set_external_entity_loader_error1.phpt | 2 +
+ ...set_external_entity_loader_variation2.phpt | 2 +
+ ext/openssl/tests/ServerClientTestCase.inc | 65 ++----
+ .../tests/http/ServerClientTestCase.inc | 199 ++++++++++++++++++
+ .../tests/http/ghsa-52jp-hrpf-2jff-001.phpt | 2 +-
+ .../tests/http/ghsa-52jp-hrpf-2jff-002.phpt | 2 +-
+ .../tests/http/ghsa-hgf5-96fm-v528-001.phpt | 2 +-
+ .../tests/http/ghsa-hgf5-96fm-v528-002.phpt | 2 +-
+ .../tests/http/ghsa-hgf5-96fm-v528-003.phpt | 2 +-
+ .../tests/http/ghsa-pcmh-g36c-qc44-001.phpt | 2 +-
+ .../tests/http/ghsa-pcmh-g36c-qc44-002.phpt | 2 +-
+ .../tests/http/ghsa-v8xr-gpvj-cx9g-001.phpt | 2 +-
+ .../tests/http/ghsa-v8xr-gpvj-cx9g-002.phpt | 2 +-
+ .../tests/http/ghsa-v8xr-gpvj-cx9g-003.phpt | 2 +-
+ .../tests/http/ghsa-v8xr-gpvj-cx9g-004.phpt | 2 +-
+ .../tests/http/ghsa-v8xr-gpvj-cx9g-005.phpt | 2 +-
+ ext/xml/tests/bug26614_libxml_gte2_11.phpt | 95 +++++++++
+ ...bxml.phpt => bug26614_libxml_pre2_11.phpt} | 1 +
+ 25 files changed, 408 insertions(+), 68 deletions(-)
+ create mode 100644 ext/dom/tests/DOMDocument_loadXML_error2_gte2_11.phpt
+ rename ext/dom/tests/{DOMDocument_loadXML_error2.phpt => DOMDocument_loadXML_error2_pre2_11.phpt} (89%)
+ create mode 100644 ext/dom/tests/DOMDocument_load_error2_gte2_11.phpt
+ rename ext/dom/tests/{DOMDocument_load_error2.phpt => DOMDocument_load_error2_pre2_11.phpt} (89%)
+ create mode 100644 ext/standard/tests/http/ServerClientTestCase.inc
+ create mode 100644 ext/xml/tests/bug26614_libxml_gte2_11.phpt
+ rename ext/xml/tests/{bug26614_libxml.phpt => bug26614_libxml_pre2_11.phpt} (96%)
+
+diff --git a/ext/dom/tests/DOMDocument_loadXML_error2_gte2_11.phpt b/ext/dom/tests/DOMDocument_loadXML_error2_gte2_11.phpt
+new file mode 100644
+index 00000000000..ff5ceb3fbed
+--- /dev/null
++++ b/ext/dom/tests/DOMDocument_loadXML_error2_gte2_11.phpt
+@@ -0,0 +1,34 @@
++--TEST--
++Test DOMDocument::loadXML() detects not-well formed XML
++--SKIPIF--
++<?php
++if (LIBXML_VERSION < 21100) die('skip libxml2 test variant for version >= 2.11');
++?>
++--DESCRIPTION--
++This test verifies the method detects attributes values not closed between " or '
++Environment variables used in the test:
++- XML_FILE: the xml file to load
++- LOAD_OPTIONS: the second parameter to pass to the method
++- EXPECTED_RESULT: the expected result
++--CREDITS--
++Antonio Diaz Ruiz <dejalatele@gmail.com>
++--INI--
++assert.bail=true
++--EXTENSIONS--
++dom
++--ENV--
++XML_FILE=/not_well_formed2.xml
++LOAD_OPTIONS=0
++EXPECTED_RESULT=0
++--FILE_EXTERNAL--
++domdocumentloadxml_test_method.inc
++--EXPECTF--
++Warning: DOMDocument::loadXML(): AttValue: " or ' expected in Entity, line: 4 in %s on line %d
++
++Warning: DOMDocument::loadXML(): internal error: xmlParseStartTag: problem parsing attributes in Entity, line: 4 in %s on line %d
++
++Warning: DOMDocument::loadXML(): Couldn't find end of Start Tag book line 4 in Entity, line: 4 in %s on line %d
++
++Warning: DOMDocument::loadXML(): Opening and ending tag mismatch: books line 3 and book in Entity, line: 7 in %s on line %d
++
++Warning: DOMDocument::loadXML(): Extra content at the end of the document in Entity, line: 8 in %s on line %d
+diff --git a/ext/dom/tests/DOMDocument_loadXML_error2.phpt b/ext/dom/tests/DOMDocument_loadXML_error2_pre2_11.phpt
+similarity index 89%
+rename from ext/dom/tests/DOMDocument_loadXML_error2.phpt
+rename to ext/dom/tests/DOMDocument_loadXML_error2_pre2_11.phpt
+index 6d56a317ed7..7e10771fdb7 100644
+--- a/ext/dom/tests/DOMDocument_loadXML_error2.phpt
++++ b/ext/dom/tests/DOMDocument_loadXML_error2_pre2_11.phpt
+@@ -1,5 +1,10 @@
+ --TEST--
+ Test DOMDocument::loadXML() detects not-well formed XML
++--SKIPIF--
++<?php
++include('skipif.inc');
++if (LIBXML_VERSION >= 21100) die('skip libxml2 test variant for version < 2.11');
++?>
+ --DESCRIPTION--
+ This test verifies the method detects attributes values not closed between " or '
+ Environment variables used in the test:
+@@ -10,8 +15,6 @@ Environment variables used in the test:
+ Antonio Diaz Ruiz <dejalatele@gmail.com>
+ --INI--
+ assert.bail=true
+---SKIPIF--
+-<?php include('skipif.inc'); ?>
+ --ENV--
+ XML_FILE=/not_well_formed2.xml
+ LOAD_OPTIONS=0
+diff --git a/ext/dom/tests/DOMDocument_load_error2_gte2_11.phpt b/ext/dom/tests/DOMDocument_load_error2_gte2_11.phpt
+new file mode 100644
+index 00000000000..32b6bf16114
+--- /dev/null
++++ b/ext/dom/tests/DOMDocument_load_error2_gte2_11.phpt
+@@ -0,0 +1,34 @@
++--TEST--
++Test DOMDocument::load() detects not-well formed
++--SKIPIF--
++<?php
++if (LIBXML_VERSION < 21100) die('skip libxml2 test variant for version >= 2.11');
++?>
++--DESCRIPTION--
++This test verifies the method detects attributes values not closed between " or '
++Environment variables used in the test:
++- XML_FILE: the xml file to load
++- LOAD_OPTIONS: the second parameter to pass to the method
++- EXPECTED_RESULT: the expected result
++--CREDITS--
++Antonio Diaz Ruiz <dejalatele@gmail.com>
++--INI--
++assert.bail=true
++--EXTENSIONS--
++dom
++--ENV--
++XML_FILE=/not_well_formed2.xml
++LOAD_OPTIONS=0
++EXPECTED_RESULT=0
++--FILE_EXTERNAL--
++domdocumentload_test_method.inc
++--EXPECTF--
++Warning: DOMDocument::load(): AttValue: " or ' expected in %s on line %d
++
++Warning: DOMDocument::load(): internal error: xmlParseStartTag: problem parsing attributes in %s on line %d
++
++Warning: DOMDocument::load(): Couldn't find end of Start Tag book line 4 in %s on line %d
++
++Warning: DOMDocument::load(): Opening and ending tag mismatch: books line 3 and book in %s on line %d
++
++Warning: DOMDocument::load(): Extra content at the end of the document in %s on line %d
+diff --git a/ext/dom/tests/DOMDocument_load_error2.phpt b/ext/dom/tests/DOMDocument_load_error2_pre2_11.phpt
+similarity index 89%
+rename from ext/dom/tests/DOMDocument_load_error2.phpt
+rename to ext/dom/tests/DOMDocument_load_error2_pre2_11.phpt
+index f450cf16545..74b20c171e0 100644
+--- a/ext/dom/tests/DOMDocument_load_error2.phpt
++++ b/ext/dom/tests/DOMDocument_load_error2_pre2_11.phpt
+@@ -1,5 +1,10 @@
+ --TEST--
+ Test DOMDocument::load() detects not-well formed XML
++--SKIPIF--
++<?php
++include('skipif.inc');
++if (LIBXML_VERSION >= 21100) die('skip libxml2 test variant for version < 2.11');
++?>
+ --DESCRIPTION--
+ This test verifies the method detects attributes values not closed between " or '
+ Environment variables used in the test:
+@@ -10,8 +15,6 @@ Environment variables used in the test:
+ Antonio Diaz Ruiz <dejalatele@gmail.com>
+ --INI--
+ assert.bail=true
+---SKIPIF--
+-<?php include('skipif.inc'); ?>
+ --ENV--
+ XML_FILE=/not_well_formed2.xml
+ LOAD_OPTIONS=0
+diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c
+index d343135b98d..5d9c23e0d7e 100644
+--- a/ext/libxml/libxml.c
++++ b/ext/libxml/libxml.c
+@@ -574,6 +574,8 @@ static void php_libxml_ctx_error_level(int level, void *ctx, const char *msg)
+ } else {
+ php_error_docref(NULL, level, "%s in Entity, line: %d", msg, parser->input->line);
+ }
++ } else {
++ php_error_docref(NULL, E_WARNING, "%s", msg);
+ }
+ }
+
+diff --git a/ext/libxml/tests/bug61367-read_2.phpt b/ext/libxml/tests/bug61367-read_2.phpt
+index 8cc0b50144c..12743adab1c 100644
+--- a/ext/libxml/tests/bug61367-read_2.phpt
++++ b/ext/libxml/tests/bug61367-read_2.phpt
+@@ -55,6 +55,6 @@ bool(true)
+ int(4)
+ bool(true)
+
+-Warning: DOMDocument::loadXML(): I/O warning : failed to load external entity "file:///%s/test_bug_61367-read/bad" in %s on line %d
++Warning: DOMDocument::loadXML(): %Sfailed to load external entity "file:///%s/test_bug_61367-read/bad" in %s on line %d
+
+ Notice: Trying to get property 'nodeValue' of non-object in %s on line %d
+diff --git a/ext/libxml/tests/libxml_disable_entity_loader_2.phpt b/ext/libxml/tests/libxml_disable_entity_loader_2.phpt
+index 845bd4bbe3c..55d8e61ee09 100644
+--- a/ext/libxml/tests/libxml_disable_entity_loader_2.phpt
++++ b/ext/libxml/tests/libxml_disable_entity_loader_2.phpt
+@@ -36,6 +36,6 @@ echo "Done\n";
+ bool(true)
+ bool(false)
+
+-Warning: DOMDocument::loadXML(): I/O warning : failed to load external entity "%s" in %s on line %d
++Warning: DOMDocument::loadXML(): %Sfailed to load external entity "%s" in %s on line %d
+ bool(true)
+ Done
+diff --git a/ext/libxml/tests/libxml_set_external_entity_loader_error1.phpt b/ext/libxml/tests/libxml_set_external_entity_loader_error1.phpt
+index 40b31ea85d3..00e06eb8a25 100644
+--- a/ext/libxml/tests/libxml_set_external_entity_loader_error1.phpt
++++ b/ext/libxml/tests/libxml_set_external_entity_loader_error1.phpt
+@@ -35,6 +35,8 @@ Warning: libxml_set_external_entity_loader() expects exactly 1 parameter, 2 give
+ NULL
+ bool(true)
+
++Warning: DOMDocument::validate(): Call to user entity loader callback %s
++
+ Warning: DOMDocument::validate(): Could not load the external subset "http://example.com/foobar" in %s on line %d
+ Exception: Too few arguments to function {closure}(), 3 passed and exactly 4 expected
+ Done.
+diff --git a/ext/libxml/tests/libxml_set_external_entity_loader_variation2.phpt b/ext/libxml/tests/libxml_set_external_entity_loader_variation2.phpt
+index e51869cf47f..0664de1ea6b 100644
+--- a/ext/libxml/tests/libxml_set_external_entity_loader_variation2.phpt
++++ b/ext/libxml/tests/libxml_set_external_entity_loader_variation2.phpt
+@@ -38,6 +38,8 @@ echo "Done.\n";
+ string(10) "-//FOO/BAR"
+ string(%d) "%sfoobar.dtd"
+
++Warning: DOMDocument::validate(): Failed to load external entity "-//FOO/BAR" in %s on line %d
++
+ Warning: DOMDocument::validate(): Could not load the external subset "foobar.dtd" in %s on line %d
+ bool(false)
+ bool(true)
+diff --git a/ext/openssl/tests/ServerClientTestCase.inc b/ext/openssl/tests/ServerClientTestCase.inc
+index c74da444102..753366df6f4 100644
+--- a/ext/openssl/tests/ServerClientTestCase.inc
++++ b/ext/openssl/tests/ServerClientTestCase.inc
+@@ -4,19 +4,14 @@ const WORKER_ARGV_VALUE = 'RUN_WORKER';
+
+ const WORKER_DEFAULT_NAME = 'server';
+
+-function phpt_notify(string $worker = WORKER_DEFAULT_NAME, string $message = ""): void
++function phpt_notify($worker = WORKER_DEFAULT_NAME)
+ {
+- ServerClientTestCase::getInstance()->notify($worker, $message);
++ ServerClientTestCase::getInstance()->notify($worker);
+ }
+
+-function phpt_wait($worker = WORKER_DEFAULT_NAME, $timeout = null): ?string
++function phpt_wait($worker = WORKER_DEFAULT_NAME, $timeout = null)
+ {
+- return ServerClientTestCase::getInstance()->wait($worker, $timeout);
+-}
+-
+-function phpt_notify_server_start($server): void
+-{
+- ServerClientTestCase::getInstance()->notify_server_start($server);
++ ServerClientTestCase::getInstance()->wait($worker, $timeout);
+ }
+
+ function phpt_has_sslv3() {
+@@ -124,73 +119,43 @@ class ServerClientTestCase
+ eval($code);
+ }
+
+- /**
+- * Run client and all workers
+- *
+- * @param string $clientCode The client PHP code
+- * @param string|array $workerCode
+- * @param bool $ephemeral Select whether automatic port selection and automatic awaiting is used
+- * @return void
+- * @throws Exception
+- */
+- public function run(string $clientCode, $workerCode, bool $ephemeral = true): void
++ public function run($masterCode, $workerCode)
+ {
+ if (!is_array($workerCode)) {
+ $workerCode = [WORKER_DEFAULT_NAME => $workerCode];
+ }
+- reset($workerCode);
+- $code = current($workerCode);
+- $worker = key($workerCode);
+- while ($worker != null) {
++ foreach ($workerCode as $worker => $code) {
+ $this->spawnWorkerProcess($worker, $this->stripPhpTagsFromCode($code));
+- $code = next($workerCode);
+- if ($ephemeral) {
+- $addr = trim($this->wait($worker));
+- if (empty($addr)) {
+- throw new \Exception("Failed server start");
+- }
+- if ($code === false) {
+- $clientCode = preg_replace('/{{\s*ADDR\s*}}/', $addr, $clientCode);
+- } else {
+- $code = preg_replace('/{{\s*ADDR\s*}}/', $addr, $code);
+- }
+- }
+- $worker = key($workerCode);
+ }
+-
+- eval($this->stripPhpTagsFromCode($clientCode));
++ eval($this->stripPhpTagsFromCode($masterCode));
+ foreach ($workerCode as $worker => $code) {
+ $this->cleanupWorkerProcess($worker);
+ }
+ }
+
+- public function wait($worker, $timeout = null): ?string
++ public function wait($worker, $timeout = null)
+ {
+ $handle = $this->isWorker ? STDIN : $this->workerStdOut[$worker];
+ if ($timeout === null) {
+- return fgets($handle);
++ fgets($handle);
++ return true;
+ }
+
+ stream_set_blocking($handle, false);
+ $read = [$handle];
+ $result = stream_select($read, $write, $except, $timeout);
+ if (!$result) {
+- return null;
++ return false;
+ }
+
+- $result = fgets($handle);
++ fgets($handle);
+ stream_set_blocking($handle, true);
+- return $result;
+- }
+-
+- public function notify(string $worker, string $message = ""): void
+- {
+- fwrite($this->isWorker ? STDOUT : $this->workerStdIn[$worker], "$message\n");
++ return true;
+ }
+
+- public function notify_server_start($server): void
++ public function notify($worker)
+ {
+- echo stream_socket_get_name($server, false) . "\n";
++ fwrite($this->isWorker ? STDOUT : $this->workerStdIn[$worker], "\n");
+ }
+ }
+
+diff --git a/ext/standard/tests/http/ServerClientTestCase.inc b/ext/standard/tests/http/ServerClientTestCase.inc
+new file mode 100644
+index 00000000000..c74da444102
+--- /dev/null
++++ b/ext/standard/tests/http/ServerClientTestCase.inc
+@@ -0,0 +1,199 @@
++<?php
++
++const WORKER_ARGV_VALUE = 'RUN_WORKER';
++
++const WORKER_DEFAULT_NAME = 'server';
++
++function phpt_notify(string $worker = WORKER_DEFAULT_NAME, string $message = ""): void
++{
++ ServerClientTestCase::getInstance()->notify($worker, $message);
++}
++
++function phpt_wait($worker = WORKER_DEFAULT_NAME, $timeout = null): ?string
++{
++ return ServerClientTestCase::getInstance()->wait($worker, $timeout);
++}
++
++function phpt_notify_server_start($server): void
++{
++ ServerClientTestCase::getInstance()->notify_server_start($server);
++}
++
++function phpt_has_sslv3() {
++ static $result = null;
++ if (!is_null($result)) {
++ return $result;
++ }
++ $server = @stream_socket_server('sslv3://127.0.0.1:10013');
++ if ($result = !!$server) {
++ fclose($server);
++ }
++ return $result;
++}
++
++/**
++ * This is a singleton to let the wait/notify functions work
++ * I know it's horrible, but it's a means to an end
++ */
++class ServerClientTestCase
++{
++ private $isWorker = false;
++
++ private $workerHandle = [];
++
++ private $workerStdIn = [];
++
++ private $workerStdOut = [];
++
++ private static $instance;
++
++ public static function getInstance($isWorker = false)
++ {
++ if (!isset(self::$instance)) {
++ self::$instance = new self($isWorker);
++ }
++
++ return self::$instance;
++ }
++
++ public function __construct($isWorker = false)
++ {
++ if (!isset(self::$instance)) {
++ self::$instance = $this;
++ }
++
++ $this->isWorker = $isWorker;
++ }
++
++ private function spawnWorkerProcess($worker, $code)
++ {
++ if (defined("PHP_WINDOWS_VERSION_MAJOR")) {
++ $ini = php_ini_loaded_file();
++ $cmd = sprintf(
++ '%s %s "%s" %s',
++ PHP_BINARY, $ini ? "-n -c $ini" : "",
++ __FILE__,
++ WORKER_ARGV_VALUE
++ );
++ } else {
++ $cmd = sprintf(
++ '%s "%s" %s %s',
++ PHP_BINARY,
++ __FILE__,
++ WORKER_ARGV_VALUE,
++ $worker
++ );
++ }
++ $this->workerHandle[$worker] = proc_open(
++ $cmd,
++ [['pipe', 'r'], ['pipe', 'w'], STDERR],
++ $pipes
++ );
++ $this->workerStdIn[$worker] = $pipes[0];
++ $this->workerStdOut[$worker] = $pipes[1];
++
++ fwrite($this->workerStdIn[$worker], $code . "\n---\n");
++ }
++
++ private function cleanupWorkerProcess($worker)
++ {
++ fclose($this->workerStdIn[$worker]);
++ fclose($this->workerStdOut[$worker]);
++ proc_close($this->workerHandle[$worker]);
++ }
++
++ private function stripPhpTagsFromCode($code)
++ {
++ return preg_replace('/^\s*<\?(?:php)?|\?>\s*$/i', '', $code);
++ }
++
++ public function runWorker()
++ {
++ $code = '';
++
++ while (1) {
++ $line = fgets(STDIN);
++
++ if (trim($line) === "---") {
++ break;
++ }
++
++ $code .= $line;
++ }
++
++ eval($code);
++ }
++
++ /**
++ * Run client and all workers
++ *
++ * @param string $clientCode The client PHP code
++ * @param string|array $workerCode
++ * @param bool $ephemeral Select whether automatic port selection and automatic awaiting is used
++ * @return void
++ * @throws Exception
++ */
++ public function run(string $clientCode, $workerCode, bool $ephemeral = true): void
++ {
++ if (!is_array($workerCode)) {
++ $workerCode = [WORKER_DEFAULT_NAME => $workerCode];
++ }
++ reset($workerCode);
++ $code = current($workerCode);
++ $worker = key($workerCode);
++ while ($worker != null) {
++ $this->spawnWorkerProcess($worker, $this->stripPhpTagsFromCode($code));
++ $code = next($workerCode);
++ if ($ephemeral) {
++ $addr = trim($this->wait($worker));
++ if (empty($addr)) {
++ throw new \Exception("Failed server start");
++ }
++ if ($code === false) {
++ $clientCode = preg_replace('/{{\s*ADDR\s*}}/', $addr, $clientCode);
++ } else {
++ $code = preg_replace('/{{\s*ADDR\s*}}/', $addr, $code);
++ }
++ }
++ $worker = key($workerCode);
++ }
++
++ eval($this->stripPhpTagsFromCode($clientCode));
++ foreach ($workerCode as $worker => $code) {
++ $this->cleanupWorkerProcess($worker);
++ }
++ }
++
++ public function wait($worker, $timeout = null): ?string
++ {
++ $handle = $this->isWorker ? STDIN : $this->workerStdOut[$worker];
++ if ($timeout === null) {
++ return fgets($handle);
++ }
++
++ stream_set_blocking($handle, false);
++ $read = [$handle];
++ $result = stream_select($read, $write, $except, $timeout);
++ if (!$result) {
++ return null;
++ }
++
++ $result = fgets($handle);
++ stream_set_blocking($handle, true);
++ return $result;
++ }
++
++ public function notify(string $worker, string $message = ""): void
++ {
++ fwrite($this->isWorker ? STDOUT : $this->workerStdIn[$worker], "$message\n");
++ }
++
++ public function notify_server_start($server): void
++ {
++ echo stream_socket_get_name($server, false) . "\n";
++ }
++}
++
++if (isset($argv[1]) && $argv[1] === WORKER_ARGV_VALUE) {
++ ServerClientTestCase::getInstance(true)->runWorker();
++}
+diff --git a/ext/standard/tests/http/ghsa-52jp-hrpf-2jff-001.phpt b/ext/standard/tests/http/ghsa-52jp-hrpf-2jff-001.phpt
+index 46d77ec4aff..3475a03beed 100644
+--- a/ext/standard/tests/http/ghsa-52jp-hrpf-2jff-001.phpt
++++ b/ext/standard/tests/http/ghsa-52jp-hrpf-2jff-001.phpt
+@@ -39,7 +39,7 @@ $clientCode = <<<'CODE'
+ var_dump($http_response_header);
+ CODE;
+
+-include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
++include sprintf("%s/ServerClientTestCase.inc", __DIR__);
+ ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
+ ?>
+ --EXPECTF--
+diff --git a/ext/standard/tests/http/ghsa-52jp-hrpf-2jff-002.phpt b/ext/standard/tests/http/ghsa-52jp-hrpf-2jff-002.phpt
+index d25c89d06e5..706a85f410b 100644
+--- a/ext/standard/tests/http/ghsa-52jp-hrpf-2jff-002.phpt
++++ b/ext/standard/tests/http/ghsa-52jp-hrpf-2jff-002.phpt
+@@ -39,7 +39,7 @@ $clientCode = <<<'CODE'
+ var_dump($http_response_header);
+ CODE;
+
+-include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
++include sprintf("%s/ServerClientTestCase.inc", __DIR__);
+ ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
+ ?>
+ --EXPECTF--
+diff --git a/ext/standard/tests/http/ghsa-hgf5-96fm-v528-001.phpt b/ext/standard/tests/http/ghsa-hgf5-96fm-v528-001.phpt
+index c8dcd47a4a4..121f077c9f5 100644
+--- a/ext/standard/tests/http/ghsa-hgf5-96fm-v528-001.phpt
++++ b/ext/standard/tests/http/ghsa-hgf5-96fm-v528-001.phpt
+@@ -36,7 +36,7 @@ $clientCode = <<<'CODE'
+ var_dump($http_response_header);
+ CODE;
+
+-include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
++include sprintf("%s/ServerClientTestCase.inc", __DIR__);
+ ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
+ ?>
+ --EXPECTF--
+diff --git a/ext/standard/tests/http/ghsa-hgf5-96fm-v528-002.phpt b/ext/standard/tests/http/ghsa-hgf5-96fm-v528-002.phpt
+index ca8f75f0327..0d141f93af3 100644
+--- a/ext/standard/tests/http/ghsa-hgf5-96fm-v528-002.phpt
++++ b/ext/standard/tests/http/ghsa-hgf5-96fm-v528-002.phpt
+@@ -36,7 +36,7 @@ $clientCode = <<<'CODE'
+ var_dump($http_response_header);
+ CODE;
+
+-include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
++include sprintf("%s/ServerClientTestCase.inc", __DIR__);
+ ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
+ ?>
+ --EXPECTF--
+diff --git a/ext/standard/tests/http/ghsa-hgf5-96fm-v528-003.phpt b/ext/standard/tests/http/ghsa-hgf5-96fm-v528-003.phpt
+index 4cfbc7ee804..8041487d044 100644
+--- a/ext/standard/tests/http/ghsa-hgf5-96fm-v528-003.phpt
++++ b/ext/standard/tests/http/ghsa-hgf5-96fm-v528-003.phpt
+@@ -36,7 +36,7 @@ $clientCode = <<<'CODE'
+ var_dump($http_response_header);
+ CODE;
+
+-include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
++include sprintf("%s/ServerClientTestCase.inc", __DIR__);
+ ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
+ ?>
+ --EXPECTF--
+diff --git a/ext/standard/tests/http/ghsa-pcmh-g36c-qc44-001.phpt b/ext/standard/tests/http/ghsa-pcmh-g36c-qc44-001.phpt
+index 53baa1c92d6..f491acfae27 100644
+--- a/ext/standard/tests/http/ghsa-pcmh-g36c-qc44-001.phpt
++++ b/ext/standard/tests/http/ghsa-pcmh-g36c-qc44-001.phpt
+@@ -35,7 +35,7 @@ $clientCode = <<<'CODE'
+ var_dump($http_response_header);
+ CODE;
+
+-include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
++include sprintf("%s/ServerClientTestCase.inc", __DIR__);
+ ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
+ ?>
+ --EXPECTF--
+diff --git a/ext/standard/tests/http/ghsa-pcmh-g36c-qc44-002.phpt b/ext/standard/tests/http/ghsa-pcmh-g36c-qc44-002.phpt
+index 5aa0ee00618..4320b17b97d 100644
+--- a/ext/standard/tests/http/ghsa-pcmh-g36c-qc44-002.phpt
++++ b/ext/standard/tests/http/ghsa-pcmh-g36c-qc44-002.phpt
+@@ -35,7 +35,7 @@ $clientCode = <<<'CODE'
+ var_dump($http_response_header);
+ CODE;
+
+-include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
++include sprintf("%s/ServerClientTestCase.inc", __DIR__);
+ ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
+ ?>
+ --EXPECTF--
+diff --git a/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-001.phpt b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-001.phpt
+index 64904bfcd1d..3f1cc79bd9c 100644
+--- a/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-001.phpt
++++ b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-001.phpt
+@@ -35,7 +35,7 @@ $clientCode = <<<'CODE'
+ var_dump($http_response_header);
+ CODE;
+
+-include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
++include sprintf("%s/ServerClientTestCase.inc", __DIR__);
+ ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
+ ?>
+ --EXPECTF--
+diff --git a/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-002.phpt b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-002.phpt
+index a6d9d00fd58..c7c13877fef 100644
+--- a/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-002.phpt
++++ b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-002.phpt
+@@ -35,7 +35,7 @@ $clientCode = <<<'CODE'
+ var_dump($http_response_header);
+ CODE;
+
+-include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
++include sprintf("%s/ServerClientTestCase.inc", __DIR__);
+ ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
+ ?>
+ --EXPECTF--
+diff --git a/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-003.phpt b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-003.phpt
+index 4eff7fc63f3..c67663b65f7 100644
+--- a/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-003.phpt
++++ b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-003.phpt
+@@ -35,7 +35,7 @@ $clientCode = <<<'CODE'
+ var_dump($http_response_header);
+ CODE;
+
+-include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
++include sprintf("%s/ServerClientTestCase.inc", __DIR__);
+ ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
+ ?>
+ --EXPECTF--
+diff --git a/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-004.phpt b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-004.phpt
+index 71aed2fa2e8..7a59e2688fd 100644
+--- a/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-004.phpt
++++ b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-004.phpt
+@@ -35,7 +35,7 @@ $clientCode = <<<'CODE'
+ var_dump($http_response_header);
+ CODE;
+
+-include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
++include sprintf("%s/ServerClientTestCase.inc", __DIR__);
+ ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
+ ?>
+ --EXPECTF--
+diff --git a/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-005.phpt b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-005.phpt
+index 49d845d84b4..f097762ef9e 100644
+--- a/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-005.phpt
++++ b/ext/standard/tests/http/ghsa-v8xr-gpvj-cx9g-005.phpt
+@@ -35,7 +35,7 @@ $clientCode = <<<'CODE'
+ var_dump($http_response_header);
+ CODE;
+
+-include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
++include sprintf("%s/ServerClientTestCase.inc", __DIR__);
+ ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
+ ?>
+ --EXPECTF--
+diff --git a/ext/xml/tests/bug26614_libxml_gte2_11.phpt b/ext/xml/tests/bug26614_libxml_gte2_11.phpt
+new file mode 100644
+index 00000000000..9a81b67686d
+--- /dev/null
++++ b/ext/xml/tests/bug26614_libxml_gte2_11.phpt
+@@ -0,0 +1,95 @@
++--TEST--
++Bug #26614 (CDATA sections skipped on line count)
++--EXTENSIONS--
++xml
++--SKIPIF--
++<?php
++if (!defined("LIBXML_VERSION")) die('skip libxml2 test');
++if (LIBXML_VERSION < 21100) die('skip libxml2 test variant for version >= 2.11');
++?>
++--FILE--
++<?php
++/*
++this test works fine with Expat but fails with libxml
++which we now use as default
++
++further investigation has shown that not only line count
++is skipped on CDATA sections but that libxml does also
++show different column numbers and byte positions depending
++on context and in opposition to what one would expect to
++see and what good old Expat reported just fine ...
++*/
++
++$xmls = array();
++
++// Case 1: CDATA Sections
++$xmls["CDATA"] ='<?xml version="1.0" encoding="iso-8859-1" ?>
++<data>
++<![CDATA[
++multi
++line
++CDATA
++block
++]]>
++</data>';
++
++// Case 2: replace some characters so that we get comments instead
++$xmls["Comment"] ='<?xml version="1.0" encoding="iso-8859-1" ?>
++<data>
++<!-- ATA[
++multi
++line
++CDATA
++block
++-->
++</data>';
++
++// Case 3: replace even more characters so that only textual data is left
++$xmls["Text"] ='<?xml version="1.0" encoding="iso-8859-1" ?>
++<data>
++-!-- ATA[
++multi
++line
++CDATA
++block
++---
++</data>';
++
++function startElement($parser, $name, $attrs) {
++ printf("<$name> at line %d, col %d (byte %d)\n",
++ xml_get_current_line_number($parser),
++ xml_get_current_column_number($parser),
++ xml_get_current_byte_index($parser));
++}
++
++function endElement($parser, $name) {
++ printf("</$name> at line %d, col %d (byte %d)\n",
++ xml_get_current_line_number($parser),
++ xml_get_current_column_number($parser),
++ xml_get_current_byte_index($parser));
++}
++
++function characterData($parser, $data) {
++ // dummy
++}
++
++foreach ($xmls as $desc => $xml) {
++ echo "$desc\n";
++ $xml_parser = xml_parser_create();
++ xml_set_element_handler($xml_parser, "startElement", "endElement");
++ xml_set_character_data_handler($xml_parser, "characterData");
++ if (!xml_parse($xml_parser, $xml, true))
++ echo "Error: ".xml_error_string(xml_get_error_code($xml_parser))."\n";
++ xml_parser_free($xml_parser);
++}
++?>
++--EXPECTF--
++CDATA
++<DATA> at line 2, col %d (byte 50)
++</DATA> at line 9, col %d (byte 96)
++Comment
++<DATA> at line 2, col %d (byte 50)
++</DATA> at line 9, col %d (byte 96)
++Text
++<DATA> at line 2, col %d (byte 50)
++</DATA> at line 9, col %d (byte 96)
+diff --git a/ext/xml/tests/bug26614_libxml.phpt b/ext/xml/tests/bug26614_libxml_pre2_11.phpt
+similarity index 96%
+rename from ext/xml/tests/bug26614_libxml.phpt
+rename to ext/xml/tests/bug26614_libxml_pre2_11.phpt
+index 3ddd35ed0ea..afacaa1c59a 100644
+--- a/ext/xml/tests/bug26614_libxml.phpt
++++ b/ext/xml/tests/bug26614_libxml_pre2_11.phpt
+@@ -4,6 +4,7 @@ Bug #26614 (CDATA sections skipped on line count)
+ <?php
+ require_once("skipif.inc");
+ if (!defined("LIBXML_VERSION")) die('skip libxml2 test');
++if (LIBXML_VERSION >= 21100) die('skip libxml2 test variant for version < 2.11');
+ ?>
+ --FILE--
+ <?php
+--
+2.48.1
+
+From 087e974d74efc977dfbd18fd3cd568b60fb7675d Mon Sep 17 00:00:00 2001
+From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
+Date: Fri, 1 Dec 2023 18:03:35 +0100
+Subject: [PATCH 06/11] Backport 0a39890c: Fix libxml2 2.12 build due to API
+ breaks
+
+See https://github.com/php/php-src/actions/runs/7062192818/job/19225478601
+
+(cherry picked from commit fa6a0f80f644932506666beb7c85e4041c4a4646)
+(cherry picked from commit 6e8e9f558aa0903e9650dd166a0a53c359d9e9e0)
+---
+ ext/libxml/libxml.c | 14 ++++++++++----
+ ext/soap/php_sdl.c | 2 +-
+ 2 files changed, 11 insertions(+), 5 deletions(-)
+
+diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c
+index 5d9c23e0d7e..7917f636a9e 100644
+--- a/ext/libxml/libxml.c
++++ b/ext/libxml/libxml.c
+@@ -530,7 +530,11 @@ static int _php_libxml_free_error(xmlErrorPtr error)
+ return 1;
+ }
+
+-static void _php_list_set_error_structure(xmlErrorPtr error, const char *msg)
++#if LIBXML_VERSION >= 21200
++static void _php_list_set_error_structure(const xmlError *error, const char *msg)
++#else
++static void _php_list_set_error_structure(xmlError *error, const char *msg)
++#endif
+ {
+ xmlError error_copy;
+ int ret;
+@@ -784,7 +788,11 @@ PHP_LIBXML_API void php_libxml_ctx_warning(void *ctx, const char *msg, ...)
+ va_end(args);
+ }
+
++#if LIBXML_VERSION >= 21200
++PHP_LIBXML_API void php_libxml_structured_error_handler(void *userData, const xmlError *error)
++#else
+ PHP_LIBXML_API void php_libxml_structured_error_handler(void *userData, xmlErrorPtr error)
++#endif
+ {
+ _php_list_set_error_structure(error, NULL);
+
+@@ -1063,9 +1071,7 @@ static PHP_FUNCTION(libxml_use_internal_errors)
+ Retrieve last error from libxml */
+ static PHP_FUNCTION(libxml_get_last_error)
+ {
+- xmlErrorPtr error;
+-
+- error = xmlGetLastError();
++ const xmlError *error = xmlGetLastError();
+
+ if (error) {
+ object_init_ex(return_value, libxmlerror_class_entry);
+diff --git a/ext/soap/php_sdl.c b/ext/soap/php_sdl.c
+index 26a23f57db2..3df532a2d65 100644
+--- a/ext/soap/php_sdl.c
++++ b/ext/soap/php_sdl.c
+@@ -333,7 +333,7 @@ static void load_wsdl_ex(zval *this_ptr, char *struri, sdlCtx *ctx, int include)
+ sdl_restore_uri_credentials(ctx);
+
+ if (!wsdl) {
+- xmlErrorPtr xmlErrorPtr = xmlGetLastError();
++ const xmlError *xmlErrorPtr = xmlGetLastError();
+
+ if (xmlErrorPtr) {
+ soap_error2(E_ERROR, "Parsing WSDL: Couldn't load from '%s' : %s", struri, xmlErrorPtr->message);
+--
+2.48.1
+
+From aa8817ab42f758c988dfd3158f705da770238a88 Mon Sep 17 00:00:00 2001
+From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
+Date: Thu, 4 Jul 2024 06:29:50 -0700
+Subject: [PATCH 07/11] Backport 4fe82131: Backport libxml2 2.13.2 fixes
+ (#14816)
+
+Backproted from https://github.com/php/php-src/pull/14789
+
+(cherry picked from commit bb46b4b799b583528025a775af45308133bfd4c1)
+(cherry picked from commit 6cb68826aaf68ffe8c70c8782450c38970236040)
+---
+ ext/dom/document.c | 6 ++--
+ .../DOMDocument_loadHTMLfile_error1.phpt | 2 +-
+ .../DOMDocument_relaxNGValidate_error2.phpt | 2 +-
+ .../tests/DOMDocument_saveHTMLFile_basic.phpt | 1 +
+ ...DOMDocument_saveHTMLFile_formatOutput.phpt | 1 +
+ ...nt_saveHTMLFile_formatOutput_gte_2_13.phpt | 32 +++++++++++++++++++
+ .../DOMDocument_saveHTML_basic_gte_2_13.phpt | 31 ++++++++++++++++++
+ .../DOMDocument_schemaValidate_error5.phpt | 2 +-
+ ext/dom/tests/dom_create_element.phpt | 14 +++-----
+ ext/libxml/libxml.c | 4 ++-
+ ext/simplexml/tests/bug79971_1.phpt | 2 +-
+ ext/soap/php_encoding.c | 9 ++++--
+ ext/soap/php_xml.c | 4 ++-
+ ext/soap/tests/bugs/bug42151.phpt | 4 +--
+ ext/xml/compat.c | 3 +-
+ ext/xmlwriter/php_xmlwriter.c | 3 +-
+ 16 files changed, 95 insertions(+), 25 deletions(-)
+ create mode 100644 ext/dom/tests/DOMDocument_saveHTMLFile_formatOutput_gte_2_13.phpt
+ create mode 100644 ext/dom/tests/DOMDocument_saveHTML_basic_gte_2_13.phpt
+
+diff --git a/ext/dom/document.c b/ext/dom/document.c
+index 989b5b3dd24..af06fb41240 100644
+--- a/ext/dom/document.c
++++ b/ext/dom/document.c
+@@ -1457,11 +1457,13 @@ static xmlDocPtr dom_document_parser(zval *id, int mode, char *source, size_t so
+ if (keep_blanks == 0 && ! (options & XML_PARSE_NOBLANKS)) {
+ options |= XML_PARSE_NOBLANKS;
+ }
++ if (recover) {
++ options |= XML_PARSE_RECOVER;
++ }
+
+ php_libxml_sanitize_parse_ctxt_options(ctxt);
+ xmlCtxtUseOptions(ctxt, options);
+
+- ctxt->recovery = recover;
+ if (recover) {
+ old_error_reporting = EG(error_reporting);
+ EG(error_reporting) = old_error_reporting | E_WARNING;
+@@ -1471,7 +1473,7 @@ static xmlDocPtr dom_document_parser(zval *id, int mode, char *source, size_t so
+
+ if (ctxt->wellFormed || recover) {
+ ret = ctxt->myDoc;
+- if (ctxt->recovery) {
++ if (recover) {
+ EG(error_reporting) = old_error_reporting;
+ }
+ /* If loading from memory, set the base reference uri for the document */
+diff --git a/ext/dom/tests/DOMDocument_loadHTMLfile_error1.phpt b/ext/dom/tests/DOMDocument_loadHTMLfile_error1.phpt
+index cfb41686e87..fc78273c85f 100644
+--- a/ext/dom/tests/DOMDocument_loadHTMLfile_error1.phpt
++++ b/ext/dom/tests/DOMDocument_loadHTMLfile_error1.phpt
+@@ -15,4 +15,4 @@ $result = $doc->loadHTMLFile(__DIR__ . "/ffff/test.html");
+ assert($result === false);
+ ?>
+ --EXPECTF--
+-%r(PHP ){0,1}%rWarning: DOMDocument::loadHTMLFile(): I/O warning : failed to load external entity %s
++%r(PHP ){0,1}%rWarning: DOMDocument::loadHTMLFile(): I/O %s
+diff --git a/ext/dom/tests/DOMDocument_relaxNGValidate_error2.phpt b/ext/dom/tests/DOMDocument_relaxNGValidate_error2.phpt
+index cdd6e64194c..19bb4dce2d6 100644
+--- a/ext/dom/tests/DOMDocument_relaxNGValidate_error2.phpt
++++ b/ext/dom/tests/DOMDocument_relaxNGValidate_error2.phpt
+@@ -22,7 +22,7 @@ $result = $doc->relaxNGValidate($rng);
+ var_dump($result);
+ ?>
+ --EXPECTF--
+-Warning: DOMDocument::relaxNGValidate(): I/O warning : failed to load external entity "%s/foo.rng" in %s on line %d
++Warning: DOMDocument::relaxNGValidate(): I/O %s : failed to load %s
+
+ Warning: DOMDocument::relaxNGValidate(): xmlRelaxNGParse: could not load %s/foo.rng in %s on line %d
+
+diff --git a/ext/dom/tests/DOMDocument_saveHTMLFile_basic.phpt b/ext/dom/tests/DOMDocument_saveHTMLFile_basic.phpt
+index f71db0c32a3..c51852e120c 100644
+--- a/ext/dom/tests/DOMDocument_saveHTMLFile_basic.phpt
++++ b/ext/dom/tests/DOMDocument_saveHTMLFile_basic.phpt
+@@ -6,6 +6,7 @@ Knut Urdalen <knut@php.net>
+ --SKIPIF--
+ <?php
+ require_once __DIR__ .'/skipif.inc';
++if (LIBXML_VERSION >= 21300) die("skip see https://gitlab.gnome.org/GNOME/libxml2/-/issues/756");
+ ?>
+ --FILE--
+ <?php
+diff --git a/ext/dom/tests/DOMDocument_saveHTMLFile_formatOutput.phpt b/ext/dom/tests/DOMDocument_saveHTMLFile_formatOutput.phpt
+index 376c9a8e323..8d7baa7b7e8 100644
+--- a/ext/dom/tests/DOMDocument_saveHTMLFile_formatOutput.phpt
++++ b/ext/dom/tests/DOMDocument_saveHTMLFile_formatOutput.phpt
+@@ -6,6 +6,7 @@ Knut Urdalen <knut@php.net>
+ --SKIPIF--
+ <?php
+ require_once __DIR__ .'/skipif.inc';
++if (LIBXML_VERSION >= 21300) die("skip see https://gitlab.gnome.org/GNOME/libxml2/-/issues/756");
+ ?>
+ --FILE--
+ <?php
+diff --git a/ext/dom/tests/DOMDocument_saveHTMLFile_formatOutput_gte_2_13.phpt b/ext/dom/tests/DOMDocument_saveHTMLFile_formatOutput_gte_2_13.phpt
+new file mode 100644
+index 00000000000..3477edfcf5f
+--- /dev/null
++++ b/ext/dom/tests/DOMDocument_saveHTMLFile_formatOutput_gte_2_13.phpt
+@@ -0,0 +1,32 @@
++--TEST--
++DOMDocument::saveHTMLFile() should format output on demand
++--CREDITS--
++Knut Urdalen <knut@php.net>
++#PHPTestFest2009 Norway 2009-06-09 \o/
++--EXTENSIONS--
++dom
++--SKIPIF--
++<?php
++if (LIBXML_VERSION < 21300) die("skip see https://gitlab.gnome.org/GNOME/libxml2/-/issues/756");
++?>
++--FILE--
++<?php
++$filename = __DIR__."/DOMDocument_saveHTMLFile_formatOutput_gte_2_13.html";
++$doc = new DOMDocument('1.0');
++$doc->formatOutput = true;
++$root = $doc->createElement('html');
++$root = $doc->appendChild($root);
++$head = $doc->createElement('head');
++$head = $root->appendChild($head);
++$title = $doc->createElement('title');
++$title = $head->appendChild($title);
++$text = $doc->createTextNode('This is the title');
++$text = $title->appendChild($text);
++$bytes = $doc->saveHTMLFile($filename);
++var_dump($bytes);
++echo file_get_contents($filename);
++unlink($filename);
++?>
++--EXPECT--
++int(59)
++<html><head><title>This is the title</title></head></html>
+diff --git a/ext/dom/tests/DOMDocument_saveHTML_basic_gte_2_13.phpt b/ext/dom/tests/DOMDocument_saveHTML_basic_gte_2_13.phpt
+new file mode 100644
+index 00000000000..c0be105253d
+--- /dev/null
++++ b/ext/dom/tests/DOMDocument_saveHTML_basic_gte_2_13.phpt
+@@ -0,0 +1,31 @@
++--TEST--
++DOMDocument::saveHTMLFile() should dump the internal document into a file using HTML formatting
++--CREDITS--
++Knut Urdalen <knut@php.net>
++#PHPTestFest2009 Norway 2009-06-09 \o/
++--EXTENSIONS--
++dom
++--SKIPIF--
++<?php
++if (LIBXML_VERSION < 21300) die("skip see https://gitlab.gnome.org/GNOME/libxml2/-/issues/756");
++?>
++--FILE--
++<?php
++$filename = __DIR__."/DOMDocument_saveHTMLFile_basic_gte_2_13.html";
++$doc = new DOMDocument('1.0');
++$root = $doc->createElement('html');
++$root = $doc->appendChild($root);
++$head = $doc->createElement('head');
++$head = $root->appendChild($head);
++$title = $doc->createElement('title');
++$title = $head->appendChild($title);
++$text = $doc->createTextNode('This is the title');
++$text = $title->appendChild($text);
++$bytes = $doc->saveHTMLFile($filename);
++var_dump($bytes);
++echo file_get_contents($filename);
++unlink($filename);
++?>
++--EXPECT--
++int(59)
++<html><head><title>This is the title</title></head></html>
+diff --git a/ext/dom/tests/DOMDocument_schemaValidate_error5.phpt b/ext/dom/tests/DOMDocument_schemaValidate_error5.phpt
+index cb57b55b41a..44ea52c2d06 100644
+--- a/ext/dom/tests/DOMDocument_schemaValidate_error5.phpt
++++ b/ext/dom/tests/DOMDocument_schemaValidate_error5.phpt
+@@ -17,7 +17,7 @@ var_dump($result);
+
+ ?>
+ --EXPECTF--
+-Warning: DOMDocument::schemaValidate(): I/O warning : failed to load external entity "%snon-existent-file" in %s.php on line %d
++Warning: DOMDocument::schemaValidate(): I/O %s : failed to load %s
+
+ Warning: DOMDocument::schemaValidate(): Failed to locate the main schema resource at '%s/non-existent-file'. in %s.php on line %d
+
+diff --git a/ext/dom/tests/dom_create_element.phpt b/ext/dom/tests/dom_create_element.phpt
+index bd2c8f11dae..70ae54a11bb 100644
+--- a/ext/dom/tests/dom_create_element.phpt
++++ b/ext/dom/tests/dom_create_element.phpt
+@@ -251,14 +251,10 @@ try {
+ print $e->getMessage() . "\n";
+ }
+
+-/* This isn't because the xml namespace isn't there and we can't create it */
+-print "29 DOMElement::__construct('xml:valid', '', 'http://www.w3.org/XML/1998/namespace')\n";
+-try {
+- $element = new DomElement('xml:valid', '', 'http://www.w3.org/XML/1998/namespace');
+- print "valid\n";
+-} catch (Exception $e) {
+- print $e->getMessage() . "\n";
+-}
++/* There used to be a 29 here that tested DOMElement::__construct('xml:valid', '', 'http://www.w3.org/XML/1998/namespace').
++ * In libxml2 version 2.12 or prior this didn't work because the xml namespace isn't there and you can't create it without
++ * a document. Starting from libxml2 version 2.13 it does actually work because the XML namespace is statically defined.
++ * The behaviour from version 2.13 is actually the desired behaviour anyway. */
+
+
+ /* the qualifiedName or its prefix is "xmlns" and the namespaceURI is
+@@ -378,8 +374,6 @@ Namespace Error
+ Namespace Error
+ 28 DOMDocument::createElementNS('http://www.w3.org/XML/1998/namespace', 'xml:valid')
+ valid
+-29 DOMElement::__construct('xml:valid', '', 'http://www.w3.org/XML/1998/namespace')
+-Namespace Error
+ 30 DOMDocument::createElementNS('http://wrong.namespaceURI.com', 'xmlns:valid')
+ Namespace Error
+ 31 DOMElement::__construct('xmlns:valid', '', 'http://wrong.namespaceURI.com')
+diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c
+index 7917f636a9e..4b9e6a918d4 100644
+--- a/ext/libxml/libxml.c
++++ b/ext/libxml/libxml.c
+@@ -476,8 +476,10 @@ php_libxml_input_buffer_create_filename(const char *URI, xmlCharEncoding enc)
+ static xmlOutputBufferPtr
+ php_libxml_output_buffer_create_filename(const char *URI,
+ xmlCharEncodingHandlerPtr encoder,
+- int compression ATTRIBUTE_UNUSED)
++ int compression)
+ {
++ ZEND_IGNORE_VALUE(compression);
++
+ xmlOutputBufferPtr ret;
+ xmlURIPtr puri;
+ void *context = NULL;
+diff --git a/ext/simplexml/tests/bug79971_1.phpt b/ext/simplexml/tests/bug79971_1.phpt
+index 197776d82d3..2ee24e89f12 100644
+--- a/ext/simplexml/tests/bug79971_1.phpt
++++ b/ext/simplexml/tests/bug79971_1.phpt
+@@ -20,7 +20,7 @@ var_dump($sxe->asXML("$uri.out%00foo"));
+ --EXPECTF--
+ Warning: simplexml_load_file(): URI must not contain percent-encoded NUL bytes in %s on line %d
+
+-Warning: simplexml_load_file(): I/O warning : failed to load external entity "%s/bug79971_1.xml%00foo" in %s on line %d
++Warning: simplexml_load_file(): I/O warning : failed to load %s
+ bool(false)
+
+ Warning: SimpleXMLElement::asXML(): URI must not contain percent-encoded NUL bytes in %s on line %d
+diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c
+index e0cf63dd1da..0a6edbf5a41 100644
+--- a/ext/soap/php_encoding.c
++++ b/ext/soap/php_encoding.c
+@@ -3381,7 +3381,6 @@ xmlNsPtr encode_add_ns(xmlNodePtr node, const char* ns)
+ } else {
+ smart_str prefix = {0};
+ int num = ++SOAP_GLOBAL(cur_uniq_ns);
+- xmlChar *enc_ns;
+
+ while (1) {
+ smart_str_appendl(&prefix, "ns", 2);
+@@ -3395,9 +3394,15 @@ xmlNsPtr encode_add_ns(xmlNodePtr node, const char* ns)
+ num = ++SOAP_GLOBAL(cur_uniq_ns);
+ }
+
+- enc_ns = xmlEncodeSpecialChars(node->doc, BAD_CAST(ns));
++ /* Starting with libxml 2.13, we don't have to do this workaround anymore, otherwise we get double-encoded
++ * entities. See libxml2 commit f506ec66547ef9bac97a2bf306d368ecea8c0c9e. */
++#if LIBXML_VERSION < 21300
++ xmlChar *enc_ns = xmlEncodeSpecialChars(node->doc, BAD_CAST(ns));
+ xmlns = xmlNewNs(node->doc->children, enc_ns, BAD_CAST(prefix.s ? ZSTR_VAL(prefix.s) : ""));
+ xmlFree(enc_ns);
++#else
++ xmlns = xmlNewNs(node->doc->children, BAD_CAST(ns), BAD_CAST(prefix.s ? ZSTR_VAL(prefix.s) : ""));
++#endif
+ smart_str_free(&prefix);
+ }
+ }
+diff --git a/ext/soap/php_xml.c b/ext/soap/php_xml.c
+index 1bb7fa00a37..446017eb5c8 100644
+--- a/ext/soap/php_xml.c
++++ b/ext/soap/php_xml.c
+@@ -94,13 +94,14 @@ xmlDocPtr soap_xmlParseFile(const char *filename)
+ zend_bool old;
+
+ php_libxml_sanitize_parse_ctxt_options(ctxt);
++ /* TODO: In libxml2 2.14.0 change this to the new options API so we don't rely on deprecated APIs. */
+ ctxt->keepBlanks = 0;
++ ctxt->options |= XML_PARSE_HUGE;
+ ctxt->sax->ignorableWhitespace = soap_ignorableWhitespace;
+ ctxt->sax->comment = soap_Comment;
+ ctxt->sax->warning = NULL;
+ ctxt->sax->error = NULL;
+ /*ctxt->sax->fatalError = NULL;*/
+- ctxt->options |= XML_PARSE_HUGE;
+ old = php_libxml_disable_entity_loader(1);
+ xmlParseDocument(ctxt);
+ php_libxml_disable_entity_loader(old);
+@@ -148,6 +149,7 @@ xmlDocPtr soap_xmlParseMemory(const void *buf, size_t buf_size)
+ ctxt->sax->warning = NULL;
+ ctxt->sax->error = NULL;
+ /*ctxt->sax->fatalError = NULL;*/
++ /* TODO: In libxml2 2.14.0 change this to the new options API so we don't rely on deprecated APIs. */
+ ctxt->options |= XML_PARSE_HUGE;
+ old = php_libxml_disable_entity_loader(1);
+ xmlParseDocument(ctxt);
+diff --git a/ext/soap/tests/bugs/bug42151.phpt b/ext/soap/tests/bugs/bug42151.phpt
+index ee53e6d525d..d1bcae83364 100644
+--- a/ext/soap/tests/bugs/bug42151.phpt
++++ b/ext/soap/tests/bugs/bug42151.phpt
+@@ -25,8 +25,8 @@ try {
+ }
+ echo "ok\n";
+ ?>
+---EXPECT--
+-SOAP-ERROR: Parsing WSDL: Couldn't load from 'httpx://' : failed to load external entity "httpx://"
++--EXPECTF--
++SOAP-ERROR: Parsing WSDL: Couldn't load from 'httpx://' : failed to load %s
+
+ ok
+ I don't get executed either.
+diff --git a/ext/xml/compat.c b/ext/xml/compat.c
+index 57eb00dd429..ea1fd835059 100644
+--- a/ext/xml/compat.c
++++ b/ext/xml/compat.c
+@@ -716,8 +716,7 @@ XML_GetCurrentByteCount(XML_Parser parser)
+ {
+ /* WARNING: this is identical to ByteIndex; it should probably
+ * be different */
+- return parser->parser->input->consumed +
+- (parser->parser->input->cur - parser->parser->input->base);
++ return XML_GetCurrentByteIndex(parser);
+ }
+
+ PHP_XML_API const XML_Char *XML_ExpatVersion(void)
+diff --git a/ext/xmlwriter/php_xmlwriter.c b/ext/xmlwriter/php_xmlwriter.c
+index 5cb141dad39..55874420f3b 100644
+--- a/ext/xmlwriter/php_xmlwriter.c
++++ b/ext/xmlwriter/php_xmlwriter.c
+@@ -1785,7 +1785,8 @@ static void php_xmlwriter_flush(INTERNAL_FUNCTION_PARAMETERS, int force_string)
+ }
+ output_bytes = xmlTextWriterFlush(ptr);
+ if (buffer) {
+- RETVAL_STRING((char *) buffer->content);
++ const xmlChar *content = xmlBufferContent(buffer);
++ RETVAL_STRING((const char *) content);
+ if (empty) {
+ xmlBufferEmpty(buffer);
+ }
+--
+2.48.1
+
+From 238d5f0aeaedc9c355f1bc1159b01e357bdaf344 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= <tim@tideways-gmbh.com>
+Date: Wed, 20 Nov 2024 10:47:27 +0100
+Subject: [PATCH 08/11] Fix GHSA-p3x9-6h7p-cgfc: libxml streams wrong
+ `content-type` on redirect
+
+libxml streams use wrong content-type header when requesting a
+redirected resource.
+
+(cherry picked from commit b6004a043c16b211d462218fbb3f72db68ec2b18)
+(cherry picked from commit 1196e566681a34564c02173ba234b5a42587ff07)
+---
+ ext/dom/tests/ghsa-p3x9-6h7p-cgfc_001.phpt | 60 ++++++++++
+ ext/dom/tests/ghsa-p3x9-6h7p-cgfc_002.phpt | 60 ++++++++++
+ ext/dom/tests/ghsa-p3x9-6h7p-cgfc_003.phpt | 60 ++++++++++
+ ext/libxml/libxml.c | 77 +++++++------
+ ext/standard/tests/http/newserver.inc | 124 +++++++++++++++++++++
+ 5 files changed, 348 insertions(+), 33 deletions(-)
+ create mode 100644 ext/dom/tests/ghsa-p3x9-6h7p-cgfc_001.phpt
+ create mode 100644 ext/dom/tests/ghsa-p3x9-6h7p-cgfc_002.phpt
+ create mode 100644 ext/dom/tests/ghsa-p3x9-6h7p-cgfc_003.phpt
+ create mode 100644 ext/standard/tests/http/newserver.inc
+
+diff --git a/ext/dom/tests/ghsa-p3x9-6h7p-cgfc_001.phpt b/ext/dom/tests/ghsa-p3x9-6h7p-cgfc_001.phpt
+new file mode 100644
+index 00000000000..87cb2aa0b1f
+--- /dev/null
++++ b/ext/dom/tests/ghsa-p3x9-6h7p-cgfc_001.phpt
+@@ -0,0 +1,60 @@
++--TEST--
++GHSA-p3x9-6h7p-cgfc: libxml streams use wrong `content-type` header when requesting a redirected resource (Basic)
++--EXTENSIONS--
++dom
++--SKIPIF--
++<?php
++if (@!include "./ext/standard/tests/http/newserver.inc") die('skip server.inc not available');
++http_server_skipif();
++?>
++--FILE--
++<?php
++require "./ext/standard/tests/http/newserver.inc";
++
++function genResponses($server) {
++ $uri = 'http://' . stream_socket_get_name($server, false);
++ yield "data://text/plain,HTTP/1.1 302 Moved Temporarily\r\nLocation: $uri/document.xml\r\nContent-Type: text/html;charset=utf-16\r\n\r\n";
++ $xml = <<<'EOT'
++ <!doctype html>
++ <html>
++ <head>
++ <title>GHSA-p3x9-6h7p-cgfc</title>
++
++ <meta charset="utf-8" />
++ <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
++ </head>
++
++ <body>
++ <h1>GHSA-p3x9-6h7p-cgfc</h1>
++ </body>
++ </html>
++ EOT;
++ // Intentionally using non-standard casing for content-type to verify it is matched not case sensitively.
++ yield "data://text/plain,HTTP/1.1 200 OK\r\nconteNt-tyPe: text/html; charset=utf-8\r\n\r\n{$xml}";
++}
++
++['pid' => $pid, 'uri' => $uri] = http_server('genResponses', $output);
++$document = new \DOMDocument();
++$document->loadHTMLFile($uri);
++
++$h1 = $document->getElementsByTagName('h1');
++var_dump($h1->length);
++var_dump($document->saveHTML());
++http_server_kill($pid);
++?>
++--EXPECT--
++int(1)
++string(266) "<!DOCTYPE html>
++<html>
++ <head>
++ <title>GHSA-p3x9-6h7p-cgfc</title>
++
++ <meta charset="utf-8">
++ <meta http-equiv="Content-type" content="text/html; charset=utf-8">
++ </head>
++
++ <body>
++ <h1>GHSA-p3x9-6h7p-cgfc</h1>
++ </body>
++</html>
++"
+diff --git a/ext/dom/tests/ghsa-p3x9-6h7p-cgfc_002.phpt b/ext/dom/tests/ghsa-p3x9-6h7p-cgfc_002.phpt
+new file mode 100644
+index 00000000000..1ce468c3b19
+--- /dev/null
++++ b/ext/dom/tests/ghsa-p3x9-6h7p-cgfc_002.phpt
+@@ -0,0 +1,60 @@
++--TEST--
++GHSA-p3x9-6h7p-cgfc: libxml streams use wrong `content-type` header when requesting a redirected resource (Missing content-type)
++--EXTENSIONS--
++dom
++--SKIPIF--
++<?php
++if (@!include "./ext/standard/tests/http/newserver.inc") die('skip server.inc not available');
++http_server_skipif();
++?>
++--FILE--
++<?php
++require "./ext/standard/tests/http/newserver.inc";
++
++function genResponses($server) {
++ $uri = 'http://' . stream_socket_get_name($server, false);
++ yield "data://text/plain,HTTP/1.1 302 Moved Temporarily\r\nLocation: $uri/document.xml\r\nContent-Type: text/html;charset=utf-16\r\n\r\n";
++ $xml = <<<'EOT'
++ <!doctype html>
++ <html>
++ <head>
++ <title>GHSA-p3x9-6h7p-cgfc</title>
++
++ <meta charset="utf-8" />
++ <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
++ </head>
++
++ <body>
++ <h1>GHSA-p3x9-6h7p-cgfc</h1>
++ </body>
++ </html>
++ EOT;
++ // Missing content-type in actual response.
++ yield "data://text/plain,HTTP/1.1 200 OK\r\n\r\n{$xml}";
++}
++
++['pid' => $pid, 'uri' => $uri] = http_server('genResponses', $output);
++$document = new \DOMDocument();
++$document->loadHTMLFile($uri);
++
++$h1 = $document->getElementsByTagName('h1');
++var_dump($h1->length);
++var_dump($document->saveHTML());
++http_server_kill($pid);
++?>
++--EXPECT--
++int(1)
++string(266) "<!DOCTYPE html>
++<html>
++ <head>
++ <title>GHSA-p3x9-6h7p-cgfc</title>
++
++ <meta charset="utf-8">
++ <meta http-equiv="Content-type" content="text/html; charset=utf-8">
++ </head>
++
++ <body>
++ <h1>GHSA-p3x9-6h7p-cgfc</h1>
++ </body>
++</html>
++"
+diff --git a/ext/dom/tests/ghsa-p3x9-6h7p-cgfc_003.phpt b/ext/dom/tests/ghsa-p3x9-6h7p-cgfc_003.phpt
+new file mode 100644
+index 00000000000..b8cac7e3247
+--- /dev/null
++++ b/ext/dom/tests/ghsa-p3x9-6h7p-cgfc_003.phpt
+@@ -0,0 +1,60 @@
++--TEST--
++GHSA-p3x9-6h7p-cgfc: libxml streams use wrong `content-type` header when requesting a redirected resource (Reason with colon)
++--EXTENSIONS--
++dom
++--SKIPIF--
++<?php
++if (@!include "./ext/standard/tests/http/newserver.inc") die('skip server.inc not available');
++http_server_skipif();
++?>
++--FILE--
++<?php
++require "./ext/standard/tests/http/newserver.inc";
++
++function genResponses($server) {
++ $uri = 'http://' . stream_socket_get_name($server, false);
++ yield "data://text/plain,HTTP/1.1 302 Moved Temporarily\r\nLocation: $uri/document.xml\r\nContent-Type: text/html;charset=utf-16\r\n\r\n";
++ $xml = <<<'EOT'
++ <!doctype html>
++ <html>
++ <head>
++ <title>GHSA-p3x9-6h7p-cgfc</title>
++
++ <meta charset="utf-8" />
++ <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
++ </head>
++
++ <body>
++ <h1>GHSA-p3x9-6h7p-cgfc</h1>
++ </body>
++ </html>
++ EOT;
++ // Missing content-type in actual response.
++ yield "data://text/plain,HTTP/1.1 200 OK: This is fine\r\n\r\n{$xml}";
++}
++
++['pid' => $pid, 'uri' => $uri] = http_server('genResponses', $output);
++$document = new \DOMDocument();
++$document->loadHTMLFile($uri);
++
++$h1 = $document->getElementsByTagName('h1');
++var_dump($h1->length);
++var_dump($document->saveHTML());
++http_server_kill($pid);
++?>
++--EXPECT--
++int(1)
++string(266) "<!DOCTYPE html>
++<html>
++ <head>
++ <title>GHSA-p3x9-6h7p-cgfc</title>
++
++ <meta charset="utf-8">
++ <meta http-equiv="Content-type" content="text/html; charset=utf-8">
++ </head>
++
++ <body>
++ <h1>GHSA-p3x9-6h7p-cgfc</h1>
++ </body>
++</html>
++"
+diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c
+index 4b9e6a918d4..1866b7b21f4 100644
+--- a/ext/libxml/libxml.c
++++ b/ext/libxml/libxml.c
+@@ -420,42 +420,53 @@ php_libxml_input_buffer_create_filename(const char *URI, xmlCharEncoding enc)
+ if (Z_TYPE(s->wrapperdata) == IS_ARRAY) {
+ zval *header;
+
+- ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL(s->wrapperdata), header) {
++ /* Scan backwards: The header array might contain the headers for multiple responses, if
++ * a redirect was followed.
++ */
++ ZEND_HASH_REVERSE_FOREACH_VAL_IND(Z_ARRVAL(s->wrapperdata), header) {
+ const char buf[] = "Content-Type:";
+- if (Z_TYPE_P(header) == IS_STRING &&
+- !zend_binary_strncasecmp(Z_STRVAL_P(header), Z_STRLEN_P(header), buf, sizeof(buf)-1, sizeof(buf)-1)) {
+- char *needle = estrdup("charset=");
+- char *haystack = estrndup(Z_STRVAL_P(header), Z_STRLEN_P(header));
+- char *encoding = php_stristr(haystack, needle, Z_STRLEN_P(header), sizeof("charset=")-1);
+-
+- if (encoding) {
+- char *end;
+-
+- encoding += sizeof("charset=")-1;
+- if (*encoding == '"') {
+- encoding++;
+- }
+- end = strchr(encoding, ';');
+- if (end == NULL) {
+- end = encoding + strlen(encoding);
+- }
+- end--; /* end == encoding-1 isn't a buffer underrun */
+- while (*end == ' ' || *end == '\t') {
+- end--;
+- }
+- if (*end == '"') {
+- end--;
+- }
+- if (encoding >= end) continue;
+- *(end+1) = '\0';
+- enc = xmlParseCharEncoding(encoding);
+- if (enc <= XML_CHAR_ENCODING_NONE) {
+- enc = XML_CHAR_ENCODING_NONE;
++ if (Z_TYPE_P(header) == IS_STRING) {
++ /* If no colon is found in the header, we assume it's the HTTP status line and bail out. */
++ char *colon = memchr(Z_STRVAL_P(header), ':', Z_STRLEN_P(header));
++ char *space = memchr(Z_STRVAL_P(header), ' ', Z_STRLEN_P(header));
++ if (colon == NULL || space < colon) {
++ break;
++ }
++
++ if (!zend_binary_strncasecmp(Z_STRVAL_P(header), Z_STRLEN_P(header), buf, sizeof(buf)-1, sizeof(buf)-1)) {
++ char *needle = estrdup("charset=");
++ char *haystack = estrndup(Z_STRVAL_P(header), Z_STRLEN_P(header));
++ char *encoding = php_stristr(haystack, needle, Z_STRLEN_P(header), sizeof("charset=")-1);
++
++ if (encoding) {
++ char *end;
++
++ encoding += sizeof("charset=")-1;
++ if (*encoding == '"') {
++ encoding++;
++ }
++ end = strchr(encoding, ';');
++ if (end == NULL) {
++ end = encoding + strlen(encoding);
++ }
++ end--; /* end == encoding-1 isn't a buffer underrun */
++ while (*end == ' ' || *end == '\t') {
++ end--;
++ }
++ if (*end == '"') {
++ end--;
++ }
++ if (encoding >= end) continue;
++ *(end+1) = '\0';
++ enc = xmlParseCharEncoding(encoding);
++ if (enc <= XML_CHAR_ENCODING_NONE) {
++ enc = XML_CHAR_ENCODING_NONE;
++ }
+ }
++ efree(haystack);
++ efree(needle);
++ break; /* found content-type */
+ }
+- efree(haystack);
+- efree(needle);
+- break; /* found content-type */
+ }
+ } ZEND_HASH_FOREACH_END();
+ }
+diff --git a/ext/standard/tests/http/newserver.inc b/ext/standard/tests/http/newserver.inc
+new file mode 100644
+index 00000000000..5c636705e8c
+--- /dev/null
++++ b/ext/standard/tests/http/newserver.inc
+@@ -0,0 +1,124 @@
++<?php declare(strict_types=1);
++
++function http_server_skipif() {
++
++ if (!function_exists('pcntl_fork')) die('skip pcntl_fork() not available');
++ if (!function_exists('posix_kill')) die('skip posix_kill() not available');
++ if (!stream_socket_server('tcp://localhost:0')) die('skip stream_socket_server() failed');
++}
++
++function http_server_init(&$output = null) {
++ pcntl_alarm(60);
++
++ $server = stream_socket_server('tcp://localhost:0', $errno, $errstr);
++ if (!$server) {
++ return false;
++ }
++
++ if ($output === null) {
++ $output = tmpfile();
++ if ($output === false) {
++ return false;
++ }
++ }
++
++ $pid = pcntl_fork();
++ if ($pid == -1) {
++ die('could not fork');
++ } else if ($pid) {
++ return [
++ 'pid' => $pid,
++ 'uri' => 'http://' . stream_socket_get_name($server, false),
++ ];
++ }
++
++ return $server;
++}
++
++/* Minimal HTTP server with predefined responses.
++ *
++ * $socket_string is the socket to create and listen on (e.g. tcp://127.0.0.1:1234)
++ * $files is an iterable of files or callable generator yielding files.
++ * containing N responses for N expected requests. Server dies after N requests.
++ * $output is a stream on which everything sent by clients is written to
++ */
++function http_server($files, &$output = null) {
++
++ if (!is_resource($server = http_server_init($output))) {
++ return $server;
++ }
++
++ if (is_callable($files)) {
++ $files = $files($server);
++ }
++
++ foreach($files as $file) {
++
++ $sock = stream_socket_accept($server);
++ if (!$sock) {
++ exit(1);
++ }
++
++ // read headers
++
++ $content_length = 0;
++
++ stream_set_blocking($sock, false);
++ while (!feof($sock)) {
++
++ list($r, $w, $e) = array(array($sock), null, null);
++ if (!stream_select($r, $w, $e, 1)) continue;
++
++ $line = stream_get_line($sock, 8192, "\r\n");
++ if ($line === '') {
++ fwrite($output, "\r\n");
++ break;
++ } else if ($line !== false) {
++ fwrite($output, "$line\r\n");
++
++ if (preg_match('#^Content-Length\s*:\s*([[:digit:]]+)\s*$#i', $line, $matches)) {
++ $content_length = (int) $matches[1];
++ }
++ }
++ }
++ stream_set_blocking($sock, true);
++
++ // read content
++
++ if ($content_length > 0) {
++ stream_copy_to_stream($sock, $output, $content_length);
++ }
++
++ // send response
++
++ $fd = fopen($file, 'rb');
++ stream_copy_to_stream($fd, $sock);
++
++ fclose($sock);
++ }
++
++ exit(0);
++}
++
++function http_server_sleep($micro_seconds = 500000)
++{
++ if (!is_resource($server = http_server_init($output))) {
++ return $server;
++ }
++
++ $sock = stream_socket_accept($server);
++ if (!$sock) {
++ exit(1);
++ }
++
++ usleep($micro_seconds);
++
++ fclose($sock);
++
++ exit(0);
++}
++
++function http_server_kill(int $pid) {
++ posix_kill($pid, SIGTERM);
++ pcntl_waitpid($pid, $status);
++}
+--
+2.48.1
+
+From c5e836c5f98c6a01778595d448bb6a5b84eccec1 Mon Sep 17 00:00:00 2001
+From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
+Date: Wed, 18 Dec 2024 18:44:05 +0100
+Subject: [PATCH 09/11] Fix GHSA-wg4p-4hqh-c3g9
+
+(cherry picked from commit 0e715e71d945b68f8ccedd62c5960df747af6625)
+(cherry picked from commit 294140ee981fda6a38244215e4b16e53b7f5b2a6)
+---
+ ext/xml/tests/toffset_bounds.phpt | 42 +++++++++++++++++++++++++++++++
+ ext/xml/xml.c | 12 ++++++---
+ 2 files changed, 50 insertions(+), 4 deletions(-)
+ create mode 100644 ext/xml/tests/toffset_bounds.phpt
+
+diff --git a/ext/xml/tests/toffset_bounds.phpt b/ext/xml/tests/toffset_bounds.phpt
+new file mode 100644
+index 00000000000..5a3fd22f86c
+--- /dev/null
++++ b/ext/xml/tests/toffset_bounds.phpt
+@@ -0,0 +1,42 @@
++--TEST--
++XML_OPTION_SKIP_TAGSTART bounds
++--EXTENSIONS--
++xml
++--FILE--
++<?php
++$sample = "<?xml version=\"1.0\"?><test><child/></test>";
++$parser = xml_parser_create();
++xml_parser_set_option($parser, XML_OPTION_SKIP_TAGSTART, 100);
++$res = xml_parse_into_struct($parser,$sample,$vals,$index);
++var_dump($vals);
++?>
++--EXPECT--
++array(3) {
++ [0]=>
++ array(3) {
++ ["tag"]=>
++ string(0) ""
++ ["type"]=>
++ string(4) "open"
++ ["level"]=>
++ int(1)
++ }
++ [1]=>
++ array(3) {
++ ["tag"]=>
++ string(0) ""
++ ["type"]=>
++ string(8) "complete"
++ ["level"]=>
++ int(2)
++ }
++ [2]=>
++ array(3) {
++ ["tag"]=>
++ string(0) ""
++ ["type"]=>
++ string(5) "close"
++ ["level"]=>
++ int(1)
++ }
++}
+diff --git a/ext/xml/xml.c b/ext/xml/xml.c
+index 6fe6151c7a1..b56bf79f55d 100644
+--- a/ext/xml/xml.c
++++ b/ext/xml/xml.c
+@@ -773,9 +773,11 @@ void _xml_startElementHandler(void *userData, const XML_Char *name, const XML_Ch
+ array_init(&tag);
+ array_init(&atr);
+
+- _xml_add_to_info(parser, ZSTR_VAL(tag_name) + parser->toffset);
++ char *skipped_tag_name = SKIP_TAGSTART(ZSTR_VAL(tag_name));
+
+- add_assoc_string(&tag, "tag", SKIP_TAGSTART(ZSTR_VAL(tag_name))); /* cast to avoid gcc-warning */
++ _xml_add_to_info(parser, skipped_tag_name);
++
++ add_assoc_string(&tag, "tag", skipped_tag_name);
+ add_assoc_string(&tag, "type", "open");
+ add_assoc_long(&tag, "level", parser->level);
+
+@@ -842,9 +844,11 @@ void _xml_endElementHandler(void *userData, const XML_Char *name)
+ } else {
+ array_init(&tag);
+
+- _xml_add_to_info(parser, ZSTR_VAL(tag_name) + parser->toffset);
++ char *skipped_tag_name = SKIP_TAGSTART(ZSTR_VAL(tag_name));
++
++ _xml_add_to_info(parser, skipped_tag_name);
+
+- add_assoc_string(&tag, "tag", SKIP_TAGSTART(ZSTR_VAL(tag_name))); /* cast to avoid gcc-warning */
++ add_assoc_string(&tag, "tag", skipped_tag_name);
+ add_assoc_string(&tag, "type", "close");
+ add_assoc_long(&tag, "level", parser->level);
+
+--
+2.48.1
+
+From 3faf7b2017ccd1e7347c30cf64cddcb684300cba Mon Sep 17 00:00:00 2001
+From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
+Date: Fri, 17 Nov 2023 19:45:40 +0100
+Subject: [PATCH 10/11] Fix GH-12702: libxml2 2.12.0 issue building from src
+
+Fixes GH-12702.
+
+Co-authored-by: nono303 <github@nono303.net>
+(cherry picked from commit 6a76e5d0a2dcf46b4ab74cc3ffcbfeb860c4fdb3)
+(cherry picked from commit d7ab2bb9856d938fca7989575695c14c25892589)
+---
+ ext/dom/document.c | 1 +
+ ext/libxml/php_libxml.h | 1 +
+ 2 files changed, 2 insertions(+)
+
+diff --git a/ext/dom/document.c b/ext/dom/document.c
+index af06fb41240..f8071774b92 100644
+--- a/ext/dom/document.c
++++ b/ext/dom/document.c
+@@ -25,6 +25,7 @@
+ #if HAVE_LIBXML && HAVE_DOM
+ #include "php_dom.h"
+ #include <libxml/SAX.h>
++#include <libxml/xmlsave.h>
+ #ifdef LIBXML_SCHEMAS_ENABLED
+ #include <libxml/relaxng.h>
+ #include <libxml/xmlschemas.h>
+diff --git a/ext/libxml/php_libxml.h b/ext/libxml/php_libxml.h
+index 92028d5703e..6f3295b5241 100644
+--- a/ext/libxml/php_libxml.h
++++ b/ext/libxml/php_libxml.h
+@@ -37,6 +37,7 @@ extern zend_module_entry libxml_module_entry;
+
+ #include "zend_smart_str.h"
+ #include <libxml/tree.h>
++#include <libxml/parser.h>
+
+ #define LIBXML_SAVE_NOEMPTYTAG 1<<2
+
+--
+2.48.1
+
+From 8ab957ca87b42b808aec7fd472fbc4063073a119 Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@remirepo.net>
+Date: Thu, 13 Mar 2025 09:39:19 +0100
+Subject: [PATCH 11/11] NEWS
+
+(cherry picked from commit adae2b8de8963ac6f92103803bf91a5174172f88)
+---
+ NEWS | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+diff --git a/NEWS b/NEWS
+index 09cf2cfa0bb..fda646c7010 100644
+--- a/NEWS
++++ b/NEWS
+@@ -1,6 +1,23 @@
+ PHP NEWS
+ |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+
++Backported from 8.1.32
++
++- LibXML:
++ . Fixed GHSA-wg4p-4hqh-c3g9 (Reocurrence of #72714). (nielsdos)
++ . Fixed GHSA-p3x9-6h7p-cgfc (libxml streams use wrong `content-type` header
++ when requesting a redirected resource). (CVE-2025-1219) (timwolla)
++
++- Streams:
++ . Fixed GHSA-hgf54-96fm-v528 (Stream HTTP wrapper header check might omit
++ basic auth header). (CVE-2025-1736) (Jakub Zelenka)
++ . Fixed GHSA-52jp-hrpf-2jff (Stream HTTP wrapper truncate redirect location
++ to 1024 bytes). (CVE-2025-1861) (Jakub Zelenka)
++ . Fixed GHSA-pcmh-g36c-qc44 (Streams HTTP wrapper does not fail for headers
++ without colon). (CVE-2025-1734) (Jakub Zelenka)
++ . Fixed GHSA-v8xr-gpvj-cx9g (Header parser of `http` stream wrapper does not
++ handle folded headers). (CVE-2025-1217) (Jakub Zelenka)
++
+ Backported from 8.1.31
+
+ - CLI:
+--
+2.48.1
+
diff --git a/php-cve-2025-1220.patch b/php-cve-2025-1220.patch
new file mode 100644
index 0000000..25f3b61
--- /dev/null
+++ b/php-cve-2025-1220.patch
@@ -0,0 +1,154 @@
+From d407d8a8735ebf43bee3e6b49fb013b8aa4b6bfc Mon Sep 17 00:00:00 2001
+From: Jakub Zelenka <bukka@php.net>
+Date: Thu, 10 Apr 2025 15:15:36 +0200
+Subject: [PATCH 2/4] Fix GHSA-3cr5-j632-f35r: Null byte in hostnames
+
+This fixes stream_socket_client() and fsockopen().
+
+Specifically it adds a check to parse_ip_address_ex and it also makes
+sure that the \0 is not ignored in fsockopen() hostname formatting.
+
+(cherry picked from commit cac8f7f1cf4939f55f06b68120040f057682d89c)
+(cherry picked from commit 36150278addd8686a9899559241296094bd57282)
+---
+ ext/standard/fsock.c | 27 +++++++++++++++++--
+ .../tests/network/ghsa-3cr5-j632-f35r.phpt | 21 +++++++++++++++
+ .../tests/streams/ghsa-3cr5-j632-f35r.phpt | 26 ++++++++++++++++++
+ main/streams/xp_socket.c | 9 ++++---
+ 4 files changed, 78 insertions(+), 5 deletions(-)
+ create mode 100644 ext/standard/tests/network/ghsa-3cr5-j632-f35r.phpt
+ create mode 100644 ext/standard/tests/streams/ghsa-3cr5-j632-f35r.phpt
+
+diff --git a/ext/standard/fsock.c b/ext/standard/fsock.c
+index fe8fbea85ca..df6a74b078f 100644
+--- a/ext/standard/fsock.c
++++ b/ext/standard/fsock.c
+@@ -25,6 +25,28 @@
+ #include "php_network.h"
+ #include "file.h"
+
++static size_t php_fsockopen_format_host_port(char **message, const char *prefix, size_t prefix_len,
++ const char *host, size_t host_len, zend_long port)
++{
++ char portbuf[32];
++ int portlen = snprintf(portbuf, sizeof(portbuf), ":" ZEND_LONG_FMT, port);
++ size_t total_len = prefix_len + host_len + portlen;
++
++ char *result = emalloc(total_len + 1);
++
++ if (prefix_len > 0) {
++ memcpy(result, prefix, prefix_len);
++ }
++ memcpy(result + prefix_len, host, host_len);
++ memcpy(result + prefix_len + host_len, portbuf, portlen);
++
++ result[total_len] = '\0';
++
++ *message = result;
++
++ return total_len;
++}
++
+ /* {{{ php_fsockopen() */
+
+ static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent)
+@@ -59,11 +81,12 @@ static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent)
+ ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
+
+ if (persistent) {
+- spprintf(&hashkey, 0, "pfsockopen__%s:" ZEND_LONG_FMT, host, port);
++ php_fsockopen_format_host_port(&hashkey, "pfsockopen__", strlen("pfsockopen__"), host,
++ host_len, port);
+ }
+
+ if (port > 0) {
+- hostname_len = spprintf(&hostname, 0, "%s:" ZEND_LONG_FMT, host, port);
++ hostname_len = php_fsockopen_format_host_port(&hostname, "", 0, host, host_len, port);
+ } else {
+ hostname_len = host_len;
+ hostname = host;
+diff --git a/ext/standard/tests/network/ghsa-3cr5-j632-f35r.phpt b/ext/standard/tests/network/ghsa-3cr5-j632-f35r.phpt
+new file mode 100644
+index 00000000000..e16d3fa9060
+--- /dev/null
++++ b/ext/standard/tests/network/ghsa-3cr5-j632-f35r.phpt
+@@ -0,0 +1,21 @@
++--TEST--
++GHSA-3cr5-j632-f35r: Null byte termination in fsockopen()
++--FILE--
++<?php
++
++$server = stream_socket_server("tcp://localhost:0");
++
++if (preg_match('/:(\d+)$/', stream_socket_get_name($server, false), $m)) {
++ $client = fsockopen("localhost\0.example.com", intval($m[1]));
++ var_dump($client);
++ if ($client) {
++ fclose($client);
++ }
++}
++fclose($server);
++
++?>
++--EXPECTF--
++
++Warning: fsockopen(): unable to connect to localhost:%d (The hostname must not contain null bytes) in %s
++bool(false)
+diff --git a/ext/standard/tests/streams/ghsa-3cr5-j632-f35r.phpt b/ext/standard/tests/streams/ghsa-3cr5-j632-f35r.phpt
+new file mode 100644
+index 00000000000..bc1f34eaf58
+--- /dev/null
++++ b/ext/standard/tests/streams/ghsa-3cr5-j632-f35r.phpt
+@@ -0,0 +1,26 @@
++--TEST--
++GHSA-3cr5-j632-f35r: Null byte termination in stream_socket_client()
++--FILE--
++<?php
++
++$server = stream_socket_server("tcp://localhost:0");
++$socket_name = stream_socket_get_name($server, false);
++
++if (preg_match('/:(\d+)$/', $socket_name, $m)) {
++ $port = $m[1];
++ $client = stream_socket_client("tcp://localhost\0.example.com:$port");
++ var_dump($client);
++ if ($client) {
++ fclose($client);
++ }
++} else {
++ echo "Could not extract port from socket name: $socket_name\n";
++}
++
++fclose($server);
++
++?>
++--EXPECTF--
++
++Warning: stream_socket_client(): unable to connect to tcp://localhost\0.example.com:%d (The hostname must not contain null bytes) in %s
++bool(false)
+diff --git a/main/streams/xp_socket.c b/main/streams/xp_socket.c
+index 46b23b63ada..7a192ea6c0b 100644
+--- a/main/streams/xp_socket.c
++++ b/main/streams/xp_socket.c
+@@ -580,12 +580,15 @@ static inline char *parse_ip_address_ex(const char *str, size_t str_len, int *po
+ char *colon;
+ char *host = NULL;
+
+-#ifdef HAVE_IPV6
+- char *p;
++ if (memchr(str, '\0', str_len)) {
++ *err = strpprintf(0, "The hostname must not contain null bytes");
++ return NULL;
++ }
+
++#ifdef HAVE_IPV6
+ if (*(str) == '[' && str_len > 1) {
+ /* IPV6 notation to specify raw address with port (i.e. [fe80::1]:80) */
+- p = memchr(str + 1, ']', str_len - 2);
++ char *p = memchr(str + 1, ']', str_len - 2);
+ if (!p || *(p + 1) != ':') {
+ if (get_err) {
+ *err = strpprintf(0, "Failed to parse IPv6 address \"%s\"", str);
+--
+2.50.0
+
diff --git a/php-cve-2025-1734.patch b/php-cve-2025-1734.patch
new file mode 100644
index 0000000..6c9aa52
--- /dev/null
+++ b/php-cve-2025-1734.patch
@@ -0,0 +1,314 @@
+From 0b965cf85f512b1a7b87f100ac77e4aa13f7f421 Mon Sep 17 00:00:00 2001
+From: Jakub Zelenka <bukka@php.net>
+Date: Sun, 19 Jan 2025 17:49:53 +0100
+Subject: [PATCH 02/11] Fix GHSA-pcmh-g36c-qc44: http headers without colon
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The header line must contain colon otherwise it is invalid and it needs
+to fail.
+
+Reviewed-by: Tim Düsterhus <tim@tideways-gmbh.com>
+(cherry picked from commit 0548c4c1756724a89ef8310709419b08aadb2b3b)
+(cherry picked from commit e81d0cd14bfeb17e899c73e3aece4991bbda76af)
+---
+ ext/standard/http_fopen_wrapper.c | 51 ++++++++++++++-----
+ ext/standard/tests/http/bug47021.phpt | 26 ++++++----
+ ext/standard/tests/http/bug75535.phpt | 4 +-
+ .../tests/http/ghsa-pcmh-g36c-qc44-001.phpt | 51 +++++++++++++++++++
+ .../tests/http/ghsa-pcmh-g36c-qc44-002.phpt | 51 +++++++++++++++++++
+ 5 files changed, 156 insertions(+), 27 deletions(-)
+ create mode 100644 ext/standard/tests/http/ghsa-pcmh-g36c-qc44-001.phpt
+ create mode 100644 ext/standard/tests/http/ghsa-pcmh-g36c-qc44-002.phpt
+
+diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c
+index 08386cfafcd..071d6a4d119 100644
+--- a/ext/standard/http_fopen_wrapper.c
++++ b/ext/standard/http_fopen_wrapper.c
+@@ -119,6 +119,7 @@ static zend_bool check_has_header(const char *headers, const char *header) {
+ typedef struct _php_stream_http_response_header_info {
+ php_stream_filter *transfer_encoding;
+ size_t file_size;
++ zend_bool error;
+ zend_bool follow_location;
+ char location[HTTP_HEADER_BLOCK_SIZE];
+ } php_stream_http_response_header_info;
+@@ -128,6 +129,7 @@ static void php_stream_http_response_header_info_init(
+ {
+ header_info->transfer_encoding = NULL;
+ header_info->file_size = 0;
++ header_info->error = 0;
+ header_info->follow_location = 1;
+ header_info->location[0] = '\0';
+ }
+@@ -165,10 +167,11 @@ static zend_bool php_stream_http_response_header_trim(char *http_header_line,
+ /* Process folding headers of the current line and if there are none, parse last full response
+ * header line. It returns NULL if the last header is finished, otherwise it returns updated
+ * last header line. */
+-static zend_string *php_stream_http_response_headers_parse(php_stream *stream,
+- php_stream_context *context, int options, zend_string *last_header_line_str,
+- char *header_line, size_t *header_line_length, int response_code,
+- zval *response_header, php_stream_http_response_header_info *header_info)
++static zend_string *php_stream_http_response_headers_parse(php_stream_wrapper *wrapper,
++ php_stream *stream, php_stream_context *context, int options,
++ zend_string *last_header_line_str, char *header_line, size_t *header_line_length,
++ int response_code, zval *response_header,
++ php_stream_http_response_header_info *header_info)
+ {
+ char *last_header_line = ZSTR_VAL(last_header_line_str);
+ size_t last_header_line_length = ZSTR_LEN(last_header_line_str);
+@@ -211,6 +214,19 @@ static zend_string *php_stream_http_response_headers_parse(php_stream *stream,
+ /* Find header separator position. */
+ char *last_header_value = memchr(last_header_line, ':', last_header_line_length);
+ if (last_header_value) {
++ /* Verify there is no space in header name */
++ char *last_header_name = last_header_line + 1;
++ while (last_header_name < last_header_value) {
++ if (*last_header_name == ' ' || *last_header_name == '\t') {
++ header_info->error = 1;
++ php_stream_wrapper_log_error(wrapper, options,
++ "HTTP invalid response format (space in header name)!");
++ zend_string_efree(last_header_line_str);
++ return NULL;
++ }
++ ++last_header_name;
++ }
++
+ last_header_value++; /* Skip ':'. */
+
+ /* Strip leading whitespace. */
+@@ -219,9 +235,12 @@ static zend_string *php_stream_http_response_headers_parse(php_stream *stream,
+ last_header_value++;
+ }
+ } else {
+- /* There is no colon. Set the value to the end of the header line, which is effectively
+- * an empty string. */
+- last_header_value = last_header_line_end;
++ /* There is no colon which means invalid response so error. */
++ header_info->error = 1;
++ php_stream_wrapper_log_error(wrapper, options,
++ "HTTP invalid response format (no colon in header line)!");
++ zend_string_efree(last_header_line_str);
++ return NULL;
+ }
+
+ zend_bool store_header = 1;
+@@ -927,10 +946,16 @@ finish:
+
+ if (last_header_line_str != NULL) {
+ /* Parse last header line. */
+- last_header_line_str = php_stream_http_response_headers_parse(stream, context,
+- options, last_header_line_str, http_header_line, &http_header_line_length,
+- response_code, response_header, &header_info);
+- if (last_header_line_str != NULL) {
++ last_header_line_str = php_stream_http_response_headers_parse(wrapper, stream,
++ context, options, last_header_line_str, http_header_line,
++ &http_header_line_length, response_code, response_header, &header_info);
++ if (EXPECTED(last_header_line_str == NULL)) {
++ if (UNEXPECTED(header_info.error)) {
++ php_stream_close(stream);
++ stream = NULL;
++ goto out;
++ }
++ } else {
+ /* Folding header present so continue. */
+ continue;
+ }
+@@ -960,8 +985,8 @@ finish:
+
+ /* If the stream was closed early, we still want to process the last line to keep BC. */
+ if (last_header_line_str != NULL) {
+- php_stream_http_response_headers_parse(stream, context, options, last_header_line_str,
+- NULL, NULL, response_code, response_header, &header_info);
++ php_stream_http_response_headers_parse(wrapper, stream, context, options,
++ last_header_line_str, NULL, NULL, response_code, response_header, &header_info);
+ }
+
+ if (!reqok || (header_info.location[0] != '\0' && header_info.follow_location)) {
+diff --git a/ext/standard/tests/http/bug47021.phpt b/ext/standard/tests/http/bug47021.phpt
+index f3db3e1be23..a287b714c62 100644
+--- a/ext/standard/tests/http/bug47021.phpt
++++ b/ext/standard/tests/http/bug47021.phpt
+@@ -47,9 +47,9 @@ function do_test($num_spaces, $leave_trailing_space=false) {
+ ];
+ $pid = http_server('tcp://127.0.0.1:12342', $responses);
+
+- echo file_get_contents('http://127.0.0.1:12342/', false, $ctx);
++ echo file_get_contents('http://127.0.0.1:12342', false, $ctx);
+ echo "\n";
+- echo file_get_contents('http://127.0.0.1:12342/', false, $ctx);
++ echo file_get_contents('http://127.0.0.1:12342', false, $ctx);
+ echo "\n";
+
+ http_server_kill($pid);
+@@ -70,23 +70,27 @@ do_test(1, true);
+ echo "\n";
+
+ ?>
+---EXPECT--
++--EXPECTF--
++
+ Type='text/plain'
+ Hello
+-Size=5
+-World
++
++Warning: file_get_contents(http://%s:%d): failed to open stream: HTTP invalid response format (no colon in header line)! in %s
++
+
+ Type='text/plain'
+ Hello
+-Size=5
+-World
++
++Warning: file_get_contents(http://%s:%d): failed to open stream: HTTP invalid response format (no colon in header line)! in %s
++
+
+ Type='text/plain'
+ Hello
+-Size=5
+-World
++
++Warning: file_get_contents(http://%s:%d): failed to open stream: HTTP invalid response format (no colon in header line)! in %s
++
+
+ Type='text/plain'
+ Hello
+-Size=5
+-World
++
++Warning: file_get_contents(http://%s:%d): failed to open stream: HTTP invalid response format (no colon in header line)! in %s
+diff --git a/ext/standard/tests/http/bug75535.phpt b/ext/standard/tests/http/bug75535.phpt
+index 9bf298cc065..e3757ba4f1d 100644
+--- a/ext/standard/tests/http/bug75535.phpt
++++ b/ext/standard/tests/http/bug75535.phpt
+@@ -22,10 +22,8 @@ http_server_kill($pid);
+ ==DONE==
+ --EXPECT--
+ string(0) ""
+-array(2) {
++array(1) {
+ [0]=>
+ string(15) "HTTP/1.0 200 Ok"
+- [1]=>
+- string(14) "Content-Length"
+ }
+ ==DONE==
+diff --git a/ext/standard/tests/http/ghsa-pcmh-g36c-qc44-001.phpt b/ext/standard/tests/http/ghsa-pcmh-g36c-qc44-001.phpt
+new file mode 100644
+index 00000000000..53baa1c92d6
+--- /dev/null
++++ b/ext/standard/tests/http/ghsa-pcmh-g36c-qc44-001.phpt
+@@ -0,0 +1,51 @@
++--TEST--
++GHSA-pcmh-g36c-qc44: Header parser of http stream wrapper does not verify header name and colon (colon)
++--FILE--
++<?php
++$serverCode = <<<'CODE'
++ $ctxt = stream_context_create([
++ "socket" => [
++ "tcp_nodelay" => true
++ ]
++ ]);
++
++ $server = stream_socket_server(
++ "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt);
++ phpt_notify_server_start($server);
++
++ $conn = stream_socket_accept($server);
++
++ phpt_notify(WORKER_DEFAULT_NAME, "server-accepted");
++
++ fwrite($conn, "HTTP/1.0 200 Ok\r\nContent-Type: text/html\r\nWrong-Header\r\nGood-Header: test\r\n\r\nbody\r\n");
++CODE;
++
++$clientCode = <<<'CODE'
++ function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) {
++ switch($notification_code) {
++ case STREAM_NOTIFY_MIME_TYPE_IS:
++ echo "Found the mime-type: ", $message, PHP_EOL;
++ break;
++ }
++ }
++
++ $ctx = stream_context_create();
++ stream_context_set_params($ctx, array("notification" => "stream_notification_callback"));
++ var_dump(file_get_contents("http://{{ ADDR }}", false, $ctx));
++ var_dump($http_response_header);
++CODE;
++
++include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
++ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
++?>
++--EXPECTF--
++Found the mime-type: text/html
++
++Warning: file_get_contents(http://127.0.0.1:%d): failed to open stream: HTTP invalid response format (no colon in header line)! in %s
++bool(false)
++array(2) {
++ [0]=>
++ string(15) "HTTP/1.0 200 Ok"
++ [1]=>
++ string(23) "Content-Type: text/html"
++}
+diff --git a/ext/standard/tests/http/ghsa-pcmh-g36c-qc44-002.phpt b/ext/standard/tests/http/ghsa-pcmh-g36c-qc44-002.phpt
+new file mode 100644
+index 00000000000..5aa0ee00618
+--- /dev/null
++++ b/ext/standard/tests/http/ghsa-pcmh-g36c-qc44-002.phpt
+@@ -0,0 +1,51 @@
++--TEST--
++GHSA-pcmh-g36c-qc44: Header parser of http stream wrapper does not verify header name and colon (name)
++--FILE--
++<?php
++$serverCode = <<<'CODE'
++ $ctxt = stream_context_create([
++ "socket" => [
++ "tcp_nodelay" => true
++ ]
++ ]);
++
++ $server = stream_socket_server(
++ "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt);
++ phpt_notify_server_start($server);
++
++ $conn = stream_socket_accept($server);
++
++ phpt_notify(WORKER_DEFAULT_NAME, "server-accepted");
++
++ fwrite($conn, "HTTP/1.0 200 Ok\r\nContent-Type: text/html\r\nWrong-Header : test\r\nGood-Header: test\r\n\r\nbody\r\n");
++CODE;
++
++$clientCode = <<<'CODE'
++ function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) {
++ switch($notification_code) {
++ case STREAM_NOTIFY_MIME_TYPE_IS:
++ echo "Found the mime-type: ", $message, PHP_EOL;
++ break;
++ }
++ }
++
++ $ctx = stream_context_create();
++ stream_context_set_params($ctx, array("notification" => "stream_notification_callback"));
++ var_dump(file_get_contents("http://{{ ADDR }}", false, $ctx));
++ var_dump($http_response_header);
++CODE;
++
++include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
++ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
++?>
++--EXPECTF--
++Found the mime-type: text/html
++
++Warning: file_get_contents(http://127.0.0.1:%d): failed to open stream: HTTP invalid response format (space in header name)! in %s
++bool(false)
++array(2) {
++ [0]=>
++ string(15) "HTTP/1.0 200 Ok"
++ [1]=>
++ string(23) "Content-Type: text/html"
++}
+--
+2.48.1
+
diff --git a/php-cve-2025-1735.patch b/php-cve-2025-1735.patch
new file mode 100644
index 0000000..e144cc4
--- /dev/null
+++ b/php-cve-2025-1735.patch
@@ -0,0 +1,492 @@
+From df2ecf34256c4a301e8959fe2eed0323f8b1b57a Mon Sep 17 00:00:00 2001
+From: Jakub Zelenka <bukka@php.net>
+Date: Tue, 4 Mar 2025 17:23:01 +0100
+Subject: [PATCH 3/4] Fix GHSA-hrwm-9436-5mv3: pgsql escaping no error checks
+
+This adds error checks for escape function is pgsql and pdo_pgsql
+extensions. It prevents possibility of storing not properly escaped
+data which could potentially lead to some security issues.
+
+(cherry picked from commit 9376aeef9f8ff81f2705b8016237ec3e30bdee44)
+(cherry picked from commit 7633d987cc11ee2601223e73cfdb8b31fed5980f)
+---
+ ext/pdo_pgsql/pgsql_driver.c | 10 +-
+ ext/pdo_pgsql/tests/ghsa-hrwm-9436-5mv3.phpt | 22 ++++
+ ext/pgsql/pgsql.c | 129 +++++++++++++++----
+ ext/pgsql/tests/ghsa-hrwm-9436-5mv3.phpt | 64 +++++++++
+ 4 files changed, 202 insertions(+), 23 deletions(-)
+ create mode 100644 ext/pdo_pgsql/tests/ghsa-hrwm-9436-5mv3.phpt
+ create mode 100644 ext/pgsql/tests/ghsa-hrwm-9436-5mv3.phpt
+
+diff --git a/ext/pdo_pgsql/pgsql_driver.c b/ext/pdo_pgsql/pgsql_driver.c
+index e578bbc2720..021471cefc0 100644
+--- a/ext/pdo_pgsql/pgsql_driver.c
++++ b/ext/pdo_pgsql/pgsql_driver.c
+@@ -323,11 +323,15 @@ static int pgsql_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, size_t unqu
+ unsigned char *escaped;
+ pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
+ size_t tmp_len;
++ int err;
+
+ switch (paramtype) {
+ case PDO_PARAM_LOB:
+ /* escapedlen returned by PQescapeBytea() accounts for trailing 0 */
+ escaped = PQescapeByteaConn(H->server, (unsigned char *)unquoted, unquotedlen, &tmp_len);
++ if (escaped == NULL) {
++ return 0;
++ }
+ *quotedlen = tmp_len + 1;
+ *quoted = emalloc(*quotedlen + 1);
+ memcpy((*quoted)+1, escaped, *quotedlen-2);
+@@ -339,7 +343,11 @@ static int pgsql_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, size_t unqu
+ default:
+ *quoted = safe_emalloc(2, unquotedlen, 3);
+ (*quoted)[0] = '\'';
+- *quotedlen = PQescapeStringConn(H->server, *quoted + 1, unquoted, unquotedlen, NULL);
++ *quotedlen = PQescapeStringConn(H->server, *quoted + 1, unquoted, unquotedlen, &err);
++ if (err) {
++ efree(*quoted);
++ return 0;
++ }
+ (*quoted)[*quotedlen + 1] = '\'';
+ (*quoted)[*quotedlen + 2] = '\0';
+ *quotedlen += 2;
+diff --git a/ext/pdo_pgsql/tests/ghsa-hrwm-9436-5mv3.phpt b/ext/pdo_pgsql/tests/ghsa-hrwm-9436-5mv3.phpt
+new file mode 100644
+index 00000000000..60e13613d04
+--- /dev/null
++++ b/ext/pdo_pgsql/tests/ghsa-hrwm-9436-5mv3.phpt
+@@ -0,0 +1,22 @@
++--TEST--
++#GHSA-hrwm-9436-5mv3: pdo_pgsql extension does not check for errors during escaping
++--SKIPIF--
++<?php
++if (!extension_loaded('pdo') || !extension_loaded('pdo_pgsql')) die('skip not loaded');
++require_once dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
++require_once dirname(__FILE__) . '/config.inc';
++PDOTest::skip();
++?>
++--FILE--
++<?php
++require_once dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
++require_once dirname(__FILE__) . '/config.inc';
++$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
++$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
++
++$invalid = "ABC\xff\x30';";
++var_dump($db->quote($invalid));
++
++?>
++--EXPECT--
++bool(false)
+diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c
+index 7dcd56cf144..9e06497125c 100644
+--- a/ext/pgsql/pgsql.c
++++ b/ext/pgsql/pgsql.c
+@@ -4393,10 +4393,16 @@ PHP_FUNCTION(pg_escape_string)
+ to = zend_string_safe_alloc(ZSTR_LEN(from), 2, 0, 0);
+ #ifdef HAVE_PQESCAPE_CONN
+ if (link) {
++ int err;
+ if ((pgsql = (PGconn *)zend_fetch_resource2(link, "PostgreSQL link", le_link, le_plink)) == NULL) {
+ RETURN_FALSE;
+ }
+- ZSTR_LEN(to) = PQescapeStringConn(pgsql, ZSTR_VAL(to), ZSTR_VAL(from), ZSTR_LEN(from), NULL);
++ ZSTR_LEN(to) = PQescapeStringConn(pgsql, ZSTR_VAL(to), ZSTR_VAL(from), ZSTR_LEN(from), &err);
++ if (err) {
++ zend_throw_exception(zend_ce_exception, "Escaping string failed", 0);
++ zend_string_efree(to);
++ return;
++ }
+ } else
+ #endif
+ {
+@@ -4445,6 +4451,10 @@ PHP_FUNCTION(pg_escape_bytea)
+ } else
+ #endif
+ to = (char *)PQescapeBytea((unsigned char*)from, from_len, &to_len);
++ if (to == NULL) {
++ zend_throw_exception(zend_ce_exception, "Escape failure", 0);
++ return;
++ }
+
+ RETVAL_STRINGL(to, to_len-1); /* to_len includes additional '\0' */
+ PQfreemem(to);
+@@ -5529,7 +5539,7 @@ PHP_PGSQL_API int php_pgsql_meta_data(PGconn *pg_link, const char *table_name, z
+ char *escaped;
+ smart_str querystr = {0};
+ size_t new_len;
+- int i, num_rows;
++ int i, num_rows, err;
+ zval elem;
+
+ if (!*table_name) {
+@@ -5570,7 +5580,14 @@ PHP_PGSQL_API int php_pgsql_meta_data(PGconn *pg_link, const char *table_name, z
+ "WHERE a.attnum > 0 AND c.relname = '");
+ }
+ escaped = (char *)safe_emalloc(strlen(tmp_name2), 2, 1);
+- new_len = PQescapeStringConn(pg_link, escaped, tmp_name2, strlen(tmp_name2), NULL);
++ new_len = PQescapeStringConn(pg_link, escaped, tmp_name2, strlen(tmp_name2), &err);
++ if (err) {
++ php_error_docref(NULL, E_WARNING, "Escaping table name '%s' failed", table_name);
++ efree(src);
++ efree(escaped);
++ smart_str_free(&querystr);
++ return FAILURE;
++ }
+ if (new_len) {
+ smart_str_appendl(&querystr, escaped, new_len);
+ }
+@@ -5578,7 +5595,14 @@ PHP_PGSQL_API int php_pgsql_meta_data(PGconn *pg_link, const char *table_name, z
+
+ smart_str_appends(&querystr, "' AND n.nspname = '");
+ escaped = (char *)safe_emalloc(strlen(tmp_name), 2, 1);
+- new_len = PQescapeStringConn(pg_link, escaped, tmp_name, strlen(tmp_name), NULL);
++ new_len = PQescapeStringConn(pg_link, escaped, tmp_name, strlen(tmp_name), &err);
++ if (err) {
++ php_error_docref(NULL, E_WARNING, "Escaping table namespace '%s' failed", table_name);
++ efree(src);
++ efree(escaped);
++ smart_str_free(&querystr);
++ return FAILURE;
++ }
+ if (new_len) {
+ smart_str_appendl(&querystr, escaped, new_len);
+ }
+@@ -5850,7 +5874,7 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
+ {
+ zend_string *field = NULL;
+ zval meta, *def, *type, *not_null, *has_default, *is_enum, *val, new_val;
+- int err = 0, skip_field;
++ int err = 0, escape_err = 0, skip_field;
+ php_pgsql_data_type data_type;
+
+ assert(pg_link != NULL);
+@@ -6101,10 +6125,14 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
+ /* PostgreSQL ignores \0 */
+ str = zend_string_alloc(Z_STRLEN_P(val) * 2, 0);
+ /* better to use PGSQLescapeLiteral since PGescapeStringConn does not handle special \ */
+- ZSTR_LEN(str) = PQescapeStringConn(pg_link, ZSTR_VAL(str), Z_STRVAL_P(val), Z_STRLEN_P(val), NULL);
+- str = zend_string_truncate(str, ZSTR_LEN(str), 0);
+- ZVAL_NEW_STR(&new_val, str);
+- php_pgsql_add_quotes(&new_val, 1);
++ ZSTR_LEN(str) = PQescapeStringConn(pg_link, ZSTR_VAL(str), Z_STRVAL_P(val), Z_STRLEN_P(val), &escape_err);
++ if (escape_err) {
++ err = 1;
++ } else {
++ str = zend_string_truncate(str, ZSTR_LEN(str), 0);
++ ZVAL_NEW_STR(&new_val, str);
++ php_pgsql_add_quotes(&new_val, 1);
++ }
+ }
+ break;
+
+@@ -6126,7 +6154,15 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
+ }
+ PGSQL_CONV_CHECK_IGNORE();
+ if (err) {
+- php_error_docref(NULL, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
++ if (escape_err) {
++ php_error_docref(NULL, E_NOTICE,
++ "String value escaping failed for PostgreSQL '%s' (%s)",
++ Z_STRVAL_P(type), ZSTR_VAL(field));
++ } else {
++ php_error_docref(NULL, E_NOTICE,
++ "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)",
++ Z_STRVAL_P(type), ZSTR_VAL(field));
++ }
+ }
+ break;
+
+@@ -6406,6 +6442,11 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
+ #else
+ tmp = PQescapeBytea(Z_STRVAL_P(val), (unsigned char *)Z_STRLEN_P(val), &to_len);
+ #endif
++ if (tmp == NULL) {
++ php_error_docref(NULL, E_NOTICE, "Escaping value failed for %s field (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
++ err = 1;
++ break;
++ }
+ ZVAL_STRINGL(&new_val, (char *)tmp, to_len - 1); /* PQescapeBytea's to_len includes additional '\0' */
+ PQfreemem(tmp);
+ php_pgsql_add_quotes(&new_val, 1);
+@@ -6488,6 +6529,12 @@ PHP_PGSQL_API int php_pgsql_convert(PGconn *pg_link, const char *table_name, con
+ zend_hash_update(Z_ARRVAL_P(result), field, &new_val);
+ } else {
+ char *escaped = PGSQLescapeIdentifier(pg_link, ZSTR_VAL(field), ZSTR_LEN(field));
++ if (escaped == NULL) {
++ /* This cannot fail because of invalid string but only due to failed memory allocation */
++ php_error_docref(NULL, E_NOTICE, "Escaping field '%s' failed", ZSTR_VAL(field));
++ err = 1;
++ break;
++ }
+ add_assoc_zval(result, escaped, &new_val);
+ PGSQLfree(escaped);
+ }
+@@ -6566,7 +6613,7 @@ static int do_exec(smart_str *querystr, ExecStatusType expect, PGconn *pg_link,
+ }
+ /* }}} */
+
+-static inline void build_tablename(smart_str *querystr, PGconn *pg_link, const char *table) /* {{{ */
++static inline int build_tablename(smart_str *querystr, PGconn *pg_link, const char *table) /* {{{ */
+ {
+ size_t table_len = strlen(table);
+
+@@ -6577,6 +6624,10 @@ static inline void build_tablename(smart_str *querystr, PGconn *pg_link, const c
+ smart_str_appendl(querystr, table, len);
+ } else {
+ char *escaped = PGSQLescapeIdentifier(pg_link, table, len);
++ if (escaped == NULL) {
++ php_error_docref(NULL, E_NOTICE, "Failed to escape table name '%s'", table);
++ return FAILURE;
++ }
+ smart_str_appends(querystr, escaped);
+ PGSQLfree(escaped);
+ }
+@@ -6589,11 +6640,17 @@ static inline void build_tablename(smart_str *querystr, PGconn *pg_link, const c
+ smart_str_appendl(querystr, after_dot, len);
+ } else {
+ char *escaped = PGSQLescapeIdentifier(pg_link, after_dot, len);
++ if (escaped == NULL) {
++ php_error_docref(NULL, E_NOTICE, "Failed to escape table name '%s'", table);
++ return FAILURE;
++ }
+ smart_str_appendc(querystr, '.');
+ smart_str_appends(querystr, escaped);
+ PGSQLfree(escaped);
+ }
+ }
++
++ return SUCCESS;
+ }
+ /* }}} */
+
+@@ -6615,7 +6672,9 @@ PHP_PGSQL_API int php_pgsql_insert(PGconn *pg_link, const char *table, zval *var
+ ZVAL_UNDEF(&converted);
+ if (zend_hash_num_elements(Z_ARRVAL_P(var_array)) == 0) {
+ smart_str_appends(&querystr, "INSERT INTO ");
+- build_tablename(&querystr, pg_link, table);
++ if (build_tablename(&querystr, pg_link, table) == FAILURE) {
++ goto cleanup;
++ }
+ smart_str_appends(&querystr, " DEFAULT VALUES");
+
+ goto no_values;
+@@ -6631,7 +6690,9 @@ PHP_PGSQL_API int php_pgsql_insert(PGconn *pg_link, const char *table, zval *var
+ }
+
+ smart_str_appends(&querystr, "INSERT INTO ");
+- build_tablename(&querystr, pg_link, table);
++ if (build_tablename(&querystr, pg_link, table) == FAILURE) {
++ goto cleanup;
++ }
+ smart_str_appends(&querystr, " (");
+
+ ZEND_HASH_FOREACH_STR_KEY(Z_ARRVAL_P(var_array), fld) {
+@@ -6641,6 +6702,10 @@ PHP_PGSQL_API int php_pgsql_insert(PGconn *pg_link, const char *table, zval *var
+ }
+ if (opt & PGSQL_DML_ESCAPE) {
+ tmp = PGSQLescapeIdentifier(pg_link, ZSTR_VAL(fld), ZSTR_LEN(fld) + 1);
++ if (tmp == NULL) {
++ php_error_docref(NULL, E_NOTICE, "Failed to escape field '%s'", ZSTR_VAL(fld));
++ goto cleanup;
++ }
+ smart_str_appends(&querystr, tmp);
+ PGSQLfree(tmp);
+ } else {
+@@ -6652,15 +6717,19 @@ PHP_PGSQL_API int php_pgsql_insert(PGconn *pg_link, const char *table, zval *var
+ smart_str_appends(&querystr, ") VALUES (");
+
+ /* make values string */
+- ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(var_array), val) {
++ ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(var_array), fld, val) {
+ /* we can avoid the key_type check here, because we tested it in the other loop */
+ switch (Z_TYPE_P(val)) {
+ case IS_STRING:
+ if (opt & PGSQL_DML_ESCAPE) {
+- size_t new_len;
+- char *tmp;
+- tmp = (char *)safe_emalloc(Z_STRLEN_P(val), 2, 1);
+- new_len = PQescapeStringConn(pg_link, tmp, Z_STRVAL_P(val), Z_STRLEN_P(val), NULL);
++ int error;
++ char *tmp = safe_emalloc(Z_STRLEN_P(val), 2, 1);
++ size_t new_len = PQescapeStringConn(pg_link, tmp, Z_STRVAL_P(val), Z_STRLEN_P(val), &error);
++ if (error) {
++ php_error_docref(NULL, E_NOTICE, "Failed to escape field '%s' value", ZSTR_VAL(fld));
++ efree(tmp);
++ goto cleanup;
++ }
+ smart_str_appendc(&querystr, '\'');
+ smart_str_appendl(&querystr, tmp, new_len);
+ smart_str_appendc(&querystr, '\'');
+@@ -6810,6 +6879,10 @@ static inline int build_assignment_string(PGconn *pg_link, smart_str *querystr,
+ }
+ if (opt & PGSQL_DML_ESCAPE) {
+ char *tmp = PGSQLescapeIdentifier(pg_link, ZSTR_VAL(fld), ZSTR_LEN(fld) + 1);
++ if (tmp == NULL) {
++ php_error_docref(NULL, E_NOTICE, "Failed to escape field '%s'", ZSTR_VAL(fld));
++ return -1;
++ }
+ smart_str_appends(querystr, tmp);
+ PGSQLfree(tmp);
+ } else {
+@@ -6824,8 +6897,14 @@ static inline int build_assignment_string(PGconn *pg_link, smart_str *querystr,
+ switch (Z_TYPE_P(val)) {
+ case IS_STRING:
+ if (opt & PGSQL_DML_ESCAPE) {
++ int error;
+ char *tmp = (char *)safe_emalloc(Z_STRLEN_P(val), 2, 1);
+- size_t new_len = PQescapeStringConn(pg_link, tmp, Z_STRVAL_P(val), Z_STRLEN_P(val), NULL);
++ size_t new_len = PQescapeStringConn(pg_link, tmp, Z_STRVAL_P(val), Z_STRLEN_P(val), &error);
++ if (error) {
++ php_error_docref(NULL, E_NOTICE, "Failed to escape field '%s' value", ZSTR_VAL(fld));
++ efree(tmp);
++ return -1;
++ }
+ smart_str_appendc(querystr, '\'');
+ smart_str_appendl(querystr, tmp, new_len);
+ smart_str_appendc(querystr, '\'');
+@@ -6894,7 +6973,9 @@ PHP_PGSQL_API int php_pgsql_update(PGconn *pg_link, const char *table, zval *var
+ }
+
+ smart_str_appends(&querystr, "UPDATE ");
+- build_tablename(&querystr, pg_link, table);
++ if (build_tablename(&querystr, pg_link, table) == FAILURE) {
++ goto cleanup;
++ }
+ smart_str_appends(&querystr, " SET ");
+
+ if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(var_array), 0, ",", 1, opt))
+@@ -6992,7 +7073,9 @@ PHP_PGSQL_API int php_pgsql_delete(PGconn *pg_link, const char *table, zval *ids
+ }
+
+ smart_str_appends(&querystr, "DELETE FROM ");
+- build_tablename(&querystr, pg_link, table);
++ if (build_tablename(&querystr, pg_link, table) == FAILURE) {
++ goto cleanup;
++ }
+ smart_str_appends(&querystr, " WHERE ");
+
+ if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt))
+@@ -7130,7 +7213,9 @@ PHP_PGSQL_API int php_pgsql_result2array(PGresult *pg_result, zval *ret_array, l
+ }
+
+ smart_str_appends(&querystr, "SELECT * FROM ");
+- build_tablename(&querystr, pg_link, table);
++ if (build_tablename(&querystr, pg_link, table) == FAILURE) {
++ goto cleanup;
++ }
+ smart_str_appends(&querystr, " WHERE ");
+
+ if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt))
+diff --git a/ext/pgsql/tests/ghsa-hrwm-9436-5mv3.phpt b/ext/pgsql/tests/ghsa-hrwm-9436-5mv3.phpt
+new file mode 100644
+index 00000000000..c1c5e05dce6
+--- /dev/null
++++ b/ext/pgsql/tests/ghsa-hrwm-9436-5mv3.phpt
+@@ -0,0 +1,64 @@
++--TEST--
++#GHSA-hrwm-9436-5mv3: pgsql extension does not check for errors during escaping
++--EXTENSIONS--
++pgsql
++--SKIPIF--
++<?php include("skipif.inc"); ?>
++--FILE--
++<?php
++
++include 'config.inc';
++define('FILE_NAME', __DIR__ . '/php.gif');
++
++$db = pg_connect($conn_str);
++pg_query($db, "DROP TABLE IF EXISTS ghsa_hrmw_9436_5mv3");
++pg_query($db, "CREATE TABLE ghsa_hrmw_9436_5mv3 (bar text);");
++
++// pg_escape_literal/pg_escape_identifier
++
++$invalid = "ABC\xff\x30';";
++$flags = PGSQL_DML_NO_CONV | PGSQL_DML_ESCAPE;
++
++var_dump(pg_insert($db, $invalid, ['bar' => 'test'])); // table name str escape in php_pgsql_meta_data
++var_dump(pg_insert($db, "$invalid.tbl", ['bar' => 'test'])); // schema name str escape in php_pgsql_meta_data
++var_dump(pg_insert($db, 'ghsa_hrmw_9436_5mv3', ['bar' => $invalid])); // converted value str escape in php_pgsql_convert
++var_dump(pg_insert($db, $invalid, [])); // ident escape in build_tablename
++var_dump(pg_insert($db, 'ghsa_hrmw_9436_5mv3', [$invalid => 'foo'], $flags)); // ident escape for field php_pgsql_insert
++var_dump(pg_insert($db, 'ghsa_hrmw_9436_5mv3', ['bar' => $invalid], $flags)); // str escape for field value in php_pgsql_insert
++var_dump(pg_update($db, 'ghsa_hrmw_9436_5mv3', ['bar' => 'val'], [$invalid => 'test'], $flags)); // ident escape in build_assignment_string
++var_dump(pg_update($db, 'ghsa_hrmw_9436_5mv3', ['bar' => 'val'], ['bar' => $invalid], $flags)); // invalid str escape in build_assignment_string
++var_dump(pg_escape_literal($db, $invalid)); // pg_escape_literal escape
++var_dump(pg_escape_identifier($db, $invalid)); // pg_escape_identifier escape
++
++?>
++--EXPECTF--
++
++Warning: pg_insert(): Escaping table name 'ABC%s';' failed in %s on line %d
++bool(false)
++
++Warning: pg_insert(): Escaping table namespace 'ABC%s';.tbl' failed in %s on line %d
++bool(false)
++
++Notice: pg_insert(): String value escaping failed for PostgreSQL 'text' (bar) in %s on line %d
++bool(false)
++
++Notice: pg_insert(): Failed to escape table name 'ABC%s';' in %s on line %d
++bool(false)
++
++Notice: pg_insert(): Failed to escape field 'ABC%s';' in %s on line %d
++bool(false)
++
++Notice: pg_insert(): Failed to escape field 'bar' value in %s on line %d
++bool(false)
++
++Notice: pg_update(): Failed to escape field 'ABC%s';' in %s on line %d
++bool(false)
++
++Notice: pg_update(): Failed to escape field 'bar' value in %s on line %d
++bool(false)
++
++Warning: pg_escape_literal(): Failed to escape in %s on line %d
++bool(false)
++
++Warning: pg_escape_identifier(): Failed to escape in %s on line %d
++bool(false)
+--
+2.50.0
+
+From d52bcc1e66edd421dfea1698b1f897ad26c5f15f Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@remirepo.net>
+Date: Thu, 3 Jul 2025 09:32:25 +0200
+Subject: [PATCH 4/4] NEWS
+
+(cherry picked from commit 970548b94b7f23be32154d05a9545b10c98bfd62)
+---
+ NEWS | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/NEWS b/NEWS
+index fda646c7010..a9dd716c003 100644
+--- a/NEWS
++++ b/NEWS
+@@ -1,6 +1,20 @@
+ PHP NEWS
+ |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+
++Backported from 8.1.33
++
++- PGSQL:
++ . Fixed GHSA-hrwm-9436-5mv3 (pgsql extension does not check for errors during
++ escaping). (CVE-2025-1735) (Jakub Zelenka)
++
++- SOAP:
++ . Fixed GHSA-453j-q27h-5p8x (NULL Pointer Dereference in PHP SOAP Extension
++ via Large XML Namespace Prefix). (CVE-2025-6491) (Lekssays, nielsdos)
++
++- Standard:
++ . Fixed GHSA-3cr5-j632-f35r (Null byte termination in hostnames).
++ (CVE-2025-1220) (Jakub Zelenka)
++
+ Backported from 8.1.32
+
+ - LibXML:
+--
+2.50.0
+
diff --git a/php-cve-2025-1736.patch b/php-cve-2025-1736.patch
new file mode 100644
index 0000000..eb33553
--- /dev/null
+++ b/php-cve-2025-1736.patch
@@ -0,0 +1,242 @@
+From 134f821622e2d2b68d66bea16e16c05b7b0f5114 Mon Sep 17 00:00:00 2001
+From: Jakub Zelenka <bukka@php.net>
+Date: Fri, 14 Feb 2025 19:17:22 +0100
+Subject: [PATCH 04/11] Fix GHSA-hgf5-96fm-v528: http user header check of crlf
+
+(cherry picked from commit 41d49abbd99dab06cdae4834db664435f8177174)
+(cherry picked from commit 8f65ef50929f6781f4973325f9b619f02cce19d8)
+---
+ ext/standard/http_fopen_wrapper.c | 2 +-
+ .../tests/http/ghsa-hgf5-96fm-v528-001.phpt | 65 +++++++++++++++++++
+ .../tests/http/ghsa-hgf5-96fm-v528-002.phpt | 62 ++++++++++++++++++
+ .../tests/http/ghsa-hgf5-96fm-v528-003.phpt | 64 ++++++++++++++++++
+ 4 files changed, 192 insertions(+), 1 deletion(-)
+ create mode 100644 ext/standard/tests/http/ghsa-hgf5-96fm-v528-001.phpt
+ create mode 100644 ext/standard/tests/http/ghsa-hgf5-96fm-v528-002.phpt
+ create mode 100644 ext/standard/tests/http/ghsa-hgf5-96fm-v528-003.phpt
+
+diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c
+index b64a7c95446..46f7c7ebcee 100644
+--- a/ext/standard/http_fopen_wrapper.c
++++ b/ext/standard/http_fopen_wrapper.c
+@@ -109,7 +109,7 @@ static inline void strip_header(char *header_bag, char *lc_header_bag,
+ static zend_bool check_has_header(const char *headers, const char *header) {
+ const char *s = headers;
+ while ((s = strstr(s, header))) {
+- if (s == headers || *(s-1) == '\n') {
++ if (s == headers || (*(s-1) == '\n' && *(s-2) == '\r')) {
+ return 1;
+ }
+ s++;
+diff --git a/ext/standard/tests/http/ghsa-hgf5-96fm-v528-001.phpt b/ext/standard/tests/http/ghsa-hgf5-96fm-v528-001.phpt
+new file mode 100644
+index 00000000000..c8dcd47a4a4
+--- /dev/null
++++ b/ext/standard/tests/http/ghsa-hgf5-96fm-v528-001.phpt
+@@ -0,0 +1,65 @@
++--TEST--
++GHSA-hgf5-96fm-v528: Stream HTTP wrapper header check might omit basic auth header (incorrect inside pos)
++--FILE--
++<?php
++$serverCode = <<<'CODE'
++ $ctxt = stream_context_create([
++ "socket" => [
++ "tcp_nodelay" => true
++ ]
++ ]);
++
++ $server = stream_socket_server(
++ "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt);
++ phpt_notify_server_start($server);
++
++ $conn = stream_socket_accept($server);
++
++ phpt_notify(WORKER_DEFAULT_NAME, "server-accepted");
++
++ $result = fread($conn, 1024);
++ $encoded_result = base64_encode($result);
++
++ fwrite($conn, "HTTP/1.0 200 Ok\r\nContent-Type: text/html; charset=utf-8\r\n\r\n$encoded_result\r\n");
++
++CODE;
++
++$clientCode = <<<'CODE'
++ $opts = [
++ "http" => [
++ "method" => "GET",
++ "header" => "Cookie: foo=bar\nauthorization:x\r\n"
++ ]
++ ];
++ $ctx = stream_context_create($opts);
++ var_dump(explode("\r\n", base64_decode(file_get_contents("http://user:pwd@{{ ADDR }}", false, $ctx))));
++ var_dump($http_response_header);
++CODE;
++
++include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
++ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
++?>
++--EXPECTF--
++array(7) {
++ [0]=>
++ string(14) "GET / HTTP/1.%d"
++ [1]=>
++ string(33) "Authorization: Basic dXNlcjpwd2Q="
++ [2]=>
++ string(21) "Host: 127.0.0.1:%d"
++ [3]=>
++ string(17) "Connection: close"
++ [4]=>
++ string(31) "Cookie: foo=bar
++authorization:x"
++ [5]=>
++ string(0) ""
++ [6]=>
++ string(0) ""
++}
++array(2) {
++ [0]=>
++ string(15) "HTTP/1.0 200 Ok"
++ [1]=>
++ string(38) "Content-Type: text/html; charset=utf-8"
++}
+diff --git a/ext/standard/tests/http/ghsa-hgf5-96fm-v528-002.phpt b/ext/standard/tests/http/ghsa-hgf5-96fm-v528-002.phpt
+new file mode 100644
+index 00000000000..ca8f75f0327
+--- /dev/null
++++ b/ext/standard/tests/http/ghsa-hgf5-96fm-v528-002.phpt
+@@ -0,0 +1,62 @@
++--TEST--
++GHSA-hgf5-96fm-v528: Header parser of http stream wrapper does not handle folded headers (correct start pos)
++--FILE--
++<?php
++$serverCode = <<<'CODE'
++ $ctxt = stream_context_create([
++ "socket" => [
++ "tcp_nodelay" => true
++ ]
++ ]);
++
++ $server = stream_socket_server(
++ "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt);
++ phpt_notify_server_start($server);
++
++ $conn = stream_socket_accept($server);
++
++ phpt_notify(WORKER_DEFAULT_NAME, "server-accepted");
++
++ $result = fread($conn, 1024);
++ $encoded_result = base64_encode($result);
++
++ fwrite($conn, "HTTP/1.0 200 Ok\r\nContent-Type: text/html; charset=utf-8\r\n\r\n$encoded_result\r\n");
++
++CODE;
++
++$clientCode = <<<'CODE'
++ $opts = [
++ "http" => [
++ "method" => "GET",
++ "header" => "Authorization: Bearer x\r\n"
++ ]
++ ];
++ $ctx = stream_context_create($opts);
++ var_dump(explode("\r\n", base64_decode(file_get_contents("http://user:pwd@{{ ADDR }}", false, $ctx))));
++ var_dump($http_response_header);
++CODE;
++
++include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
++ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
++?>
++--EXPECTF--
++array(6) {
++ [0]=>
++ string(14) "GET / HTTP/1.%d"
++ [1]=>
++ string(21) "Host: 127.0.0.1:%d"
++ [2]=>
++ string(17) "Connection: close"
++ [3]=>
++ string(23) "Authorization: Bearer x"
++ [4]=>
++ string(0) ""
++ [5]=>
++ string(0) ""
++}
++array(2) {
++ [0]=>
++ string(15) "HTTP/1.0 200 Ok"
++ [1]=>
++ string(38) "Content-Type: text/html; charset=utf-8"
++}
+diff --git a/ext/standard/tests/http/ghsa-hgf5-96fm-v528-003.phpt b/ext/standard/tests/http/ghsa-hgf5-96fm-v528-003.phpt
+new file mode 100644
+index 00000000000..4cfbc7ee804
+--- /dev/null
++++ b/ext/standard/tests/http/ghsa-hgf5-96fm-v528-003.phpt
+@@ -0,0 +1,64 @@
++--TEST--
++GHSA-hgf5-96fm-v528: Header parser of http stream wrapper does not handle folded headers (correct middle pos)
++--FILE--
++<?php
++$serverCode = <<<'CODE'
++ $ctxt = stream_context_create([
++ "socket" => [
++ "tcp_nodelay" => true
++ ]
++ ]);
++
++ $server = stream_socket_server(
++ "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt);
++ phpt_notify_server_start($server);
++
++ $conn = stream_socket_accept($server);
++
++ phpt_notify(WORKER_DEFAULT_NAME, "server-accepted");
++
++ $result = fread($conn, 1024);
++ $encoded_result = base64_encode($result);
++
++ fwrite($conn, "HTTP/1.0 200 Ok\r\nContent-Type: text/html; charset=utf-8\r\n\r\n$encoded_result\r\n");
++
++CODE;
++
++$clientCode = <<<'CODE'
++ $opts = [
++ "http" => [
++ "method" => "GET",
++ "header" => "Cookie: x=y\r\nAuthorization: Bearer x\r\n"
++ ]
++ ];
++ $ctx = stream_context_create($opts);
++ var_dump(explode("\r\n", base64_decode(file_get_contents("http://user:pwd@{{ ADDR }}", false, $ctx))));
++ var_dump($http_response_header);
++CODE;
++
++include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
++ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
++?>
++--EXPECTF--
++array(7) {
++ [0]=>
++ string(14) "GET / HTTP/1.%d"
++ [1]=>
++ string(21) "Host: 127.0.0.1:%d"
++ [2]=>
++ string(17) "Connection: close"
++ [3]=>
++ string(11) "Cookie: x=y"
++ [4]=>
++ string(23) "Authorization: Bearer x"
++ [5]=>
++ string(0) ""
++ [6]=>
++ string(0) ""
++}
++array(2) {
++ [0]=>
++ string(15) "HTTP/1.0 200 Ok"
++ [1]=>
++ string(38) "Content-Type: text/html; charset=utf-8"
++}
+--
+2.48.1
+
diff --git a/php-cve-2025-1861.patch b/php-cve-2025-1861.patch
new file mode 100644
index 0000000..b31e74f
--- /dev/null
+++ b/php-cve-2025-1861.patch
@@ -0,0 +1,349 @@
+From 5418040dcaaca46965ed6f8a4ad1541709c32e9f Mon Sep 17 00:00:00 2001
+From: Jakub Zelenka <bukka@php.net>
+Date: Tue, 4 Mar 2025 09:01:34 +0100
+Subject: [PATCH 03/11] Fix GHSA-52jp-hrpf-2jff: http redirect location
+ truncation
+
+It converts the allocation of location to be on heap instead of stack
+and errors if the location length is greater than 8086 bytes.
+
+(cherry picked from commit ac1a054bb3eb5994a199e8b18cca28cbabf5943e)
+(cherry picked from commit adc7e9f20c9a9aab9cd23ca47ec3fb96287898ae)
+---
+ ext/standard/http_fopen_wrapper.c | 87 ++++++++++++-------
+ .../tests/http/ghsa-52jp-hrpf-2jff-001.phpt | 58 +++++++++++++
+ .../tests/http/ghsa-52jp-hrpf-2jff-002.phpt | 55 ++++++++++++
+ 3 files changed, 168 insertions(+), 32 deletions(-)
+ create mode 100644 ext/standard/tests/http/ghsa-52jp-hrpf-2jff-001.phpt
+ create mode 100644 ext/standard/tests/http/ghsa-52jp-hrpf-2jff-002.phpt
+
+diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c
+index 071d6a4d119..b64a7c95446 100644
+--- a/ext/standard/http_fopen_wrapper.c
++++ b/ext/standard/http_fopen_wrapper.c
+@@ -69,15 +69,16 @@
+
+ #include "php_fopen_wrappers.h"
+
+-#define HTTP_HEADER_BLOCK_SIZE 1024
+-#define PHP_URL_REDIRECT_MAX 20
+-#define HTTP_HEADER_USER_AGENT 1
+-#define HTTP_HEADER_HOST 2
+-#define HTTP_HEADER_AUTH 4
+-#define HTTP_HEADER_FROM 8
+-#define HTTP_HEADER_CONTENT_LENGTH 16
+-#define HTTP_HEADER_TYPE 32
+-#define HTTP_HEADER_CONNECTION 64
++#define HTTP_HEADER_BLOCK_SIZE 1024
++#define HTTP_HEADER_MAX_LOCATION_SIZE 8182 /* 8192 - 10 (size of "Location: ") */
++#define PHP_URL_REDIRECT_MAX 20
++#define HTTP_HEADER_USER_AGENT 1
++#define HTTP_HEADER_HOST 2
++#define HTTP_HEADER_AUTH 4
++#define HTTP_HEADER_FROM 8
++#define HTTP_HEADER_CONTENT_LENGTH 16
++#define HTTP_HEADER_TYPE 32
++#define HTTP_HEADER_CONNECTION 64
+
+ #define HTTP_WRAPPER_HEADER_INIT 1
+ #define HTTP_WRAPPER_REDIRECTED 2
+@@ -121,17 +122,15 @@ typedef struct _php_stream_http_response_header_info {
+ size_t file_size;
+ zend_bool error;
+ zend_bool follow_location;
+- char location[HTTP_HEADER_BLOCK_SIZE];
++ char *location;
++ size_t location_len;
+ } php_stream_http_response_header_info;
+
+ static void php_stream_http_response_header_info_init(
+ php_stream_http_response_header_info *header_info)
+ {
+- header_info->transfer_encoding = NULL;
+- header_info->file_size = 0;
+- header_info->error = 0;
++ memset(header_info, 0, sizeof(php_stream_http_response_header_info));
+ header_info->follow_location = 1;
+- header_info->location[0] = '\0';
+ }
+
+ /* Trim white spaces from response header line and update its length */
+@@ -258,7 +257,22 @@ static zend_string *php_stream_http_response_headers_parse(php_stream_wrapper *w
+ * RFC 7238 defines 308: http://tools.ietf.org/html/rfc7238 */
+ header_info->follow_location = 0;
+ }
+- strlcpy(header_info->location, last_header_value, sizeof(header_info->location));
++ size_t last_header_value_len = strlen(last_header_value);
++ if (last_header_value_len > HTTP_HEADER_MAX_LOCATION_SIZE) {
++ header_info->error = 1;
++ php_stream_wrapper_log_error(wrapper, options,
++ "HTTP Location header size is over the limit of %d bytes",
++ HTTP_HEADER_MAX_LOCATION_SIZE);
++ zend_string_efree(last_header_line_str);
++ return NULL;
++ }
++ if (header_info->location_len == 0) {
++ header_info->location = emalloc(last_header_value_len + 1);
++ } else if (header_info->location_len <= last_header_value_len) {
++ header_info->location = erealloc(header_info->location, last_header_value_len + 1);
++ }
++ header_info->location_len = last_header_value_len;
++ memcpy(header_info->location, last_header_value, last_header_value_len + 1);
+ } else if (!strncasecmp(last_header_line, "Content-Type:", sizeof("Content-Type:")-1)) {
+ php_stream_notify_info(context, PHP_STREAM_NOTIFY_MIME_TYPE_IS, last_header_value, 0);
+ } else if (!strncasecmp(last_header_line, "Content-Length:", sizeof("Content-Length:")-1)) {
+@@ -541,6 +555,8 @@ finish:
+ }
+ }
+
++ php_stream_http_response_header_info_init(&header_info);
++
+ if (stream == NULL)
+ goto out;
+
+@@ -918,8 +934,6 @@ finish:
+ }
+ }
+
+- php_stream_http_response_header_info_init(&header_info);
+-
+ /* read past HTTP headers */
+ while (!php_stream_eof(stream)) {
+ size_t http_header_line_length;
+@@ -989,12 +1003,12 @@ finish:
+ last_header_line_str, NULL, NULL, response_code, response_header, &header_info);
+ }
+
+- if (!reqok || (header_info.location[0] != '\0' && header_info.follow_location)) {
++ if (!reqok || (header_info.location != NULL && header_info.follow_location)) {
+ if (!header_info.follow_location || (((options & STREAM_ONLY_GET_HEADERS) || ignore_errors) && redirect_max <= 1)) {
+ goto out;
+ }
+
+- if (header_info.location[0] != '\0')
++ if (header_info.location != NULL)
+ php_stream_notify_info(context, PHP_STREAM_NOTIFY_REDIRECTED, header_info.location, 0);
+
+ php_stream_close(stream);
+@@ -1005,18 +1019,17 @@ finish:
+ header_info.transfer_encoding = NULL;
+ }
+
+- if (header_info.location[0] != '\0') {
++ if (header_info.location != NULL) {
+
+- char new_path[HTTP_HEADER_BLOCK_SIZE];
+- char loc_path[HTTP_HEADER_BLOCK_SIZE];
++ char *new_path = NULL;
+
+- *new_path='\0';
+ if (strlen(header_info.location) < 8 ||
+ (strncasecmp(header_info.location, "http://", sizeof("http://")-1) &&
+ strncasecmp(header_info.location, "https://", sizeof("https://")-1) &&
+ strncasecmp(header_info.location, "ftp://", sizeof("ftp://")-1) &&
+ strncasecmp(header_info.location, "ftps://", sizeof("ftps://")-1)))
+ {
++ char *loc_path = NULL;
+ if (*header_info.location != '/') {
+ if (*(header_info.location+1) != '\0' && resource->path) {
+ char *s = strrchr(ZSTR_VAL(resource->path), '/');
+@@ -1034,31 +1047,35 @@ finish:
+ if (resource->path &&
+ ZSTR_VAL(resource->path)[0] == '/' &&
+ ZSTR_VAL(resource->path)[1] == '\0') {
+- snprintf(loc_path, sizeof(loc_path) - 1, "%s%s",
+- ZSTR_VAL(resource->path), header_info.location);
++ spprintf(&loc_path, 0, "%s%s", ZSTR_VAL(resource->path), header_info.location);
+ } else {
+- snprintf(loc_path, sizeof(loc_path) - 1, "%s/%s",
+- ZSTR_VAL(resource->path), header_info.location);
++ spprintf(&loc_path, 0, "%s/%s", ZSTR_VAL(resource->path), header_info.location);
+ }
+ } else {
+- snprintf(loc_path, sizeof(loc_path) - 1, "/%s", header_info.location);
++ spprintf(&loc_path, 0, "/%s", header_info.location);
+ }
+ } else {
+- strlcpy(loc_path, header_info.location, sizeof(loc_path));
++ loc_path = header_info.location;
++ header_info.location = NULL;
+ }
+ if ((use_ssl && resource->port != 443) || (!use_ssl && resource->port != 80)) {
+- snprintf(new_path, sizeof(new_path) - 1, "%s://%s:%d%s", ZSTR_VAL(resource->scheme), ZSTR_VAL(resource->host), resource->port, loc_path);
++ spprintf(&new_path, 0, "%s://%s:%d%s", ZSTR_VAL(resource->scheme),
++ ZSTR_VAL(resource->host), resource->port, loc_path);
+ } else {
+- snprintf(new_path, sizeof(new_path) - 1, "%s://%s%s", ZSTR_VAL(resource->scheme), ZSTR_VAL(resource->host), loc_path);
++ spprintf(&new_path, 0, "%s://%s%s", ZSTR_VAL(resource->scheme),
++ ZSTR_VAL(resource->host), loc_path);
+ }
++ efree(loc_path);
+ } else {
+- strlcpy(new_path, header_info.location, sizeof(new_path));
++ new_path = header_info.location;
++ header_info.location = NULL;
+ }
+
+ php_url_free(resource);
+ /* check for invalid redirection URLs */
+ if ((resource = php_url_parse(new_path)) == NULL) {
+ php_stream_wrapper_log_error(wrapper, options, "Invalid redirect URL! %s", new_path);
++ efree(new_path);
+ goto out;
+ }
+
+@@ -1070,6 +1087,7 @@ finish:
+ while (s < e) { \
+ if (iscntrl(*s)) { \
+ php_stream_wrapper_log_error(wrapper, options, "Invalid redirect URL! %s", new_path); \
++ efree(new_path); \
+ goto out; \
+ } \
+ s++; \
+@@ -1085,6 +1103,7 @@ finish:
+ stream = php_stream_url_wrap_http_ex(
+ wrapper, new_path, mode, options, opened_path, context,
+ --redirect_max, HTTP_WRAPPER_REDIRECTED, response_header STREAMS_CC);
++ efree(new_path);
+ } else {
+ php_stream_wrapper_log_error(wrapper, options, "HTTP request failed! %s", tmp_line);
+ }
+@@ -1097,6 +1116,10 @@ out:
+ efree(http_header_line);
+ }
+
++ if (header_info.location != NULL) {
++ efree(header_info.location);
++ }
++
+ if (resource) {
+ php_url_free(resource);
+ }
+diff --git a/ext/standard/tests/http/ghsa-52jp-hrpf-2jff-001.phpt b/ext/standard/tests/http/ghsa-52jp-hrpf-2jff-001.phpt
+new file mode 100644
+index 00000000000..46d77ec4aff
+--- /dev/null
++++ b/ext/standard/tests/http/ghsa-52jp-hrpf-2jff-001.phpt
+@@ -0,0 +1,58 @@
++--TEST--
++GHSA-52jp-hrpf-2jff: HTTP stream wrapper truncate redirect location to 1024 bytes (success)
++--FILE--
++<?php
++$serverCode = <<<'CODE'
++$ctxt = stream_context_create([
++ "socket" => [
++ "tcp_nodelay" => true
++ ]
++ ]);
++
++ $server = stream_socket_server(
++ "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt);
++ phpt_notify_server_start($server);
++
++ $conn = stream_socket_accept($server);
++
++ phpt_notify(WORKER_DEFAULT_NAME, "server-accepted");
++
++ $loc = str_repeat("y", 8000);
++ fwrite($conn, "HTTP/1.0 301 Ok\r\nContent-Type: text/html;\r\nLocation: $loc\r\n\r\nbody\r\n");
++CODE;
++
++$clientCode = <<<'CODE'
++ function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) {
++ switch($notification_code) {
++ case STREAM_NOTIFY_MIME_TYPE_IS:
++ echo "Found the mime-type: ", $message, PHP_EOL;
++ break;
++ case STREAM_NOTIFY_REDIRECTED:
++ echo "Redirected: ";
++ var_dump($message);
++ }
++ }
++
++ $ctx = stream_context_create();
++ stream_context_set_params($ctx, array("notification" => "stream_notification_callback"));
++ var_dump(trim(file_get_contents("http://{{ ADDR }}", false, $ctx)));
++ var_dump($http_response_header);
++CODE;
++
++include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
++ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
++?>
++--EXPECTF--
++Found the mime-type: text/html;
++Redirected: string(8000) "%s"
++
++Warning: file_get_contents(http://127.0.0.1:%d): failed to open stream: %s
++string(0) ""
++array(3) {
++ [0]=>
++ string(15) "HTTP/1.0 301 Ok"
++ [1]=>
++ string(24) "Content-Type: text/html;"
++ [2]=>
++ string(8010) "Location: %s"
++}
+diff --git a/ext/standard/tests/http/ghsa-52jp-hrpf-2jff-002.phpt b/ext/standard/tests/http/ghsa-52jp-hrpf-2jff-002.phpt
+new file mode 100644
+index 00000000000..d25c89d06e5
+--- /dev/null
++++ b/ext/standard/tests/http/ghsa-52jp-hrpf-2jff-002.phpt
+@@ -0,0 +1,55 @@
++--TEST--
++GHSA-52jp-hrpf-2jff: HTTP stream wrapper truncate redirect location to 1024 bytes (over limit)
++--FILE--
++<?php
++$serverCode = <<<'CODE'
++$ctxt = stream_context_create([
++ "socket" => [
++ "tcp_nodelay" => true
++ ]
++ ]);
++
++ $server = stream_socket_server(
++ "tcp://127.0.0.1:0", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt);
++ phpt_notify_server_start($server);
++
++ $conn = stream_socket_accept($server);
++
++ phpt_notify(WORKER_DEFAULT_NAME, "server-accepted");
++
++ $loc = str_repeat("y", 9000);
++ fwrite($conn, "HTTP/1.0 301 Ok\r\nContent-Type: text/html;\r\nLocation: $loc\r\n\r\nbody\r\n");
++CODE;
++
++$clientCode = <<<'CODE'
++ function stream_notification_callback($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) {
++ switch($notification_code) {
++ case STREAM_NOTIFY_MIME_TYPE_IS:
++ echo "Found the mime-type: ", $message, PHP_EOL;
++ break;
++ case STREAM_NOTIFY_REDIRECTED:
++ echo "Redirected: ";
++ var_dump($message);
++ }
++ }
++
++ $ctx = stream_context_create();
++ stream_context_set_params($ctx, array("notification" => "stream_notification_callback"));
++ var_dump(trim(file_get_contents("http://{{ ADDR }}", false, $ctx)));
++ var_dump($http_response_header);
++CODE;
++
++include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
++ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
++?>
++--EXPECTF--
++Found the mime-type: text/html;
++
++Warning: file_get_contents(http://127.0.0.1:%d): failed to open stream: HTTP Location header size is over the limit of 8182 bytes in %s
++string(0) ""
++array(2) {
++ [0]=>
++ string(15) "HTTP/1.0 301 Ok"
++ [1]=>
++ string(24) "Content-Type: text/html;"
++}
+--
+2.48.1
+
diff --git a/php-cve-2025-6491.patch b/php-cve-2025-6491.patch
new file mode 100644
index 0000000..ec8ce61
--- /dev/null
+++ b/php-cve-2025-6491.patch
@@ -0,0 +1,103 @@
+From c13a3b2a3710c66231f0cad16ff74ef75c8672a7 Mon Sep 17 00:00:00 2001
+From: Ahmed Lekssays <lekssaysahmed@gmail.com>
+Date: Tue, 3 Jun 2025 09:00:55 +0000
+Subject: [PATCH 1/4] Fix GHSA-453j-q27h-5p8x
+
+Libxml versions prior to 2.13 cannot correctly handle a call to
+xmlNodeSetName() with a name longer than 2G. It will leave the node
+object in an invalid state with a NULL name. This later causes a NULL
+pointer dereference when using the name during message serialization.
+
+To solve this, implement a workaround that resets the name to the
+sentinel name if this situation arises.
+
+Versions of libxml of 2.13 and higher are not affected.
+
+This can be exploited if a SoapVar is created with a fully qualified
+name that is longer than 2G. This would be possible if some application
+code uses a namespace prefix from an untrusted source like from a remote
+SOAP service.
+
+Co-authored-by: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
+(cherry picked from commit 9cb3d8d200f0c822b17bda35a2a67a97b039d3e1)
+(cherry picked from commit 1b7410a57f8a5fd1dd43854bcf7b9200517c9fd2)
+---
+ ext/soap/soap.c | 6 ++--
+ ext/soap/tests/soap_qname_crash.phpt | 48 ++++++++++++++++++++++++++++
+ 2 files changed, 52 insertions(+), 2 deletions(-)
+ create mode 100644 ext/soap/tests/soap_qname_crash.phpt
+
+diff --git a/ext/soap/soap.c b/ext/soap/soap.c
+index 7429aebbf70..94f1db526c6 100644
+--- a/ext/soap/soap.c
++++ b/ext/soap/soap.c
+@@ -4457,8 +4457,10 @@ static xmlNodePtr serialize_zval(zval *val, sdlParamPtr param, char *paramName,
+ }
+ xmlParam = master_to_xml(enc, val, style, parent);
+ zval_ptr_dtor(&defval);
+- if (!strcmp((char*)xmlParam->name, "BOGUS")) {
+- xmlNodeSetName(xmlParam, BAD_CAST(paramName));
++ if (xmlParam != NULL) {
++ if (xmlParam->name == NULL || strcmp((char*)xmlParam->name, "BOGUS") == 0) {
++ xmlNodeSetName(xmlParam, BAD_CAST(paramName));
++ }
+ }
+ return xmlParam;
+ }
+diff --git a/ext/soap/tests/soap_qname_crash.phpt b/ext/soap/tests/soap_qname_crash.phpt
+new file mode 100644
+index 00000000000..7a1bf026022
+--- /dev/null
++++ b/ext/soap/tests/soap_qname_crash.phpt
+@@ -0,0 +1,48 @@
++--TEST--
++Test SoapClient with excessively large QName prefix in SoapVar
++--EXTENSIONS--
++soap
++--SKIPIF--
++<?php
++if (PHP_INT_SIZE != 8) die("skip: 64-bit only");
++?>
++--INI--
++memory_limit=8G
++--FILE--
++<?php
++
++class TestSoapClient extends SoapClient {
++ public function __doRequest(
++ $request,
++ $location,
++ $action,
++ $version,
++ $one_way = false
++ ): ?string {
++ die($request);
++ }
++}
++
++$prefix = str_repeat("A", 2 * 1024 * 1024 * 1024);
++$qname = "{$prefix}:tag";
++
++echo "Attempting to create SoapVar with very large QName\n";
++
++$var = new SoapVar("value", XSD_QNAME, null, null, $qname);
++
++echo "Attempting encoding\n";
++
++$options = [
++ 'location' => 'http://127.0.0.1/',
++ 'uri' => 'urn:dummy',
++ 'trace' => 1,
++ 'exceptions' => true,
++];
++$client = new TestSoapClient(null, $options);
++$client->__soapCall("DummyFunction", [$var]);
++?>
++--EXPECT--
++Attempting to create SoapVar with very large QName
++Attempting encoding
++<?xml version="1.0" encoding="UTF-8"?>
++<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:dummy" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:DummyFunction><param0 xsi:type="xsd:QName">value</param0></ns1:DummyFunction></SOAP-ENV:Body></SOAP-ENV:Envelope>
+--
+2.50.0
+
diff --git a/php-fpm.service b/php-fpm.service
index 687dfc0..0712a11 100644
--- a/php-fpm.service
+++ b/php-fpm.service
@@ -4,7 +4,7 @@
[Unit]
Description=The PHP FastCGI Process Manager
-After=syslog.target network.target
+After=network.target
[Service]
Type=notify
diff --git a/php-ghsa-4w77-75f9-2c8w.patch b/php-ghsa-4w77-75f9-2c8w.patch
new file mode 100644
index 0000000..4886973
--- /dev/null
+++ b/php-ghsa-4w77-75f9-2c8w.patch
@@ -0,0 +1,135 @@
+From 56488a8a4ec68e58eecc9e78dd75e41adf56984c Mon Sep 17 00:00:00 2001
+From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
+Date: Sat, 9 Nov 2024 15:29:52 +0100
+Subject: [PATCH 6/7] Fix GHSA-4w77-75f9-2c8w
+
+(cherry picked from commit 7dd336ae838bbf2c62dc47e3c900d657d3534c02)
+(cherry picked from commit 462092a48aa0dbad24d9fa8a4a9d418faa14d309)
+---
+ sapi/cli/php_cli_server.c | 6 +---
+ sapi/cli/tests/ghsa-4w77-75f9-2c8w.phpt | 41 +++++++++++++++++++++++++
+ 2 files changed, 42 insertions(+), 5 deletions(-)
+ create mode 100644 sapi/cli/tests/ghsa-4w77-75f9-2c8w.phpt
+
+diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c
+index c3097861e3f..8717dc57418 100644
+--- a/sapi/cli/php_cli_server.c
++++ b/sapi/cli/php_cli_server.c
+@@ -1923,8 +1923,6 @@ static size_t php_cli_server_client_send_through(php_cli_server_client *client,
+
+ static void php_cli_server_client_populate_request_info(const php_cli_server_client *client, sapi_request_info *request_info) /* {{{ */
+ {
+- char *val;
+-
+ request_info->request_method = php_http_method_str(client->request.request_method);
+ request_info->proto_num = client->request.protocol_version;
+ request_info->request_uri = client->request.request_uri;
+@@ -1932,9 +1930,7 @@ static void php_cli_server_client_populate_request_info(const php_cli_server_cli
+ request_info->query_string = client->request.query_string;
+ request_info->content_length = client->request.content_len;
+ request_info->auth_user = request_info->auth_password = request_info->auth_digest = NULL;
+- if (NULL != (val = zend_hash_str_find_ptr(&client->request.headers, "content-type", sizeof("content-type")-1))) {
+- request_info->content_type = val;
+- }
++ request_info->content_type = zend_hash_str_find_ptr(&client->request.headers, "content-type", sizeof("content-type")-1);
+ } /* }}} */
+
+ static void destroy_request_info(sapi_request_info *request_info) /* {{{ */
+diff --git a/sapi/cli/tests/ghsa-4w77-75f9-2c8w.phpt b/sapi/cli/tests/ghsa-4w77-75f9-2c8w.phpt
+new file mode 100644
+index 00000000000..80944c3d14f
+--- /dev/null
++++ b/sapi/cli/tests/ghsa-4w77-75f9-2c8w.phpt
+@@ -0,0 +1,41 @@
++--TEST--
++GHSA-4w77-75f9-2c8w (Heap-Use-After-Free in sapi_read_post_data Processing in CLI SAPI Interface)
++--INI--
++allow_url_fopen=1
++--SKIPIF--
++<?php
++include "skipif.inc";
++?>
++--FILE--
++<?php
++include "php_cli_server.inc";
++
++$serverCode = <<<'CODE'
++var_dump(file_get_contents('php://input'));
++CODE;
++
++php_cli_server_start($serverCode, null, []);
++
++$options = [
++ "http" => [
++ "method" => "POST",
++ "header" => "Content-Type: application/x-www-form-urlencoded",
++ "content" => "AAAAA",
++ ],
++];
++$context = stream_context_create($options);
++
++echo file_get_contents("http://" . PHP_CLI_SERVER_ADDRESS . "/", false, $context);
++
++$options = [
++ "http" => [
++ "method" => "POST",
++ ],
++];
++$context = stream_context_create($options);
++
++echo file_get_contents("http://" . PHP_CLI_SERVER_ADDRESS . "/", false, $context);
++?>
++--EXPECT--
++string(5) "AAAAA"
++string(0) ""
+--
+2.47.0
+
+From d8d682d3d6a4d027771806c8fc77128cae078d29 Mon Sep 17 00:00:00 2001
+From: Remi Collet <remi@remirepo.net>
+Date: Fri, 22 Nov 2024 08:58:10 +0100
+Subject: [PATCH 7/7] NEWS for 8.1.31 backports
+
+(cherry picked from commit 22bdb43da0ecd6e72d63b63aa6c1f3a25d1bca3a)
+---
+ NEWS | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+diff --git a/NEWS b/NEWS
+index 62616d6312d..f600d6aea65 100644
+--- a/NEWS
++++ b/NEWS
+@@ -1,6 +1,30 @@
+ PHP NEWS
+ |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+
++Backported from 8.1.31
++
++- CLI:
++ . Fixed bug GHSA-4w77-75f9-2c8w (Heap-Use-After-Free in sapi_read_post_data
++ Processing in CLI SAPI Interface). (nielsdos)
++
++- LDAP:
++ . Fixed bug GHSA-g665-fm4p-vhff (OOB access in ldap_escape). (CVE-2024-8932)
++ (nielsdos)
++
++- PDO DBLIB:
++ . Fixed bug GHSA-5hqh-c84r-qjcv (Integer overflow in the dblib quoter causing
++ OOB writes). (CVE-2024-11236) (nielsdos)
++
++- PDO Firebird:
++ . Fixed bug GHSA-5hqh-c84r-qjcv (Integer overflow in the firebird quoter
++ causing OOB writes). (CVE-2024-11236) (nielsdos)
++
++- Streams:
++ . Fixed bug GHSA-c5f2-jwm7-mmq2 (Configuring a proxy in a stream context
++ might allow for CRLF injection in URIs). (CVE-2024-11234) (Jakub Zelenka)
++ . Fixed bug GHSA-r977-prxv-hc43 (Single byte overread with
++ convert.quoted-printable-decode filter). (CVE-2024-11233) (nielsdos)
++
+ Backported from 8.1.30
+
+ - CGI:
+--
+2.47.0
+
diff --git a/php-keyring.gpg b/php-keyring.gpg
index 870d816..0774fa8 100644
--- a/php-keyring.gpg
+++ b/php-keyring.gpg
@@ -1,415 +1,780 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
-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
-bh57GXdFtudEaKvQbGW9yalYwuj7Yip5XJGttg==
-=XZOV
+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
+5zO4pPQ1rIGTN4CBa7QcJH3fc3i9rYMYAtuVlpCUmDMEYHHgIBYJKwYBBAHaRw8B
+AQdAOm0RDYTmM6omlqoTx6Wy65agVJ4q8EPGczNnYOrHyo20HUpha3ViIFplbGVu
+a2EgPGJ1a2thQHBocC5uZXQ+iJMEExYIADsCGwMFCwkIBwIGFQoJCAsCBBYCAwEC
+HgECF4AWIQTCjZN1dWA+tKu3JYYcB3ncXAqd5AUCYHHi+QIZAQAKCRAcB3ncXAqd
+5MZdAP0eAbdHgjHqKYol3QaXRhErAvvLHPSEXN5cAImF3zIICgD+NJZZMQDXd1OO
+KDt+YLiIqIq2ibRhOP5mZryPCGkq9QG0J0pha3ViIFplbGVua2EgPGpha3ViLm9w
+ZW5zc2xAZ21haWwuY29tPoiQBBMWCAA4FiEEwo2TdXVgPrSrtyWGHAd53FwKneQF
+AmBx4owCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQHAd53FwKneS0NwEA
+t0IRpoCN/JNwg1TIseybpmC65nSzYVyX10xe4Ji50dcBAI6TYA+47z6F4IVRg2c8
+Vtg1xktot7b/tKn6hgdv59sLtCdKYWt1YiBaZWxlbmthIDxqYWt1Yi56ZWxlbmth
+QGdtYWlsLmNvbT6IkAQTFggAOBYhBMKNk3V1YD60q7clhhwHedxcCp3kBQJgceAg
+AhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEBwHedxcCp3k+3MBAKuK15Xy
+Hw+sdFATFuW9vN+lXqHnYid2jRzQUoh5wG/FAQDcBXQgXRfe72XRoxY4AE3E4onG
+MfzW3kbDKDVF7o4zDrg4BGBx4CASCisGAQQBl1UBBQEBB0Bm2FjWsSDUwL5nbAht
+l+rwnGLKbWiVYrwHQocgKFj6GwMBCAeIeAQYFggAIBYhBMKNk3V1YD60q7clhhwH
+edxcCp3kBQJgceAgAhsMAAoJEBwHedxcCp3k8ZwA/jLRHUBKIeRAxeGJhoqJRr2o
+TxrP887FuX9/ikSX21bcAQD90AB2fu6dpAkOFyZzX9UdE7QxtBhHVWRx3DRr4P/c
+DpgzBGYgDVwWCSsGAQQB2kcPAQEHQET/J56AhF3VoW7XvfydS3kGVTEN7zzOwA06
+KmRjb1w3tCZDYWx2aW4gQnVja2xleSAoUEhQKSA8Y2FsdmluYkBwaHAubmV0PoiT
+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
+=ilrq
-----END PGP PUBLIC KEY BLOCK-----
diff --git a/php.spec b/php.spec
index 2c07d20..8990793 100644
--- a/php.spec
+++ b/php.spec
@@ -49,8 +49,10 @@
%global mysql_sock %(mysql_config --socket 2>/dev/null || echo /var/lib/mysql/mysql.sock)
-%global oraclever 21.5
-%global oraclelib 21.1
+%global oraclever 23.8
+%global oraclemax 24
+%global oraclelib 23.1
+%global oracledir 23
# Build for LiteSpeed Web Server (LSAPI)
%global with_lsws 1
@@ -66,12 +68,18 @@
# Optional components; pass "--with mssql" etc to rpmbuild.
%global with_oci8 %{?_with_oci8:1}%{!?_with_oci8:0}
%global with_imap 1
-%global with_interbase 1
%global with_freetds 1
%global with_tidy 1
%global with_sqlite3 1
%global with_enchant 1
+# Build firebird extensions, you can disable using --without firebird
+%if 0%{?rhel} == 10
+%bcond_with firebird
+%else
+%bcond_without firebird
+%endif
+
%if 0%{?fedora} >= 27 || 0%{?rhel} >= 8
%global with_libpcre 1
%else
@@ -104,13 +112,13 @@
#global gh_date 20190612
%global gh_owner php
%global gh_project php-src
-%global upver 7.4.28
+%global upver 7.4.33
#global rcver RC1
Summary: PHP scripting language for creating dynamic web sites
Name: %{?scl_prefix}php
Version: %{upver}%{?rcver:~%{rcver}}%{?gh_date:.%{gh_date}}
-Release: 2%{?dist}
+Release: 24%{?dist}
# All files licensed under PHP version 3.01, except
# Zend is licensed under Zend
# TSRM is licensed under BSD
@@ -151,7 +159,11 @@ Patch1: php-7.4.0-httpd.patch
Patch5: php-7.2.0-includedir.patch
Patch6: php-7.4.0-embed.patch
Patch8: php-7.2.0-libdb.patch
-Patch9: php-7.0.7-curl.patch
+Patch10: php-7.4.33-gcc14.patch
+# For recent ICU from 8.2
+Patch11: php-7.4.33-icu.patch
+# Fix strict prototypes from 8.1
+Patch12: php-7.4.33-proto.patch
# Functional changes
Patch42: php-7.3.3-systzdata-v19.patch
@@ -175,10 +187,44 @@ Patch91: php-7.2.0-oci8conf.patch
# Upstream fixes (100+)
# Security fixes (200+)
+Patch200: php-cve-2022-31631.patch
+Patch201: php-cve-2023-0567.patch
+Patch202: php-cve-2023-0568.patch
+Patch203: php-cve-2023-0662.patch
+Patch204: php-cve-2023-3247.patch
+Patch205: php-cve-2023-3823.patch
+Patch206: php-cve-2023-3824.patch
+Patch207: php-cve-2024-2756.patch
+Patch208: php-cve-2024-3096.patch
+Patch209: php-cve-2024-5458.patch
+Patch210: php-cve-2024-8925.patch
+Patch211: php-cve-2024-8926.patch
+Patch212: php-cve-2024-8927.patch
+Patch213: php-cve-2024-9026.patch
+Patch214: php-cve-2024-11236.patch
+Patch215: php-cve-2024-11234.patch
+Patch216: php-cve-2024-8932.patch
+Patch217: php-cve-2024-11233.patch
+Patch218: php-ghsa-4w77-75f9-2c8w.patch
+Patch219: php-cve-2024-8929.patch
+Patch220: php-cve-2025-1217.patch
+Patch221: php-cve-2025-1734.patch
+Patch222: php-cve-2025-1861.patch
+Patch223: php-cve-2025-1736.patch
+Patch224: php-cve-2025-1219.patch
+Patch225: php-cve-2025-6491.patch
+Patch226: php-cve-2025-1220.patch
+Patch227: php-cve-2025-1735.patch
# Fixes for tests (300+)
# Factory is droped from system tzdata
Patch300: php-7.0.10-datetests.patch
+# Make test slower
+Patch301: php-7.4.33-tests.patch
+# For zlib-ng
+Patch302: php-7.4.33-zlib-tests.patch
+# for pcre2 10.45
+Patch303: php-7.4.33-pcretests.patch
# WIP
@@ -215,6 +261,9 @@ BuildRequires: libtool
BuildRequires: libtool-ltdl-devel
%if %{with_dtrace}
BuildRequires: %{?dtsprefix}systemtap-sdt-devel
+%if 0%{?fedora} >= 41
+BuildRequires: %{?dtsprefix}systemtap-sdt-dtrace
+%endif
%endif
%if 0%{?gh_date}
BuildRequires: bison
@@ -300,7 +349,6 @@ Group: Development/Languages
Summary: PHP FastCGI Process Manager
BuildRequires: libacl-devel
BuildRequires: pkgconfig(libsystemd) >= 209
-Requires(pre): %{_root_sbindir}/useradd
Requires: %{?scl_prefix}php-common%{?_isa} = %{version}-%{release}
%{?systemd_requires}
# This is actually needed for the %%triggerun script but Requires(triggerun)
@@ -313,6 +361,8 @@ Requires(pre): httpd-filesystem
# For php.conf in /etc/httpd/conf.d
# and version 2.4.10 for proxy support in SetHandler
Requires: httpd-filesystem >= 2.4.10
+%else
+Requires(pre): %{_root_sbindir}/useradd
%endif
%description fpm
@@ -352,6 +402,13 @@ Summary: Common files for PHP
# fileinfo is licensed under PHP version 3.0
# regex, libmagic are licensed under BSD
License: PHP and BSD
+
+Requires: tzdata
+%if %{with_libpcre}
+%global pcre2_buildver %(pkg-config --silence-errors --modversion libpcre2-8 2>/dev/null || echo 10.30)
+Requires: pcre2%{?_isa} >= %{pcre2_buildver}
+%endif
+
# ABI/API check - Arch specific
Provides: %{?scl_prefix}php(api) = %{apiver}-%{__isa_bits}
Provides: %{?scl_prefix}php(zend-abi) = %{zendver}-%{__isa_bits}
@@ -580,7 +637,7 @@ BuildRequires: pkgconfig(libxml-2.0)
The %{?scl_prefix}php-soap package contains a dynamic shared object that will add
support to PHP for using the SOAP web services protocol.
-%if %{with_interbase}
+%if %{with firebird}
%package pdo-firebird
Summary: PDO driver for Interbase/Firebird databases
Group: Development/Languages
@@ -612,7 +669,7 @@ Summary: A module for PHP applications that use OCI8 databases
Group: Development/Languages
# All files licensed under PHP version 3.01
License: PHP
-BuildRequires: oracle-instantclient-devel >= %{oraclever}
+BuildRequires: (oracle-instantclient-devel >= %{oraclever} with oracle-instantclient-devel < %{oraclemax})
Requires: %{?scl_prefix}php-pdo%{?_isa} = %{version}-%{release}
Provides: %{?scl_prefix}php_database
Provides: %{?scl_prefix}php-pdo_oci
@@ -621,8 +678,6 @@ Obsoletes: %{?scl_prefix}php-pecl-oci8 <= %{oci8ver}
Conflicts: %{?scl_prefix}php-pecl-oci8 > %{oci8ver}
Provides: %{?scl_prefix}php-pecl(oci8) = %{oci8ver}
Provides: %{?scl_prefix}php-pecl(oci8)%{?_isa} = %{oci8ver}
-# Should requires libclntsh.so.18.3, but it's not provided by Oracle RPM.
-AutoReq: 0
%description oci8
The %{?scl_prefix}php-oci8 packages provides the OCI8 extension version %{oci8ver}
@@ -632,13 +687,9 @@ The extension is linked with Oracle client libraries %{oraclever}
(Oracle Instant Client). For details, see Oracle's note
"Oracle Client / Server Interoperability Support" (ID 207303.1).
-You must install libclntsh.so.%{oraclelib} to use this package, provided
-in the database installation, or in the free Oracle Instant Client
-available from Oracle.
-
-Notice:
-- %{?scl_prefix}php-oci8 provides oci8 and pdo_oci extensions from php sources.
-- %{?scl_prefix}php-pecl-oci8 only provides oci8 extension.
+You must install libclntsh.so.%{oraclelib} to use this package,
+provided by Oracle Instant Client RPM available from Oracle on:
+https://www.oracle.com/database/technologies/instant-client/downloads.html
Documentation is at http://php.net/oci8 and http://php.net/pdo_oci
%endif
@@ -722,7 +773,7 @@ License: PHP and BSD
%endif
Requires: %{?scl_prefix}php-common%{?_isa} = %{version}-%{release}
%if %{with_libgd}
-BuildRequires: pkgconfig(gdlib) >= 2.3
+BuildRequires: pkgconfig(gdlib) >= 2.3.3
%else
# Required to build the bundled GD library
BuildRequires: pkgconfig(zlib)
@@ -828,9 +879,9 @@ Group: System Environment/Libraries
# All files licensed under PHP version 3.01
License: PHP
Requires: %{?scl_prefix}php-common%{?_isa} = %{version}-%{release}
-BuildRequires: pkgconfig(icu-i18n) >= 69
-BuildRequires: pkgconfig(icu-io) >= 69
-BuildRequires: pkgconfig(icu-uc) >= 69
+BuildRequires: pkgconfig(icu-i18n) >= 74
+BuildRequires: pkgconfig(icu-io) >= 74
+BuildRequires: pkgconfig(icu-uc) >= 74
%description intl
The %{?scl_prefix}php-intl package contains a dynamic shared object that will add
@@ -923,38 +974,65 @@ in pure PHP.
%setup -q -n php-%{upver}%{?rcver}
%endif
-%patch1 -p1 -b .mpmcheck
-%patch5 -p1 -b .includedir
-%patch6 -p1 -b .embed
-%patch8 -p1 -b .libdb
-%if 0%{?rhel}
-%patch9 -p1 -b .curltls
-%endif
+%patch -P1 -p1 -b .mpmcheck
+%patch -P5 -p1 -b .includedir
+%patch -P6 -p1 -b .embed
+%patch -P8 -p1 -b .libdb
+%patch -P10 -p1 -b .gcc14
+%patch -P11 -p1 -b .icu74
+%patch -P12 -p1 -b .proto
-%if 0%{?fedora} >= 28 || 0%{?rhel} >= 6
-%patch42 -p1 -b .systzdata
-%endif
-%patch43 -p1 -b .headers
+%patch -P42 -p1 -b .systzdata
+%patch -P43 -p1 -b .headers
sed -e 's/php-devel/%{?scl_prefix}php-devel/' -i scripts/phpize.in
-%if 0%{?fedora} >= 18 || 0%{?rhel} >= 7
-%patch45 -p1 -b .ldap_r
-%endif
-%patch46 -p1 -b .argon2
-%patch47 -p1 -b .phpinfo
-%patch48 -p1 -b .snmp
+%patch -P45 -p1 -b .ldap_r
+%patch -P46 -p1 -b .argon2
+%patch -P47 -p1 -b .phpinfo
+%patch -P48 -p1 -b .snmp
%if 0%{?fedora} >= 36 || 0%{?rhel} >= 9
-%patch50 -p1 -b .openssl3
+%patch -P50 -p1 -b .openssl3
rm ext/openssl/tests/p12_with_extra_certs.p12
%endif
-%patch91 -p1 -b .remi-oci8
+%patch -P91 -p1 -b .remi-oci8
# upstream patches
# security patches
+%patch -P200 -p1 -b .cve31631
+%patch -P201 -p1 -b .cve0567
+%patch -P202 -p1 -b .cve0568
+%patch -P203 -p1 -b .cve0662
+%patch -P204 -p1 -b .cve3247
+%patch -P205 -p1 -b .cve3823
+%patch -P206 -p1 -b .cve3824
+%patch -P207 -p1 -b .cve2756
+%patch -P208 -p1 -b .cve3096
+%patch -P209 -p1 -b .cve5458
+%patch -P210 -p1 -b .cve8925
+%patch -P211 -p1 -b .cve8926
+%patch -P212 -p1 -b .cve8927
+%patch -P213 -p1 -b .cve9026
+%patch -P214 -p1 -b .cve11236
+%patch -P215 -p1 -b .cve11234
+%patch -P216 -p1 -b .cve8932
+%patch -P217 -p1 -b .cve11233
+%patch -P218 -p1 -b .ghsa4w77
+%patch -P219 -p1 -b .cve8929
+%patch -P220 -p1 -b .cve1217
+%patch -P221 -p1 -b .cve1734
+%patch -P222 -p1 -b .cve1861
+%patch -P223 -p1 -b .cve1736
+%patch -P224 -p1 -b .cve1219
+%patch -P225 -p1 -b .cve6491
+%patch -P226 -p1 -b .cve1220
+%patch -P227 -p1 -b .cve1735
# Fixes for tests
-%patch300 -p1 -b .datetests
+%patch -P300 -p1 -b .datetests
+%patch -P301 -p1 -b .tests
+%patch -P302 -p1 -b .zlibng
+%patch -P303 -p1 -b .pcretests
# WIP patch
@@ -977,14 +1055,12 @@ mkdir \
# ----- Manage known as failed test -------
# affected by systzdata patch
rm ext/date/tests/timezone_location_get.phpt
-rm ext/date/tests/timezone_version_get.phpt
-rm ext/date/tests/timezone_version_get_basic1.phpt
%if 0%{?fedora} < 28
# need tzdata 2018i
rm ext/date/tests/bug33414-1.phpt
-rm ext/date/tests/bug33415-2.phpt
rm ext/date/tests/date_modify-1.phpt
%endif
+rm ext/date/tests/bug33415-2.phpt
# too fast builder
rm ext/date/tests/bug73837.phpt
# fails sometime
@@ -998,6 +1074,13 @@ rm Zend/tests/bug68412.phpt
rm sapi/cli/tests/upload_2G.phpt
# tar issue
rm ext/zlib/tests/004-mb.phpt
+# Known to fail
+%if 0%{?rhel} == 8
+rm ext/openssl/tests/openssl_error_string_basic.phpt
+rm ext/openssl/tests/openssl_open_basic.phpt
+%endif
+rm ext/openssl/tests/openssl_private_decrypt_basic.phpt
+rm ext/openssl/tests/openssl_x509_parse_basic.phpt
# Safety check for API version change.
pver=$(sed -n '/#define PHP_VERSION /{s/.* "//;s/".*$//;p}' main/php_version.h)
@@ -1222,10 +1305,10 @@ build --libdir=%{_libdir}/php \
--with-mysqli=shared,mysqlnd \
--with-mysql-sock=%{mysql_sock} \
%if %{with_oci8}
- --with-oci8=shared,instantclient,%{_root_libdir}/oracle/%{oraclever}/client64/lib,%{oraclever} \
- --with-pdo-oci=shared,instantclient,%{_root_libdir}/oracle/%{oraclever}/client64/lib,%{oraclever} \
+ --with-oci8=shared,instantclient,%{_root_prefix}/lib/oracle/%{oracledir}/client64/lib,%{oraclever} \
+ --with-pdo-oci=shared,instantclient,%{_root_prefix}/lib/oracle/%{oracledir}/client64/lib,%{oraclever} \
%endif
-%if %{with_interbase}
+%if %{with firebird}
--with-pdo-firebird=shared \
%endif
--enable-dom=shared \
@@ -1437,9 +1520,9 @@ mv $RPM_BUILD_ROOT%{_sysconfdir}/php-fpm.d/www.conf.default .
# install systemd unit files and scripts for handling server startup
install -Dm 644 %{SOURCE6} $RPM_BUILD_ROOT%{_unitdir}/%{?scl_prefix}php-fpm.service
%if 0%{?fedora} >= 27 || 0%{?rhel} >= 8
-install -Dm 644 %{SOURCE12} $RPM_BUILD_ROOT%{_unitdir}/httpd.service.d/%{?scl_prefix}php-fpm.conf
-install -Dm 644 %{SOURCE12} $RPM_BUILD_ROOT%{_unitdir}/nginx.service.d/%{?scl_prefix}php-fpm.conf
-sed -e 's/php-fpm/%{?scl_prefix}php-fpm/' -i $RPM_BUILD_ROOT%{_unitdir}/*.service.d/%{?scl_prefix}php-fpm.conf
+install -Dm 644 %{SOURCE12} $RPM_BUILD_ROOT%{_root_sysconfdir}/systemd/system/httpd.service.d/%{?scl_prefix}php-fpm.conf
+install -Dm 644 %{SOURCE12} $RPM_BUILD_ROOT%{_root_sysconfdir}/systemd/system/nginx.service.d/%{?scl_prefix}php-fpm.conf
+sed -e 's/php-fpm/%{?scl_prefix}php-fpm/' -i $RPM_BUILD_ROOT%{_root_sysconfdir}/systemd/system/*.service.d/%{?scl_prefix}php-fpm.conf
%endif
sed -e 's:/run:%{_localstatedir}/run:' \
-e 's:/etc/sysconfig:%{_sysconfdir}/sysconfig:' \
@@ -1530,7 +1613,7 @@ for mod in pgsql odbc ldap snmp \
%if %{with_oci8}
oci8 pdo_oci \
%endif
-%if %{with_interbase}
+%if %{with firebird}
pdo_firebird \
%endif
%if %{with_freetds}
@@ -1671,6 +1754,19 @@ fi
%endif
+%posttrans common
+cat << EOF
+=====================================================================
+
+ WARNING : PHP 7.4 have reached its "End of Life" in
+ November 2022. Even, if this package includes some of
+ the important security fixes, backported from 8.1, the
+ UPGRADE to a maintained version is very strongly RECOMMENDED.
+
+=====================================================================
+EOF
+
+
%{!?_licensedir:%global license %%doc}
%files
@@ -1750,8 +1846,8 @@ fi
%{_unitdir}/%{?scl_prefix}php-fpm.service
%dir %{_root_sysconfdir}/systemd/system/%{?scl_prefix}php-fpm.service.d
%if 0%{?fedora} >= 27 || 0%{?rhel} >= 8
-%{_unitdir}/httpd.service.d/%{?scl_prefix}php-fpm.conf
-%{_unitdir}/nginx.service.d/%{?scl_prefix}php-fpm.conf
+%config(noreplace) %{_root_sysconfdir}/systemd/system/httpd.service.d/%{?scl_prefix}php-fpm.conf
+%config(noreplace) %{_root_sysconfdir}/systemd/system/nginx.service.d/%{?scl_prefix}php-fpm.conf
%endif
%{_sbindir}/php-fpm
%dir %{_sysconfdir}/php-fpm.d
@@ -1808,7 +1904,7 @@ fi
%files pspell -f files.pspell
%files intl -f files.intl
%files process -f files.process
-%if %{with_interbase}
+%if %{with firebird}
%files pdo-firebird -f files.pdo_firebird
%endif
%if %{with_enchant}
@@ -1830,6 +1926,151 @@ fi
%changelog
+* Thu Jul 3 2025 Remi Collet <remi@remirepo.net> - 7.4.33-24
+- Fix pgsql extension does not check for errors during escaping
+ CVE-2025-1735
+- Fix NULL Pointer Dereference in PHP SOAP Extension via Large XML Namespace Prefix
+ CVE-2025-6491
+- Fix Null byte termination in hostnames
+ CVE-2025-1220
+
+* Mon Mar 17 2025 Remi Collet <remi@remirepo.net> - 7.4.33-23
+- Fix libxml streams use wrong `content-type` header when requesting a redirected resource
+ CVE-2025-1219
+- Fix Stream HTTP wrapper header check might omit basic auth header
+ CVE-2025-1736
+- Fix Stream HTTP wrapper truncate redirect location to 1024 bytes
+ CVE-2025-1861
+- Fix Streams HTTP wrapper does not fail for headers without colon
+ CVE-2025-1734
+- Fix Header parser of `http` stream wrapper does not handle folded headers
+ CVE-2025-1217
+- use oracle client library version 23.7 on x86_64 and aarch64
+
+* Thu Feb 13 2025 Remi Collet <remi@remirepo.net> - 7.4.33-22
+- backport fix for ICU 74+
+- backport fix strict prototypes
+
+* Wed Nov 27 2024 Remi Collet <remi@remirepo.net> - 7.4.33-21
+- Fix Leak partial content of the heap through heap buffer over-read
+ CVE-2024-8929
+
+* Fri Nov 22 2024 Remi Collet <remi@remirepo.net> - 7.4.33-20
+- Fix Heap-Use-After-Free in sapi_read_post_data Processing in CLI SAPI Interface
+ GHSA-4w77-75f9-2c8w
+- Fix OOB access in ldap_escape
+ CVE-2024-8932
+- Fix Integer overflow in the dblib/firebird quoter causing OOB writes
+ CVE-2024-11236
+- Fix Configuring a proxy in a stream context might allow for CRLF injection in URIs
+ CVE-2024-11234
+- Fix Single byte overread with convert.quoted-printable-decode filter
+ CVE-2024-11233
+
+* Fri Nov 15 2024 Remi Collet <remi@remirepo.net> - 7.4.33-19
+- disable firebird on EL-10
+
+* Thu Sep 26 2024 Remi Collet <remi@remirepo.net> - 7.4.33-18
+- Fix Bypass of CVE-2012-1823, Argument Injection in PHP-CGI
+ CVE-2024-4577
+- Fix Bypass of CVE-2024-4577, Parameter Injection Vulnerability
+ CVE-2024-8926
+- Fix cgi.force_redirect configuration is bypassable due to the environment variable collision
+ CVE-2024-8927
+- Fix Logs from childrens may be altered
+ CVE-2024-9026
+- Fix Erroneous parsing of multipart form data
+ CVE-2024-8925
+- use ICU 74.2
+
+* Mon Aug 26 2024 Remi Collet <remi@remirepo.net> - 7.4.33-17
+- add backport for https://bugs.php.net/79589
+ error:14095126:SSL routines:ssl3_read_n:unexpected eof while reading
+
+* Wed Jul 31 2024 Remi Collet <remi@remirepo.net> - 7.4.33-16
+- use oracle client library version 23.5 on x86_64
+
+* Tue Jun 4 2024 Remi Collet <remi@remirepo.net> - 7.4.33-15
+- Fix filter bypass in filter_var FILTER_VALIDATE_URL
+ CVE-2024-5458
+
+* Wed Apr 10 2024 Remi Collet <remi@remirepo.net> - 7.4.33-14
+- Fix __Host-/__Secure- cookie bypass due to partial CVE-2022-31629 fix
+ CVE-2024-2756
+- Fix password_verify can erroneously return true opening ATO risk
+ CVE-2024-3096
+
+* Wed Mar 6 2024 Remi Collet <remi@remirepo.net> - 7.4.33-13
+- patch test suite for zlib-ng
+
+* Mon Feb 19 2024 Remi Collet <remi@remirepo.net> - 7.4.33-12
+- more build patch for GCC 14
+
+* Wed Feb 14 2024 Remi Collet <remi@remirepo.net> - 7.4.33-11
+- add build patch for GCC 14
+- use oracle client library version 21.13 on x86_64
+
+* Tue Dec 12 2023 Remi Collet <remi@remirepo.net> - 7.4.33-10
+- use ICU 73.2
+- use oracle client library version 21.12 on x86_64, 19.19 on aarch64
+- add fixes for libxml 2.11 and 2.12 from 8.1
+
+* Thu Sep 21 2023 Remi Collet <remi@remirepo.net> - 7.4.33-9
+- use oracle client library version 21.11 on x86_64, 19.19 on aarch64
+- use official Oracle Instant Client RPM
+
+* Tue Aug 1 2023 Remi Collet <remi@remirepo.net> - 7.4.33-8
+- Fix Security issue with external entity loading in XML without enabling it
+ GHSA-3qrf-m4j2-pcrr CVE-2023-3823
+- Fix Buffer mismanagement in phar_dir_read()
+ GHSA-jqcx-ccgc-xwhv CVE-2023-3824
+- move httpd/nginx wants directive to config files in /etc
+
+* Tue Jun 6 2023 Remi Collet <remi@remirepo.net> - 7.4.33-7
+- Fix Missing error check and insufficient random bytes in HTTP Digest
+ authentication for SOAP
+ GHSA-76gg-c692-v2mw CVE-2023-3247
+
+* Fri Apr 14 2023 Remi Collet <remi@remirepo.net> - 7.4.33-6
+- use ICU 72.1
+- use oracle client library version 21.10
+- fix possible buffer overflow in date
+- define %%php74___phpize and %%php74___phpconfig
+
+* Tue Feb 21 2023 Remi Collet <remi@remirepo.net> - 7.4.33-5
+- F38: enable imap extension
+
+* Tue Feb 14 2023 Remi Collet <remi@remirepo.net> - 7.4.33-4
+- fix #81744: Password_verify() always return true with some hash
+ CVE-2023-0567
+- fix #81746: 1-byte array overrun in common path resolve code
+ CVE-2023-0568
+- fix DOS vulnerability when parsing multipart request body
+ CVE-2023-0662
+- add dependency on pcre2 minimal version
+
+* Mon Dec 19 2022 Remi Collet <remi@remirepo.net> - 7.4.33-2
+- pdo: fix #81740: PDO::quote() may return unquoted string
+ CVE-2022-31631
+- use oracle client library version 21.8
+
+* Tue Nov 1 2022 Remi Collet <remi@remirepo.net> - 7.4.33-1
+- Update to 7.4.33 - http://www.php.net/releases/7_4_33.php
+
+* Wed Oct 26 2022 Remi Collet <remi@remirepo.net> - 7.4.32-2
+- add upstream fix for CVE-2022-31630 and CVE-2022-37454
+
+* Wed Sep 28 2022 Remi Collet <remi@remirepo.net> - 7.4.32-1
+- Update to 7.4.32 - http://www.php.net/releases/7_4_32.php
+- use ICU 71.1
+
+* Tue Jun 7 2022 Remi Collet <remi@remirepo.net> - 7.4.30-1
+- Update to 7.4.30 - http://www.php.net/releases/7_4_30.php
+- use oracle client library version 21.6
+
+* Tue Apr 12 2022 Remi Collet <remi@remirepo.net> - 7.4.29-1
+- Update to 7.4.29 - http://www.php.net/releases/7_4_29.php
+
* Tue Feb 22 2022 Remi Collet <remi@remirepo.net> - 7.4.28-2
- retrieve tzdata version
- use oracle client library version 21.5