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