1/*
2   +----------------------------------------------------------------------+
3   | PHP Version 5                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2013 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/* }}} */
75
76/*
77* class xsl_xsltprocessor
78*
79* URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#
80* Since:
81*/
82
83const zend_function_entry php_xsl_xsltprocessor_class_functions[] = {
84    PHP_FALIAS(importStylesheet, xsl_xsltprocessor_import_stylesheet, arginfo_xsl_xsltprocessor_import_stylesheet)
85    PHP_FALIAS(transformToDoc, xsl_xsltprocessor_transform_to_doc, arginfo_xsl_xsltprocessor_transform_to_doc)
86    PHP_FALIAS(transformToUri, xsl_xsltprocessor_transform_to_uri, arginfo_xsl_xsltprocessor_transform_to_uri)
87    PHP_FALIAS(transformToXml, xsl_xsltprocessor_transform_to_xml, arginfo_xsl_xsltprocessor_transform_to_xml)
88    PHP_FALIAS(setParameter, xsl_xsltprocessor_set_parameter, arginfo_xsl_xsltprocessor_set_parameter)
89    PHP_FALIAS(getParameter, xsl_xsltprocessor_get_parameter, arginfo_xsl_xsltprocessor_get_parameter)
90    PHP_FALIAS(removeParameter, xsl_xsltprocessor_remove_parameter, arginfo_xsl_xsltprocessor_remove_parameter)
91    PHP_FALIAS(hasExsltSupport, xsl_xsltprocessor_has_exslt_support, arginfo_xsl_xsltprocessor_has_exslt_support)
92    PHP_FALIAS(registerPHPFunctions, xsl_xsltprocessor_register_php_functions, arginfo_xsl_xsltprocessor_register_php_functions)
93    PHP_FALIAS(setProfiling, xsl_xsltprocessor_set_profiling, arginfo_xsl_xsltprocessor_set_profiling)
94    {NULL, NULL, NULL}
95};
96
97/* {{{ php_xsl_xslt_string_to_xpathexpr()
98   Translates a string to a XPath Expression */
99static char *php_xsl_xslt_string_to_xpathexpr(const char *str TSRMLS_DC)
100{
101    const xmlChar *string = (const xmlChar *)str;
102
103    xmlChar *value;
104    int str_len;
105
106    str_len = xmlStrlen(string) + 3;
107
108    if (xmlStrchr(string, '"')) {
109        if (xmlStrchr(string, '\'')) {
110            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot create XPath expression (string contains both quote and double-quotes)");
111            return NULL;
112        }
113        value = (xmlChar*) safe_emalloc (str_len, sizeof(xmlChar), 0);
114        snprintf(value, str_len, "'%s'", string);
115    } else {
116        value = (xmlChar*) safe_emalloc (str_len, sizeof(xmlChar), 0);
117        snprintf(value, str_len, "\"%s\"", string);
118    }
119    return (char *) value;
120}
121/* }}} */
122
123/* {{{ php_xsl_xslt_make_params()
124   Translates a PHP array to a libxslt parameters array */
125static char **php_xsl_xslt_make_params(HashTable *parht, int xpath_params TSRMLS_DC)
126{
127
128    int parsize;
129    zval **value;
130    char *xpath_expr, *string_key = NULL;
131    ulong num_key;
132    char **params = NULL;
133    int i = 0;
134
135    parsize = (2 * zend_hash_num_elements(parht) + 1) * sizeof(char *);
136    params = (char **)safe_emalloc((2 * zend_hash_num_elements(parht) + 1), sizeof(char *), 0);
137    memset((char *)params, 0, parsize);
138
139    for (zend_hash_internal_pointer_reset(parht);
140        zend_hash_get_current_data(parht, (void **)&value) == SUCCESS;
141        zend_hash_move_forward(parht)) {
142
143        if (zend_hash_get_current_key(parht, &string_key, &num_key, 1) != HASH_KEY_IS_STRING) {
144            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid argument or parameter array");
145            efree(params);
146            return NULL;
147        } else {
148            if (Z_TYPE_PP(value) != IS_STRING) {
149                SEPARATE_ZVAL(value);
150                convert_to_string(*value);
151            }
152
153            if (!xpath_params) {
154                xpath_expr = php_xsl_xslt_string_to_xpathexpr(Z_STRVAL_PP(value) TSRMLS_CC);
155            } else {
156                xpath_expr = estrndup(Z_STRVAL_PP(value), Z_STRLEN_PP(value));
157            }
158            if (xpath_expr) {
159                params[i++] = string_key;
160                params[i++] = xpath_expr;
161            } else {
162                efree(string_key);
163            }
164        }
165    }
166
167    params[i++] = NULL;
168
169    return params;
170}
171/* }}} */
172
173static void xsl_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int type) /* {{{ */
174{
175    xsltTransformContextPtr tctxt;
176    zval **args;
177    zval *retval;
178    int result, i, ret;
179    int error = 0;
180    zend_fcall_info fci;
181    zval handler;
182    xmlXPathObjectPtr obj;
183    char *str;
184    char *callable = NULL;
185    xsl_object *intern;
186
187    TSRMLS_FETCH();
188
189    if (! zend_is_executing(TSRMLS_C)) {
190        xsltGenericError(xsltGenericErrorContext,
191        "xsltExtFunctionTest: Function called from outside of PHP\n");
192        error = 1;
193    } else {
194        tctxt = xsltXPathGetTransformContext(ctxt);
195        if (tctxt == NULL) {
196            xsltGenericError(xsltGenericErrorContext,
197            "xsltExtFunctionTest: failed to get the transformation context\n");
198            error = 1;
199        } else {
200            intern = (xsl_object *) tctxt->_private;
201            if (intern == NULL) {
202                xsltGenericError(xsltGenericErrorContext,
203                "xsltExtFunctionTest: failed to get the internal object\n");
204                error = 1;
205            }
206            else if (intern->registerPhpFunctions == 0) {
207                xsltGenericError(xsltGenericErrorContext,
208                "xsltExtFunctionTest: PHP Object did not register PHP functions\n");
209                error = 1;
210            }
211        }
212    }
213
214    if (error == 1) {
215        for (i = nargs - 1; i >= 0; i--) {
216            obj = valuePop(ctxt);
217            xmlXPathFreeObject(obj);
218        }
219        return;
220    }
221
222    fci.param_count = nargs - 1;
223    if (fci.param_count > 0) {
224        fci.params = safe_emalloc(fci.param_count, sizeof(zval**), 0);
225        args = safe_emalloc(fci.param_count, sizeof(zval *), 0);
226    }
227    /* Reverse order to pop values off ctxt stack */
228    for (i = nargs - 2; i >= 0; i--) {
229        obj = valuePop(ctxt);
230        MAKE_STD_ZVAL(args[i]);
231        switch (obj->type) {
232            case XPATH_STRING:
233                ZVAL_STRING(args[i],  obj->stringval, 1);
234                break;
235            case XPATH_BOOLEAN:
236                ZVAL_BOOL(args[i],  obj->boolval);
237                break;
238            case XPATH_NUMBER:
239                ZVAL_DOUBLE(args[i], obj->floatval);
240                break;
241            case XPATH_NODESET:
242                if (type == 1) {
243                    str = xmlXPathCastToString(obj);
244                    ZVAL_STRING(args[i], str, 1);
245                    xmlFree(str);
246                } else if (type == 2) {
247                    int j;
248                    dom_object *domintern = (dom_object *)intern->doc;
249                    array_init(args[i]);
250                    if (obj->nodesetval && obj->nodesetval->nodeNr > 0) {
251                        for (j = 0; j < obj->nodesetval->nodeNr; j++) {
252                            xmlNodePtr node = obj->nodesetval->nodeTab[j];
253                            zval *child;
254                            MAKE_STD_ZVAL(child);
255                            /* not sure, if we need this... it's copied from xpath.c */
256                            if (node->type == XML_NAMESPACE_DECL) {
257                                xmlNsPtr curns;
258                                xmlNodePtr nsparent;
259
260                                nsparent = node->_private;
261                                curns = xmlNewNs(NULL, node->name, NULL);
262                                if (node->children) {
263                                    curns->prefix = xmlStrdup((char *) node->children);
264                                }
265                                if (node->children) {
266                                    node = xmlNewDocNode(node->doc, NULL, (char *) node->children, node->name);
267                                } else {
268                                    node = xmlNewDocNode(node->doc, NULL, "xmlns", node->name);
269                                }
270                                node->type = XML_NAMESPACE_DECL;
271                                node->parent = nsparent;
272                                node->ns = curns;
273                            }
274                            child = php_dom_create_object(node, &ret, NULL, child, domintern TSRMLS_CC);
275                            add_next_index_zval(args[i], child);
276                        }
277                    }
278                }
279                break;
280            default:
281                str = xmlXPathCastToString(obj);
282                ZVAL_STRING(args[i], str, 1);
283                xmlFree(str);
284        }
285        xmlXPathFreeObject(obj);
286        fci.params[i] = &args[i];
287    }
288
289    fci.size = sizeof(fci);
290    fci.function_table = EG(function_table);
291
292    obj = valuePop(ctxt);
293    if (obj->stringval == NULL) {
294        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Handler name must be a string");
295        xmlXPathFreeObject(obj);
296        if (fci.param_count > 0) {
297            for (i = 0; i < nargs - 1; i++) {
298                zval_ptr_dtor(&args[i]);
299            }
300            efree(args);
301            efree(fci.params);
302        }
303        return;
304    }
305    INIT_PZVAL(&handler);
306    ZVAL_STRING(&handler, obj->stringval, 1);
307    xmlXPathFreeObject(obj);
308
309    fci.function_name = &handler;
310    fci.symbol_table = NULL;
311    fci.object_ptr = NULL;
312    fci.retval_ptr_ptr = &retval;
313    fci.no_separation = 0;
314    /*fci.function_handler_cache = &function_ptr;*/
315    if (!zend_make_callable(&handler, &callable TSRMLS_CC)) {
316        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to call handler %s()", callable);
317
318    } else if ( intern->registerPhpFunctions == 2 && zend_hash_exists(intern->registered_phpfunctions, callable, strlen(callable) + 1) == 0) {
319        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not allowed to call handler '%s()'", callable);
320        /* Push an empty string, so that we at least have an xslt result... */
321        valuePush(ctxt, xmlXPathNewString(""));
322    } else {
323        result = zend_call_function(&fci, NULL TSRMLS_CC);
324        if (result == FAILURE) {
325            if (Z_TYPE(handler) == IS_STRING) {
326                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to call handler %s()", Z_STRVAL_P(&handler));
327            }
328        /* retval is == NULL, when an exception occured, don't report anything, because PHP itself will handle that */
329        } else if (retval == NULL) {
330        } else {
331            if (retval->type == IS_OBJECT && instanceof_function( Z_OBJCE_P(retval), dom_node_class_entry TSRMLS_CC)) {
332                xmlNode *nodep;
333                dom_object *obj;
334                if (intern->node_list == NULL) {
335                    ALLOC_HASHTABLE(intern->node_list);
336                    zend_hash_init(intern->node_list, 0, NULL, ZVAL_PTR_DTOR, 0);
337                }
338                zval_add_ref(&retval);
339                zend_hash_next_index_insert(intern->node_list, &retval, sizeof(zval *), NULL);
340                obj = (dom_object *)zend_object_store_get_object(retval TSRMLS_CC);
341                nodep = dom_object_get_node(obj);
342                valuePush(ctxt, xmlXPathNewNodeSet(nodep));
343            } else if (retval->type == IS_BOOL) {
344                valuePush(ctxt, xmlXPathNewBoolean(retval->value.lval));
345            } else if (retval->type == IS_OBJECT) {
346                php_error_docref(NULL TSRMLS_CC, E_WARNING, "A PHP Object cannot be converted to a XPath-string");
347                valuePush(ctxt, xmlXPathNewString(""));
348            } else {
349                convert_to_string_ex(&retval);
350                valuePush(ctxt, xmlXPathNewString( Z_STRVAL_P(retval)));
351            }
352            zval_ptr_dtor(&retval);
353        }
354    }
355    efree(callable);
356    zval_dtor(&handler);
357    if (fci.param_count > 0) {
358        for (i = 0; i < nargs - 1; i++) {
359            zval_ptr_dtor(&args[i]);
360        }
361        efree(args);
362        efree(fci.params);
363    }
364}
365/* }}} */
366
367void xsl_ext_function_string_php(xmlXPathParserContextPtr ctxt, int nargs) /* {{{ */
368{
369    xsl_ext_function_php(ctxt, nargs, 1);
370}
371/* }}} */
372
373void xsl_ext_function_object_php(xmlXPathParserContextPtr ctxt, int nargs) /* {{{ */
374{
375    xsl_ext_function_php(ctxt, nargs, 2);
376}
377/* }}} */
378
379/* {{{ proto void xsl_xsltprocessor_import_stylesheet(domdocument doc);
380URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#
381Since:
382*/
383PHP_FUNCTION(xsl_xsltprocessor_import_stylesheet)
384{
385    zval *id, *docp = NULL;
386    xmlDoc *doc = NULL, *newdoc = NULL;
387    xsltStylesheetPtr sheetp, oldsheetp;
388    xsl_object *intern;
389    int prevSubstValue, prevExtDtdValue, clone_docu = 0;
390    xmlNode *nodep = NULL;
391    zend_object_handlers *std_hnd;
392    zval *cloneDocu, *member;
393
394    if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oo", &id, xsl_xsltprocessor_class_entry, &docp) == FAILURE) {
395        RETURN_FALSE;
396    }
397
398    nodep = php_libxml_import_node(docp TSRMLS_CC);
399
400    if (nodep) {
401        doc = nodep->doc;
402    }
403    if (doc == NULL) {
404        php_error(E_WARNING, "Invalid Document");
405        RETURN_FALSE;
406    }
407
408    /* libxslt uses _private, so we must copy the imported
409    stylesheet document otherwise the node proxies will be a mess */
410    newdoc = xmlCopyDoc(doc, 1);
411    xmlNodeSetBase((xmlNodePtr) newdoc, (xmlChar *)doc->URL);
412    prevSubstValue = xmlSubstituteEntitiesDefault(1);
413    prevExtDtdValue = xmlLoadExtDtdDefaultValue;
414    xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
415
416    sheetp = xsltParseStylesheetDoc(newdoc);
417    xmlSubstituteEntitiesDefault(prevSubstValue);
418    xmlLoadExtDtdDefaultValue = prevExtDtdValue;
419
420    if (!sheetp) {
421        xmlFreeDoc(newdoc);
422        RETURN_FALSE;
423    }
424
425    intern = (xsl_object *)zend_object_store_get_object(id TSRMLS_CC);
426
427    std_hnd = zend_get_std_object_handlers();
428    MAKE_STD_ZVAL(member);
429    ZVAL_STRING(member, "cloneDocument", 0);
430    cloneDocu = std_hnd->read_property(id, member, BP_VAR_IS TSRMLS_CC);
431    if (Z_TYPE_P(cloneDocu) != IS_NULL) {
432        convert_to_long(cloneDocu);
433        clone_docu = Z_LVAL_P(cloneDocu);
434    }
435    efree(member);
436    if (clone_docu == 0) {
437        /* check if the stylesheet is using xsl:key, if yes, we have to clone the document _always_ before a transformation */
438        nodep = xmlDocGetRootElement(sheetp->doc);
439        if (nodep && (nodep = nodep->children)) {
440            while (nodep) {
441                if (nodep->type == XML_ELEMENT_NODE && xmlStrEqual(nodep->name, "key") && xmlStrEqual(nodep->ns->href, XSLT_NAMESPACE)) {
442                    intern->hasKeys = 1;
443                    break;
444                }
445                nodep = nodep->next;
446            }
447        }
448    } else {
449        intern->hasKeys = clone_docu;
450    }
451
452    if ((oldsheetp = (xsltStylesheetPtr)intern->ptr)) {
453        /* free wrapper */
454        if (((xsltStylesheetPtr) intern->ptr)->_private != NULL) {
455            ((xsltStylesheetPtr) intern->ptr)->_private = NULL;
456        }
457        xsltFreeStylesheet((xsltStylesheetPtr) intern->ptr);
458        intern->ptr = NULL;
459    }
460
461    php_xsl_set_object(id, sheetp TSRMLS_CC);
462    RETVAL_TRUE;
463}
464/* }}} end xsl_xsltprocessor_import_stylesheet */
465
466static xmlDocPtr php_xsl_apply_stylesheet(zval *id, xsl_object *intern, xsltStylesheetPtr style, zval *docp TSRMLS_DC) /* {{{ */
467{
468    xmlDocPtr newdocp;
469    xmlDocPtr doc = NULL;
470    xmlNodePtr node = NULL;
471    xsltTransformContextPtr ctxt;
472    php_libxml_node_object *object;
473    char **params = NULL;
474    int clone;
475    zval *doXInclude, *member;
476    zend_object_handlers *std_hnd;
477    FILE *f;
478    int secPrefsError = 0;
479    int secPrefsValue;
480    xsltSecurityPrefsPtr secPrefs = NULL;
481
482    node = php_libxml_import_node(docp TSRMLS_CC);
483
484    if (node) {
485        doc = node->doc;
486    }
487    if (doc == NULL) {
488        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Document");
489        return NULL;
490    }
491
492    if (style == NULL) {
493        php_error_docref(NULL TSRMLS_CC, E_WARNING, "No stylesheet associated to this object");
494        return NULL;
495    }
496
497    if (intern->profiling) {
498        if (php_check_open_basedir(intern->profiling TSRMLS_CC)) {
499            f = NULL;
500        } else {
501            f = VCWD_FOPEN(intern->profiling, "w");
502        }
503    } else {
504        f = NULL;
505    }
506
507    if (intern->parameter) {
508        params = php_xsl_xslt_make_params(intern->parameter, 0 TSRMLS_CC);
509    }
510
511    intern->doc = emalloc(sizeof(php_libxml_node_object));
512    memset(intern->doc, 0, sizeof(php_libxml_node_object));
513
514    if (intern->hasKeys == 1) {
515        doc = xmlCopyDoc(doc, 1);
516    } else {
517        object = (php_libxml_node_object *)zend_object_store_get_object(docp TSRMLS_CC);
518        intern->doc->document = object->document;
519    }
520
521    php_libxml_increment_doc_ref(intern->doc, doc TSRMLS_CC);
522
523    ctxt = xsltNewTransformContext(style, doc);
524    ctxt->_private = (void *) intern;
525
526    std_hnd = zend_get_std_object_handlers();
527
528    MAKE_STD_ZVAL(member);
529    ZVAL_STRING(member, "doXInclude", 0);
530    doXInclude = std_hnd->read_property(id, member, BP_VAR_IS TSRMLS_CC);
531    if (Z_TYPE_P(doXInclude) != IS_NULL) {
532        convert_to_long(doXInclude);
533        ctxt->xinclude = Z_LVAL_P(doXInclude);
534    }
535    efree(member);
536
537
538    secPrefsValue = INI_INT("xsl.security_prefs");
539
540    /* if securityPrefs is set to NONE, we don't have to do any checks, but otherwise... */
541    if (secPrefsValue != XSL_SECPREF_NONE) {
542        secPrefs = xsltNewSecurityPrefs();
543        if (secPrefsValue & XSL_SECPREF_READ_FILE ) {
544            if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_READ_FILE, xsltSecurityForbid)) {
545                secPrefsError = 1;
546            }
547        }
548        if (secPrefsValue & XSL_SECPREF_WRITE_FILE ) {
549            if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_WRITE_FILE, xsltSecurityForbid)) {
550                secPrefsError = 1;
551            }
552        }
553        if (secPrefsValue & XSL_SECPREF_CREATE_DIRECTORY ) {
554            if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_CREATE_DIRECTORY, xsltSecurityForbid)) {
555                secPrefsError = 1;
556            }
557        }
558        if (secPrefsValue & XSL_SECPREF_READ_NETWORK) {
559            if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_READ_NETWORK, xsltSecurityForbid)) {
560                secPrefsError = 1;
561            }
562        }
563        if (secPrefsValue & XSL_SECPREF_WRITE_NETWORK) {
564            if (0 != xsltSetSecurityPrefs(secPrefs, XSLT_SECPREF_WRITE_NETWORK, xsltSecurityForbid)) {
565                secPrefsError = 1;
566            }
567        }
568
569        if (0 != xsltSetCtxtSecurityPrefs(secPrefs, ctxt)) {
570            secPrefsError = 1;
571        }
572    }
573
574    if (secPrefsError == 1) {
575        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't set libxslt security properties, not doing transformation for security reasons");
576    } else {
577        newdocp = xsltApplyStylesheetUser(style, doc, (const char**) params,  NULL, f, ctxt);
578    }
579    if (f) {
580        fclose(f);
581    }
582
583    xsltFreeTransformContext(ctxt);
584    if (secPrefs) {
585        xsltFreeSecurityPrefs(secPrefs);
586    }
587
588    if (intern->node_list != NULL) {
589        zend_hash_destroy(intern->node_list);
590        FREE_HASHTABLE(intern->node_list);
591        intern->node_list = NULL;
592    }
593
594    php_libxml_decrement_doc_ref(intern->doc TSRMLS_CC);
595    efree(intern->doc);
596    intern->doc = NULL;
597
598    if (params) {
599        clone = 0;
600        while(params[clone]) {
601            efree(params[clone++]);
602        }
603        efree(params);
604    }
605
606    return newdocp;
607
608}
609/* }}} */
610
611/* {{{ proto domdocument xsl_xsltprocessor_transform_to_doc(domnode doc);
612URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#
613Since:
614*/
615PHP_FUNCTION(xsl_xsltprocessor_transform_to_doc)
616{
617    zval *id, *rv = NULL, *docp = NULL;
618    xmlDoc *newdocp;
619    xsltStylesheetPtr sheetp;
620    int ret, ret_class_len=0;
621    char *ret_class = NULL;
622    xsl_object *intern;
623
624    id = getThis();
625    intern = (xsl_object *)zend_object_store_get_object(id TSRMLS_CC);
626    sheetp = (xsltStylesheetPtr) intern->ptr;
627
628    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o|s!", &docp, &ret_class, &ret_class_len) == FAILURE) {
629        RETURN_FALSE;
630    }
631
632    newdocp = php_xsl_apply_stylesheet(id, intern, sheetp, docp TSRMLS_CC);
633
634    if (newdocp) {
635        if (ret_class) {
636            int found;
637            char *curclass_name;
638            zend_class_entry *curce, **ce;
639            php_libxml_node_object *interndoc;
640
641            curce = Z_OBJCE_P(docp);
642            curclass_name = curce->name;
643            while (curce->parent != NULL) {
644                curce = curce->parent;
645            }
646
647            found = zend_lookup_class(ret_class, ret_class_len, &ce TSRMLS_CC);
648            if ((found != SUCCESS) || !instanceof_function(*ce, curce TSRMLS_CC)) {
649                xmlFreeDoc(newdocp);
650                php_error_docref(NULL TSRMLS_CC, E_WARNING,
651                    "Expecting class compatible with %s, '%s' given", curclass_name, ret_class);
652                RETURN_FALSE;
653            }
654
655            object_init_ex(return_value, *ce);
656
657            interndoc = (php_libxml_node_object *)zend_objects_get_address(return_value TSRMLS_CC);
658            php_libxml_increment_doc_ref(interndoc, newdocp TSRMLS_CC);
659            php_libxml_increment_node_ptr(interndoc, (xmlNodePtr)newdocp, (void *)interndoc TSRMLS_CC);
660        } else {
661            DOM_RET_OBJ(rv, (xmlNodePtr) newdocp, &ret, NULL);
662        }
663    } else {
664        RETURN_FALSE;
665    }
666
667}
668/* }}} end xsl_xsltprocessor_transform_to_doc */
669
670/* {{{ proto int xsl_xsltprocessor_transform_to_uri(domdocument doc, string uri);
671*/
672PHP_FUNCTION(xsl_xsltprocessor_transform_to_uri)
673{
674    zval *id, *docp = NULL;
675    xmlDoc *newdocp;
676    xsltStylesheetPtr sheetp;
677    int ret, uri_len;
678    char *uri;
679    xsl_object *intern;
680
681    id = getThis();
682    intern = (xsl_object *)zend_object_store_get_object(id TSRMLS_CC);
683    sheetp = (xsltStylesheetPtr) intern->ptr;
684
685    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "os", &docp, &uri, &uri_len) == FAILURE) {
686        RETURN_FALSE;
687    }
688
689    newdocp = php_xsl_apply_stylesheet(id, intern, sheetp, docp TSRMLS_CC);
690
691    ret = -1;
692    if (newdocp) {
693        if (strlen(uri) != uri_len) {
694            xmlFreeDoc(newdocp);
695            RETURN_FALSE;
696        }
697        ret = xsltSaveResultToFilename(uri, newdocp, sheetp, 0);
698        xmlFreeDoc(newdocp);
699    }
700
701    RETVAL_LONG(ret);
702}
703/* }}} end xsl_xsltprocessor_transform_to_uri */
704
705/* {{{ proto string xsl_xsltprocessor_transform_to_xml(domdocument doc);
706*/
707PHP_FUNCTION(xsl_xsltprocessor_transform_to_xml)
708{
709    zval *id, *docp = NULL;
710    xmlDoc *newdocp;
711    xsltStylesheetPtr sheetp;
712    int ret;
713    xmlChar *doc_txt_ptr;
714    int doc_txt_len;
715    xsl_object *intern;
716
717    id = getThis();
718    intern = (xsl_object *)zend_object_store_get_object(id TSRMLS_CC);
719    sheetp = (xsltStylesheetPtr) intern->ptr;
720
721    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &docp) == FAILURE) {
722        RETURN_FALSE;
723    }
724
725    newdocp = php_xsl_apply_stylesheet(id, intern, sheetp, docp TSRMLS_CC);
726
727    ret = -1;
728    if (newdocp) {
729        ret = xsltSaveResultToString(&doc_txt_ptr, &doc_txt_len, newdocp, sheetp);
730        if (doc_txt_ptr && doc_txt_len) {
731            RETVAL_STRINGL(doc_txt_ptr, doc_txt_len, 1);
732            xmlFree(doc_txt_ptr);
733        }
734        xmlFreeDoc(newdocp);
735    }
736
737    if (ret < 0) {
738        RETURN_FALSE;
739    }
740}
741/* }}} end xsl_xsltprocessor_transform_to_xml */
742
743/* {{{ proto bool xsl_xsltprocessor_set_parameter(string namespace, mixed name [, string value]);
744*/
745PHP_FUNCTION(xsl_xsltprocessor_set_parameter)
746{
747
748    zval *id;
749    zval *array_value, **entry, *new_string;
750    xsl_object *intern;
751    char *string_key, *name, *value, *namespace;
752    ulong idx;
753    int string_key_len, namespace_len, name_len, value_len;
754    DOM_GET_THIS(id);
755
756    if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "sa", &namespace, &namespace_len, &array_value) == SUCCESS) {
757        intern = (xsl_object *)zend_object_store_get_object(id TSRMLS_CC);
758        zend_hash_internal_pointer_reset(Z_ARRVAL_P(array_value));
759
760        while (zend_hash_get_current_data(Z_ARRVAL_P(array_value), (void **)&entry) == SUCCESS) {
761            SEPARATE_ZVAL(entry);
762            convert_to_string_ex(entry);
763
764            if (zend_hash_get_current_key_ex(Z_ARRVAL_P(array_value), &string_key, &string_key_len, &idx, 0, NULL) != HASH_KEY_IS_STRING) {
765                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid parameter array");
766                RETURN_FALSE;
767            }
768
769            ALLOC_ZVAL(new_string);
770            Z_ADDREF_PP(entry);
771            COPY_PZVAL_TO_ZVAL(*new_string, *entry);
772
773            zend_hash_update(intern->parameter, string_key, string_key_len, &new_string, sizeof(zval*), NULL);
774            zend_hash_move_forward(Z_ARRVAL_P(array_value));
775        }
776        RETURN_TRUE;
777
778    } else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "sss", &namespace, &namespace_len, &name, &name_len, &value, &value_len) == SUCCESS) {
779
780        intern = (xsl_object *)zend_object_store_get_object(id TSRMLS_CC);
781
782        MAKE_STD_ZVAL(new_string);
783        ZVAL_STRING(new_string, value, 1);
784
785        zend_hash_update(intern->parameter, name, name_len + 1, &new_string, sizeof(zval*), NULL);
786        RETURN_TRUE;
787    } else {
788        WRONG_PARAM_COUNT;
789    }
790
791}
792/* }}} end xsl_xsltprocessor_set_parameter */
793
794/* {{{ proto string xsl_xsltprocessor_get_parameter(string namespace, string name);
795*/
796PHP_FUNCTION(xsl_xsltprocessor_get_parameter)
797{
798    zval *id;
799    int name_len = 0, namespace_len = 0;
800    char *name, *namespace;
801    zval **value;
802    xsl_object *intern;
803
804    DOM_GET_THIS(id);
805
806    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &namespace, &namespace_len, &name, &name_len) == FAILURE) {
807        RETURN_FALSE;
808    }
809    intern = (xsl_object *)zend_object_store_get_object(id TSRMLS_CC);
810    if ( zend_hash_find(intern->parameter, name, name_len + 1,  (void**) &value) == SUCCESS) {
811        convert_to_string_ex(value);
812        RETVAL_STRING(Z_STRVAL_PP(value),1);
813    } else {
814        RETURN_FALSE;
815    }
816}
817/* }}} end xsl_xsltprocessor_get_parameter */
818
819/* {{{ proto bool xsl_xsltprocessor_remove_parameter(string namespace, string name);
820*/
821PHP_FUNCTION(xsl_xsltprocessor_remove_parameter)
822{
823    zval *id;
824    int name_len = 0, namespace_len = 0;
825    char *name, *namespace;
826    xsl_object *intern;
827
828    DOM_GET_THIS(id);
829
830    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &namespace, &namespace_len, &name, &name_len) == FAILURE) {
831        RETURN_FALSE;
832    }
833    intern = (xsl_object *)zend_object_store_get_object(id TSRMLS_CC);
834    if ( zend_hash_del(intern->parameter, name, name_len + 1) == SUCCESS) {
835        RETURN_TRUE;
836    } else {
837        RETURN_FALSE;
838    }
839}
840/* }}} end xsl_xsltprocessor_remove_parameter */
841
842/* {{{ proto void xsl_xsltprocessor_register_php_functions([mixed $restrict]);
843*/
844PHP_FUNCTION(xsl_xsltprocessor_register_php_functions)
845{
846    zval *id;
847    xsl_object *intern;
848    zval *array_value, **entry, *new_string;
849    int  name_len = 0;
850    char *name;
851
852    DOM_GET_THIS(id);
853
854    if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "a",  &array_value) == SUCCESS) {
855        intern = (xsl_object *)zend_object_store_get_object(id TSRMLS_CC);
856        zend_hash_internal_pointer_reset(Z_ARRVAL_P(array_value));
857
858        while (zend_hash_get_current_data(Z_ARRVAL_P(array_value), (void **)&entry) == SUCCESS) {
859            SEPARATE_ZVAL(entry);
860            convert_to_string_ex(entry);
861
862            MAKE_STD_ZVAL(new_string);
863            ZVAL_LONG(new_string,1);
864
865            zend_hash_update(intern->registered_phpfunctions, Z_STRVAL_PP(entry), Z_STRLEN_PP(entry) + 1, &new_string, sizeof(zval*), NULL);
866            zend_hash_move_forward(Z_ARRVAL_P(array_value));
867        }
868        intern->registerPhpFunctions = 2;
869
870    } else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s",  &name, &name_len) == SUCCESS) {
871        intern = (xsl_object *)zend_object_store_get_object(id TSRMLS_CC);
872
873        MAKE_STD_ZVAL(new_string);
874        ZVAL_LONG(new_string,1);
875        zend_hash_update(intern->registered_phpfunctions, name, name_len + 1, &new_string, sizeof(zval*), NULL);
876        intern->registerPhpFunctions = 2;
877
878    } else {
879        intern = (xsl_object *)zend_object_store_get_object(id TSRMLS_CC);
880        intern->registerPhpFunctions = 1;
881    }
882
883}
884/* }}} end xsl_xsltprocessor_register_php_functions(); */
885
886/* {{{ proto bool xsl_xsltprocessor_set_profiling(string filename) */
887PHP_FUNCTION(xsl_xsltprocessor_set_profiling)
888{
889    zval *id;
890    xsl_object *intern;
891    char *filename = NULL;
892    int filename_len;
893    DOM_GET_THIS(id);
894
895    if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s!", &filename, &filename_len) == SUCCESS) {
896        intern = (xsl_object *)zend_object_store_get_object(id TSRMLS_CC);
897        if (intern->profiling) {
898            efree(intern->profiling);
899        }
900        if (filename != NULL && strlen(filename) == filename_len) {
901            intern->profiling = estrndup(filename,filename_len);
902        } else {
903            intern->profiling = NULL;
904        }
905        RETURN_TRUE;
906    } else {
907        WRONG_PARAM_COUNT;
908    }
909}
910/* }}} end xsl_xsltprocessor_set_profiling */
911
912/* {{{ proto bool xsl_xsltprocessor_has_exslt_support();
913*/
914PHP_FUNCTION(xsl_xsltprocessor_has_exslt_support)
915{
916#if HAVE_XSL_EXSLT
917    RETURN_TRUE;
918#else
919    RETURN_FALSE;
920#endif
921}
922/* }}} end xsl_xsltprocessor_has_exslt_support(); */
923
924/*
925 * Local variables:
926 * tab-width: 4
927 * c-basic-offset: 4
928 * End:
929 * vim600: sw=4 ts=4 fdm=marker
930 * vim<600: sw=4 ts=4
931 */
932