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 Resolves: RHEL-87151
1780 lines
63 KiB
Diff
1780 lines
63 KiB
Diff
From 78ae0886bd1a3e42c53c9ba65764b6e6357640b5 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)
|
|
---
|
|
.../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/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 +
|
|
24 files changed, 404 insertions(+), 64 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/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 90%
|
|
rename from ext/dom/tests/DOMDocument_loadXML_error2.phpt
|
|
rename to ext/dom/tests/DOMDocument_loadXML_error2_pre2_11.phpt
|
|
index 6d56a317ed7..0e36d209058 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 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 90%
|
|
rename from ext/dom/tests/DOMDocument_load_error2.phpt
|
|
rename to ext/dom/tests/DOMDocument_load_error2_pre2_11.phpt
|
|
index f450cf16545..b97fff9d2f1 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 73486ae253f..c8bd1be60a4 100644
|
|
--- a/ext/libxml/libxml.c
|
|
+++ b/ext/libxml/libxml.c
|
|
@@ -525,6 +525,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 ed6576aa752..b935261cb2e 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
|
|
|
|
Warning: Attempt to read property "nodeValue" on null 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 caa7356ad30..d90f909ac2b 100644
|
|
--- a/ext/libxml/tests/libxml_disable_entity_loader_2.phpt
|
|
+++ b/ext/libxml/tests/libxml_disable_entity_loader_2.phpt
|
|
@@ -38,6 +38,6 @@ bool(true)
|
|
Deprecated: Function libxml_disable_entity_loader() is deprecated in %s on line %d
|
|
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 87894bcb91a..ddaf9bfa50e 100644
|
|
--- a/ext/libxml/tests/libxml_set_external_entity_loader_variation2.phpt
|
|
+++ b/ext/libxml/tests/libxml_set_external_entity_loader_variation2.phpt
|
|
@@ -39,6 +39,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 61d45385b62..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, string|array $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..61d45385b62
|
|
--- /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, string|array $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 744cff9cc72..461a649b147 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 bc71fd4e411..126b77bae62 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 c40123560ef..0f04f565d6b 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 37a47df060a..aa23a96aedc 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 6c84679ff63..8ef42b5700f 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 bb7945ce62d..595f0fd9272 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 1d0e4fa70a2..99c8e025f93 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 f935b5a02ca..945225d9e06 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 078d605b671..6619db3a5dd 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 ad5ddc879ce..7eb9015d963 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 d0396e819fb..f8f67886634 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 037d2002cc5..671c82e8ee0 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 b6c0b875818..90283850d24 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 6e8e9f558aa0903e9650dd166a0a53c359d9e9e0 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)
|
|
---
|
|
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 c8bd1be60a4..554fcc34ff2 100644
|
|
--- a/ext/libxml/libxml.c
|
|
+++ b/ext/libxml/libxml.c
|
|
@@ -481,7 +481,11 @@ static void _php_libxml_free_error(void *ptr)
|
|
xmlResetError((xmlErrorPtr) ptr);
|
|
}
|
|
|
|
-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;
|
|
@@ -734,7 +738,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);
|
|
|
|
@@ -1037,11 +1045,9 @@ PHP_FUNCTION(libxml_use_internal_errors)
|
|
/* {{{ Retrieve last error from libxml */
|
|
PHP_FUNCTION(libxml_get_last_error)
|
|
{
|
|
- xmlErrorPtr error;
|
|
-
|
|
ZEND_PARSE_PARAMETERS_NONE();
|
|
|
|
- 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 e5e7f2f9554..6060f634508 100644
|
|
--- a/ext/soap/php_sdl.c
|
|
+++ b/ext/soap/php_sdl.c
|
|
@@ -331,7 +331,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 6cb68826aaf68ffe8c70c8782450c38970236040 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)
|
|
---
|
|
ext/dom/document.c | 6 ++--
|
|
.../DOMDocument_loadHTMLfile_error1.phpt | 2 +-
|
|
.../DOMDocument_loadXML_error2_pre2_11.phpt | 3 +-
|
|
.../DOMDocument_load_error2_pre2_11.phpt | 3 +-
|
|
.../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 +-
|
|
18 files changed, 97 insertions(+), 29 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 02522b5014f..7735e5d5dc3 100644
|
|
--- a/ext/dom/document.c
|
|
+++ b/ext/dom/document.c
|
|
@@ -1253,11 +1253,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;
|
|
@@ -1267,7 +1269,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_loadXML_error2_pre2_11.phpt b/ext/dom/tests/DOMDocument_loadXML_error2_pre2_11.phpt
|
|
index 0e36d209058..7e10771fdb7 100644
|
|
--- a/ext/dom/tests/DOMDocument_loadXML_error2_pre2_11.phpt
|
|
+++ b/ext/dom/tests/DOMDocument_loadXML_error2_pre2_11.phpt
|
|
@@ -2,6 +2,7 @@
|
|
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--
|
|
@@ -14,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_pre2_11.phpt b/ext/dom/tests/DOMDocument_load_error2_pre2_11.phpt
|
|
index b97fff9d2f1..74b20c171e0 100644
|
|
--- a/ext/dom/tests/DOMDocument_load_error2_pre2_11.phpt
|
|
+++ b/ext/dom/tests/DOMDocument_load_error2_pre2_11.phpt
|
|
@@ -2,6 +2,7 @@
|
|
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--
|
|
@@ -14,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_relaxNGValidate_error2.phpt b/ext/dom/tests/DOMDocument_relaxNGValidate_error2.phpt
|
|
index 3aa6a3b3189..bf8d7befa53 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 554fcc34ff2..28dd86a55c9 100644
|
|
--- a/ext/libxml/libxml.c
|
|
+++ b/ext/libxml/libxml.c
|
|
@@ -428,8 +428,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 f5723e213a4..2634d2c7db4 100644
|
|
--- a/ext/soap/php_encoding.c
|
|
+++ b/ext/soap/php_encoding.c
|
|
@@ -3379,7 +3379,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);
|
|
@@ -3393,9 +3392,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 ed3495c1266..58c176031f9 100644
|
|
--- a/ext/soap/php_xml.c
|
|
+++ b/ext/soap/php_xml.c
|
|
@@ -92,13 +92,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);
|
|
@@ -146,6 +147,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 f945a8753e5..dd14d1afb62 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 3b2a0cdf7fb..4d1f506840a 100644
|
|
--- a/ext/xml/compat.c
|
|
+++ b/ext/xml/compat.c
|
|
@@ -714,8 +714,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 61e4a3a7d95..8a3fa1cea67 100644
|
|
--- a/ext/xmlwriter/php_xmlwriter.c
|
|
+++ b/ext/xmlwriter/php_xmlwriter.c
|
|
@@ -1001,7 +1001,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 1196e566681a34564c02173ba234b5a42587ff07 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)
|
|
---
|
|
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 ++++++++++++----------
|
|
4 files changed, 224 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
|
|
|
|
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..47212cb3410
|
|
--- /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/server.inc") die('skip server.inc not available');
|
|
+http_server_skipif();
|
|
+?>
|
|
+--FILE--
|
|
+<?php
|
|
+require "./ext/standard/tests/http/server.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..a7eff3b9a8b
|
|
--- /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/server.inc") die('skip server.inc not available');
|
|
+http_server_skipif();
|
|
+?>
|
|
+--FILE--
|
|
+<?php
|
|
+require "./ext/standard/tests/http/server.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..178b35f3525
|
|
--- /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/server.inc") die('skip server.inc not available');
|
|
+http_server_skipif();
|
|
+?>
|
|
+--FILE--
|
|
+<?php
|
|
+require "./ext/standard/tests/http/server.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 28dd86a55c9..7886ca79ad9 100644
|
|
--- a/ext/libxml/libxml.c
|
|
+++ b/ext/libxml/libxml.c
|
|
@@ -372,42 +372,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();
|
|
}
|
|
--
|
|
2.48.1
|
|
|
|
From 294140ee981fda6a38244215e4b16e53b7f5b2a6 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)
|
|
---
|
|
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 cc1457d9705..cac86ca7508 100644
|
|
--- a/ext/xml/xml.c
|
|
+++ b/ext/xml/xml.c
|
|
@@ -668,9 +668,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);
|
|
|
|
@@ -737,9 +739,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 d7ab2bb9856d938fca7989575695c14c25892589 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)
|
|
---
|
|
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 7735e5d5dc3..5ef5dc479d6 100644
|
|
--- a/ext/dom/document.c
|
|
+++ b/ext/dom/document.c
|
|
@@ -23,6 +23,7 @@
|
|
#if defined(HAVE_LIBXML) && defined(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 d0ce7cec714..02717417a71 100644
|
|
--- a/ext/libxml/php_libxml.h
|
|
+++ b/ext/libxml/php_libxml.h
|
|
@@ -35,6 +35,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 adae2b8de8963ac6f92103803bf91a5174172f88 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
|
|
|
|
---
|
|
NEWS | 17 +++++++++++++++++
|
|
1 file changed, 17 insertions(+)
|
|
|
|
diff --git a/NEWS b/NEWS
|
|
index e043901ee96..7db6f2660d2 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
|
|
|