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 */
29ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_import_stylesheet, 0, 0, 1)
30	ZEND_ARG_INFO(0, doc)
31ZEND_END_ARG_INFO();
32
33ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_transform_to_doc, 0, 0, 1)
34	ZEND_ARG_INFO(0, doc)
35ZEND_END_ARG_INFO();
36
37ZEND_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)
40ZEND_END_ARG_INFO();
41
42ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_transform_to_xml, 0, 0, 1)
43	ZEND_ARG_INFO(0, doc)
44ZEND_END_ARG_INFO();
45
46ZEND_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)
50ZEND_END_ARG_INFO();
51
52ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_get_parameter, 0, 0, 2)
53	ZEND_ARG_INFO(0, namespace)
54	ZEND_ARG_INFO(0, name)
55ZEND_END_ARG_INFO();
56
57ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_remove_parameter, 0, 0, 2)
58	ZEND_ARG_INFO(0, namespace)
59	ZEND_ARG_INFO(0, name)
60ZEND_END_ARG_INFO();
61
62ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_has_exslt_support, 0, 0, 0)
63ZEND_END_ARG_INFO();
64
65ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_register_php_functions, 0, 0, 0)
66	ZEND_ARG_INFO(0, restrict)
67ZEND_END_ARG_INFO();
68
69ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_set_profiling, 0, 0, 1)
70	ZEND_ARG_INFO(0, filename)
71ZEND_END_ARG_INFO();
72
73ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_set_security_prefs, 0, 0, 1)
74	ZEND_ARG_INFO(0, securityPrefs)
75ZEND_END_ARG_INFO();
76
77ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_get_security_prefs, 0, 0, 0)
78ZEND_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
88const 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 */
106static 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 */
132static 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
174static 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
376void xsl_ext_function_string_php(xmlXPathParserContextPtr ctxt, int nargs) /* {{{ */
377{
378	xsl_ext_function_php(ctxt, nargs, 1);
379}
380/* }}} */
381
382void 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)
389URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#
390Since:
391*/
392PHP_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
472static 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)
613URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#
614Since:
615*/
616PHP_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*/
671PHP_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*/
703PHP_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*/
741PHP_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*/
781PHP_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*/
806PHP_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*/
830PHP_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) */
865PHP_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) */
891PHP_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() */
911PHP_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*/
928PHP_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