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