1/*
2   +----------------------------------------------------------------------+
3   | PHP Version 7                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2016 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/* $Id$ */
21
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
25
26#include "php.h"
27#include "php_xsl.h"
28#include "ext/libxml/php_libxml.h"
29
30/* {{{ arginfo */
31ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_import_stylesheet, 0, 0, 1)
32	ZEND_ARG_INFO(0, doc)
33ZEND_END_ARG_INFO();
34
35ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_transform_to_doc, 0, 0, 1)
36	ZEND_ARG_INFO(0, doc)
37ZEND_END_ARG_INFO();
38
39ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_transform_to_uri, 0, 0, 2)
40	ZEND_ARG_INFO(0, doc)
41	ZEND_ARG_INFO(0, uri)
42ZEND_END_ARG_INFO();
43
44ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_transform_to_xml, 0, 0, 1)
45	ZEND_ARG_INFO(0, doc)
46ZEND_END_ARG_INFO();
47
48ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_set_parameter, 0, 0, 2)
49	ZEND_ARG_INFO(0, namespace)
50	ZEND_ARG_INFO(0, name)
51	ZEND_ARG_INFO(0, value)
52ZEND_END_ARG_INFO();
53
54ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_get_parameter, 0, 0, 2)
55	ZEND_ARG_INFO(0, namespace)
56	ZEND_ARG_INFO(0, name)
57ZEND_END_ARG_INFO();
58
59ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_remove_parameter, 0, 0, 2)
60	ZEND_ARG_INFO(0, namespace)
61	ZEND_ARG_INFO(0, name)
62ZEND_END_ARG_INFO();
63
64ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_has_exslt_support, 0, 0, 0)
65ZEND_END_ARG_INFO();
66
67ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_register_php_functions, 0, 0, 0)
68	ZEND_ARG_INFO(0, restrict)
69ZEND_END_ARG_INFO();
70
71ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_set_profiling, 0, 0, 1)
72	ZEND_ARG_INFO(0, filename)
73ZEND_END_ARG_INFO();
74
75ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_set_security_prefs, 0, 0, 1)
76	ZEND_ARG_INFO(0, securityPrefs)
77ZEND_END_ARG_INFO();
78
79ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_get_security_prefs, 0, 0, 0)
80ZEND_END_ARG_INFO();
81/* }}} */
82
83/*
84* class xsl_xsltprocessor
85*
86* URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#
87* Since:
88*/
89
90const zend_function_entry php_xsl_xsltprocessor_class_functions[] = {
91	PHP_FALIAS(importStylesheet, xsl_xsltprocessor_import_stylesheet, arginfo_xsl_xsltprocessor_import_stylesheet)
92	PHP_FALIAS(transformToDoc, xsl_xsltprocessor_transform_to_doc, arginfo_xsl_xsltprocessor_transform_to_doc)
93	PHP_FALIAS(transformToUri, xsl_xsltprocessor_transform_to_uri, arginfo_xsl_xsltprocessor_transform_to_uri)
94	PHP_FALIAS(transformToXml, xsl_xsltprocessor_transform_to_xml, arginfo_xsl_xsltprocessor_transform_to_xml)
95	PHP_FALIAS(setParameter, xsl_xsltprocessor_set_parameter, arginfo_xsl_xsltprocessor_set_parameter)
96	PHP_FALIAS(getParameter, xsl_xsltprocessor_get_parameter, arginfo_xsl_xsltprocessor_get_parameter)
97	PHP_FALIAS(removeParameter, xsl_xsltprocessor_remove_parameter, arginfo_xsl_xsltprocessor_remove_parameter)
98	PHP_FALIAS(hasExsltSupport, xsl_xsltprocessor_has_exslt_support, arginfo_xsl_xsltprocessor_has_exslt_support)
99	PHP_FALIAS(registerPHPFunctions, xsl_xsltprocessor_register_php_functions, arginfo_xsl_xsltprocessor_register_php_functions)
100	PHP_FALIAS(setProfiling, xsl_xsltprocessor_set_profiling, arginfo_xsl_xsltprocessor_set_profiling)
101	PHP_FALIAS(setSecurityPrefs, xsl_xsltprocessor_set_security_prefs, arginfo_xsl_xsltprocessor_set_security_prefs)
102	PHP_FALIAS(getSecurityPrefs, xsl_xsltprocessor_get_security_prefs, arginfo_xsl_xsltprocessor_get_security_prefs)
103	{NULL, NULL, NULL}
104};
105
106/* {{{ php_xsl_xslt_string_to_xpathexpr()
107   Translates a string to a XPath Expression */
108static char *php_xsl_xslt_string_to_xpathexpr(const char *str)
109{
110	const xmlChar *string = (const xmlChar *)str;
111
112	xmlChar *value;
113	int str_len;
114
115	str_len = xmlStrlen(string) + 3;
116
117	if (xmlStrchr(string, '"')) {
118		if (xmlStrchr(string, '\'')) {
119			php_error_docref(NULL, E_WARNING, "Cannot create XPath expression (string contains both quote and double-quotes)");
120			return NULL;
121		}
122		value = (xmlChar*) safe_emalloc (str_len, sizeof(xmlChar), 0);
123		snprintf((char*)value, str_len, "'%s'", string);
124	} else {
125		value = (xmlChar*) safe_emalloc (str_len, sizeof(xmlChar), 0);
126		snprintf((char *)value, str_len, "\"%s\"", string);
127	}
128	return (char *) value;
129}
130/* }}} */
131
132/* {{{ php_xsl_xslt_make_params()
133   Translates a PHP array to a libxslt parameters array */
134static char **php_xsl_xslt_make_params(HashTable *parht, int xpath_params)
135{
136
137	int parsize;
138	zval *value;
139	char *xpath_expr;
140	zend_string *string_key;
141	zend_ulong num_key;
142	char **params = NULL;
143	int i = 0;
144
145	parsize = (2 * zend_hash_num_elements(parht) + 1) * sizeof(char *);
146	params = (char **)safe_emalloc((2 * zend_hash_num_elements(parht) + 1), sizeof(char *), 0);
147	memset((char *)params, 0, parsize);
148
149	ZEND_HASH_FOREACH_KEY_VAL(parht, num_key, string_key, value) {
150		if (string_key == NULL) {
151			php_error_docref(NULL, E_WARNING, "Invalid argument or parameter array");
152			efree(params);
153			return NULL;
154		} else {
155			if (Z_TYPE_P(value) != IS_STRING) {
156				convert_to_string(value);
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
177static void xsl_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int type) /* {{{ */
178{
179	xsltTransformContextPtr tctxt;
180	zval *args;
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					array_init(&args[i]);
257					if (obj->nodesetval && obj->nodesetval->nodeNr > 0) {
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((char *)node->children);
270								}
271								if (node->children) {
272									node = xmlNewDocNode(node->doc, NULL, (char *) 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 = xmlDocCopyNodeList(domintern->document->ptr, node);
281							}
282
283							php_dom_create_object(node, &child, domintern);
284							add_next_index_zval(&args[i], &child);
285						}
286					}
287				}
288				break;
289			default:
290				str = (char *) xmlXPathCastToString(obj);
291				ZVAL_STRING(&args[i], str);
292				xmlFree(str);
293		}
294		xmlXPathFreeObject(obj);
295	}
296
297	fci.size = sizeof(fci);
298	if (fci.param_count > 0) {
299		fci.params = args;
300	} else {
301		fci.params = NULL;
302	}
303
304
305	obj = valuePop(ctxt);
306	if (obj == NULL || obj->stringval == NULL) {
307		php_error_docref(NULL, E_WARNING, "Handler name must be a string");
308		xmlXPathFreeObject(obj);
309		valuePush(ctxt, xmlXPathNewString((const xmlChar *) ""));
310		if (fci.param_count > 0) {
311			for (i = 0; i < nargs - 1; i++) {
312				zval_ptr_dtor(&args[i]);
313			}
314			efree(args);
315		}
316		return;
317	}
318	ZVAL_STRING(&handler, (char *) obj->stringval);
319	xmlXPathFreeObject(obj);
320
321	ZVAL_COPY_VALUE(&fci.function_name, &handler);
322	fci.object = NULL;
323	fci.retval = &retval;
324	fci.no_separation = 0;
325	/*fci.function_handler_cache = &function_ptr;*/
326	if (!zend_make_callable(&handler, &callable)) {
327		php_error_docref(NULL, E_WARNING, "Unable to call handler %s()", ZSTR_VAL(callable));
328		valuePush(ctxt, xmlXPathNewString((const xmlChar *) ""));
329	} else if ( intern->registerPhpFunctions == 2 && zend_hash_exists(intern->registered_phpfunctions, callable) == 0) {
330		php_error_docref(NULL, E_WARNING, "Not allowed to call handler '%s()'", ZSTR_VAL(callable));
331		/* Push an empty string, so that we at least have an xslt result... */
332		valuePush(ctxt, xmlXPathNewString((const xmlChar *) ""));
333	} else {
334		result = zend_call_function(&fci, NULL);
335		if (result == FAILURE) {
336			if (Z_TYPE(handler) == IS_STRING) {
337				php_error_docref(NULL, E_WARNING, "Unable to call handler %s()", Z_STRVAL(handler));
338				valuePush(ctxt, xmlXPathNewString((const xmlChar *) ""));
339			}
340		/* retval is == NULL, when an exception occurred, don't report anything, because PHP itself will handle that */
341		} else if (Z_ISUNDEF(retval)) {
342		} else {
343			if (Z_TYPE(retval) == IS_OBJECT && instanceof_function(Z_OBJCE(retval), dom_node_class_entry)) {
344				xmlNode *nodep;
345				dom_object *obj;
346				if (intern->node_list == NULL) {
347					ALLOC_HASHTABLE(intern->node_list);
348					zend_hash_init(intern->node_list, 0, NULL, ZVAL_PTR_DTOR, 0);
349				}
350				Z_ADDREF(retval);
351				zend_hash_next_index_insert(intern->node_list, &retval);
352				obj = Z_DOMOBJ_P(&retval);
353				nodep = dom_object_get_node(obj);
354				valuePush(ctxt, xmlXPathNewNodeSet(nodep));
355			} else if (Z_TYPE(retval) == IS_TRUE || Z_TYPE(retval) == IS_FALSE) {
356				valuePush(ctxt, xmlXPathNewBoolean(Z_TYPE(retval) == IS_TRUE));
357			} else if (Z_TYPE(retval) == IS_OBJECT) {
358				php_error_docref(NULL, E_WARNING, "A PHP Object cannot be converted to a XPath-string");
359				valuePush(ctxt, xmlXPathNewString((const xmlChar *) ""));
360			} else {
361				convert_to_string_ex(&retval);
362				valuePush(ctxt, xmlXPathNewString((xmlChar *) Z_STRVAL(retval)));
363			}
364			zval_ptr_dtor(&retval);
365		}
366	}
367	zend_string_release(callable);
368	zval_ptr_dtor(&handler);
369	if (fci.param_count > 0) {
370		for (i = 0; i < nargs - 1; i++) {
371			zval_ptr_dtor(&args[i]);
372		}
373		efree(args);
374	}
375}
376/* }}} */
377
378void xsl_ext_function_string_php(xmlXPathParserContextPtr ctxt, int nargs) /* {{{ */
379{
380	xsl_ext_function_php(ctxt, nargs, 1);
381}
382/* }}} */
383
384void xsl_ext_function_object_php(xmlXPathParserContextPtr ctxt, int nargs) /* {{{ */
385{
386	xsl_ext_function_php(ctxt, nargs, 2);
387}
388/* }}} */
389
390/* {{{ proto void xsl_xsltprocessor_import_stylesheet(domdocument doc)
391URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#
392Since:
393*/
394PHP_FUNCTION(xsl_xsltprocessor_import_stylesheet)
395{
396	zval *id, *docp = NULL;
397	xmlDoc *doc = NULL, *newdoc = NULL;
398	xsltStylesheetPtr sheetp, oldsheetp;
399	xsl_object *intern;
400	int prevSubstValue, prevExtDtdValue, clone_docu = 0;
401	xmlNode *nodep = NULL;
402	zend_object_handlers *std_hnd;
403	zval *cloneDocu, member, rv;
404
405	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oo", &id, xsl_xsltprocessor_class_entry, &docp) == FAILURE) {
406		RETURN_FALSE;
407	}
408
409	nodep = php_libxml_import_node(docp);
410
411	if (nodep) {
412		doc = nodep->doc;
413	}
414	if (doc == NULL) {
415		php_error(E_WARNING, "Invalid Document");
416		RETURN_FALSE;
417	}
418
419	/* libxslt uses _private, so we must copy the imported
420	stylesheet document otherwise the node proxies will be a mess */
421	newdoc = xmlCopyDoc(doc, 1);
422	xmlNodeSetBase((xmlNodePtr) newdoc, (xmlChar *)doc->URL);
423	prevSubstValue = xmlSubstituteEntitiesDefault(1);
424	prevExtDtdValue = xmlLoadExtDtdDefaultValue;
425	xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
426
427	sheetp = xsltParseStylesheetDoc(newdoc);
428	xmlSubstituteEntitiesDefault(prevSubstValue);
429	xmlLoadExtDtdDefaultValue = prevExtDtdValue;
430
431	if (!sheetp) {
432		xmlFreeDoc(newdoc);
433		RETURN_FALSE;
434	}
435
436	intern = Z_XSL_P(id);
437
438	std_hnd = zend_get_std_object_handlers();
439	ZVAL_STRING(&member, "cloneDocument");
440	cloneDocu = std_hnd->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
476static 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	zend_object_handlers *std_hnd;
487	FILE *f;
488	int secPrefsError = 0;
489	int secPrefsValue;
490	xsltSecurityPrefsPtr secPrefs = NULL;
491
492	node = php_libxml_import_node(docp);
493
494	if (node) {
495		doc = node->doc;
496	}
497	if (doc == NULL) {
498		php_error_docref(NULL, E_WARNING, "Invalid Document");
499		return NULL;
500	}
501
502	if (style == NULL) {
503		php_error_docref(NULL, E_WARNING, "No stylesheet associated to this object");
504		return NULL;
505	}
506
507	if (intern->profiling) {
508		if (php_check_open_basedir(intern->profiling)) {
509			f = NULL;
510		} else {
511			f = VCWD_FOPEN(intern->profiling, "w");
512		}
513	} else {
514		f = NULL;
515	}
516
517	if (intern->parameter) {
518		params = php_xsl_xslt_make_params(intern->parameter, 0);
519	}
520
521	intern->doc = emalloc(sizeof(php_libxml_node_object));
522	memset(intern->doc, 0, sizeof(php_libxml_node_object));
523
524	if (intern->hasKeys == 1) {
525		doc = xmlCopyDoc(doc, 1);
526	} else {
527		object = Z_LIBXML_NODE_P(docp);
528		intern->doc->document = object->document;
529	}
530
531	php_libxml_increment_doc_ref(intern->doc, doc);
532
533	ctxt = xsltNewTransformContext(style, doc);
534	ctxt->_private = (void *) intern;
535
536	std_hnd = zend_get_std_object_handlers();
537
538	ZVAL_STRING(&member, "doXInclude");
539	doXInclude = std_hnd->read_property(id, &member, BP_VAR_IS, NULL, &rv);
540	if (Z_TYPE_P(doXInclude) != IS_NULL) {
541		convert_to_long(doXInclude);
542		ctxt->xinclude = Z_LVAL_P(doXInclude);
543	}
544	zval_ptr_dtor(&member);
545
546	secPrefsValue = intern->securityPrefs;
547
548	/* if securityPrefs is set to NONE, we don't have to do any checks, but otherwise... */
549	if (secPrefsValue != XSL_SECPREF_NONE) {
550		secPrefs = xsltNewSecurityPrefs();
551		if (secPrefsValue & XSL_SECPREF_READ_FILE ) {
552			if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_READ_FILE, xsltSecurityForbid)) {
553				secPrefsError = 1;
554			}
555		}
556		if (secPrefsValue & XSL_SECPREF_WRITE_FILE ) {
557			if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_WRITE_FILE, xsltSecurityForbid)) {
558				secPrefsError = 1;
559			}
560		}
561		if (secPrefsValue & XSL_SECPREF_CREATE_DIRECTORY ) {
562			if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_CREATE_DIRECTORY, xsltSecurityForbid)) {
563				secPrefsError = 1;
564			}
565		}
566		if (secPrefsValue & XSL_SECPREF_READ_NETWORK) {
567			if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_READ_NETWORK, xsltSecurityForbid)) {
568				secPrefsError = 1;
569			}
570		}
571		if (secPrefsValue & XSL_SECPREF_WRITE_NETWORK) {
572			if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_WRITE_NETWORK, xsltSecurityForbid)) {
573				secPrefsError = 1;
574			}
575		}
576
577		if (0 != xsltSetCtxtSecurityPrefs(secPrefs, ctxt)) {
578			secPrefsError = 1;
579		}
580	}
581
582	if (secPrefsError == 1) {
583		php_error_docref(NULL, E_WARNING, "Can't set libxslt security properties, not doing transformation for security reasons");
584	} else {
585		newdocp = xsltApplyStylesheetUser(style, doc, (const char**) params,  NULL, f, ctxt);
586	}
587	if (f) {
588		fclose(f);
589	}
590
591	xsltFreeTransformContext(ctxt);
592	if (secPrefs) {
593		xsltFreeSecurityPrefs(secPrefs);
594	}
595
596	if (intern->node_list != NULL) {
597		zend_hash_destroy(intern->node_list);
598		FREE_HASHTABLE(intern->node_list);
599		intern->node_list = NULL;
600	}
601
602	php_libxml_decrement_doc_ref(intern->doc);
603	efree(intern->doc);
604	intern->doc = NULL;
605
606	if (params) {
607		clone = 0;
608		while(params[clone]) {
609			efree(params[clone++]);
610		}
611		efree(params);
612	}
613
614	return newdocp;
615
616}
617/* }}} */
618
619/* {{{ proto domdocument xsl_xsltprocessor_transform_to_doc(domnode doc)
620URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#
621Since:
622*/
623PHP_FUNCTION(xsl_xsltprocessor_transform_to_doc)
624{
625	zval *id, *docp = NULL;
626	xmlDoc *newdocp;
627	xsltStylesheetPtr sheetp;
628	zend_string *ret_class = NULL;
629	xsl_object *intern;
630
631	id = getThis();
632	intern = Z_XSL_P(id);
633	sheetp = (xsltStylesheetPtr) intern->ptr;
634
635	if (zend_parse_parameters(ZEND_NUM_ARGS(), "o|S!", &docp, &ret_class) == FAILURE) {
636		RETURN_FALSE;
637	}
638
639	newdocp = php_xsl_apply_stylesheet(id, intern, sheetp, docp);
640
641	if (newdocp) {
642		if (ret_class) {
643			zend_string *curclass_name;
644			zend_class_entry *curce, *ce;
645			php_libxml_node_object *interndoc;
646
647			curce = Z_OBJCE_P(docp);
648			curclass_name = curce->name;
649			while (curce->parent != NULL) {
650				curce = curce->parent;
651			}
652
653			ce = zend_lookup_class(ret_class);
654			if (ce == NULL || !instanceof_function(ce, curce)) {
655				xmlFreeDoc(newdocp);
656				php_error_docref(NULL, E_WARNING,
657					"Expecting class compatible with %s, '%s' given", ZSTR_VAL(curclass_name), ZSTR_VAL(ret_class));
658				RETURN_FALSE;
659			}
660
661			object_init_ex(return_value, ce);
662
663			interndoc = Z_LIBXML_NODE_P(return_value);
664			php_libxml_increment_doc_ref(interndoc, newdocp);
665			php_libxml_increment_node_ptr(interndoc, (xmlNodePtr)newdocp, (void *)interndoc);
666		} else {
667			php_dom_create_object((xmlNodePtr) newdocp, return_value, NULL);
668		}
669	} else {
670		RETURN_FALSE;
671	}
672
673}
674/* }}} end xsl_xsltprocessor_transform_to_doc */
675
676/* {{{ proto int xsl_xsltprocessor_transform_to_uri(domdocument doc, string uri)
677*/
678PHP_FUNCTION(xsl_xsltprocessor_transform_to_uri)
679{
680	zval *id, *docp = NULL;
681	xmlDoc *newdocp;
682	xsltStylesheetPtr sheetp;
683	int ret;
684	size_t uri_len;
685	char *uri;
686	xsl_object *intern;
687
688	id = getThis();
689	intern = Z_XSL_P(id);
690	sheetp = (xsltStylesheetPtr) intern->ptr;
691
692	if (zend_parse_parameters(ZEND_NUM_ARGS(), "op", &docp, &uri, &uri_len) == FAILURE) {
693		RETURN_FALSE;
694	}
695
696	newdocp = php_xsl_apply_stylesheet(id, intern, sheetp, docp);
697
698	ret = -1;
699	if (newdocp) {
700		ret = xsltSaveResultToFilename(uri, newdocp, sheetp, 0);
701		xmlFreeDoc(newdocp);
702	}
703
704	RETVAL_LONG(ret);
705}
706/* }}} end xsl_xsltprocessor_transform_to_uri */
707
708/* {{{ proto string xsl_xsltprocessor_transform_to_xml(domdocument doc)
709*/
710PHP_FUNCTION(xsl_xsltprocessor_transform_to_xml)
711{
712	zval *id, *docp = NULL;
713	xmlDoc *newdocp;
714	xsltStylesheetPtr sheetp;
715	int ret;
716	xmlChar *doc_txt_ptr;
717	int doc_txt_len;
718	xsl_object *intern;
719
720	id = getThis();
721	intern = Z_XSL_P(id);
722	sheetp = (xsltStylesheetPtr) intern->ptr;
723
724	if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &docp) == FAILURE) {
725		RETURN_FALSE;
726	}
727
728	newdocp = php_xsl_apply_stylesheet(id, intern, sheetp, docp);
729
730	ret = -1;
731	if (newdocp) {
732		ret = xsltSaveResultToString(&doc_txt_ptr, &doc_txt_len, newdocp, sheetp);
733		if (doc_txt_ptr && doc_txt_len) {
734			RETVAL_STRINGL((char *) doc_txt_ptr, doc_txt_len);
735			xmlFree(doc_txt_ptr);
736		}
737		xmlFreeDoc(newdocp);
738	}
739
740	if (ret < 0) {
741		RETURN_FALSE;
742	}
743}
744/* }}} end xsl_xsltprocessor_transform_to_xml */
745
746/* {{{ proto bool xsl_xsltprocessor_set_parameter(string namespace, mixed name [, string value])
747*/
748PHP_FUNCTION(xsl_xsltprocessor_set_parameter)
749{
750
751	zval *id;
752	zval *array_value, *entry, new_string;
753	xsl_object *intern;
754	char *namespace;
755	size_t namespace_len;
756	zend_string *string_key, *name, *value;
757	DOM_GET_THIS(id);
758
759	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "sa", &namespace, &namespace_len, &array_value) == SUCCESS) {
760		intern = Z_XSL_P(id);
761		ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(array_value), string_key, entry) {
762			if (string_key == NULL) {
763				php_error_docref(NULL, E_WARNING, "Invalid parameter array");
764				RETURN_FALSE;
765			}
766			convert_to_string_ex(entry);
767			if (Z_REFCOUNTED_P(entry)) {
768				Z_ADDREF_P(entry);
769			}
770			zend_hash_update(intern->parameter, string_key, entry);
771		} ZEND_HASH_FOREACH_END();
772		RETURN_TRUE;
773	} else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "sSS", &namespace, &namespace_len, &name, &value) == SUCCESS) {
774
775		intern = Z_XSL_P(id);
776
777		ZVAL_STR_COPY(&new_string, value);
778
779		zend_hash_update(intern->parameter, name, &new_string);
780		RETURN_TRUE;
781	} else {
782		WRONG_PARAM_COUNT;
783	}
784
785}
786/* }}} end xsl_xsltprocessor_set_parameter */
787
788/* {{{ proto string xsl_xsltprocessor_get_parameter(string namespace, string name)
789*/
790PHP_FUNCTION(xsl_xsltprocessor_get_parameter)
791{
792	zval *id;
793	char *namespace;
794	size_t namespace_len = 0;
795	zval *value;
796	zend_string *name;
797	xsl_object *intern;
798
799	DOM_GET_THIS(id);
800
801	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sS", &namespace, &namespace_len, &name) == FAILURE) {
802		RETURN_FALSE;
803	}
804	intern = Z_XSL_P(id);
805	if ((value = zend_hash_find(intern->parameter, name)) != NULL) {
806		convert_to_string_ex(value);
807		RETURN_STR_COPY(Z_STR_P(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*/
816PHP_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*/
840PHP_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			convert_to_string_ex(entry);
854			ZVAL_LONG(&new_string ,1);
855			zend_hash_update(intern->registered_phpfunctions, Z_STR_P(entry), &new_string);
856		} ZEND_HASH_FOREACH_END();
857
858		intern->registerPhpFunctions = 2;
859	} else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "S",  &name) == SUCCESS) {
860		intern = Z_XSL_P(id);
861
862		ZVAL_LONG(&new_string,1);
863		zend_hash_update(intern->registered_phpfunctions, name, &new_string);
864		intern->registerPhpFunctions = 2;
865
866	} else {
867		intern = Z_XSL_P(id);
868		intern->registerPhpFunctions = 1;
869	}
870
871}
872/* }}} end xsl_xsltprocessor_register_php_functions(); */
873
874/* {{{ proto bool xsl_xsltprocessor_set_profiling(string filename) */
875PHP_FUNCTION(xsl_xsltprocessor_set_profiling)
876{
877	zval *id;
878	xsl_object *intern;
879	char *filename = NULL;
880	size_t filename_len;
881	DOM_GET_THIS(id);
882
883	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "p!", &filename, &filename_len) == SUCCESS) {
884		intern = Z_XSL_P(id);
885		if (intern->profiling) {
886			efree(intern->profiling);
887		}
888		if (filename != NULL) {
889			intern->profiling = estrndup(filename, filename_len);
890		} else {
891			intern->profiling = NULL;
892		}
893		RETURN_TRUE;
894	} else {
895		WRONG_PARAM_COUNT;
896	}
897}
898/* }}} end xsl_xsltprocessor_set_profiling */
899
900/* {{{ proto long xsl_xsltprocessor_set_security_prefs(long securityPrefs) */
901PHP_FUNCTION(xsl_xsltprocessor_set_security_prefs)
902{
903	zval *id;
904	xsl_object *intern;
905	zend_long securityPrefs, oldSecurityPrefs;
906
907	DOM_GET_THIS(id);
908 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &securityPrefs) == FAILURE) {
909		return;
910	}
911	intern = Z_XSL_P(id);
912	oldSecurityPrefs = intern->securityPrefs;
913	intern->securityPrefs = securityPrefs;
914	/* set this to 1 so that we know, it was set through this method. Can be removed, when we remove the ini setting */
915	intern->securityPrefsSet = 1;
916	RETURN_LONG(oldSecurityPrefs);
917}
918/* }}} end xsl_xsltprocessor_set_security_prefs */
919
920/* {{{ proto long xsl_xsltprocessor_get_security_prefs() */
921PHP_FUNCTION(xsl_xsltprocessor_get_security_prefs)
922{
923	zval *id;
924	xsl_object *intern;
925
926	DOM_GET_THIS(id);
927	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "") == SUCCESS) {
928		intern = Z_XSL_P(id);
929		RETURN_LONG(intern->securityPrefs);
930	} else {
931		WRONG_PARAM_COUNT;
932	}
933}
934/* }}} end xsl_xsltprocessor_get_security_prefs */
935
936/* {{{ proto bool xsl_xsltprocessor_has_exslt_support()
937*/
938PHP_FUNCTION(xsl_xsltprocessor_has_exslt_support)
939{
940#if HAVE_XSL_EXSLT
941	RETURN_TRUE;
942#else
943	RETURN_FALSE;
944#endif
945}
946/* }}} end xsl_xsltprocessor_has_exslt_support(); */
947
948/*
949 * Local variables:
950 * tab-width: 4
951 * c-basic-offset: 4
952 * End:
953 * vim600: sw=4 ts=4 fdm=marker
954 * vim<600: sw=4 ts=4
955 */
956