]> granicus.if.org Git - php/commitdiff
DOMNodeList elements are accessible through array notation
authorFlorian MARGAINE <florian@margaine.com>
Fri, 26 Sep 2014 16:25:56 +0000 (18:25 +0200)
committerFlorian MARGAINE <florian@margaine.com>
Fri, 26 Sep 2014 23:27:46 +0000 (01:27 +0200)
Fixes #67949

ext/dom/dom_properties.h
ext/dom/nodelist.c
ext/dom/php_dom.c
ext/dom/php_dom.h
ext/dom/tests/bug67949.phpt [new file with mode: 0644]

index a658b1d843e8cecacd7e3198c70f506a6a7fcbb0..9d82d0e860ac5e0dcf6546e48fc1900efdcb3095 100644 (file)
@@ -137,6 +137,8 @@ int dom_node_text_content_write(dom_object *obj, zval *newval TSRMLS_DC);
 
 /* nodelist properties */
 int dom_nodelist_length_read(dom_object *obj, zval **retval TSRMLS_DC);
+xmlNodePtr dom_nodelist_xml_item(dom_nnodemap_object *objmap, long index);
+xmlNodePtr dom_nodelist_baseobj_item(dom_nnodemap_object *objmap, long index);
 
 /* notation properties */
 int dom_notation_public_id_read(dom_object *obj, zval **retval TSRMLS_DC);
index 1a0c8111853bf880192c6626ed7fb26e84d1fcdf..b8657407758353da182a7ab521b29527ff6b6ccb 100644 (file)
@@ -98,6 +98,47 @@ int dom_nodelist_length_read(dom_object *obj, zval **retval TSRMLS_DC)
 
 /* }}} */
 
+xmlNodePtr dom_nodelist_xml_item(dom_nnodemap_object *objmap, long index) /* {{{ */
+{
+       xmlNodePtr itemnode = NULL;
+
+       if (objmap->nodetype == XML_ENTITY_NODE) {
+               itemnode = php_dom_libxml_hash_iter(objmap->ht, index);
+       } else {
+               itemnode = php_dom_libxml_notation_iter(objmap->ht, index);
+       }
+
+       return itemnode;
+} /* }}} end dom_nodelist_xml_item */
+
+xmlNodePtr dom_nodelist_baseobj_item(dom_nnodemap_object *objmap, long index) /* {{{ */
+{
+       xmlNodePtr itemnode = NULL;
+       xmlNodePtr nodep, curnode;
+       int count = 0;
+
+       nodep = dom_object_get_node(objmap->baseobj);
+       if (nodep) {
+               if (objmap->nodetype == XML_ATTRIBUTE_NODE || objmap->nodetype == XML_ELEMENT_NODE) {
+                       curnode = nodep->children;
+                       while (count < index && curnode != NULL) {
+                               count++;
+                               curnode = curnode->next;
+                       }
+                       itemnode = curnode;
+               } else {
+                       if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
+                               nodep = xmlDocGetRootElement((xmlDoc *) nodep);
+                       } else {
+                               nodep = nodep->children;
+                       }
+                       itemnode = dom_get_elements_by_tag_name_ns_raw(nodep, (char *) objmap->ns, (char *) objmap->local, &count, index);
+               }
+       }
+
+       return itemnode;
+} /* }}} end dom_nodelist_baseobj_item */
+
 /* {{{ proto DOMNode dom_nodelist_item(int index);
 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#ID-844377136
 Since: 
@@ -111,8 +152,6 @@ PHP_FUNCTION(dom_nodelist_item)
        xmlNodePtr itemnode = NULL;
 
        dom_nnodemap_object *objmap;
-       xmlNodePtr nodep, curnode;
-       int count = 0;
        HashTable *nodeht;
        zval **entry;
 
@@ -126,38 +165,16 @@ PHP_FUNCTION(dom_nodelist_item)
                objmap = (dom_nnodemap_object *)intern->ptr;
                if (objmap != NULL) {
                        if (objmap->ht) {
-                               if (objmap->nodetype == XML_ENTITY_NODE) {
-                                       itemnode = php_dom_libxml_hash_iter(objmap->ht, index);
-                               } else {
-                                       itemnode = php_dom_libxml_notation_iter(objmap->ht, index);
-                               }
+                               itemnode = dom_nodelist_xml_item(objmap, index);
                        } else {
                                if (objmap->nodetype == DOM_NODESET) {
                                        nodeht = HASH_OF(objmap->baseobjptr);
                                        if (zend_hash_index_find(nodeht, index, (void **) &entry)==SUCCESS) {
-                                               *return_value = **entry;
-                                               zval_copy_ctor(return_value);
+                                               MAKE_COPY_ZVAL(entry, return_value);
                                                return;
                                        }
                                } else if (objmap->baseobj) {
-                                       nodep = dom_object_get_node(objmap->baseobj);
-                                       if (nodep) {
-                                               if (objmap->nodetype == XML_ATTRIBUTE_NODE || objmap->nodetype == XML_ELEMENT_NODE) {
-                                                       curnode = nodep->children;
-                                                       while (count < index && curnode != NULL) {
-                                                               count++;
-                                                               curnode = curnode->next;
-                                                       }
-                                                       itemnode = curnode;
-                                               } else {
-                                                       if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
-                                                               nodep = xmlDocGetRootElement((xmlDoc *) nodep);
-                                                       } else {
-                                                               nodep = nodep->children;
-                                                       }
-                                                       itemnode = dom_get_elements_by_tag_name_ns_raw(nodep, objmap->ns, objmap->local, &count, index);
-                                               }
-                                       }
+                                       itemnode = dom_nodelist_baseobj_item(objmap, index);
                                }
                        }
                }
index a9621eeb4c5550ee33b80a5631c90eb986b3d423..01a0a6c6bb94a8f666cdb22502fa3b61c0c6945f 100644 (file)
@@ -72,6 +72,7 @@ zend_class_entry *dom_namespace_node_class_entry;
 /* }}} */
 
 zend_object_handlers dom_object_handlers;
