xref: /PHP-8.1/ext/xmlreader/php_xmlreader.c (revision 900f0cab)
1 /*
2   +----------------------------------------------------------------------+
3   | Copyright (c) The PHP Group                                          |
4   +----------------------------------------------------------------------+
5   | This source file is subject to version 3.01 of the PHP license,      |
6   | that is bundled with this package in the file LICENSE, and is        |
7   | available through the world-wide-web at the following url:           |
8   | https://www.php.net/license/3_01.txt                                 |
9   | If you did not receive a copy of the PHP license and are unable to   |
10   | obtain it through the world-wide-web, please send a note to          |
11   | license@php.net so we can mail you a copy immediately.               |
12   +----------------------------------------------------------------------+
13   | Author: Rob Richards <rrichards@php.net>                             |
14   +----------------------------------------------------------------------+
15 */
16 
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20 
21 
22 #include "php.h"
23 #include "php_ini.h"
24 #include "ext/standard/info.h"
25 #include "php_xmlreader.h"
26 #include "php_xmlreader_arginfo.h"
27 #ifdef HAVE_DOM
28 #include "ext/dom/xml_common.h"
29 #include "ext/dom/dom_ce.h"
30 #endif
31 #include <libxml/xmlreader.h>
32 #include <libxml/uri.h>
33 
34 zend_class_entry *xmlreader_class_entry;
35 
36 static zend_object_handlers xmlreader_object_handlers;
37 
38 static HashTable xmlreader_prop_handlers;
39 
40 static zend_internal_function xmlreader_open_fn;
41 static zend_internal_function xmlreader_xml_fn;
42 
43 typedef int (*xmlreader_read_int_t)(xmlTextReaderPtr reader);
44 typedef unsigned char *(*xmlreader_read_char_t)(xmlTextReaderPtr reader);
45 typedef const unsigned char *(*xmlreader_read_const_char_t)(xmlTextReaderPtr reader);
46 typedef int (*xmlreader_write_t)(xmlreader_object *obj, zval *newval);
47 
48 typedef unsigned char *(*xmlreader_read_one_char_t)(xmlTextReaderPtr reader, const unsigned char *);
49 
50 typedef struct _xmlreader_prop_handler {
51 	xmlreader_read_int_t read_int_func;
52 	xmlreader_read_const_char_t read_char_func;
53 	xmlreader_write_t write_func;
54 	int type;
55 } xmlreader_prop_handler;
56 
57 #define XMLREADER_LOAD_STRING 0
58 #define XMLREADER_LOAD_FILE 1
59 
60 /* {{{ xmlreader_register_prop_handler */
xmlreader_register_prop_handler(HashTable * prop_handler,char * name,xmlreader_read_int_t read_int_func,xmlreader_read_const_char_t read_char_func,int rettype)61 static void xmlreader_register_prop_handler(HashTable *prop_handler, char *name, xmlreader_read_int_t read_int_func, xmlreader_read_const_char_t read_char_func, int rettype)
62 {
63 	xmlreader_prop_handler hnd;
64 	zend_string *str;
65 
66 	hnd.read_char_func = read_char_func;
67 	hnd.read_int_func = read_int_func;
68 	hnd.type = rettype;
69 	str = zend_string_init_interned(name, strlen(name), 1);
70 	zend_hash_add_mem(prop_handler, str, &hnd, sizeof(xmlreader_prop_handler));
71 	zend_string_release_ex(str, 1);
72 }
73 /* }}} */
74 
75 /* {{{ xmlreader_property_reader */
xmlreader_property_reader(xmlreader_object * obj,xmlreader_prop_handler * hnd,zval * rv)76 static int xmlreader_property_reader(xmlreader_object *obj, xmlreader_prop_handler *hnd, zval *rv)
77 {
78 	const xmlChar *retchar = NULL;
79 	int retint = 0;
80 
81 	if (obj->ptr != NULL) {
82 		if (hnd->read_char_func) {
83 			retchar = hnd->read_char_func(obj->ptr);
84 		} else {
85 			if (hnd->read_int_func) {
86 				retint = hnd->read_int_func(obj->ptr);
87 				if (retint == -1) {
88 					zend_throw_error(NULL, "Failed to read property due to libxml error");
89 					return FAILURE;
90 				}
91 			}
92 		}
93 	}
94 
95 	switch (hnd->type) {
96 		case IS_STRING:
97 			if (retchar) {
98 				ZVAL_STRING(rv, (char *) retchar);
99 			} else {
100 				ZVAL_EMPTY_STRING(rv);
101 			}
102 			break;
103 		case _IS_BOOL:
104 			ZVAL_BOOL(rv, retint);
105 			break;
106 		case IS_LONG:
107 			ZVAL_LONG(rv, retint);
108 			break;
109 		EMPTY_SWITCH_DEFAULT_CASE()
110 	}
111 
112 	return SUCCESS;
113 }
114 /* }}} */
115 
116 /* {{{ xmlreader_get_property_ptr_ptr */
xmlreader_get_property_ptr_ptr(zend_object * object,zend_string * name,int type,void ** cache_slot)117 zval *xmlreader_get_property_ptr_ptr(zend_object *object, zend_string *name, int type, void **cache_slot)
118 {
119 	xmlreader_object *obj;
120 	zval *retval = NULL;
121 	xmlreader_prop_handler *hnd = NULL;
122 
123 	obj = php_xmlreader_fetch_object(object);
124 
125 	if (obj->prop_handler != NULL) {
126 		hnd = zend_hash_find_ptr(obj->prop_handler, name);
127 	}
128 
129 	if (hnd == NULL) {
130 		retval = zend_std_get_property_ptr_ptr(object, name, type, cache_slot);
131 	}
132 
133 	return retval;
134 }
135 /* }}} */
136 
137 /* {{{ xmlreader_read_property */
xmlreader_read_property(zend_object * object,zend_string * name,int type,void ** cache_slot,zval * rv)138 zval *xmlreader_read_property(zend_object *object, zend_string *name, int type, void **cache_slot, zval *rv)
139 {
140 	xmlreader_object *obj;
141 	zval *retval = NULL;
142 	xmlreader_prop_handler *hnd = NULL;
143 
144 	obj = php_xmlreader_fetch_object(object);
145 
146 	if (obj->prop_handler != NULL) {
147 		hnd = zend_hash_find_ptr(obj->prop_handler, name);
148 	}
149 
150 	if (hnd != NULL) {
151 		if (xmlreader_property_reader(obj, hnd, rv) == FAILURE) {
152 			retval = &EG(uninitialized_zval);
153 		} else {
154 			retval = rv;
155 		}
156 	} else {
157 		retval = zend_std_read_property(object, name, type, cache_slot, rv);
158 	}
159 
160 	return retval;
161 }
162 /* }}} */
163 
164 /* {{{ xmlreader_write_property */
xmlreader_write_property(zend_object * object,zend_string * name,zval * value,void ** cache_slot)165 zval *xmlreader_write_property(zend_object *object, zend_string *name, zval *value, void **cache_slot)
166 {
167 	xmlreader_object *obj;
168 	xmlreader_prop_handler *hnd = NULL;
169 
170 	obj = php_xmlreader_fetch_object(object);
171 
172 	if (obj->prop_handler != NULL) {
173 		hnd = zend_hash_find_ptr(obj->prop_handler, name);
174 	}
175 	if (hnd != NULL) {
176 		zend_throw_error(NULL, "Cannot write to read-only property");
177 	} else {
178 		value = zend_std_write_property(object, name, value, cache_slot);
179 	}
180 
181 	return value;
182 }
183 /* }}} */
184 
185 /* {{{ */
xmlreader_get_method(zend_object ** obj,zend_string * name,const zval * key)186 static zend_function *xmlreader_get_method(zend_object **obj, zend_string *name, const zval *key)
187 {
188 	if (ZSTR_LEN(name) == sizeof("open") - 1
189 			&& (ZSTR_VAL(name)[0] == 'o' || ZSTR_VAL(name)[0] == 'O')
190 			&& (ZSTR_VAL(name)[1] == 'p' || ZSTR_VAL(name)[1] == 'P')
191 			&& (ZSTR_VAL(name)[2] == 'e' || ZSTR_VAL(name)[2] == 'E')
192 			&& (ZSTR_VAL(name)[3] == 'n' || ZSTR_VAL(name)[3] == 'N')) {
193 		return (zend_function*)&xmlreader_open_fn;
194 	} else if (ZSTR_LEN(name) == sizeof("xml") - 1
195 			&& (ZSTR_VAL(name)[0] == 'x' || ZSTR_VAL(name)[0] == 'X')
196 			&& (ZSTR_VAL(name)[1] == 'm' || ZSTR_VAL(name)[1] == 'M')
197 			&& (ZSTR_VAL(name)[2] == 'l' || ZSTR_VAL(name)[2] == 'L')) {
198 		return (zend_function*)&xmlreader_xml_fn;
199 	}
200 	return zend_std_get_method(obj, name, key);;
201 }
202 /* }}} */
203 
204 /* {{{ _xmlreader_get_valid_file_path */
205 /* _xmlreader_get_valid_file_path and _xmlreader_get_relaxNG should be made a
206 	common function in libxml extension as code is common to a few xml extensions */
_xmlreader_get_valid_file_path(char * source,char * resolved_path,int resolved_path_len)207 char *_xmlreader_get_valid_file_path(char *source, char *resolved_path, int resolved_path_len ) {
208 	xmlURI *uri;
209 	xmlChar *escsource;
210 	char *file_dest;
211 	int isFileUri = 0;
212 
213 	uri = xmlCreateURI();
214 	if (uri == NULL) {
215 		return NULL;
216 	}
217 	escsource = xmlURIEscapeStr((xmlChar *)source, (xmlChar *)":");
218 	xmlParseURIReference(uri, (const char *)escsource);
219 	xmlFree(escsource);
220 
221 	if (uri->scheme != NULL) {
222 		/* absolute file uris - libxml only supports localhost or empty host */
223 		if (strncasecmp(source, "file:///",8) == 0) {
224 			isFileUri = 1;
225 #ifdef PHP_WIN32
226 			source += 8;
227 #else
228 			source += 7;
229 #endif
230 		} else if (strncasecmp(source, "file://localhost/",17) == 0) {
231 			isFileUri = 1;
232 #ifdef PHP_WIN32
233 			source += 17;
234 #else
235 			source += 16;
236 #endif
237 		}
238 	}
239 
240 	file_dest = source;
241 
242 	if ((uri->scheme == NULL || isFileUri)) {
243 		if (!VCWD_REALPATH(source, resolved_path) && !expand_filepath(source, resolved_path)) {
244 			xmlFreeURI(uri);
245 			return NULL;
246 		}
247 		file_dest = resolved_path;
248 	}
249 
250 	xmlFreeURI(uri);
251 
252 	return file_dest;
253 }
254 /* }}} */
255 
256 #ifdef LIBXML_SCHEMAS_ENABLED
257 /* {{{ _xmlreader_get_relaxNG */
_xmlreader_get_relaxNG(char * source,size_t source_len,size_t type,xmlRelaxNGValidityErrorFunc error_func,xmlRelaxNGValidityWarningFunc warn_func)258 static xmlRelaxNGPtr _xmlreader_get_relaxNG(char *source, size_t source_len, size_t type,
259 											xmlRelaxNGValidityErrorFunc error_func,
260 											xmlRelaxNGValidityWarningFunc warn_func)
261 {
262 	char *valid_file = NULL;
263 	xmlRelaxNGParserCtxtPtr parser = NULL;
264 	xmlRelaxNGPtr           sptr;
265 	char resolved_path[MAXPATHLEN + 1];
266 
267 	switch (type) {
268 	case XMLREADER_LOAD_FILE:
269 		valid_file = _xmlreader_get_valid_file_path(source, resolved_path, MAXPATHLEN );
270 		if (!valid_file) {
271 			return NULL;
272 		}
273 		parser = xmlRelaxNGNewParserCtxt(valid_file);
274 		break;
275 	case XMLREADER_LOAD_STRING:
276 		parser = xmlRelaxNGNewMemParserCtxt(source, source_len);
277 		/* If loading from memory, we need to set the base directory for the document
278 		   but it is not apparent how to do that for schema's */
279 		break;
280 	default:
281 		return NULL;
282 	}
283 
284 	if (parser == NULL) {
285 		return NULL;
286 	}
287 
288 	PHP_LIBXML_SANITIZE_GLOBALS(parse);
289 	if (error_func || warn_func) {
290 		xmlRelaxNGSetParserErrors(parser,
291 			(xmlRelaxNGValidityErrorFunc) error_func,
292 			(xmlRelaxNGValidityWarningFunc) warn_func,
293 			parser);
294 	}
295 	sptr = xmlRelaxNGParse(parser);
296 	xmlRelaxNGFreeParserCtxt(parser);
297 	PHP_LIBXML_RESTORE_GLOBALS(parse);
298 
299 	return sptr;
300 }
301 /* }}} */
302 #endif
303 
304 static const zend_module_dep xmlreader_deps[] = {
305 	ZEND_MOD_REQUIRED("libxml")
306 	ZEND_MOD_END
307 };
308 
309 /* {{{ xmlreader_module_entry */
310 zend_module_entry xmlreader_module_entry = {
311 	STANDARD_MODULE_HEADER_EX, NULL,
312 	xmlreader_deps,
313 	"xmlreader",
314 	NULL,
315 	PHP_MINIT(xmlreader),
316 	PHP_MSHUTDOWN(xmlreader),
317 	NULL,
318 	NULL,
319 	PHP_MINFO(xmlreader),
320 	PHP_XMLREADER_VERSION,
321 	STANDARD_MODULE_PROPERTIES
322 };
323 /* }}} */
324 
325 #ifdef COMPILE_DL_XMLREADER
ZEND_GET_MODULE(xmlreader)326 ZEND_GET_MODULE(xmlreader)
327 #endif
328 
329 /* {{{ xmlreader_objects_clone */
330 void xmlreader_objects_clone(void *object, void **object_clone)
331 {
332 	/* TODO */
333 }
334 /* }}} */
335 
336 /* {{{ xmlreader_free_resources */
xmlreader_free_resources(xmlreader_object * intern)337 static void xmlreader_free_resources(xmlreader_object *intern) {
338 	if (intern->input) {
339 		xmlFreeParserInputBuffer(intern->input);
340 		intern->input = NULL;
341 	}
342 
343 	if (intern->ptr) {
344 		xmlFreeTextReader(intern->ptr);
345 		intern->ptr = NULL;
346 	}
347 #ifdef LIBXML_SCHEMAS_ENABLED
348 	if (intern->schema) {
349 		xmlRelaxNGFree((xmlRelaxNGPtr) intern->schema);
350 		intern->schema = NULL;
351 	}
352 #endif
353 }
354 /* }}} */
355 
356 /* {{{ xmlreader_objects_free_storage */
xmlreader_objects_free_storage(zend_object * object)357 void xmlreader_objects_free_storage(zend_object *object)
358 {
359 	xmlreader_object *intern = php_xmlreader_fetch_object(object);
360 
361 	zend_object_std_dtor(&intern->std);
362 
363 	xmlreader_free_resources(intern);
364 }
365 /* }}} */
366 
367 /* {{{ xmlreader_objects_new */
xmlreader_objects_new(zend_class_entry * class_type)368 zend_object *xmlreader_objects_new(zend_class_entry *class_type)
369 {
370 	xmlreader_object *intern;
371 
372 	intern = zend_object_alloc(sizeof(xmlreader_object), class_type);
373 	zend_object_std_init(&intern->std, class_type);
374 	object_properties_init(&intern->std, class_type);
375 	intern->prop_handler = &xmlreader_prop_handlers;
376 	intern->std.handlers = &xmlreader_object_handlers;
377 
378 	return &intern->std;
379 }
380 /* }}} */
381 
382 /* {{{ php_xmlreader_string_arg */
php_xmlreader_string_arg(INTERNAL_FUNCTION_PARAMETERS,xmlreader_read_one_char_t internal_function)383 static void php_xmlreader_string_arg(INTERNAL_FUNCTION_PARAMETERS, xmlreader_read_one_char_t internal_function) {
384 	zval *id;
385 	size_t name_len = 0;
386 	char *retchar = NULL;
387 	xmlreader_object *intern;
388 	char *name;
389 
390 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
391 		RETURN_THROWS();
392 	}
393 
394 	if (!name_len) {
395 		zend_argument_value_error(1, "cannot be empty");
396 		RETURN_THROWS();
397 	}
398 
399 	id = ZEND_THIS;
400 
401 	intern = Z_XMLREADER_P(id);
402 	if (intern->ptr) {
403 		retchar = (char *)internal_function(intern->ptr, (const unsigned char *)name);
404 	}
405 	if (retchar) {
406 		RETVAL_STRING(retchar);
407 		xmlFree(retchar);
408 		return;
409 	} else {
410 		RETVAL_NULL();
411 	}
412 }
413 /* }}} */
414 
415 /* {{{ php_xmlreader_no_arg */
php_xmlreader_no_arg(INTERNAL_FUNCTION_PARAMETERS,xmlreader_read_int_t internal_function)416 static void php_xmlreader_no_arg(INTERNAL_FUNCTION_PARAMETERS, xmlreader_read_int_t internal_function) {
417 	zval *id;
418 	int retval;
419 	xmlreader_object *intern;
420 
421 	if (zend_parse_parameters_none() == FAILURE) {
422 		RETURN_THROWS();
423 	}
424 
425 	id = ZEND_THIS;
426 
427 	intern = Z_XMLREADER_P(id);
428 	if (intern->ptr) {
429 		retval = internal_function(intern->ptr);
430 		if (retval == 1) {
431 			RETURN_TRUE;
432 		}
433 	}
434 
435 	RETURN_FALSE;
436 }
437 /* }}} */
438 
php_xmlreader_free_prop_handler(zval * el)439 static void php_xmlreader_free_prop_handler(zval *el) /* {{{ */ {
440 	pefree(Z_PTR_P(el), 1);
441 } /* }}} */
442 
443 /* {{{ php_xmlreader_no_arg_string */
php_xmlreader_no_arg_string(INTERNAL_FUNCTION_PARAMETERS,xmlreader_read_char_t internal_function)444 static void php_xmlreader_no_arg_string(INTERNAL_FUNCTION_PARAMETERS, xmlreader_read_char_t internal_function) {
445 	zval *id;
446 	char *retchar = NULL;
447 	xmlreader_object *intern;
448 
449 	if (zend_parse_parameters_none() == FAILURE) {
450 		RETURN_THROWS();
451 	}
452 
453 	id = ZEND_THIS;
454 
455 	intern = Z_XMLREADER_P(id);
456 	if (intern->ptr) {
457 		retchar = (char *)internal_function(intern->ptr);
458 	}
459 	if (retchar) {
460 		RETVAL_STRING(retchar);
461 		xmlFree(retchar);
462 		return;
463 	} else {
464 		RETVAL_EMPTY_STRING();
465 	}
466 }
467 /* }}} */
468 
469 /* {{{ php_xmlreader_set_relaxng_schema */
php_xmlreader_set_relaxng_schema(INTERNAL_FUNCTION_PARAMETERS,int type)470 static void php_xmlreader_set_relaxng_schema(INTERNAL_FUNCTION_PARAMETERS, int type) {
471 #ifdef LIBXML_SCHEMAS_ENABLED
472 	zval *id;
473 	size_t source_len = 0;
474 	int retval = -1;
475 	xmlreader_object *intern;
476 	xmlRelaxNGPtr schema = NULL;
477 	char *source;
478 
479 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "p!", &source, &source_len) == FAILURE) {
480 		RETURN_THROWS();
481 	}
482 
483 	if (source != NULL && !source_len) {
484 		zend_argument_value_error(1, "cannot be empty");
485 		RETURN_THROWS();
486 	}
487 
488 	id = ZEND_THIS;
489 
490 	intern = Z_XMLREADER_P(id);
491 	if (intern->ptr) {
492 		if (source) {
493 			schema =  _xmlreader_get_relaxNG(source, source_len, type, NULL, NULL);
494 			if (schema) {
495 				retval = xmlTextReaderRelaxNGSetSchema(intern->ptr, schema);
496 			}
497 		} else {
498 			/* unset the associated relaxNG context and schema if one exists */
499 			retval = xmlTextReaderRelaxNGSetSchema(intern->ptr, NULL);
500 		}
501 
502 		if (retval == 0) {
503 			if (intern->schema) {
504 				xmlRelaxNGFree((xmlRelaxNGPtr) intern->schema);
505 			}
506 
507 			intern->schema = schema;
508 
509 			RETURN_TRUE;
510 		} else {
511 			php_error_docref(NULL, E_WARNING, "Schema contains errors");
512 			RETURN_FALSE;
513 		}
514 	} else {
515 		zend_throw_error(NULL, "Schema must be set prior to reading");
516 		RETURN_THROWS();
517 	}
518 #else
519 	php_error_docref(NULL, E_WARNING, "No schema support built into libxml");
520 	RETURN_FALSE;
521 #endif
522 }
523 /* }}} */
524 
525 /* {{{ Closes xmlreader - current frees resources until xmlTextReaderClose is fixed in libxml */
PHP_METHOD(XMLReader,close)526 PHP_METHOD(XMLReader, close)
527 {
528 	zval *id;
529 	xmlreader_object *intern;
530 
531 	if (zend_parse_parameters_none() == FAILURE) {
532 		RETURN_THROWS();
533 	}
534 
535 	id = ZEND_THIS;
536 	intern = Z_XMLREADER_P(id);
537 	/* libxml is segfaulting in versions up to 2.6.8 using xmlTextReaderClose so for
538 	now we will free the whole reader when close is called as it would get rebuilt on
539 	a new load anyways */
540 	xmlreader_free_resources(intern);
541 
542 	RETURN_TRUE;
543 }
544 /* }}} */
545 
546 /* {{{ Get value of an attribute from current element */
PHP_METHOD(XMLReader,getAttribute)547 PHP_METHOD(XMLReader, getAttribute)
548 {
549 	php_xmlreader_string_arg(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextReaderGetAttribute);
550 }
551 /* }}} */
552 
553 /* {{{ Get value of an attribute at index from current element */
PHP_METHOD(XMLReader,getAttributeNo)554 PHP_METHOD(XMLReader, getAttributeNo)
555 {
556 	zval *id;
557 	zend_long attr_pos;
558 	char *retchar = NULL;
559 	xmlreader_object *intern;
560 
561 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &attr_pos) == FAILURE) {
562 		RETURN_THROWS();
563 	}
564 
565 	id = ZEND_THIS;
566 
567 	intern = Z_XMLREADER_P(id);
568 	if (intern->ptr) {
569 		retchar = (char *)xmlTextReaderGetAttributeNo(intern->ptr, attr_pos);
570 	}
571 	if (retchar) {
572 		RETVAL_STRING(retchar);
573 		xmlFree(retchar);
574 	}
575 }
576 /* }}} */
577 
578 /* {{{ Get value of a attribute via name and namespace from current element */
PHP_METHOD(XMLReader,getAttributeNs)579 PHP_METHOD(XMLReader, getAttributeNs)
580 {
581 	zval *id;
582 	size_t name_len = 0, ns_uri_len = 0;
583 	xmlreader_object *intern;
584 	char *name, *ns_uri, *retchar = NULL;
585 
586 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &name, &name_len, &ns_uri, &ns_uri_len) == FAILURE) {
587 		RETURN_THROWS();
588 	}
589 
590 	if (name_len == 0) {
591 		zend_argument_value_error(1, "cannot be empty");
592 		RETURN_THROWS();
593 	}
594 
595 	if (ns_uri_len == 0) {
596 		zend_argument_value_error(2, "cannot be empty");
597 		RETURN_THROWS();
598 	}
599 
600 	id = ZEND_THIS;
601 
602 	intern = Z_XMLREADER_P(id);
603 	if (intern->ptr) {
604 		retchar = (char *)xmlTextReaderGetAttributeNs(intern->ptr, (xmlChar *)name, (xmlChar *)ns_uri);
605 	}
606 	if (retchar) {
607 		RETVAL_STRING(retchar);
608 		xmlFree(retchar);
609 	}
610 }
611 /* }}} */
612 
613 /* {{{ Indicates whether given property (one of the parser option constants) is set or not on parser */
PHP_METHOD(XMLReader,getParserProperty)614 PHP_METHOD(XMLReader, getParserProperty)
615 {
616 	zval *id;
617 	zend_long property;
618 	xmlreader_object *intern;
619 
620 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &property) == FAILURE) {
621 		RETURN_THROWS();
622 	}
623 
624 	id = ZEND_THIS;
625 
626 	intern = Z_XMLREADER_P(id);
627 	if (!intern || !intern->ptr) {
628 		zend_throw_error(NULL, "Cannot access parser properties before loading data");
629 		RETURN_THROWS();
630 	}
631 
632 	int retval = xmlTextReaderGetParserProp(intern->ptr,property);
633 	if (retval == -1) {
634 		zend_argument_value_error(1, "must be a valid parser property");
635 		RETURN_THROWS();
636 	}
637 
638 	RETURN_BOOL(retval);
639 }
640 /* }}} */
641 
642 /* {{{ Returns boolean indicating if parsed document is valid or not.
643 Must set XMLREADER_LOADDTD or XMLREADER_VALIDATE parser option prior to the first call to read
644 or this method will always return FALSE */
PHP_METHOD(XMLReader,isValid)645 PHP_METHOD(XMLReader, isValid)
646 {
647 	php_xmlreader_no_arg(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextReaderIsValid);
648 }
649 /* }}} */
650 
651 /* {{{ Return namespaceURI for associated prefix on current node */
PHP_METHOD(XMLReader,lookupNamespace)652 PHP_METHOD(XMLReader, lookupNamespace)
653 {
654 	php_xmlreader_string_arg(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextReaderLookupNamespace);
655 }
656 /* }}} */
657 
658 /* {{{ Positions reader at specified attribute - Returns TRUE on success and FALSE on failure */
PHP_METHOD(XMLReader,moveToAttribute)659 PHP_METHOD(XMLReader, moveToAttribute)
660 {
661 	zval *id;
662 	size_t name_len = 0;
663 	int retval;
664 	xmlreader_object *intern;
665 	char *name;
666 
667 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
668 		RETURN_THROWS();
669 	}
670 
671 	if (name_len == 0) {
672 		zend_argument_value_error(1, "cannot be empty");
673 		RETURN_THROWS();
674 	}
675 
676 	id = ZEND_THIS;
677 
678 	intern = Z_XMLREADER_P(id);
679 	if (intern->ptr) {
680 		retval = xmlTextReaderMoveToAttribute(intern->ptr, (xmlChar *)name);
681 		if (retval == 1) {
682 			RETURN_TRUE;
683 		}
684 	}
685 
686 	RETURN_FALSE;
687 }
688 /* }}} */
689 
690 /* {{{ Positions reader at attribute at specified index.
691 Returns TRUE on success and FALSE on failure */
PHP_METHOD(XMLReader,moveToAttributeNo)692 PHP_METHOD(XMLReader, moveToAttributeNo)
693 {
694 	zval *id;
695 	zend_long attr_pos;
696 	int retval;
697 	xmlreader_object *intern;
698 
699 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &attr_pos) == FAILURE) {
700 		RETURN_THROWS();
701 	}
702 
703 	id = ZEND_THIS;
704 
705 	intern = Z_XMLREADER_P(id);
706 	if (intern->ptr) {
707 		retval = xmlTextReaderMoveToAttributeNo(intern->ptr, attr_pos);
708 		if (retval == 1) {
709 			RETURN_TRUE;
710 		}
711 	}
712 
713 	RETURN_FALSE;
714 }
715 /* }}} */
716 
717 /* {{{ Positions reader at attribute spcified by name and namespaceURI.
718 Returns TRUE on success and FALSE on failure */
PHP_METHOD(XMLReader,moveToAttributeNs)719 PHP_METHOD(XMLReader, moveToAttributeNs)
720 {
721 	zval *id;
722 	size_t name_len=0, ns_uri_len=0;
723 	int retval;
724 	xmlreader_object *intern;
725 	char *name, *ns_uri;
726 
727 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &name, &name_len, &ns_uri, &ns_uri_len) == FAILURE) {
728 		RETURN_THROWS();
729 	}
730 
731 	if (name_len == 0) {
732 		zend_argument_value_error(1, "cannot be empty");
733 		RETURN_THROWS();
734 	}
735 
736 	if (ns_uri_len == 0) {
737 		zend_argument_value_error(2, "cannot be empty");
738 		RETURN_THROWS();
739 	}
740 
741 	id = ZEND_THIS;
742 
743 	intern = Z_XMLREADER_P(id);
744 	if (intern->ptr) {
745 		retval = xmlTextReaderMoveToAttributeNs(intern->ptr, (xmlChar *)name, (xmlChar *)ns_uri);
746 		if (retval == 1) {
747 			RETURN_TRUE;
748 		}
749 	}
750 
751 	RETURN_FALSE;
752 }
753 /* }}} */
754 
755 /* {{{ Moves the position of the current instance to the node that contains the current Attribute node. */
PHP_METHOD(XMLReader,moveToElement)756 PHP_METHOD(XMLReader, moveToElement)
757 {
758 	php_xmlreader_no_arg(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextReaderMoveToElement);
759 }
760 /* }}} */
761 
762 /* {{{ Moves the position of the current instance to the first attribute associated with the current node. */
PHP_METHOD(XMLReader,moveToFirstAttribute)763 PHP_METHOD(XMLReader, moveToFirstAttribute)
764 {
765 	php_xmlreader_no_arg(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextReaderMoveToFirstAttribute);
766 }
767 /* }}} */
768 
769 /* {{{ Moves the position of the current instance to the next attribute associated with the current node. */
PHP_METHOD(XMLReader,moveToNextAttribute)770 PHP_METHOD(XMLReader, moveToNextAttribute)
771 {
772 	php_xmlreader_no_arg(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextReaderMoveToNextAttribute);
773 }
774 /* }}} */
775 
776 /* {{{ Moves the position of the current instance to the next node in the stream. */
PHP_METHOD(XMLReader,read)777 PHP_METHOD(XMLReader, read)
778 {
779 	zval *id;
780 	int retval;
781 	xmlreader_object *intern;
782 
783 	if (zend_parse_parameters_none() == FAILURE) {
784 		RETURN_THROWS();
785 	}
786 
787 	id = ZEND_THIS;
788 	intern = Z_XMLREADER_P(id);
789 	if (!intern->ptr) {
790 		zend_throw_error(NULL, "Data must be loaded before reading");
791 		RETURN_THROWS();
792 	}
793 
794 	retval = xmlTextReaderRead(intern->ptr);
795 	if (retval == -1) {
796 		RETURN_FALSE;
797 	} else {
798 		RETURN_BOOL(retval);
799 	}
800 }
801 /* }}} */
802 
803 /* {{{ Moves the position of the current instance to the next node in the stream. */
PHP_METHOD(XMLReader,next)804 PHP_METHOD(XMLReader, next)
805 {
806 	zval *id;
807 	int retval;
808 	size_t name_len=0;
809 	xmlreader_object *intern;
810 	char *name = NULL;
811 
812 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s!", &name, &name_len) == FAILURE) {
813 		RETURN_THROWS();
814 	}
815 
816 	id = ZEND_THIS;
817 	intern = Z_XMLREADER_P(id);
818 	if (intern->ptr) {
819 		retval = xmlTextReaderNext(intern->ptr);
820 		while (name != NULL && retval == 1) {
821 			if (xmlStrEqual(xmlTextReaderConstLocalName(intern->ptr), (xmlChar *)name)) {
822 				RETURN_TRUE;
823 			}
824 			retval = xmlTextReaderNext(intern->ptr);
825 		}
826 		if (retval == -1) {
827 			RETURN_FALSE;
828 		} else {
829 			RETURN_BOOL(retval);
830 		}
831 	}
832 
833 	zend_throw_error(NULL, "Data must be loaded before reading");
834 }
835 /* }}} */
836 
837 /* {{{ Sets the URI that the XMLReader will parse. */
PHP_METHOD(XMLReader,open)838 PHP_METHOD(XMLReader, open)
839 {
840 	zval *id;
841 	size_t source_len = 0, encoding_len = 0;
842 	zend_long options = 0;
843 	xmlreader_object *intern = NULL;
844 	char *source, *valid_file = NULL;
845 	char *encoding = NULL;
846 	char resolved_path[MAXPATHLEN + 1];
847 	xmlTextReaderPtr reader = NULL;
848 
849 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|s!l", &source, &source_len, &encoding, &encoding_len, &options) == FAILURE) {
850 		RETURN_THROWS();
851 	}
852 
853 	id = getThis();
854 	if (id != NULL) {
855 		ZEND_ASSERT(instanceof_function(Z_OBJCE_P(id), xmlreader_class_entry));
856 		intern = Z_XMLREADER_P(id);
857 		xmlreader_free_resources(intern);
858 	}
859 
860 	if (!source_len) {
861 		zend_argument_value_error(1, "cannot be empty");
862 		RETURN_THROWS();
863 	}
864 
865 	if (encoding && CHECK_NULL_PATH(encoding, encoding_len)) {
866 		php_error_docref(NULL, E_WARNING, "Encoding must not contain NUL bytes");
867 		RETURN_FALSE;
868 	}
869 
870 	valid_file = _xmlreader_get_valid_file_path(source, resolved_path, MAXPATHLEN );
871 
872 	if (valid_file) {
873 		PHP_LIBXML_SANITIZE_GLOBALS(reader_for_file);
874 		reader = xmlReaderForFile(valid_file, encoding, options);
875 		PHP_LIBXML_RESTORE_GLOBALS(reader_for_file);
876 	}
877 
878 	if (reader == NULL) {
879 		php_error_docref(NULL, E_WARNING, "Unable to open source data");
880 		RETURN_FALSE;
881 	}
882 
883 	if (id == NULL) {
884 		object_init_ex(return_value, xmlreader_class_entry);
885 		intern = Z_XMLREADER_P(return_value);
886 		intern->ptr = reader;
887 		return;
888 	}
889 
890 	intern->ptr = reader;
891 
892 	RETURN_TRUE;
893 
894 }
895 /* }}} */
896 
897 /* Not Yet Implemented in libxml - functions exist just not coded
898 PHP_METHOD(XMLReader, resetState)
899 {
900 
901 }
902 */
903 
904 /* {{{ Reads the contents of the current node, including child nodes and markup. */
PHP_METHOD(XMLReader,readInnerXml)905 PHP_METHOD(XMLReader, readInnerXml)
906 {
907 	php_xmlreader_no_arg_string(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextReaderReadInnerXml);
908 }
909 /* }}} */
910 
911 /* {{{ Reads the contents of the current node, including child nodes and markup. */
PHP_METHOD(XMLReader,readOuterXml)912 PHP_METHOD(XMLReader, readOuterXml)
913 {
914 	php_xmlreader_no_arg_string(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextReaderReadOuterXml);
915 }
916 /* }}} */
917 
918 /* {{{ Reads the contents of an element or a text node as a string. */
PHP_METHOD(XMLReader,readString)919 PHP_METHOD(XMLReader, readString)
920 {
921 	php_xmlreader_no_arg_string(INTERNAL_FUNCTION_PARAM_PASSTHRU, xmlTextReaderReadString);
922 }
923 /* }}} */
924 
925 /* {{{ Use W3C XSD schema to validate the document as it is processed. Activation is only possible before the first Read(). */
PHP_METHOD(XMLReader,setSchema)926 PHP_METHOD(XMLReader, setSchema)
927 {
928 #ifdef LIBXML_SCHEMAS_ENABLED
929 	zval *id;
930 	size_t source_len = 0;
931 	int retval = -1;
932 	xmlreader_object *intern;
933 	char *source;
934 
935 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "p!", &source, &source_len) == FAILURE) {
936 		RETURN_THROWS();
937 	}
938 
939 	if (source != NULL && !source_len) {
940 		zend_argument_value_error(1, "cannot be empty");
941 		RETURN_THROWS();
942 	}
943 
944 	id = ZEND_THIS;
945 
946 	intern = Z_XMLREADER_P(id);
947 	if (intern && intern->ptr) {
948 		PHP_LIBXML_SANITIZE_GLOBALS(schema);
949 		retval = xmlTextReaderSchemaValidate(intern->ptr, source);
950 		PHP_LIBXML_RESTORE_GLOBALS(schema);
951 
952 		if (retval == 0) {
953 			RETURN_TRUE;
954 		} else {
955 			php_error_docref(NULL, E_WARNING, "Schema contains errors");
956 			RETURN_FALSE;
957 		}
958 	} else {
959 		zend_throw_error(NULL, "Schema must be set prior to reading");
960 		RETURN_THROWS();
961 	}
962 #else
963 	php_error_docref(NULL, E_WARNING, "No schema support built into libxml");
964 	RETURN_FALSE;
965 #endif
966 }
967 /* }}} */
968 
969 /* {{{ Sets parser property (one of the parser option constants).
970 Properties must be set after open() or XML() and before the first read() is called */
PHP_METHOD(XMLReader,setParserProperty)971 PHP_METHOD(XMLReader, setParserProperty)
972 {
973 	zval *id;
974 	zend_long property;
975 	bool value;
976 	xmlreader_object *intern;
977 
978 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "lb", &property, &value) == FAILURE) {
979 		RETURN_THROWS();
980 	}
981 
982 	id = ZEND_THIS;
983 
984 	intern = Z_XMLREADER_P(id);
985 	if (!intern || !intern->ptr) {
986 		zend_throw_error(NULL, "Cannot access parser properties before loading data");
987 		RETURN_THROWS();
988 	}
989 
990 	int retval = xmlTextReaderSetParserProp(intern->ptr,property, value);
991 	if (retval == -1) {
992 		zend_argument_value_error(1, "must be a valid parser property");
993 		RETURN_THROWS();
994 	}
995 
996 	RETURN_TRUE;
997 }
998 /* }}} */
999 
1000 /* {{{ Sets the string that the XMLReader will parse. */
PHP_METHOD(XMLReader,setRelaxNGSchema)1001 PHP_METHOD(XMLReader, setRelaxNGSchema)
1002 {
1003 	php_xmlreader_set_relaxng_schema(INTERNAL_FUNCTION_PARAM_PASSTHRU, XMLREADER_LOAD_FILE);
1004 }
1005 /* }}} */
1006 
1007 /* {{{ Sets the string that the XMLReader will parse. */
PHP_METHOD(XMLReader,setRelaxNGSchemaSource)1008 PHP_METHOD(XMLReader, setRelaxNGSchemaSource)
1009 {
1010 	php_xmlreader_set_relaxng_schema(INTERNAL_FUNCTION_PARAM_PASSTHRU, XMLREADER_LOAD_STRING);
1011 }
1012 /* }}} */
1013 
1014 /* TODO
1015 XMLPUBFUN int XMLCALL
1016 		    xmlTextReaderSetSchema	(xmlTextReaderPtr reader,
1017 		    				 xmlSchemaPtr schema);
1018 */
1019 
1020 /* {{{ Sets the string that the XMLReader will parse. */
PHP_METHOD(XMLReader,XML)1021 PHP_METHOD(XMLReader, XML)
1022 {
1023 	zval *id;
1024 	size_t source_len = 0, encoding_len = 0;
1025 	zend_long options = 0;
1026 	xmlreader_object *intern = NULL;
1027 	char *source, *uri = NULL, *encoding = NULL;
1028 	int resolved_path_len, ret = 0;
1029 	char *directory=NULL, resolved_path[MAXPATHLEN + 1];
1030 	xmlParserInputBufferPtr inputbfr;
1031 	xmlTextReaderPtr reader;
1032 
1033 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s!l", &source, &source_len, &encoding, &encoding_len, &options) == FAILURE) {
1034 		RETURN_THROWS();
1035 	}
1036 
1037 	id = getThis();
1038 	if (id != NULL) {
1039 		ZEND_ASSERT(instanceof_function(Z_OBJCE_P(id), xmlreader_class_entry));
1040 		intern = Z_XMLREADER_P(id);
1041 		xmlreader_free_resources(intern);
1042 	}
1043 
1044 	if (!source_len) {
1045 		zend_argument_value_error(1, "cannot be empty");
1046 		RETURN_THROWS();
1047 	}
1048 
1049 	if (encoding && CHECK_NULL_PATH(encoding, encoding_len)) {
1050 		php_error_docref(NULL, E_WARNING, "Encoding must not contain NUL bytes");
1051 		RETURN_FALSE;
1052 	}
1053 
1054 	inputbfr = xmlParserInputBufferCreateMem(source, source_len, XML_CHAR_ENCODING_NONE);
1055 
1056 	if (inputbfr != NULL) {
1057 /* Get the URI of the current script so that we can set the base directory in libxml */
1058 #ifdef HAVE_GETCWD
1059 		directory = VCWD_GETCWD(resolved_path, MAXPATHLEN);
1060 #elif defined(HAVE_GETWD)
1061 		directory = VCWD_GETWD(resolved_path);
1062 #endif
1063 		if (directory) {
1064 			resolved_path_len = strlen(resolved_path);
1065 			if (resolved_path[resolved_path_len - 1] != DEFAULT_SLASH) {
1066 				resolved_path[resolved_path_len] = DEFAULT_SLASH;
1067 				resolved_path[++resolved_path_len] = '\0';
1068 			}
1069 			uri = (char *) xmlCanonicPath((const xmlChar *) resolved_path);
1070 		}
1071 		PHP_LIBXML_SANITIZE_GLOBALS(text_reader);
1072 		reader = xmlNewTextReader(inputbfr, uri);
1073 
1074 		if (reader != NULL) {
1075 			ret = xmlTextReaderSetup(reader, NULL, uri, encoding, options);
1076 			if (ret == 0) {
1077 				if (id == NULL) {
1078 					object_init_ex(return_value, xmlreader_class_entry);
1079 					intern = Z_XMLREADER_P(return_value);
1080 				} else {
1081 					RETVAL_TRUE;
1082 				}
1083 				intern->input = inputbfr;
1084 				intern->ptr = reader;
1085 
1086 				if (uri) {
1087 					xmlFree(uri);
1088 				}
1089 
1090 				PHP_LIBXML_RESTORE_GLOBALS(text_reader);
1091 				return;
1092 			}
1093 		}
1094 		PHP_LIBXML_RESTORE_GLOBALS(text_reader);
1095 	}
1096 
1097 	if (uri) {
1098 		xmlFree(uri);
1099 	}
1100 
1101 	if (inputbfr) {
1102 		xmlFreeParserInputBuffer(inputbfr);
1103 	}
1104 	php_error_docref(NULL, E_WARNING, "Unable to load source data");
1105 	RETURN_FALSE;
1106 }
1107 /* }}} */
1108 
1109 /* {{{ Moves the position of the current instance to the next node in the stream. */
PHP_METHOD(XMLReader,expand)1110 PHP_METHOD(XMLReader, expand)
1111 {
1112 #ifdef HAVE_DOM
1113 	zval *id, *basenode = NULL;
1114 	int ret;
1115 	xmlreader_object *intern;
1116 	xmlNode *node, *nodec;
1117 	xmlDocPtr docp = NULL;
1118 	php_libxml_node_object *domobj = NULL;
1119 
1120 	id = ZEND_THIS;
1121 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|O!", &basenode, dom_node_class_entry) == FAILURE) {
1122 		RETURN_THROWS();
1123 	}
1124 
1125 	if (basenode != NULL) {
1126 		NODE_GET_OBJ(node, basenode, xmlNodePtr, domobj);
1127 		docp = node->doc;
1128 	}
1129 
1130 	intern = Z_XMLREADER_P(id);
1131 
1132 	if (intern->ptr) {
1133 		node = xmlTextReaderExpand(intern->ptr);
1134 
1135 		if (node == NULL) {
1136 			php_error_docref(NULL, E_WARNING, "An Error Occurred while expanding");
1137 			RETURN_FALSE;
1138 		} else {
1139 			nodec = xmlDocCopyNode(node, docp, 1);
1140 			if (nodec == NULL) {
1141 				php_error_docref(NULL, E_NOTICE, "Cannot expand this node type");
1142 				RETURN_FALSE;
1143 			} else {
1144 				DOM_RET_OBJ(nodec, &ret, (dom_object *)domobj);
1145 			}
1146 		}
1147 	} else {
1148 		zend_throw_error(NULL, "Data must be loaded before expanding");
1149 		RETURN_THROWS();
1150 	}
1151 #else
1152 	zval *dummy;
1153 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|z!", &dummy) == FAILURE) {
1154 		RETURN_THROWS();
1155 	}
1156 
1157 	zend_throw_error(NULL, "XMLReader::expand() requires the DOM extension to be enabled");
1158 	RETURN_THROWS();
1159 #endif
1160 }
1161 /* }}} */
1162 
1163 /* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(xmlreader)1164 PHP_MINIT_FUNCTION(xmlreader)
1165 {
1166 
1167 	memcpy(&xmlreader_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
1168 	xmlreader_object_handlers.offset = XtOffsetOf(xmlreader_object, std);
1169 	xmlreader_object_handlers.free_obj = xmlreader_objects_free_storage;
1170 	xmlreader_object_handlers.read_property = xmlreader_read_property;
1171 	xmlreader_object_handlers.write_property = xmlreader_write_property;
1172 	xmlreader_object_handlers.get_property_ptr_ptr = xmlreader_get_property_ptr_ptr;
1173 	xmlreader_object_handlers.get_method = xmlreader_get_method;
1174 	xmlreader_object_handlers.clone_obj = NULL;
1175 
1176 	xmlreader_class_entry = register_class_XMLReader();
1177 	xmlreader_class_entry->create_object = xmlreader_objects_new;
1178 
1179 	memcpy(&xmlreader_open_fn, zend_hash_str_find_ptr(&xmlreader_class_entry->function_table, "open", sizeof("open")-1), sizeof(zend_internal_function));
1180 	xmlreader_open_fn.fn_flags &= ~ZEND_ACC_STATIC;
1181 	memcpy(&xmlreader_xml_fn, zend_hash_str_find_ptr(&xmlreader_class_entry->function_table, "xml", sizeof("xml")-1), sizeof(zend_internal_function));
1182 	xmlreader_xml_fn.fn_flags &= ~ZEND_ACC_STATIC;
1183 
1184 	zend_hash_init(&xmlreader_prop_handlers, 0, NULL, php_xmlreader_free_prop_handler, 1);
1185 	xmlreader_register_prop_handler(&xmlreader_prop_handlers, "attributeCount", xmlTextReaderAttributeCount, NULL, IS_LONG);
1186 	xmlreader_register_prop_handler(&xmlreader_prop_handlers, "baseURI", NULL, xmlTextReaderConstBaseUri, IS_STRING);
1187 	xmlreader_register_prop_handler(&xmlreader_prop_handlers, "depth", xmlTextReaderDepth, NULL, IS_LONG);
1188 	xmlreader_register_prop_handler(&xmlreader_prop_handlers, "hasAttributes", xmlTextReaderHasAttributes, NULL, _IS_BOOL);
1189 	xmlreader_register_prop_handler(&xmlreader_prop_handlers, "hasValue", xmlTextReaderHasValue, NULL, _IS_BOOL);
1190 	xmlreader_register_prop_handler(&xmlreader_prop_handlers, "isDefault", xmlTextReaderIsDefault, NULL, _IS_BOOL);
1191 	xmlreader_register_prop_handler(&xmlreader_prop_handlers, "isEmptyElement", xmlTextReaderIsEmptyElement, NULL, _IS_BOOL);
1192 	xmlreader_register_prop_handler(&xmlreader_prop_handlers, "localName", NULL, xmlTextReaderConstLocalName, IS_STRING);
1193 	xmlreader_register_prop_handler(&xmlreader_prop_handlers, "name", NULL, xmlTextReaderConstName, IS_STRING);
1194 	xmlreader_register_prop_handler(&xmlreader_prop_handlers, "namespaceURI", NULL, xmlTextReaderConstNamespaceUri, IS_STRING);
1195 	xmlreader_register_prop_handler(&xmlreader_prop_handlers, "nodeType", xmlTextReaderNodeType, NULL, IS_LONG);
1196 	xmlreader_register_prop_handler(&xmlreader_prop_handlers, "prefix", NULL, xmlTextReaderConstPrefix, IS_STRING);
1197 	xmlreader_register_prop_handler(&xmlreader_prop_handlers, "value", NULL, xmlTextReaderConstValue, IS_STRING);
1198 	xmlreader_register_prop_handler(&xmlreader_prop_handlers, "xmlLang", NULL, xmlTextReaderConstXmlLang, IS_STRING);
1199 
1200 	/* Constants for NodeType - cannot define common types to share with dom as there are differences in these types */
1201 
1202 	REGISTER_XMLREADER_CLASS_CONST_LONG("NONE",	XML_READER_TYPE_NONE);
1203 	REGISTER_XMLREADER_CLASS_CONST_LONG("ELEMENT",	XML_READER_TYPE_ELEMENT);
1204 	REGISTER_XMLREADER_CLASS_CONST_LONG("ATTRIBUTE",	XML_READER_TYPE_ATTRIBUTE);
1205 	REGISTER_XMLREADER_CLASS_CONST_LONG("TEXT",	XML_READER_TYPE_TEXT);
1206 	REGISTER_XMLREADER_CLASS_CONST_LONG("CDATA",	XML_READER_TYPE_CDATA);
1207 	REGISTER_XMLREADER_CLASS_CONST_LONG("ENTITY_REF",	XML_READER_TYPE_ENTITY_REFERENCE);
1208 	REGISTER_XMLREADER_CLASS_CONST_LONG("ENTITY",	XML_READER_TYPE_ENTITY);
1209 	REGISTER_XMLREADER_CLASS_CONST_LONG("PI",	XML_READER_TYPE_PROCESSING_INSTRUCTION);
1210 	REGISTER_XMLREADER_CLASS_CONST_LONG("COMMENT",	XML_READER_TYPE_COMMENT);
1211 	REGISTER_XMLREADER_CLASS_CONST_LONG("DOC",	XML_READER_TYPE_DOCUMENT);
1212 	REGISTER_XMLREADER_CLASS_CONST_LONG("DOC_TYPE",	XML_READER_TYPE_DOCUMENT_TYPE);
1213 	REGISTER_XMLREADER_CLASS_CONST_LONG("DOC_FRAGMENT",	XML_READER_TYPE_DOCUMENT_FRAGMENT);
1214 	REGISTER_XMLREADER_CLASS_CONST_LONG("NOTATION",	XML_READER_TYPE_NOTATION);
1215 	REGISTER_XMLREADER_CLASS_CONST_LONG("WHITESPACE",	XML_READER_TYPE_WHITESPACE);
1216 	REGISTER_XMLREADER_CLASS_CONST_LONG("SIGNIFICANT_WHITESPACE",	XML_READER_TYPE_SIGNIFICANT_WHITESPACE);
1217 	REGISTER_XMLREADER_CLASS_CONST_LONG("END_ELEMENT",	XML_READER_TYPE_END_ELEMENT);
1218 	REGISTER_XMLREADER_CLASS_CONST_LONG("END_ENTITY",	XML_READER_TYPE_END_ENTITY);
1219 	REGISTER_XMLREADER_CLASS_CONST_LONG("XML_DECLARATION",	XML_READER_TYPE_XML_DECLARATION);
1220 
1221 	/* Constants for Parser options */
1222 	REGISTER_XMLREADER_CLASS_CONST_LONG("LOADDTD",	XML_PARSER_LOADDTD);
1223 	REGISTER_XMLREADER_CLASS_CONST_LONG("DEFAULTATTRS",	XML_PARSER_DEFAULTATTRS);
1224 	REGISTER_XMLREADER_CLASS_CONST_LONG("VALIDATE",	XML_PARSER_VALIDATE);
1225 	REGISTER_XMLREADER_CLASS_CONST_LONG("SUBST_ENTITIES",	XML_PARSER_SUBST_ENTITIES);
1226 
1227 	/* Constants for Errors when loading - not yet used until we implement custom error handling
1228 	REGISTER_XMLREADER_CLASS_CONST_LONG("VALIDITY_WARNING",		XML_PARSER_SEVERITY_VALIDITY_WARNING,	CONST_CS | CONST_PERSISTENT);
1229 	REGISTER_XMLREADER_CLASS_CONST_LONG("VALIDITY_ERROR",		XML_PARSER_SEVERITY_VALIDITY_ERROR,		CONST_CS | CONST_PERSISTENT);
1230 	REGISTER_XMLREADER_CLASS_CONST_LONG("WARNING",				XML_PARSER_SEVERITY_WARNING,			CONST_CS | CONST_PERSISTENT);
1231 	REGISTER_XMLREADER_CLASS_CONST_LONG("ERROR",				XML_PARSER_SEVERITY_ERROR,				CONST_CS | CONST_PERSISTENT);
1232 	*/
1233 
1234 	return SUCCESS;
1235 }
1236 /* }}} */
1237 
1238 /* {{{ PHP_MSHUTDOWN_FUNCTION */
PHP_MSHUTDOWN_FUNCTION(xmlreader)1239 PHP_MSHUTDOWN_FUNCTION(xmlreader)
1240 {
1241 	zend_hash_destroy(&xmlreader_prop_handlers);
1242 	return SUCCESS;
1243 }
1244 /* }}} */
1245 
1246 /* {{{ PHP_MINFO_FUNCTION */
PHP_MINFO_FUNCTION(xmlreader)1247 PHP_MINFO_FUNCTION(xmlreader)
1248 {
1249 	php_info_print_table_start();
1250 	{
1251 		php_info_print_table_row(2, "XMLReader", "enabled");
1252 	}
1253 	php_info_print_table_end();
1254 }
1255 /* }}} */
1256