xref: /PHP-7.4/ext/xsl/xsltprocessor.c (revision 8226e704)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) The PHP Group                                          |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Authors: Christian Stocker <chregu@php.net>                          |
16    |          Rob Richards <rrichards@php.net>                            |
17    +----------------------------------------------------------------------+
18 */
19 
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #include "php.h"
25 #include "php_xsl.h"
26 #include "ext/libxml/php_libxml.h"
27 
28 /* {{{ arginfo */
29 ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_import_stylesheet, 0, 0, 1)
30 	ZEND_ARG_INFO(0, doc)
31 ZEND_END_ARG_INFO();
32 
33 ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_transform_to_doc, 0, 0, 1)
34 	ZEND_ARG_INFO(0, doc)
35 ZEND_END_ARG_INFO();
36 
37 ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_transform_to_uri, 0, 0, 2)
38 	ZEND_ARG_INFO(0, doc)
39 	ZEND_ARG_INFO(0, uri)
40 ZEND_END_ARG_INFO();
41 
42 ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_transform_to_xml, 0, 0, 1)
43 	ZEND_ARG_INFO(0, doc)
44 ZEND_END_ARG_INFO();
45 
46 ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_set_parameter, 0, 0, 2)
47 	ZEND_ARG_INFO(0, namespace)
48 	ZEND_ARG_INFO(0, name)
49 	ZEND_ARG_INFO(0, value)
50 ZEND_END_ARG_INFO();
51 
52 ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_get_parameter, 0, 0, 2)
53 	ZEND_ARG_INFO(0, namespace)
54 	ZEND_ARG_INFO(0, name)
55 ZEND_END_ARG_INFO();
56 
57 ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_remove_parameter, 0, 0, 2)
58 	ZEND_ARG_INFO(0, namespace)
59 	ZEND_ARG_INFO(0, name)
60 ZEND_END_ARG_INFO();
61 
62 ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_has_exslt_support, 0, 0, 0)
63 ZEND_END_ARG_INFO();
64 
65 ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_register_php_functions, 0, 0, 0)
66 	ZEND_ARG_INFO(0, restrict)
67 ZEND_END_ARG_INFO();
68 
69 ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_set_profiling, 0, 0, 1)
70 	ZEND_ARG_INFO(0, filename)
71 ZEND_END_ARG_INFO();
72 
73 ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_set_security_prefs, 0, 0, 1)
74 	ZEND_ARG_INFO(0, securityPrefs)
75 ZEND_END_ARG_INFO();
76 
77 ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_get_security_prefs, 0, 0, 0)
78 ZEND_END_ARG_INFO();
79 /* }}} */
80 
81 /*
82 * class xsl_xsltprocessor
83 *
84 * URL: https://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#
85 * Since:
86 */
87 
88 const zend_function_entry php_xsl_xsltprocessor_class_functions[] = {
89 	PHP_FALIAS(importStylesheet, xsl_xsltprocessor_import_stylesheet, arginfo_xsl_xsltprocessor_import_stylesheet)
90 	PHP_FALIAS(transformToDoc, xsl_xsltprocessor_transform_to_doc, arginfo_xsl_xsltprocessor_transform_to_doc)
91 	PHP_FALIAS(transformToUri, xsl_xsltprocessor_transform_to_uri, arginfo_xsl_xsltprocessor_transform_to_uri)
92 	PHP_FALIAS(transformToXml, xsl_xsltprocessor_transform_to_xml, arginfo_xsl_xsltprocessor_transform_to_xml)
93 	PHP_FALIAS(setParameter, xsl_xsltprocessor_set_parameter, arginfo_xsl_xsltprocessor_set_parameter)
94 	PHP_FALIAS(getParameter, xsl_xsltprocessor_get_parameter, arginfo_xsl_xsltprocessor_get_parameter)
95 	PHP_FALIAS(removeParameter, xsl_xsltprocessor_remove_parameter, arginfo_xsl_xsltprocessor_remove_parameter)
96 	PHP_FALIAS(hasExsltSupport, xsl_xsltprocessor_has_exslt_support, arginfo_xsl_xsltprocessor_has_exslt_support)
97 	PHP_FALIAS(registerPHPFunctions, xsl_xsltprocessor_register_php_functions, arginfo_xsl_xsltprocessor_register_php_functions)
98 	PHP_FALIAS(setProfiling, xsl_xsltprocessor_set_profiling, arginfo_xsl_xsltprocessor_set_profiling)
99 	PHP_FALIAS(setSecurityPrefs, xsl_xsltprocessor_set_security_prefs, arginfo_xsl_xsltprocessor_set_security_prefs)
100 	PHP_FALIAS(getSecurityPrefs, xsl_xsltprocessor_get_security_prefs, arginfo_xsl_xsltprocessor_get_security_prefs)
101 	PHP_FE_END
102 };
103 
104 /* {{{ php_xsl_xslt_string_to_xpathexpr()
105    Translates a string to a XPath Expression */
php_xsl_xslt_string_to_xpathexpr(const char * str)106 static char *php_xsl_xslt_string_to_xpathexpr(const char *str)
107 {
108 	const xmlChar *string = (const xmlChar *)str;
109 
110 	xmlChar *value;
111 	int str_len;
112 
113 	str_len = xmlStrlen(string) + 3;
114 
115 	if (xmlStrchr(string, '"')) {
116 		if (xmlStrchr(string, '\'')) {
117 			php_error_docref(NULL, E_WARNING, "Cannot create XPath expression (string contains both quote and double-quotes)");
118 			return NULL;
119 		}
120 		value = (xmlChar*) safe_emalloc (str_len, sizeof(xmlChar), 0);
121 		snprintf((char*)value, str_len, "'%s'", string);
122 	} else {
123 		value = (xmlChar*) safe_emalloc (str_len, sizeof(xmlChar), 0);
124 		snprintf((char *)value, str_len, "\"%s\"", string);
125 	}
126 	return (char *) value;
127 }
128 /* }}} */
129 
130 /* {{{ php_xsl_xslt_make_params()
131    Translates a PHP array to a libxslt parameters array */
php_xsl_xslt_make_params(HashTable * parht,int xpath_params)132 static char **php_xsl_xslt_make_params(HashTable *parht, int xpath_params)
133 {
134 
135 	int parsize;
136 	zval *value;
137 	char *xpath_expr;
138 	zend_string *string_key;
139 	char **params = NULL;
140 	int i = 0;
141 
142 	parsize = (2 * zend_hash_num_elements(parht) + 1) * sizeof(char *);
143 	params = (char **)safe_emalloc((2 * zend_hash_num_elements(parht) + 1), sizeof(char *), 0);
144 	memset((char *)params, 0, parsize);
145 
146 	ZEND_HASH_FOREACH_STR_KEY_VAL(parht, string_key, value) {
147 		if (string_key == NULL) {
148 			php_error_docref(NULL, E_WARNING, "Invalid argument or parameter array");
149 			efree(params);
150 			return NULL;
151 		} else {
152 			if (Z_TYPE_P(value) != IS_STRING) {
153 				if (!try_convert_to_string(value)) {
154 					efree(params);
155 					return NULL;
156 				}
157 			}
158 
159 			if (!xpath_params) {
160 				xpath_expr = php_xsl_xslt_string_to_xpathexpr(Z_STRVAL_P(value));
161 			} else {
162 				xpath_expr = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value));
163 			}
164 			if (xpath_expr) {
165 				params[i++] = estrndup(ZSTR_VAL(string_key), ZSTR_LEN(string_key));
166 				params[i++] = xpath_expr;
167 			}
168 		}
169 	} ZEND_HASH_FOREACH_END();
170 
171 	params[i++] = NULL;
172 
173 	return params;
174 }
175 /* }}} */
176 
xsl_ext_function_php(xmlXPathParserContextPtr ctxt,int nargs,int type)177 static void xsl_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int type) /* {{{ */
178 {
179 	xsltTransformContextPtr tctxt;
180 	zval *args = NULL;
181 	zval retval;
182 	int result, i;
183 	int error = 0;
184 	zend_fcall_info fci;
185 	zval handler;
186 	xmlXPathObjectPtr obj;
187 	char *str;
188 	xsl_object *intern;
189 	zend_string *callable = NULL;
190 
191 
192 	if (! zend_is_executing()) {
193 		xsltGenericError(xsltGenericErrorContext,
194 		"xsltExtFunctionTest: Function called from outside of PHP\n");
195 		error = 1;
196 	} else {
197 		tctxt = xsltXPathGetTransformContext(ctxt);
198 		if (tctxt == NULL) {
199 			xsltGenericError(xsltGenericErrorContext,
200 			"xsltExtFunctionTest: failed to get the transformation context\n");
201 			error = 1;
202 		} else {
203 			intern = (xsl_object*)tctxt->_private;
204 			if (intern == NULL) {
205 				xsltGenericError(xsltGenericErrorContext,
206 				"xsltExtFunctionTest: failed to get the internal object\n");
207 				error = 1;
208 			}
209 			else if (intern->registerPhpFunctions == 0) {
210 				xsltGenericError(xsltGenericErrorContext,
211 				"xsltExtFunctionTest: PHP Object did not register PHP functions\n");
212 				error = 1;
213 			}
214 		}
215 	}
216 
217 	if (error == 1) {
218 		for (i = nargs - 1; i >= 0; i--) {
219 			obj = valuePop(ctxt);
220 			if (obj) {
221 				xmlXPathFreeObject(obj);
222 			}
223 		}
224 		return;
225 	}
226 
227 	fci.param_count = nargs - 1;
228 	if (fci.param_count > 0) {
229 		args = safe_emalloc(fci.param_count, sizeof(zval), 0);
230 	}
231 	/* Reverse order to pop values off ctxt stack */
232 	for (i = nargs - 2; i >= 0; i--) {
233 		obj = valuePop(ctxt);
234 		if (obj == NULL) {
235 			ZVAL_NULL(&args[i]);
236 			continue;
237 		}
238 		switch (obj->type) {
239 			case XPATH_STRING:
240 				ZVAL_STRING(&args[i], (char *)obj->stringval);
241 				break;
242 			case XPATH_BOOLEAN:
243 				ZVAL_BOOL(&args[i],  obj->boolval);
244 				break;
245 			case XPATH_NUMBER:
246 				ZVAL_DOUBLE(&args[i], obj->floatval);
247 				break;
248 			case XPATH_NODESET:
249 				if (type == 1) {
250 					str = (char*)xmlXPathCastToString(obj);
251 					ZVAL_STRING(&args[i], str);
252 					xmlFree(str);
253 				} else if (type == 2) {
254 					int j;
255 					dom_object *domintern = (dom_object *)intern->doc;
256 					if (obj->nodesetval && obj->nodesetval->nodeNr > 0) {
257 						array_init(&args[i]);
258 						for (j = 0; j < obj->nodesetval->nodeNr; j++) {
259 							xmlNodePtr node = obj->nodesetval->nodeTab[j];
260 							zval child;
261 							/* not sure, if we need this... it's copied from xpath.c */
262 							if (node->type == XML_NAMESPACE_DECL) {
263 								xmlNsPtr curns;
264 								xmlNodePtr nsparent;
265 
266 								nsparent = node->_private;
267 								curns = xmlNewNs(NULL, node->name, NULL);
268 								if (node->children) {
269 									curns->prefix = xmlStrdup((xmlChar *)node->children);
270 								}
271 								if (node->children) {
272 									node = xmlNewDocNode(node->doc, NULL, (xmlChar *) node->children, node->name);
273 								} else {
274 									node = xmlNewDocNode(node->doc, NULL, (const xmlChar *) "xmlns", node->name);
275 								}
276 								node->type = XML_NAMESPACE_DECL;
277 								node->parent = nsparent;
278 								node->ns = curns;
279 							} else {
280 								node = xmlDocCopyNode(node, domintern->document->ptr, 1);
281 							}
282 
283 							php_dom_create_object(node, &child, domintern);
284 							add_next_index_zval(&args[i], &child);
285 						}
286 					} else {
287 						ZVAL_EMPTY_ARRAY(&args[i]);
288 					}
289 				}
290 				break;
291 			default:
292 				str = (char *) xmlXPathCastToString(obj);
293 				ZVAL_STRING(&args[i], str);
294 				xmlFree(str);
295 		}
296 		xmlXPathFreeObject(obj);
297 	}
298 
299 	fci.size = sizeof(fci);
300 	if (fci.param_count > 0) {
301 		fci.params = args;
302 	} else {
303 		fci.params = NULL;
304 	}
305 
306 
307 	obj = valuePop(ctxt);
308 	if (obj == NULL || obj->stringval == NULL) {
309 		php_error_docref(NULL, E_WARNING, "Handler name must be a string");
310 		xmlXPathFreeObject(obj);
311 		valuePush(ctxt, xmlXPathNewString((const xmlChar *) ""));
312 		if (fci.param_count > 0) {
313 			for (i = 0; i < nargs - 1; i++) {
314 				zval_ptr_dtor(&args[i]);
315 			}
316 			efree(args);
317 		}
318 		return;
319 	}
320 	ZVAL_STRING(&handler, (char *) obj->stringval);
321 	xmlXPathFreeObject(obj);
322 
323 	ZVAL_COPY_VALUE(&fci.function_name, &handler);
324 	fci.object = NULL;
325 	fci.retval = &retval;
326 	fci.no_separation = 0;
327 	/*fci.function_handler_cache = &function_ptr;*/
328 	if (!zend_make_callable(&handler, &callable)) {
329 		php_error_docref(NULL, E_WARNING, "Unable to call handler %s()", ZSTR_VAL(callable));
330 		valuePush(ctxt, xmlXPathNewString((const xmlChar *) ""));
331 	} else if ( intern->registerPhpFunctions == 2 && zend_hash_exists(intern->registered_phpfunctions, callable) == 0) {
332 		php_error_docref(NULL, E_WARNING, "Not allowed to call handler '%s()'", ZSTR_VAL(callable));
333 		/* Push an empty string, so that we at least have an xslt result... */
334 		valuePush(ctxt, xmlXPathNewString((const xmlChar *) ""));
335 	} else {
336 		result = zend_call_function(&fci, NULL);
337 		if (result == FAILURE) {
338 			if (Z_TYPE(handler) == IS_STRING) {
339 				php_error_docref(NULL, E_WARNING, "Unable to call handler %s()", Z_STRVAL(handler));
340 				valuePush(ctxt, xmlXPathNewString((const xmlChar *) ""));
341 			}
342 		/* retval is == NULL, when an exception occurred, don't report anything, because PHP itself will handle that */
343 		} else if (Z_ISUNDEF(retval)) {
344 		} else {
345 			if (Z_TYPE(retval) == IS_OBJECT && instanceof_function(Z_OBJCE(retval), dom_node_class_entry)) {
346 				xmlNode *nodep;
347 				dom_object *obj;
348 				if (intern->node_list == NULL) {
349 					intern->node_list = zend_new_array(0);
350 				}
351 				Z_ADDREF(retval);
352 				zend_hash_next_index_insert(intern->node_list, &retval);
353 				obj = Z_DOMOBJ_P(&retval);
354 				nodep = dom_object_get_node(obj);
355 				valuePush(ctxt, xmlXPathNewNodeSet(nodep));
356 			} else if (Z_TYPE(retval) == IS_TRUE || Z_TYPE(retval) == IS_FALSE) {
357 				valuePush(ctxt, xmlXPathNewBoolean(Z_TYPE(retval) == IS_TRUE));
358 			} else if (Z_TYPE(retval) == IS_OBJECT) {
359 				php_error_docref(NULL, E_WARNING, "A PHP Object cannot be converted to a XPath-string");
360 				valuePush(ctxt, xmlXPathNewString((const xmlChar *) ""));
361 			} else {
362 				convert_to_string_ex(&retval);
363 				valuePush(ctxt, xmlXPathNewString((xmlChar *) Z_STRVAL(retval)));
364 			}
365 			zval_ptr_dtor(&retval);
366 		}
367 	}
368 	zend_string_release_ex(callable, 0);
369 	zval_ptr_dtor(&handler);
370 	if (fci.param_count > 0) {
371 		for (i = 0; i < nargs - 1; i++) {
372 			zval_ptr_dtor(&args[i]);
373 		}
374 		efree(args);
375 	}
376 }
377 /* }}} */
378 
xsl_ext_function_string_php(xmlXPathParserContextPtr ctxt,int nargs)379 void xsl_ext_function_string_php(xmlXPathParserContextPtr ctxt, int nargs) /* {{{ */
380 {
381 	xsl_ext_function_php(ctxt, nargs, 1);
382 }
383 /* }}} */
384 
xsl_ext_function_object_php(xmlXPathParserContextPtr ctxt,int nargs)385 void xsl_ext_function_object_php(xmlXPathParserContextPtr ctxt, int nargs) /* {{{ */
386 {
387 	xsl_ext_function_php(ctxt, nargs, 2);
388 }
389 /* }}} */
390 
391 /* {{{ proto void xsl_xsltprocessor_import_stylesheet(domdocument doc)
392 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#
393 Since:
394 */
PHP_FUNCTION(xsl_xsltprocessor_import_stylesheet)395 PHP_FUNCTION(xsl_xsltprocessor_import_stylesheet)
396 {
397 	zval *id, *docp = NULL;
398 	xmlDoc *doc = NULL, *newdoc = NULL;
399 	xsltStylesheetPtr sheetp, oldsheetp;
400 	xsl_object *intern;
401 	int prevSubstValue, prevExtDtdValue, clone_docu = 0;
402 	xmlNode *nodep = NULL;
403 	zval *cloneDocu, member, rv;
404 
405 	id = ZEND_THIS;
406 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &docp) == FAILURE) {
407 		RETURN_FALSE;
408 	}
409 
410 	nodep = php_libxml_import_node(docp);
411 
412 	if (nodep) {
413 		doc = nodep->doc;
414 	}
415 	if (doc == NULL) {
416 		php_error(E_WARNING, "Invalid Document");
417 		RETURN_FALSE;
418 	}
419 
420 	/* libxslt uses _private, so we must copy the imported
421 	stylesheet document otherwise the node proxies will be a mess */
422 	newdoc = xmlCopyDoc(doc, 1);
423 	xmlNodeSetBase((xmlNodePtr) newdoc, (xmlChar *)doc->URL);
424 	prevSubstValue = xmlSubstituteEntitiesDefault(1);
425 	prevExtDtdValue = xmlLoadExtDtdDefaultValue;
426 	xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
427 
428 	sheetp = xsltParseStylesheetDoc(newdoc);
429 	xmlSubstituteEntitiesDefault(prevSubstValue);
430 	xmlLoadExtDtdDefaultValue = prevExtDtdValue;
431 
432 	if (!sheetp) {
433 		xmlFreeDoc(newdoc);
434 		RETURN_FALSE;
435 	}
436 
437 	intern = Z_XSL_P(id);
438 
439 	ZVAL_STRING(&member, "cloneDocument");
440 	cloneDocu = zend_std_read_property(id, &member, BP_VAR_IS, NULL, &rv);
441 	if (Z_TYPE_P(cloneDocu) != IS_NULL) {
442 		convert_to_long(cloneDocu);
443 		clone_docu = Z_LVAL_P(cloneDocu);
444 	}
445 	zval_ptr_dtor(&member);
446 	if (clone_docu == 0) {
447 		/* check if the stylesheet is using xsl:key, if yes, we have to clone the document _always_ before a transformation */
448 		nodep = xmlDocGetRootElement(sheetp->doc);
449 		if (nodep && (nodep = nodep->children)) {
450 			while (nodep) {
451 				if (nodep->type == XML_ELEMENT_NODE && xmlStrEqual(nodep->name, (const xmlChar *) "key") && xmlStrEqual(nodep->ns->href, XSLT_NAMESPACE)) {
452 					intern->hasKeys = 1;
453 					break;
454 				}
455 				nodep = nodep->next;
456 			}
457 		}
458 	} else {
459 		intern->hasKeys = clone_docu;
460 	}
461 
462 	if ((oldsheetp = (xsltStylesheetPtr)intern->ptr)) {
463 		/* free wrapper */
464 		if (((xsltStylesheetPtr) intern->ptr)->_private != NULL) {
465 			((xsltStylesheetPtr) intern->ptr)->_private = NULL;
466 		}
467 		xsltFreeStylesheet((xsltStylesheetPtr) intern->ptr);
468 		intern->ptr = NULL;
469 	}
470 
471 	php_xsl_set_object(id, sheetp);
472 	RETVAL_TRUE;
473 }
474 /* }}} end xsl_xsltprocessor_import_stylesheet */
475 
php_xsl_apply_stylesheet(zval * id,xsl_object * intern,xsltStylesheetPtr style,zval * docp)476 static xmlDocPtr php_xsl_apply_stylesheet(zval *id, xsl_object *intern, xsltStylesheetPtr style, zval *docp) /* {{{ */
477 {
478 	xmlDocPtr newdocp = NULL;
479 	xmlDocPtr doc = NULL;
480 	xmlNodePtr node = NULL;
481 	xsltTransformContextPtr ctxt;
482 	php_libxml_node_object *object;
483 	char **params = NULL;
484 	int clone;
485 	zval *doXInclude, member, rv;
486 	FILE *f;
487 	int secPrefsError = 0;
488 	int secPrefsValue;
489 	xsltSecurityPrefsPtr secPrefs = NULL;
490 
491 	node = php_libxml_import_node(docp);
492 
493 	if (node) {
494 		doc = node->doc;
495 	}
496 	if (doc == NULL) {
497 		php_error_docref(NULL, E_WARNING, "Invalid Document");
498 		return NULL;
499 	}
500 
501 	if (style == NULL) {
502 		php_error_docref(NULL, E_WARNING, "No stylesheet associated to this object");
503 		return NULL;
504 	}
505 
506 	if (intern->profiling) {
507 		if (php_check_open_basedir(intern->profiling)) {
508 			f = NULL;
509 		} else {
510 			f = VCWD_FOPEN(intern->profiling, "w");
511 		}
512 	} else {
513 		f = NULL;
514 	}
515 
516 	if (intern->parameter) {
517 		params = php_xsl_xslt_make_params(intern->parameter, 0);
518 	}
519 
520 	intern->doc = emalloc(sizeof(php_libxml_node_object));
521 	memset(intern->doc, 0, sizeof(php_libxml_node_object));
522 
523 	if (intern->hasKeys == 1) {
524 		doc = xmlCopyDoc(doc, 1);
525 	} else {
526 		object = Z_LIBXML_NODE_P(docp);
527 		intern->doc->document = object->document;
528 	}
529 
530 	php_libxml_increment_doc_ref(intern->doc, doc);
531 
532 	ctxt = xsltNewTransformContext(style, doc);
533 	ctxt->_private = (void *) intern;
534 
535 	ZVAL_STRING(&member, "doXInclude");
536 	doXInclude = zend_std_read_property(id, &member, BP_VAR_IS, NULL, &rv);
537 	if (Z_TYPE_P(doXInclude) != IS_NULL) {
538 		convert_to_long(doXInclude);
539 		ctxt->xinclude = Z_LVAL_P(doXInclude);
540 	}
541 	zval_ptr_dtor(&member);
542 
543 	secPrefsValue = intern->securityPrefs;
544 
545 	/* if securityPrefs is set to NONE, we don't have to do any checks, but otherwise... */
546 	if (secPrefsValue != XSL_SECPREF_NONE) {
547 		secPrefs = xsltNewSecurityPrefs();
548 		if (secPrefsValue & XSL_SECPREF_READ_FILE ) {
549 			if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_READ_FILE, xsltSecurityForbid)) {
550 				secPrefsError = 1;
551 			}
552 		}
553 		if (secPrefsValue & XSL_SECPREF_WRITE_FILE ) {
554 			if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_WRITE_FILE, xsltSecurityForbid)) {
555 				secPrefsError = 1;
556 			}
557 		}
558 		if (secPrefsValue & XSL_SECPREF_CREATE_DIRECTORY ) {
559 			if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_CREATE_DIRECTORY, xsltSecurityForbid)) {
560 				secPrefsError = 1;
561 			}
562 		}
563 		if (secPrefsValue & XSL_SECPREF_READ_NETWORK) {
564 			if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_READ_NETWORK, xsltSecurityForbid)) {
565 				secPrefsError = 1;
566 			}
567 		}
568 		if (secPrefsValue & XSL_SECPREF_WRITE_NETWORK) {
569 			if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_WRITE_NETWORK, xsltSecurityForbid)) {
570 				secPrefsError = 1;
571 			}
572 		}
573 
574 		if (0 != xsltSetCtxtSecurityPrefs(secPrefs, ctxt)) {
575 			secPrefsError = 1;
576 		}
577 	}
578 
579 	if (secPrefsError == 1) {
580 		php_error_docref(NULL, E_WARNING, "Can't set libxslt security properties, not doing transformation for security reasons");
581 	} else {
582 		newdocp = xsltApplyStylesheetUser(style, doc, (const char**) params,  NULL, f, ctxt);
583 	}
584 	if (f) {
585 		fclose(f);
586 	}
587 
588 	xsltFreeTransformContext(ctxt);
589 	if (secPrefs) {
590 		xsltFreeSecurityPrefs(secPrefs);
591 	}
592 
593 	if (intern->node_list != NULL) {
594 		zend_hash_destroy(intern->node_list);
595 		FREE_HASHTABLE(intern->node_list);
596 		intern->node_list = NULL;
597 	}
598 
599 	php_libxml_decrement_doc_ref(intern->doc);
600 	efree(intern->doc);
601 	intern->doc = NULL;
602 
603 	if (params) {
604 		clone = 0;
605 		while(params[clone]) {
606 			efree(params[clone++]);
607 		}
608 		efree(params);
609 	}
610 
611 	return newdocp;
612 
613 }
614 /* }}} */
615 
616 /* {{{ proto domdocument xsl_xsltprocessor_transform_to_doc(domnode doc)
617 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#
618 Since:
619 */
PHP_FUNCTION(xsl_xsltprocessor_transform_to_doc)620 PHP_FUNCTION(xsl_xsltprocessor_transform_to_doc)
621 {
622 	zval *id, *docp = NULL;
623 	xmlDoc *newdocp;
624 	xsltStylesheetPtr sheetp;
625 	zend_string *ret_class = NULL;
626 	xsl_object *intern;
627 
628 	id = ZEND_THIS;
629 	intern = Z_XSL_P(id);
630 	sheetp = (xsltStylesheetPtr) intern->ptr;
631 
632 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "o|S!", &docp, &ret_class) == FAILURE) {
633 		RETURN_FALSE;
634 	}
635 
636 	newdocp = php_xsl_apply_stylesheet(id, intern, sheetp, docp);
637 
638 	if (newdocp) {
639 		if (ret_class) {
640 			zend_string *curclass_name;
641 			zend_class_entry *curce, *ce;
642 			php_libxml_node_object *interndoc;
643 
644 			curce = Z_OBJCE_P(docp);
645 			curclass_name = curce->name;
646 			while (curce->parent != NULL) {
647 				curce = curce->parent;
648 			}
649 
650 			ce = zend_lookup_class(ret_class);
651 			if (ce == NULL || !instanceof_function(ce, curce)) {
652 				xmlFreeDoc(newdocp);
653 				php_error_docref(NULL, E_WARNING,
654 					"Expecting class compatible with %s, '%s' given", ZSTR_VAL(curclass_name), ZSTR_VAL(ret_class));
655 				RETURN_FALSE;
656 			}
657 
658 			object_init_ex(return_value, ce);
659 
660 			interndoc = Z_LIBXML_NODE_P(return_value);
661 			php_libxml_increment_doc_ref(interndoc, newdocp);
662 			php_libxml_increment_node_ptr(interndoc, (xmlNodePtr)newdocp, (void *)interndoc);
663 		} else {
664 			php_dom_create_object((xmlNodePtr) newdocp, return_value, NULL);
665 		}
666 	} else {
667 		RETURN_FALSE;
668 	}
669 
670 }
671 /* }}} end xsl_xsltprocessor_transform_to_doc */
672 
673 /* {{{ proto int xsl_xsltprocessor_transform_to_uri(domdocument doc, string uri)
674 */
PHP_FUNCTION(xsl_xsltprocessor_transform_to_uri)675 PHP_FUNCTION(xsl_xsltprocessor_transform_to_uri)
676 {
677 	zval *id, *docp = NULL;
678 	xmlDoc *newdocp;
679 	xsltStylesheetPtr sheetp;
680 	int ret;
681 	size_t uri_len;
682 	char *uri;
683 	xsl_object *intern;
684 
685 	id = ZEND_THIS;
686 	intern = Z_XSL_P(id);
687 	sheetp = (xsltStylesheetPtr) intern->ptr;
688 
689 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "op", &docp, &uri, &uri_len) == FAILURE) {
690 		RETURN_FALSE;
691 	}
692 
693 	newdocp = php_xsl_apply_stylesheet(id, intern, sheetp, docp);
694 
695 	ret = -1;
696 	if (newdocp) {
697 		ret = xsltSaveResultToFilename(uri, newdocp, sheetp, 0);
698 		xmlFreeDoc(newdocp);
699 	}
700 
701 	RETVAL_LONG(ret);
702 }
703 /* }}} end xsl_xsltprocessor_transform_to_uri */
704 
705 /* {{{ proto string xsl_xsltprocessor_transform_to_xml(domdocument doc)
706 */
PHP_FUNCTION(xsl_xsltprocessor_transform_to_xml)707 PHP_FUNCTION(xsl_xsltprocessor_transform_to_xml)
708 {
709 	zval *id, *docp = NULL;
710 	xmlDoc *newdocp;
711 	xsltStylesheetPtr sheetp;
712 	int ret;
713 	xmlChar *doc_txt_ptr;
714 	int doc_txt_len;
715 	xsl_object *intern;
716 
717 	id = ZEND_THIS;
718 	intern = Z_XSL_P(id);
719 	sheetp = (xsltStylesheetPtr) intern->ptr;
720 
721 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &docp) == FAILURE) {
722 		RETURN_FALSE;
723 	}
724 
725 	newdocp = php_xsl_apply_stylesheet(id, intern, sheetp, docp);
726 
727 	ret = -1;
728 	if (newdocp) {
729 		ret = xsltSaveResultToString(&doc_txt_ptr, &doc_txt_len, newdocp, sheetp);
730 		if (doc_txt_ptr && doc_txt_len) {
731 			RETVAL_STRINGL((char *) doc_txt_ptr, doc_txt_len);
732 			xmlFree(doc_txt_ptr);
733 		}
734 		xmlFreeDoc(newdocp);
735 	}
736 
737 	if (ret < 0) {
738 		RETURN_FALSE;
739 	}
740 }
741 /* }}} end xsl_xsltprocessor_transform_to_xml */
742 
743 /* {{{ proto bool xsl_xsltprocessor_set_parameter(string namespace, mixed name [, string value])
744 */
PHP_FUNCTION(xsl_xsltprocessor_set_parameter)745 PHP_FUNCTION(xsl_xsltprocessor_set_parameter)
746 {
747 
748 	zval *id;
749 	zval *array_value, *entry, new_string;
750 	xsl_object *intern;
751 	char *namespace;
752 	size_t namespace_len;
753 	zend_string *string_key, *name, *value;
754 	DOM_GET_THIS(id);
755 
756 	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "sa", &namespace, &namespace_len, &array_value) == SUCCESS) {
757 		intern = Z_XSL_P(id);
758 		ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(array_value), string_key, entry) {
759 			zval tmp;
760 			zend_string *str;
761 
762 			if (string_key == NULL) {
763 				php_error_docref(NULL, E_WARNING, "Invalid parameter array");
764 				RETURN_FALSE;
765 			}
766 			str = zval_try_get_string(entry);
767 			if (UNEXPECTED(!str)) {
768 				return;
769 			}
770 			ZVAL_STR(&tmp, str);
771 			zend_hash_update(intern->parameter, string_key, &tmp);
772 		} ZEND_HASH_FOREACH_END();
773 		RETURN_TRUE;
774 	} else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "sSS", &namespace, &namespace_len, &name, &value) == SUCCESS) {
775 
776 		intern = Z_XSL_P(id);
777 
778 		ZVAL_STR_COPY(&new_string, value);
779 
780 		zend_hash_update(intern->parameter, name, &new_string);
781 		RETURN_TRUE;
782 	} else {
783 		WRONG_PARAM_COUNT;
784 	}
785 
786 }
787 /* }}} end xsl_xsltprocessor_set_parameter */
788 
789 /* {{{ proto string xsl_xsltprocessor_get_parameter(string namespace, string name)
790 */
PHP_FUNCTION(xsl_xsltprocessor_get_parameter)791 PHP_FUNCTION(xsl_xsltprocessor_get_parameter)
792 {
793 	zval *id;
794 	char *namespace;
795 	size_t namespace_len = 0;
796 	zval *value;
797 	zend_string *name;
798 	xsl_object *intern;
799 
800 	DOM_GET_THIS(id);
801 
802 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sS", &namespace, &namespace_len, &name) == FAILURE) {
803 		RETURN_FALSE;
804 	}
805 	intern = Z_XSL_P(id);
806 	if ((value = zend_hash_find(intern->parameter, name)) != NULL) {
807 		RETURN_STR(zval_get_string(value));
808 	} else {
809 		RETURN_FALSE;
810 	}
811 }
812 /* }}} end xsl_xsltprocessor_get_parameter */
813 
814 /* {{{ proto bool xsl_xsltprocessor_remove_parameter(string namespace, string name)
815 */
PHP_FUNCTION(xsl_xsltprocessor_remove_parameter)816 PHP_FUNCTION(xsl_xsltprocessor_remove_parameter)
817 {
818 	zval *id;
819 	size_t namespace_len = 0;
820 	char *namespace;
821 	zend_string *name;
822 	xsl_object *intern;
823 
824 	DOM_GET_THIS(id);
825 
826 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sS", &namespace, &namespace_len, &name) == FAILURE) {
827 		RETURN_FALSE;
828 	}
829 	intern = Z_XSL_P(id);
830 	if (zend_hash_del(intern->parameter, name) == SUCCESS) {
831 		RETURN_TRUE;
832 	} else {
833 		RETURN_FALSE;
834 	}
835 }
836 /* }}} end xsl_xsltprocessor_remove_parameter */
837 
838 /* {{{ proto void xsl_xsltprocessor_register_php_functions([mixed $restrict])
839 */
PHP_FUNCTION(xsl_xsltprocessor_register_php_functions)840 PHP_FUNCTION(xsl_xsltprocessor_register_php_functions)
841 {
842 	zval *id;
843 	xsl_object *intern;
844 	zval *array_value, *entry, new_string;
845 	zend_string *name;
846 
847 	DOM_GET_THIS(id);
848 
849 	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "a",  &array_value) == SUCCESS) {
850 		intern = Z_XSL_P(id);
851 
852 		ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(array_value), entry) {
853 			zend_string *str = zval_try_get_string(entry);
854 			if (UNEXPECTED(!str)) {
855 				return;
856 			}
857 			ZVAL_LONG(&new_string, 1);
858 			zend_hash_update(intern->registered_phpfunctions, str, &new_string);
859 			zend_string_release(str);
860 		} ZEND_HASH_FOREACH_END();
861 
862 		intern->registerPhpFunctions = 2;
863 	} else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "S",  &name) == SUCCESS) {
864 		intern = Z_XSL_P(id);
865 
866 		ZVAL_LONG(&new_string,1);
867 		zend_hash_update(intern->registered_phpfunctions, name, &new_string);
868 		intern->registerPhpFunctions = 2;
869 
870 	} else {
871 		intern = Z_XSL_P(id);
872 		intern->registerPhpFunctions = 1;
873 	}
874 
875 }
876 /* }}} end xsl_xsltprocessor_register_php_functions(); */
877 
878 /* {{{ proto bool xsl_xsltprocessor_set_profiling(string filename) */
PHP_FUNCTION(xsl_xsltprocessor_set_profiling)879 PHP_FUNCTION(xsl_xsltprocessor_set_profiling)
880 {
881 	zval *id;
882 	xsl_object *intern;
883 	char *filename = NULL;
884 	size_t filename_len;
885 	DOM_GET_THIS(id);
886 
887 	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "p!", &filename, &filename_len) == SUCCESS) {
888 		intern = Z_XSL_P(id);
889 		if (intern->profiling) {
890 			efree(intern->profiling);
891 		}
892 		if (filename != NULL) {
893 			intern->profiling = estrndup(filename, filename_len);
894 		} else {
895 			intern->profiling = NULL;
896 		}
897 		RETURN_TRUE;
898 	} else {
899 		WRONG_PARAM_COUNT;
900 	}
901 }
902 /* }}} end xsl_xsltprocessor_set_profiling */
903 
904 /* {{{ proto int xsl_xsltprocessor_set_security_prefs(int securityPrefs) */
PHP_FUNCTION(xsl_xsltprocessor_set_security_prefs)905 PHP_FUNCTION(xsl_xsltprocessor_set_security_prefs)
906 {
907 	zval *id;
908 	xsl_object *intern;
909 	zend_long securityPrefs, oldSecurityPrefs;
910 
911 	DOM_GET_THIS(id);
912  	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &securityPrefs) == FAILURE) {
913 		return;
914 	}
915 	intern = Z_XSL_P(id);
916 	oldSecurityPrefs = intern->securityPrefs;
917 	intern->securityPrefs = securityPrefs;
918 	/* set this to 1 so that we know, it was set through this method. Can be removed, when we remove the ini setting */
919 	intern->securityPrefsSet = 1;
920 	RETURN_LONG(oldSecurityPrefs);
921 }
922 /* }}} end xsl_xsltprocessor_set_security_prefs */
923 
924 /* {{{ proto int xsl_xsltprocessor_get_security_prefs() */
PHP_FUNCTION(xsl_xsltprocessor_get_security_prefs)925 PHP_FUNCTION(xsl_xsltprocessor_get_security_prefs)
926 {
927 	zval *id;
928 	xsl_object *intern;
929 
930 	DOM_GET_THIS(id);
931 	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "") == SUCCESS) {
932 		intern = Z_XSL_P(id);
933 		RETURN_LONG(intern->securityPrefs);
934 	} else {
935 		WRONG_PARAM_COUNT;
936 	}
937 }
938 /* }}} end xsl_xsltprocessor_get_security_prefs */
939 
940 /* {{{ proto bool xsl_xsltprocessor_has_exslt_support()
941 */
PHP_FUNCTION(xsl_xsltprocessor_has_exslt_support)942 PHP_FUNCTION(xsl_xsltprocessor_has_exslt_support)
943 {
944 #if HAVE_XSL_EXSLT
945 	RETURN_TRUE;
946 #else
947 	RETURN_FALSE;
948 #endif
949 }
950 /* }}} end xsl_xsltprocessor_has_exslt_support(); */
951