diff --git a/ext/dom/parentnode.c b/ext/dom/parentnode.c
index b7a7cfd07f3..9fdfc7818e8 100644
--- a/ext/dom/parentnode.c
+++ b/ext/dom/parentnode.c
@@ -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);
diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c
index 662c6e9ef7c..00725d3fb00 100644
--- a/ext/dom/php_dom.c
+++ b/ext/dom/php_dom.c
@@ -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;
diff --git a/ext/dom/tests/DOMDocument_getElementsByTagNameNS_match_any_namespace.phpt b/ext/dom/tests/DOMDocument_getElementsByTagNameNS_match_any_namespace.phpt
new file mode 100644
index 00000000000..888d1ef9b80
--- /dev/null
+++ b/ext/dom/tests/DOMDocument_getElementsByTagNameNS_match_any_namespace.phpt
@@ -0,0 +1,82 @@
+--TEST--
+DOMDocument::getElementsByTagNameNS() match any namespace
+--EXTENSIONS--
+dom
+--FILE--
+
+
helloworld
'); + +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('other
'); +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) "helloworld
+" +-- Append hello with world's child -- +string(39) "helloworld
+" +-- Append world's child with hello -- +string(39) "worldhello
+" +-- Append hello with itself -- +Hierarchy Request Error +string(39) "helloworld
+" +-- Append world's i tag with the parent -- +Hierarchy Request Error +string(39) "helloworld
+" +-- Append from another document -- +Wrong Document Error +string(13) "other
+" +string(39) "helloworld
+" diff --git a/ext/dom/tests/DOMElement_prepend_hierarchy_test.phpt b/ext/dom/tests/DOMElement_prepend_hierarchy_test.phpt new file mode 100644 index 00000000000..4d9cf24a618 --- /dev/null +++ b/ext/dom/tests/DOMElement_prepend_hierarchy_test.phpt @@ -0,0 +1,89 @@ +--TEST-- +DOMElement::prepend() with hierarchy changes and errors +--EXTENSIONS-- +dom +--FILE-- +loadXML('helloworld
'); + +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('other
'); +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) "worldhello
+" +-- Prepend hello with world's child -- +string(39) "worldhello
+" +-- Prepend world's child with hello -- +string(39) "helloworld
+" +-- Prepend hello with itself -- +Hierarchy Request Error +string(39) "helloworld
+" +-- Prepend world's i tag with the parent -- +Hierarchy Request Error +string(39) "helloworld
+" +-- Append from another document -- +Wrong Document Error +string(13) "other
+" +string(39) "helloworld
+" diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index 11ab472631b..a4113f954ef 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -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; diff --git a/ext/opcache/zend_shared_alloc.c b/ext/opcache/zend_shared_alloc.c index 87bfa2f71f9..befcbe442ab 100644 --- a/ext/opcache/zend_shared_alloc.c +++ b/ext/opcache/zend_shared_alloc.c @@ -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 diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index 029edcdfb21..378f707f44c 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -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); diff --git a/ext/spl/tests/gh11338.phpt b/ext/spl/tests/gh11338.phpt new file mode 100644 index 00000000000..0a59cea9e74 --- /dev/null +++ b/ext/spl/tests/gh11338.phpt @@ -0,0 +1,47 @@ +--TEST-- +GH-11338 (SplFileInfo empty getBasename with more than on slash) +--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) ""