1/* 2 +----------------------------------------------------------------------+ 3 | PHP Version 5 | 4 +----------------------------------------------------------------------+ 5 | Copyright (c) 1997-2013 The PHP Group | 6 +----------------------------------------------------------------------+ 7 | This source file is subject to version 3.01 of the PHP license, | 8 | that is bundled with this package in the file LICENSE, and is | 9 | available through the world-wide-web at the following url: | 10 | http://www.php.net/license/3_01.txt | 11 | If you did not receive a copy of the PHP license and are unable to | 12 | obtain it through the world-wide-web, please send a note to | 13 | license@php.net so we can mail you a copy immediately. | 14 +----------------------------------------------------------------------+ 15 | Authors: Sterling Hughes <sterling@php.net> | 16 | Marcus Boerger <helly@php.net> | 17 | Rob Richards <rrichards@php.net> | 18 +----------------------------------------------------------------------+ 19*/ 20 21/* $Id: 692516840b2d7d6e7aedb0bedded1f53b764a99f $ */ 22 23#ifdef HAVE_CONFIG_H 24#include "config.h" 25#endif 26 27#include "php.h" 28#if HAVE_LIBXML && HAVE_SIMPLEXML 29 30#include "php_ini.h" 31#include "ext/standard/info.h" 32#include "ext/standard/php_string.h" 33#include "php_simplexml.h" 34#include "php_simplexml_exports.h" 35#include "zend_exceptions.h" 36#include "zend_interfaces.h" 37#include "sxe.h" 38 39#define SXE_ELEMENT_BY_NAME 0 40 41zend_class_entry *sxe_class_entry = NULL; 42 43PHP_SXE_API zend_class_entry *sxe_get_element_class_entry() /* {{{ */ 44{ 45 return sxe_class_entry; 46} 47/* }}} */ 48 49#define SXE_ME(func, arg_info, flags) PHP_ME(simplexml_element, func, arg_info, flags) 50#define SXE_MALIAS(func, alias, arg_info, flags) PHP_MALIAS(simplexml_element, func, alias, arg_info, flags) 51 52#define SXE_METHOD(func) PHP_METHOD(simplexml_element, func) 53 54static php_sxe_object* php_sxe_object_new(zend_class_entry *ce TSRMLS_DC); 55static zend_object_value php_sxe_register_object(php_sxe_object * TSRMLS_DC); 56static xmlNodePtr php_sxe_reset_iterator(php_sxe_object *sxe, int use_data TSRMLS_DC); 57static xmlNodePtr php_sxe_iterator_fetch(php_sxe_object *sxe, xmlNodePtr node, int use_data TSRMLS_DC); 58static zval *sxe_get_value(zval *z TSRMLS_DC); 59static void php_sxe_iterator_dtor(zend_object_iterator *iter TSRMLS_DC); 60static int php_sxe_iterator_valid(zend_object_iterator *iter TSRMLS_DC); 61static void php_sxe_iterator_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC); 62static int php_sxe_iterator_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC); 63static void php_sxe_iterator_move_forward(zend_object_iterator *iter TSRMLS_DC); 64static void php_sxe_iterator_rewind(zend_object_iterator *iter TSRMLS_DC); 65 66/* {{{ _node_as_zval() 67 */ 68static void _node_as_zval(php_sxe_object *sxe, xmlNodePtr node, zval *value, SXE_ITER itertype, char *name, const xmlChar *nsprefix, int isprefix TSRMLS_DC) 69{ 70 php_sxe_object *subnode; 71 72 subnode = php_sxe_object_new(sxe->zo.ce TSRMLS_CC); 73 subnode->document = sxe->document; 74 subnode->document->refcount++; 75 subnode->iter.type = itertype; 76 if (name) { 77 subnode->iter.name = xmlStrdup((xmlChar *)name); 78 } 79 if (nsprefix && *nsprefix) { 80 subnode->iter.nsprefix = xmlStrdup(nsprefix); 81 subnode->iter.isprefix = isprefix; 82 } 83 84 php_libxml_increment_node_ptr((php_libxml_node_object *)subnode, node, NULL TSRMLS_CC); 85 86 value->type = IS_OBJECT; 87 value->value.obj = php_sxe_register_object(subnode TSRMLS_CC); 88} 89/* }}} */ 90 91#define APPEND_PREV_ELEMENT(__c, __v) \ 92 if ((__c) == 1) { \ 93 array_init(return_value); \ 94 add_next_index_zval(return_value, __v); \ 95 } 96 97#define APPEND_CUR_ELEMENT(__c, __v) \ 98 if (++(__c) > 1) { \ 99 add_next_index_zval(return_value, __v); \ 100 } 101 102#define GET_NODE(__s, __n) { \ 103 if ((__s)->node && (__s)->node->node) { \ 104 __n = (__s)->node->node; \ 105 } else { \ 106 __n = NULL; \ 107 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Node no longer exists"); \ 108 } \ 109} 110 111static xmlNodePtr php_sxe_get_first_node(php_sxe_object *sxe, xmlNodePtr node TSRMLS_DC) /* {{{ */ 112{ 113 php_sxe_object *intern; 114 xmlNodePtr retnode = NULL; 115 116 if (sxe && sxe->iter.type != SXE_ITER_NONE) { 117 php_sxe_reset_iterator(sxe, 1 TSRMLS_CC); 118 if (sxe->iter.data) { 119 intern = (php_sxe_object *)zend_object_store_get_object(sxe->iter.data TSRMLS_CC); 120 GET_NODE(intern, retnode) 121 } 122 return retnode; 123 } else { 124 return node; 125 } 126} 127/* }}} */ 128 129static inline int match_ns(php_sxe_object *sxe, xmlNodePtr node, xmlChar *name, int prefix) /* {{{ */ 130{ 131 if (name == NULL && (node->ns == NULL || node->ns->prefix == NULL)) { 132 return 1; 133 } 134 135 if (node->ns && !xmlStrcmp(prefix ? node->ns->prefix : node->ns->href, name)) { 136 return 1; 137 } 138 139 return 0; 140} 141/* }}} */ 142 143static xmlNodePtr sxe_get_element_by_offset(php_sxe_object *sxe, long offset, xmlNodePtr node, long *cnt) /* {{{ */ 144{ 145 long nodendx = 0; 146 147 if (sxe->iter.type == SXE_ITER_NONE) { 148 if (offset == 0) { 149 if (cnt) { 150 *cnt = 0; 151 } 152 return node; 153 } else { 154 return NULL; 155 } 156 } 157 while (node && nodendx <= offset) { 158 SKIP_TEXT(node) 159 if (node->type == XML_ELEMENT_NODE && match_ns(sxe, node, sxe->iter.nsprefix, sxe->iter.isprefix)) { 160 if (sxe->iter.type == SXE_ITER_CHILD || ( 161 sxe->iter.type == SXE_ITER_ELEMENT && !xmlStrcmp(node->name, sxe->iter.name))) { 162 if (nodendx == offset) { 163 break; 164 } 165 nodendx++; 166 } 167 } 168next_iter: 169 node = node->next; 170 } 171 172 if (cnt) { 173 *cnt = nodendx; 174 } 175 176 return node; 177} 178/* }}} */ 179 180static xmlNodePtr sxe_find_element_by_name(php_sxe_object *sxe, xmlNodePtr node, xmlChar *name TSRMLS_DC) /* {{{ */ 181{ 182 while (node) { 183 SKIP_TEXT(node) 184 if (node->type == XML_ELEMENT_NODE && match_ns(sxe, node, sxe->iter.nsprefix, sxe->iter.isprefix)) { 185 if (!xmlStrcmp(node->name, name)) { 186 return node; 187 } 188 } 189next_iter: 190 node = node->next; 191 } 192 return NULL; 193} /* }}} */ 194 195static xmlNodePtr sxe_get_element_by_name(php_sxe_object *sxe, xmlNodePtr node, char **name, SXE_ITER *type TSRMLS_DC) /* {{{ */ 196{ 197 int orgtype; 198 xmlNodePtr orgnode = node; 199 xmlNodePtr retnode = NULL; 200 201 if (sxe->iter.type != SXE_ITER_ATTRLIST) 202 { 203 orgtype = sxe->iter.type; 204 if (sxe->iter.type == SXE_ITER_NONE) { 205 sxe->iter.type = SXE_ITER_CHILD; 206 } 207 node = php_sxe_get_first_node(sxe, node TSRMLS_CC); 208 sxe->iter.type = orgtype; 209 } 210 211 if (sxe->iter.type == SXE_ITER_ELEMENT) { 212 orgnode = sxe_find_element_by_name(sxe, node, sxe->iter.name TSRMLS_CC); 213 if (!orgnode) { 214 return NULL; 215 } 216 node = orgnode->children; 217 } 218 219 while (node) { 220 SKIP_TEXT(node) 221 if (node->type == XML_ELEMENT_NODE && match_ns(sxe, node, sxe->iter.nsprefix, sxe->iter.isprefix)) { 222 if (!xmlStrcmp(node->name, (xmlChar *)*name)) { 223 if (1||retnode) 224 { 225 *type = SXE_ITER_ELEMENT; 226 return orgnode; 227 } 228 retnode = node; 229 } 230 } 231next_iter: 232 node = node->next; 233 } 234 235 if (retnode) 236 { 237 *type = SXE_ITER_NONE; 238 *name = NULL; 239 return retnode; 240 } 241 242 return NULL; 243} 244/* }}} */ 245 246/* {{{ sxe_prop_dim_read() 247 */ 248static zval * sxe_prop_dim_read(zval *object, zval *member, zend_bool elements, zend_bool attribs, int type TSRMLS_DC) 249{ 250 zval *return_value; 251 php_sxe_object *sxe; 252 char *name; 253 xmlNodePtr node; 254 xmlAttrPtr attr = NULL; 255 zval tmp_zv; 256 int nodendx = 0; 257 int test = 0; 258 259 sxe = php_sxe_fetch_object(object TSRMLS_CC); 260 261 if (!member || Z_TYPE_P(member) == IS_LONG) { 262 if (sxe->iter.type != SXE_ITER_ATTRLIST) { 263 attribs = 0; 264 elements = 1; 265 } else if (!member) { 266 /* This happens when the user did: $sxe[]->foo = $value */ 267 php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot create unnamed attribute"); 268 return NULL; 269 } 270 name = NULL; 271 } else { 272 if (Z_TYPE_P(member) != IS_STRING) { 273 tmp_zv = *member; 274 zval_copy_ctor(&tmp_zv); 275 member = &tmp_zv; 276 convert_to_string(member); 277 } 278 name = Z_STRVAL_P(member); 279 } 280 281 GET_NODE(sxe, node); 282 283 if (sxe->iter.type == SXE_ITER_ATTRLIST) { 284 attribs = 1; 285 elements = 0; 286 node = php_sxe_get_first_node(sxe, node TSRMLS_CC); 287 attr = (xmlAttrPtr)node; 288 test = sxe->iter.name != NULL; 289 } else if (sxe->iter.type != SXE_ITER_CHILD) { 290 node = php_sxe_get_first_node(sxe, node TSRMLS_CC); 291 attr = node ? node->properties : NULL; 292 test = 0; 293 if (!member && node && node->parent && 294 node->parent->type == XML_DOCUMENT_NODE) { 295 /* This happens when the user did: $sxe[]->foo = $value */ 296 php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot create unnamed attribute"); 297 return NULL; 298 } 299 } 300 301 MAKE_STD_ZVAL(return_value); 302 ZVAL_NULL(return_value); 303 304 if (node) { 305 if (attribs) { 306 if (Z_TYPE_P(member) != IS_LONG || sxe->iter.type == SXE_ITER_ATTRLIST) { 307 if (Z_TYPE_P(member) == IS_LONG) { 308 while (attr && nodendx <= Z_LVAL_P(member)) { 309 if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) { 310 if (nodendx == Z_LVAL_P(member)) { 311 _node_as_zval(sxe, (xmlNodePtr) attr, return_value, SXE_ITER_NONE, NULL, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC); 312 break; 313 } 314 nodendx++; 315 } 316 attr = attr->next; 317 } 318 } else { 319 while (attr) { 320 if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && !xmlStrcmp(attr->name, (xmlChar *)name) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) { 321 _node_as_zval(sxe, (xmlNodePtr) attr, return_value, SXE_ITER_NONE, NULL, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC); 322 break; 323 } 324 attr = attr->next; 325 } 326 } 327 } 328 } 329 330 if (elements) { 331 if (!sxe->node) { 332 php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, node, NULL TSRMLS_CC); 333 } 334 if (!member || Z_TYPE_P(member) == IS_LONG) { 335 long cnt = 0; 336 xmlNodePtr mynode = node; 337 338 if (sxe->iter.type == SXE_ITER_CHILD) { 339 node = php_sxe_get_first_node(sxe, node TSRMLS_CC); 340 } 341 if (sxe->iter.type == SXE_ITER_NONE) { 342 if (member && Z_LVAL_P(member) > 0) { 343 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element %s number %ld when only 0 such elements exist", mynode->name, Z_LVAL_P(member)); 344 } 345 } else if (member) { 346 node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, &cnt); 347 } else { 348 node = NULL; 349 } 350 if (node) { 351 _node_as_zval(sxe, node, return_value, SXE_ITER_NONE, NULL, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC); 352 } else if (type == BP_VAR_W || type == BP_VAR_RW) { 353 if (member && cnt < Z_LVAL_P(member)) { 354 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element %s number %ld when only %ld such elements exist", mynode->name, Z_LVAL_P(member), cnt); 355 } 356 node = xmlNewTextChild(mynode->parent, mynode->ns, mynode->name, NULL); 357 _node_as_zval(sxe, node, return_value, SXE_ITER_NONE, NULL, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC); 358 } 359 } else { 360#if SXE_ELEMENT_BY_NAME 361 int newtype; 362 363 GET_NODE(sxe, node); 364 node = sxe_get_element_by_name(sxe, node, &name, &newtype TSRMLS_CC); 365 if (node) { 366 _node_as_zval(sxe, node, return_value, newtype, name, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC); 367 } 368#else 369 _node_as_zval(sxe, node, return_value, SXE_ITER_ELEMENT, name, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC); 370#endif 371 } 372 } 373 } 374 375 Z_SET_REFCOUNT_P(return_value, 0); 376 Z_UNSET_ISREF_P(return_value); 377 378 if (member == &tmp_zv) { 379 zval_dtor(&tmp_zv); 380 } 381 if (Z_TYPE_P(return_value) == IS_NULL) { 382 FREE_ZVAL(return_value); 383 return_value = &EG(uninitialized_zval); 384 } 385 386 return return_value; 387} 388/* }}} */ 389 390/* {{{ sxe_property_read() 391 */ 392static zval * sxe_property_read(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) 393{ 394 return sxe_prop_dim_read(object, member, 1, 0, type TSRMLS_CC); 395} 396/* }}} */ 397 398/* {{{ sxe_dimension_read() 399 */ 400static zval * sxe_dimension_read(zval *object, zval *offset, int type TSRMLS_DC) 401{ 402 return sxe_prop_dim_read(object, offset, 0, 1, type TSRMLS_CC); 403} 404/* }}} */ 405 406/* {{{ change_node_zval() 407 */ 408static void change_node_zval(xmlNodePtr node, zval *value TSRMLS_DC) 409{ 410 zval value_copy; 411 xmlChar *buffer; 412 int buffer_len; 413 414 if (!value) 415 { 416 xmlNodeSetContentLen(node, (xmlChar *)"", 0); 417 return; 418 } 419 switch (Z_TYPE_P(value)) { 420 case IS_LONG: 421 case IS_BOOL: 422 case IS_DOUBLE: 423 case IS_NULL: 424 if (Z_REFCOUNT_P(value) > 1) { 425 value_copy = *value; 426 zval_copy_ctor(&value_copy); 427 value = &value_copy; 428 } 429 convert_to_string(value); 430 /* break missing intentionally */ 431 case IS_STRING: 432 buffer = xmlEncodeEntitiesReentrant(node->doc, (xmlChar *)Z_STRVAL_P(value)); 433 buffer_len = xmlStrlen(buffer); 434 /* check for NULL buffer in case of memory error in xmlEncodeEntitiesReentrant */ 435 if (buffer) { 436 xmlNodeSetContentLen(node, buffer, buffer_len); 437 xmlFree(buffer); 438 } 439 if (value == &value_copy) { 440 zval_dtor(value); 441 } 442 break; 443 default: 444 php_error_docref(NULL TSRMLS_CC, E_WARNING, "It is not possible to assign complex types to nodes"); 445 break; 446 } 447} 448/* }}} */ 449 450/* {{{ sxe_property_write() 451 */ 452static int sxe_prop_dim_write(zval *object, zval *member, zval *value, zend_bool elements, zend_bool attribs, xmlNodePtr *pnewnode TSRMLS_DC) 453{ 454 php_sxe_object *sxe; 455 xmlNodePtr node; 456 xmlNodePtr newnode = NULL; 457 xmlNodePtr mynode; 458 xmlNodePtr tempnode; 459 xmlAttrPtr attr = NULL; 460 int counter = 0; 461 int is_attr = 0; 462 int nodendx = 0; 463 int test = 0; 464 int new_value = 0; 465 long cnt = 0; 466 int retval = SUCCESS; 467 zval tmp_zv, trim_zv, value_copy; 468 469 sxe = php_sxe_fetch_object(object TSRMLS_CC); 470 471 if (!member || Z_TYPE_P(member) == IS_LONG) { 472 if (sxe->iter.type != SXE_ITER_ATTRLIST) { 473 attribs = 0; 474 elements = 1; 475 } else if (!member) { 476 /* This happens when the user did: $sxe[] = $value 477 * and could also be E_PARSE, but we use this only during parsing 478 * and this is during runtime. 479 */ 480 php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot create unnamed attribute"); 481 return FAILURE; 482 } 483 } else { 484 if (Z_TYPE_P(member) != IS_STRING) { 485 trim_zv = *member; 486 zval_copy_ctor(&trim_zv); 487 convert_to_string(&trim_zv); 488 php_trim(Z_STRVAL(trim_zv), Z_STRLEN(trim_zv), NULL, 0, &tmp_zv, 3 TSRMLS_CC); 489 zval_dtor(&trim_zv); 490 member = &tmp_zv; 491 } 492 493 if (!Z_STRLEN_P(member)) { 494 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot write or create unnamed %s", attribs ? "attribute" : "element"); 495 if (member == &tmp_zv) { 496 zval_dtor(&tmp_zv); 497 } 498 return FAILURE; 499 } 500 } 501 502 GET_NODE(sxe, node); 503 504 if (sxe->iter.type == SXE_ITER_ATTRLIST) { 505 attribs = 1; 506 elements = 0; 507 node = php_sxe_get_first_node(sxe, node TSRMLS_CC); 508 attr = (xmlAttrPtr)node; 509 test = sxe->iter.name != NULL; 510 } else if (sxe->iter.type != SXE_ITER_CHILD) { 511 mynode = node; 512 node = php_sxe_get_first_node(sxe, node TSRMLS_CC); 513 attr = node ? node->properties : NULL; 514 test = 0; 515 if (!member && node && node->parent && 516 node->parent->type == XML_DOCUMENT_NODE) { 517 /* This happens when the user did: $sxe[] = $value 518 * and could also be E_PARSE, but we use this only during parsing 519 * and this is during runtime. 520 */ 521 php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot create unnamed attribute"); 522 return FAILURE; 523 } 524 if (attribs && !node && sxe->iter.type == SXE_ITER_ELEMENT) { 525 node = xmlNewChild(mynode, mynode->ns, sxe->iter.name, NULL); 526 attr = node->properties; 527 } 528 } 529 530 mynode = node; 531 532 if (value) { 533 switch (Z_TYPE_P(value)) { 534 case IS_LONG: 535 case IS_BOOL: 536 case IS_DOUBLE: 537 case IS_NULL: 538 if (Z_REFCOUNT_P(value) > 1) { 539 value_copy = *value; 540 zval_copy_ctor(&value_copy); 541 value = &value_copy; 542 } 543 convert_to_string(value); 544 break; 545 case IS_STRING: 546 break; 547 case IS_OBJECT: 548 if (Z_OBJCE_P(value) == sxe_class_entry) { 549 value = sxe_get_value(value TSRMLS_CC); 550 INIT_PZVAL(value); 551 new_value = 1; 552 break; 553 } 554 /* break is missing intentionally */ 555 default: 556 if (member == &tmp_zv) { 557 zval_dtor(&tmp_zv); 558 } 559 zend_error(E_WARNING, "It is not yet possible to assign complex types to %s", attribs ? "attributes" : "properties"); 560 return FAILURE; 561 } 562 } 563 564 if (node) { 565 if (attribs) { 566 if (Z_TYPE_P(member) == IS_LONG) { 567 while (attr && nodendx <= Z_LVAL_P(member)) { 568 if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) { 569 if (nodendx == Z_LVAL_P(member)) { 570 is_attr = 1; 571 ++counter; 572 break; 573 } 574 nodendx++; 575 } 576 attr = attr->next; 577 } 578 } else { 579 while (attr) { 580 if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && !xmlStrcmp(attr->name, (xmlChar *)Z_STRVAL_P(member)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) { 581 is_attr = 1; 582 ++counter; 583 break; 584 } 585 attr = attr->next; 586 } 587 } 588 589 } 590 591 if (elements) { 592 if (!member || Z_TYPE_P(member) == IS_LONG) { 593 if (node->type == XML_ATTRIBUTE_NODE) { 594 php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot create duplicate attribute"); 595 return FAILURE; 596 } 597 598 if (sxe->iter.type == SXE_ITER_NONE) { 599 newnode = node; 600 ++counter; 601 if (member && Z_LVAL_P(member) > 0) { 602 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element %s number %ld when only 0 such elements exist", mynode->name, Z_LVAL_P(member)); 603 retval = FAILURE; 604 } 605 } else if (member) { 606 newnode = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, &cnt); 607 if (newnode) { 608 ++counter; 609 } 610 } 611 } else { 612 node = node->children; 613 while (node) { 614 SKIP_TEXT(node); 615 616 if (!xmlStrcmp(node->name, (xmlChar *)Z_STRVAL_P(member))) { 617 newnode = node; 618 ++counter; 619 } 620 621next_iter: 622 node = node->next; 623 } 624 } 625 } 626 627 if (counter == 1) { 628 if (is_attr) { 629 newnode = (xmlNodePtr) attr; 630 } 631 if (value) { 632 while ((tempnode = (xmlNodePtr) newnode->children)) { 633 xmlUnlinkNode(tempnode); 634 php_libxml_node_free_resource((xmlNodePtr) tempnode TSRMLS_CC); 635 } 636 change_node_zval(newnode, value TSRMLS_CC); 637 } 638 } else if (counter > 1) { 639 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot assign to an array of nodes (duplicate subnodes or attr detected)"); 640 retval = FAILURE; 641 } else if (elements) { 642 if (!node) { 643 if (!member || Z_TYPE_P(member) == IS_LONG) { 644 newnode = xmlNewTextChild(mynode->parent, mynode->ns, mynode->name, value ? (xmlChar *)Z_STRVAL_P(value) : NULL); 645 } else { 646 newnode = xmlNewTextChild(mynode, mynode->ns, (xmlChar *)Z_STRVAL_P(member), value ? (xmlChar *)Z_STRVAL_P(value) : NULL); 647 } 648 } else if (!member || Z_TYPE_P(member) == IS_LONG) { 649 if (member && cnt < Z_LVAL_P(member)) { 650 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element %s number %ld when only %ld such elements exist", mynode->name, Z_LVAL_P(member), cnt); 651 retval = FAILURE; 652 } 653 newnode = xmlNewTextChild(mynode->parent, mynode->ns, mynode->name, value ? (xmlChar *)Z_STRVAL_P(value) : NULL); 654 } 655 } else if (attribs) { 656 if (Z_TYPE_P(member) == IS_LONG) { 657 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot change attribute number %ld when only %d attributes exist", Z_LVAL_P(member), nodendx); 658 retval = FAILURE; 659 } else { 660 newnode = (xmlNodePtr)xmlNewProp(node, (xmlChar *)Z_STRVAL_P(member), value ? (xmlChar *)Z_STRVAL_P(value) : NULL); 661 } 662 } 663 } 664 665 if (member == &tmp_zv) { 666 zval_dtor(&tmp_zv); 667 } 668 if (pnewnode) { 669 *pnewnode = newnode; 670 } 671 if (value && value == &value_copy) { 672 zval_dtor(value); 673 } 674 if (new_value) { 675 zval_ptr_dtor(&value); 676 } 677 return retval; 678} 679/* }}} */ 680 681/* {{{ sxe_property_write() 682 */ 683static void sxe_property_write(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) 684{ 685 sxe_prop_dim_write(object, member, value, 1, 0, NULL TSRMLS_CC); 686} 687/* }}} */ 688 689/* {{{ sxe_dimension_write() 690 */ 691static void sxe_dimension_write(zval *object, zval *offset, zval *value TSRMLS_DC) 692{ 693 sxe_prop_dim_write(object, offset, value, 0, 1, NULL TSRMLS_CC); 694} 695/* }}} */ 696 697static zval** sxe_property_get_adr(zval *object, zval *member, const zend_literal *key TSRMLS_DC) /* {{{ */ 698{ 699 php_sxe_object *sxe; 700 xmlNodePtr node; 701 zval *return_value; 702 char *name; 703 SXE_ITER type; 704 705 sxe = php_sxe_fetch_object(object TSRMLS_CC); 706 707 GET_NODE(sxe, node); 708 convert_to_string(member); 709 name = Z_STRVAL_P(member); 710 node = sxe_get_element_by_name(sxe, node, &name, &type TSRMLS_CC); 711 if (node) { 712 return NULL; 713 } 714 if (sxe_prop_dim_write(object, member, NULL, 1, 0, &node TSRMLS_CC) != SUCCESS) { 715 return NULL; 716 } 717 type = SXE_ITER_NONE; 718 name = NULL; 719 720 MAKE_STD_ZVAL(return_value); 721 _node_as_zval(sxe, node, return_value, type, name, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC); 722 723 sxe = php_sxe_fetch_object(return_value TSRMLS_CC); 724 if (sxe->tmp) { 725 zval_ptr_dtor(&sxe->tmp); 726 } 727 sxe->tmp = return_value; 728 Z_SET_ISREF_P(return_value); 729 730 return &sxe->tmp; 731} 732/* }}} */ 733 734/* {{{ sxe_prop_dim_exists() 735 */ 736static int sxe_prop_dim_exists(zval *object, zval *member, int check_empty, zend_bool elements, zend_bool attribs TSRMLS_DC) 737{ 738 php_sxe_object *sxe; 739 xmlNodePtr node; 740 xmlAttrPtr attr = NULL; 741 int exists = 0; 742 int test = 0; 743 zval tmp_zv; 744 745 if (Z_TYPE_P(member) != IS_STRING && Z_TYPE_P(member) != IS_LONG) { 746 tmp_zv = *member; 747 zval_copy_ctor(&tmp_zv); 748 member = &tmp_zv; 749 convert_to_string(member); 750 } 751 752 sxe = php_sxe_fetch_object(object TSRMLS_CC); 753 754 GET_NODE(sxe, node); 755 756 if (Z_TYPE_P(member) == IS_LONG) { 757 if (sxe->iter.type != SXE_ITER_ATTRLIST) { 758 attribs = 0; 759 elements = 1; 760 if (sxe->iter.type == SXE_ITER_CHILD) { 761 node = php_sxe_get_first_node(sxe, node TSRMLS_CC); 762 } 763 } 764 } 765 766 if (sxe->iter.type == SXE_ITER_ATTRLIST) { 767 attribs = 1; 768 elements = 0; 769 node = php_sxe_get_first_node(sxe, node TSRMLS_CC); 770 attr = (xmlAttrPtr)node; 771 test = sxe->iter.name != NULL; 772 } else if (sxe->iter.type != SXE_ITER_CHILD) { 773 node = php_sxe_get_first_node(sxe, node TSRMLS_CC); 774 attr = node ? node->properties : NULL; 775 test = 0; 776 } 777 778 if (node) { 779 if (attribs) { 780 if (Z_TYPE_P(member) == IS_LONG) { 781 int nodendx = 0; 782 783 while (attr && nodendx <= Z_LVAL_P(member)) { 784 if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) { 785 if (nodendx == Z_LVAL_P(member)) { 786 exists = 1; 787 break; 788 } 789 nodendx++; 790 } 791 attr = attr->next; 792 } 793 } else { 794 while (attr) { 795 if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && !xmlStrcmp(attr->name, (xmlChar *)Z_STRVAL_P(member)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) { 796 exists = 1; 797 break; 798 } 799 800 attr = attr->next; 801 } 802 } 803 if (exists && check_empty == 1 && 804 (!attr->children || !attr->children->content || !attr->children->content[0] || !xmlStrcmp(attr->children->content, "0")) ) { 805 /* Attribute with no content in it's text node */ 806 exists = 0; 807 } 808 } 809 810 if (elements) { 811 if (Z_TYPE_P(member) == IS_LONG) { 812 if (sxe->iter.type == SXE_ITER_CHILD) { 813 node = php_sxe_get_first_node(sxe, node TSRMLS_CC); 814 } 815 node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, NULL); 816 } 817 else { 818 node = node->children; 819 while (node) { 820 xmlNodePtr nnext; 821 nnext = node->next; 822 if ((node->type == XML_ELEMENT_NODE) && !xmlStrcmp(node->name, (xmlChar *)Z_STRVAL_P(member))) { 823 break; 824 } 825 node = nnext; 826 } 827 } 828 if (node) { 829 exists = 1; 830 if (check_empty == 1 && 831 (!node->children || (node->children->type == XML_TEXT_NODE && !node->children->next && 832 (!node->children->content || !node->children->content[0] || !xmlStrcmp(node->children->content, "0")))) ) { 833 exists = 0; 834 } 835 } 836 } 837 } 838 839 if (member == &tmp_zv) { 840 zval_dtor(&tmp_zv); 841 } 842 843 return exists; 844} 845/* }}} */ 846 847/* {{{ sxe_property_exists() 848 */ 849static int sxe_property_exists(zval *object, zval *member, int check_empty, const zend_literal *key TSRMLS_DC) 850{ 851 return sxe_prop_dim_exists(object, member, check_empty, 1, 0 TSRMLS_CC); 852} 853/* }}} */ 854 855/* {{{ sxe_property_exists() 856 */ 857static int sxe_dimension_exists(zval *object, zval *member, int check_empty TSRMLS_DC) 858{ 859 return sxe_prop_dim_exists(object, member, check_empty, 0, 1 TSRMLS_CC); 860} 861/* }}} */ 862 863/* {{{ sxe_prop_dim_delete() 864 */ 865static void sxe_prop_dim_delete(zval *object, zval *member, zend_bool elements, zend_bool attribs TSRMLS_DC) 866{ 867 php_sxe_object *sxe; 868 xmlNodePtr node; 869 xmlNodePtr nnext; 870 xmlAttrPtr attr = NULL; 871 xmlAttrPtr anext; 872 zval tmp_zv; 873 int test = 0; 874 875 if (Z_TYPE_P(member) != IS_STRING && Z_TYPE_P(member) != IS_LONG) { 876 tmp_zv = *member; 877 zval_copy_ctor(&tmp_zv); 878 member = &tmp_zv; 879 convert_to_string(member); 880 } 881 882 sxe = php_sxe_fetch_object(object TSRMLS_CC); 883 884 GET_NODE(sxe, node); 885 886 if (Z_TYPE_P(member) == IS_LONG) { 887 if (sxe->iter.type != SXE_ITER_ATTRLIST) { 888 attribs = 0; 889 elements = 1; 890 if (sxe->iter.type == SXE_ITER_CHILD) { 891 node = php_sxe_get_first_node(sxe, node TSRMLS_CC); 892 } 893 } 894 } 895 896 if (sxe->iter.type == SXE_ITER_ATTRLIST) { 897 attribs = 1; 898 elements = 0; 899 node = php_sxe_get_first_node(sxe, node TSRMLS_CC); 900 attr = (xmlAttrPtr)node; 901 test = sxe->iter.name != NULL; 902 } else if (sxe->iter.type != SXE_ITER_CHILD) { 903 node = php_sxe_get_first_node(sxe, node TSRMLS_CC); 904 attr = node ? node->properties : NULL; 905 test = 0; 906 } 907 908 if (node) { 909 if (attribs) { 910 if (Z_TYPE_P(member) == IS_LONG) { 911 int nodendx = 0; 912 913 while (attr && nodendx <= Z_LVAL_P(member)) { 914 if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) { 915 if (nodendx == Z_LVAL_P(member)) { 916 xmlUnlinkNode((xmlNodePtr) attr); 917 php_libxml_node_free_resource((xmlNodePtr) attr TSRMLS_CC); 918 break; 919 } 920 nodendx++; 921 } 922 attr = attr->next; 923 } 924 } else { 925 while (attr) { 926 anext = attr->next; 927 if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && !xmlStrcmp(attr->name, (xmlChar *)Z_STRVAL_P(member)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix, sxe->iter.isprefix)) { 928 xmlUnlinkNode((xmlNodePtr) attr); 929 php_libxml_node_free_resource((xmlNodePtr) attr TSRMLS_CC); 930 break; 931 } 932 attr = anext; 933 } 934 } 935 } 936 937 if (elements) { 938 if (Z_TYPE_P(member) == IS_LONG) { 939 if (sxe->iter.type == SXE_ITER_CHILD) { 940 node = php_sxe_get_first_node(sxe, node TSRMLS_CC); 941 } 942 node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, NULL); 943 if (node) { 944 xmlUnlinkNode(node); 945 php_libxml_node_free_resource(node TSRMLS_CC); 946 } 947 } else { 948 node = node->children; 949 while (node) { 950 nnext = node->next; 951 952 SKIP_TEXT(node); 953 954 if (!xmlStrcmp(node->name, (xmlChar *)Z_STRVAL_P(member))) { 955 xmlUnlinkNode(node); 956 php_libxml_node_free_resource(node TSRMLS_CC); 957 } 958 959next_iter: 960 node = nnext; 961 } 962 } 963 } 964 } 965 966 if (member == &tmp_zv) { 967 zval_dtor(&tmp_zv); 968 } 969} 970/* }}} */ 971 972/* {{{ sxe_property_delete() 973 */ 974static void sxe_property_delete(zval *object, zval *member, const zend_literal *key TSRMLS_DC) 975{ 976 sxe_prop_dim_delete(object, member, 1, 0 TSRMLS_CC); 977} 978/* }}} */ 979 980/* {{{ sxe_dimension_unset() 981 */ 982static void sxe_dimension_delete(zval *object, zval *offset TSRMLS_DC) 983{ 984 sxe_prop_dim_delete(object, offset, 0, 1 TSRMLS_CC); 985} 986/* }}} */ 987 988static inline char * sxe_xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) /* {{{ */ 989{ 990 xmlChar *tmp = xmlNodeListGetString(doc, list, inLine); 991 char *res; 992 993 if (tmp) { 994 res = estrdup((char*)tmp); 995 xmlFree(tmp); 996 } else { 997 res = STR_EMPTY_ALLOC(); 998 } 999 1000 return res; 1001} 1002/* }}} */ 1003 1004/* {{{ _get_base_node_value() 1005 */ 1006static void _get_base_node_value(php_sxe_object *sxe_ref, xmlNodePtr node, zval **value, xmlChar *nsprefix, int isprefix TSRMLS_DC) 1007{ 1008 php_sxe_object *subnode; 1009 xmlChar *contents; 1010 1011 MAKE_STD_ZVAL(*value); 1012 1013 if (node->children && node->children->type == XML_TEXT_NODE && !xmlIsBlankNode(node->children)) { 1014 contents = xmlNodeListGetString(node->doc, node->children, 1); 1015 if (contents) { 1016 ZVAL_STRING(*value, (char *)contents, 1); 1017 xmlFree(contents); 1018 } 1019 } else { 1020 subnode = php_sxe_object_new(sxe_ref->zo.ce TSRMLS_CC); 1021 subnode->document = sxe_ref->document; 1022 subnode->document->refcount++; 1023 if (nsprefix && *nsprefix) { 1024 subnode->iter.nsprefix = xmlStrdup((xmlChar *)nsprefix); 1025 subnode->iter.isprefix = isprefix; 1026 } 1027 php_libxml_increment_node_ptr((php_libxml_node_object *)subnode, node, NULL TSRMLS_CC); 1028 1029 (*value)->type = IS_OBJECT; 1030 (*value)->value.obj = php_sxe_register_object(subnode TSRMLS_CC); 1031 /*zval_add_ref(value);*/ 1032 } 1033} 1034/* }}} */ 1035 1036static void sxe_properties_add(HashTable *rv, char *name, int namelen, zval *value TSRMLS_DC) /* {{{ */ 1037{ 1038 zval **data_ptr; 1039 zval *newptr; 1040 ulong h = zend_hash_func(name, namelen); 1041 1042 if (zend_hash_quick_find(rv, name, namelen, h, (void **) &data_ptr) == SUCCESS) { 1043 if (Z_TYPE_PP(data_ptr) == IS_ARRAY) { 1044 zend_hash_next_index_insert(Z_ARRVAL_PP(data_ptr), &value, sizeof(zval *), NULL); 1045 } else { 1046 MAKE_STD_ZVAL(newptr); 1047 array_init(newptr); 1048 1049 zval_add_ref(data_ptr); 1050 zend_hash_next_index_insert(Z_ARRVAL_P(newptr), data_ptr, sizeof(zval *), NULL); 1051 zend_hash_next_index_insert(Z_ARRVAL_P(newptr), &value, sizeof(zval *), NULL); 1052 1053 zend_hash_quick_update(rv, name, namelen, h, &newptr, sizeof(zval *), NULL); 1054 } 1055 } else { 1056 zend_hash_quick_update(rv, name, namelen, h, &value, sizeof(zval *), NULL); 1057 } 1058} 1059/* }}} */ 1060 1061static HashTable * sxe_get_prop_hash(zval *object, int is_debug TSRMLS_DC) /* {{{ */ 1062{ 1063 zval *value; 1064 zval *zattr; 1065 HashTable *rv; 1066 php_sxe_object *sxe; 1067 char *name; 1068 xmlNodePtr node; 1069 xmlAttrPtr attr; 1070 int namelen; 1071 int test; 1072 char use_iter; 1073 zval *iter_data; 1074 1075 use_iter = 0; 1076 1077 sxe = php_sxe_fetch_object(object TSRMLS_CC); 1078 1079 if (is_debug) { 1080 ALLOC_HASHTABLE(rv); 1081 zend_hash_init(rv, 0, NULL, ZVAL_PTR_DTOR, 0); 1082 } 1083 else if (sxe->properties) { 1084 zend_hash_clean(sxe->properties); 1085 rv = sxe->properties; 1086 } else { 1087 ALLOC_HASHTABLE(rv); 1088 zend_hash_init(rv, 0, NULL, ZVAL_PTR_DTOR, 0); 1089 sxe->properties = rv; 1090 } 1091 1092 GET_NODE(sxe, node); 1093 if (!node) { 1094 return rv; 1095 } 1096 if (is_debug || sxe->iter.type != SXE_ITER_CHILD) { 1097 if (sxe->iter.type == SXE_ITER_ELEMENT) { 1098 node = php_sxe_get_first_node(sxe, node TSRMLS_CC); 1099 } 1100 if (!node || node->type != XML_ENTITY_DECL) { 1101 attr = node ? (xmlAttrPtr)node->properties : NULL; 1102 zattr = NULL; 1103 test = sxe->iter.name && sxe->iter.type == SXE_ITER_ATTRLIST; 1104 while (attr) { 1105 if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr)attr, sxe->iter.nsprefix, sxe->iter.isprefix)) { 1106 MAKE_STD_ZVAL(value); 1107 ZVAL_STRING(value, sxe_xmlNodeListGetString((xmlDocPtr) sxe->document->ptr, attr->children, 1), 0); 1108 namelen = xmlStrlen(attr->name) + 1; 1109 if (!zattr) { 1110 MAKE_STD_ZVAL(zattr); 1111 array_init(zattr); 1112 sxe_properties_add(rv, "@attributes", sizeof("@attributes"), zattr TSRMLS_CC); 1113 } 1114 add_assoc_zval_ex(zattr, (char*)attr->name, namelen, value); 1115 } 1116 attr = attr->next; 1117 } 1118 } 1119 } 1120 1121 GET_NODE(sxe, node); 1122 node = php_sxe_get_first_node(sxe, node TSRMLS_CC); 1123 1124 if (node && sxe->iter.type != SXE_ITER_ATTRLIST) { 1125 if (node->type == XML_ATTRIBUTE_NODE) { 1126 MAKE_STD_ZVAL(value); 1127 ZVAL_STRING(value, sxe_xmlNodeListGetString(node->doc, node->children, 1), 0); 1128 zend_hash_next_index_insert(rv, &value, sizeof(zval *), NULL); 1129 node = NULL; 1130 } else if (sxe->iter.type != SXE_ITER_CHILD) { 1131 1132 if ( !node->children || !node->parent || node->children->next || node->children->children || node->parent->children == node->parent->last ) { 1133 node = node->children; 1134 } else { 1135 iter_data = sxe->iter.data; 1136 sxe->iter.data = NULL; 1137 1138 node = php_sxe_reset_iterator(sxe, 0 TSRMLS_CC); 1139 1140 use_iter = 1; 1141 } 1142 } 1143 1144 while (node) { 1145 if (node->children != NULL || node->prev != NULL || node->next != NULL) { 1146 SKIP_TEXT(node); 1147 } else { 1148 if (node->type == XML_TEXT_NODE) { 1149 const xmlChar *cur = node->content; 1150 1151 if (*cur != 0) { 1152 MAKE_STD_ZVAL(value); 1153 ZVAL_STRING(value, sxe_xmlNodeListGetString(node->doc, node, 1), 0); 1154 zend_hash_next_index_insert(rv, &value, sizeof(zval *), NULL); 1155 } 1156 goto next_iter; 1157 } 1158 } 1159 1160 if (node->type == XML_ELEMENT_NODE && (! match_ns(sxe, node, sxe->iter.nsprefix, sxe->iter.isprefix))) { 1161 goto next_iter; 1162 } 1163 1164 name = (char *) node->name; 1165 if (!name) { 1166 goto next_iter; 1167 } else { 1168 namelen = xmlStrlen(node->name) + 1; 1169 } 1170 1171 _get_base_node_value(sxe, node, &value, sxe->iter.nsprefix, sxe->iter.isprefix TSRMLS_CC); 1172 1173 if ( use_iter ) { 1174 zend_hash_next_index_insert(rv, &value, sizeof(zval *), NULL); 1175 } else { 1176 sxe_properties_add(rv, name, namelen, value TSRMLS_CC); 1177 } 1178next_iter: 1179 if ( use_iter ) { 1180 node = php_sxe_iterator_fetch(sxe, node->next, 0 TSRMLS_CC); 1181 } else { 1182 node = node->next; 1183 } 1184 } 1185 } 1186 1187 if ( use_iter ) { 1188 if (sxe->iter.data) { 1189 zval_ptr_dtor(&sxe->iter.data); 1190 } 1191 sxe->iter.data = iter_data; 1192 } 1193 1194 return rv; 1195} 1196/* }}} */ 1197 1198static HashTable * sxe_get_gc(zval *object, zval ***table, int *n TSRMLS_DC) /* {{{ */ { 1199 php_sxe_object *sxe; 1200 sxe = php_sxe_fetch_object(object TSRMLS_CC); 1201 1202 *table = NULL; 1203 *n = 0; 1204 return sxe->properties; 1205} 1206/* }}} */ 1207 1208static HashTable * sxe_get_properties(zval *object TSRMLS_DC) /* {{{ */ 1209{ 1210 return sxe_get_prop_hash(object, 0 TSRMLS_CC); 1211} 1212/* }}} */ 1213 1214static HashTable * sxe_get_debug_info(zval *object, int *is_temp TSRMLS_DC) /* {{{ */ 1215{ 1216 *is_temp = 1; 1217 return sxe_get_prop_hash(object, 1 TSRMLS_CC); 1218} 1219/* }}} */ 1220 1221static int sxe_objects_compare(zval *object1, zval *object2 TSRMLS_DC) /* {{{ */ 1222{ 1223 php_sxe_object *sxe1; 1224 php_sxe_object *sxe2; 1225 1226 sxe1 = php_sxe_fetch_object(object1 TSRMLS_CC); 1227 sxe2 = php_sxe_fetch_object(object2 TSRMLS_CC); 1228 1229 if (sxe1->node == NULL) { 1230 if (sxe2->node) { 1231 return 1; 1232 } else if (sxe1->document->ptr == sxe2->document->ptr) { 1233 return 0; 1234 } 1235 } else { 1236 return !(sxe1->node == sxe2->node); 1237 } 1238 return 1; 1239} 1240/* }}} */ 1241 1242/* {{{ proto array SimpleXMLElement::xpath(string path) 1243 Runs XPath query on the XML data */ 1244SXE_METHOD(xpath) 1245{ 1246 php_sxe_object *sxe; 1247 zval *value; 1248 char *query; 1249 int query_len; 1250 int i; 1251 int nsnbr = 0; 1252 xmlNsPtr *ns = NULL; 1253 xmlXPathObjectPtr retval; 1254 xmlNodeSetPtr result; 1255 xmlNodePtr nodeptr; 1256 1257 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &query, &query_len) == FAILURE) { 1258 return; 1259 } 1260 1261 sxe = php_sxe_fetch_object(getThis() TSRMLS_CC); 1262 1263 if (sxe->iter.type == SXE_ITER_ATTRLIST) { 1264 return; /* attributes don't have attributes */ 1265 } 1266 1267 if (!sxe->xpath) { 1268 sxe->xpath = xmlXPathNewContext((xmlDocPtr) sxe->document->ptr); 1269 } 1270 if (!sxe->node) { 1271 php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement((xmlDocPtr) sxe->document->ptr), NULL TSRMLS_CC); 1272 } 1273 1274 nodeptr = php_sxe_get_first_node(sxe, sxe->node->node TSRMLS_CC); 1275 1276 sxe->xpath->node = nodeptr; 1277 1278 ns = xmlGetNsList((xmlDocPtr) sxe->document->ptr, nodeptr); 1279 if (ns != NULL) { 1280 while (ns[nsnbr] != NULL) { 1281 nsnbr++; 1282 } 1283 } 1284 1285 sxe->xpath->namespaces = ns; 1286 sxe->xpath->nsNr = nsnbr; 1287 1288 retval = xmlXPathEval((xmlChar *)query, sxe->xpath); 1289 if (ns != NULL) { 1290 xmlFree(ns); 1291 sxe->xpath->namespaces = NULL; 1292 sxe->xpath->nsNr = 0; 1293 } 1294 1295 if (!retval) { 1296 RETURN_FALSE; 1297 } 1298 1299 result = retval->nodesetval; 1300 1301 array_init(return_value); 1302 1303 if (result != NULL) { 1304 for (i = 0; i < result->nodeNr; ++i) { 1305 nodeptr = result->nodeTab[i]; 1306 if (nodeptr->type == XML_TEXT_NODE || nodeptr->type == XML_ELEMENT_NODE || nodeptr->type == XML_ATTRIBUTE_NODE) { 1307 MAKE_STD_ZVAL(value); 1308 /** 1309 * Detect the case where the last selector is text(), simplexml 1310 * always accesses the text() child by default, therefore we assign 1311 * to the parent node. 1312 */ 1313 if (nodeptr->type == XML_TEXT_NODE) { 1314 _node_as_zval(sxe, nodeptr->parent, value, SXE_ITER_NONE, NULL, NULL, 0 TSRMLS_CC); 1315 } else if (nodeptr->type == XML_ATTRIBUTE_NODE) { 1316 _node_as_zval(sxe, nodeptr->parent, value, SXE_ITER_ATTRLIST, (char*)nodeptr->name, nodeptr->ns ? (xmlChar *)nodeptr->ns->href : NULL, 0 TSRMLS_CC); 1317 } else { 1318 _node_as_zval(sxe, nodeptr, value, SXE_ITER_NONE, NULL, NULL, 0 TSRMLS_CC); 1319 } 1320 1321 add_next_index_zval(return_value, value); 1322 } 1323 } 1324 } 1325 1326 xmlXPathFreeObject(retval); 1327} 1328/* }}} */ 1329 1330/* {{{ proto bool SimpleXMLElement::registerXPathNamespace(string prefix, string ns) 1331 Creates a prefix/ns context for the next XPath query */ 1332SXE_METHOD(registerXPathNamespace) 1333{ 1334 php_sxe_object *sxe; 1335 int prefix_len, ns_uri_len; 1336 char *prefix, *ns_uri; 1337 1338 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &prefix, &prefix_len, &ns_uri, &ns_uri_len) == FAILURE) { 1339 return; 1340 } 1341 1342 sxe = php_sxe_fetch_object(getThis() TSRMLS_CC); 1343 if (!sxe->xpath) { 1344 sxe->xpath = xmlXPathNewContext((xmlDocPtr) sxe->document->ptr); 1345 } 1346 1347 if (xmlXPathRegisterNs(sxe->xpath, (xmlChar *)prefix, (xmlChar *)ns_uri) != 0) { 1348 RETURN_FALSE 1349 } 1350 RETURN_TRUE; 1351} 1352 1353/* }}} */ 1354 1355/* {{{ proto string SimpleXMLElement::asXML([string filename]) 1356 Return a well-formed XML string based on SimpleXML element */ 1357SXE_METHOD(asXML) 1358{ 1359 php_sxe_object *sxe; 1360 xmlNodePtr node; 1361 xmlOutputBufferPtr outbuf; 1362 xmlChar *strval; 1363 int strval_len; 1364 char *filename; 1365 int filename_len; 1366 1367 if (ZEND_NUM_ARGS() > 1) { 1368 RETURN_FALSE; 1369 } 1370 1371 if (ZEND_NUM_ARGS() == 1) { 1372 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p", &filename, &filename_len) == FAILURE) { 1373 RETURN_FALSE; 1374 } 1375 1376 sxe = php_sxe_fetch_object(getThis() TSRMLS_CC); 1377 GET_NODE(sxe, node); 1378 node = php_sxe_get_first_node(sxe, node TSRMLS_CC); 1379 1380 if (node) { 1381 if (node->parent && (XML_DOCUMENT_NODE == node->parent->type)) { 1382 int bytes; 1383 bytes = xmlSaveFile(filename, (xmlDocPtr) sxe->document->ptr); 1384 if (bytes == -1) { 1385 RETURN_FALSE; 1386 } else { 1387 RETURN_TRUE; 1388 } 1389 } else { 1390 outbuf = xmlOutputBufferCreateFilename(filename, NULL, 0); 1391 1392 if (outbuf == NULL) { 1393 RETURN_FALSE; 1394 } 1395 1396 xmlNodeDumpOutput(outbuf, (xmlDocPtr) sxe->document->ptr, node, 0, 0, NULL); 1397 xmlOutputBufferClose(outbuf); 1398 RETURN_TRUE; 1399 } 1400 } else { 1401 RETURN_FALSE; 1402 } 1403 } 1404 1405 sxe = php_sxe_fetch_object(getThis() TSRMLS_CC); 1406 GET_NODE(sxe, node); 1407 node = php_sxe_get_first_node(sxe, node TSRMLS_CC); 1408 1409 if (node) { 1410 if (node->parent && (XML_DOCUMENT_NODE == node->parent->type)) { 1411 xmlDocDumpMemoryEnc((xmlDocPtr) sxe->document->ptr, &strval, &strval_len, ((xmlDocPtr) sxe->document->ptr)->encoding); 1412 RETVAL_STRINGL((char *)strval, strval_len, 1); 1413 xmlFree(strval); 1414 } else { 1415 /* Should we be passing encoding information instead of NULL? */ 1416 outbuf = xmlAllocOutputBuffer(NULL); 1417 1418 if (outbuf == NULL) { 1419 RETURN_FALSE; 1420 } 1421 1422 xmlNodeDumpOutput(outbuf, (xmlDocPtr) sxe->document->ptr, node, 0, 0, ((xmlDocPtr) sxe->document->ptr)->encoding); 1423 xmlOutputBufferFlush(outbuf); 1424#ifdef LIBXML2_NEW_BUFFER 1425 RETVAL_STRINGL((char *)xmlOutputBufferGetContent(outbuf), xmlOutputBufferGetSize(outbuf), 1); 1426#else 1427 RETVAL_STRINGL((char *)outbuf->buffer->content, outbuf->buffer->use, 1); 1428#endif 1429 xmlOutputBufferClose(outbuf); 1430 } 1431 } else { 1432 RETVAL_FALSE; 1433 } 1434} 1435/* }}} */ 1436 1437#define SXE_NS_PREFIX(ns) (ns->prefix ? (char*)ns->prefix : "") 1438 1439static inline void sxe_add_namespace_name(zval *return_value, xmlNsPtr ns) /* {{{ */ 1440{ 1441 char *prefix = SXE_NS_PREFIX(ns); 1442 if (zend_hash_exists(Z_ARRVAL_P(return_value), prefix, strlen(prefix) + 1) == 0) { 1443 add_assoc_string(return_value, prefix, (char*)ns->href, 1); 1444 } 1445} 1446/* }}} */ 1447 1448static void sxe_add_namespaces(php_sxe_object *sxe, xmlNodePtr node, zend_bool recursive, zval *return_value TSRMLS_DC) /* {{{ */ 1449{ 1450 xmlAttrPtr attr; 1451 1452 if (node->ns) { 1453 sxe_add_namespace_name(return_value, node->ns); 1454 } 1455 1456 attr = node->properties; 1457 while (attr) { 1458 if (attr->ns) { 1459 sxe_add_namespace_name(return_value, attr->ns); 1460 } 1461 attr = attr->next; 1462 } 1463 1464 if (recursive) { 1465 node = node->children; 1466 while (node) { 1467 if (node->type == XML_ELEMENT_NODE) { 1468 sxe_add_namespaces(sxe, node, recursive, return_value TSRMLS_CC); 1469 } 1470 node = node->next; 1471 } 1472 } 1473} /* }}} */ 1474 1475/* {{{ proto string SimpleXMLElement::getNamespaces([bool recursve]) 1476 Return all namespaces in use */ 1477SXE_METHOD(getNamespaces) 1478{ 1479 zend_bool recursive = 0; 1480 php_sxe_object *sxe; 1481 xmlNodePtr node; 1482 1483 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &recursive) == FAILURE) { 1484 return; 1485 } 1486 1487 array_init(return_value); 1488 1489 sxe = php_sxe_fetch_object(getThis() TSRMLS_CC); 1490 GET_NODE(sxe, node); 1491 node = php_sxe_get_first_node(sxe, node TSRMLS_CC); 1492 1493 if (node) { 1494 if (node->type == XML_ELEMENT_NODE) { 1495 sxe_add_namespaces(sxe, node, recursive, return_value TSRMLS_CC); 1496 } else if (node->type == XML_ATTRIBUTE_NODE && node->ns) { 1497 sxe_add_namespace_name(return_value, node->ns); 1498 } 1499 } 1500} 1501/* }}} */ 1502 1503static void sxe_add_registered_namespaces(php_sxe_object *sxe, xmlNodePtr node, zend_bool recursive, zval *return_value TSRMLS_DC) /* {{{ */ 1504{ 1505 xmlNsPtr ns; 1506 1507 if (node->type == XML_ELEMENT_NODE) { 1508 ns = node->nsDef; 1509 while (ns != NULL) { 1510 sxe_add_namespace_name(return_value, ns); 1511 ns = ns->next; 1512 } 1513 if (recursive) { 1514 node = node->children; 1515 while (node) { 1516 sxe_add_registered_namespaces(sxe, node, recursive, return_value TSRMLS_CC); 1517 node = node->next; 1518 } 1519 } 1520 } 1521} 1522/* }}} */ 1523 1524/* {{{ proto string SimpleXMLElement::getDocNamespaces([bool recursive [, bool from_root]) 1525 Return all namespaces registered with document */ 1526SXE_METHOD(getDocNamespaces) 1527{ 1528 zend_bool recursive = 0, from_root = 1; 1529 php_sxe_object *sxe; 1530 xmlNodePtr node; 1531 1532 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|bb", &recursive, &from_root) == FAILURE) { 1533 return; 1534 } 1535 1536 array_init(return_value); 1537 1538 sxe = php_sxe_fetch_object(getThis() TSRMLS_CC); 1539 if(from_root){ 1540 node = xmlDocGetRootElement((xmlDocPtr)sxe->document->ptr); 1541 }else{ 1542 GET_NODE(sxe, node); 1543 } 1544 1545 sxe_add_registered_namespaces(sxe, node, recursive, return_value TSRMLS_CC); 1546} 1547/* }}} */ 1548 1549/* {{{ proto object SimpleXMLElement::children([string ns [, bool is_prefix]]) 1550 Finds children of given node */ 1551SXE_METHOD(children) 1552{ 1553 php_sxe_object *sxe; 1554 char *nsprefix = NULL; 1555 int nsprefix_len = 0; 1556 xmlNodePtr node; 1557 zend_bool isprefix = 0; 1558 1559 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!b", &nsprefix, &nsprefix_len, &isprefix) == FAILURE) { 1560 return; 1561 } 1562 1563 sxe = php_sxe_fetch_object(getThis() TSRMLS_CC); 1564 1565 if (sxe->iter.type == SXE_ITER_ATTRLIST) { 1566 return; /* attributes don't have attributes */ 1567 } 1568 1569 GET_NODE(sxe, node); 1570 node = php_sxe_get_first_node(sxe, node TSRMLS_CC); 1571 1572 _node_as_zval(sxe, node, return_value, SXE_ITER_CHILD, NULL, (xmlChar *)nsprefix, isprefix TSRMLS_CC); 1573 1574} 1575/* }}} */ 1576 1577/* {{{ proto object SimpleXMLElement::getName() 1578 Finds children of given node */ 1579SXE_METHOD(getName) 1580{ 1581 php_sxe_object *sxe; 1582 xmlNodePtr node; 1583 int namelen; 1584 1585 sxe = php_sxe_fetch_object(getThis() TSRMLS_CC); 1586 1587 GET_NODE(sxe, node); 1588 node = php_sxe_get_first_node(sxe, node TSRMLS_CC); 1589 if (node) { 1590 namelen = xmlStrlen(node->name); 1591 RETURN_STRINGL((char*)node->name, namelen, 1); 1592 } else { 1593 RETURN_EMPTY_STRING(); 1594 } 1595} 1596/* }}} */ 1597 1598/* {{{ proto array SimpleXMLElement::attributes([string ns [, bool is_prefix]]) 1599 Identifies an element's attributes */ 1600SXE_METHOD(attributes) 1601{ 1602 php_sxe_object *sxe; 1603 char *nsprefix = NULL; 1604 int nsprefix_len = 0; 1605 xmlNodePtr node; 1606 zend_bool isprefix = 0; 1607 1608 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!b", &nsprefix, &nsprefix_len, &isprefix) == FAILURE) { 1609 return; 1610 } 1611 1612 sxe = php_sxe_fetch_object(getThis() TSRMLS_CC); 1613 GET_NODE(sxe, node); 1614 1615 if (sxe->iter.type == SXE_ITER_ATTRLIST) { 1616 return; /* attributes don't have attributes */ 1617 } 1618 1619 node = php_sxe_get_first_node(sxe, node TSRMLS_CC); 1620 1621 _node_as_zval(sxe, node, return_value, SXE_ITER_ATTRLIST, NULL, (xmlChar *)nsprefix, isprefix TSRMLS_CC); 1622} 1623/* }}} */ 1624 1625/* {{{ proto void SimpleXMLElement::addChild(string qName [, string value [, string ns]]) 1626 Add Element with optional namespace information */ 1627SXE_METHOD(addChild) 1628{ 1629 php_sxe_object *sxe; 1630 char *qname, *value = NULL, *nsuri = NULL; 1631 int qname_len, value_len = 0, nsuri_len = 0; 1632 xmlNodePtr node, newnode; 1633 xmlNsPtr nsptr = NULL; 1634 xmlChar *localname, *prefix = NULL; 1635 1636 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!s!", 1637 &qname, &qname_len, &value, &value_len, &nsuri, &nsuri_len) == FAILURE) { 1638 return; 1639 } 1640 1641 if (qname_len == 0) { 1642 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Element name is required"); 1643 return; 1644 } 1645 1646 sxe = php_sxe_fetch_object(getThis() TSRMLS_CC); 1647 GET_NODE(sxe, node); 1648 1649 if (sxe->iter.type == SXE_ITER_ATTRLIST) { 1650 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element to attributes"); 1651 return; 1652 } 1653 1654 node = php_sxe_get_first_node(sxe, node TSRMLS_CC); 1655 1656 if (node == NULL) { 1657 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add child. Parent is not a permanent member of the XML tree"); 1658 return; 1659 } 1660 1661 localname = xmlSplitQName2((xmlChar *)qname, &prefix); 1662 if (localname == NULL) { 1663 localname = xmlStrdup((xmlChar *)qname); 1664 } 1665 1666 newnode = xmlNewChild(node, NULL, localname, (xmlChar *)value); 1667 1668 if (nsuri != NULL) { 1669 if (nsuri_len == 0) { 1670 newnode->ns = NULL; 1671 nsptr = xmlNewNs(newnode, (xmlChar *)nsuri, prefix); 1672 } else { 1673 nsptr = xmlSearchNsByHref(node->doc, node, (xmlChar *)nsuri); 1674 if (nsptr == NULL) { 1675 nsptr = xmlNewNs(newnode, (xmlChar *)nsuri, prefix); 1676 } 1677 newnode->ns = nsptr; 1678 } 1679 } 1680 1681 _node_as_zval(sxe, newnode, return_value, SXE_ITER_NONE, (char *)localname, prefix, 0 TSRMLS_CC); 1682 1683 xmlFree(localname); 1684 if (prefix != NULL) { 1685 xmlFree(prefix); 1686 } 1687} 1688/* }}} */ 1689 1690/* {{{ proto void SimpleXMLElement::addAttribute(string qName, string value [,string ns]) 1691 Add Attribute with optional namespace information */ 1692SXE_METHOD(addAttribute) 1693{ 1694 php_sxe_object *sxe; 1695 char *qname, *value = NULL, *nsuri = NULL; 1696 int qname_len, value_len = 0, nsuri_len = 0; 1697 xmlNodePtr node; 1698 xmlAttrPtr attrp = NULL; 1699 xmlNsPtr nsptr = NULL; 1700 xmlChar *localname, *prefix = NULL; 1701 1702 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s!", 1703 &qname, &qname_len, &value, &value_len, &nsuri, &nsuri_len) == FAILURE) { 1704 return; 1705 } 1706 1707 if (qname_len == 0) { 1708 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attribute name is required"); 1709 return; 1710 } 1711 1712 sxe = php_sxe_fetch_object(getThis() TSRMLS_CC); 1713 GET_NODE(sxe, node); 1714 1715 node = php_sxe_get_first_node(sxe, node TSRMLS_CC); 1716 1717 if (node && node->type != XML_ELEMENT_NODE) { 1718 node = node->parent; 1719 } 1720 1721 if (node == NULL) { 1722 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to locate parent Element"); 1723 return; 1724 } 1725 1726 localname = xmlSplitQName2((xmlChar *)qname, &prefix); 1727 if (localname == NULL) { 1728 if (nsuri_len > 0) { 1729 if (prefix != NULL) { 1730 xmlFree(prefix); 1731 } 1732 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attribute requires prefix for namespace"); 1733 return; 1734 } 1735 localname = xmlStrdup((xmlChar *)qname); 1736 } 1737 1738 attrp = xmlHasNsProp(node, localname, (xmlChar *)nsuri); 1739 if (attrp != NULL && attrp->type != XML_ATTRIBUTE_DECL) { 1740 xmlFree(localname); 1741 if (prefix != NULL) { 1742 xmlFree(prefix); 1743 } 1744 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attribute already exists"); 1745 return; 1746 } 1747 1748 if (nsuri != NULL) { 1749 nsptr = xmlSearchNsByHref(node->doc, node, (xmlChar *)nsuri); 1750 if (nsptr == NULL) { 1751 nsptr = xmlNewNs(node, (xmlChar *)nsuri, prefix); 1752 } 1753 } 1754 1755 attrp = xmlNewNsProp(node, nsptr, localname, (xmlChar *)value); 1756 1757 xmlFree(localname); 1758 if (prefix != NULL) { 1759 xmlFree(prefix); 1760 } 1761} 1762/* }}} */ 1763 1764/* {{{ cast_object() 1765 */ 1766static int cast_object(zval *object, int type, char *contents TSRMLS_DC) 1767{ 1768 if (contents) { 1769 ZVAL_STRINGL(object, contents, strlen(contents), 1); 1770 } else { 1771 ZVAL_NULL(object); 1772 } 1773 Z_SET_REFCOUNT_P(object, 1); 1774 Z_UNSET_ISREF_P(object); 1775 1776 switch (type) { 1777 case IS_STRING: 1778 convert_to_string(object); 1779 break; 1780 case IS_BOOL: 1781 convert_to_boolean(object); 1782 break; 1783 case IS_LONG: 1784 convert_to_long(object); 1785 break; 1786 case IS_DOUBLE: 1787 convert_to_double(object); 1788 break; 1789 default: 1790 return FAILURE; 1791 } 1792 return SUCCESS; 1793} 1794/* }}} */ 1795 1796/* {{{ sxe_object_cast() 1797 */ 1798static int sxe_object_cast(zval *readobj, zval *writeobj, int type TSRMLS_DC) 1799{ 1800 php_sxe_object *sxe; 1801 xmlChar *contents = NULL; 1802 xmlNodePtr node; 1803 int rv; 1804 HashTable *prop_hash; 1805 1806 sxe = php_sxe_fetch_object(readobj TSRMLS_CC); 1807 1808 if (type == IS_BOOL) { 1809 node = php_sxe_get_first_node(sxe, NULL TSRMLS_CC); 1810 prop_hash = sxe_get_prop_hash(readobj, 1 TSRMLS_CC); 1811 INIT_PZVAL(writeobj); 1812 ZVAL_BOOL(writeobj, node != NULL || zend_hash_num_elements(prop_hash) > 0); 1813 zend_hash_destroy(prop_hash); 1814 efree(prop_hash); 1815 return SUCCESS; 1816 } 1817 1818 if (sxe->iter.type != SXE_ITER_NONE) { 1819 node = php_sxe_get_first_node(sxe, NULL TSRMLS_CC); 1820 if (node) { 1821 contents = xmlNodeListGetString((xmlDocPtr) sxe->document->ptr, node->children, 1); 1822 } 1823 } else { 1824 if (!sxe->node) { 1825 if (sxe->document) { 1826 php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement((xmlDocPtr) sxe->document->ptr), NULL TSRMLS_CC); 1827 } 1828 } 1829 1830 if (sxe->node && sxe->node->node) { 1831 if (sxe->node->node->children) { 1832 contents = xmlNodeListGetString((xmlDocPtr) sxe->document->ptr, sxe->node->node->children, 1); 1833 } 1834 } 1835 } 1836 1837 if (readobj == writeobj) { 1838 INIT_PZVAL(writeobj); 1839 zval_dtor(readobj); 1840 } 1841 1842 rv = cast_object(writeobj, type, (char *)contents TSRMLS_CC); 1843 1844 if (contents) { 1845 xmlFree(contents); 1846 } 1847 return rv; 1848} 1849/* }}} */ 1850 1851/* {{{ proto object SimpleXMLElement::__toString() U 1852 Returns the string content */ 1853SXE_METHOD(__toString) 1854{ 1855 zval *result; 1856 1857 ALLOC_INIT_ZVAL(result); 1858 1859 if (sxe_object_cast(getThis(), result, IS_STRING TSRMLS_CC) == SUCCESS) { 1860 RETURN_ZVAL(result, 1, 1); 1861 } else { 1862 zval_ptr_dtor(&result); 1863 RETURN_EMPTY_STRING(); 1864 } 1865} 1866/* }}} */ 1867 1868static int php_sxe_count_elements_helper(php_sxe_object *sxe, long *count TSRMLS_DC) /* {{{ */ 1869{ 1870 xmlNodePtr node; 1871 zval *data; 1872 1873 *count = 0; 1874 1875 data = sxe->iter.data; 1876 sxe->iter.data = NULL; 1877 1878 node = php_sxe_reset_iterator(sxe, 0 TSRMLS_CC); 1879 1880 while (node) 1881 { 1882 (*count)++; 1883 node = php_sxe_iterator_fetch(sxe, node->next, 0 TSRMLS_CC); 1884 } 1885 1886 if (sxe->iter.data) { 1887 zval_ptr_dtor(&sxe->iter.data); 1888 } 1889 sxe->iter.data = data; 1890 1891 return SUCCESS; 1892} 1893/* }}} */ 1894 1895static int sxe_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */ 1896{ 1897 php_sxe_object *intern; 1898 intern = php_sxe_fetch_object(object TSRMLS_CC); 1899 if (intern->fptr_count) { 1900 zval *rv; 1901 zend_call_method_with_0_params(&object, intern->zo.ce, &intern->fptr_count, "count", &rv); 1902 if (rv) { 1903 if (intern->tmp) { 1904 zval_ptr_dtor(&intern->tmp); 1905 } 1906 MAKE_STD_ZVAL(intern->tmp); 1907 ZVAL_ZVAL(intern->tmp, rv, 1, 1); 1908 convert_to_long(intern->tmp); 1909 *count = (long) Z_LVAL_P(intern->tmp); 1910 return SUCCESS; 1911 } 1912 return FAILURE; 1913 } 1914 return php_sxe_count_elements_helper(intern, count TSRMLS_CC); 1915} 1916/* }}} */ 1917 1918/* {{{ proto int SimpleXMLElement::count() 1919 Get number of child elements */ 1920SXE_METHOD(count) 1921{ 1922 long count = 0; 1923 php_sxe_object *sxe = php_sxe_fetch_object(getThis() TSRMLS_CC); 1924 1925 if (zend_parse_parameters_none() == FAILURE) { 1926 return; 1927 } 1928 1929 php_sxe_count_elements_helper(sxe, &count TSRMLS_CC); 1930 1931 RETURN_LONG(count); 1932} 1933/* }}} */ 1934 1935static zval *sxe_get_value(zval *z TSRMLS_DC) /* {{{ */ 1936{ 1937 zval *retval; 1938 1939 MAKE_STD_ZVAL(retval); 1940 1941 if (sxe_object_cast(z, retval, IS_STRING TSRMLS_CC)==FAILURE) { 1942 zend_error(E_ERROR, "Unable to cast node to string"); 1943 /* FIXME: Should not be fatal */ 1944 } 1945 1946 Z_SET_REFCOUNT_P(retval, 0); 1947 return retval; 1948} 1949/* }}} */ 1950 1951static zend_object_handlers sxe_object_handlers = { /* {{{ */ 1952 ZEND_OBJECTS_STORE_HANDLERS, 1953 sxe_property_read, 1954 sxe_property_write, 1955 sxe_dimension_read, 1956 sxe_dimension_write, 1957 sxe_property_get_adr, 1958 sxe_get_value, /* get */ 1959 NULL, 1960 sxe_property_exists, 1961 sxe_property_delete, 1962 sxe_dimension_exists, 1963 sxe_dimension_delete, 1964 sxe_get_properties, 1965 NULL, /* zend_get_std_object_handlers()->get_method,*/ 1966 NULL, /* zend_get_std_object_handlers()->call_method,*/ 1967 NULL, /* zend_get_std_object_handlers()->get_constructor, */ 1968 NULL, /* zend_get_std_object_handlers()->get_class_entry,*/ 1969 NULL, /* zend_get_std_object_handlers()->get_class_name,*/ 1970 sxe_objects_compare, 1971 sxe_object_cast, 1972 sxe_count_elements, 1973 sxe_get_debug_info, 1974 NULL, 1975 sxe_get_gc 1976}; 1977/* }}} */ 1978 1979/* {{{ sxe_object_clone() 1980 */ 1981static void 1982sxe_object_clone(void *object, void **clone_ptr TSRMLS_DC) 1983{ 1984 php_sxe_object *sxe = (php_sxe_object *) object; 1985 php_sxe_object *clone; 1986 xmlNodePtr nodep = NULL; 1987 xmlDocPtr docp = NULL; 1988 1989 clone = php_sxe_object_new(sxe->zo.ce TSRMLS_CC); 1990 clone->document = sxe->document; 1991 if (clone->document) { 1992 clone->document->refcount++; 1993 docp = clone->document->ptr; 1994 } 1995 1996 clone->iter.isprefix = sxe->iter.isprefix; 1997 if (sxe->iter.name != NULL) { 1998 clone->iter.name = xmlStrdup((xmlChar *)sxe->iter.name); 1999 } 2000 if (sxe->iter.nsprefix != NULL) { 2001 clone->iter.nsprefix = xmlStrdup((xmlChar *)sxe->iter.nsprefix); 2002 } 2003 clone->iter.type = sxe->iter.type; 2004 2005 if (sxe->node) { 2006 nodep = xmlDocCopyNode(sxe->node->node, docp, 1); 2007 } 2008 2009 php_libxml_increment_node_ptr((php_libxml_node_object *)clone, nodep, NULL TSRMLS_CC); 2010 2011 *clone_ptr = (void *) clone; 2012} 2013/* }}} */ 2014 2015/* {{{ sxe_object_dtor() 2016 */ 2017static void sxe_object_dtor(void *object, zend_object_handle handle TSRMLS_DC) 2018{ 2019 /* dtor required to cleanup iterator related data properly */ 2020 2021 php_sxe_object *sxe; 2022 2023 sxe = (php_sxe_object *) object; 2024 2025 if (sxe->iter.data) { 2026 zval_ptr_dtor(&sxe->iter.data); 2027 sxe->iter.data = NULL; 2028 } 2029 2030 if (sxe->iter.name) { 2031 xmlFree(sxe->iter.name); 2032 sxe->iter.name = NULL; 2033 } 2034 if (sxe->iter.nsprefix) { 2035 xmlFree(sxe->iter.nsprefix); 2036 sxe->iter.nsprefix = NULL; 2037 } 2038 if (sxe->tmp) { 2039 zval_ptr_dtor(&sxe->tmp); 2040 sxe->tmp = NULL; 2041 } 2042} 2043/* }}} */ 2044 2045/* {{{ sxe_object_free_storage() 2046 */ 2047static void sxe_object_free_storage(void *object TSRMLS_DC) 2048{ 2049 php_sxe_object *sxe; 2050 2051 sxe = (php_sxe_object *) object; 2052 2053#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION == 1 && PHP_RELEASE_VERSION > 2) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 1) || (PHP_MAJOR_VERSION > 5) 2054 zend_object_std_dtor(&sxe->zo TSRMLS_CC); 2055#else 2056 if (sxe->zo.guards) { 2057 zend_hash_destroy(sxe->zo.guards); 2058 FREE_HASHTABLE(sxe->zo.guards); 2059 } 2060 2061 if (sxe->zo.properties) { 2062 zend_hash_destroy(sxe->zo.properties); 2063 FREE_HASHTABLE(sxe->zo.properties); 2064 } 2065#endif 2066 2067 php_libxml_node_decrement_resource((php_libxml_node_object *)sxe TSRMLS_CC); 2068 2069 if (sxe->xpath) { 2070 xmlXPathFreeContext(sxe->xpath); 2071 } 2072 2073 if (sxe->properties) { 2074 zend_hash_destroy(sxe->properties); 2075 FREE_HASHTABLE(sxe->properties); 2076 } 2077 2078 efree(object); 2079} 2080/* }}} */ 2081 2082/* {{{ php_sxe_object_new() 2083 */ 2084static php_sxe_object* php_sxe_object_new(zend_class_entry *ce TSRMLS_DC) 2085{ 2086 php_sxe_object *intern; 2087 zend_class_entry *parent = ce; 2088 int inherited = 0; 2089 2090 intern = ecalloc(1, sizeof(php_sxe_object)); 2091 2092 intern->iter.type = SXE_ITER_NONE; 2093 intern->iter.nsprefix = NULL; 2094 intern->iter.name = NULL; 2095 intern->fptr_count = NULL; 2096 2097#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION == 1 && PHP_RELEASE_VERSION > 2) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 1) || (PHP_MAJOR_VERSION > 5) 2098 zend_object_std_init(&intern->zo, ce TSRMLS_CC); 2099#else 2100 ALLOC_HASHTABLE(intern->zo.properties); 2101 zend_hash_init(intern->zo.properties, 0, NULL, ZVAL_PTR_DTOR, 0); 2102 2103 intern->zo.ce = ce; 2104 intern->zo.guards = NULL; 2105#endif 2106 2107 while (parent) { 2108 if (parent == sxe_class_entry) { 2109 break; 2110 } 2111 2112 parent = parent->parent; 2113 inherited = 1; 2114 } 2115 2116 if (inherited) { 2117 zend_hash_find(&ce->function_table, "count", sizeof("count"),(void **) &intern->fptr_count); 2118 if (intern->fptr_count->common.scope == parent) { 2119 intern->fptr_count = NULL; 2120 } 2121 } 2122 2123 return intern; 2124} 2125/* }}} */ 2126 2127/* {{{ php_sxe_register_object 2128 */ 2129static zend_object_value 2130php_sxe_register_object(php_sxe_object *intern TSRMLS_DC) 2131{ 2132 zend_object_value rv; 2133 2134 rv.handle = zend_objects_store_put(intern, sxe_object_dtor, (zend_objects_free_object_storage_t)sxe_object_free_storage, sxe_object_clone TSRMLS_CC); 2135 rv.handlers = (zend_object_handlers *) &sxe_object_handlers; 2136 2137 return rv; 2138} 2139/* }}} */ 2140 2141/* {{{ sxe_object_new() 2142 */ 2143PHP_SXE_API zend_object_value 2144sxe_object_new(zend_class_entry *ce TSRMLS_DC) 2145{ 2146 php_sxe_object *intern; 2147 2148 intern = php_sxe_object_new(ce TSRMLS_CC); 2149 return php_sxe_register_object(intern TSRMLS_CC); 2150} 2151/* }}} */ 2152 2153/* {{{ proto simplemxml_element simplexml_load_file(string filename [, string class_name [, int options [, string ns [, bool is_prefix]]]]) 2154 Load a filename and return a simplexml_element object to allow for processing */ 2155PHP_FUNCTION(simplexml_load_file) 2156{ 2157 php_sxe_object *sxe; 2158 char *filename; 2159 int filename_len; 2160 xmlDocPtr docp; 2161 char *ns = NULL; 2162 int ns_len = 0; 2163 long options = 0; 2164 zend_class_entry *ce= sxe_class_entry; 2165 zend_bool isprefix = 0; 2166 2167 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p|C!lsb", &filename, &filename_len, &ce, &options, &ns, &ns_len, &isprefix) == FAILURE) { 2168 return; 2169 } 2170 2171 docp = xmlReadFile(filename, NULL, options); 2172 2173 if (! docp) { 2174 RETURN_FALSE; 2175 } 2176 2177 if (!ce) { 2178 ce = sxe_class_entry; 2179 } 2180 sxe = php_sxe_object_new(ce TSRMLS_CC); 2181 sxe->iter.nsprefix = ns_len ? xmlStrdup((xmlChar *)ns) : NULL; 2182 sxe->iter.isprefix = isprefix; 2183 php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp TSRMLS_CC); 2184 php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL TSRMLS_CC); 2185 2186 return_value->type = IS_OBJECT; 2187 return_value->value.obj = php_sxe_register_object(sxe TSRMLS_CC); 2188} 2189/* }}} */ 2190 2191/* {{{ proto simplemxml_element simplexml_load_string(string data [, string class_name [, int options [, string ns [, bool is_prefix]]]]) 2192 Load a string and return a simplexml_element object to allow for processing */ 2193PHP_FUNCTION(simplexml_load_string) 2194{ 2195 php_sxe_object *sxe; 2196 char *data; 2197 int data_len; 2198 xmlDocPtr docp; 2199 char *ns = NULL; 2200 int ns_len = 0; 2201 long options = 0; 2202 zend_class_entry *ce= sxe_class_entry; 2203 zend_bool isprefix = 0; 2204 2205 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|C!lsb", &data, &data_len, &ce, &options, &ns, &ns_len, &isprefix) == FAILURE) { 2206 return; 2207 } 2208 2209 docp = xmlReadMemory(data, data_len, NULL, NULL, options); 2210 2211 if (! docp) { 2212 RETURN_FALSE; 2213 } 2214 2215 if (!ce) { 2216 ce = sxe_class_entry; 2217 } 2218 sxe = php_sxe_object_new(ce TSRMLS_CC); 2219 sxe->iter.nsprefix = ns_len ? xmlStrdup((xmlChar *)ns) : NULL; 2220 sxe->iter.isprefix = isprefix; 2221 php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp TSRMLS_CC); 2222 php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL TSRMLS_CC); 2223 2224 return_value->type = IS_OBJECT; 2225 return_value->value.obj = php_sxe_register_object(sxe TSRMLS_CC); 2226} 2227/* }}} */ 2228 2229/* {{{ proto SimpleXMLElement::__construct(string data [, int options [, bool data_is_url [, string ns [, bool is_prefix]]]]) 2230 SimpleXMLElement constructor */ 2231SXE_METHOD(__construct) 2232{ 2233 php_sxe_object *sxe = php_sxe_fetch_object(getThis() TSRMLS_CC); 2234 char *data, *ns = NULL; 2235 int data_len, ns_len = 0; 2236 xmlDocPtr docp; 2237 long options = 0; 2238 zend_bool is_url = 0, isprefix = 0; 2239 zend_error_handling error_handling; 2240 2241 zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC); 2242 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lbsb", &data, &data_len, &options, &is_url, &ns, &ns_len, &isprefix) == FAILURE) { 2243 zend_restore_error_handling(&error_handling TSRMLS_CC); 2244 return; 2245 } 2246 2247 zend_restore_error_handling(&error_handling TSRMLS_CC); 2248 2249 docp = is_url ? xmlReadFile(data, NULL, options) : xmlReadMemory(data, data_len, NULL, NULL, options); 2250 2251 if (!docp) { 2252 ((php_libxml_node_object *)sxe)->document = NULL; 2253 zend_throw_exception(zend_exception_get_default(TSRMLS_C), "String could not be parsed as XML", 0 TSRMLS_CC); 2254 return; 2255 } 2256 2257 sxe->iter.nsprefix = ns_len ? xmlStrdup((xmlChar *)ns) : NULL; 2258 sxe->iter.isprefix = isprefix; 2259 php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp TSRMLS_CC); 2260 php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL TSRMLS_CC); 2261} 2262/* }}} */ 2263 2264zend_object_iterator_funcs php_sxe_iterator_funcs = { /* {{{ */ 2265 php_sxe_iterator_dtor, 2266 php_sxe_iterator_valid, 2267 php_sxe_iterator_current_data, 2268 php_sxe_iterator_current_key, 2269 php_sxe_iterator_move_forward, 2270 php_sxe_iterator_rewind, 2271}; 2272/* }}} */ 2273 2274static xmlNodePtr php_sxe_iterator_fetch(php_sxe_object *sxe, xmlNodePtr node, int use_data TSRMLS_DC) /* {{{ */ 2275{ 2276 xmlChar *prefix = sxe->iter.nsprefix; 2277 int isprefix = sxe->iter.isprefix; 2278 int test_elem = sxe->iter.type == SXE_ITER_ELEMENT && sxe->iter.name; 2279 int test_attr = sxe->iter.type == SXE_ITER_ATTRLIST && sxe->iter.name; 2280 2281 while (node) { 2282 SKIP_TEXT(node); 2283 if (sxe->iter.type != SXE_ITER_ATTRLIST && node->type == XML_ELEMENT_NODE) { 2284 if ((!test_elem || !xmlStrcmp(node->name, sxe->iter.name)) && match_ns(sxe, node, prefix, isprefix)) { 2285 break; 2286 } 2287 } else if (node->type == XML_ATTRIBUTE_NODE) { 2288 if ((!test_attr || !xmlStrcmp(node->name, sxe->iter.name)) && match_ns(sxe, node, prefix, isprefix)) { 2289 break; 2290 } 2291 } 2292next_iter: 2293 node = node->next; 2294 } 2295 2296 if (node && use_data) { 2297 ALLOC_INIT_ZVAL(sxe->iter.data); 2298 _node_as_zval(sxe, node, sxe->iter.data, SXE_ITER_NONE, NULL, prefix, isprefix TSRMLS_CC); 2299 } 2300 2301 return node; 2302} 2303/* }}} */ 2304 2305static xmlNodePtr php_sxe_reset_iterator(php_sxe_object *sxe, int use_data TSRMLS_DC) /* {{{ */ 2306{ 2307 xmlNodePtr node; 2308 2309 if (sxe->iter.data) { 2310 zval_ptr_dtor(&sxe->iter.data); 2311 sxe->iter.data = NULL; 2312 } 2313 2314 GET_NODE(sxe, node) 2315 2316 if (node) { 2317 switch (sxe->iter.type) { 2318 case SXE_ITER_ELEMENT: 2319 case SXE_ITER_CHILD: 2320 case SXE_ITER_NONE: 2321 node = node->children; 2322 break; 2323 case SXE_ITER_ATTRLIST: 2324 node = (xmlNodePtr) node->properties; 2325 } 2326 return php_sxe_iterator_fetch(sxe, node, use_data TSRMLS_CC); 2327 } 2328 return NULL; 2329} 2330/* }}} */ 2331 2332zend_object_iterator *php_sxe_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */ 2333{ 2334 php_sxe_iterator *iterator; 2335 2336 if (by_ref) { 2337 zend_error(E_ERROR, "An iterator cannot be used with foreach by reference"); 2338 } 2339 iterator = emalloc(sizeof(php_sxe_iterator)); 2340 2341 Z_ADDREF_P(object); 2342 iterator->intern.data = (void*)object; 2343 iterator->intern.funcs = &php_sxe_iterator_funcs; 2344 iterator->sxe = php_sxe_fetch_object(object TSRMLS_CC); 2345 2346 return (zend_object_iterator*)iterator; 2347} 2348/* }}} */ 2349 2350static void php_sxe_iterator_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ 2351{ 2352 php_sxe_iterator *iterator = (php_sxe_iterator *)iter; 2353 2354 /* cleanup handled in sxe_object_dtor as we dont always have an iterator wrapper */ 2355 if (iterator->intern.data) { 2356 zval_ptr_dtor((zval**)&iterator->intern.data); 2357 } 2358 2359 efree(iterator); 2360} 2361/* }}} */ 2362 2363static int php_sxe_iterator_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ 2364{ 2365 php_sxe_iterator *iterator = (php_sxe_iterator *)iter; 2366 2367 return iterator->sxe->iter.data ? SUCCESS : FAILURE; 2368} 2369/* }}} */ 2370 2371static void php_sxe_iterator_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */ 2372{ 2373 php_sxe_iterator *iterator = (php_sxe_iterator *)iter; 2374 2375 *data = &iterator->sxe->iter.data; 2376} 2377/* }}} */ 2378 2379static int php_sxe_iterator_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */ 2380{ 2381 zval *curobj; 2382 xmlNodePtr curnode = NULL; 2383 php_sxe_object *intern; 2384 int namelen; 2385 2386 php_sxe_iterator *iterator = (php_sxe_iterator *)iter; 2387 curobj = iterator->sxe->iter.data; 2388 2389 intern = (php_sxe_object *)zend_object_store_get_object(curobj TSRMLS_CC); 2390 if (intern != NULL && intern->node != NULL) { 2391 curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->node)->node; 2392 } 2393 if (!curnode) { 2394 return HASH_KEY_NON_EXISTANT; 2395 } 2396 2397 namelen = xmlStrlen(curnode->name); 2398 *str_key = estrndup((char *)curnode->name, namelen); 2399 *str_key_len = namelen + 1; 2400 return HASH_KEY_IS_STRING; 2401 2402} 2403/* }}} */ 2404 2405PHP_SXE_API void php_sxe_move_forward_iterator(php_sxe_object *sxe TSRMLS_DC) /* {{{ */ 2406{ 2407 xmlNodePtr node = NULL; 2408 php_sxe_object *intern; 2409 2410 if (sxe->iter.data) { 2411 intern = (php_sxe_object *)zend_object_store_get_object(sxe->iter.data TSRMLS_CC); 2412 GET_NODE(intern, node) 2413 zval_ptr_dtor(&sxe->iter.data); 2414 sxe->iter.data = NULL; 2415 } 2416 2417 if (node) { 2418 php_sxe_iterator_fetch(sxe, node->next, 1 TSRMLS_CC); 2419 } 2420} 2421/* }}} */ 2422 2423static void php_sxe_iterator_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ 2424{ 2425 php_sxe_iterator *iterator = (php_sxe_iterator *)iter; 2426 php_sxe_move_forward_iterator(iterator->sxe TSRMLS_CC); 2427} 2428/* }}} */ 2429 2430static void php_sxe_iterator_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ 2431{ 2432 php_sxe_object *sxe; 2433 2434 php_sxe_iterator *iterator = (php_sxe_iterator *)iter; 2435 sxe = iterator->sxe; 2436 2437 php_sxe_reset_iterator(sxe, 1 TSRMLS_CC); 2438} 2439/* }}} */ 2440 2441void *simplexml_export_node(zval *object TSRMLS_DC) /* {{{ */ 2442{ 2443 php_sxe_object *sxe; 2444 xmlNodePtr node; 2445 2446 sxe = php_sxe_fetch_object(object TSRMLS_CC); 2447 GET_NODE(sxe, node); 2448 return php_sxe_get_first_node(sxe, node TSRMLS_CC); 2449} 2450/* }}} */ 2451 2452/* {{{ proto simplemxml_element simplexml_import_dom(domNode node [, string class_name]) 2453 Get a simplexml_element object from dom to allow for processing */ 2454PHP_FUNCTION(simplexml_import_dom) 2455{ 2456 php_sxe_object *sxe; 2457 zval *node; 2458 php_libxml_node_object *object; 2459 xmlNodePtr nodep = NULL; 2460 zend_class_entry *ce= sxe_class_entry; 2461 2462 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o|C!", &node, &ce) == FAILURE) { 2463 return; 2464 } 2465 2466 object = (php_libxml_node_object *)zend_object_store_get_object(node TSRMLS_CC); 2467 2468 nodep = php_libxml_import_node(node TSRMLS_CC); 2469 2470 if (nodep) { 2471 if (nodep->doc == NULL) { 2472 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Imported Node must have associated Document"); 2473 RETURN_NULL(); 2474 } 2475 if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) { 2476 nodep = xmlDocGetRootElement((xmlDocPtr) nodep); 2477 } 2478 } 2479 2480 if (nodep && nodep->type == XML_ELEMENT_NODE) { 2481 if (!ce) { 2482 ce = sxe_class_entry; 2483 } 2484 sxe = php_sxe_object_new(ce TSRMLS_CC); 2485 sxe->document = object->document; 2486 php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, nodep->doc TSRMLS_CC); 2487 php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, nodep, NULL TSRMLS_CC); 2488 2489 return_value->type = IS_OBJECT; 2490 return_value->value.obj = php_sxe_register_object(sxe TSRMLS_CC); 2491 } else { 2492 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Nodetype to import"); 2493 RETVAL_NULL(); 2494 } 2495} 2496/* }}} */ 2497 2498/* {{{ arginfo */ 2499ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexml_load_file, 0, 0, 1) 2500 ZEND_ARG_INFO(0, filename) 2501 ZEND_ARG_INFO(0, class_name) 2502 ZEND_ARG_INFO(0, options) 2503 ZEND_ARG_INFO(0, ns) 2504 ZEND_ARG_INFO(0, is_prefix) 2505ZEND_END_ARG_INFO() 2506 2507ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexml_load_string, 0, 0, 1) 2508 ZEND_ARG_INFO(0, data) 2509 ZEND_ARG_INFO(0, class_name) 2510 ZEND_ARG_INFO(0, options) 2511 ZEND_ARG_INFO(0, ns) 2512 ZEND_ARG_INFO(0, is_prefix) 2513ZEND_END_ARG_INFO() 2514 2515ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexml_import_dom, 0, 0, 1) 2516 ZEND_ARG_INFO(0, node) 2517 ZEND_ARG_INFO(0, class_name) 2518ZEND_END_ARG_INFO() 2519 2520ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_xpath, 0, 0, 1) 2521 ZEND_ARG_INFO(0, path) 2522ZEND_END_ARG_INFO() 2523 2524ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_registerxpathnamespace, 0, 0, 2) 2525 ZEND_ARG_INFO(0, prefix) 2526 ZEND_ARG_INFO(0, ns) 2527ZEND_END_ARG_INFO() 2528 2529ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_asxml, 0, 0, 0) 2530 ZEND_ARG_INFO(0, filename) 2531ZEND_END_ARG_INFO() 2532 2533ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_getnamespaces, 0, 0, 0) 2534 ZEND_ARG_INFO(0, recursve) 2535ZEND_END_ARG_INFO() 2536 2537ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_getdocnamespaces, 0, 0, 0) 2538 ZEND_ARG_INFO(0, recursve) 2539 ZEND_ARG_INFO(0, from_root) 2540ZEND_END_ARG_INFO() 2541 2542ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_children, 0, 0, 0) 2543 ZEND_ARG_INFO(0, ns) 2544 ZEND_ARG_INFO(0, is_prefix) 2545ZEND_END_ARG_INFO() 2546 2547ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement__construct, 0, 0, 1) 2548 ZEND_ARG_INFO(0, data) 2549 ZEND_ARG_INFO(0, options) 2550 ZEND_ARG_INFO(0, data_is_url) 2551 ZEND_ARG_INFO(0, ns) 2552 ZEND_ARG_INFO(0, is_prefix) 2553ZEND_END_ARG_INFO() 2554 2555ZEND_BEGIN_ARG_INFO(arginfo_simplexmlelement__void, 0) 2556ZEND_END_ARG_INFO() 2557 2558ZEND_BEGIN_ARG_INFO_EX(arginfo_simplexmlelement_addchild, 0, 0, 1) 2559 ZEND_ARG_INFO(0, name) 2560 ZEND_ARG_INFO(0, value) 2561 ZEND_ARG_INFO(0, ns) 2562ZEND_END_ARG_INFO() 2563/* }}} */ 2564 2565const zend_function_entry simplexml_functions[] = { /* {{{ */ 2566 PHP_FE(simplexml_load_file, arginfo_simplexml_load_file) 2567 PHP_FE(simplexml_load_string, arginfo_simplexml_load_string) 2568 PHP_FE(simplexml_import_dom, arginfo_simplexml_import_dom) 2569 PHP_FE_END 2570}; 2571/* }}} */ 2572 2573static const zend_module_dep simplexml_deps[] = { /* {{{ */ 2574 ZEND_MOD_REQUIRED("libxml") 2575 ZEND_MOD_REQUIRED("spl") 2576 ZEND_MOD_END 2577}; 2578/* }}} */ 2579 2580zend_module_entry simplexml_module_entry = { /* {{{ */ 2581 STANDARD_MODULE_HEADER_EX, NULL, 2582 simplexml_deps, 2583 "SimpleXML", 2584 simplexml_functions, 2585 PHP_MINIT(simplexml), 2586 PHP_MSHUTDOWN(simplexml), 2587 NULL, 2588 NULL, 2589 PHP_MINFO(simplexml), 2590 "0.1", 2591 STANDARD_MODULE_PROPERTIES 2592}; 2593/* }}} */ 2594 2595#ifdef COMPILE_DL_SIMPLEXML 2596ZEND_GET_MODULE(simplexml) 2597#endif 2598 2599/* the method table */ 2600/* each method can have its own parameters and visibility */ 2601static const zend_function_entry sxe_functions[] = { /* {{{ */ 2602 SXE_ME(__construct, arginfo_simplexmlelement__construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) /* must be called */ 2603 SXE_ME(asXML, arginfo_simplexmlelement_asxml, ZEND_ACC_PUBLIC) 2604 SXE_MALIAS(saveXML, asXML, arginfo_simplexmlelement_asxml, ZEND_ACC_PUBLIC) 2605 SXE_ME(xpath, arginfo_simplexmlelement_xpath, ZEND_ACC_PUBLIC) 2606 SXE_ME(registerXPathNamespace, arginfo_simplexmlelement_registerxpathnamespace, ZEND_ACC_PUBLIC) 2607 SXE_ME(attributes, arginfo_simplexmlelement_children, ZEND_ACC_PUBLIC) 2608 SXE_ME(children, arginfo_simplexmlelement_children, ZEND_ACC_PUBLIC) 2609 SXE_ME(getNamespaces, arginfo_simplexmlelement_getnamespaces, ZEND_ACC_PUBLIC) 2610 SXE_ME(getDocNamespaces, arginfo_simplexmlelement_getdocnamespaces, ZEND_ACC_PUBLIC) 2611 SXE_ME(getName, arginfo_simplexmlelement__void, ZEND_ACC_PUBLIC) 2612 SXE_ME(addChild, arginfo_simplexmlelement_addchild, ZEND_ACC_PUBLIC) 2613 SXE_ME(addAttribute, arginfo_simplexmlelement_addchild, ZEND_ACC_PUBLIC) 2614 SXE_ME(__toString, arginfo_simplexmlelement__void, ZEND_ACC_PUBLIC) 2615 SXE_ME(count, arginfo_simplexmlelement__void, ZEND_ACC_PUBLIC) 2616 PHP_FE_END 2617}; 2618/* }}} */ 2619 2620/* {{{ PHP_MINIT_FUNCTION(simplexml) 2621 */ 2622PHP_MINIT_FUNCTION(simplexml) 2623{ 2624 zend_class_entry sxe; 2625 2626 INIT_CLASS_ENTRY(sxe, "SimpleXMLElement", sxe_functions); 2627 sxe.create_object = sxe_object_new; 2628 sxe_class_entry = zend_register_internal_class(&sxe TSRMLS_CC); 2629 sxe_class_entry->get_iterator = php_sxe_get_iterator; 2630 sxe_class_entry->iterator_funcs.funcs = &php_sxe_iterator_funcs; 2631 zend_class_implements(sxe_class_entry TSRMLS_CC, 1, zend_ce_traversable); 2632 sxe_object_handlers.get_method = zend_get_std_object_handlers()->get_method; 2633 sxe_object_handlers.get_constructor = zend_get_std_object_handlers()->get_constructor; 2634 sxe_object_handlers.get_class_entry = zend_get_std_object_handlers()->get_class_entry; 2635 sxe_object_handlers.get_class_name = zend_get_std_object_handlers()->get_class_name; 2636 sxe_class_entry->serialize = zend_class_serialize_deny; 2637 sxe_class_entry->unserialize = zend_class_unserialize_deny; 2638 2639 php_libxml_register_export(sxe_class_entry, simplexml_export_node); 2640 2641 PHP_MINIT(sxe)(INIT_FUNC_ARGS_PASSTHRU); 2642 2643 return SUCCESS; 2644} 2645/* }}} */ 2646 2647/* {{{ PHP_MSHUTDOWN_FUNCTION(simplexml) 2648 */ 2649PHP_MSHUTDOWN_FUNCTION(simplexml) 2650{ 2651 sxe_class_entry = NULL; 2652 return SUCCESS; 2653} 2654/* }}} */ 2655 2656/* {{{ PHP_MINFO_FUNCTION(simplexml) 2657 */ 2658PHP_MINFO_FUNCTION(simplexml) 2659{ 2660 php_info_print_table_start(); 2661 php_info_print_table_header(2, "Simplexml support", "enabled"); 2662 php_info_print_table_row(2, "Revision", "$Id: 692516840b2d7d6e7aedb0bedded1f53b764a99f $"); 2663 php_info_print_table_row(2, "Schema support", 2664#ifdef LIBXML_SCHEMAS_ENABLED 2665 "enabled"); 2666#else 2667 "not available"); 2668#endif 2669 php_info_print_table_end(); 2670} 2671/* }}} */ 2672 2673#endif 2674 2675/** 2676 * Local Variables: 2677 * c-basic-offset: 4 2678 * tab-width: 4 2679 * indent-tabs-mode: t 2680 * End: 2681 * vim600: fdm=marker 2682 * vim: noet sw=4 ts=4 2683 */ 2684