root/trunk/fastxsl.c

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

make error handling more php5 esque

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   +----------------------------------------------------------------------+
17
18   $Id: fastxsl.c,v 1.1.1.1 2004/02/17 23:31:44 sterling Exp $
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <libxml/xmlmemory.h>
26 #include <libxml/debugXML.h>
27 #include <libxml/HTMLtree.h>
28 #include <libxml/xmlIO.h>
29 #include <libxml/xinclude.h>
30 #include <libxml/catalog.h>
31 #include <libxml/xpathInternals.h>
32 #include <libxml/xpath.h>
33 #include <libxslt/xslt.h>
34 #include <libxslt/xsltInternals.h>
35 #include <libxslt/transform.h>
36 #include <libxslt/xsltutils.h>
37
38 #ifdef FASTXSL_MM
39 #include <mm.h>
40 #endif
41 #include <sys/types.h>
42 #include <unistd.h>
43
44 #include "fl_hash.h"
45 #include "php.h"
46 #include "php_ini.h"
47 #include "ext/standard/info.h"
48 #include "php_fastxsl.h"
49
50 ZEND_DECLARE_MODULE_GLOBALS(fastxsl);
51
52 static int le_fastxsl_stylesheet;
53 #define le_fastxsl_stylesheet_name "FastXSL Stylesheet"
54 static int le_fastxsl_document;
55 #define le_fastxsl_document_name "FastXSL Document"
56
57 #define FASTXSL_PRM_ALLOC 1
58 #define FASTXSL_SHARED_ALLOC 2
59
60 void fastxsl_errorfunc(void *ctx, const char *msg, ...);
61
62 static php_ss_wrapper *
63 SS_Wrapper_Alloc(int shared TSRMLS_DC)
64 {
65         php_ss_wrapper *wrapper;
66
67         if (shared) {
68 #ifdef FASTXSL_MM
69                 if (shared == FASTXSL_SHARED_ALLOC) {
70                         wrapper = (php_ss_wrapper *) mm_calloc(FASTXSL_G(cache)->mm, 1, sizeof(php_ss_wrapper));
71                 } else {
72                         wrapper = (php_ss_wrapper *) calloc(1, sizeof(php_ss_wrapper));
73                 }
74                 wrapper->persistant = 1;
75 #else
76         wrapper = (php_ss_wrapper *) calloc(1, sizeof(php_ss_wrapper));
77         wrapper->persistant = 1;
78 #endif
79         } else {
80                 wrapper = (php_ss_wrapper *) calloc(1, sizeof(php_ss_wrapper));
81         }
82
83         return wrapper;
84 }
85
86 static php_xd_wrapper *
87 XD_Wrapper_Alloc(void)
88 {
89         php_xd_wrapper *wrapper;
90
91         wrapper = (php_xd_wrapper *) calloc(1, sizeof(php_xd_wrapper));
92         return wrapper;
93 }
94
95 static xmlFreeFunc    free_ptr;
96 static xmlMallocFunc  malloc_ptr;
97 static xmlReallocFunc realloc_ptr;
98 static xmlStrdupFunc  strdup_ptr;
99
100 #ifdef FASTXSL_MM
101 static void
102 ShmCache_Free(void *ptr)
103 {
104         TSRMLS_FETCH();
105         FASTXSL_G(tmp_allocated_size) -= mm_sizeof(FASTXSL_G(cache)->mm, ptr);
106        
107         mm_free(FASTXSL_G(cache)->mm, ptr);
108 }
109
110 static void *
111 ShmCache_Malloc(size_t size)
112 {
113         void *ptr;
114         TSRMLS_FETCH();
115
116         ptr = mm_malloc(FASTXSL_G(cache)->mm, size);
117         if (!ptr) {
118                 php_error(E_ERROR, "Ran out of Shared memory to allocate data for FastXSL cache, "
119                                            "in function %s() cannot allocate %d bytes (%d available, %d allocated)",
120                                                    get_active_function_name(TSRMLS_C), size, mm_available(FASTXSL_G(cache)->mm),
121                                                    mm_maxsize() - mm_available(FASTXSL_G(cache)->mm));
122                 return NULL;
123         }
124
125         FASTXSL_G(tmp_allocated_size) += size;
126
127         return ptr;
128 }
129
130 static void *
131 ShmCache_Calloc(size_t nmemb, size_t size)
132 {
133         void *ptr;
134
135         ptr = ShmCache_Malloc(nmemb * size);
136         memset(ptr, 0, nmemb * size);
137
138         return ptr;
139 }
140
141 static void *
142 ShmCache_Realloc(void *ptr, size_t size)
143 {
144         void *newptr;
145         long  oldsize;
146         TSRMLS_FETCH();
147
148         oldsize = mm_sizeof(FASTXSL_G(cache)->mm, ptr);
149         newptr = mm_realloc(FASTXSL_G(cache)->mm, ptr, size);
150         if (!newptr) {
151                 TSRMLS_FETCH();
152                 php_error(E_ERROR, "Ran out of Shared memory to allocate data for FastXSL cache, "
153                                            "in function %s() cannot allocate %d bytes (%d available, %d allocated)",
154                                                    get_active_function_name(TSRMLS_C), size, mm_available(FASTXSL_G(cache)->mm),
155                                                    mm_maxsize() - mm_available(FASTXSL_G(cache)->mm));
156                 return NULL;
157         }
158         FASTXSL_G(tmp_allocated_size) += (size - oldsize);
159
160         return newptr;
161 }
162
163 static char *
164 ShmCache_Strdup(const char *string)
165 {
166         char *newstring;
167         int   string_length;
168
169         string_length = strlen(string);
170         newstring = ShmCache_Malloc(string_length);
171         memcpy(newstring, string, string_length);
172         newstring[string_length] = 0;
173
174         return newstring;
175 }
176 #endif
177
178 static void
179 Php_Free(void *ptr)
180 {
181         efree(ptr);
182 }
183
184 static void *
185 Php_Malloc(size_t size)
186 {
187         return emalloc(size);
188 }
189
190 static void *
191 Php_Realloc(void *ptr, size_t size)
192 {
193         return erealloc(ptr, size);
194 }
195
196 static char *
197 Php_Strdup(const char *string)
198 {
199         return estrdup(string);
200 }
201
202 #ifdef FASTXSL_MM
203 static void
204 ShmCache_UseAllocationFunctions(void)
205 {
206         xmlMemSetup(ShmCache_Free, ShmCache_Malloc, ShmCache_Realloc, ShmCache_Strdup);
207 }
208 #endif
209
210 static void
211 Php_UseAllocationFunctions(void)
212 {
213         xmlMemSetup(Php_Free, Php_Malloc, Php_Realloc, Php_Strdup);
214 }
215
216 static void
217 Xml_UseAllocationFunctions(void)
218 {
219         xmlMemSetup(free_ptr, malloc_ptr, realloc_ptr, strdup_ptr);
220 }
221
222 #ifdef FASTXSL_MM
223 static php_ss_wrapper *
224 ShmCache_Stylesheet_ParseAndStore(char *filename, size_t filename_len, int mtime TSRMLS_DC)
225 {
226         php_ss_wrapper *wrapper;
227        
228         wrapper = SS_Wrapper_Alloc(FASTXSL_SHARED_ALLOC TSRMLS_CC);
229
230         ShmCache_UseAllocationFunctions();
231         FASTXSL_G(tmp_allocated_size) = 0;
232         wrapper->ss = xsltParseStylesheetFile(filename);
233         if (!wrapper->ss) {
234                 Xml_UseAllocationFunctions();
235                 return NULL;
236         }
237         Xml_UseAllocationFunctions();
238         wrapper->mtime = mtime;
239         wrapper->allocsize = FASTXSL_G(tmp_allocated_size);
240        
241         fl_hash_add(FASTXSL_G(cache)->table, filename, filename_len, wrapper);
242
243         return wrapper;
244 }
245
246 static void
247 ShmCache_Stylesheet_Free(php_ss_wrapper *wrapper TSRMLS_DC)
248 {
249         if (wrapper->ss) {
250                 ShmCache_UseAllocationFunctions();
251                 xsltFreeStylesheet(wrapper->ss);
252                 Xml_UseAllocationFunctions();
253         }
254         mm_free(FASTXSL_G(cache)->mm, wrapper);
255 }
256
257 static void
258 ShmCache_Stylesheet_Delete(char *filename, size_t filename_len)
259 {
260         php_ss_wrapper *wrapper;
261
262         wrapper = fl_hash_find(FASTXSL_G(cache)->table, filename, filename_len);
263         if (wrapper) {
264                 fl_hash_delete(FASTXSL_G(cache)->table, filename, filename_len);
265                 ShmCache_Stylesheet_Free(wrapper);
266         }
267 }
268 #endif
269
270 static php_ss_wrapper *
271 PrmCache_Stylesheet_ParseAndStore(char *filename, size_t filename_len, int mtime)
272 {
273         php_ss_wrapper *wrapper;
274
275         wrapper = (php_ss_wrapper *) SS_Wrapper_Alloc(FASTXSL_PRM_ALLOC TSRMLS_CC);
276
277         wrapper->ss = xsltParseStylesheetFile(filename);
278         if (!wrapper->ss) {
279                 return NULL;
280         }
281         wrapper->mtime = mtime;
282        
283         fl_hash_add(FASTXSL_G(cache)->prmtable, filename, filename_len, wrapper);
284
285         return wrapper;
286 }
287
288 static void
289 PrmCache_Stylesheet_Free(php_ss_wrapper *wrapper)
290 {
291         if (wrapper->ss) {
292                 xsltFreeStylesheet(wrapper->ss);
293         }
294         free(wrapper);
295 }
296
297 static void
298 PrmCache_Stylesheet_Delete(char *filename, size_t filename_len TSRMLS_DC)
299 {
300         php_ss_wrapper *wrapper;
301
302         wrapper = fl_hash_find(FASTXSL_G(cache)->prmtable, filename, filename_len);
303         if (wrapper) {
304                 fl_hash_delete(FASTXSL_G(cache)->prmtable, filename, filename_len);
305                 PrmCache_Stylesheet_Free(wrapper TSRMLS_CC);
306         }
307 }
308
309 /* {{{ proto array fastxsl_prmcache_getstatistics(void)
310    Get an array of statistics regarding the fastxsl documents in the process resident memory cache */
311 PHP_FUNCTION(fastxsl_prmcache_getstatistics)
312 {
313         php_ss_wrapper *wrapper;       
314
315         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
316                 return;
317         }
318
319 }
320 /* }}} */
321
322 /* {{{ proto array fastxsl_shmcache_getstatistics(void)
323    Get an array of statistics regarding the documents in the shared memory cache */
324 #ifdef FASTXSL_MM
325 PHP_FUNCTION(fastxsl_shmcache_getstatistics)
326 {
327         php_ss_wrapper *ss_wrapper;
328         FL_Bucket      *bucket;
329         zval           *files_array;
330         zval           *info_array;
331         int             i;
332         long            allocated_bytes = 0;
333        
334         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
335                 return;
336         }
337
338         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
339        
340         array_init(return_value);
341
342         MAKE_STD_ZVAL(files_array);
343         array_init(files_array);
344
345         for (i = 0; i < FL_HASH_SIZE; i++) {
346                 for (bucket = FASTXSL_G(cache)->table->buckets[i]; bucket != NULL; bucket = bucket->next) {
347                         ss_wrapper = (php_ss_wrapper *) bucket->data;
348
349                         MAKE_STD_ZVAL(info_array);
350                         array_init(info_array);
351
352                         add_assoc_long(info_array, "allocated", ss_wrapper->allocsize);
353                         add_assoc_long(info_array, "mtime", ss_wrapper->mtime);
354
355                         add_assoc_zval(files_array, bucket->key, info_array);
356
357                         allocated_bytes += ss_wrapper->allocsize;
358                 }
359         }
360         add_assoc_zval(return_value, "files", files_array);
361
362         add_assoc_long(return_value, "shm_allocated", allocated_bytes);
363         add_assoc_long(return_value, "shm_maxsize", (long) mm_maxsize());
364
365         mm_unlock(FASTXSL_G(cache)->mm);
366 }
367 #endif
368 /* }}} */
369
370 /* {{{ proto resource fastxsl_stylesheet_parsefile(string filename)
371    Parse a stylesheet file located at filename. */
372 PHP_FUNCTION(fastxsl_stylesheet_parsefile)
373 {
374         php_ss_wrapper *wrapper;
375         char           *filename;
376         size_t          filename_len;
377
378         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename,
379                                 &filename_len) == FAILURE) {
380                 return;
381         }
382
383         wrapper = (php_ss_wrapper *) SS_Wrapper_Alloc(0 TSRMLS_CC);
384         wrapper->ss = xsltParseStylesheetFile(filename);
385         if (!wrapper->ss) {
386                 RETURN_FALSE;
387         }
388
389         ZEND_REGISTER_RESOURCE(return_value, wrapper, le_fastxsl_stylesheet);
390 }
391 /* }}} */
392
393 /* {{{ proto resource fastxsl_xml_parsestring(string text)
394   Parse a string containing an XML document and return a resource pointer to the resulting libxml2 tree */
395 PHP_FUNCTION(fastxsl_xml_parsestring)
396 {
397         php_xd_wrapper *wrapper;
398         char           *text;
399         size_t          text_len;
400
401         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &text, &text_len) == FAILURE) {
402                 return;
403         }
404
405         wrapper = XD_Wrapper_Alloc();
406         wrapper->xd = xmlParseDoc(text);
407         if (!wrapper->xd) {
408                 RETURN_FALSE;
409         }
410
411         ZEND_REGISTER_RESOURCE(return_value, wrapper, le_fastxsl_document);
412 }
413 /* }}} */
414
415 /* {{{ proto resource fastxsl_xml_parsefile(string filename)
416    Parse an XML file into a FastXSL resource */
417 PHP_FUNCTION(fastxsl_xml_parsefile)
418 {
419         php_xd_wrapper *wrapper;
420         char           *filename;
421         size_t          filename_len;
422
423         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename,
424                                 &filename_len) == FAILURE) {
425                 return;
426         }
427
428         wrapper = XD_Wrapper_Alloc();
429         wrapper->xd = xmlParseFile((const xmlChar *) filename);
430         if (!wrapper->xd) {
431                 RETURN_FALSE;
432         }
433
434         ZEND_REGISTER_RESOURCE(return_value, wrapper, le_fastxsl_document);
435 }
436 /* }}} */
437
438 static int
439 ParseTransformParameters(zval *z_parameters, char ***parameters TSRMLS_DC)
440 {
441         zval         **current;
442         HashTable     *h_parameters;
443         HashPosition   pos;
444         char          *key;
445         int            key_length;
446         unsigned long  ival;
447         int            index = 0;
448
449         h_parameters = Z_ARRVAL_P(z_parameters);
450
451         if (zend_hash_num_elements(h_parameters) == 0) {
452                 *parameters = NULL;
453                 return SUCCESS;
454         }
455        
456         *parameters = calloc(1, (zend_hash_num_elements(h_parameters) * (2 * sizeof(char *))) + 1);
457         if (!*parameters) {
458                 php_error(E_WARNING, "Cannot allocate parameters array to pass to FastXSL");
459                 return FAILURE;
460         }
461        
462         for (zend_hash_internal_pointer_reset_ex(h_parameters, &pos);
463              zend_hash_get_current_data_ex(h_parameters, (void **) &current, &pos) == SUCCESS;
464                  zend_hash_move_forward_ex(h_parameters, &pos)) {
465                 if (zend_hash_get_current_key_ex(h_parameters, &key, &key_length,
466                                         &ival, 0, &pos) == HASH_KEY_IS_LONG) {
467                         efree(*parameters);
468                         *parameters = NULL;
469
470                         php_error(E_WARNING,
471                                         "Parameters array passed to %s() may not contain numeric keys",
472                                         get_active_function_name(TSRMLS_C));
473                         return FAILURE;
474                 }
475
476                 convert_to_string_ex(current);
477
478                 (*parameters)[index++] = key;
479                 (*parameters)[index++] = Z_STRVAL_PP(current);
480         }
481         (*parameters)[index] = NULL;
482
483         return SUCCESS;
484 }
485
486 /* {{{ proto resource fastxsl_shmcache_transform(string filename, resource xmldoc[, array parameters])
487    Transform a XML document, "xmldoc", by a XSL stylesheet "filename" with transform "parameters." */
488 #ifdef FASTXSL_MM
489 PHP_FUNCTION(fastxsl_shmcache_transform)
490 {
491         char            **parameters = NULL;
492         php_xd_wrapper   *xd_wrapper;
493         php_xd_wrapper   *result_wrapper;
494         php_ss_wrapper   *ss_wrapper;
495         char             *ss_filename;
496         size_t            ss_filename_len;
497         zval             *z_xd_wrapper;
498         zval             *z_parameters;
499         struct stat       sb;
500        
501         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|z", &ss_filename, &ss_filename_len,
502                                 &z_xd_wrapper, &z_parameters) == FAILURE) {
503                 return;
504         }
505        
506         ZEND_FETCH_RESOURCE(xd_wrapper, php_xd_wrapper *, &z_xd_wrapper, -1, "FastXSL XML Document",
507                         le_fastxsl_document);
508
509         if (ZEND_NUM_ARGS() > 2 && Z_TYPE_P(z_parameters) == IS_ARRAY) {
510                 if (ParseTransformParameters(z_parameters, &parameters TSRMLS_CC) == FAILURE) {
511                         RETURN_FALSE;
512                 }
513         }
514
515         result_wrapper = XD_Wrapper_Alloc();
516
517         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RW);
518         if (!FASTXSL_G(nostat)) {
519                 if (stat(ss_filename, &sb) == -1) {
520                         ShmCache_Stylesheet_Delete(ss_filename, ss_filename_len TSRMLS_CC);
521                         mm_unlock(FASTXSL_G(cache)->mm);
522                         free(parameters);
523                         RETURN_FALSE;
524                 }
525         } else {
526                 sb.st_mtime = 0;
527         }
528        
529         ss_wrapper = fl_hash_find(FASTXSL_G(cache)->table, ss_filename, ss_filename_len);
530         if (!ss_wrapper) {
531                 ss_wrapper = ShmCache_Stylesheet_ParseAndStore(ss_filename, ss_filename_len, sb.st_mtime);
532                 if (!ss_wrapper) {
533                         mm_unlock(FASTXSL_G(cache)->mm);
534                         free(parameters);
535                         RETURN_FALSE;
536                 }
537         } else {
538                 if (!FASTXSL_G(nostat)) {
539                         if (ss_wrapper->mtime != sb.st_mtime) {
540                                 ShmCache_Stylesheet_Delete(ss_filename, ss_filename_len TSRMLS_CC);
541                                 ss_wrapper = ShmCache_Stylesheet_ParseAndStore(ss_filename, ss_filename_len, sb.st_mtime TSRMLS_CC);
542                                 if (!ss_wrapper) {
543                                         mm_unlock(FASTXSL_G(cache)->mm);
544                                         free(parameters);
545                                         RETURN_FALSE;
546                                 }
547                         }
548                 }
549         }
550
551         wrapper = (php_ss_wrapper *) SS_Wrapper_Alloc(0 TSRMLS_CC);
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.