You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1753 lines
44 KiB

23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
22 years ago
23 years ago
23 years ago
22 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
22 years ago
22 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
22 years ago
23 years ago
23 years ago
23 years ago
23 years ago
22 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
22 years ago
22 years ago
23 years ago
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2004 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.0 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_0.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. /* $Id$ */
  21. #ifdef HAVE_CONFIG_H
  22. #include "config.h"
  23. #endif
  24. #include "php.h"
  25. #if HAVE_LIBXML && HAVE_SIMPLEXML
  26. #include "php_ini.h"
  27. #include "ext/standard/info.h"
  28. #include "ext/standard/php_string.h"
  29. #include "php_simplexml.h"
  30. #include "php_simplexml_exports.h"
  31. #include "zend_exceptions.h"
  32. #include "zend_interfaces.h"
  33. #if HAVE_SPL && !defined(COMPILE_DL_SPL)
  34. #include "ext/spl/spl_sxe.h"
  35. #endif
  36. zend_class_entry *sxe_class_entry = NULL;
  37. ZEND_API zend_class_entry *sxe_get_element_class_entry()
  38. {
  39. return sxe_class_entry;
  40. }
  41. #define SXE_ME(func, arg_info, flags) PHP_ME(simplexml_element, func, arg_info, flags)
  42. #define SXE_METHOD(func) PHP_METHOD(simplexml_element, func)
  43. static php_sxe_object* php_sxe_object_new(zend_class_entry *ce TSRMLS_DC);
  44. static zend_object_value php_sxe_register_object(php_sxe_object * TSRMLS_DC);
  45. /* {{{ _node_as_zval()
  46. */
  47. static void _node_as_zval(php_sxe_object *sxe, xmlNodePtr node, zval *value, int itertype, char *name, char *prefix TSRMLS_DC)
  48. {
  49. php_sxe_object *subnode;
  50. subnode = php_sxe_object_new(sxe->zo.ce TSRMLS_CC);
  51. subnode->document = sxe->document;
  52. subnode->document->refcount++;
  53. subnode->iter.type = itertype;
  54. if (name) {
  55. subnode->iter.name = xmlStrdup(name);
  56. }
  57. if (prefix) {
  58. subnode->iter.nsprefix = xmlStrdup(prefix);
  59. }
  60. php_libxml_increment_node_ptr((php_libxml_node_object *)subnode, node, NULL TSRMLS_CC);
  61. value->type = IS_OBJECT;
  62. value->value.obj = php_sxe_register_object(subnode TSRMLS_CC);
  63. }
  64. /* }}} */
  65. #define APPEND_PREV_ELEMENT(__c, __v) \
  66. if ((__c) == 1) { \
  67. array_init(return_value); \
  68. add_next_index_zval(return_value, __v); \
  69. }
  70. #define APPEND_CUR_ELEMENT(__c, __v) \
  71. if (++(__c) > 1) { \
  72. add_next_index_zval(return_value, __v); \
  73. }
  74. #define GET_NODE(__s, __n) { \
  75. if ((__s)->node && (__s)->node->node) { \
  76. __n = (__s)->node->node; \
  77. } else { \
  78. __n = NULL; \
  79. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Node no longer exists"); \
  80. } \
  81. }
  82. static xmlNodePtr php_sxe_get_first_node(php_sxe_object *sxe, xmlNodePtr node TSRMLS_DC) {
  83. php_sxe_object *intern;
  84. xmlNodePtr retnode = NULL;
  85. if (sxe && sxe->iter.type != SXE_ITER_NONE) {
  86. php_sxe_reset_iterator(sxe TSRMLS_CC);
  87. if (sxe->iter.data) {
  88. intern = (php_sxe_object *)zend_object_store_get_object(sxe->iter.data TSRMLS_CC);
  89. GET_NODE(intern, retnode)
  90. }
  91. return retnode;
  92. } else {
  93. return node;
  94. }
  95. }
  96. /* {{{ match_ns()
  97. */
  98. static inline int
  99. match_ns(php_sxe_object *sxe, xmlNodePtr node, xmlChar *name)
  100. {
  101. if (name == NULL && (node->ns == NULL || node->ns->prefix == NULL)) {
  102. return 1;
  103. }
  104. if (node->ns && !xmlStrcmp(node->ns->href, name)) {
  105. return 1;
  106. }
  107. return 0;
  108. }
  109. /* }}} */
  110. /* {{{ sxe_get_element_node()
  111. */
  112. static xmlNodePtr sxe_get_element_by_offset(php_sxe_object *sxe, long offset, xmlNodePtr node) {
  113. long nodendx = 0;
  114. if (sxe->iter.type == SXE_ITER_NONE) {
  115. return NULL;
  116. }
  117. while (node && nodendx <= offset) {
  118. SKIP_TEXT(node)
  119. if (node->type == XML_ELEMENT_NODE && match_ns(sxe, node, sxe->iter.nsprefix)) {
  120. if (sxe->iter.type == SXE_ITER_CHILD || (
  121. sxe->iter.type == SXE_ITER_ELEMENT && !xmlStrcmp(node->name, sxe->iter.name))) {
  122. if (nodendx == offset) {
  123. break;
  124. }
  125. nodendx++;
  126. }
  127. }
  128. next_iter:
  129. node = node->next;
  130. }
  131. return node;
  132. }
  133. /* }}} */
  134. /* {{{ sxe_prop_dim_read()
  135. */
  136. static zval * sxe_prop_dim_read(zval *object, zval *member, zend_bool elements, zend_bool attribs, zend_bool silent TSRMLS_DC)
  137. {
  138. zval *return_value;
  139. php_sxe_object *sxe;
  140. char *name;
  141. xmlNodePtr node;
  142. xmlAttrPtr attr;
  143. zval tmp_zv;
  144. int nodendx = 0;
  145. sxe = php_sxe_fetch_object(object TSRMLS_CC);
  146. if (Z_TYPE_P(member) == IS_LONG) {
  147. if (sxe->iter.type != SXE_ITER_ATTRLIST) {
  148. attribs = 0;
  149. elements = 1;
  150. }
  151. } else {
  152. if (Z_TYPE_P(member) != IS_STRING) {
  153. tmp_zv = *member;
  154. zval_copy_ctor(&tmp_zv);
  155. member = &tmp_zv;
  156. convert_to_string(member);
  157. }
  158. }
  159. MAKE_STD_ZVAL(return_value);
  160. ZVAL_NULL(return_value);
  161. name = Z_STRVAL_P(member);
  162. GET_NODE(sxe, node);
  163. if (sxe->iter.type != SXE_ITER_CHILD && sxe->iter.type != SXE_ITER_ATTRLIST) {
  164. node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
  165. }
  166. if (node) {
  167. if (attribs) {
  168. if (Z_TYPE_P(member) == IS_LONG && sxe->iter.type != SXE_ITER_ATTRLIST) {
  169. attr = NULL;
  170. } else {
  171. attr = node->properties;
  172. if (Z_TYPE_P(member) == IS_LONG) {
  173. while (attr && nodendx <= Z_LVAL_P(member)) {
  174. if (match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix)) {
  175. if (nodendx == Z_LVAL_P(member)) {
  176. _node_as_zval(sxe, (xmlNodePtr) attr, return_value, SXE_ITER_NONE, NULL, sxe->iter.nsprefix TSRMLS_CC);
  177. break;
  178. }
  179. nodendx++;
  180. }
  181. attr = attr->next;
  182. }
  183. } else {
  184. while (attr) {
  185. if (!xmlStrcmp(attr->name, name) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix)) {
  186. _node_as_zval(sxe, (xmlNodePtr) attr, return_value, SXE_ITER_NONE, NULL, sxe->iter.nsprefix TSRMLS_CC);
  187. break;
  188. }
  189. attr = attr->next;
  190. }
  191. }
  192. }
  193. }
  194. if (elements) {
  195. if (!sxe->node) {
  196. php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, node, NULL TSRMLS_CC);
  197. }
  198. if (Z_TYPE_P(member) == IS_LONG) {
  199. if (sxe->iter.type == SXE_ITER_CHILD) {
  200. node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
  201. }
  202. node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node);
  203. if (node) {
  204. _node_as_zval(sxe, node, return_value, SXE_ITER_NONE, NULL, sxe->iter.nsprefix TSRMLS_CC);
  205. }
  206. } else {
  207. _node_as_zval(sxe, node, return_value, SXE_ITER_ELEMENT, name, sxe->iter.nsprefix TSRMLS_CC);
  208. }
  209. }
  210. }
  211. return_value->refcount = 0;
  212. return_value->is_ref = 0;
  213. if (member == &tmp_zv) {
  214. zval_dtor(&tmp_zv);
  215. }
  216. return return_value;
  217. }
  218. /* }}} */
  219. /* {{{ sxe_property_read()
  220. */
  221. static zval * sxe_property_read(zval *object, zval *member, int type TSRMLS_DC)
  222. {
  223. return sxe_prop_dim_read(object, member, 1, 0, type == BP_VAR_IS TSRMLS_CC);
  224. }
  225. /* }}} */
  226. /* {{{ sxe_dimension_read()
  227. */
  228. static zval * sxe_dimension_read(zval *object, zval *offset, int type TSRMLS_DC)
  229. {
  230. return sxe_prop_dim_read(object, offset, 0, 1, 0 TSRMLS_CC);
  231. }
  232. /* }}} */
  233. /* {{{ change_node_zval()
  234. */
  235. static void change_node_zval(xmlNodePtr node, zval *value TSRMLS_DC)
  236. {
  237. zval value_copy;
  238. switch (Z_TYPE_P(value)) {
  239. case IS_LONG:
  240. case IS_BOOL:
  241. case IS_DOUBLE:
  242. case IS_NULL:
  243. if (value->refcount > 1) {
  244. value_copy = *value;
  245. zval_copy_ctor(&value_copy);
  246. value = &value_copy;
  247. }
  248. convert_to_string(value);
  249. /* break missing intentionally */
  250. case IS_STRING:
  251. xmlNodeSetContentLen(node, Z_STRVAL_P(value), Z_STRLEN_P(value));
  252. if (value == &value_copy) {
  253. zval_dtor(value);
  254. }
  255. break;
  256. default:
  257. php_error_docref(NULL TSRMLS_CC, E_WARNING, "It is not possible to assign complex types to nodes");
  258. break;
  259. }
  260. }
  261. /* }}} */
  262. /* {{{ sxe_property_write()
  263. */
  264. static void sxe_prop_dim_write(zval *object, zval *member, zval *value, zend_bool elements, zend_bool attribs TSRMLS_DC)
  265. {
  266. php_sxe_object *sxe;
  267. char *name;
  268. xmlNodePtr node;
  269. xmlNodePtr newnode = NULL;
  270. xmlNodePtr tempnode;
  271. xmlAttrPtr attr = NULL;
  272. int counter = 0;
  273. int is_attr = 0;
  274. int nodendx = 0;
  275. zval tmp_zv, trim_zv;
  276. if (!member) {
  277. /* This happens when the user did: $sxe[] = $value
  278. * and could also be E_PARSE, but we use this only during parsing
  279. * and this is during runtime.
  280. */
  281. php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot create unnamed attribute");
  282. return;
  283. }
  284. sxe = php_sxe_fetch_object(object TSRMLS_CC);
  285. if (Z_TYPE_P(member) == IS_LONG) {
  286. if (sxe->iter.type != SXE_ITER_ATTRLIST) {
  287. attribs = 0;
  288. elements = 1;
  289. }
  290. } else {
  291. if (Z_TYPE_P(member) != IS_STRING) {
  292. trim_zv = *member;
  293. zval_copy_ctor(&trim_zv);
  294. convert_to_string(&trim_zv);
  295. php_trim(Z_STRVAL(trim_zv), Z_STRLEN(trim_zv), NULL, 0, &tmp_zv, 3 TSRMLS_CC);
  296. zval_dtor(&trim_zv);
  297. member = &tmp_zv;
  298. }
  299. if (!Z_STRLEN_P(member)) {
  300. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot write or create unnamed %s", attribs ? "attribute" : "element");
  301. if (member == &tmp_zv) {
  302. zval_dtor(&tmp_zv);
  303. }
  304. return;
  305. }
  306. }
  307. name = Z_STRVAL_P(member);
  308. GET_NODE(sxe, node);
  309. if (sxe->iter.type != SXE_ITER_ATTRLIST) {
  310. node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
  311. }
  312. if (node) {
  313. if (attribs) {
  314. attr = node->properties;
  315. if (Z_TYPE_P(member) == IS_LONG) {
  316. while (attr && nodendx <= Z_LVAL_P(member)) {
  317. if (match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix)) {
  318. if (nodendx == Z_LVAL_P(member)) {
  319. is_attr = 1;
  320. ++counter;
  321. break;
  322. }
  323. nodendx++;
  324. }
  325. attr = attr->next;
  326. }
  327. } else {
  328. while (attr) {
  329. if (!xmlStrcmp(attr->name, name) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix)) {
  330. is_attr = 1;
  331. ++counter;
  332. break;
  333. }
  334. attr = attr->next;
  335. }
  336. }
  337. }
  338. if (elements) {
  339. if (Z_TYPE_P(member) == IS_LONG) {
  340. newnode = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node);
  341. if (newnode) {
  342. ++counter;
  343. }
  344. } else {
  345. node = node->children;
  346. while (node) {
  347. SKIP_TEXT(node);
  348. if (!xmlStrcmp(node->name, name)) {
  349. newnode = node;
  350. ++counter;
  351. }
  352. next_iter:
  353. node = node->next;
  354. }
  355. }
  356. }
  357. if (counter == 1) {
  358. if (is_attr) {
  359. newnode = (xmlNodePtr) attr;
  360. }
  361. while ((tempnode = (xmlNodePtr) newnode->children)) {
  362. xmlUnlinkNode(tempnode);
  363. php_libxml_node_free_resource((xmlNodePtr) tempnode TSRMLS_CC);
  364. }
  365. change_node_zval(newnode, value TSRMLS_CC);
  366. } else if (counter > 1) {
  367. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot assign to an array of nodes (duplicate subnodes or attr detected)\n");
  368. } else {
  369. if (attribs) {
  370. switch (Z_TYPE_P(value)) {
  371. case IS_LONG:
  372. case IS_BOOL:
  373. case IS_DOUBLE:
  374. case IS_NULL:
  375. convert_to_string(value);
  376. case IS_STRING:
  377. newnode = (xmlNodePtr)xmlNewProp(node, name, Z_STRVAL_P(value));
  378. break;
  379. default:
  380. php_error_docref(NULL TSRMLS_CC, E_WARNING, "It is not yet possible to assign complex types to attributes");
  381. }
  382. }
  383. }
  384. }
  385. if (member == &tmp_zv) {
  386. zval_dtor(&tmp_zv);
  387. }
  388. }
  389. /* }}} */
  390. /* {{{ sxe_property_write()
  391. */
  392. static void sxe_property_write(zval *object, zval *member, zval *value TSRMLS_DC)
  393. {
  394. sxe_prop_dim_write(object, member, value, 1, 0 TSRMLS_CC);
  395. }
  396. /* }}} */
  397. /* {{{ sxe_dimension_write()
  398. */
  399. static void sxe_dimension_write(zval *object, zval *offset, zval *value TSRMLS_DC)
  400. {
  401. sxe_prop_dim_write(object, offset, value, 0, 1 TSRMLS_CC);
  402. }
  403. /* }}} */
  404. /* {{{ sxe_prop_dim_exists()
  405. */
  406. static int sxe_prop_dim_exists(zval *object, zval *member, int check_empty, zend_bool elements, zend_bool attribs TSRMLS_DC)
  407. {
  408. php_sxe_object *sxe;
  409. char *name;
  410. xmlNodePtr node;
  411. xmlAttrPtr attr = NULL;
  412. int exists = 0;
  413. sxe = php_sxe_fetch_object(object TSRMLS_CC);
  414. name = Z_STRVAL_P(member);
  415. GET_NODE(sxe, node);
  416. if (Z_TYPE_P(member) == IS_LONG) {
  417. if (sxe->iter.type != SXE_ITER_ATTRLIST) {
  418. attribs = 0;
  419. elements = 1;
  420. if (sxe->iter.type == SXE_ITER_CHILD) {
  421. node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
  422. }
  423. }
  424. }
  425. if (sxe->iter.type != SXE_ITER_CHILD && sxe->iter.type != SXE_ITER_ATTRLIST) {
  426. node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
  427. }
  428. if (node) {
  429. if (attribs) {
  430. attr = node->properties;
  431. while (attr) {
  432. if (!xmlStrcmp(attr->name, name) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix)) {
  433. exists = 1;
  434. break;
  435. }
  436. attr = attr->next;
  437. }
  438. }
  439. if (elements) {
  440. if (Z_TYPE_P(member) == IS_LONG) {
  441. if (sxe->iter.type == SXE_ITER_CHILD) {
  442. node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
  443. }
  444. node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node);
  445. }
  446. else {
  447. if (Z_TYPE_P(member) != IS_STRING) {
  448. zval tmp_zv = *member;
  449. zval_copy_ctor(&tmp_zv);
  450. member = &tmp_zv;
  451. convert_to_string(member);
  452. }
  453. node = node->children;
  454. while (node) {
  455. xmlNodePtr nnext;
  456. nnext = node->next;
  457. if (!xmlStrcmp(node->name, Z_STRVAL_P(member))) {
  458. break;
  459. }
  460. node = nnext;
  461. }
  462. }
  463. if (node) {
  464. exists = 1;
  465. }
  466. }
  467. }
  468. return exists;
  469. }
  470. /* }}} */
  471. /* {{{ sxe_property_exists()
  472. */
  473. static int sxe_property_exists(zval *object, zval *member, int check_empty TSRMLS_DC)
  474. {
  475. return sxe_prop_dim_exists(object, member, check_empty, 1, 0 TSRMLS_CC);
  476. }
  477. /* }}} */
  478. /* {{{ sxe_property_exists()
  479. */
  480. static int sxe_dimension_exists(zval *object, zval *member, int check_empty TSRMLS_DC)
  481. {
  482. return sxe_prop_dim_exists(object, member, check_empty, 0, 1 TSRMLS_CC);
  483. }
  484. /* }}} */
  485. /* {{{ sxe_prop_dim_delete()
  486. */
  487. static void sxe_prop_dim_delete(zval *object, zval *member, zend_bool elements, zend_bool attribs TSRMLS_DC)
  488. {
  489. php_sxe_object *sxe;
  490. xmlNodePtr node;
  491. xmlNodePtr nnext;
  492. xmlAttrPtr attr;
  493. xmlAttrPtr anext;
  494. zval tmp_zv;
  495. if (Z_TYPE_P(member) != IS_STRING) {
  496. tmp_zv = *member;
  497. zval_copy_ctor(&tmp_zv);
  498. member = &tmp_zv;
  499. convert_to_string(member);
  500. }
  501. sxe = php_sxe_fetch_object(object TSRMLS_CC);
  502. GET_NODE(sxe, node);
  503. node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
  504. if (node) {
  505. if (attribs) {
  506. attr = node->properties;
  507. while (attr) {
  508. anext = attr->next;
  509. if (!xmlStrcmp(attr->name, Z_STRVAL_P(member)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix)) {
  510. xmlUnlinkNode((xmlNodePtr) attr);
  511. php_libxml_node_free_resource((xmlNodePtr) attr TSRMLS_CC);
  512. break;
  513. }
  514. attr = anext;
  515. }
  516. }
  517. if (elements) {
  518. node = node->children;
  519. while (node) {
  520. nnext = node->next;
  521. SKIP_TEXT(node);
  522. if (!xmlStrcmp(node->name, Z_STRVAL_P(member))) {
  523. xmlUnlinkNode(node);
  524. php_libxml_node_free_resource(node TSRMLS_CC);
  525. }
  526. next_iter:
  527. node = nnext;
  528. }
  529. }
  530. }
  531. if (member == &tmp_zv) {
  532. zval_dtor(&tmp_zv);
  533. }
  534. }
  535. /* }}} */
  536. /* {{{ sxe_property_delete()
  537. */
  538. static void sxe_property_delete(zval *object, zval *member TSRMLS_DC)
  539. {
  540. sxe_prop_dim_delete(object, member, 1, 0 TSRMLS_CC);
  541. }
  542. /* }}} */
  543. /* {{{ sxe_dimension_unset()
  544. */
  545. static void sxe_dimension_delete(zval *object, zval *offset TSRMLS_DC)
  546. {
  547. sxe_prop_dim_delete(object, offset, 0, 1 TSRMLS_CC);
  548. }
  549. /* }}} */
  550. /* {{{ _get_base_node_value()
  551. */
  552. static void
  553. _get_base_node_value(php_sxe_object *sxe_ref, xmlNodePtr node, zval **value TSRMLS_DC)
  554. {
  555. php_sxe_object *subnode;
  556. xmlChar *contents;
  557. MAKE_STD_ZVAL(*value);
  558. if (node->children && node->children->type == XML_TEXT_NODE && !xmlIsBlankNode(node->children)) {
  559. contents = xmlNodeListGetString(node->doc, node->children, 1);
  560. if (contents) {
  561. ZVAL_STRING(*value, contents, 1);
  562. xmlFree(contents);
  563. }
  564. } else {
  565. subnode = php_sxe_object_new(sxe_ref->zo.ce TSRMLS_CC);
  566. subnode->document = sxe_ref->document;
  567. subnode->document->refcount++;
  568. php_libxml_increment_node_ptr((php_libxml_node_object *)subnode, node, NULL TSRMLS_CC);
  569. (*value)->type = IS_OBJECT;
  570. (*value)->value.obj = php_sxe_register_object(subnode TSRMLS_CC);
  571. /*zval_add_ref(value);*/
  572. }
  573. }
  574. /* }}} */
  575. /* {{{ sxe_properties_get()
  576. */
  577. static HashTable *
  578. sxe_properties_get(zval *object TSRMLS_DC)
  579. {
  580. zval **data_ptr;
  581. zval *value;
  582. zval *newptr;
  583. HashTable *rv;
  584. php_sxe_object *sxe;
  585. char *name;
  586. xmlNodePtr node;
  587. ulong h;
  588. int namelen;
  589. sxe = php_sxe_fetch_object(object TSRMLS_CC);
  590. if (sxe->properties) {
  591. zend_hash_clean(sxe->properties);
  592. rv = sxe->properties;
  593. } else {
  594. ALLOC_HASHTABLE(rv);
  595. zend_hash_init(rv, 0, NULL, ZVAL_PTR_DTOR, 0);
  596. sxe->properties = rv;
  597. }
  598. GET_NODE(sxe, node);
  599. node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
  600. if (node) {
  601. node = node->children;
  602. while (node) {
  603. if (node->children != NULL || node->prev != NULL || node->next != NULL) {
  604. SKIP_TEXT(node);
  605. } else {
  606. if (node->type == XML_TEXT_NODE) {
  607. MAKE_STD_ZVAL(value);
  608. ZVAL_STRING(value, xmlNodeListGetString(node->doc, node, 1), 1);
  609. zend_hash_next_index_insert(rv, &value, sizeof(zval *), NULL);
  610. goto next_iter;
  611. }
  612. }
  613. name = (char *) node->name;
  614. if (!name) {
  615. goto next_iter;
  616. } else {
  617. namelen = xmlStrlen(node->name) + 1;
  618. }
  619. _get_base_node_value(sxe, node, &value TSRMLS_CC);
  620. h = zend_hash_func(name, namelen);
  621. if (zend_hash_quick_find(rv, name, namelen, h, (void **) &data_ptr) == SUCCESS) {
  622. if (Z_TYPE_PP(data_ptr) == IS_ARRAY) {
  623. zend_hash_next_index_insert(Z_ARRVAL_PP(data_ptr), &value, sizeof(zval *), NULL);
  624. } else {
  625. MAKE_STD_ZVAL(newptr);
  626. array_init(newptr);
  627. zval_add_ref(data_ptr);
  628. zend_hash_next_index_insert(Z_ARRVAL_P(newptr), data_ptr, sizeof(zval *), NULL);
  629. zend_hash_next_index_insert(Z_ARRVAL_P(newptr), &value, sizeof(zval *), NULL);
  630. zend_hash_quick_update(rv, name, namelen, h, &newptr, sizeof(zval *), NULL);
  631. }
  632. } else {
  633. zend_hash_quick_update(rv, name, namelen, h, &value, sizeof(zval *), NULL);
  634. }
  635. next_iter:
  636. node = node->next;
  637. }
  638. }
  639. return rv;
  640. }
  641. /* }}} */
  642. /* {{{ sxe_objects_compare()
  643. */
  644. static int
  645. sxe_objects_compare(zval *object1, zval *object2 TSRMLS_DC)
  646. {
  647. php_sxe_object *sxe1;
  648. php_sxe_object *sxe2;
  649. sxe1 = php_sxe_fetch_object(object1 TSRMLS_CC);
  650. sxe2 = php_sxe_fetch_object(object2 TSRMLS_CC);
  651. if (sxe1->node == NULL) {
  652. if (sxe2->node) {
  653. return 1;
  654. } else if (sxe1->document->ptr == sxe2->document->ptr) {
  655. return 0;
  656. }
  657. } else {
  658. return !(sxe1->node == sxe2->node);
  659. }
  660. return 1;
  661. }
  662. /* }}} */
  663. /* {{{ array SimpleXMLElement::xpath(string path)
  664. Runs XPath query on the XML data */
  665. SXE_METHOD(xpath)
  666. {
  667. php_sxe_object *sxe;
  668. zval *value;
  669. char *query;
  670. int query_len;
  671. int i;
  672. int nsnbr = 0;
  673. xmlNsPtr *ns = NULL;
  674. xmlXPathObjectPtr retval;
  675. xmlNodeSetPtr result;
  676. xmlNodePtr nodeptr;
  677. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &query, &query_len) == FAILURE) {
  678. return;
  679. }
  680. sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
  681. if (!sxe->xpath) {
  682. sxe->xpath = xmlXPathNewContext((xmlDocPtr) sxe->document->ptr);
  683. }
  684. if (!sxe->node) {
  685. php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement((xmlDocPtr) sxe->document->ptr), NULL TSRMLS_CC);
  686. }
  687. sxe->xpath->node = sxe->node->node;
  688. ns = xmlGetNsList((xmlDocPtr) sxe->document->ptr, (xmlNodePtr) sxe->node->node);
  689. if (ns != NULL) {
  690. while (ns[nsnbr] != NULL) {
  691. nsnbr++;
  692. }
  693. }
  694. sxe->xpath->namespaces = ns;
  695. sxe->xpath->nsNr = nsnbr;
  696. retval = xmlXPathEval(query, sxe->xpath);
  697. if (ns != NULL) {
  698. xmlFree(ns);
  699. sxe->xpath->namespaces = NULL;
  700. sxe->xpath->nsNr = 0;
  701. }
  702. if (!retval) {
  703. RETURN_FALSE;
  704. }
  705. result = retval->nodesetval;
  706. if (!result) {
  707. xmlXPathFreeObject(retval);
  708. RETURN_FALSE;
  709. }
  710. array_init(return_value);
  711. for (i = 0; i < result->nodeNr; ++i) {
  712. nodeptr = result->nodeTab[i];
  713. if (nodeptr->type == XML_TEXT_NODE || nodeptr->type == XML_ELEMENT_NODE || nodeptr->type == XML_ATTRIBUTE_NODE) {
  714. MAKE_STD_ZVAL(value);
  715. /**
  716. * Detect the case where the last selector is text(), simplexml
  717. * always accesses the text() child by default, therefore we assign
  718. * to the parent node.
  719. */
  720. if (nodeptr->type == XML_TEXT_NODE) {
  721. _node_as_zval(sxe, nodeptr->parent, value, SXE_ITER_NONE, NULL, NULL TSRMLS_CC);
  722. } else {
  723. _node_as_zval(sxe, nodeptr, value, SXE_ITER_NONE, NULL, NULL TSRMLS_CC);
  724. }
  725. add_next_index_zval(return_value, value);
  726. }
  727. }
  728. xmlXPathFreeObject(retval);
  729. }
  730. SXE_METHOD(registerXPathNamespace)
  731. {
  732. php_sxe_object *sxe;
  733. int prefix_len, ns_uri_len;
  734. char *prefix, *ns_uri;
  735. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &prefix, &prefix_len, &ns_uri, &ns_uri_len) == FAILURE) {
  736. return;
  737. }
  738. sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
  739. if (!sxe->xpath) {
  740. sxe->xpath = xmlXPathNewContext((xmlDocPtr) sxe->document->ptr);
  741. }
  742. if (xmlXPathRegisterNs(sxe->xpath, prefix, ns_uri) != 0) {
  743. RETURN_FALSE
  744. }
  745. RETURN_TRUE;
  746. }
  747. /* }}} */
  748. /* {{{ proto string SimpleXMLElement::asXML([string filename])
  749. Return a well-formed XML string based on SimpleXML element */
  750. SXE_METHOD(asXML)
  751. {
  752. php_sxe_object *sxe;
  753. xmlNodePtr node;
  754. xmlOutputBufferPtr outbuf;
  755. xmlChar *strval;
  756. int strval_len;
  757. char *filename;
  758. int filename_len;
  759. if (ZEND_NUM_ARGS() > 1) {
  760. RETURN_FALSE;
  761. }
  762. if (ZEND_NUM_ARGS() == 1) {
  763. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
  764. RETURN_FALSE;
  765. }
  766. sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
  767. GET_NODE(sxe, node);
  768. node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
  769. if (node) {
  770. if (XML_DOCUMENT_NODE == node->parent->type) {
  771. xmlSaveFile(filename, (xmlDocPtr) sxe->document->ptr);
  772. } else {
  773. outbuf = xmlOutputBufferCreateFilename(filename, NULL, 0);
  774. if (outbuf == NULL) {
  775. RETURN_FALSE;
  776. }
  777. xmlNodeDumpOutput(outbuf, (xmlDocPtr) sxe->document->ptr, node, 0, 1, NULL);
  778. xmlOutputBufferClose(outbuf);
  779. RETURN_TRUE;
  780. }
  781. } else {
  782. RETURN_FALSE;
  783. }
  784. }
  785. sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
  786. GET_NODE(sxe, node);
  787. node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
  788. if (node) {
  789. if (XML_DOCUMENT_NODE == node->parent->type) {
  790. xmlDocDumpMemory((xmlDocPtr) sxe->document->ptr, &strval, &strval_len);
  791. } else {
  792. /* Should we be passing encoding information instead of NULL? */
  793. outbuf = xmlAllocOutputBuffer(NULL);
  794. if (outbuf == NULL) {
  795. RETURN_FALSE;
  796. }
  797. xmlNodeDumpOutput(outbuf, (xmlDocPtr) sxe->document->ptr, node, 0, 1, ((xmlDocPtr) sxe->document->ptr)->encoding);
  798. xmlOutputBufferFlush(outbuf);
  799. strval = xmlStrndup(outbuf->buffer->content, outbuf->buffer->use);
  800. xmlOutputBufferClose(outbuf);
  801. }
  802. RETVAL_STRINGL(strval, strlen(strval), 1);
  803. xmlFree(strval);
  804. } else {
  805. RETVAL_FALSE;
  806. }
  807. }
  808. /* }}} */
  809. /* {{{ proto object SimpleXMLElement::children()
  810. Finds children of given node */
  811. SXE_METHOD(children)
  812. {
  813. php_sxe_object *sxe;
  814. char *nsprefix = NULL;
  815. int nsprefix_len;
  816. xmlNodePtr node;
  817. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &nsprefix, &nsprefix_len) == FAILURE) {
  818. return;
  819. }
  820. sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
  821. GET_NODE(sxe, node);
  822. node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
  823. _node_as_zval(sxe, node, return_value, SXE_ITER_CHILD, NULL, nsprefix TSRMLS_CC);
  824. }
  825. /* }}} */
  826. /* {{{ proto array SimpleXMLElement::attributes([string ns])
  827. Identifies an element's attributes */
  828. SXE_METHOD(attributes)
  829. {
  830. php_sxe_object *sxe;
  831. char *nsprefix = NULL;
  832. int nsprefix_len;
  833. xmlNodePtr node;
  834. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &nsprefix, &nsprefix_len) == FAILURE) {
  835. return;
  836. }
  837. sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
  838. GET_NODE(sxe, node);
  839. node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
  840. _node_as_zval(sxe, node, return_value, SXE_ITER_ATTRLIST, NULL, nsprefix TSRMLS_CC);
  841. }
  842. /* }}} */
  843. /* {{{ cast_object()
  844. */
  845. static int
  846. cast_object(zval *object, int type, char *contents TSRMLS_DC)
  847. {
  848. if (contents) {
  849. ZVAL_STRINGL(object, contents, strlen(contents), 1);
  850. } else {
  851. ZVAL_NULL(object);
  852. }
  853. object->refcount = 1;
  854. object->is_ref = 0;
  855. switch (type) {
  856. case IS_STRING:
  857. convert_to_string(object);
  858. break;
  859. case IS_BOOL:
  860. convert_to_boolean(object);
  861. break;
  862. case IS_LONG:
  863. convert_to_long(object);
  864. break;
  865. case IS_DOUBLE:
  866. convert_to_double(object);
  867. break;
  868. default:
  869. return FAILURE;
  870. }
  871. return SUCCESS;
  872. }
  873. /* }}} */
  874. /* {{{ sxe_object_cast()
  875. */
  876. static int
  877. sxe_object_cast(zval *readobj, zval *writeobj, int type, int should_free TSRMLS_DC)
  878. {
  879. php_sxe_object *sxe;
  880. char *contents = NULL;
  881. xmlNodePtr node;
  882. zval free_obj;
  883. int rv;
  884. sxe = php_sxe_fetch_object(readobj TSRMLS_CC);
  885. if (should_free) {
  886. free_obj = *writeobj;
  887. }
  888. if (sxe->iter.type != SXE_ITER_NONE) {
  889. node = php_sxe_get_first_node(sxe, NULL TSRMLS_CC);
  890. if (node) {
  891. contents = xmlNodeListGetString((xmlDocPtr) sxe->document->ptr, node->children, 1);
  892. }
  893. } else {
  894. if (!sxe->node) {
  895. if (sxe->document) {
  896. php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement((xmlDocPtr) sxe->document->ptr), NULL TSRMLS_CC);
  897. }
  898. }
  899. if (sxe->node && sxe->node->node) {
  900. if (sxe->node->node->children) {
  901. contents = xmlNodeListGetString((xmlDocPtr) sxe->document->ptr, sxe->node->node->children, 1);
  902. }
  903. }
  904. }
  905. rv = cast_object(writeobj, type, contents TSRMLS_CC);
  906. if (contents) {
  907. xmlFree(contents);
  908. }
  909. if (should_free) {
  910. zval_dtor(&free_obj);
  911. }
  912. return rv;
  913. }
  914. /* }}} */
  915. static zval *sxe_get_value(zval *z TSRMLS_DC)
  916. {
  917. zval *retval;
  918. MAKE_STD_ZVAL(retval);
  919. if (sxe_object_cast(z, retval, IS_STRING, 0 TSRMLS_CC)==FAILURE) {
  920. zend_error(E_ERROR, "Unable to cast node to string");
  921. }
  922. retval->refcount = 0;
  923. return retval;
  924. }
  925. static zend_object_handlers sxe_object_handlers = {
  926. ZEND_OBJECTS_STORE_HANDLERS,
  927. sxe_property_read,
  928. sxe_property_write,
  929. sxe_dimension_read,
  930. sxe_dimension_write,
  931. NULL,
  932. sxe_get_value, /* get */
  933. NULL,
  934. sxe_property_exists,
  935. sxe_property_delete,
  936. sxe_dimension_exists,
  937. sxe_dimension_delete,
  938. sxe_properties_get,
  939. NULL, /* zend_get_std_object_handlers()->get_method,*/
  940. NULL, /* zend_get_std_object_handlers()->call_method,*/
  941. NULL, /* zend_get_std_object_handlers()->get_constructor, */
  942. NULL, /* zend_get_std_object_handlers()->get_class_entry,*/
  943. NULL, /* zend_get_std_object_handlers()->get_class_name,*/
  944. sxe_objects_compare,
  945. sxe_object_cast,
  946. NULL
  947. };
  948. static zend_object_handlers sxe_ze1_object_handlers = {
  949. ZEND_OBJECTS_STORE_HANDLERS,
  950. sxe_property_read,
  951. sxe_property_write,
  952. sxe_dimension_read,
  953. sxe_dimension_write,
  954. NULL,
  955. sxe_get_value, /* get */
  956. NULL,
  957. sxe_property_exists,
  958. sxe_property_delete,
  959. sxe_dimension_exists,
  960. sxe_dimension_delete,
  961. sxe_properties_get,
  962. NULL, /* zend_get_std_object_handlers()->get_method,*/
  963. NULL, /* zend_get_std_object_handlers()->call_method,*/
  964. NULL, /* zend_get_std_object_handlers()->get_constructor, */
  965. NULL, /* zend_get_std_object_handlers()->get_class_entry,*/
  966. NULL, /* zend_get_std_object_handlers()->get_class_name,*/
  967. sxe_objects_compare,
  968. sxe_object_cast,
  969. NULL
  970. };
  971. static zend_object_value sxe_object_ze1_clone(zval *zobject TSRMLS_DC)
  972. {
  973. php_error(E_ERROR, "Cannot clone object of class %s due to 'zend.ze1_compatibility_mode'", Z_OBJCE_P(zobject)->name);
  974. /* Return zobject->value.obj just to satisfy compiler */
  975. return zobject->value.obj;
  976. }
  977. /* {{{ sxe_object_clone()
  978. */
  979. static void
  980. sxe_object_clone(void *object, void **clone_ptr TSRMLS_DC)
  981. {
  982. php_sxe_object *sxe = (php_sxe_object *) object;
  983. php_sxe_object *clone;
  984. xmlNodePtr nodep = NULL;
  985. xmlDocPtr docp = NULL;
  986. clone = php_sxe_object_new(sxe->zo.ce TSRMLS_CC);
  987. clone->document = sxe->document;
  988. if (clone->document) {
  989. clone->document->refcount++;
  990. docp = clone->document->ptr;
  991. }
  992. if (sxe->node) {
  993. nodep = xmlDocCopyNode(sxe->node->node, docp, 1);
  994. }
  995. php_libxml_increment_node_ptr((php_libxml_node_object *)clone, nodep, NULL TSRMLS_CC);
  996. *clone_ptr = (void *) clone;
  997. }
  998. /* }}} */
  999. /* {{{ sxe_object_dtor()
  1000. */
  1001. static void sxe_object_dtor(void *object, zend_object_handle handle TSRMLS_DC)
  1002. {
  1003. /* dtor required to cleanup iterator related data properly */
  1004. php_sxe_object *sxe;
  1005. sxe = (php_sxe_object *) object;
  1006. if (sxe->iter.data) {
  1007. zval_ptr_dtor(&sxe->iter.data);
  1008. sxe->iter.data = NULL;
  1009. }
  1010. if (sxe->iter.name) {
  1011. xmlFree(sxe->iter.name);
  1012. sxe->iter.name = NULL;
  1013. }
  1014. if (sxe->iter.nsprefix) {
  1015. xmlFree(sxe->iter.nsprefix);
  1016. sxe->iter.nsprefix = NULL;
  1017. }
  1018. }
  1019. /* {{{ sxe_object_free_storage()
  1020. */
  1021. static void sxe_object_free_storage(void *object TSRMLS_DC)
  1022. {
  1023. php_sxe_object *sxe;
  1024. sxe = (php_sxe_object *) object;
  1025. zend_hash_destroy(sxe->zo.properties);
  1026. FREE_HASHTABLE(sxe->zo.properties);
  1027. php_libxml_node_decrement_resource((php_libxml_node_object *)sxe TSRMLS_CC);
  1028. if (sxe->xpath) {
  1029. xmlXPathFreeContext(sxe->xpath);
  1030. }
  1031. if (sxe->properties) {
  1032. zend_hash_destroy(sxe->properties);
  1033. FREE_HASHTABLE(sxe->properties);
  1034. }
  1035. efree(object);
  1036. }
  1037. /* }}} */
  1038. /* {{{ php_sxe_object_new()
  1039. */
  1040. static php_sxe_object* php_sxe_object_new(zend_class_entry *ce TSRMLS_DC)
  1041. {
  1042. php_sxe_object *intern;
  1043. intern = ecalloc(1, sizeof(php_sxe_object));
  1044. intern->zo.ce = ce;
  1045. intern->iter.type = SXE_ITER_NONE;
  1046. intern->iter.nsprefix = NULL;
  1047. intern->iter.name = NULL;
  1048. ALLOC_HASHTABLE(intern->zo.properties);
  1049. zend_hash_init(intern->zo.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
  1050. return intern;
  1051. }
  1052. /* }}} */
  1053. /* {{{ php_sxe_register_object
  1054. */
  1055. static zend_object_value
  1056. php_sxe_register_object(php_sxe_object *intern TSRMLS_DC)
  1057. {
  1058. zend_object_value rv;
  1059. 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);
  1060. if (EG(ze1_compatibility_mode)) {
  1061. rv.handlers = (zend_object_handlers *) &sxe_ze1_object_handlers;
  1062. } else {
  1063. rv.handlers = (zend_object_handlers *) &sxe_object_handlers;
  1064. }
  1065. return rv;
  1066. }
  1067. /* }}} */
  1068. /* {{{ sxe_object_new()
  1069. */
  1070. ZEND_API zend_object_value
  1071. sxe_object_new(zend_class_entry *ce TSRMLS_DC)
  1072. {
  1073. php_sxe_object *intern;
  1074. intern = php_sxe_object_new(ce TSRMLS_CC);
  1075. return php_sxe_register_object(intern TSRMLS_CC);
  1076. }
  1077. /* }}} */
  1078. /* {{{ proto simplemxml_element simplexml_load_file(string filename [, string class_name [, int options]])
  1079. Load a filename and return a simplexml_element object to allow for processing */
  1080. PHP_FUNCTION(simplexml_load_file)
  1081. {
  1082. php_sxe_object *sxe;
  1083. char *filename;
  1084. int filename_len;
  1085. xmlDocPtr docp;
  1086. char *classname = "";
  1087. int classname_len = 0, options=0;
  1088. zend_class_entry *ce= sxe_class_entry;
  1089. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|sl", &filename, &filename_len, &classname, &classname_len, &options) == FAILURE) {
  1090. return;
  1091. }
  1092. #if LIBXML_VERSION >= 20600
  1093. docp = xmlReadFile(filename, NULL, options);
  1094. #else
  1095. docp = xmlParseFile(filename);
  1096. #endif
  1097. if (! docp) {
  1098. RETURN_FALSE;
  1099. }
  1100. if (classname_len) {
  1101. zend_class_entry **pce;
  1102. if (zend_lookup_class(classname, classname_len, &pce TSRMLS_CC) == FAILURE) {
  1103. php_error_docref(NULL TSRMLS_CC, E_ERROR, "Class %s does not exist", classname);
  1104. }
  1105. ce = *pce;
  1106. }
  1107. sxe = php_sxe_object_new(ce TSRMLS_CC);
  1108. php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp TSRMLS_CC);
  1109. php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL TSRMLS_CC);
  1110. return_value->type = IS_OBJECT;
  1111. return_value->value.obj = php_sxe_register_object(sxe TSRMLS_CC);
  1112. }
  1113. /* }}} */
  1114. /* {{{ proto simplemxml_element simplexml_load_string(string data [, string class_name [, int options]])
  1115. Load a string and return a simplexml_element object to allow for processing */
  1116. PHP_FUNCTION(simplexml_load_string)
  1117. {
  1118. php_sxe_object *sxe;
  1119. char *data;
  1120. int data_len;
  1121. xmlDocPtr docp;
  1122. char *classname = "";
  1123. int classname_len = 0, options=0;
  1124. zend_class_entry *ce= sxe_class_entry;
  1125. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|sl", &data, &data_len, &classname, &classname_len, &options) == FAILURE) {
  1126. return;
  1127. }
  1128. #if LIBXML_VERSION >= 20600
  1129. docp = xmlReadMemory(data, data_len, NULL, NULL, options);
  1130. #else
  1131. docp = xmlParseMemory(data, data_len);
  1132. #endif
  1133. if (! docp) {
  1134. RETURN_FALSE;
  1135. }
  1136. if (classname_len) {
  1137. zend_class_entry **pce;
  1138. if (zend_lookup_class(classname, classname_len, &pce TSRMLS_CC) == FAILURE) {
  1139. php_error_docref(NULL TSRMLS_CC, E_ERROR, "Class %s does not exist", classname);
  1140. }
  1141. ce = *pce;
  1142. }
  1143. sxe = php_sxe_object_new(ce TSRMLS_CC);
  1144. php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp TSRMLS_CC);
  1145. php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL TSRMLS_CC);
  1146. return_value->type = IS_OBJECT;
  1147. return_value->value.obj = php_sxe_register_object(sxe TSRMLS_CC);
  1148. }
  1149. /* }}} */
  1150. /* {{{ proto SimpleXMLElement::__construct()
  1151. SimpleXMLElement constructor */
  1152. SXE_METHOD(__construct)
  1153. {
  1154. php_sxe_object *sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
  1155. char *data;
  1156. int data_len;
  1157. xmlDocPtr docp;
  1158. php_set_error_handling(EH_THROW, zend_exception_get_default() TSRMLS_CC);
  1159. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len) == FAILURE) {
  1160. php_std_error_handling();
  1161. return;
  1162. }
  1163. php_std_error_handling();
  1164. docp = xmlParseMemory(data, data_len);
  1165. if (!docp) {
  1166. ((php_libxml_node_object *)sxe)->document = NULL;
  1167. zend_throw_exception(zend_exception_get_default(), "String could not be parsed as XML", 0 TSRMLS_CC);
  1168. return;
  1169. }
  1170. php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp TSRMLS_CC);
  1171. php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, xmlDocGetRootElement(docp), NULL TSRMLS_CC);
  1172. }
  1173. /* }}} */
  1174. typedef struct {
  1175. zend_object_iterator intern;
  1176. php_sxe_object *sxe;
  1177. } php_sxe_iterator;
  1178. static void php_sxe_iterator_dtor(zend_object_iterator *iter TSRMLS_DC);
  1179. static int php_sxe_iterator_valid(zend_object_iterator *iter TSRMLS_DC);
  1180. static void php_sxe_iterator_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC);
  1181. static int php_sxe_iterator_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC);
  1182. static void php_sxe_iterator_move_forward(zend_object_iterator *iter TSRMLS_DC);
  1183. static void php_sxe_iterator_rewind(zend_object_iterator *iter TSRMLS_DC);
  1184. zend_object_iterator_funcs php_sxe_iterator_funcs = {
  1185. php_sxe_iterator_dtor,
  1186. php_sxe_iterator_valid,
  1187. php_sxe_iterator_current_data,
  1188. php_sxe_iterator_current_key,
  1189. php_sxe_iterator_move_forward,
  1190. php_sxe_iterator_rewind,
  1191. };
  1192. ZEND_API void php_sxe_reset_iterator(php_sxe_object *sxe TSRMLS_DC)
  1193. {
  1194. xmlNodePtr node;
  1195. char *prefix;
  1196. if (sxe->iter.data) {
  1197. zval_ptr_dtor(&sxe->iter.data);
  1198. sxe->iter.data = NULL;
  1199. }
  1200. GET_NODE(sxe, node)
  1201. if (node) {
  1202. switch (sxe->iter.type) {
  1203. case SXE_ITER_ELEMENT:
  1204. case SXE_ITER_CHILD:
  1205. case SXE_ITER_NONE:
  1206. node = node->children;
  1207. break;
  1208. case SXE_ITER_ATTRLIST:
  1209. node = (xmlNodePtr) node->properties;
  1210. }
  1211. }
  1212. prefix = sxe->iter.nsprefix;
  1213. while (node) {
  1214. SKIP_TEXT(node);
  1215. if (sxe->iter.type != SXE_ITER_ATTRLIST && node->type == XML_ELEMENT_NODE) {
  1216. if (sxe->iter.type == SXE_ITER_ELEMENT) {
  1217. if (!xmlStrcmp(node->name, sxe->iter.name) && match_ns(sxe, node, prefix)) {
  1218. break;
  1219. }
  1220. } else {
  1221. if (match_ns(sxe, node, prefix)) {
  1222. break;
  1223. }
  1224. }
  1225. } else {
  1226. if (node->type == XML_ATTRIBUTE_NODE) {
  1227. if (match_ns(sxe, node, sxe->iter.nsprefix)) {
  1228. break;
  1229. }
  1230. }
  1231. }
  1232. next_iter:
  1233. node = node->next;
  1234. }
  1235. if (node) {
  1236. ALLOC_INIT_ZVAL(sxe->iter.data);
  1237. _node_as_zval(sxe, node, sxe->iter.data, SXE_ITER_NONE, NULL, sxe->iter.nsprefix TSRMLS_CC);
  1238. }
  1239. }
  1240. zend_object_iterator *php_sxe_get_iterator(zend_class_entry *ce, zval *object TSRMLS_DC)
  1241. {
  1242. php_sxe_iterator *iterator = emalloc(sizeof(php_sxe_iterator));
  1243. object->refcount++;
  1244. iterator->intern.data = (void*)object;
  1245. iterator->intern.funcs = &php_sxe_iterator_funcs;
  1246. iterator->sxe = php_sxe_fetch_object(object TSRMLS_CC);
  1247. return (zend_object_iterator*)iterator;
  1248. }
  1249. static void php_sxe_iterator_dtor(zend_object_iterator *iter TSRMLS_DC)
  1250. {
  1251. php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
  1252. /* cleanup handled in sxe_object_dtor as we dont always have an iterator wrapper */
  1253. if (iterator->intern.data) {
  1254. zval_ptr_dtor((zval**)&iterator->intern.data);
  1255. }
  1256. efree(iterator);
  1257. }
  1258. static int php_sxe_iterator_valid(zend_object_iterator *iter TSRMLS_DC)
  1259. {
  1260. php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
  1261. return iterator->sxe->iter.data ? SUCCESS : FAILURE;
  1262. }
  1263. static void php_sxe_iterator_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
  1264. {
  1265. php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
  1266. *data = &iterator->sxe->iter.data;
  1267. }
  1268. static int php_sxe_iterator_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
  1269. {
  1270. zval *curobj;
  1271. xmlNodePtr curnode = NULL;
  1272. php_sxe_object *intern;
  1273. int namelen;
  1274. php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
  1275. curobj = iterator->sxe->iter.data;
  1276. intern = (php_sxe_object *)zend_object_store_get_object(curobj TSRMLS_CC);
  1277. if (intern != NULL && intern->node != NULL) {
  1278. curnode = (xmlNodePtr)((php_libxml_node_ptr *)intern->node)->node;
  1279. }
  1280. namelen = xmlStrlen(curnode->name);
  1281. *str_key = estrndup(curnode->name, namelen);
  1282. *str_key_len = namelen + 1;
  1283. return HASH_KEY_IS_STRING;
  1284. }
  1285. ZEND_API void php_sxe_move_forward_iterator(php_sxe_object *sxe TSRMLS_DC)
  1286. {
  1287. xmlNodePtr node = NULL;
  1288. php_sxe_object *intern;
  1289. char *prefix;
  1290. if (sxe->iter.data) {
  1291. intern = (php_sxe_object *)zend_object_store_get_object(sxe->iter.data TSRMLS_CC);
  1292. GET_NODE(intern, node)
  1293. zval_ptr_dtor(&sxe->iter.data);
  1294. sxe->iter.data = NULL;
  1295. }
  1296. if (node) {
  1297. node = node->next;
  1298. }
  1299. prefix = sxe->iter.nsprefix;
  1300. while (node) {
  1301. SKIP_TEXT(node);
  1302. if (sxe->iter.type != SXE_ITER_ATTRLIST && node->type == XML_ELEMENT_NODE) {
  1303. if (sxe->iter.type == SXE_ITER_ELEMENT) {
  1304. if (!xmlStrcmp(node->name, sxe->iter.name) && match_ns(sxe, node, prefix)) {
  1305. break;
  1306. }
  1307. } else {
  1308. if (match_ns(sxe, node, prefix)) {
  1309. break;
  1310. }
  1311. }
  1312. } else {
  1313. if (node->type == XML_ATTRIBUTE_NODE) {
  1314. if (match_ns(sxe, node, sxe->iter.nsprefix)) {
  1315. break;
  1316. }
  1317. }
  1318. }
  1319. next_iter:
  1320. node = node->next;
  1321. }
  1322. if (node) {
  1323. ALLOC_INIT_ZVAL(sxe->iter.data);
  1324. _node_as_zval(sxe, node, sxe->iter.data, SXE_ITER_NONE, NULL, sxe->iter.nsprefix TSRMLS_CC);
  1325. }
  1326. }
  1327. static void php_sxe_iterator_move_forward(zend_object_iterator *iter TSRMLS_DC)
  1328. {
  1329. php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
  1330. php_sxe_move_forward_iterator(iterator->sxe TSRMLS_CC);
  1331. }
  1332. static void php_sxe_iterator_rewind(zend_object_iterator *iter TSRMLS_DC)
  1333. {
  1334. php_sxe_object *sxe;
  1335. php_sxe_iterator *iterator = (php_sxe_iterator *)iter;
  1336. sxe = iterator->sxe;
  1337. php_sxe_reset_iterator(sxe TSRMLS_CC);
  1338. }
  1339. void *simplexml_export_node(zval *object TSRMLS_DC)
  1340. {
  1341. php_sxe_object *sxe;
  1342. xmlNodePtr node;
  1343. sxe = php_sxe_fetch_object(object TSRMLS_CC);
  1344. GET_NODE(sxe, node);
  1345. return php_sxe_get_first_node(sxe, node TSRMLS_CC);
  1346. }
  1347. #ifdef HAVE_DOM
  1348. /* {{{ proto simplemxml_element simplexml_import_dom(domNode node [, string class_name])
  1349. Get a simplexml_element object from dom to allow for processing */
  1350. PHP_FUNCTION(simplexml_import_dom)
  1351. {
  1352. php_sxe_object *sxe;
  1353. zval *node;
  1354. php_libxml_node_object *object;
  1355. xmlNodePtr nodep = NULL;
  1356. char *classname = "";
  1357. int classname_len = 0;
  1358. zend_class_entry *ce= sxe_class_entry;
  1359. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o|s", &node, &classname, &classname_len) == FAILURE) {
  1360. return;
  1361. }
  1362. object = (php_libxml_node_object *)zend_object_store_get_object(node TSRMLS_CC);
  1363. nodep = php_libxml_import_node(node TSRMLS_CC);
  1364. if (nodep) {
  1365. if (nodep->doc == NULL) {
  1366. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Imported Node must have associated Document");
  1367. RETURN_NULL();
  1368. }
  1369. if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
  1370. nodep = xmlDocGetRootElement((xmlDocPtr) nodep);
  1371. }
  1372. }
  1373. if (nodep && nodep->type == XML_ELEMENT_NODE) {
  1374. if (classname_len) {
  1375. zend_class_entry **pce;
  1376. if (zend_lookup_class(classname, classname_len, &pce TSRMLS_CC) == FAILURE) {
  1377. php_error_docref(NULL TSRMLS_CC, E_ERROR, "Class %s does not exist", classname);
  1378. }
  1379. ce = *pce;
  1380. }
  1381. sxe = php_sxe_object_new(ce TSRMLS_CC);
  1382. sxe->document = object->document;
  1383. php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, nodep->doc TSRMLS_CC);
  1384. php_libxml_increment_node_ptr((php_libxml_node_object *)sxe, nodep, NULL TSRMLS_CC);
  1385. return_value->type = IS_OBJECT;
  1386. return_value->value.obj = php_sxe_register_object(sxe TSRMLS_CC);
  1387. } else {
  1388. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Nodetype to import");
  1389. RETVAL_NULL();
  1390. }
  1391. }
  1392. /* }}} */
  1393. #endif
  1394. function_entry simplexml_functions[] = {
  1395. PHP_FE(simplexml_load_file, NULL)
  1396. PHP_FE(simplexml_load_string, NULL)
  1397. #ifdef HAVE_DOM
  1398. PHP_FE(simplexml_import_dom, NULL)
  1399. #endif
  1400. {NULL, NULL, NULL}
  1401. };
  1402. zend_module_entry simplexml_module_entry = {
  1403. STANDARD_MODULE_HEADER,
  1404. "SimpleXML",
  1405. simplexml_functions,
  1406. PHP_MINIT(simplexml),
  1407. PHP_MSHUTDOWN(simplexml),
  1408. NULL,
  1409. NULL,
  1410. PHP_MINFO(simplexml),
  1411. "0.1",
  1412. STANDARD_MODULE_PROPERTIES
  1413. };
  1414. #ifdef COMPILE_DL_SIMPLEXML
  1415. ZEND_GET_MODULE(simplexml)
  1416. #endif
  1417. /* the method table */
  1418. /* each method can have its own parameters and visibility */
  1419. static zend_function_entry sxe_functions[] = {
  1420. SXE_ME(__construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) /* must be called */
  1421. SXE_ME(asXML, NULL, ZEND_ACC_PUBLIC)
  1422. SXE_ME(xpath, NULL, ZEND_ACC_PUBLIC)
  1423. SXE_ME(registerXPathNamespace, NULL, ZEND_ACC_PUBLIC)
  1424. SXE_ME(attributes, NULL, ZEND_ACC_PUBLIC)
  1425. SXE_ME(children, NULL, ZEND_ACC_PUBLIC)
  1426. {NULL, NULL, NULL}
  1427. };
  1428. /* {{{ PHP_MINIT_FUNCTION(simplexml)
  1429. */
  1430. PHP_MINIT_FUNCTION(simplexml)
  1431. {
  1432. zend_class_entry sxe;
  1433. INIT_CLASS_ENTRY(sxe, "SimpleXMLElement", sxe_functions);
  1434. sxe.create_object = sxe_object_new;
  1435. sxe_class_entry = zend_register_internal_class(&sxe TSRMLS_CC);
  1436. sxe_class_entry->get_iterator = php_sxe_get_iterator;
  1437. zend_class_implements(sxe_class_entry TSRMLS_CC, 1, zend_ce_traversable);
  1438. sxe_object_handlers.get_method = zend_get_std_object_handlers()->get_method;
  1439. sxe_object_handlers.get_constructor = zend_get_std_object_handlers()->get_constructor;
  1440. sxe_object_handlers.get_class_entry = zend_get_std_object_handlers()->get_class_entry;
  1441. sxe_object_handlers.get_class_name = zend_get_std_object_handlers()->get_class_name;
  1442. sxe_ze1_object_handlers.get_method = zend_get_std_object_handlers()->get_method;
  1443. sxe_ze1_object_handlers.get_constructor = zend_get_std_object_handlers()->get_constructor;
  1444. sxe_ze1_object_handlers.get_class_entry = zend_get_std_object_handlers()->get_class_entry;
  1445. sxe_ze1_object_handlers.get_class_name = zend_get_std_object_handlers()->get_class_name;
  1446. sxe_ze1_object_handlers.clone_obj = sxe_object_ze1_clone;
  1447. #if HAVE_SPL && !defined(COMPILE_DL_SPL)
  1448. if (zend_get_module_started("spl") == SUCCESS) {
  1449. PHP_MINIT(spl_sxe)(INIT_FUNC_ARGS_PASSTHRU);
  1450. }
  1451. #endif /* HAVE_SPL */
  1452. php_libxml_register_export(sxe_class_entry, simplexml_export_node);
  1453. return SUCCESS;
  1454. }
  1455. /* }}} */
  1456. /* {{{ PHP_MSHUTDOWN_FUNCTION(simplexml)
  1457. */
  1458. PHP_MSHUTDOWN_FUNCTION(simplexml)
  1459. {
  1460. sxe_class_entry = NULL;
  1461. return SUCCESS;
  1462. }
  1463. /* }}} */
  1464. /* {{{ PHP_MINFO_FUNCTION(simplexml)
  1465. */
  1466. PHP_MINFO_FUNCTION(simplexml)
  1467. {
  1468. php_info_print_table_start();
  1469. php_info_print_table_header(2, "Simplexml support", "enabled");
  1470. php_info_print_table_row(2, "Revision", "$Revision$");
  1471. php_info_print_table_row(2, "Schema support",
  1472. #ifdef LIBXML_SCHEMAS_ENABLED
  1473. "enabled");
  1474. #else
  1475. "not available");
  1476. #endif
  1477. php_info_print_table_end();
  1478. }
  1479. /* }}} */
  1480. #endif
  1481. /**
  1482. * Local Variables:
  1483. * c-basic-offset: 4
  1484. * tab-width: 4
  1485. * indent-tabs-mode: t
  1486. * End:
  1487. * vim600: fdm=marker
  1488. * vim: noet sw=4 ts=4
  1489. */