+zend_object_handlers dom_nnodemap_object_handlers;
 
 static HashTable classes;
 /* {{{ prop handler tables */
@@ -668,6 +669,10 @@ PHP_MINIT_FUNCTION(dom)
        dom_object_handlers.has_property = dom_property_exists;
        dom_object_handlers.get_debug_info = dom_get_debug_info;
 
+       memcpy(&dom_nnodemap_object_handlers, &dom_object_handlers, sizeof(zend_object_handlers));
+       dom_nnodemap_object_handlers.read_dimension = dom_nodelist_read_dimension;
+       dom_nnodemap_object_handlers.has_dimension = dom_nodelist_has_dimension;
+
        zend_hash_init(&classes, 0, NULL, NULL, 1);
 
        INIT_CLASS_ENTRY(ce, "DOMException", php_dom_domexception_class_functions);
@@ -1297,7 +1302,7 @@ zend_object_value dom_nnodemap_objects_new(zend_class_entry *class_type TSRMLS_D
 
        retval.handle = zend_objects_store_put(intern, dom_nnodemap_object_dtor, (zend_objects_free_object_storage_t)dom_nnodemap_objects_free_storage, dom_objects_clone TSRMLS_CC);
        intern->handle = retval.handle;
-       retval.handlers = dom_get_obj_handlers(TSRMLS_C);
+       retval.handlers = &dom_nnodemap_object_handlers;
 
        return retval;
 }
@@ -1674,6 +1679,83 @@ xmlNsPtr dom_get_nsdecl(xmlNode *node, xmlChar *localName) {
 }
 /* }}} end dom_get_nsdecl */
 
