xref: /PHP-8.2/ext/xsl/xsltprocessor.c (revision 4bd63568)
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    | Authors: Christian Stocker <chregu@php.net>                          |
14    |          Rob Richards <rrichards@php.net>                            |
15    +----------------------------------------------------------------------+
16 */
17 
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21 
22 #include "php.h"
23 #include "php_xsl.h"
24 #include <libxslt/variables.h>
25 #include "ext/libxml/php_libxml.h"
26 
27 
php_xsl_xslt_apply_params(xsltTransformContextPtr ctxt,HashTable * params)28 static zend_result php_xsl_xslt_apply_params(xsltTransformContextPtr ctxt, HashTable *params)
29 {
30 	zend_string *string_key;
31 	zval *value;
32 
33 	ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(params, string_key, value) {
34 		ZEND_ASSERT(string_key != NULL);
35 		/* Already a string because of setParameter() */
36 		ZEND_ASSERT(Z_TYPE_P(value) == IS_STRING);
37 
38 		int result = xsltQuoteOneUserParam(ctxt, (const xmlChar *) ZSTR_VAL(string_key), (const xmlChar *) Z_STRVAL_P(value));
39 		if (result < 0) {
40 			php_error_docref(NULL, E_WARNING, "Could not apply parameter \"%s\"", ZSTR_VAL(string_key));
41 			return FAILURE;
42 		}
43 	} ZEND_HASH_FOREACH_END();
44 
45 	return SUCCESS;
46 }
47 
xsl_proxy_factory(xmlNodePtr node,zval * child,dom_object * intern,xmlXPathParserContextPtr ctxt)48 static void xsl_proxy_factory(xmlNodePtr node, zval *child, dom_object *intern, xmlXPathParserContextPtr ctxt)
49 {
50 	ZEND_ASSERT(node->type != XML_NAMESPACE_DECL);
51 
52 	/**
53 	 * Upon freeing libxslt's context, every document that is not the *main* document will be freed by libxslt.
54 	 * If a node of a document that is *not the main* document gets returned to userland, we'd free the node twice:
55 	 * first by the cleanup of the xslt context, and then by our own refcounting mechanism.
56 	 * To prevent this, we'll take a copy if the node is not from the main document.
57 	 * It is important that we do not copy the node unconditionally, because that means that:
58 	 *  - modifications to the node will only modify the copy, and not the original
59 	 *  - accesses to the parent, path, ... will not work
60 	 */
61 	xsltTransformContextPtr transform_ctxt = (xsltTransformContextPtr) ctxt->context->extra;
62 	if (node->doc != transform_ctxt->document->doc) {
63 		node = xmlDocCopyNode(node, intern->document->ptr, 1);
64 	}
65 	php_dom_create_object(node, child, intern);
66 }
67 
xsl_ext_fetch_intern(xmlXPathParserContextPtr ctxt)68 static xsl_object *xsl_ext_fetch_intern(xmlXPathParserContextPtr ctxt)
69 {
70 	if (UNEXPECTED(!zend_is_executing())) {
71 		xsltGenericError(xsltGenericErrorContext,
72 		"xsltExtFunctionTest: Function called from outside of PHP\n");
73 		return NULL;
74 	}
75 
76 	xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt);
77 	if (UNEXPECTED(tctxt == NULL)) {
78 		xsltGenericError(xsltGenericErrorContext,
79 		"xsltExtFunctionTest: failed to get the transformation context\n");
80 		return NULL;
81 	}
82 
83 	xsl_object *intern = (xsl_object *) tctxt->_private;
84 	if (UNEXPECTED(intern == NULL)) {
85 		xsltGenericError(xsltGenericErrorContext,
86 		"xsltExtFunctionTest: failed to get the internal object\n");
87 		return NULL;
88 	}
89 	return intern;
90 }
91 
xsl_ext_function_php(xmlXPathParserContextPtr ctxt,int nargs,php_dom_xpath_nodeset_evaluation_mode evaluation_mode)92 static void xsl_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, php_dom_xpath_nodeset_evaluation_mode evaluation_mode) /* {{{ */
93 {
94 	xsl_object *intern = xsl_ext_fetch_intern(ctxt);
95 	if (!intern) {
96 		php_dom_xpath_callbacks_clean_argument_stack(ctxt, nargs);
97 	} else {
98 		php_dom_xpath_callbacks_call_php_ns(&intern->xpath_callbacks, ctxt, nargs, evaluation_mode, (dom_object *) intern->doc, xsl_proxy_factory);
99 	}
100 }
101 /* }}} */
102 
xsl_ext_function_string_php(xmlXPathParserContextPtr ctxt,int nargs)103 void xsl_ext_function_string_php(xmlXPathParserContextPtr ctxt, int nargs) /* {{{ */
104 {
105 	xsl_ext_function_php(ctxt, nargs, PHP_DOM_XPATH_EVALUATE_NODESET_TO_STRING);
106 }
107 /* }}} */
108 
xsl_ext_function_object_php(xmlXPathParserContextPtr ctxt,int nargs)109 void xsl_ext_function_object_php(xmlXPathParserContextPtr ctxt, int nargs) /* {{{ */
110 {
111 	xsl_ext_function_php(ctxt, nargs, PHP_DOM_XPATH_EVALUATE_NODESET_TO_NODESET);
112 }
113 /* }}} */
114 
xsl_ext_function_trampoline(xmlXPathParserContextPtr ctxt,int nargs)115 static void xsl_ext_function_trampoline(xmlXPathParserContextPtr ctxt, int nargs)
116 {
117 	xsl_object *intern = xsl_ext_fetch_intern(ctxt);
118 	if (!intern) {
119 		php_dom_xpath_callbacks_clean_argument_stack(ctxt, nargs);
120 	} else {
121 		php_dom_xpath_callbacks_call_custom_ns(&intern->xpath_callbacks, ctxt, nargs, PHP_DOM_XPATH_EVALUATE_NODESET_TO_NODESET, (dom_object *) intern->doc, xsl_proxy_factory);
122 	}
123 }
124 
125 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#
126 Since:
127 */
PHP_METHOD(XSLTProcessor,importStylesheet)128 PHP_METHOD(XSLTProcessor, importStylesheet)
129 {
130 	zval *id, *docp = NULL;
131 	xmlDoc *doc = NULL, *newdoc = NULL;
132 	xsltStylesheetPtr sheetp, oldsheetp;
133 	xsl_object *intern;
134 	int clone_docu = 0;
135 	xmlNode *nodep = NULL;
136 	zval *cloneDocu, rv;
137 	zend_string *member;
138 
139 	id = ZEND_THIS;
140 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &docp) == FAILURE) {
141 		RETURN_THROWS();
142 	}
143 
144 	nodep = php_libxml_import_node(docp);
145 
146 	if (nodep) {
147 		doc = nodep->doc;
148 	}
149 	if (doc == NULL) {
150 		zend_argument_type_error(1, "must be a valid XML node");
151 		RETURN_THROWS();
152 	}
153 
154 	/* libxslt uses _private, so we must copy the imported
155 	stylesheet document otherwise the node proxies will be a mess */
156 	newdoc = xmlCopyDoc(doc, 1);
157 	xmlNodeSetBase((xmlNodePtr) newdoc, (xmlChar *)doc->URL);
158 	PHP_LIBXML_SANITIZE_GLOBALS(parse);
159 	ZEND_DIAGNOSTIC_IGNORED_START("-Wdeprecated-declarations")
160 	xmlSubstituteEntitiesDefault(1);
161 	xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
162 	ZEND_DIAGNOSTIC_IGNORED_END
163 
164 	sheetp = xsltParseStylesheetDoc(newdoc);
165 	PHP_LIBXML_RESTORE_GLOBALS(parse);
166 
167 	if (!sheetp) {
168 		xmlFreeDoc(newdoc);
169 		RETURN_FALSE;
170 	}
171 
172 	intern = Z_XSL_P(id);
173 
174 	member = ZSTR_INIT_LITERAL("cloneDocument", 0);
175 	cloneDocu = zend_std_read_property(Z_OBJ_P(id), member, BP_VAR_R, NULL, &rv);
176 	clone_docu = zend_is_true(cloneDocu);
177 	zend_string_release_ex(member, 0);
178 	if (clone_docu == 0) {
179 		/* check if the stylesheet is using xsl:key, if yes, we have to clone the document _always_ before a transformation */
180 		nodep = xmlDocGetRootElement(sheetp->doc);
181 		if (nodep && (nodep = nodep->children)) {
182 			while (nodep) {
183 				if (nodep->type == XML_ELEMENT_NODE && xmlStrEqual(nodep->name, (const xmlChar *) "key") && xmlStrEqual(nodep->ns->href, XSLT_NAMESPACE)) {
184 					intern->hasKeys = true;
185 					break;
186 				}
187 				nodep = nodep->next;
188 			}
189 		}
190 	} else {
191 		intern->hasKeys = true;
192 	}
193 
194 	if ((oldsheetp = (xsltStylesheetPtr)intern->ptr)) {
195 		/* free wrapper */
196 		if (((xsltStylesheetPtr) intern->ptr)->_private != NULL) {
197 			((xsltStylesheetPtr) intern->ptr)->_private = NULL;
198 		}
199 		xsltFreeStylesheet((xsltStylesheetPtr) intern->ptr);
200 		intern->ptr = NULL;
201 	}
202 
203 	php_xsl_set_object(id, sheetp);
204 	RETVAL_TRUE;
205 }
206 /* }}} end XSLTProcessor::importStylesheet */
207 
php_xsl_delayed_lib_registration(void * ctxt,const zend_string * ns,const zend_string * name)208 static void php_xsl_delayed_lib_registration(void *ctxt, const zend_string *ns, const zend_string *name)
209 {
210 	xsltTransformContextPtr xsl = (xsltTransformContextPtr) ctxt;
211 	xsltRegisterExtFunction(xsl, (const xmlChar *) ZSTR_VAL(name), (const xmlChar *) ZSTR_VAL(ns), xsl_ext_function_trampoline);
212 }
213 
php_xsl_apply_stylesheet(zval * id,xsl_object * intern,xsltStylesheetPtr style,zval * docp)214 static xmlDocPtr php_xsl_apply_stylesheet(zval *id, xsl_object *intern, xsltStylesheetPtr style, zval *docp) /* {{{ */
215 {
216 	xmlDocPtr newdocp = NULL;
217 	xmlDocPtr doc = NULL;
218 	xmlNodePtr node = NULL;
219 	xsltTransformContextPtr ctxt;
220 	php_libxml_node_object *object;
221 	zval *doXInclude, rv;
222 	zend_string *member;
223 	FILE *f;
224 	int secPrefsError = 0;
225 	int secPrefsValue;
226 	xsltSecurityPrefsPtr secPrefs = NULL;
227 
228 	node = php_libxml_import_node(docp);
229 
230 	if (node) {
231 		doc = node->doc;
232 	}
233 
234 	if (doc == NULL) {
235 		zend_argument_type_error(1, "must be a valid XML node");
236 		return NULL;
237 	}
238 
239 	if (style == NULL) {
240 		zend_string *name = get_active_function_or_method_name();
241 		zend_throw_error(NULL, "%s() can only be called after a stylesheet has been imported",
242 			ZSTR_VAL(name));
243 		zend_string_release(name);
244 		return NULL;
245 	}
246 
247 	if (intern->profiling) {
248 		if (php_check_open_basedir(intern->profiling)) {
249 			f = NULL;
250 		} else {
251 			f = VCWD_FOPEN(intern->profiling, "w");
252 		}
253 	} else {
254 		f = NULL;
255 	}
256 
257 	intern->doc = emalloc(sizeof(php_libxml_node_object));
258 	memset(intern->doc, 0, sizeof(php_libxml_node_object));
259 
260 	if (intern->hasKeys) {
261 		doc = xmlCopyDoc(doc, 1);
262 	} else {
263 		object = Z_LIBXML_NODE_P(docp);
264 		intern->doc->document = object->document;
265 	}
266 
267 	php_libxml_increment_doc_ref(intern->doc, doc);
268 
269 	ctxt = xsltNewTransformContext(style, doc);
270 	ctxt->_private = (void *) intern;
271 
272 	if (intern->parameter) {
273 		zend_result status = php_xsl_xslt_apply_params(ctxt, intern->parameter);
274 		if (UNEXPECTED(status != SUCCESS) && EG(exception)) {
275 			goto out;
276 		}
277 	}
278 
279 	member = ZSTR_INIT_LITERAL("doXInclude", 0);
280 	doXInclude = zend_std_read_property(Z_OBJ_P(id), member, BP_VAR_R, NULL, &rv);
281 	ctxt->xinclude = zend_is_true(doXInclude);
282 	zend_string_release_ex(member, 0);
283 
284 	secPrefsValue = intern->securityPrefs;
285 
286 	/* if securityPrefs is set to NONE, we don't have to do any checks, but otherwise... */
287 	if (secPrefsValue != XSL_SECPREF_NONE) {
288 		secPrefs = xsltNewSecurityPrefs();
289 		if (secPrefsValue & XSL_SECPREF_READ_FILE ) {
290 			if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_READ_FILE, xsltSecurityForbid)) {
291 				secPrefsError = 1;
292 			}
293 		}
294 		if (secPrefsValue & XSL_SECPREF_WRITE_FILE ) {
295 			if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_WRITE_FILE, xsltSecurityForbid)) {
296 				secPrefsError = 1;
297 			}
298 		}
299 		if (secPrefsValue & XSL_SECPREF_CREATE_DIRECTORY ) {
300 			if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_CREATE_DIRECTORY, xsltSecurityForbid)) {
301 				secPrefsError = 1;
302 			}
303 		}
304 		if (secPrefsValue & XSL_SECPREF_READ_NETWORK) {
305 			if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_READ_NETWORK, xsltSecurityForbid)) {
306 				secPrefsError = 1;
307 			}
308 		}
309 		if (secPrefsValue & XSL_SECPREF_WRITE_NETWORK) {
310 			if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_WRITE_NETWORK, xsltSecurityForbid)) {
311 				secPrefsError = 1;
312 			}
313 		}
314 
315 		if (0 != xsltSetCtxtSecurityPrefs(secPrefs, ctxt)) {
316 			secPrefsError = 1;
317 		}
318 	}
319 
320 	php_dom_xpath_callbacks_delayed_lib_registration(&intern->xpath_callbacks, ctxt, php_xsl_delayed_lib_registration);
321 
322 	if (secPrefsError == 1) {
323 		php_error_docref(NULL, E_WARNING, "Can't set libxslt security properties, not doing transformation for security reasons");
324 	} else {
325 		newdocp = xsltApplyStylesheetUser(style, doc, /* params (handled manually) */ NULL, /* output */ NULL, f, ctxt);
326 	}
327 
328 out:
329 	if (f) {
330 		fclose(f);
331 	}
332 
333 	xsltFreeTransformContext(ctxt);
334 	if (secPrefs) {
335 		xsltFreeSecurityPrefs(secPrefs);
336 	}
337 
338 	php_dom_xpath_callbacks_clean_node_list(&intern->xpath_callbacks);
339 
340 	php_libxml_decrement_doc_ref(intern->doc);
341 	efree(intern->doc);
342 	intern->doc = NULL;
343 
344 	return newdocp;
345 
346 }
347 /* }}} */
348 
349 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#
350 Since:
351 */
PHP_METHOD(XSLTProcessor,transformToDoc)352 PHP_METHOD(XSLTProcessor, transformToDoc)
353 {
354 	zval *id, *docp = NULL;
355 	xmlDoc *newdocp;
356 	xsltStylesheetPtr sheetp;
357 	zend_class_entry *ret_class = NULL;
358 	xsl_object *intern;
359 
360 	id = ZEND_THIS;
361 	intern = Z_XSL_P(id);
362 	sheetp = (xsltStylesheetPtr) intern->ptr;
363 
364 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "o|C!", &docp, &ret_class) == FAILURE) {
365 		RETURN_THROWS();
366 	}
367 
368 	newdocp = php_xsl_apply_stylesheet(id, intern, sheetp, docp);
369 
370 	if (newdocp) {
371 		if (ret_class) {
372 			zend_string *curclass_name;
373 			zend_class_entry *curce;
374 			php_libxml_node_object *interndoc;
375 
376 			curce = Z_OBJCE_P(docp);
377 			curclass_name = curce->name;
378 			while (curce->parent != NULL) {
379 				curce = curce->parent;
380 			}
381 
382 			if (!instanceof_function(ret_class, curce)) {
383 				xmlFreeDoc(newdocp);
384 				zend_argument_type_error(2, "must be a class name compatible with %s, %s given",
385 					ZSTR_VAL(curclass_name), ZSTR_VAL(ret_class->name)
386 				);
387 				RETURN_THROWS();
388 			}
389 
390 			object_init_ex(return_value, ret_class);
391 
392 			interndoc = Z_LIBXML_NODE_P(return_value);
393 			php_libxml_increment_doc_ref(interndoc, newdocp);
394 			php_libxml_increment_node_ptr(interndoc, (xmlNodePtr)newdocp, (void *)interndoc);
395 		} else {
396 			php_dom_create_object((xmlNodePtr) newdocp, return_value, NULL);
397 		}
398 	} else {
399 		RETURN_FALSE;
400 	}
401 }
402 /* }}} end XSLTProcessor::transformToDoc */
403 
404 /* {{{ */
PHP_METHOD(XSLTProcessor,transformToUri)405 PHP_METHOD(XSLTProcessor, transformToUri)
406 {
407 	zval *id, *docp = NULL;
408 	xmlDoc *newdocp;
409 	xsltStylesheetPtr sheetp;
410 	int ret;
411 	size_t uri_len;
412 	char *uri;
413 	xsl_object *intern;
414 
415 	id = ZEND_THIS;
416 	intern = Z_XSL_P(id);
417 	sheetp = (xsltStylesheetPtr) intern->ptr;
418 
419 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "op", &docp, &uri, &uri_len) == FAILURE) {
420 		RETURN_THROWS();
421 	}
422 
423 	newdocp = php_xsl_apply_stylesheet(id, intern, sheetp, docp);
424 
425 	ret = -1;
426 	if (newdocp) {
427 		ret = xsltSaveResultToFilename(uri, newdocp, sheetp, 0);
428 		xmlFreeDoc(newdocp);
429 	}
430 
431 	RETVAL_LONG(ret);
432 }
433 /* }}} end XSLTProcessor::transformToUri */
434 
435 /* {{{ */
PHP_METHOD(XSLTProcessor,transformToXml)436 PHP_METHOD(XSLTProcessor, transformToXml)
437 {
438 	zval *id, *docp = NULL;
439 	xmlDoc *newdocp;
440 	xsltStylesheetPtr sheetp;
441 	int ret;
442 	xmlChar *doc_txt_ptr;
443 	int doc_txt_len;
444 	xsl_object *intern;
445 
446 	id = ZEND_THIS;
447 	intern = Z_XSL_P(id);
448 	sheetp = (xsltStylesheetPtr) intern->ptr;
449 
450 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &docp) == FAILURE) {
451 		RETURN_THROWS();
452 	}
453 
454 	newdocp = php_xsl_apply_stylesheet(id, intern, sheetp, docp);
455 
456 	ret = -1;
457 	if (newdocp) {
458 		ret = xsltSaveResultToString(&doc_txt_ptr, &doc_txt_len, newdocp, sheetp);
459 		if (doc_txt_ptr && doc_txt_len) {
460 			RETVAL_STRINGL((char *) doc_txt_ptr, doc_txt_len);
461 			xmlFree(doc_txt_ptr);
462 		}
463 		xmlFreeDoc(newdocp);
464 	}
465 
466 	if (ret < 0) {
467 		RETURN_FALSE;
468 	}
469 }
470 /* }}} end XSLTProcessor::transformToXml */
471 
472 /* {{{ */
PHP_METHOD(XSLTProcessor,setParameter)473 PHP_METHOD(XSLTProcessor, setParameter)
474 {
475 
476 	zval *id = ZEND_THIS;
477 	zval *entry, new_string;
478 	HashTable *array_value;
479 	xsl_object *intern;
480 	char *namespace;
481 	size_t namespace_len;
482 	zend_string *string_key, *name, *value = NULL;
483 
484 	ZEND_PARSE_PARAMETERS_START(2, 3)
485 		Z_PARAM_STRING(namespace, namespace_len)
486 		Z_PARAM_ARRAY_HT_OR_STR(array_value, name)
487 		Z_PARAM_OPTIONAL
488 		Z_PARAM_PATH_STR_OR_NULL(value)
489 	ZEND_PARSE_PARAMETERS_END();
490 
491 	intern = Z_XSL_P(id);
492 
493 	if (array_value) {
494 		if (value) {
495 			zend_argument_value_error(3, "must be null when argument #2 ($name) is an array");
496 			RETURN_THROWS();
497 		}
498 
499 		ZEND_HASH_FOREACH_STR_KEY_VAL(array_value, string_key, entry) {
500 			zval tmp;
501 			zend_string *str;
502 
503 			if (string_key == NULL) {
504 				zend_argument_type_error(2, "must contain only string keys");
505 				RETURN_THROWS();
506 			}
507 
508 			if (UNEXPECTED(CHECK_NULL_PATH(ZSTR_VAL(string_key), ZSTR_LEN(string_key)))) {
509 				zend_argument_value_error(3, "must not contain keys with any null bytes");
510 				RETURN_THROWS();
511 			}
512 
513 			str = zval_try_get_string(entry);
514 			if (UNEXPECTED(!str)) {
515 				RETURN_THROWS();
516 			}
517 
518 			if (UNEXPECTED(CHECK_NULL_PATH(ZSTR_VAL(str), ZSTR_LEN(str)))) {
519 				zend_string_release(str);
520 				zend_argument_value_error(3, "must not contain values with any null bytes");
521 				RETURN_THROWS();
522 			}
523 
524 			ZVAL_STR(&tmp, str);
525 			zend_hash_update(intern->parameter, string_key, &tmp);
526 		} ZEND_HASH_FOREACH_END();
527 		RETURN_TRUE;
528 	} else {
529 		if (!value) {
530 			zend_argument_value_error(3, "cannot be null when argument #2 ($name) is a string");
531 			RETURN_THROWS();
532 		}
533 
534 		if (UNEXPECTED(CHECK_NULL_PATH(ZSTR_VAL(name), ZSTR_LEN(name)))) {
535 			zend_argument_value_error(2, "must not contain any null bytes");
536 			RETURN_THROWS();
537 		}
538 
539 		ZVAL_STR_COPY(&new_string, value);
540 
541 		zend_hash_update(intern->parameter, name, &new_string);
542 		RETURN_TRUE;
543 	}
544 }
545 /* }}} end XSLTProcessor::setParameter */
546 
547 /* {{{ */
PHP_METHOD(XSLTProcessor,getParameter)548 PHP_METHOD(XSLTProcessor, getParameter)
549 {
550 	zval *id = ZEND_THIS;
551 	char *namespace;
552 	size_t namespace_len = 0;
553 	zval *value;
554 	zend_string *name;
555 	xsl_object *intern;
556 
557 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sS", &namespace, &namespace_len, &name) == FAILURE) {
558 		RETURN_THROWS();
559 	}
560 	intern = Z_XSL_P(id);
561 	if ((value = zend_hash_find(intern->parameter, name)) != NULL) {
562 		RETURN_STR_COPY(Z_STR_P(value));
563 	} else {
564 		RETURN_FALSE;
565 	}
566 }
567 /* }}} end XSLTProcessor::getParameter */
568 
569 /* {{{ */
PHP_METHOD(XSLTProcessor,removeParameter)570 PHP_METHOD(XSLTProcessor, removeParameter)
571 {
572 	zval *id = ZEND_THIS;
573 	size_t namespace_len = 0;
574 	char *namespace;
575 	zend_string *name;
576 	xsl_object *intern;
577 
578 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sS", &namespace, &namespace_len, &name) == FAILURE) {
579 		RETURN_THROWS();
580 	}
581 	intern = Z_XSL_P(id);
582 	if (zend_hash_del(intern->parameter, name) == SUCCESS) {
583 		RETURN_TRUE;
584 	} else {
585 		RETURN_FALSE;
586 	}
587 }
588 /* }}} end XSLTProcessor::removeParameter */
589 
590 /* {{{ */
PHP_METHOD(XSLTProcessor,registerPHPFunctions)591 PHP_METHOD(XSLTProcessor, registerPHPFunctions)
592 {
593 	xsl_object *intern = Z_XSL_P(ZEND_THIS);
594 
595 	zend_string *name = NULL;
596 	HashTable *callable_ht = NULL;
597 
598 	ZEND_PARSE_PARAMETERS_START(0, 1)
599 		Z_PARAM_OPTIONAL
600 		Z_PARAM_ARRAY_HT_OR_STR_OR_NULL(callable_ht, name)
601 	ZEND_PARSE_PARAMETERS_END();
602 
603 	php_dom_xpath_callbacks_update_method_handler(
604 		&intern->xpath_callbacks,
605 		NULL,
606 		NULL,
607 		name,
608 		callable_ht,
609 		PHP_DOM_XPATH_CALLBACK_NAME_VALIDATE_NULLS,
610 		NULL
611 	);
612 }
613 /* }}} end XSLTProcessor::registerPHPFunctions(); */
614 
PHP_METHOD(XSLTProcessor,registerPHPFunctionNS)615 PHP_METHOD(XSLTProcessor, registerPHPFunctionNS)
616 {
617 	xsl_object *intern = Z_XSL_P(ZEND_THIS);
618 
619 	zend_string *namespace, *name;
620 	zend_fcall_info fci;
621 	zend_fcall_info_cache fcc;
622 
623 	ZEND_PARSE_PARAMETERS_START(3, 3)
624 		Z_PARAM_PATH_STR(namespace)
625 		Z_PARAM_PATH_STR(name)
626 		Z_PARAM_FUNC_NO_TRAMPOLINE_FREE(fci, fcc)
627 	ZEND_PARSE_PARAMETERS_END();
628 
629 	if (zend_string_equals_literal(namespace, "http://php.net/xsl")) {
630 		zend_argument_value_error(1, "must not be \"http://php.net/xsl\" because it is reserved by PHP");
631 		RETURN_THROWS();
632 	}
633 
634 	php_dom_xpath_callbacks_update_single_method_handler(
635 		&intern->xpath_callbacks,
636 		NULL,
637 		namespace,
638 		name,
639 		&fcc,
640 		PHP_DOM_XPATH_CALLBACK_NAME_VALIDATE_NCNAME,
641 		NULL
642 	);
643 }
644 
645 /* {{{ */
PHP_METHOD(XSLTProcessor,setProfiling)646 PHP_METHOD(XSLTProcessor, setProfiling)
647 {
648 	zval *id = ZEND_THIS;
649 	xsl_object *intern;
650 	char *filename = NULL;
651 	size_t filename_len;
652 
653 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "p!", &filename, &filename_len) == FAILURE) {
654 		RETURN_THROWS();
655 	}
656 
657 	intern = Z_XSL_P(id);
658 	if (intern->profiling) {
659 		efree(intern->profiling);
660 	}
661 	if (filename != NULL) {
662 		intern->profiling = estrndup(filename, filename_len);
663 	} else {
664 		intern->profiling = NULL;
665 	}
666 
667 	RETURN_TRUE;
668 }
669 /* }}} end XSLTProcessor::setProfiling */
670 
671 /* {{{ */
PHP_METHOD(XSLTProcessor,setSecurityPrefs)672 PHP_METHOD(XSLTProcessor, setSecurityPrefs)
673 {
674 	zval *id = ZEND_THIS;
675 	xsl_object *intern;
676 	zend_long securityPrefs, oldSecurityPrefs;
677 
678 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &securityPrefs) == FAILURE) {
679 		RETURN_THROWS();
680 	}
681 	intern = Z_XSL_P(id);
682 	oldSecurityPrefs = intern->securityPrefs;
683 	intern->securityPrefs = securityPrefs;
684 	RETURN_LONG(oldSecurityPrefs);
685 }
686 /* }}} end XSLTProcessor::setSecurityPrefs */
687 
688 /* {{{ */
PHP_METHOD(XSLTProcessor,getSecurityPrefs)689 PHP_METHOD(XSLTProcessor, getSecurityPrefs)
690 {
691 	zval *id = ZEND_THIS;
692 	xsl_object *intern;
693 
694 	if (zend_parse_parameters_none() == FAILURE) {
695 		RETURN_THROWS();
696 	}
697 
698 	intern = Z_XSL_P(id);
699 
700 	RETURN_LONG(intern->securityPrefs);
701 }
702 /* }}} end XSLTProcessor::getSecurityPrefs */
703 
704 /* {{{ */
PHP_METHOD(XSLTProcessor,hasExsltSupport)705 PHP_METHOD(XSLTProcessor, hasExsltSupport)
706 {
707 	if (zend_parse_parameters_none() == FAILURE) {
708 		RETURN_THROWS();
709 	}
710 
711 #ifdef HAVE_XSL_EXSLT
712 	RETURN_TRUE;
713 #else
714 	RETURN_FALSE;
715 #endif
716 }
717 /* }}} end XSLTProcessor::hasExsltSupport(); */
718