root/trunk/fastxsl.c

Revision 10, 30.8 kB (checked in by rasmus, 10 years ago)

As far as I can tell, that line of code doesn't belong there.

Line 
1 /*
2   +----------------------------------------------------------------------+
3   | PHP Version 4                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2003 The PHP Group                                |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 2.02 of the PHP license,      |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available at through the world-wide-web at                           |
10   | http://www.php.net/license/2_02.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   | Author: Sterling Hughes <sterling@php.net>                           |
16   |         George Schlossnagle <george@omniti.com>                      |
17   +----------------------------------------------------------------------+
18
19   $Id: fastxsl.c,v 1.1.1.1 2004/02/17 23:31:44 sterling Exp $
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <libxml/xmlmemory.h>
27 #include <libxml/debugXML.h>
28 #include <libxml/HTMLtree.h>
29 #include <libxml/xmlIO.h>
30 #include <libxml/xinclude.h>
31 #include <libxml/catalog.h>
32 #include <libxml/xpathInternals.h>
33 #include <libxml/xpath.h>
34 #include <libxslt/xslt.h>
35 #include <libxslt/xsltInternals.h>
36 #include <libxslt/transform.h>
37 #include <libxslt/xsltutils.h>
38
39 #ifdef FASTXSL_MM
40 #include <mm.h>
41 #endif
42 #include <sys/types.h>
43 #include <unistd.h>
44
45 #include "fl_hash.h"
46 #include "php.h"
47 #include "php_ini.h"
48 #include "ext/standard/info.h"
49 #include "php_fastxsl.h"
50
51 ZEND_DECLARE_MODULE_GLOBALS(fastxsl);
52
53 static int le_fastxsl_stylesheet;
54 #define le_fastxsl_stylesheet_name "FastXSL Stylesheet"
55 static int le_fastxsl_document;
56 #define le_fastxsl_document_name "FastXSL Document"
57
58 #define FASTXSL_PRM_ALLOC 1
59 #define FASTXSL_SHARED_ALLOC 2
60
61 void fastxsl_errorfunc(void *ctx, const char *msg, ...);
62
63 static php_ss_wrapper *
64 SS_Wrapper_Alloc(int shared TSRMLS_DC)
65 {
66         php_ss_wrapper *wrapper;
67
68         if (shared) {
69 #ifdef FASTXSL_MM
70                 if (shared == FASTXSL_SHARED_ALLOC) {
71                         wrapper = (php_ss_wrapper *) mm_calloc(FASTXSL_G(cache)->mm, 1, sizeof(php_ss_wrapper));
72                 } else {
73                         wrapper = (php_ss_wrapper *) calloc(1, sizeof(php_ss_wrapper));
74                 }
75                 wrapper->persistant = 1;
76 #else
77         wrapper = (php_ss_wrapper *) calloc(1, sizeof(php_ss_wrapper));
78         wrapper->persistant = 1;
79 #endif
80         } else {
81                 wrapper = (php_ss_wrapper *) calloc(1, sizeof(php_ss_wrapper));
82         }
83
84         return wrapper;
85 }
86
87 static php_xd_wrapper *
88 XD_Wrapper_Alloc(void)
89 {
90         php_xd_wrapper *wrapper;
91
92         wrapper = (php_xd_wrapper *) calloc(1, sizeof(php_xd_wrapper));
93         return wrapper;
94 }
95
96 static xmlFreeFunc    free_ptr;
97 static xmlMallocFunc  malloc_ptr;
98 static xmlReallocFunc realloc_ptr;
99 static xmlStrdupFunc  strdup_ptr;
100
101 #ifdef FASTXSL_MM
102 static void
103 ShmCache_Free(void *ptr)
104 {
105         TSRMLS_FETCH();
106         FASTXSL_G(tmp_allocated_size) -= mm_sizeof(FASTXSL_G(cache)->mm, ptr);
107        
108         mm_free(FASTXSL_G(cache)->mm, ptr);
109 }
110
111 static void *
112 ShmCache_Malloc(size_t size)
113 {
114         void *ptr;
115         TSRMLS_FETCH();
116
117         ptr = mm_malloc(FASTXSL_G(cache)->mm, size);
118         if (!ptr) {
119                 php_error(E_ERROR, "Ran out of Shared memory to allocate data for FastXSL cache, "
120                                            "in function %s() cannot allocate %d bytes (%d available, %d allocated)",
121                                                    get_active_function_name(TSRMLS_C), size, mm_available(FASTXSL_G(cache)->mm),
122                                                    mm_maxsize() - mm_available(FASTXSL_G(cache)->mm));
123                 return NULL;
124         }
125
126         FASTXSL_G(tmp_allocated_size) += size;
127
128         return ptr;
129 }
130
131 static void *
132 ShmCache_Calloc(size_t nmemb, size_t size)
133 {
134         void *ptr;
135
136         ptr = ShmCache_Malloc(nmemb * size);
137         memset(ptr, 0, nmemb * size);
138
139         return ptr;
140 }
141
142 static void *
143 ShmCache_Realloc(void *ptr, size_t size)
144 {
145         void *newptr;
146         long  oldsize;
147         TSRMLS_FETCH();
148
149         oldsize = mm_sizeof(FASTXSL_G(cache)->mm, ptr);
150         newptr = mm_realloc(FASTXSL_G(cache)->mm, ptr, size);
151         if (!newptr) {
152                 TSRMLS_FETCH();
153                 php_error(E_ERROR, "Ran out of Shared memory to allocate data for FastXSL cache, "
154                                            "in function %s() cannot allocate %d bytes (%d available, %d allocated)",
155                                                    get_active_function_name(TSRMLS_C), size, mm_available(FASTXSL_G(cache)->mm),
156                                                    mm_maxsize() - mm_available(FASTXSL_G(cache)->mm));
157                 return NULL;
158         }
159         FASTXSL_G(tmp_allocated_size) += (size - oldsize);
160
161         return newptr;
162 }
163
164 static char *
165 ShmCache_Strdup(const char *string)
166 {
167         char *newstring;
168         int   string_length;
169
170         string_length = strlen(string);
171         newstring = ShmCache_Malloc(string_length);
172         memcpy(newstring, string, string_length);
173         newstring[string_length] = 0;
174
175         return newstring;
176 }
177 #endif
178
179 static void
180 Php_Free(void *ptr)
181 {
182         efree(ptr);
183 }
184
185 static void *
186 Php_Malloc(size_t size)
187 {
188         return emalloc(size);
189 }
190
191 static void *
192 Php_Realloc(void *ptr, size_t size)
193 {
194         return erealloc(ptr, size);
195 }
196
197 static char *
198 Php_Strdup(const char *string)
199 {
200         return estrdup(string);
201 }
202
203 #ifdef FASTXSL_MM
204 static void
205 ShmCache_UseAllocationFunctions(void)
206 {
207         xmlMemSetup(ShmCache_Free, ShmCache_Malloc, ShmCache_Realloc, ShmCache_Strdup);
208 }
209 #endif
210
211 static void
212 Php_UseAllocationFunctions(void)
213 {
214         xmlMemSetup(Php_Free, Php_Malloc, Php_Realloc, Php_Strdup);
215 }
216
217 static void
218 Xml_UseAllocationFunctions(void)
219 {
220         xmlMemSetup(free_ptr, malloc_ptr, realloc_ptr, strdup_ptr);
221 }
222
223 #ifdef FASTXSL_MM
224 static php_ss_wrapper *
225 ShmCache_Stylesheet_ParseAndStore(char *filename, size_t filename_len, int mtime TSRMLS_DC)
226 {
227         php_ss_wrapper *wrapper;
228        
229         wrapper = SS_Wrapper_Alloc(FASTXSL_SHARED_ALLOC TSRMLS_CC);
230
231         ShmCache_UseAllocationFunctions();
232         FASTXSL_G(tmp_allocated_size) = 0;
233         wrapper->ss = xsltParseStylesheetFile(filename);
234         if (!wrapper->ss) {
235                 Xml_UseAllocationFunctions();
236                 return NULL;
237         }
238         Xml_UseAllocationFunctions();
239         wrapper->mtime = mtime;
240         wrapper->allocsize = FASTXSL_G(tmp_allocated_size);
241        
242         fl_hash_add(FASTXSL_G(cache)->table, filename, filename_len, wrapper);
243
244         return wrapper;
245 }
246
247 static void
248 ShmCache_Stylesheet_Free(php_ss_wrapper *wrapper TSRMLS_DC)
249 {
250         if (wrapper->ss) {
251                 ShmCache_UseAllocationFunctions();
252                 xsltFreeStylesheet(wrapper->ss);
253                 Xml_UseAllocationFunctions();
254         }
255         mm_free(FASTXSL_G(cache)->mm, wrapper);
256 }
257
258 static void
259 ShmCache_Stylesheet_Delete(char *filename, size_t filename_len)
260 {
261         php_ss_wrapper *wrapper;
262
263         wrapper = fl_hash_find(FASTXSL_G(cache)->table, filename, filename_len);
264         if (wrapper) {
265                 fl_hash_delete(FASTXSL_G(cache)->table, filename, filename_len);
266                 ShmCache_Stylesheet_Free(wrapper);
267         }
268 }
269 #endif
270
271 static php_ss_wrapper *
272 PrmCache_Stylesheet_ParseAndStore(char *filename, size_t filename_len, int mtime)
273 {
274         php_ss_wrapper *wrapper;
275
276         wrapper = (php_ss_wrapper *) SS_Wrapper_Alloc(FASTXSL_PRM_ALLOC TSRMLS_CC);
277
278         wrapper->ss = xsltParseStylesheetFile(filename);
279         if (!wrapper->ss) {
280                 return NULL;
281         }
282         wrapper->mtime = mtime;
283        
284         fl_hash_add(FASTXSL_G(cache)->prmtable, filename, filename_len, wrapper);
285
286         return wrapper;
287 }
288
289 static void
290 PrmCache_Stylesheet_Free(php_ss_wrapper *wrapper)
291 {
292         if (wrapper->ss) {
293                 xsltFreeStylesheet(wrapper->ss);
294         }
295         free(wrapper);
296 }
297
298 static void
299 PrmCache_Stylesheet_Delete(char *filename, size_t filename_len TSRMLS_DC)
300 {
301         php_ss_wrapper *wrapper;
302
303         wrapper = fl_hash_find(FASTXSL_G(cache)->prmtable, filename, filename_len);
304         if (wrapper) {
305                 fl_hash_delete(FASTXSL_G(cache)->prmtable, filename, filename_len);
306                 PrmCache_Stylesheet_Free(wrapper TSRMLS_CC);
307         }
308 }
309
310 /* {{{ proto array fastxsl_prmcache_getstatistics(void)
311    Get an array of statistics regarding the fastxsl documents in the process resident memory cache */
312 PHP_FUNCTION(fastxsl_prmcache_getstatistics)
313 {
314         php_ss_wrapper *wrapper;       
315
316         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
317                 return;
318         }
319
320 }
321 /* }}} */
322
323 /* {{{ proto array fastxsl_shmcache_getstatistics(void)
324    Get an array of statistics regarding the documents in the shared memory cache */
325 #ifdef FASTXSL_MM
326 PHP_FUNCTION(fastxsl_shmcache_getstatistics)
327 {
328         php_ss_wrapper *ss_wrapper;
329         FL_Bucket      *bucket;
330         zval           *files_array;
331         zval           *info_array;
332         int             i;
333         long            allocated_bytes = 0;
334        
335         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
336                 return;
337         }
338
339         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
340        
341         array_init(return_value);
342
343         MAKE_STD_ZVAL(files_array);
344         array_init(files_array);
345
346         for (i = 0; i < FL_HASH_SIZE; i++) {
347                 for (bucket = FASTXSL_G(cache)->table->buckets[i]; bucket != NULL; bucket = bucket->next) {
348                         ss_wrapper = (php_ss_wrapper *) bucket->data;
349
350                         MAKE_STD_ZVAL(info_array);
351                         array_init(info_array);
352
353                         add_assoc_long(info_array, "allocated", ss_wrapper->allocsize);
354                         add_assoc_long(info_array, "mtime", ss_wrapper->mtime);
355
356                         add_assoc_zval(files_array, bucket->key, info_array);
357
358                         allocated_bytes += ss_wrapper->allocsize;
359                 }
360         }
361         add_assoc_zval(return_value, "files", files_array);
362
363         add_assoc_long(return_value, "shm_allocated", allocated_bytes);
364         add_assoc_long(return_value, "shm_maxsize", (long) mm_maxsize());
365
366         mm_unlock(FASTXSL_G(cache)->mm);
367 }
368 #endif
369 /* }}} */
370
371 /* {{{ proto resource fastxsl_stylesheet_parsefile(string filename)
372    Parse a stylesheet file located at filename. */
373 PHP_FUNCTION(fastxsl_stylesheet_parsefile)
374 {
375         php_ss_wrapper *wrapper;
376         char           *filename;
377         size_t          filename_len;
378
379         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename,
380                                 &filename_len) == FAILURE) {
381                 return;
382         }
383
384         wrapper = (php_ss_wrapper *) SS_Wrapper_Alloc(0 TSRMLS_CC);
385         wrapper->ss = xsltParseStylesheetFile(filename);
386         if (!wrapper->ss) {
387                 RETURN_FALSE;
388         }
389
390         ZEND_REGISTER_RESOURCE(return_value, wrapper, le_fastxsl_stylesheet);
391 }
392 /* }}} */
393
394 /* {{{ proto resource fastxsl_xml_parsestring(string text)
395   Parse a string containing an XML document and return a resource pointer to the resulting libxml2 tree */
396 PHP_FUNCTION(fastxsl_xml_parsestring)
397 {
398         php_xd_wrapper *wrapper;
399         char           *text;
400         size_t          text_len;
401
402         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &text, &text_len) == FAILURE) {
403                 return;
404         }
405
406         wrapper = XD_Wrapper_Alloc();
407         wrapper->xd = xmlParseDoc(text);
408         if (!wrapper->xd) {
409                 RETURN_FALSE;
410         }
411
412         ZEND_REGISTER_RESOURCE(return_value, wrapper, le_fastxsl_document);
413 }
414 /* }}} */
415
416 /* {{{ proto resource fastxsl_xml_parsefile(string filename)
417    Parse an XML file into a FastXSL resource */
418 PHP_FUNCTION(fastxsl_xml_parsefile)
419 {
420         php_xd_wrapper *wrapper;
421         char           *filename;
422         size_t          filename_len;
423
424         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename,
425                                 &filename_len) == FAILURE) {
426                 return;
427         }
428
429         wrapper = XD_Wrapper_Alloc();
430         wrapper->xd = xmlParseFile((const xmlChar *) filename);
431         if (!wrapper->xd) {
432                 RETURN_FALSE;
433         }
434
435         ZEND_REGISTER_RESOURCE(return_value, wrapper, le_fastxsl_document);
436 }
437 /* }}} */
438
439 static int
440 ParseTransformParameters(zval *z_parameters, char ***parameters TSRMLS_DC)
441 {
442         zval         **current;
443         HashTable     *h_parameters;
444         HashPosition   pos;
445         char          *key;
446         int            key_length;
447         unsigned long  ival;
448         int            index = 0;
449
450         h_parameters = Z_ARRVAL_P(z_parameters);
451
452         if (zend_hash_num_elements(h_parameters) == 0) {
453                 *parameters = NULL;
454                 return SUCCESS;
455         }
456        
457         *parameters = calloc(1, (zend_hash_num_elements(h_parameters) * (2 * sizeof(char *))) + 1);
458         if (!*parameters) {
459                 php_error(E_WARNING, "Cannot allocate parameters array to pass to FastXSL");
460                 return FAILURE;
461         }
462        
463         for (zend_hash_internal_pointer_reset_ex(h_parameters, &pos);
464              zend_hash_get_current_data_ex(h_parameters, (void **) &current, &pos) == SUCCESS;
465                  zend_hash_move_forward_ex(h_parameters, &pos)) {
466                 if (zend_hash_get_current_key_ex(h_parameters, &key, &key_length,
467                                         &ival, 0, &pos) == HASH_KEY_IS_LONG) {
468                         efree(*parameters);
469                         *parameters = NULL;
470
471                         php_error(E_WARNING,
472                                         "Parameters array passed to %s() may not contain numeric keys",
473                                         get_active_function_name(TSRMLS_C));
474                         return FAILURE;
475                 }
476
477                 convert_to_string_ex(current);
478
479                 (*parameters)[index++] = key;
480                 (*parameters)[index++] = Z_STRVAL_PP(current);
481         }
482         (*parameters)[index] = NULL;
483
484         return SUCCESS;
485 }
486
487 /* {{{ proto resource fastxsl_shmcache_transform(string filename, resource xmldoc[, array parameters])
488    Transform a XML document, "xmldoc", by a XSL stylesheet "filename" with transform "parameters." */
489 #ifdef FASTXSL_MM
490 PHP_FUNCTION(fastxsl_shmcache_transform)
491 {
492         char            **parameters = NULL;
493         php_xd_wrapper   *xd_wrapper;
494         php_xd_wrapper   *result_wrapper;
495         php_ss_wrapper   *ss_wrapper;
496         char             *ss_filename;
497         size_t            ss_filename_len;
498         zval             *z_xd_wrapper;
499         zval             *z_parameters;
500         struct stat       sb;
501        
502         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|z", &ss_filename, &ss_filename_len,
503                                 &z_xd_wrapper, &z_parameters) == FAILURE) {
504                 return;
505         }
506        
507         ZEND_FETCH_RESOURCE(xd_wrapper, php_xd_wrapper *, &z_xd_wrapper, -1, "FastXSL XML Document",
508                         le_fastxsl_document);
509
510         if (ZEND_NUM_ARGS() > 2 && Z_TYPE_P(z_parameters) == IS_ARRAY) {
511                 if (ParseTransformParameters(z_parameters, &parameters TSRMLS_CC) == FAILURE) {
512                         RETURN_FALSE;
513                 }
514         }
515
516         result_wrapper = XD_Wrapper_Alloc();
517
518         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RW);
519         if (!FASTXSL_G(nostat)) {
520                 if (stat(ss_filename, &sb) == -1) {
521                         ShmCache_Stylesheet_Delete(ss_filename, ss_filename_len TSRMLS_CC);
522                         mm_unlock(FASTXSL_G(cache)->mm);
523                         free(parameters);
524                         RETURN_FALSE;
525                 }
526         } else {
527                 sb.st_mtime = 0;
528         }
529        
530         ss_wrapper = fl_hash_find(FASTXSL_G(cache)->table, ss_filename, ss_filename_len);
531         if (!ss_wrapper) {
532                 ss_wrapper = ShmCache_Stylesheet_ParseAndStore(ss_filename, ss_filename_len, sb.st_mtime);
533                 if (!ss_wrapper) {
534                         mm_unlock(FASTXSL_G(cache)->mm);
535                         free(parameters);
536                         RETURN_FALSE;
537                 }
538         } else {
539                 if (!FASTXSL_G(nostat)) {
540                         if (ss_wrapper->mtime != sb.st_mtime) {
541                                 ShmCache_Stylesheet_Delete(ss_filename, ss_filename_len TSRMLS_CC);
542                                 ss_wrapper = ShmCache_Stylesheet_ParseAndStore(ss_filename, ss_filename_len, sb.st_mtime TSRMLS_CC);
543                                 if (!ss_wrapper) {
544                                         mm_unlock(FASTXSL_G(cache)->mm);
545                                         free(parameters);
546                                         RETURN_FALSE;
547                                 }
548                         }
549                 }
550         }
551
552         result_wrapper->xd = xsltApplyStylesheet(ss_wrapper->ss, xd_wrapper->xd,
553                         (const char **) parameters);
554
555         mm_unlock(FASTXSL_G(cache)->mm);
556        
557         if (parameters)
558                 free(parameters);
559        
560         if (!result_wrapper->xd) {
561                 RETURN_FALSE;
562         }       
563        
564         ZEND_REGISTER_RESOURCE(return_value, result_wrapper, le_fastxsl_document);
565 }
566 #endif
567 /* }}} */
568
569 /* {{{ proto resource fastxsl_prmcache_transform(string filename, resource xmldoc[, array parameters])
570    Transform a XML document, "xmldoc", by a XSL stylesheet "filename" with transform "parameters." */
571 PHP_FUNCTION(fastxsl_prmcache_transform)
572 {
573         char            **parameters = NULL;
574         php_xd_wrapper   *xd_wrapper;
575         php_xd_wrapper   *result_wrapper;
576         php_ss_wrapper   *ss_wrapper;
577         char             *ss_filename;
578         size_t            ss_filename_len;
579         zval             *z_xd_wrapper;
580         zval             *z_parameters;
581         struct stat       sb;
582        
583         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|z", &ss_filename, &ss_filename_len,
584                                 &z_xd_wrapper, &z_parameters) == FAILURE) {
585                 return;
586         }
587         ZEND_FETCH_RESOURCE(xd_wrapper, php_xd_wrapper *, &z_xd_wrapper, -1, "FastXSL XML Document",
588                         le_fastxsl_document);
589
590         if (ZEND_NUM_ARGS() > 2 && Z_TYPE_P(z_parameters) == IS_ARRAY) {
591                 if (ParseTransformParameters(z_parameters, &parameters TSRMLS_CC) == FAILURE) {
592                         RETURN_FALSE;
593                 }
594         }
595
596         result_wrapper = XD_Wrapper_Alloc();
597
598         if (!FASTXSL_G(nostat)) {
599                 if (stat(ss_filename, &sb) == -1) {
600                         PrmCache_Stylesheet_Delete(ss_filename, ss_filename_len TSRMLS_CC);
601                         free(parameters);
602                         RETURN_FALSE;
603                 }
604         } else {
605                 sb.st_mtime = 0;
606         }
607        
608         ss_wrapper = fl_hash_find(FASTXSL_G(cache)->prmtable, ss_filename, ss_filename_len);
609         if (!ss_wrapper) {
610                 ss_wrapper = PrmCache_Stylesheet_ParseAndStore(ss_filename, ss_filename_len, sb.st_mtime TSRMLS_CC);
611                 if (!ss_wrapper) {
612                         free(parameters);
613                         RETURN_FALSE;
614                 }
615         } else {
616                 if (!FASTXSL_G(nostat)) {
617                         if (ss_wrapper->mtime != sb.st_mtime) {
618                                 PrmCache_Stylesheet_Delete(ss_filename, ss_filename_len TSRMLS_CC);
619                                 ss_wrapper = PrmCache_Stylesheet_ParseAndStore(ss_filename, ss_filename_len, sb.st_mtime TSRMLS_CC);
620                                 if (!ss_wrapper) {
621                                         free(parameters);
622                                         RETURN_FALSE;
623                                 }
624                         }
625                 }
626         }
627
628         result_wrapper->xd = xsltApplyStylesheet(ss_wrapper->ss, xd_wrapper->xd,
629                         (const char **) parameters);
630
631         if (parameters)
632                 free(parameters);
633        
634         if (!result_wrapper->xd) {
635                 RETURN_FALSE;
636         }       
637        
638         ZEND_REGISTER_RESOURCE(return_value, result_wrapper, le_fastxsl_document);
639 }
640
641 /* {{{ proto void fastxsl_nocache_transform(resource stylesheet, resource xmldoc[, array parameters])
642    Transform the stylesheet document by the xml document with parameters. */
643 PHP_FUNCTION(fastxsl_nocache_transform)
644 {
645         char           **parameters = NULL;
646         php_xd_wrapper  *xd_wrapper;
647         php_xd_wrapper  *result_wrapper;
648         php_ss_wrapper  *ss_wrapper;
649         zval            *z_xd_wrapper;
650         zval            *z_ss_wrapper;
651         zval            *z_parameters;
652
653         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|z", &z_ss_wrapper,
654                                 &z_xd_wrapper, &z_parameters) == FAILURE) {
655                 return;
656         }
657         ZEND_FETCH_RESOURCE(ss_wrapper, php_ss_wrapper *, &z_ss_wrapper, -1, "FastXSL Stylesheet",
658                         le_fastxsl_stylesheet);
659         ZEND_FETCH_RESOURCE(xd_wrapper, php_xd_wrapper *, &z_xd_wrapper, -1, "FastXSL XML Document",
660                         le_fastxsl_document);
661
662         if (ZEND_NUM_ARGS() > 2 && Z_TYPE_P(z_parameters) == IS_ARRAY) {
663                 if (ParseTransformParameters(z_parameters, &parameters TSRMLS_CC) == FAILURE) {
664                         RETURN_FALSE;
665                 }
666         }
667
668         result_wrapper = XD_Wrapper_Alloc();
669        
670         result_wrapper->xd = xsltApplyStylesheet(ss_wrapper->ss, xd_wrapper->xd,
671                         (const char **) parameters);
672         if (parameters)
673                 free(parameters);
674
675         if (!result_wrapper->xd) {
676                 RETURN_FALSE;
677         }       
678
679        
680         ZEND_REGISTER_RESOURCE(return_value, result_wrapper, le_fastxsl_document);
681 }
682 /* }}} */
683
684 /* {{{ proto void fastxsl_nocache_profile(resource stylesheet, resource xmldoc[, array parameters, string filename])
685    Profile the stylesheet document by the xml document with parameters and output the results to filename (or stderr, if filename doesn't exist). */
686 PHP_FUNCTION(fastxsl_nocache_profile)
687 {
688         char           **parameters = NULL;
689         char            *filename = "php://stderr";
690         php_xd_wrapper  *xd_wrapper;
691         php_xd_wrapper  *result_wrapper;
692         php_ss_wrapper  *ss_wrapper;
693         zval            *z_xd_wrapper;
694         zval            *z_ss_wrapper;
695         zval            *z_parameters;
696         FILE            *dbgprof;
697         int              filename_len;
698
699         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|zs", &z_ss_wrapper,
700                                 &z_xd_wrapper, &z_parameters, &filename, &filename_len) == FAILURE) {
701                 return;
702         }
703         ZEND_FETCH_RESOURCE(ss_wrapper, php_ss_wrapper *, &z_ss_wrapper, -1, "FastXSL Stylesheet",
704                         le_fastxsl_stylesheet);
705         ZEND_FETCH_RESOURCE(xd_wrapper, php_xd_wrapper *, &z_xd_wrapper, -1, "FastXSL XML Document",
706                         le_fastxsl_document);
707
708         if (ZEND_NUM_ARGS() > 2 && Z_TYPE_P(z_parameters) == IS_ARRAY) {
709                 if (ParseTransformParameters(z_parameters, &parameters TSRMLS_CC) == FAILURE) {
710                         RETURN_FALSE;
711                 }
712         }
713
714         if (!strcmp(filename, "php://stdout")) {
715                 dbgprof = stdout;
716         } else if (!strcmp(filename, "php://stderr")) {
717                 dbgprof = stderr;
718         } else {
719                 dbgprof = fopen(filename, "w");
720         }
721
722         result_wrapper = XD_Wrapper_Alloc();
723
724         result_wrapper->xd = xsltProfileStylesheet(ss_wrapper->ss, xd_wrapper->xd,
725                         (const char **) parameters, dbgprof);
726        
727         if (parameters)
728                 free(parameters);
729
730         fclose(dbgprof);
731        
732         if (!result_wrapper->xd) {
733                 RETURN_FALSE;
734         }       
735        
736         ZEND_REGISTER_RESOURCE(return_value, result_wrapper, le_fastxsl_document);
737 }
738 /* }}} */
739
740 /* {{{ proto string fastxsl_nocache_tostring(resource stylesheet, resource xmldoc)
741    Return the contents of an XML stylesheet result as a string */
742 PHP_FUNCTION(fastxsl_nocache_tostring)
743 {
744         zval           *z_xd_wrapper;
745         zval           *z_ss_wrapper;
746         php_ss_wrapper *ss_wrapper;
747         php_xd_wrapper *xd_wrapper;
748         xmlChar        *result = NULL;
749         int             length;
750
751         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &z_ss_wrapper,
752                                 &z_xd_wrapper) == FAILURE) {
753                 return;
754         }
755         ZEND_FETCH_RESOURCE(ss_wrapper, php_ss_wrapper *, &z_ss_wrapper, -1, "FastXSL XML Stylesheet",
756                         le_fastxsl_stylesheet);
757         ZEND_FETCH_RESOURCE(xd_wrapper, php_xd_wrapper *, &z_xd_wrapper, -1, "FastXSL XML Document",
758                         le_fastxsl_document);
759
760         xsltSaveResultToString(&result, &length, xd_wrapper->xd, ss_wrapper->ss);
761
762         if (result) {
763                 RETVAL_STRINGL((char *) result, length, 1);
764                 xmlFree(result);
765         } else {
766                 RETURN_FALSE;
767         }
768 }
769 /* }}} */
770
771 /* {{{ proto string fastxsl_shmcache_tostring(string filename, resource xmldoc)
772    Return the string representation of xmldoc which is the result of an XSLT transformation on filename */
773 #ifdef FASTXSL_MM
774 PHP_FUNCTION(fastxsl_shmcache_tostring)
775 {
776         zval           *z_xd_wrapper;
777         php_ss_wrapper *ss_wrapper;
778         php_xd_wrapper *xd_wrapper;
779         xmlChar        *result = NULL;
780         char           *ss_filename;
781         size_t          ss_filename_len;
782         int             length;
783
784         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &ss_filename, &ss_filename_len,
785                                 &z_xd_wrapper) == FAILURE) {
786                 return;
787         }
788         ZEND_FETCH_RESOURCE(xd_wrapper, php_xd_wrapper *, &z_xd_wrapper, -1, "FastXSL XML Document",
789                         le_fastxsl_document);
790
791         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
792         ss_wrapper = fl_hash_find(FASTXSL_G(cache)->table, ss_filename, ss_filename_len);
793         if (!ss_wrapper) {
794                 mm_unlock(FASTXSL_G(cache)->mm);
795                 RETURN_FALSE;
796         }
797         xsltSaveResultToString(&result, &length, xd_wrapper->xd, ss_wrapper->ss);
798         mm_unlock(FASTXSL_G(cache)->mm);
799         if (result) {
800                 RETVAL_STRINGL((char *) result, length, 1);
801                 xmlFree(result);
802         } else {
803                 RETURN_FALSE;
804         }
805 }
806 #endif
807 /* }}} */
808
809 /* {{{ proto string fastxsl_prmcache_tostring(string filename, resource xmldoc)
810    Return the string representation of xmldoc which is the result of an XSLT transformation on filename */
811 PHP_FUNCTION(fastxsl_prmcache_tostring)
812 {
813         zval           *z_xd_wrapper;
814         php_ss_wrapper *ss_wrapper;
815         php_xd_wrapper *xd_wrapper;
816         xmlChar        *result = NULL;
817         char           *ss_filename;
818         size_t          ss_filename_len;
819         int             length;
820
821         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &ss_filename, &ss_filename_len,
822                                 &z_xd_wrapper) == FAILURE) {
823                 return;
824         }
825         ZEND_FETCH_RESOURCE(xd_wrapper, php_xd_wrapper *, &z_xd_wrapper, -1, "FastXSL XML Document",
826                         le_fastxsl_document);
827
828         ss_wrapper = fl_hash_find(FASTXSL_G(cache)->prmtable, ss_filename, ss_filename_len);
829         if (!ss_wrapper) {
830                 RETURN_FALSE;
831         }
832         xsltSaveResultToString(&result, &length, xd_wrapper->xd, ss_wrapper->ss);
833        
834         if (result) {
835                 RETVAL_STRINGL((char *) result, length, 1);
836                 xmlFree(result);
837         } else {
838                 RETURN_FALSE;
839         }
840 }
841 /* }}} */
842
843 function_entry fastxsl_functions[] = {
844         PHP_FE(fastxsl_stylesheet_parsefile,         NULL)
845         PHP_FE(fastxsl_xml_parsefile,                NULL)
846         PHP_FE(fastxsl_xml_parsestring,              NULL)
847 #ifdef FASTXSL_MM
848         PHP_FE(fastxsl_shmcache_transform,           NULL)
849         PHP_FE(fastxsl_shmcache_tostring,            NULL)
850         PHP_FE(fastxsl_shmcache_getstatistics,       NULL)
851 #endif
852         PHP_FE(fastxsl_prmcache_transform,           NULL)
853         PHP_FE(fastxsl_nocache_transform,            NULL)
854         PHP_FE(fastxsl_nocache_profile,              NULL)
855         PHP_FE(fastxsl_nocache_tostring,             NULL)
856         PHP_FE(fastxsl_prmcache_tostring,            NULL)
857         PHP_FE(fastxsl_prmcache_getstatistics,       NULL)
858         {NULL, NULL, NULL}
859 };
860
861
862 zend_module_entry fastxsl_module_entry = {
863 #if ZEND_MODULE_API_NO >= 20010901
864         STANDARD_MODULE_HEADER,
865 #endif
866         "fastxsl",
867         fastxsl_functions,
868         PHP_MINIT(fastxsl),
869         NULL,
870         NULL,   
871         NULL,
872         PHP_MINFO(fastxsl),
873 #if ZEND_MODULE_API_NO >= 20010901
874         "0.1",
875 #endif
876         STANDARD_MODULE_PROPERTIES
877 };
878
879
880 #ifdef COMPILE_DL_FASTXSL
881 ZEND_GET_MODULE(fastxsl)
882 #endif
883
884 static void
885 SS_Wrapper_Dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
886 {
887         php_ss_wrapper *wrapper = (php_ss_wrapper *) rsrc->ptr;
888        
889         if (wrapper->persistant) {
890                 return;
891         }
892        
893         if (wrapper->ss)
894                 xsltFreeStylesheet(wrapper->ss);
895
896         free(wrapper);
897 }
898
899 static void
900 XD_Wrapper_Dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
901 {
902         php_xd_wrapper *wrapper = (php_xd_wrapper *) rsrc->ptr;
903        
904         if (wrapper->xd)
905                 xmlFreeDoc(wrapper->xd);
906         free(wrapper);
907 }
908
909 void fastxsl_errorfunc(void *ctx, const char *msg, ...)
910 {
911         char *frag;
912         int fraglen;
913         int output = 0;
914         va_list args;
915         va_start(args, msg);
916         fraglen = vspprintf(&frag, 0, msg, args);
917         while(fraglen && frag[fraglen - 1] == '\n') {
918                 frag[--fraglen] = '\0';
919                 output = 1;
920         }
921         if(fraglen) {
922                 if(FASTXSL_G(errbuf)) {
923                         FASTXSL_G(errbuf) = erealloc(FASTXSL_G(errbuf), fraglen + strlen(FASTXSL_G(errbuf)));
924                         strcat(FASTXSL_G(errbuf), frag);
925                 } else {
926                         FASTXSL_G(errbuf) = frag;
927                 }
928         }
929         va_end(args);
930         if(output) {
931                 php_error_docref(NULL TSRMLS_CC, E_WARNING, FASTXSL_G(errbuf));
932                 efree(FASTXSL_G(errbuf));
933                 FASTXSL_G(errbuf) = NULL;
934         }
935 }
936
937 static int
938 Stream_MatchWrapper(const char *filename)
939 {
940         TSRMLS_FETCH();
941         return php_stream_locate_url_wrapper(filename, NULL, STREAM_LOCATE_WRAPPERS_ONLY TSRMLS_CC) ? 1 : 0;
942 }
943
944 static void *
945 Stream_XmlWrite_OpenWrapper(const char *filename)
946 {
947         TSRMLS_FETCH();
948         return php_stream_open_wrapper((char *) filename, "wb", ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL);
949 }
950
951 static int
952 Stream_XmlWrite_WriteWrapper(void *context, const char *buffer, int length)
953 {
954         TSRMLS_FETCH();
955         return php_stream_write((php_stream *) context, (char *) buffer, length);
956 }
957
958 static int
959 Stream_CloseWrapper(void *context)
960 {
961         TSRMLS_FETCH();
962         return php_stream_close((php_stream *) context);
963 }
964
965
966 extern int xmlLoadExtDtdDefaultValue;
967
968 /**
969  * Allocators for the fl_hash storage
970  */
971 #ifdef FASTXSL_MM
972 static FL_Allocator mm_allocators = {ShmCache_Free, ShmCache_Malloc, ShmCache_Calloc};
973 #endif
974 static FL_Allocator normal_allocators = {free, malloc, calloc};
975
976 static void
977 php_fastxsl_init_globals(zend_fastxsl_globals *globals)
978 {
979         memset(globals, 0, sizeof(zend_fastxsl_globals));
980        
981         globals->cache = calloc(1, sizeof(fl_cache));
982 }
983
984
985 static void
986 php_fastxsl_destroy_globals(zend_fastxsl_globals *globals)
987 {
988         fl_cache *cache;
989        
990         cache = globals->cache;
991         if (cache) {
992                 if (cache->owner != getpid()) {
993                         return;
994                 }
995 #ifdef FASTXSL_MM
996                 mm_lock(cache->mm, MM_LOCK_RW);
997                 fl_hash_free(cache->table);
998                 mm_unlock(cache->mm);
999
1000                 mm_destroy(cache->mm);
1001 #endif
1002                 fl_hash_free(cache->prmtable);
1003         }
1004 }
1005
1006 /* {{{ php function -> xslt exporting
1007  */
1008  
1009 static void fastxsl_ext_function(xmlXPathParserContextPtr ctxt, int nargs)
1010 {
1011         xsltTransformContextPtr tctxt;
1012         zval **params;
1013         zval *param;
1014         zval *function = NULL;
1015         zval *ret = NULL;
1016         xmlChar *fname;
1017         int param_count = nargs - 1;
1018         int i;
1019        
1020         tctxt = (xsltTransformContextPtr) xsltXPathGetTransformContext(ctxt);
1021         if (tctxt == NULL) {
1022                 xsltGenericError(xsltGenericErrorContext,
1023                 "fastxsl extension functions: failed to get the transformation context\n");
1024                 return;
1025         }
1026         /* allocate for args.  first position is function name */
1027         params = emalloc(sizeof(zval *) * param_count);
1028         for(i = param_count - 1; i >=0; i--) {
1029                 xmlXPathObjectPtr obj;
1030                 xmlChar *tmp;
1031                 obj = valuePop(ctxt);
1032                 MAKE_STD_ZVAL(param);
1033                 switch(obj->type) {
1034                         case XPATH_UNDEFINED:
1035                                 ZVAL_NULL(param);
1036                                 break;
1037                         case XPATH_NODESET:
1038                                 tmp = xmlXPathCastToString(obj);
1039                                 ZVAL_STRING(param, tmp, 1);
1040                                 xmlFree(tmp);
1041                                 break;
1042                         case XPATH_BOOLEAN:
1043                                 ZVAL_BOOL(param, obj->boolval);
1044                                 break;
1045                         case XPATH_NUMBER:
1046                                 ZVAL_DOUBLE(param, obj->floatval);
1047                                 break;
1048                         case XPATH_STRING:
1049                                 ZVAL_STRING(param, obj->stringval, 1);
1050                                 break;
1051                         default:
1052                                 zend_error(E_WARNING, "inexact type conversion %d", obj->type);
1053                                 tmp = xmlXPathCastToString(obj);
1054                                 ZVAL_STRING(param, tmp, 1);
1055                                 xmlFree(tmp);
1056                                 break;
1057                 }
1058                 params[i] = param;
1059                 xmlXPathFreeObject(obj);
1060         }
1061         fname = xmlXPathPopString(ctxt);
1062         if(!fname) {
1063                 xsltGenericError(xsltGenericDebugContext,
1064                         "passed function name is not a string");
1065                 xmlXPathReturnEmptyString(ctxt);
1066                 goto cleanup;
1067         }
1068         MAKE_STD_ZVAL(function);
1069         ZVAL_STRING(function, fname, 1);
1070         xmlFree(fname);
1071         MAKE_STD_ZVAL(ret);
1072         ZVAL_FALSE(ret);
1073         if(call_user_function(EG(function_table), NULL, function, ret,
1074                                  param_count, params TSRMLS_CC) == FAILURE) {
1075                         xsltGenericError(xsltGenericDebugContext,
1076                                 "function evaluation error");
1077                 xmlXPathReturnEmptyString(ctxt);
1078                 goto cleanup;
1079         }
1080         switch(ret->type) {
1081                 case IS_BOOL:
1082                         xmlXPathReturnBoolean(ctxt, Z_BVAL_P(ret));
1083                         break;
1084                 case IS_LONG:
1085                         xmlXPathReturnNumber(ctxt, (float) Z_LVAL_P(ret));
1086                         break;
1087                 case IS_DOUBLE:
1088                         xmlXPathReturnNumber(ctxt, Z_DVAL_P(ret));
1089                         break;
1090                 case IS_STRING:
1091                         xmlXPathReturnString(ctxt, xmlStrdup(Z_STRVAL_P(ret)));
1092                         break;
1093                 default:
1094                         convert_to_string_ex(&ret);
1095                         xmlXPathReturnString(ctxt, xmlStrdup(Z_STRVAL_P(ret)));
1096                         break;
1097         }
1098 cleanup:
1099         if(params) {
1100                 for(i=0; i < param_count; i++) {
1101                         zval_ptr_dtor(&params[i]);
1102                 }
1103                 efree(params); params = NULL;
1104         }
1105         if(function) {
1106                 efree(function); function = NULL;
1107         }
1108         if(ret) {
1109                 efree(ret); ret = NULL;
1110         }
1111         return;
1112 }               
1113 /* }}} */
1114
1115
1116 PHP_INI_BEGIN()
1117         STD_PHP_INI_ENTRY("fastxsl.shmpath", "/tmp/fastxsl_mem", PHP_INI_SYSTEM, OnUpdateString, shmpath, zend_fastxsl_globals, fastxsl_globals)
1118         STD_PHP_INI_BOOLEAN("fastxsl.nostat", "0", PHP_INI_ALL, OnUpdateInt, nostat, zend_fastxsl_globals, fastxsl_globals)
1119         STD_PHP_INI_BOOLEAN("fastxsl.register_functions", "0", PHP_INI_ALL, OnUpdateInt, register_functions, zend_fastxsl_globals, fastxsl_globals)
1120 PHP_INI_END()
1121
1122 PHP_MINIT_FUNCTION(fastxsl)
1123 {
1124         char   *shmpath;
1125         size_t  shmpath_len;
1126         char    euid[30];
1127
1128         ZEND_INIT_MODULE_GLOBALS(fastxsl, php_fastxsl_init_globals, php_fastxsl_destroy_globals);
1129        
1130         REGISTER_INI_ENTRIES();
1131        
1132         le_fastxsl_stylesheet = zend_register_list_destructors_ex(SS_Wrapper_Dtor, NULL,
1133         le_fastxsl_stylesheet_name, module_number);
1134         le_fastxsl_document   = zend_register_list_destructors_ex(XD_Wrapper_Dtor, NULL,
1135                         le_fastxsl_document_name,   module_number);
1136
1137         xsltRegisterAllExtras();
1138         xmlSubstituteEntitiesDefault(1);
1139         xmlLoadExtDtdDefaultValue = 1;
1140
1141         xmlMemGet(&free_ptr, &malloc_ptr, &realloc_ptr, &strdup_ptr);
1142         xmlRegisterOutputCallbacks(Stream_MatchWrapper, Stream_XmlWrite_OpenWrapper,
1143                                            Stream_XmlWrite_WriteWrapper, Stream_CloseWrapper);
1144         xsltSetGenericErrorFunc(NULL, fastxsl_errorfunc);
1145         xmlSetGenericErrorFunc(NULL, fastxsl_errorfunc);
1146 #ifdef FASTXSL_MM
1147         if (!sprintf(euid, "%d", geteuid())) {
1148                 return FAILURE;
1149         }
1150
1151         shmpath_len = strlen(FASTXSL_G(shmpath)) + strlen(euid);
1152         shmpath = do_alloca(shmpath_len + 1);
1153
1154         strcpy(shmpath, FASTXSL_G(shmpath));
1155         strcat(shmpath, euid);
1156        
1157         FASTXSL_G(cache)->owner = getpid();
1158         FASTXSL_G(cache)->mm = mm_create(0, shmpath);
1159
1160         free_alloca(shmpath);
1161         if (!FASTXSL_G(cache)->mm) {
1162                 return FAILURE;
1163         }
1164
1165         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RW);
1166         FASTXSL_G(cache)->table = fl_hash_new(&mm_allocators, NULL);
1167         mm_unlock(FASTXSL_G(cache)->mm);
1168 #endif
1169         FASTXSL_G(cache)->prmtable = fl_hash_new(&normal_allocators, NULL);
1170        
1171         if(FASTXSL_G(register_functions)) {
1172                 xsltRegisterExtModuleFunction ((const xmlChar *) "function",
1173                                            (const xmlChar *) "http://php.net/fastxsl",
1174                                            fastxsl_ext_function);
1175         }
1176         return SUCCESS;
1177 }
1178
1179 PHP_MINFO_FUNCTION(fastxsl)
1180 {
1181         php_info_print_table_start();
1182         php_info_print_table_header(2, "fastxsl support", "enabled");
1183         php_info_print_table_end();
1184
1185 }
1186
Note: See TracBrowser for help on using the browser.