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