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