1 /*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Authors: Christian Stocker <chregu@php.net> |
14 | Rob Richards <rrichards@php.net> |
15 +----------------------------------------------------------------------+
16 */
17
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21
22 #include "php.h"
23 #include "php_xsl.h"
24 #include "ext/libxml/php_libxml.h"
25
26 /* {{{ php_xsl_xslt_string_to_xpathexpr()
27 Translates a string to a XPath Expression */
php_xsl_xslt_string_to_xpathexpr(const char * str)28 static char *php_xsl_xslt_string_to_xpathexpr(const char *str)
29 {
30 const xmlChar *string = (const xmlChar *)str;
31
32 xmlChar *value;
33 int str_len;
34
35 str_len = xmlStrlen(string) + 3;
36
37 if (xmlStrchr(string, '"')) {
38 if (xmlStrchr(string, '\'')) {
39 php_error_docref(NULL, E_WARNING, "Cannot create XPath expression (string contains both quote and double-quotes)");
40 return NULL;
41 }
42 value = (xmlChar*) safe_emalloc (str_len, sizeof(xmlChar), 0);
43 snprintf((char*)value, str_len, "'%s'", string);
44 } else {
45 value = (xmlChar*) safe_emalloc (str_len, sizeof(xmlChar), 0);
46 snprintf((char *)value, str_len, "\"%s\"", string);
47 }
48 return (char *) value;
49 }
50 /* }}} */
51
52 /* {{{ php_xsl_xslt_make_params()
53 Translates a PHP array to a libxslt parameters array */
php_xsl_xslt_make_params(HashTable * parht,int xpath_params)54 static char **php_xsl_xslt_make_params(HashTable *parht, int xpath_params)
55 {
56
57 int parsize;
58 zval *value;
59 char *xpath_expr;
60 zend_string *string_key;
61 char **params = NULL;
62 int i = 0;
63
64 parsize = (2 * zend_hash_num_elements(parht) + 1) * sizeof(char *);
65 params = (char **)safe_emalloc((2 * zend_hash_num_elements(parht) + 1), sizeof(char *), 0);
66 memset((char *)params, 0, parsize);
67
68 ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(parht, string_key, value) {
69 ZEND_ASSERT(string_key != NULL);
70 if (Z_TYPE_P(value) != IS_STRING) {
71 if (!try_convert_to_string(value)) {
72 efree(params);
73 return NULL;
74 }
75 }
76
77 if (!xpath_params) {
78 xpath_expr = php_xsl_xslt_string_to_xpathexpr(Z_STRVAL_P(value));
79 } else {
80 xpath_expr = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value));
81 }
82 if (xpath_expr) {
83 params[i++] = estrndup(ZSTR_VAL(string_key), ZSTR_LEN(string_key));
84 params[i++] = xpath_expr;
85 }
86 } ZEND_HASH_FOREACH_END();
87
88 params[i++] = NULL;
89
90 return params;
91 }
92 /* }}} */
93
xsl_ext_function_php(xmlXPathParserContextPtr ctxt,int nargs,int type)94 static void xsl_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int type) /* {{{ */
95 {
96 xsltTransformContextPtr tctxt;
97 zval *args = NULL;
98 zval retval;
99 int i;
100 int error = 0;
101 zend_fcall_info fci;
102 zval handler;
103 xmlXPathObjectPtr obj;
104 char *str;
105 xsl_object *intern;
106 zend_string *callable = NULL;
107
108
109 if (! zend_is_executing()) {
110 xsltGenericError(xsltGenericErrorContext,
111 "xsltExtFunctionTest: Function called from outside of PHP\n");
112 error = 1;
113 } else {
114 tctxt = xsltXPathGetTransformContext(ctxt);
115 if (tctxt == NULL) {
116 xsltGenericError(xsltGenericErrorContext,
117 "xsltExtFunctionTest: failed to get the transformation context\n");
118 error = 1;
119 } else {
120 intern = (xsl_object*)tctxt->_private;
121 if (intern == NULL) {
122 xsltGenericError(xsltGenericErrorContext,
123 "xsltExtFunctionTest: failed to get the internal object\n");
124 error = 1;
125 }
126 else if (intern->registerPhpFunctions == 0) {
127 xsltGenericError(xsltGenericErrorContext,
128 "xsltExtFunctionTest: PHP Object did not register PHP functions\n");
129 error = 1;
130 }
131 }
132 }
133
134 if (error == 1) {
135 for (i = nargs - 1; i >= 0; i--) {
136 obj = valuePop(ctxt);
137 if (obj) {
138 xmlXPathFreeObject(obj);
139 }
140 }
141 return;
142 }
143
144 if (UNEXPECTED(nargs == 0)) {
145 zend_throw_error(NULL, "Function name must be passed as the first argument");
146 return;
147 }
148
149 fci.param_count = nargs - 1;
150 if (fci.param_count > 0) {
151 args = safe_emalloc(fci.param_count, sizeof(zval), 0);
152 }
153 /* Reverse order to pop values off ctxt stack */
154 for (i = fci.param_count - 1; i >= 0; i--) {
155 obj = valuePop(ctxt);
156 if (obj == NULL) {
157 ZVAL_NULL(&args[i]);
158 continue;
159 }
160 switch (obj->type) {
161 case XPATH_STRING:
162 ZVAL_STRING(&args[i], (char *)obj->stringval);
163 break;
164 case XPATH_BOOLEAN:
165 ZVAL_BOOL(&args[i], obj->boolval);
166 break;
167 case XPATH_NUMBER:
168 ZVAL_DOUBLE(&args[i], obj->floatval);
169 break;
170 case XPATH_NODESET:
171 if (type == 1) {
172 str = (char*)xmlXPathCastToString(obj);
173 ZVAL_STRING(&args[i], str);
174 xmlFree(str);
175 } else if (type == 2) {
176 int j;
177 dom_object *domintern = (dom_object *)intern->doc;
178 if (obj->nodesetval && obj->nodesetval->nodeNr > 0) {
179 array_init(&args[i]);
180 for (j = 0; j < obj->nodesetval->nodeNr; j++) {
181 xmlNodePtr node = obj->nodesetval->nodeTab[j];
182 zval child;
183 /* not sure, if we need this... it's copied from xpath.c */
184 if (node->type == XML_NAMESPACE_DECL) {
185 xmlNsPtr curns;
186 xmlNodePtr nsparent;
187
188 nsparent = node->_private;
189 curns = xmlNewNs(NULL, node->name, NULL);
190 if (node->children) {
191 curns->prefix = xmlStrdup((xmlChar *)node->children);
192 }
193 if (node->children) {
194 node = xmlNewDocNode(node->doc, NULL, (xmlChar *) node->children, node->name);
195 } else {
196 node = xmlNewDocNode(node->doc, NULL, (const xmlChar *) "xmlns", node->name);
197 }
198 node->type = XML_NAMESPACE_DECL;
199 node->parent = nsparent;
200 node->ns = curns;
201 } else {
202 /**
203 * Upon freeing libxslt's context, every document which is not the *main* document will be freed by libxslt.
204 * If a node of a document which is *not the main* document gets returned to userland, we'd free the node twice:
205 * first by the cleanup of the xslt context, and then by our own refcounting mechanism.
206 * To prevent this, we'll take a copy if the node is not from the main document.
207 * It is important that we do not copy the node unconditionally, because that means that:
208 * - modifications to the node will only modify the copy, and not the original
209 * - accesses to the parent, path, ... will not work
210 */
211 xsltTransformContextPtr transform_ctxt = (xsltTransformContextPtr) ctxt->context->extra;
212 if (node->doc != transform_ctxt->document->doc) {
213 node = xmlDocCopyNode(node, domintern->document->ptr, 1);
214 }
215 }
216
217 php_dom_create_object(node, &child, domintern);
218 add_next_index_zval(&args[i], &child);
219 }
220 } else {
221 ZVAL_EMPTY_ARRAY(&args[i]);
222 }
223 }
224 break;
225 default:
226 str = (char *) xmlXPathCastToString(obj);
227 ZVAL_STRING(&args[i], str);
228 xmlFree(str);
229 }
230 xmlXPathFreeObject(obj);
231 }
232
233 fci.size = sizeof(fci);
234 fci.named_params = NULL;
235 if (fci.param_count > 0) {
236 fci.params = args;
237 } else {
238 fci.params = NULL;
239 }
240
241 /* Last element of the stack is the function name */
242 obj = valuePop(ctxt);
243 if (obj == NULL || obj->stringval == NULL) {
244 php_error_docref(NULL, E_WARNING, "Handler name must be a string");
245 xmlXPathFreeObject(obj);
246 valuePush(ctxt, xmlXPathNewString((const xmlChar *) ""));
247 if (fci.param_count > 0) {
248 for (i = 0; i < nargs - 1; i++) {
249 zval_ptr_dtor(&args[i]);
250 }
251 efree(args);
252 }
253 return;
254 }
255 ZVAL_STRING(&handler, (char *) obj->stringval);
256 xmlXPathFreeObject(obj);
257
258 ZVAL_COPY_VALUE(&fci.function_name, &handler);
259 fci.object = NULL;
260 fci.retval = &retval;
261 if (!zend_make_callable(&handler, &callable)) {
262 if (!EG(exception)) {
263 php_error_docref(NULL, E_WARNING, "Unable to call handler %s()", ZSTR_VAL(callable));
264 }
265 valuePush(ctxt, xmlXPathNewString((const xmlChar *) ""));
266 } else if ( intern->registerPhpFunctions == 2 && zend_hash_exists(intern->registered_phpfunctions, callable) == 0) {
267 php_error_docref(NULL, E_WARNING, "Not allowed to call handler '%s()'", ZSTR_VAL(callable));
268 /* Push an empty string, so that we at least have an xslt result... */
269 valuePush(ctxt, xmlXPathNewString((const xmlChar *) ""));
270 } else {
271 zend_call_function(&fci, NULL);
272 if (Z_ISUNDEF(retval)) {
273 /* Exception thrown, don't do anything further. */
274 } else if (Z_TYPE(retval) == IS_OBJECT && instanceof_function(Z_OBJCE(retval), dom_node_class_entry)) {
275 xmlNode *nodep;
276 dom_object *obj;
277 if (intern->node_list == NULL) {
278 intern->node_list = zend_new_array(0);
279 }
280 Z_ADDREF(retval);
281 zend_hash_next_index_insert(intern->node_list, &retval);
282 obj = Z_DOMOBJ_P(&retval);
283 nodep = dom_object_get_node(obj);
284 valuePush(ctxt, xmlXPathNewNodeSet(nodep));
285 } else if (Z_TYPE(retval) == IS_TRUE || Z_TYPE(retval) == IS_FALSE) {
286 valuePush(ctxt, xmlXPathNewBoolean(Z_TYPE(retval) == IS_TRUE));
287 } else if (Z_TYPE(retval) == IS_OBJECT) {
288 php_error_docref(NULL, E_WARNING, "A PHP Object cannot be converted to a XPath-string");
289 valuePush(ctxt, xmlXPathNewString((const xmlChar *) ""));
290 } else {
291 convert_to_string(&retval);
292 valuePush(ctxt, xmlXPathNewString((xmlChar *) Z_STRVAL(retval)));
293 }
294 zval_ptr_dtor(&retval);
295 }
296 zend_string_release_ex(callable, 0);
297 zval_ptr_dtor_nogc(&handler);
298 if (fci.param_count > 0) {
299 for (i = 0; i < nargs - 1; i++) {
300 zval_ptr_dtor(&args[i]);
301 }
302 efree(args);
303 }
304 }
305 /* }}} */
306
xsl_ext_function_string_php(xmlXPathParserContextPtr ctxt,int nargs)307 void xsl_ext_function_string_php(xmlXPathParserContextPtr ctxt, int nargs) /* {{{ */
308 {
309 xsl_ext_function_php(ctxt, nargs, 1);
310 }
311 /* }}} */
312
xsl_ext_function_object_php(xmlXPathParserContextPtr ctxt,int nargs)313 void xsl_ext_function_object_php(xmlXPathParserContextPtr ctxt, int nargs) /* {{{ */
314 {
315 xsl_ext_function_php(ctxt, nargs, 2);
316 }
317 /* }}} */
318
319 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#
320 Since:
321 */
PHP_METHOD(XSLTProcessor,importStylesheet)322 PHP_METHOD(XSLTProcessor, importStylesheet)
323 {
324 zval *id, *docp = NULL;
325 xmlDoc *doc = NULL, *newdoc = NULL;
326 xsltStylesheetPtr sheetp, oldsheetp;
327 xsl_object *intern;
328 int clone_docu = 0;
329 xmlNode *nodep = NULL;
330 zval *cloneDocu, rv;
331 zend_string *member;
332
333 id = ZEND_THIS;
334 if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &docp) == FAILURE) {
335 RETURN_THROWS();
336 }
337
338 nodep = php_libxml_import_node(docp);
339
340 if (nodep) {
341 doc = nodep->doc;
342 }
343 if (doc == NULL) {
344 zend_argument_value_error(1, "must be a valid XML node");
345 RETURN_THROWS();
346 }
347
348 /* libxslt uses _private, so we must copy the imported
349 stylesheet document otherwise the node proxies will be a mess */
350 newdoc = xmlCopyDoc(doc, 1);
351 xmlNodeSetBase((xmlNodePtr) newdoc, (xmlChar *)doc->URL);
352 PHP_LIBXML_SANITIZE_GLOBALS(parse);
353 PHP_LIBXML_IGNORE_DEPRECATIONS_START
354 xmlSubstituteEntitiesDefault(1);
355 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
356 PHP_LIBXML_IGNORE_DEPRECATIONS_END
357
358 sheetp = xsltParseStylesheetDoc(newdoc);
359 PHP_LIBXML_RESTORE_GLOBALS(parse);
360
361 if (!sheetp) {
362 xmlFreeDoc(newdoc);
363 RETURN_FALSE;
364 }
365
366 intern = Z_XSL_P(id);
367
368 member = ZSTR_INIT_LITERAL("cloneDocument", 0);
369 cloneDocu = zend_std_read_property(Z_OBJ_P(id), member, BP_VAR_IS, NULL, &rv);
370 if (Z_TYPE_P(cloneDocu) != IS_NULL) {
371 convert_to_long(cloneDocu);
372 clone_docu = Z_LVAL_P(cloneDocu);
373 }
374 zend_string_release_ex(member, 0);
375 if (clone_docu == 0) {
376 /* check if the stylesheet is using xsl:key, if yes, we have to clone the document _always_ before a transformation */
377 nodep = xmlDocGetRootElement(sheetp->doc);
378 if (nodep && (nodep = nodep->children)) {
379 while (nodep) {
380 if (nodep->type == XML_ELEMENT_NODE && xmlStrEqual(nodep->name, (const xmlChar *) "key") && xmlStrEqual(nodep->ns->href, XSLT_NAMESPACE)) {
381 intern->hasKeys = 1;
382 break;
383 }
384 nodep = nodep->next;
385 }
386 }
387 } else {
388 intern->hasKeys = clone_docu;
389 }
390
391 if ((oldsheetp = (xsltStylesheetPtr)intern->ptr)) {
392 /* free wrapper */
393 if (((xsltStylesheetPtr) intern->ptr)->_private != NULL) {
394 ((xsltStylesheetPtr) intern->ptr)->_private = NULL;
395 }
396 xsltFreeStylesheet((xsltStylesheetPtr) intern->ptr);
397 intern->ptr = NULL;
398 }
399
400 php_xsl_set_object(id, sheetp);
401 RETVAL_TRUE;
402 }
403 /* }}} end XSLTProcessor::importStylesheet */
404
php_xsl_apply_stylesheet(zval * id,xsl_object * intern,xsltStylesheetPtr style,zval * docp)405 static xmlDocPtr php_xsl_apply_stylesheet(zval *id, xsl_object *intern, xsltStylesheetPtr style, zval *docp) /* {{{ */
406 {
407 xmlDocPtr newdocp = NULL;
408 xmlDocPtr doc = NULL;
409 xmlNodePtr node = NULL;
410 xsltTransformContextPtr ctxt;
411 php_libxml_node_object *object;
412 char **params = NULL;
413 int clone;
414 zval *doXInclude, rv;
415 zend_string *member;
416 FILE *f;
417 int secPrefsError = 0;
418 int secPrefsValue;
419 xsltSecurityPrefsPtr secPrefs = NULL;
420
421 node = php_libxml_import_node(docp);
422
423 if (node) {
424 doc = node->doc;
425 }
426
427 if (doc == NULL) {
428 zend_argument_value_error(1, "must be a valid XML node");
429 return NULL;
430 }
431
432 if (style == NULL) {
433 zend_string *name = get_active_function_or_method_name();
434 zend_throw_error(NULL, "%s() can only be called after a stylesheet has been imported",
435 ZSTR_VAL(name));
436 zend_string_release(name);
437 return NULL;
438 }
439
440 if (intern->profiling) {
441 if (php_check_open_basedir(intern->profiling)) {
442 f = NULL;
443 } else {
444 f = VCWD_FOPEN(intern->profiling, "w");
445 }
446 } else {
447 f = NULL;
448 }
449
450 if (intern->parameter) {
451 params = php_xsl_xslt_make_params(intern->parameter, 0);
452 }
453
454 intern->doc = emalloc(sizeof(php_libxml_node_object));
455 memset(intern->doc, 0, sizeof(php_libxml_node_object));
456
457 if (intern->hasKeys == 1) {
458 doc = xmlCopyDoc(doc, 1);
459 } else {
460 object = Z_LIBXML_NODE_P(docp);
461 intern->doc->document = object->document;
462 }
463
464 php_libxml_increment_doc_ref(intern->doc, doc);
465
466 ctxt = xsltNewTransformContext(style, doc);
467 ctxt->_private = (void *) intern;
468
469 member = ZSTR_INIT_LITERAL("doXInclude", 0);
470 doXInclude = zend_std_read_property(Z_OBJ_P(id), member, BP_VAR_IS, NULL, &rv);
471 if (Z_TYPE_P(doXInclude) != IS_NULL) {
472 convert_to_long(doXInclude);
473 ctxt->xinclude = Z_LVAL_P(doXInclude);
474 }
475 zend_string_release_ex(member, 0);
476
477 secPrefsValue = intern->securityPrefs;
478
479 /* if securityPrefs is set to NONE, we don't have to do any checks, but otherwise... */
480 if (secPrefsValue != XSL_SECPREF_NONE) {
481 secPrefs = xsltNewSecurityPrefs();
482 if (secPrefsValue & XSL_SECPREF_READ_FILE ) {
483 if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_READ_FILE, xsltSecurityForbid)) {
484 secPrefsError = 1;
485 }
486 }
487 if (secPrefsValue & XSL_SECPREF_WRITE_FILE ) {
488 if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_WRITE_FILE, xsltSecurityForbid)) {
489 secPrefsError = 1;
490 }
491 }
492 if (secPrefsValue & XSL_SECPREF_CREATE_DIRECTORY ) {
493 if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_CREATE_DIRECTORY, xsltSecurityForbid)) {
494 secPrefsError = 1;
495 }
496 }
497 if (secPrefsValue & XSL_SECPREF_READ_NETWORK) {
498 if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_READ_NETWORK, xsltSecurityForbid)) {
499 secPrefsError = 1;
500 }
501 }
502 if (secPrefsValue & XSL_SECPREF_WRITE_NETWORK) {
503 if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_WRITE_NETWORK, xsltSecurityForbid)) {
504 secPrefsError = 1;
505 }
506 }
507
508 if (0 != xsltSetCtxtSecurityPrefs(secPrefs, ctxt)) {
509 secPrefsError = 1;
510 }
511 }
512
513 if (secPrefsError == 1) {
514 php_error_docref(NULL, E_WARNING, "Can't set libxslt security properties, not doing transformation for security reasons");
515 } else {
516 newdocp = xsltApplyStylesheetUser(style, doc, (const char**) params, NULL, f, ctxt);
517 }
518 if (f) {
519 fclose(f);
520 }
521
522 xsltFreeTransformContext(ctxt);
523 if (secPrefs) {
524 xsltFreeSecurityPrefs(secPrefs);
525 }
526
527 if (intern->node_list != NULL) {
528 zend_hash_destroy(intern->node_list);
529 FREE_HASHTABLE(intern->node_list);
530 intern->node_list = NULL;
531 }
532
533 php_libxml_decrement_doc_ref(intern->doc);
534 efree(intern->doc);
535 intern->doc = NULL;
536
537 if (params) {
538 clone = 0;
539 while(params[clone]) {
540 efree(params[clone++]);
541 }
542 efree(params);
543 }
544
545 return newdocp;
546
547 }
548 /* }}} */
549
550 /* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#
551 Since:
552 */
PHP_METHOD(XSLTProcessor,transformToDoc)553 PHP_METHOD(XSLTProcessor, transformToDoc)
554 {
555 zval *id, *docp = NULL;
556 xmlDoc *newdocp;
557 xsltStylesheetPtr sheetp;
558 zend_string *ret_class = NULL;
559 xsl_object *intern;
560
561 id = ZEND_THIS;
562 intern = Z_XSL_P(id);
563 sheetp = (xsltStylesheetPtr) intern->ptr;
564
565 if (zend_parse_parameters(ZEND_NUM_ARGS(), "o|S!", &docp, &ret_class) == FAILURE) {
566 RETURN_THROWS();
567 }
568
569 newdocp = php_xsl_apply_stylesheet(id, intern, sheetp, docp);
570
571 if (newdocp) {
572 if (ret_class) {
573 zend_string *curclass_name;
574 zend_class_entry *curce, *ce;
575 php_libxml_node_object *interndoc;
576
577 curce = Z_OBJCE_P(docp);
578 curclass_name = curce->name;
579 while (curce->parent != NULL) {
580 curce = curce->parent;
581 }
582
583 ce = zend_lookup_class(ret_class);
584 if (ce == NULL || !instanceof_function(ce, curce)) {
585 xmlFreeDoc(newdocp);
586 zend_argument_type_error(2, "must be a class name compatible with %s, \"%s\" given",
587 ZSTR_VAL(curclass_name), ZSTR_VAL(ret_class)
588 );
589 RETURN_THROWS();
590 }
591
592 object_init_ex(return_value, ce);
593
594 interndoc = Z_LIBXML_NODE_P(return_value);
595 php_libxml_increment_doc_ref(interndoc, newdocp);
596 php_libxml_increment_node_ptr(interndoc, (xmlNodePtr)newdocp, (void *)interndoc);
597 } else {
598 php_dom_create_object((xmlNodePtr) newdocp, return_value, NULL);
599 }
600 } else {
601 RETURN_FALSE;
602 }
603
604 }
605 /* }}} end XSLTProcessor::transformToDoc */
606
607 /* {{{ */
PHP_METHOD(XSLTProcessor,transformToUri)608 PHP_METHOD(XSLTProcessor, transformToUri)
609 {
610 zval *id, *docp = NULL;
611 xmlDoc *newdocp;
612 xsltStylesheetPtr sheetp;
613 int ret;
614 size_t uri_len;
615 char *uri;
616 xsl_object *intern;
617
618 id = ZEND_THIS;
619 intern = Z_XSL_P(id);
620 sheetp = (xsltStylesheetPtr) intern->ptr;
621
622 if (zend_parse_parameters(ZEND_NUM_ARGS(), "op", &docp, &uri, &uri_len) == FAILURE) {
623 RETURN_THROWS();
624 }
625
626 newdocp = php_xsl_apply_stylesheet(id, intern, sheetp, docp);
627
628 ret = -1;
629 if (newdocp) {
630 ret = xsltSaveResultToFilename(uri, newdocp, sheetp, 0);
631 xmlFreeDoc(newdocp);
632 }
633
634 RETVAL_LONG(ret);
635 }
636 /* }}} end XSLTProcessor::transformToUri */
637
638 /* {{{ */
PHP_METHOD(XSLTProcessor,transformToXml)639 PHP_METHOD(XSLTProcessor, transformToXml)
640 {
641 zval *id, *docp = NULL;
642 xmlDoc *newdocp;
643 xsltStylesheetPtr sheetp;
644 int ret;
645 xmlChar *doc_txt_ptr;
646 int doc_txt_len;
647 xsl_object *intern;
648
649 id = ZEND_THIS;
650 intern = Z_XSL_P(id);
651 sheetp = (xsltStylesheetPtr) intern->ptr;
652
653 if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &docp) == FAILURE) {
654 RETURN_THROWS();
655 }
656
657 newdocp = php_xsl_apply_stylesheet(id, intern, sheetp, docp);
658
659 ret = -1;
660 if (newdocp) {
661 ret = xsltSaveResultToString(&doc_txt_ptr, &doc_txt_len, newdocp, sheetp);
662 if (doc_txt_ptr && doc_txt_len) {
663 RETVAL_STRINGL((char *) doc_txt_ptr, doc_txt_len);
664 xmlFree(doc_txt_ptr);
665 }
666 xmlFreeDoc(newdocp);
667 }
668
669 if (ret < 0) {
670 RETURN_FALSE;
671 }
672 }
673 /* }}} end XSLTProcessor::transformToXml */
674
675 /* {{{ */
PHP_METHOD(XSLTProcessor,setParameter)676 PHP_METHOD(XSLTProcessor, setParameter)
677 {
678
679 zval *id = ZEND_THIS;
680 zval *entry, new_string;
681 HashTable *array_value;
682 xsl_object *intern;
683 char *namespace;
684 size_t namespace_len;
685 zend_string *string_key, *name, *value = NULL;
686
687 ZEND_PARSE_PARAMETERS_START(2, 3)
688 Z_PARAM_STRING(namespace, namespace_len)
689 Z_PARAM_ARRAY_HT_OR_STR(array_value, name)
690 Z_PARAM_OPTIONAL
691 Z_PARAM_STR_OR_NULL(value)
692 ZEND_PARSE_PARAMETERS_END();
693
694 intern = Z_XSL_P(id);
695
696 if (array_value) {
697 if (value) {
698 zend_argument_value_error(3, "must be null when argument #2 ($name) is an array");
699 RETURN_THROWS();
700 }
701
702 ZEND_HASH_FOREACH_STR_KEY_VAL(array_value, string_key, entry) {
703 zval tmp;
704 zend_string *str;
705
706 if (string_key == NULL) {
707 zend_argument_type_error(2, "must contain only string keys");
708 RETURN_THROWS();
709 }
710 str = zval_try_get_string(entry);
711 if (UNEXPECTED(!str)) {
712 RETURN_THROWS();
713 }
714 ZVAL_STR(&tmp, str);
715 zend_hash_update(intern->parameter, string_key, &tmp);
716 } ZEND_HASH_FOREACH_END();
717 RETURN_TRUE;
718 } else {
719 if (!value) {
720 zend_argument_value_error(3, "cannot be null when argument #2 ($name) is a string");
721 RETURN_THROWS();
722 }
723
724 ZVAL_STR_COPY(&new_string, value);
725
726 zend_hash_update(intern->parameter, name, &new_string);
727 RETURN_TRUE;
728 }
729 }
730 /* }}} end XSLTProcessor::setParameter */
731
732 /* {{{ */
PHP_METHOD(XSLTProcessor,getParameter)733 PHP_METHOD(XSLTProcessor, getParameter)
734 {
735 zval *id = ZEND_THIS;
736 char *namespace;
737 size_t namespace_len = 0;
738 zval *value;
739 zend_string *name;
740 xsl_object *intern;
741
742 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sS", &namespace, &namespace_len, &name) == FAILURE) {
743 RETURN_THROWS();
744 }
745 intern = Z_XSL_P(id);
746 if ((value = zend_hash_find(intern->parameter, name)) != NULL) {
747 RETURN_STR(zval_get_string(value));
748 } else {
749 RETURN_FALSE;
750 }
751 }
752 /* }}} end XSLTProcessor::getParameter */
753
754 /* {{{ */
PHP_METHOD(XSLTProcessor,removeParameter)755 PHP_METHOD(XSLTProcessor, removeParameter)
756 {
757 zval *id = ZEND_THIS;
758 size_t namespace_len = 0;
759 char *namespace;
760 zend_string *name;
761 xsl_object *intern;
762
763 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sS", &namespace, &namespace_len, &name) == FAILURE) {
764 RETURN_THROWS();
765 }
766 intern = Z_XSL_P(id);
767 if (zend_hash_del(intern->parameter, name) == SUCCESS) {
768 RETURN_TRUE;
769 } else {
770 RETURN_FALSE;
771 }
772 }
773 /* }}} end XSLTProcessor::removeParameter */
774
775 /* {{{ */
PHP_METHOD(XSLTProcessor,registerPHPFunctions)776 PHP_METHOD(XSLTProcessor, registerPHPFunctions)
777 {
778 zval *id = ZEND_THIS;
779 xsl_object *intern;
780 zval *entry, new_string;
781 zend_string *restrict_str = NULL;
782 HashTable *restrict_ht = NULL;
783
784 ZEND_PARSE_PARAMETERS_START(0, 1)
785 Z_PARAM_OPTIONAL
786 Z_PARAM_ARRAY_HT_OR_STR_OR_NULL(restrict_ht, restrict_str)
787 ZEND_PARSE_PARAMETERS_END();
788
789 intern = Z_XSL_P(id);
790
791 if (restrict_ht) {
792 ZEND_HASH_FOREACH_VAL(restrict_ht, entry) {
793 zend_string *str = zval_try_get_string(entry);
794 if (UNEXPECTED(!str)) {
795 return;
796 }
797 ZVAL_LONG(&new_string, 1);
798 zend_hash_update(intern->registered_phpfunctions, str, &new_string);
799 zend_string_release(str);
800 } ZEND_HASH_FOREACH_END();
801
802 intern->registerPhpFunctions = 2;
803 } else if (restrict_str) {
804 ZVAL_LONG(&new_string, 1);
805 zend_hash_update(intern->registered_phpfunctions, restrict_str, &new_string);
806 intern->registerPhpFunctions = 2;
807 } else {
808 intern->registerPhpFunctions = 1;
809 }
810 }
811 /* }}} end XSLTProcessor::registerPHPFunctions(); */
812
813 /* {{{ */
PHP_METHOD(XSLTProcessor,setProfiling)814 PHP_METHOD(XSLTProcessor, setProfiling)
815 {
816 zval *id = ZEND_THIS;
817 xsl_object *intern;
818 char *filename = NULL;
819 size_t filename_len;
820
821 if (zend_parse_parameters(ZEND_NUM_ARGS(), "p!", &filename, &filename_len) == FAILURE) {
822 RETURN_THROWS();
823 }
824
825 intern = Z_XSL_P(id);
826 if (intern->profiling) {
827 efree(intern->profiling);
828 }
829 if (filename != NULL) {
830 intern->profiling = estrndup(filename, filename_len);
831 } else {
832 intern->profiling = NULL;
833 }
834
835 RETURN_TRUE;
836 }
837 /* }}} end XSLTProcessor::setProfiling */
838
839 /* {{{ */
PHP_METHOD(XSLTProcessor,setSecurityPrefs)840 PHP_METHOD(XSLTProcessor, setSecurityPrefs)
841 {
842 zval *id = ZEND_THIS;
843 xsl_object *intern;
844 zend_long securityPrefs, oldSecurityPrefs;
845
846 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &securityPrefs) == FAILURE) {
847 RETURN_THROWS();
848 }
849 intern = Z_XSL_P(id);
850 oldSecurityPrefs = intern->securityPrefs;
851 intern->securityPrefs = securityPrefs;
852 /* set this to 1 so that we know, it was set through this method. Can be removed, when we remove the ini setting */
853 intern->securityPrefsSet = 1;
854 RETURN_LONG(oldSecurityPrefs);
855 }
856 /* }}} end XSLTProcessor::setSecurityPrefs */
857
858 /* {{{ */
PHP_METHOD(XSLTProcessor,getSecurityPrefs)859 PHP_METHOD(XSLTProcessor, getSecurityPrefs)
860 {
861 zval *id = ZEND_THIS;
862 xsl_object *intern;
863
864 if (zend_parse_parameters_none() == FAILURE) {
865 RETURN_THROWS();
866 }
867
868 intern = Z_XSL_P(id);
869
870 RETURN_LONG(intern->securityPrefs);
871 }
872 /* }}} end XSLTProcessor::getSecurityPrefs */
873
874 /* {{{ */
PHP_METHOD(XSLTProcessor,hasExsltSupport)875 PHP_METHOD(XSLTProcessor, hasExsltSupport)
876 {
877 if (zend_parse_parameters_none() == FAILURE) {
878 RETURN_THROWS();
879 }
880
881 #ifdef HAVE_XSL_EXSLT
882 RETURN_TRUE;
883 #else
884 RETURN_FALSE;
885 #endif
886 }
887 /* }}} end XSLTProcessor::hasExsltSupport(); */
888