1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Merge branch 'PHP-8.2'

* PHP-8.2:
  Fix DOMElement::append() and DOMElement::prepend() hierarchy checks
  Fix spec compliance error for DOMDocument::getElementsByTagNameNS
  Fix GH-11336: php still tries to unlock the shared memory ZendSem with opcache.file_cache_only=1 but it was never locked
  Fix GH-11338: SplFileInfo empty getBasename with more than one slash
This commit is contained in:
nielsdos
2023-05-30 17:41:54 +02:00
9 changed files with 349 additions and 3 deletions

View File

@@ -255,10 +255,33 @@ static void dom_fragment_assign_parent_node(xmlNodePtr parentNode, xmlNodePtr fr
fragment->last = NULL;
}
static zend_result dom_hierarchy_node_list(xmlNodePtr parentNode, zval *nodes, int nodesc)
{
for (int i = 0; i < nodesc; i++) {
if (Z_TYPE(nodes[i]) == IS_OBJECT) {
const zend_class_entry *ce = Z_OBJCE(nodes[i]);
if (instanceof_function(ce, dom_node_class_entry)) {
if (dom_hierarchy(parentNode, dom_object_get_node(Z_DOMOBJ_P(nodes + i))) != SUCCESS) {
return FAILURE;
}
}
}
}
return SUCCESS;
}
void dom_parent_node_append(dom_object *context, zval *nodes, int nodesc)
{
xmlNode *parentNode = dom_object_get_node(context);
xmlNodePtr newchild, prevsib;
if (UNEXPECTED(dom_hierarchy_node_list(parentNode, nodes, nodesc) != SUCCESS)) {
php_dom_throw_error(HIERARCHY_REQUEST_ERR, dom_get_strict_error(context->document));
return;
}
xmlNode *fragment = dom_zvals_to_fragment(context->document, parentNode, nodes, nodesc);
if (fragment == NULL) {
@@ -296,6 +319,11 @@ void dom_parent_node_prepend(dom_object *context, zval *nodes, int nodesc)
return;
}
if (UNEXPECTED(dom_hierarchy_node_list(parentNode, nodes, nodesc) != SUCCESS)) {
php_dom_throw_error(HIERARCHY_REQUEST_ERR, dom_get_strict_error(context->document));
return;
}
xmlNodePtr newchild, nextsib;
xmlNode *fragment = dom_zvals_to_fragment(context->document, parentNode, nodes, nodesc);

View File

@@ -1221,10 +1221,15 @@ xmlNode *dom_get_elements_by_tag_name_ns_raw(xmlNodePtr nodep, char *ns, char *l
{
xmlNodePtr ret = NULL;
/* Note: The spec says that ns == '' must be transformed to ns == NULL. In other words, they are equivalent.
* PHP however does not do this and internally uses the empty string everywhere when the user provides ns == NULL.
* This is because for PHP ns == NULL has another meaning: "match every namespace" instead of "match the empty namespace". */
bool ns_match_any = ns == NULL || (ns[0] == '*' && ns[1] == '\0');
while (nodep != NULL && (*cur <= index || index == -1)) {
if (nodep->type == XML_ELEMENT_NODE) {
if (xmlStrEqual(nodep->name, (xmlChar *)local) || xmlStrEqual((xmlChar *)"*", (xmlChar *)local)) {
if (ns == NULL || (!strcmp(ns, "") && nodep->ns == NULL) || (nodep->ns != NULL && (xmlStrEqual(nodep->ns->href, (xmlChar *)ns) || xmlStrEqual((xmlChar *)"*", (xmlChar *)ns)))) {
if (ns_match_any || (!strcmp(ns, "") && nodep->ns == NULL) || (nodep->ns != NULL && xmlStrEqual(nodep->ns->href, (xmlChar *)ns))) {
if (*cur == index) {
ret = nodep;
break;

View File

@@ -0,0 +1,82 @@
--TEST--
DOMDocument::getElementsByTagNameNS() match any namespace
--EXTENSIONS--
dom
--FILE--
<?php
/* Sample document taken from https://www.php.net/manual/en/domdocument.getelementsbytagname.php */
$xml = <<<EOD
<?xml version="1.0" ?>
<chapter xmlns:xi="http://www.w3.org/2001/XInclude">
<title>Books of the other guy..</title>
<para>
<xi:include href="book.xml">
<xi:fallback>
<error>xinclude: book.xml not found</error>
</xi:fallback>
</xi:include>
<include>
This is another namespace
</include>
</para>
</chapter>
EOD;
$dom = new DOMDocument;
// load the XML string defined above
$dom->loadXML($xml);
function test($namespace, $local) {
global $dom;
$namespace_str = $namespace !== NULL ? "'$namespace'" : "null";
echo "-- getElementsByTagNameNS($namespace_str, '$local') --\n";
foreach ($dom->getElementsByTagNameNS($namespace, $local) as $element) {
echo 'local name: \'', $element->localName, '\', prefix: \'', $element->prefix, "'\n";
}
}
// Should *also* include objects even without a namespace
test(null, '*');
// Should *also* include objects even without a namespace
test('*', '*');
// Should *only* include objects without a namespace
test('', '*');
// Should *only* include objects with the specified namespace
test('http://www.w3.org/2001/XInclude', '*');
// Should not give any output
test('', 'fallback');
// Should not give any output, because the null namespace is the same as the empty namespace
test(null, 'fallback');
// Should only output the include from the empty namespace
test(null, 'include');
?>
--EXPECT--
-- getElementsByTagNameNS(null, '*') --
local name: 'chapter', prefix: ''
local name: 'title', prefix: ''
local name: 'para', prefix: ''
local name: 'error', prefix: ''
local name: 'include', prefix: ''
-- getElementsByTagNameNS('*', '*') --
local name: 'chapter', prefix: ''
local name: 'title', prefix: ''
local name: 'para', prefix: ''
local name: 'include', prefix: 'xi'
local name: 'fallback', prefix: 'xi'
local name: 'error', prefix: ''
local name: 'include', prefix: ''
-- getElementsByTagNameNS('', '*') --
local name: 'chapter', prefix: ''
local name: 'title', prefix: ''
local name: 'para', prefix: ''
local name: 'error', prefix: ''
local name: 'include', prefix: ''
-- getElementsByTagNameNS('http://www.w3.org/2001/XInclude', '*') --
local name: 'include', prefix: 'xi'
local name: 'fallback', prefix: 'xi'
-- getElementsByTagNameNS('', 'fallback') --
-- getElementsByTagNameNS(null, 'fallback') --
-- getElementsByTagNameNS(null, 'include') --
local name: 'include', prefix: ''

View File

@@ -0,0 +1,89 @@
--TEST--
DOMElement::append() with hierarchy changes and errors
--EXTENSIONS--
dom
--FILE--
<?php
$dom_original = new DOMDocument;
$dom_original->loadXML('<p><b>hello</b><b><i>world</i></b></p>');
echo "-- Append hello with world --\n";
$dom = clone $dom_original;
$b_hello = $dom->firstChild->firstChild;
$b_world = $b_hello->nextSibling;
$b_hello->append($b_world);
var_dump($dom->saveHTML());
echo "-- Append hello with world's child --\n";
$dom = clone $dom_original;
$b_hello = $dom->firstChild->firstChild;
$b_world = $b_hello->nextSibling;
$b_hello->append($b_world->firstChild);
var_dump($dom->saveHTML());
echo "-- Append world's child with hello --\n";
$dom = clone $dom_original;
$b_hello = $dom->firstChild->firstChild;
$b_world = $b_hello->nextSibling;
$b_world->firstChild->append($b_hello);
var_dump($dom->saveHTML());
echo "-- Append hello with itself --\n";
$dom = clone $dom_original;
$b_hello = $dom->firstChild->firstChild;
try {
$b_hello->append($b_hello);
} catch (\DOMException $e) {
echo $e->getMessage(), "\n";
}
var_dump($dom->saveHTML());
echo "-- Append world's i tag with the parent --\n";
$dom = clone $dom_original;
$b_hello = $dom->firstChild->firstChild;
$b_world = $b_hello->nextSibling;
try {
$b_world->firstChild->append($b_world);
} catch (\DOMException $e) {
echo $e->getMessage(), "\n";
}
var_dump($dom->saveHTML());
echo "-- Append from another document --\n";
$dom = clone $dom_original;
$dom2 = new DOMDocument;
$dom2->loadXML('<p>other</p>');
try {
$dom->firstChild->firstChild->prepend($dom2->firstChild);
} catch (\DOMException $e) {
echo $e->getMessage(), "\n";
}
var_dump($dom2->saveHTML());
var_dump($dom->saveHTML());
?>
--EXPECT--
-- Append hello with world --
string(39) "<p><b>hello<b><i>world</i></b></b></p>
"
-- Append hello with world's child --
string(39) "<p><b>hello<i>world</i></b><b></b></p>
"
-- Append world's child with hello --
string(39) "<p><b><i>world<b>hello</b></i></b></p>
"
-- Append hello with itself --
Hierarchy Request Error
string(39) "<p><b>hello</b><b><i>world</i></b></p>
"
-- Append world's i tag with the parent --
Hierarchy Request Error
string(39) "<p><b>hello</b><b><i>world</i></b></p>
"
-- Append from another document --
Wrong Document Error
string(13) "<p>other</p>
"
string(39) "<p><b>hello</b><b><i>world</i></b></p>
"

View File

@@ -0,0 +1,89 @@
--TEST--
DOMElement::prepend() with hierarchy changes and errors
--EXTENSIONS--
dom
--FILE--
<?php
$dom_original = new DOMDocument;
$dom_original->loadXML('<p><b>hello</b><b><i>world</i></b></p>');
echo "-- Prepend hello with world --\n";
$dom = clone $dom_original;
$b_hello = $dom->firstChild->firstChild;
$b_world = $b_hello->nextSibling;
$b_hello->prepend($b_world);
var_dump($dom->saveHTML());
echo "-- Prepend hello with world's child --\n";
$dom = clone $dom_original;
$b_hello = $dom->firstChild->firstChild;
$b_world = $b_hello->nextSibling;
$b_hello->prepend($b_world->firstChild);
var_dump($dom->saveHTML());
echo "-- Prepend world's child with hello --\n";
$dom = clone $dom_original;
$b_hello = $dom->firstChild->firstChild;
$b_world = $b_hello->nextSibling;
$b_world->firstChild->prepend($b_hello);
var_dump($dom->saveHTML());
echo "-- Prepend hello with itself --\n";
$dom = clone $dom_original;
$b_hello = $dom->firstChild->firstChild;
try {
$b_hello->prepend($b_hello);
} catch (\DOMException $e) {
echo $e->getMessage(), "\n";
}
var_dump($dom->saveHTML());
echo "-- Prepend world's i tag with the parent --\n";
$dom = clone $dom_original;
$b_hello = $dom->firstChild->firstChild;
$b_world = $b_hello->nextSibling;
try {
$b_world->firstChild->prepend($b_world);
} catch (\DOMException $e) {
echo $e->getMessage(), "\n";
}
var_dump($dom->saveHTML());
echo "-- Append from another document --\n";
$dom = clone $dom_original;
$dom2 = new DOMDocument;
$dom2->loadXML('<p>other</p>');
try {
$dom->firstChild->firstChild->prepend($dom2->firstChild);
} catch (\DOMException $e) {
echo $e->getMessage(), "\n";
}
var_dump($dom2->saveHTML());
var_dump($dom->saveHTML());
?>
--EXPECT--
-- Prepend hello with world --
string(39) "<p><b><b><i>world</i></b>hello</b></p>
"
-- Prepend hello with world's child --
string(39) "<p><b><i>world</i>hello</b><b></b></p>
"
-- Prepend world's child with hello --
string(39) "<p><b><i><b>hello</b>world</i></b></p>
"
-- Prepend hello with itself --
Hierarchy Request Error
string(39) "<p><b>hello</b><b><i>world</i></b></p>
"
-- Prepend world's i tag with the parent --
Hierarchy Request Error
string(39) "<p><b>hello</b><b><i>world</i></b></p>
"
-- Append from another document --
Wrong Document Error
string(13) "<p>other</p>
"
string(39) "<p><b>hello</b><b><i>world</i></b></p>
"

View File

@@ -390,6 +390,10 @@ static inline void accel_unlock_all(void)
#ifdef ZEND_WIN32
accel_deactivate_sub();
#else
if (lock_file == -1) {
return;
}
struct flock mem_usage_unlock_all;
mem_usage_unlock_all.l_type = F_UNLCK;

View File

@@ -59,7 +59,7 @@ zend_smm_shared_globals *smm_shared_globals;
#ifdef ZTS
static MUTEX_T zts_lock;
#endif
int lock_file;
int lock_file = -1;
static char lockfile_name[MAXPATHLEN];
#endif

View File

@@ -454,7 +454,9 @@ static void spl_filesystem_info_set_filename(spl_filesystem_object *intern, zend
path_len = ZSTR_LEN(path);
if (path_len > 1 && IS_SLASH_AT(ZSTR_VAL(path), path_len-1)) {
path_len--;
do {
path_len--;
} while (path_len > 1 && IS_SLASH_AT(ZSTR_VAL(path), path_len - 1));
intern->file_name = zend_string_init(ZSTR_VAL(path), path_len, 0);
} else {
intern->file_name = zend_string_copy(path);

View File

@@ -0,0 +1,47 @@
--TEST--
GH-11338 (SplFileInfo empty getBasename with more than on slash)
--FILE--
<?php
function test($path) {
echo "Testing: '$path'\n";
$file = new \SplFileInfo($path);
var_dump($file->getBasename());
var_dump($file->getFilename());
}
test('/dir/anotherdir/basedir//');
test('/dir/anotherdir/basedir/');
test('/dir/anotherdir/basedir');
test('/dir/anotherdir//basedir');
test('///');
test('//');
test('/');
test('');
?>
--EXPECT--
Testing: '/dir/anotherdir/basedir//'
string(7) "basedir"
string(7) "basedir"
Testing: '/dir/anotherdir/basedir/'
string(7) "basedir"
string(7) "basedir"
Testing: '/dir/anotherdir/basedir'
string(7) "basedir"
string(7) "basedir"
Testing: '/dir/anotherdir//basedir'
string(7) "basedir"
string(7) "basedir"
Testing: '///'
string(0) ""
string(1) "/"
Testing: '//'
string(0) ""
string(1) "/"
Testing: '/'
string(0) ""
string(1) "/"
Testing: ''
string(0) ""
string(0) ""