xref: /PHP-7.0/ext/xsl/xsltprocessor.c (revision 478f119a)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2017 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 */
31 ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_import_stylesheet, 0, 0, 1)
32 	ZEND_ARG_INFO(0, doc)
33 ZEND_END_ARG_INFO();
34 
35 ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_transform_to_doc, 0, 0, 1)
36 	ZEND_ARG_INFO(0, doc)
37 ZEND_END_ARG_INFO();
38 
39 ZEND_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)
42 ZEND_END_ARG_INFO();
43 
44 ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_transform_to_xml, 0, 0, 1)
45 	ZEND_ARG_INFO(0, doc)
46 ZEND_END_ARG_INFO();
47 
48 ZEND_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)
52 ZEND_END_ARG_INFO();
53 
54 ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_get_parameter, 0, 0, 2)
55 	ZEND_ARG_INFO(0, namespace)
56 	ZEND_ARG_INFO(0, name)
57 ZEND_END_ARG_INFO();
58 
59 ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_remove_parameter, 0, 0, 2)
60 	ZEND_ARG_INFO(0, namespace)
61 	ZEND_ARG_INFO(0, name)
62 ZEND_END_ARG_INFO();
63 
64 ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_has_exslt_support, 0, 0, 0)
65 ZEND_END_ARG_INFO();
66 
67 ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_register_php_functions, 0, 0, 0)
68 	ZEND_ARG_INFO(0, restrict)
69 ZEND_END_ARG_INFO();
70 
71 ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_set_profiling, 0, 0, 1)
72 	ZEND_ARG_INFO(0, filename)
73 ZEND_END_ARG_INFO();
74 
75 ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_set_security_prefs, 0, 0, 1)
76 	ZEND_ARG_INFO(0, securityPrefs)
77 ZEND_END_ARG_INFO();
78 
79 ZEND_BEGIN_ARG_INFO_EX(arginfo_xsl_xsltprocessor_get_security_prefs, 0, 0, 0)
80 ZEND_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 
90 const 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 */
php_xsl_xslt_string_to_xpathexpr(const char * str)108 static 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 */
php_xsl_xslt_make_params(HashTable * parht,int xpath_params)134 static 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 
xsl_ext_function_php(xmlXPathParserContextPtr ctxt,int nargs,int type)177 static void xsl_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int type) /* {{{ */
178 {
179 	xsltTransformContextPtr tctxt;
180 	zval *args;
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 	fci.function_table = EG(function_table);
299 	if (fci.param_count > 0) {
300 		fci.params = args;
301 	} else {
302 		fci.params = NULL;
303 	}
304 
305 
306 	obj = valuePop(ctxt);
307 	if (obj == NULL || obj->stringval == NULL) {
308 		php_error_docref(NULL, E_WARNING, "Handler name must be a string");
309 		xmlXPathFreeObject(obj);
310 		valuePush(ctxt, xmlXPathNewString((const xmlChar *) ""));
311 		if (fci.param_count > 0) {
312 			for (i = 0; i < nargs - 1; i++) {
313 				zval_ptr_dtor(&args[i]);
314 			}
315 			efree(args);
316 		}
317 		return;
318 	}
319 	ZVAL_STRING(&handler, (char *) obj->stringval);
320 	xmlXPathFreeObject(obj);
321 
322 	ZVAL_COPY_VALUE(&fci.function_name, &handler);
323 	fci.symbol_table = NULL;
324 	fci.object = NULL;
325 	fci.retval = &retval;
326 	fci.no_separation = 0;
327 	/*fci.function_handler_cache = &function_ptr;*/
328 	if (!zend_make_callable(&handler, &callable)) {
329 		php_error_docref(NULL, E_WARNING, "Unable to call handler %s()", ZSTR_VAL(callable));
330 		valuePush(ctxt, xmlXPathNewString((const xmlChar *) ""));
331 	} else if ( intern->registerPhpFunctions == 2 && zend_hash_exists(intern->registered_phpfunctions, callable) == 0) {
332 		php_error_docref(NULL, E_WARNING, "Not allowed to call handler '%s()'", ZSTR_VAL(callable));
333 		/* Push an empty string, so that we at least have an xslt result... */
334 		valuePush(ctxt, xmlXPathNewString((const xmlChar *) ""));
335 	} else {
336 		result = zend_call_function(&fci, NULL);
337 		if (result == FAILURE) {
338 			if (Z_TYPE(handler) == IS_STRING) {
339 				php_error_docref(NULL, E_WARNING, "Unable to call handler %s()", Z_STRVAL(handler));
340 				valuePush(ctxt, xmlXPathNewString((const xmlChar *) ""));
341 			}
342 		/* retval is == NULL, when an exception occurred, don't report anything, because PHP itself will handle that */
343 		} else if (Z_ISUNDEF(retval)) {
344 		} else {
345 			if (Z_TYPE(retval) == IS_OBJECT && instanceof_function(Z_OBJCE(retval), dom_node_class_entry)) {
346 				xmlNode *nodep;
347 				dom_object *obj;
348 				if (intern->node_list == NULL) {
349 					ALLOC_HASHTABLE(intern->node_list);
350 					zend_hash_init(intern->node_list, 0, NULL, ZVAL_PTR_DTOR, 0);
351 				}
352 				Z_ADDREF(retval);
353 				zend_hash_next_index_insert(intern->node_list, &retval);
354 				obj = Z_DOMOBJ_P(&retval);
355 				nodep = dom_object_get_node(obj);
356 				valuePush(ctxt, xmlXPathNewNodeSet(nodep));
357 			} else if (Z_TYPE(retval) == IS_TRUE || Z_TYPE(retval) == IS_FALSE) {
358 				valuePush(ctxt, xmlXPathNewBoolean(Z_TYPE(retval) == IS_TRUE));
359 			} else if (Z_TYPE(retval) == IS_OBJECT) {
360 				php_error_docref(NULL, E_WARNING, "A PHP Object cannot be converted to a XPath-string");
361 				valuePush(ctxt, xmlXPathNewString((const xmlChar *) ""));
362 			} else {
363 				convert_to_string_ex(&retval);
364 				valuePush(ctxt, xmlXPathNewString((xmlChar *) Z_STRVAL(retval)));
365 			}
366 			zval_ptr_dtor(&retval);
367 		}
368 	}
369 	zend_string_release(callable);
370 	zval_ptr_dtor(&handler);
371 	if (fci.param_count > 0) {
372 		for (i = 0; i < nargs - 1; i++) {
373 			zval_ptr_dtor(&args[i]);
374 		}
375 		efree(args);
376 	}
377 }
378 /* }}} */
379 
xsl_ext_function_string_php(xmlXPathParserContextPtr ctxt,int nargs)380 void xsl_ext_function_string_php(xmlXPathParserContextPtr ctxt, int nargs) /* {{{ */
381 {
382 	xsl_ext_function_php(ctxt, nargs, 1);
383 }
384 /* }}} */
385 
xsl_ext_function_object_php(xmlXPathParserContextPtr ctxt,int nargs)386 void xsl_ext_function_object_php(xmlXPathParserContextPtr ctxt, int nargs) /* {{{ */
387 {
388 	xsl_ext_function_php(ctxt, nargs, 2);
389 }
390 /* }}} */
391 
392 /* {{{ proto void xsl_xsltprocessor_import_stylesheet(domdocument doc)
393 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#
394 Since:
395 */
PHP_FUNCTION(xsl_xsltprocessor_import_stylesheet)396 PHP_FUNCTION(xsl_xsltprocessor_import_stylesheet)
397 {
398 	zval *id, *docp = NULL;
399 	xmlDoc *doc = NULL, *newdoc = NULL;
400 	xsltStylesheetPtr sheetp, oldsheetp;
401 	xsl_object *intern;
402 	int prevSubstValue, prevExtDtdValue, clone_docu = 0;
403 	xmlNode *nodep = NULL;
404 	zend_object_handlers *std_hnd;
405 	zval *cloneDocu, member, rv;
406 
407 	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oo", &id, xsl_xsltprocessor_class_entry, &docp) == FAILURE) {
408 		RETURN_FALSE;
409 	}
410 
411 	nodep = php_libxml_import_node(docp);
412 
413 	if (nodep) {
414 		doc = nodep->doc;
415 	}
416 	if (doc == NULL) {
417 		php_error(E_WARNING, "Invalid Document");
418 		RETURN_FALSE;
419 	}
420 
421 	/* libxslt uses _private, so we must copy the imported
422 	stylesheet document otherwise the node proxies will be a mess */
423 	newdoc = xmlCopyDoc(doc, 1);
424 	xmlNodeSetBase((xmlNodePtr) newdoc, (xmlChar *)doc->URL);
425 	prevSubstValue = xmlSubstituteEntitiesDefault(1);
426 	prevExtDtdValue = xmlLoadExtDtdDefaultValue;
427 	xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
428 
429 	sheetp = xsltParseStylesheetDoc(newdoc);
430 	xmlSubstituteEntitiesDefault(prevSubstValue);
431 	xmlLoadExtDtdDefaultValue = prevExtDtdValue;
432 
433 	if (!sheetp) {
434 		xmlFreeDoc(newdoc);
435 		RETURN_FALSE;
436 	}
437 
438 	intern = Z_XSL_P(id);
439 
440 	std_hnd = zend_get_std_object_handlers();
441 	ZVAL_STRING(&member, "cloneDocument");
442 	cloneDocu = std_hnd->read_property(id, &member, BP_VAR_IS, NULL, &rv);
443 	if (Z_TYPE_P(cloneDocu) != IS_NULL) {
444 		convert_to_long(cloneDocu);
445 		clone_docu = Z_LVAL_P(cloneDocu);
446 	}
447 	zval_ptr_dtor(&member);
448 	if (clone_docu == 0) {
449 		/* check if the stylesheet is using xsl:key, if yes, we have to clone the document _always_ before a transformation */
450 		nodep = xmlDocGetRootElement(sheetp->doc);
451 		if (nodep && (nodep = nodep->children)) {
452 			while (nodep) {
453 				if (nodep->type == XML_ELEMENT_NODE && xmlStrEqual(nodep->name, (const xmlChar *) "key") && xmlStrEqual(nodep->ns->href, XSLT_NAMESPACE)) {
454 					intern->hasKeys = 1;
455 					break;
456 				}
457 				nodep = nodep->next;
458 			}
459 		}
460 	} else {
461 		intern->hasKeys = clone_docu;
462 	}
463 
464 	if ((oldsheetp = (xsltStylesheetPtr)intern->ptr)) {
465 		/* free wrapper */
466 		if (((xsltStylesheetPtr) intern->ptr)->_private != NULL) {
467 			((xsltStylesheetPtr) intern->ptr)->_private = NULL;
468 		}
469 		xsltFreeStylesheet((xsltStylesheetPtr) intern->ptr);
470 		intern->ptr = NULL;
471 	}
472 
473 	php_xsl_set_object(id, sheetp);
474 	RETVAL_TRUE;
475 }
476 /* }}} end xsl_xsltprocessor_import_stylesheet */
477 
php_xsl_apply_stylesheet(zval * id,xsl_object * intern,xsltStylesheetPtr style,zval * docp)478 static xmlDocPtr php_xsl_apply_stylesheet(zval *id, xsl_object *intern, xsltStylesheetPtr style, zval *docp) /* {{{ */
479 {
480 	xmlDocPtr newdocp = NULL;
481 	xmlDocPtr doc = NULL;
482 	xmlNodePtr node = NULL;
483 	xsltTransformContextPtr ctxt;
484 	php_libxml_node_object *object;
485 	char **params = NULL;
486 	int clone;
487 	zval *doXInclude, member, rv;
488 	zend_object_handlers *std_hnd;
489 	FILE *f;
490 	int secPrefsError = 0;
491 	int secPrefsValue;
492 	xsltSecurityPrefsPtr secPrefs = NULL;
493 
494 	node = php_libxml_import_node(docp);
495 
496 	if (node) {
497 		doc = node->doc;
498 	}
499 	if (doc == NULL) {
500 		php_error_docref(NULL, E_WARNING, "Invalid Document");
501 		return NULL;
502 	}
503 
504 	if (style == NULL) {
505 		php_error_docref(NULL, E_WARNING, "No stylesheet associated to this object");
506 		return NULL;
507 	}
508 
509 	if (intern->profiling) {
510 		if (php_check_open_basedir(intern->profiling)) {
511 			f = NULL;
512 		} else {
513 			f = VCWD_FOPEN(intern->profiling, "w");
514 		}
515 	} else {
516 		f = NULL;
517 	}
518 
519 	if (intern->parameter) {
520 		params = php_xsl_xslt_make_params(intern->parameter, 0);
521 	}
522 
523 	intern->doc = emalloc(sizeof(php_libxml_node_object));
524 	memset(intern->doc, 0, sizeof(php_libxml_node_object));
525 
526 	if (intern->hasKeys == 1) {
527 		doc = xmlCopyDoc(doc, 1);
528 	} else {
529 		object = Z_LIBXML_NODE_P(docp);
530 		intern->doc->document = object->document;
531 	}
532 
533 	php_libxml_increment_doc_ref(intern->doc, doc);
534 
535 	ctxt = xsltNewTransformContext(style, doc);
536 	ctxt->_private = (void *) intern;
537 
538 	std_hnd = zend_get_std_object_handlers();
539 
540 	ZVAL_STRING(&member, "doXInclude");
541 	doXInclude = std_hnd->read_property(id, &member, BP_VAR_IS, NULL, &rv);
542 	if (Z_TYPE_P(doXInclude) != IS_NULL) {
543 		convert_to_long(doXInclude);
544 		ctxt->xinclude = Z_LVAL_P(doXInclude);
545 	}
546 	zval_ptr_dtor(&member);
547 
548 	secPrefsValue = intern->securityPrefs;
549 
550 	/* if securityPrefs is set to NONE, we don't have to do any checks, but otherwise... */
551 	if (secPrefsValue != XSL_SECPREF_NONE) {
552 		secPrefs = xsltNewSecurityPrefs();
553 		if (secPrefsValue & XSL_SECPREF_READ_FILE ) {
554 			if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_READ_FILE, xsltSecurityForbid)) {
555 				secPrefsError = 1;
556 			}
557 		}
558 		if (secPrefsValue & XSL_SECPREF_WRITE_FILE ) {
559 			if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_WRITE_FILE, xsltSecurityForbid)) {
560 				secPrefsError = 1;
561 			}
562 		}
563 		if (secPrefsValue & XSL_SECPREF_CREATE_DIRECTORY ) {
564 			if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_CREATE_DIRECTORY, xsltSecurityForbid)) {
565 				secPrefsError = 1;
566 			}
567 		}
568 		if (secPrefsValue & XSL_SECPREF_READ_NETWORK) {
569 			if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_READ_NETWORK, xsltSecurityForbid)) {
570 				secPrefsError = 1;
571 			}
572 		}
573 		if (secPrefsValue & XSL_SECPREF_WRITE_NETWORK) {
574 			if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_WRITE_NETWORK, xsltSecurityForbid)) {
575 				secPrefsError = 1;
576 			}
577 		}
578 
579 		if (0 != xsltSetCtxtSecurityPrefs(secPrefs, ctxt)) {
580 			secPrefsError = 1;
581 		}
582 	}
583 
584 	if (secPrefsError == 1) {
585 		php_error_docref(NULL, E_WARNING, "Can't set libxslt security properties, not doing transformation for security reasons");
586 	} else {
587 		newdocp = xsltApplyStylesheetUser(style, doc, (const char**) params,  NULL, f, ctxt);
588 	}
589 	if (f) {
590 		fclose(f);
591 	}
592 
593 	xsltFreeTransformContext(ctxt);
594 	if (secPrefs) {
595 		xsltFreeSecurityPrefs(secPrefs);
596 	}
597 
598 	if (intern->node_list != NULL) {
599 		zend_hash_destroy(intern->node_list);
600 		FREE_HASHTABLE(intern->node_list);
601 		intern->node_list = NULL;
602 	}
603 
604 	php_libxml_decrement_doc_ref(intern->doc);
605 	efree(intern->doc);
606 	intern->doc = NULL;
607 
608 	if (params) {
609 		clone = 0;
610 		while(params[clone]) {
611 			efree(params[clone++]);
612 		}
613 		efree(params);
614 	}
615 
616 	return newdocp;
617 
618 }
619 /* }}} */
620 
621 /* {{{ proto domdocument xsl_xsltprocessor_transform_to_doc(domnode doc)
622 URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#
623 Since:
624 */
PHP_FUNCTION(xsl_xsltprocessor_transform_to_doc)625 PHP_FUNCTION(xsl_xsltprocessor_transform_to_doc)
626 {
627 	zval *id, *docp = NULL;
628 	xmlDoc *newdocp;
629 	xsltStylesheetPtr sheetp;
630 	zend_string *ret_class = NULL;
631 	xsl_object *intern;
632 
633 	id = getThis();
634 	intern = Z_XSL_P(id);
635 	sheetp = (xsltStylesheetPtr) intern->ptr;
636 
637 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "o|S!", &docp, &ret_class) == FAILURE) {
638 		RETURN_FALSE;
639 	}
640 
641 	newdocp = php_xsl_apply_stylesheet(id, intern, sheetp, docp);
642 
643 	if (newdocp) {
644 		if (ret_class) {
645 			zend_string *curclass_name;
646 			zend_class_entry *curce, *ce;
647 			php_libxml_node_object *interndoc;
648 
649 			curce = Z_OBJCE_P(docp);
650 			curclass_name = curce->name;
651 			while (curce->parent != NULL) {
652 				curce = curce->parent;
653 			}
654 
655 			ce = zend_lookup_class(ret_class);
656 			if (ce == NULL || !instanceof_function(ce, curce)) {
657 				xmlFreeDoc(newdocp);
658 				php_error_docref(NULL, E_WARNING,
659 					"Expecting class compatible with %s, '%s' given", ZSTR_VAL(curclass_name), ZSTR_VAL(ret_class));
660 				RETURN_FALSE;
661 			}
662 
663 			object_init_ex(return_value, ce);
664 
665 			interndoc = Z_LIBXML_NODE_P(return_value);
666 			php_libxml_increment_doc_ref(interndoc, newdocp);
667 			php_libxml_increment_node_ptr(interndoc, (xmlNodePtr)newdocp, (void *)interndoc);
668 		} else {
669 			php_dom_create_object((xmlNodePtr) newdocp, return_value, NULL);
670 		}
671 	} else {
672 		RETURN_FALSE;
673 	}
674 
675 }
676 /* }}} end xsl_xsltprocessor_transform_to_doc */
677 
678 /* {{{ proto int xsl_xsltprocessor_transform_to_uri(domdocument doc, string uri)
679 */
PHP_FUNCTION(xsl_xsltprocessor_transform_to_uri)680 PHP_FUNCTION(xsl_xsltprocessor_transform_to_uri)
681 {
682 	zval *id, *docp = NULL;
683 	xmlDoc *newdocp;
684 	xsltStylesheetPtr sheetp;
685 	int ret;
686 	size_t uri_len;
687 	char *uri;
688 	xsl_object *intern;
689 
690 	id = getThis();
691 	intern = Z_XSL_P(id);
692 	sheetp = (xsltStylesheetPtr) intern->ptr;
693 
694 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "op", &docp, &uri, &uri_len) == FAILURE) {
695 		RETURN_FALSE;
696 	}
697 
698 	newdocp = php_xsl_apply_stylesheet(id, intern, sheetp, docp);
699 
700 	ret = -1;
701 	if (newdocp) {
702 		ret = xsltSaveResultToFilename(uri, newdocp, sheetp, 0);
703 		xmlFreeDoc(newdocp);
704 	}
705 
706 	RETVAL_LONG(ret);
707 }
708 /* }}} end xsl_xsltprocessor_transform_to_uri */
709 
710 /* {{{ proto string xsl_xsltprocessor_transform_to_xml(domdocument doc)
711 */
PHP_FUNCTION(xsl_xsltprocessor_transform_to_xml)712 PHP_FUNCTION(xsl_xsltprocessor_transform_to_xml)
713 {
714 	zval *id, *docp = NULL;
715 	xmlDoc *newdocp;
716 	xsltStylesheetPtr sheetp;
717 	int ret;
718 	xmlChar *doc_txt_ptr;
719 	int doc_txt_len;
720 	xsl_object *intern;
721 
722 	id = getThis();
723 	intern = Z_XSL_P(id);
724 	sheetp = (xsltStylesheetPtr) intern->ptr;
725 
726 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &docp) == FAILURE) {
727 		RETURN_FALSE;
728 	}
729 
730 	newdocp = php_xsl_apply_stylesheet(id, intern, sheetp, docp);
731 
732 	ret = -1;
733 	if (newdocp) {
734 		ret = xsltSaveResultToString(&doc_txt_ptr, &doc_txt_len, newdocp, sheetp);
735 		if (doc_txt_ptr && doc_txt_len) {
736 			RETVAL_STRINGL((char *) doc_txt_ptr, doc_txt_len);
737 			xmlFree(doc_txt_ptr);
738 		}
739 		xmlFreeDoc(newdocp);
740 	}
741 
742 	if (ret < 0) {
743 		RETURN_FALSE;
744 	}
745 }
746 /* }}} end xsl_xsltprocessor_transform_to_xml */
747 
748 /* {{{ proto bool xsl_xsltprocessor_set_parameter(string namespace, mixed name [, string value])
749 */
PHP_FUNCTION(xsl_xsltprocessor_set_parameter)750 PHP_FUNCTION(xsl_xsltprocessor_set_parameter)
751 {
752 
753 	zval *id;
754 	zval *array_value, *entry, new_string;
755 	xsl_object *intern;
756 	char *namespace;
757 	size_t namespace_len;
758 	zend_string *string_key, *name, *value;
759 	DOM_GET_THIS(id);
760 
761 	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "sa", &namespace, &namespace_len, &array_value) == SUCCESS) {
762 		intern = Z_XSL_P(id);
763 		ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(array_value), string_key, entry) {
764 			if (string_key == NULL) {
765 				php_error_docref(NULL, E_WARNING, "Invalid parameter array");
766 				RETURN_FALSE;
767 			}
768 			convert_to_string_ex(entry);
769 			if (Z_REFCOUNTED_P(entry)) {
770 				Z_ADDREF_P(entry);
771 			}
772 			zend_hash_update(intern->parameter, string_key, entry);
773 		} ZEND_HASH_FOREACH_END();
774 		RETURN_TRUE;
775 	} else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "sSS", &namespace, &namespace_len, &name, &value) == SUCCESS) {
776 
777 		intern = Z_XSL_P(id);
778 
779 		ZVAL_STR_COPY(&new_string, value);
780 
781 		zend_hash_update(intern->parameter, name, &new_string);
782 		RETURN_TRUE;
783 	} else {
784 		WRONG_PARAM_COUNT;
785 	}
786 
787 }
788 /* }}} end xsl_xsltprocessor_set_parameter */
789 
790 /* {{{ proto string xsl_xsltprocessor_get_parameter(string namespace, string name)
791 */
PHP_FUNCTION(xsl_xsltprocessor_get_parameter)792 PHP_FUNCTION(xsl_xsltprocessor_get_parameter)
793 {
794 	zval *id;
795 	char *namespace;
796 	size_t namespace_len = 0;
797 	zval *value;
798 	zend_string *name;
799 	xsl_object *intern;
800 
801 	DOM_GET_THIS(id);
802 
803 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sS", &namespace, &namespace_len, &name) == FAILURE) {
804 		RETURN_FALSE;
805 	}
806 	intern = Z_XSL_P(id);
807 	if ((value = zend_hash_find(intern->parameter, name)) != NULL) {
808 		convert_to_string_ex(value);
809 		RETURN_STR_COPY(Z_STR_P(value));
810 	} else {
811 		RETURN_FALSE;
812 	}
813 }
814 /* }}} end xsl_xsltprocessor_get_parameter */
815 
816 /* {{{ proto bool xsl_xsltprocessor_remove_parameter(string namespace, string name)
817 */
PHP_FUNCTION(xsl_xsltprocessor_remove_parameter)818 PHP_FUNCTION(xsl_xsltprocessor_remove_parameter)
819 {
820 	zval *id;
821 	size_t namespace_len = 0;
822 	char *namespace;
823 	zend_string *name;
824 	xsl_object *intern;
825 
826 	DOM_GET_THIS(id);
827 
828 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sS", &namespace, &namespace_len, &name) == FAILURE) {
829 		RETURN_FALSE;
830 	}
831 	intern = Z_XSL_P(id);
832 	if (zend_hash_del(intern->parameter, name) == SUCCESS) {
833 		RETURN_TRUE;
834 	} else {
835 		RETURN_FALSE;
836 	}
837 }
838 /* }}} end xsl_xsltprocessor_remove_parameter */
839 
840 /* {{{ proto void xsl_xsltprocessor_register_php_functions([mixed $restrict])
841 */
PHP_FUNCTION(xsl_xsltprocessor_register_php_functions)842 PHP_FUNCTION(xsl_xsltprocessor_register_php_functions)
843 {
844 	zval *id;
845 	xsl_object *intern;
846 	zval *array_value, *entry, new_string;
847 	zend_string *name;
848 
849 	DOM_GET_THIS(id);
850 
851 	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "a",  &array_value) == SUCCESS) {
852 		intern = Z_XSL_P(id);
853 
854 		ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(array_value), entry) {
855 			convert_to_string_ex(entry);
856 			ZVAL_LONG(&new_string ,1);
857 			zend_hash_update(intern->registered_phpfunctions, Z_STR_P(entry), &new_string);
858 		} ZEND_HASH_FOREACH_END();
859 
860 		intern->registerPhpFunctions = 2;
861 	} else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "S",  &name) == SUCCESS) {
862 		intern = Z_XSL_P(id);
863 
864 		ZVAL_LONG(&new_string,1);
865 		zend_hash_update(intern->registered_phpfunctions, name, &new_string);
866 		intern->registerPhpFunctions = 2;
867 
868 	} else {
869 		intern = Z_XSL_P(id);
870 		intern->registerPhpFunctions = 1;
871 	}
872 
873 }
874 /* }}} end xsl_xsltprocessor_register_php_functions(); */
875 
876 /* {{{ proto bool xsl_xsltprocessor_set_profiling(string filename) */
PHP_FUNCTION(xsl_xsltprocessor_set_profiling)877 PHP_FUNCTION(xsl_xsltprocessor_set_profiling)
878 {
879 	zval *id;
880 	xsl_object *intern;
881 	char *filename = NULL;
882 	size_t filename_len;
883 	DOM_GET_THIS(id);
884 
885 	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "p!", &filename, &filename_len) == SUCCESS) {
886 		intern = Z_XSL_P(id);
887 		if (intern->profiling) {
888 			efree(intern->profiling);
889 		}
890 		if (filename != NULL) {
891 			intern->profiling = estrndup(filename, filename_len);
892 		} else {
893 			intern->profiling = NULL;
894 		}
895 		RETURN_TRUE;
896 	} else {
897 		WRONG_PARAM_COUNT;
898 	}
899 }
900 /* }}} end xsl_xsltprocessor_set_profiling */
901 
902 /* {{{ proto long xsl_xsltprocessor_set_security_prefs(long securityPrefs) */
PHP_FUNCTION(xsl_xsltprocessor_set_security_prefs)903 PHP_FUNCTION(xsl_xsltprocessor_set_security_prefs)
904 {
905 	zval *id;
906 	xsl_object *intern;
907 	zend_long securityPrefs, oldSecurityPrefs;
908 
909 	DOM_GET_THIS(id);
910  	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &securityPrefs) == FAILURE) {
911 		return;
912 	}
913 	intern = Z_XSL_P(id);
914 	oldSecurityPrefs = intern->securityPrefs;
915 	intern->securityPrefs = securityPrefs;
916 	/* set this to 1 so that we know, it was set through this method. Can be removed, when we remove the ini setting */
917 	intern->securityPrefsSet = 1;
918 	RETURN_LONG(oldSecurityPrefs);
919 }
920 /* }}} end xsl_xsltprocessor_set_security_prefs */
921 
922 /* {{{ proto long xsl_xsltprocessor_get_security_prefs() */
PHP_FUNCTION(xsl_xsltprocessor_get_security_prefs)923 PHP_FUNCTION(xsl_xsltprocessor_get_security_prefs)
924 {
925 	zval *id;
926 	xsl_object *intern;
927 
928 	DOM_GET_THIS(id);
929 	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "") == SUCCESS) {
930 		intern = Z_XSL_P(id);
931 		RETURN_LONG(intern->securityPrefs);
932 	} else {
933 		WRONG_PARAM_COUNT;
934 	}
935 }
936 /* }}} end xsl_xsltprocessor_get_security_prefs */
937 
938 /* {{{ proto bool xsl_xsltprocessor_has_exslt_support()
939 */
PHP_FUNCTION(xsl_xsltprocessor_has_exslt_support)940 PHP_FUNCTION(xsl_xsltprocessor_has_exslt_support)
941 {
942 #if HAVE_XSL_EXSLT
943 	RETURN_TRUE;
944 #else
945 	RETURN_FALSE;
946 #endif
947 }
948 /* }}} end xsl_xsltprocessor_has_exslt_support(); */
949 
950 /*
951  * Local variables:
952  * tab-width: 4
953  * c-basic-offset: 4
954  * End:
955  * vim600: sw=4 ts=4 fdm=marker
956  * vim<600: sw=4 ts=4
957  */
958