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