diff --git a/NEWS b/NEWS
index 4bd6e99b437..5b66fb559e3 100644
--- a/NEWS
+++ b/NEWS
@@ -2,7 +2,10 @@ PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? ????, PHP 8.4.0alpha2
-- PDO
+- LibXML:
+ . Added LIBXML_NO_XXE constant. (nielsdos)
+
+- PDO:
. Fixed bug GH-14792 (Compilation failure on pdo_* extensions).
(Peter Kokot)
diff --git a/UPGRADING b/UPGRADING
index d72ce15cf0a..abc564135f8 100644
--- a/UPGRADING
+++ b/UPGRADING
@@ -763,6 +763,10 @@ PHP 8.4 UPGRADE NOTES
- LibXML:
. LIBXML_RECOVER.
+ . LIBXML_NO_XXE.
+ This is used together with LIBXML_NOENT for when you want to perform entity
+ substitution, but want to disallow external entity loading.
+ This constant is available as of libxml2 2.13.
- OpenSSL:
. X509_PURPOSE_OCSP_HELPER.
diff --git a/ext/dom/tests/modern/xml/XMLDocument_fromString_03.phpt b/ext/dom/tests/modern/xml/XMLDocument_fromString_03.phpt
index 4f29c01c264..13359f4b285 100644
--- a/ext/dom/tests/modern/xml/XMLDocument_fromString_03.phpt
+++ b/ext/dom/tests/modern/xml/XMLDocument_fromString_03.phpt
@@ -12,7 +12,7 @@ $flags = [
try {
Dom\XMLDocument::createFromString('', -1);
} catch (ValueError $e) {
- echo $e->getMessage();
+ echo $e->getMessage(), "\n";
}
foreach ($flags as $flag) {
@@ -20,8 +20,9 @@ foreach ($flags as $flag) {
}
?>
---EXPECT--
-Dom\XMLDocument::createFromString(): Argument #2 ($options) contains invalid flags (allowed flags: LIBXML_RECOVER, LIBXML_NOENT, LIBXML_DTDLOAD, LIBXML_DTDATTR, LIBXML_DTDVALID, LIBXML_NOERROR, LIBXML_NOWARNING, LIBXML_NOBLANKS, LIBXML_XINCLUDE, LIBXML_NSCLEAN, LIBXML_NOCDATA, LIBXML_NONET, LIBXML_PEDANTIC, LIBXML_COMPACT, LIBXML_PARSEHUGE, LIBXML_BIGLINES)bool(true)
+--EXPECTF--
+Dom\XMLDocument::createFromString(): Argument #2 ($options) contains invalid flags (allowed flags: %s)
+bool(true)
bool(true)
bool(true)
bool(true)
diff --git a/ext/dom/tests/xml_parsing_LIBXML_NO_XXE.phpt b/ext/dom/tests/xml_parsing_LIBXML_NO_XXE.phpt
new file mode 100644
index 00000000000..9033ce50f9e
--- /dev/null
+++ b/ext/dom/tests/xml_parsing_LIBXML_NO_XXE.phpt
@@ -0,0 +1,29 @@
+--TEST--
+Test flag LIBXML_NO_XXE
+--EXTENSIONS--
+dom
+--SKIPIF--
+
+--FILE--
+
+bar'>
+
+]>
+&foo;&xxe;
+XML;
+
+$doc = Dom\XMLDocument::createFromString($xml, LIBXML_NOENT | LIBXML_NO_XXE);
+echo $doc->saveXML();
+?>
+--EXPECT--
+
+bar">
+
+]>
+bar
diff --git a/ext/dom/xml_document.c b/ext/dom/xml_document.c
index 59b8b1178ae..e1511b65ef7 100644
--- a/ext/dom/xml_document.c
+++ b/ext/dom/xml_document.c
@@ -29,6 +29,9 @@ static bool check_options_validity(uint32_t arg_num, zend_long options)
{
const zend_long VALID_OPTIONS = XML_PARSE_RECOVER
| XML_PARSE_NOENT
+#if LIBXML_VERSION >= 21300
+ | XML_PARSE_NO_XXE
+#endif
| XML_PARSE_DTDLOAD
| XML_PARSE_DTDATTR
| XML_PARSE_DTDVALID
@@ -47,6 +50,9 @@ static bool check_options_validity(uint32_t arg_num, zend_long options)
zend_argument_value_error(arg_num, "contains invalid flags (allowed flags: "
"LIBXML_RECOVER, "
"LIBXML_NOENT, "
+#if LIBXML_VERSION >= 21300
+ "LIBXML_NO_XXE, "
+#endif
"LIBXML_DTDLOAD, "
"LIBXML_DTDATTR, "
"LIBXML_DTDVALID, "
diff --git a/ext/libxml/libxml.stub.php b/ext/libxml/libxml.stub.php
index ac9220c4f1d..231d7f5368c 100644
--- a/ext/libxml/libxml.stub.php
+++ b/ext/libxml/libxml.stub.php
@@ -28,6 +28,13 @@ const LIBXML_RECOVER = UNKNOWN;
* @cvalue XML_PARSE_NOENT
*/
const LIBXML_NOENT = UNKNOWN;
+#if LIBXML_VERSION >= 21300
+/**
+ * @var int
+ * @cvalue XML_PARSE_NO_XXE
+ */
+const LIBXML_NO_XXE = UNKNOWN;
+#endif
/**
* @var int
* @cvalue XML_PARSE_DTDLOAD
diff --git a/ext/libxml/libxml_arginfo.h b/ext/libxml/libxml_arginfo.h
index a4c072a9b02..fe50c20c220 100644
--- a/ext/libxml/libxml_arginfo.h
+++ b/ext/libxml/libxml_arginfo.h
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
- * Stub hash: 08e4e3f10ba89430292831f50c4760a362593282 */
+ * Stub hash: 9baeff96436234ec51bd329477c6143caca7dd20 */
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_libxml_set_streams_context, 0, 1, IS_VOID, 0)
ZEND_ARG_INFO(0, context)
@@ -61,6 +61,9 @@ static void register_libxml_symbols(int module_number)
REGISTER_STRING_CONSTANT("LIBXML_LOADED_VERSION", PHP_LIBXML_LOADED_VERSION, CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("LIBXML_RECOVER", XML_PARSE_RECOVER, CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("LIBXML_NOENT", XML_PARSE_NOENT, CONST_PERSISTENT);
+#if LIBXML_VERSION >= 21300
+ REGISTER_LONG_CONSTANT("LIBXML_NO_XXE", XML_PARSE_NO_XXE, CONST_PERSISTENT);
+#endif
REGISTER_LONG_CONSTANT("LIBXML_DTDLOAD", XML_PARSE_DTDLOAD, CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("LIBXML_DTDATTR", XML_PARSE_DTDATTR, CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("LIBXML_DTDVALID", XML_PARSE_DTDVALID, CONST_PERSISTENT);
diff --git a/ext/simplexml/tests/xml_parsing_LIBXML_NO_XXE.phpt b/ext/simplexml/tests/xml_parsing_LIBXML_NO_XXE.phpt
new file mode 100644
index 00000000000..c80c70a1d0b
--- /dev/null
+++ b/ext/simplexml/tests/xml_parsing_LIBXML_NO_XXE.phpt
@@ -0,0 +1,28 @@
+--TEST--
+XML parsing with LIBXML_NO_XXE
+--EXTENSIONS--
+simplexml
+--SKIPIF--
+
+--FILE--
+
+bar'>
+
+]>
+&foo;&xxe;
+XML;
+
+var_dump(simplexml_load_string($xml, options: LIBXML_NOENT | LIBXML_NO_XXE));
+
+?>
+--EXPECT--
+object(SimpleXMLElement)#1 (1) {
+ ["foo"]=>
+ string(3) "bar"
+}