+static int dom_nodelist_fetch_dimension(xmlNodePtr *itemnode, zval *offset, dom_nnodemap_object *objmap, zval *rv TSRMLS_DC) /* {{{ */
+{
+       convert_to_long(offset);
+       long index = Z_LVAL_P(offset);
+       HashTable *nodeht;
+       zval **entry;
+       int ret = 0;
+
+       if (objmap->ht) {
+               *itemnode = dom_nodelist_xml_item(objmap, index);
+       } else {
+               if (objmap->nodetype == DOM_NODESET) {
+                       nodeht = HASH_OF(objmap->baseobjptr);
+                       if (zend_hash_index_find(nodeht, index, (void **) &entry) == SUCCESS) {
+                               if (itemnode != NULL && rv != NULL) {
+                                       /* Passed by read_dimension */
+                                       MAKE_COPY_ZVAL(entry, rv);
+                               }
+                               ret = 1;
+                       }
+               } else if (objmap->baseobj) {
+                       if (itemnode == NULL && rv == NULL) {
+                               /* Passed by has_dimension */
+                               if (dom_nodelist_baseobj_item(objmap, index)) {
+                                       ret = 1;
+                               }
+                       } else {
+                               *itemnode = dom_nodelist_baseobj_item(objmap, index);
+                       }
+               }
+       }
+
+       if (rv != NULL && itemnode != NULL) {
+               if (*itemnode) {
+                       ret = 1;
+               }
+       }
+
+       return ret;
+} /* }}} end dom_nodelist_fetch_dimension */
+
+zval *dom_nodelist_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
+{
+       dom_object *intern;
+       xmlNodePtr itemnode = NULL;
+       dom_nnodemap_object *objmap;
+       zval *rv;
+       int found;
+
+       ALLOC_INIT_ZVAL(rv);
+
+       intern = (dom_object *) zend_object_store_get_object(object TSRMLS_CC);
+
+       objmap = (dom_nnodemap_object *)intern->ptr;
+
+       if (dom_nodelist_fetch_dimension(&itemnode, offset, objmap, rv TSRMLS_CC)) {
+               if (itemnode) {
+                       php_dom_create_object(itemnode, &found, rv, objmap->baseobj TSRMLS_CC);
+               }
+       }
+
+       Z_DELREF_P(rv);
+
+       return rv;
+} /* }}} end dom_nodelist_read_dimension */
+
+int dom_nodelist_has_dimension(zval *object, zval *member, int check_empty TSRMLS_DC)
+{
+       dom_object *intern;
+       dom_nnodemap_object *objmap;
+
+       intern = (dom_object *) zend_object_store_get_object(object TSRMLS_CC);
+       objmap = (dom_nnodemap_object *)intern->ptr;
+
+       return dom_nodelist_fetch_dimension(NULL, member, objmap, NULL TSRMLS_CC);
+} /* }}} end dom_nodelist_has_dimension */
+
 #endif /* HAVE_DOM */
 
 /*
index f5f0bc6a728e80df57ec4fbe5d9d7a403858cc01..eb35aa015d08f6cb6ce2f0d611866f43b9d871bd 100644 (file)
@@ -123,6 +123,9 @@ xmlNode *php_dom_libxml_hash_iter(xmlHashTable *ht, int index);
 xmlNode *php_dom_libxml_notation_iter(xmlHashTable *ht, int index);
 zend_object_iterator *php_dom_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC);
 int dom_set_doc_classmap(php_libxml_ref_obj *document, zend_class_entry *basece, zend_class_entry *ce TSRMLS_DC);
+zval *dom_nodelist_read_dimension(zval *object, zval *offset, int type TSRMLS_DC);
+int dom_nodelist_has_dimension(zval *object, zval *member, int check_empty TSRMLS_DC);
+static int dom_nodelist_fetch_dimension(xmlNodePtr *itemnode, zval *offset, dom_nnodemap_object *objmap, zval *rv TSRMLS_DC);
 
 #define REGISTER_DOM_CLASS(ce, name, parent_ce, funcs, entry) \
 INIT_CLASS_ENTRY(ce, name, funcs); \
diff --git a/ext/dom/tests/bug67949.phpt b/ext/dom/tests/bug67949.phpt
new file mode 100644 (file)
index 0000000..b12dc81
--- /dev/null
@@ -0,0 +1,20 @@
+--TEST--
+Bug #67949: DOMNodeList elements should be accessible through array notation
+--FILE--
+<?php
+
+$html = <<<HTML
+<div>data</div>
+HTML;
+$doc = new DOMDocument;
+$doc->loadHTML($html);
+var_dump($doc->getElementsByTagName('div')[0]->textContent);
+var_dump($doc->getElementsByTagName('div')['test']->textContent); // testing that weak casting works
+var_dump(isset($doc->getElementsByTagName('div')[0]));
+var_dump(isset($doc->getElementsByTagName('div')[1]));
+
+--EXPECT--
+string(4) "data"
+string(4) "data"
+bool(true)
+bool(false)