diff options
-rw-r--r-- | ext/dom/dom_properties.h | 2 | ||||
-rw-r--r-- | ext/dom/nodelist.c | 71 | ||||
-rw-r--r-- | ext/dom/php_dom.c | 84 | ||||
-rw-r--r-- | ext/dom/php_dom.h | 3 | ||||
-rw-r--r-- | ext/dom/tests/bug67949.phpt | 20 |
5 files changed, 152 insertions, 28 deletions
diff --git a/ext/dom/dom_properties.h b/ext/dom/dom_properties.h index a658b1d843..9d82d0e860 100644 --- a/ext/dom/dom_properties.h +++ b/ext/dom/dom_properties.h @@ -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); diff --git a/ext/dom/nodelist.c b/ext/dom/nodelist.c index 1a0c811185..b865740775 100644 --- a/ext/dom/nodelist.c +++ b/ext/dom/nodelist.c @@ -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); } } } diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c index a9621eeb4c..01a0a6c6bb 100644 --- a/ext/dom/php_dom.c +++ b/ext/dom/php_dom.c @@ -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 */ /* diff --git a/ext/dom/php_dom.h b/ext/dom/php_dom.h index f5f0bc6a72..eb35aa015d 100644 --- a/ext/dom/php_dom.h +++ b/ext/dom/php_dom.h @@ -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 index 0000000000..b12dc81d1d --- /dev/null +++ b/ext/dom/tests/bug67949.phpt @@ -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) |