diff --git a/UPGRADING b/UPGRADING index 11cca55bd1735..274f45d8f401b 100644 --- a/UPGRADING +++ b/UPGRADING @@ -82,6 +82,11 @@ PHP 8.5 UPGRADE NOTES . A ValueError is now thrown when trying to set a cursor name that is too long on a PDOStatement resulting from the Firebird driver. +- SimpleXML: + - Passing an XPath expression that returns something other than a node set + to SimpleXMLElement::xpath() will now emit a warning and return false, + instead of silently failing and returning an empty array. + - SPL: . ArrayObject no longer accepts enums, as modifying the $name or $value properties can break engine assumptions. diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c index 1de7ccc6e74e8..877280fb378dc 100644 --- a/ext/simplexml/simplexml.c +++ b/ext/simplexml/simplexml.c @@ -1215,6 +1215,21 @@ static int sxe_objects_compare(zval *object1, zval *object2) /* {{{ */ } /* }}} */ +static const char *sxe_get_object_type_name(xmlXPathObjectType type) +{ + switch (type) { + case XPATH_BOOLEAN: return "bool"; + case XPATH_NUMBER: return "number"; + case XPATH_STRING: return "string"; +#ifdef LIBXML_XPTR_LOCS_ENABLED + case XPATH_POINT: return "point"; + case XPATH_RANGE: return "range"; + case XPATH_LOCATIONSET: return "location set"; +#endif + default: return "undefined"; + } +} + /* {{{ Runs XPath query on the XML data */ PHP_METHOD(SimpleXMLElement, xpath) { @@ -1271,6 +1286,13 @@ PHP_METHOD(SimpleXMLElement, xpath) RETURN_FALSE; } + if (UNEXPECTED(retval->type != XPATH_NODESET)) { + php_error_docref(NULL, E_WARNING, "XPath expression must return a node set, %s returned", + sxe_get_object_type_name(retval->type)); + xmlXPathFreeObject(retval); + RETURN_FALSE; + } + result = retval->nodesetval; if (result != NULL) { diff --git a/ext/simplexml/tests/008.phpt b/ext/simplexml/tests/008.phpt index c946c36dafe63..dea6f98eacfcc 100644 --- a/ext/simplexml/tests/008.phpt +++ b/ext/simplexml/tests/008.phpt @@ -39,8 +39,9 @@ array(1) { } } } -array(0) { -} -Warning: SimpleXMLElement::xpath(): Invalid expression in %s on line %d%A +Warning: SimpleXMLElement::xpath(): XPath expression must return a node set, number returned in %s on line %d +bool(false) + +Warning: SimpleXMLElement::xpath(): Invalid expression in %s on line %d bool(false) diff --git a/ext/simplexml/tests/gh12231.phpt b/ext/simplexml/tests/gh12231.phpt new file mode 100644 index 0000000000000..efacd92b76f95 --- /dev/null +++ b/ext/simplexml/tests/gh12231.phpt @@ -0,0 +1,26 @@ +--TEST-- +GH-12231 (SimpleXML xpath should warn when returning other return types than node lists) +--EXTENSIONS-- +simplexml +--FILE-- +"; +$sxe = simplexml_load_string($xml); + +var_dump($sxe->xpath("count(//foo)")); +var_dump($sxe->xpath("string(//foo)")); +var_dump($sxe->xpath("boolean(//foo)")); +var_dump(count($sxe->xpath("//foo"))); + +?> +--EXPECTF-- +Warning: SimpleXMLElement::xpath(): XPath expression must return a node set, number returned in %s on line %d +bool(false) + +Warning: SimpleXMLElement::xpath(): XPath expression must return a node set, string returned in %s on line %d +bool(false) + +Warning: SimpleXMLElement::xpath(): XPath expression must return a node set, bool returned in %s on line %d +bool(false) +int(2)