root/trunk/fastxsl.c

Revision 44, 44.4 kB (checked in by jesus, 7 years ago)

take fster branch up to [43] into trunk

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 <libxml/uri.h>
35 #include <libxslt/xslt.h>
36 #include <libxslt/xsltInternals.h>
37 #include <libxslt/transform.h>
38 #include <libxslt/xsltutils.h>
39 #include <libxslt/extensions.h>
40 #include <libxslt/functions.h>
41
42 #ifdef FASTXSL_MM
43 #include <mm.h>
44 #endif
45 #include <sys/types.h>
46 #include <sys/file.h>
47 #include <unistd.h>
48 #include <fcntl.h>
49
50
51 #include "fl_hash.h"
52 #include "php.h"
53 #include "php_ini.h"
54 #include "ext/standard/info.h"
55 #include "php_fastxsl.h"
56
57 ZEND_DECLARE_MODULE_GLOBALS(fastxsl)
58
59 static int le_fastxsl_stylesheet;
60 #define le_fastxsl_stylesheet_name "FastXSL Stylesheet"
61 static int le_fastxsl_document;
62 #define le_fastxsl_document_name "FastXSL Document"
63
64 #define FASTXSL_PRM_ALLOC 1
65 #define FASTXSL_SHARED_ALLOC 2
66
67 void fastxsl_errorfunc(void *ctx, const char *msg, ...);
68 static void ShmCache_Stylesheet_Free(php_ss_wrapper *wrapper TSRMLS_DC);
69 static void _SS_Wrapper_Dtor(php_ss_wrapper *wrapper);
70 static void _XD_Wrapper_Dtor(php_xd_wrapper *wrapper);
71
72 extern void HACK_xsltDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs);
73
74 static php_ss_wrapper *
75 SS_Wrapper_Alloc(int shared TSRMLS_DC)
76 {
77         php_ss_wrapper *wrapper;
78
79         if (shared) {
80 #ifdef FASTXSL_MM
81                 if (shared == FASTXSL_SHARED_ALLOC) {
82                         wrapper = (php_ss_wrapper *) mm_calloc(FASTXSL_G(cache)->mm, 1, sizeof(php_ss_wrapper));
83                 } else {
84                         wrapper = (php_ss_wrapper *) calloc(1, sizeof(php_ss_wrapper));
85                 }
86                 if(!wrapper) {
87                         mm_display_info(FASTXSL_G(cache)->mm);
88                 }
89                 wrapper->persistant = 1;
90 #else
91                 wrapper = (php_ss_wrapper *) calloc(1, sizeof(php_ss_wrapper));
92                 wrapper->persistant = 1;
93 #endif
94         } else {
95                 wrapper = (php_ss_wrapper *) calloc(1, sizeof(php_ss_wrapper));
96         }
97
98         return wrapper;
99 }
100
101 static php_xd_wrapper *
102 XD_Wrapper_Alloc(void)
103 {
104         php_xd_wrapper *wrapper;
105
106         wrapper = (php_xd_wrapper *) calloc(1, sizeof(php_xd_wrapper));
107         return wrapper;
108 }
109
110 static xmlFreeFunc    free_ptr;
111 static xmlMallocFunc  malloc_ptr;
112 static xmlMallocFunc  mallocatomic_ptr;
113 static xmlReallocFunc realloc_ptr;
114 static xmlStrdupFunc  strdup_ptr;
115
116 #ifdef FASTXSL_MM
117 void
118 ShmCache_Free(void *ptr)
119 {
120         TSRMLS_FETCH();
121         FASTXSL_G(tmp_allocated_size) -= mm_sizeof(FASTXSL_G(cache)->mm, ptr);
122         mm_free(FASTXSL_G(cache)->mm, ptr);
123 }
124
125 void *
126 ShmCache_Malloc(size_t size)
127 {
128         void *ptr;
129         TSRMLS_FETCH();
130         ptr = mm_malloc(FASTXSL_G(cache)->mm, size);
131         if (!ptr) {
132                 php_error(E_ERROR, "Ran out of Shared memory to allocate data for FastXSL cache, "
133                                            "in function %s() cannot allocate %ld bytes (%ld available, %ld allocated)",
134                                                    get_active_function_name(TSRMLS_C), size, mm_available(FASTXSL_G(cache)->mm),
135                                                    mm_maxsize() - mm_available(FASTXSL_G(cache)->mm));
136                 return NULL;
137         }
138
139         FASTXSL_G(tmp_allocated_size) += size;
140         return ptr;
141 }
142
143 void *
144 ShmCache_Calloc(size_t nmemb, size_t size)
145 {
146         void *ptr;
147
148         ptr = ShmCache_Malloc(nmemb * size);
149         memset(ptr, 0, nmemb * size);
150         return ptr;
151 }
152
153 void *
154 ShmCache_Realloc(void *ptr, size_t size)
155 {
156         void *newptr;
157         long  oldsize;
158         TSRMLS_FETCH();
159
160         oldsize = mm_sizeof(FASTXSL_G(cache)->mm, ptr);
161         newptr = mm_realloc(FASTXSL_G(cache)->mm, ptr, size);
162         if (!newptr) {
163                 TSRMLS_FETCH();
164                 php_error(E_ERROR, "Ran out of Shared memory to allocate data for FastXSL cache, "
165                                            "in function %s() cannot allocate %d bytes (%d available, %d allocated)",
166                                                    get_active_function_name(TSRMLS_C), size, mm_available(FASTXSL_G(cache)->mm),
167                                                    mm_maxsize() - mm_available(FASTXSL_G(cache)->mm));
168                 return NULL;
169         }
170         FASTXSL_G(tmp_allocated_size) += (size - oldsize);
171         return newptr;
172 }
173
174 char *
175 ShmCache_Strdup(const char *string)
176 {
177         char *newstring;
178         int   string_length;
179
180         string_length = strlen(string);
181         newstring = ShmCache_Malloc(string_length + 1);
182         memcpy(newstring, string, string_length);
183         newstring[string_length] = 0;
184
185         return newstring;
186 }
187 #endif
188
189 static void
190 Php_Free(void *ptr)
191 {
192         efree(ptr);
193 }
194
195 static void *
196 Php_Malloc(size_t size)
197 {
198         return emalloc(size);
199 }
200
201 static void *
202 Php_Realloc(void *ptr, size_t size)
203 {
204         return erealloc(ptr, size);
205 }
206
207 static char *
208 Php_Strdup(const char *string)
209 {
210         return estrdup(string);
211 }
212
213 #ifdef FASTXSL_MM
214 static void
215 ShmCache_UseAllocationFunctions(void)
216 {
217         xmlMemSetup(ShmCache_Free, ShmCache_Malloc, ShmCache_Realloc, ShmCache_Strdup);
218 }
219 #endif
220
221 static void
222 Php_UseAllocationFunctions(void)
223 {
224         xmlMemSetup(Php_Free, Php_Malloc, Php_Realloc, Php_Strdup);
225 }
226
227 static void
228 Xml_UseAllocationFunctions(void)
229 {
230         xmlMemSetup(free_ptr, malloc_ptr,  realloc_ptr, strdup);
231 }
232
233 #ifdef FASTXSL_MM
234 static php_ss_wrapper *
235 ShmCache_Stylesheet_ParseAndStore(char *filename, size_t filename_len, int mtime TSRMLS_DC)
236 {
237         php_ss_wrapper *wrapper;
238         int rv;
239         wrapper = SS_Wrapper_Alloc(FASTXSL_SHARED_ALLOC TSRMLS_CC);
240
241         ShmCache_UseAllocationFunctions();
242         wrapper->alloc_type = FASTXSL_SHMALLOC;
243         FASTXSL_G(tmp_allocated_size) = 0;
244         zend_set_timeout(0);
245         wrapper->data.ss = xsltParseStylesheetFile((unsigned char *)filename);
246         wrapper->data_type = FASTXSL_STYLESHEET;
247         Xml_UseAllocationFunctions();
248         if (!wrapper->data.ss) {
249                 _SS_Wrapper_Dtor(wrapper);
250                 return NULL;
251         }
252         wrapper->mtime = mtime;
253         wrapper->allocsize = FASTXSL_G(tmp_allocated_size);
254         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
255         rv = fl_hash_add(FASTXSL_G(cache)->table, filename, filename_len, wrapper);
256         mm_unlock(FASTXSL_G(cache)->mm);
257         if(rv == 0) {
258                 /* we failed */
259                 php_ss_wrapper *fallback;
260                 mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
261                 fallback = fl_hash_find(FASTXSL_G(cache)->table, filename,
262                                         filename_len);
263                 mm_unlock(FASTXSL_G(cache)->mm);
264                 if(fallback && fallback->data_type == FASTXSL_STYLESHEET) {
265                         ShmCache_Stylesheet_Free(wrapper);
266                         wrapper = fallback;
267                 } else {
268                 }
269         } else {
270         }
271
272         return wrapper;
273 }
274
275 static void
276 ShmCache_Stylesheet_Free(php_ss_wrapper *wrapper TSRMLS_DC)
277 {
278         if (wrapper->data_type == FASTXSL_STYLESHEET) {
279                 if (wrapper->data.ss) {
280                         ShmCache_UseAllocationFunctions();
281                         xsltFreeStylesheet(wrapper->data.ss);
282                         Xml_UseAllocationFunctions();
283                 }
284                 mm_free(FASTXSL_G(cache)->mm, wrapper);
285         }
286 }
287
288 static void
289 ShmCache_XPathObject_Free(php_ss_wrapper *wrapper TSRMLS_DC)
290 {
291         if (wrapper->data_type == FASTXSL_XPATHOBJ) {
292                 if (wrapper->data.ss) {
293                         ShmCache_UseAllocationFunctions();
294                         xmlXPathFreeObject(wrapper->data.op);
295                         Xml_UseAllocationFunctions();
296                 }
297                 mm_free(FASTXSL_G(cache)->mm, wrapper);
298         }
299 }
300
301 static void
302 ShmCache_Document_Delete(char *filename, size_t filename_len)
303 {
304         php_ss_wrapper *wrapper;
305
306         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
307         wrapper = fl_hash_find(FASTXSL_G(cache)->table, filename, filename_len);
308         mm_unlock(FASTXSL_G(cache)->mm);
309         if (wrapper) {
310                 mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
311                 fl_hash_delete(FASTXSL_G(cache)->table, filename, filename_len);
312                 mm_unlock(FASTXSL_G(cache)->mm);
313                 switch(wrapper->data_type) {
314                         case FASTXSL_STYLESHEET:
315                                 ShmCache_Stylesheet_Free(wrapper);
316                                 break;
317                         case FASTXSL_XPATHOBJ:
318                                 ShmCache_XPathObject_Free(wrapper);
319                                 break;
320                         default:
321                                 break;
322                 }
323         }
324 }
325 #endif
326
327 #ifdef FASTXSL_MM
328 /* {{{ proto void fastxsl_CachedDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs)
329    Emulate xsltDocumentFunction but leverage the MM shared cache for speed. */
330 void
331 fastxsl_CachedDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs)
332 {
333         xmlXPathFunction func;
334         xmlXPathObjectPtr idoc, obj;
335         xsltTransformContextPtr tctxt;
336         xmlChar *base = NULL, *URI;
337         char *ss_filename;
338         int ss_filename_len;
339         struct stat sb;
340         php_ss_wrapper *ss_wrapper;
341
342         xmlXPathStringFunction(ctxt, 1);
343         if (ctxt->value->type != XPATH_STRING) {
344                 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
345                                                  "document() : invalid arg expecting a string\n");
346                 goto error;
347         }
348         obj = ctxt->value;
349
350         /* Translate this document as would xsltLoadDocument */
351         tctxt = xsltXPathGetTransformContext(ctxt);
352         if ((tctxt != NULL) && (tctxt->inst != NULL)) {
353                 base = xmlNodeGetBase(tctxt->inst->doc, tctxt->inst);
354         }
355         else {
356                 base = xmlNodeGetBase(tctxt->style->doc,
357                                         (xmlNodePtr) tctxt->style->doc);
358         }
359         URI = xmlBuildURI(obj->stringval, base);
360         if (base != NULL)               
361                  xmlFree(base);
362
363         ss_filename_len = strlen((char *)URI);
364         ss_filename = alloca(ss_filename_len + 1);
365         strcpy(ss_filename, (char *)URI);
366
367         sb.st_mtime = 0;
368
369         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RW);
370         ss_wrapper = fl_hash_find(FASTXSL_G(cache)->table, ss_filename, ss_filename_len);
371         if(ss_wrapper) ss_wrapper->hits++;
372         mm_unlock(FASTXSL_G(cache)->mm);
373
374         if (!ss_wrapper) {
375                 int lockfd;
376                 lockfd = open(ss_filename, O_RDONLY);
377                 if(lockfd < 0) goto error;
378
379                 /* It would be really bad if we longjmp'd out with the lock */
380                 zend_set_timeout(0);
381                 /* Lock, but we may not be the only one... */
382                 ACQUIRE(lockfd);
383                 /* We have the lock, lets see if someone beat us here */
384                 mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RW);
385                 ss_wrapper = fl_hash_find(FASTXSL_G(cache)->table, ss_filename, ss_filename_len);
386                 if(ss_wrapper) ss_wrapper->hits++;
387                 mm_unlock(FASTXSL_G(cache)->mm);
388
389                 if(ss_wrapper) {
390                         /* Someone beat us */
391                 }
392                 else {
393                         ss_wrapper = SS_Wrapper_Alloc(FASTXSL_SHARED_ALLOC TSRMLS_CC);
394                         if(ss_wrapper) {
395                                 int rv;
396                                 if (!FASTXSL_G(nostat)) {
397                                         if (fstat(lockfd, &sb) == -1) {
398                                                 ShmCache_UseAllocationFunctions();
399                                                 ShmCache_Document_Delete(ss_filename, ss_filename_len TSRMLS_CC);
400                                                 Xml_UseAllocationFunctions();
401                                                 RELEASE(lockfd);
402                                                 close(lockfd);
403                                                 goto error;
404                                         }
405                                 }
406                                 ss_wrapper->alloc_type = FASTXSL_SHMALLOC;
407                                 ss_wrapper->data_type = FASTXSL_XPATHOBJ;
408                                 ShmCache_UseAllocationFunctions();
409                                 FASTXSL_G(tmp_allocated_size) = 0;
410                                 valuePush(ctxt, xmlXPathObjectCopy(ctxt->value));
411                                 HACK_xsltDocumentFunction(ctxt, nargs);
412                                 ss_wrapper->data.op = xmlXPathObjectCopy(ctxt->value);
413                                 valuePop(ctxt);
414                                 ss_wrapper->allocsize = FASTXSL_G(tmp_allocated_size);
415                                 Xml_UseAllocationFunctions();
416                                 ss_wrapper->mtime = sb.st_mtime;
417                                 mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
418                                 rv = fl_hash_add(FASTXSL_G(cache)->table, ss_filename, ss_filename_len, ss_wrapper);
419                                 mm_unlock(FASTXSL_G(cache)->mm);
420                                 if(rv == 0) {
421                                         /* we failed */
422                                         php_ss_wrapper *fallback;
423                                         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
424                                         fallback = fl_hash_find(FASTXSL_G(cache)->table, ss_filename, ss_filename_len);
425                                         mm_unlock(FASTXSL_G(cache)->mm);
426                                         if(fallback && fallback->data_type == FASTXSL_XPATHOBJ) {
427                                                 ShmCache_UseAllocationFunctions();
428                                                 ShmCache_XPathObject_Free(ss_wrapper);
429                                                 Xml_UseAllocationFunctions();
430                                                 ss_wrapper = fallback;
431                                         } else {
432                                         }
433                                 } else {
434                                 }
435                         }
436                 }
437                 RELEASE(lockfd);
438                 close(lockfd);
439                 if (!ss_wrapper) {
440                         Xml_UseAllocationFunctions();
441                         goto error;
442                 }
443         }
444         else {
445                 if (!FASTXSL_G(nostat)) {
446                         int lockfd;
447                         lockfd = open(ss_filename, O_RDONLY);
448                         if(lockfd < 0) goto error;
449
450                         if (fstat(lockfd, &sb) == -1) {
451                                 ShmCache_UseAllocationFunctions();
452                                 ShmCache_Document_Delete(ss_filename, ss_filename_len TSRMLS_CC);
453                                 Xml_UseAllocationFunctions();
454                                 close(lockfd);
455                                 goto error;
456                         }
457                         if (ss_wrapper->mtime != sb.st_mtime) {
458                                 /* It would be really bad if we longjmp'd out with the lock */
459                                 zend_set_timeout(0);
460                                 ACQUIRE(lockfd);
461                                 ShmCache_UseAllocationFunctions();
462                                 ShmCache_Document_Delete(ss_filename, ss_filename_len TSRMLS_CC);
463                                 Xml_UseAllocationFunctions();
464                                 ss_wrapper = SS_Wrapper_Alloc(FASTXSL_SHARED_ALLOC TSRMLS_CC);
465                                 if(ss_wrapper) {
466                                         int rv;
467                                         ss_wrapper->alloc_type = FASTXSL_SHMALLOC;
468                                         ss_wrapper->data_type = FASTXSL_STYLESHEET;
469                                         ShmCache_UseAllocationFunctions();
470                                         FASTXSL_G(tmp_allocated_size) = 0;
471                                         valuePush(ctxt, xmlXPathObjectCopy(ctxt->value));
472                                         HACK_xsltDocumentFunction(ctxt, nargs);
473                                         ss_wrapper->data.op = xmlXPathObjectCopy(ctxt->value);
474                                         valuePop(ctxt);
475                                         ss_wrapper->allocsize = FASTXSL_G(tmp_allocated_size);
476                                         Xml_UseAllocationFunctions();
477                                         ss_wrapper->mtime = sb.st_mtime;
478                                         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
479                                         rv = fl_hash_add(FASTXSL_G(cache)->table, ss_filename, ss_filename_len, ss_wrapper);
480                                         mm_unlock(FASTXSL_G(cache)->mm);
481                                         if(rv == 0) {
482                                                 /* we failed */
483                                                 php_ss_wrapper *fallback;
484                                                 mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
485                                                 fallback = fl_hash_find(FASTXSL_G(cache)->table, ss_filename, ss_filename_len);
486                                                 mm_unlock(FASTXSL_G(cache)->mm);
487                                                 if(fallback && fallback->data_type == FASTXSL_XPATHOBJ) {
488                                                         ShmCache_UseAllocationFunctions();
489                                                         ShmCache_XPathObject_Free(ss_wrapper);
490                                                         Xml_UseAllocationFunctions();
491                                                         ss_wrapper = fallback;
492                                                 } else {
493                                                 }
494                                         } else {
495                                         }
496                                 }
497                                 RELEASE(lockfd);
498                                 close(lockfd);
499                                 if (!ss_wrapper) {
500                                         goto error;
501                                 }
502                         }
503                 }
504         }
505         Xml_UseAllocationFunctions();
506
507         valuePop(ctxt);
508         valuePush(ctxt, xmlXPathObjectCopy(ss_wrapper->data.op));
509         return;
510 error:
511         ctxt->error = XPATH_INVALID_TYPE;
512         return;
513 }
514 /* }}} */
515 #endif
516
517 static php_ss_wrapper *
518 PrmCache_Stylesheet_ParseAndStore(char *filename, size_t filename_len, int mtime TSRMLS_DC)
519 {
520         php_ss_wrapper *wrapper;
521
522         wrapper = (php_ss_wrapper *) SS_Wrapper_Alloc(FASTXSL_PRM_ALLOC TSRMLS_CC);
523         wrapper->alloc_type = FASTXSL_PRMALLOC;
524
525         wrapper->data.ss = xsltParseStylesheetFile((xmlChar *)filename);
526         wrapper->data_type = FASTXSL_STYLESHEET;
527         if (!wrapper->data.ss) {
528                 return NULL;
529         }
530         wrapper->mtime = mtime;
531        
532         if(fl_hash_add(FASTXSL_G(cache)->prmtable, filename, filename_len, wrapper) == 0) {
533                 /* we failed */
534                 php_ss_wrapper *fallback;
535                 mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
536                 fallback = fl_hash_find(FASTXSL_G(cache)->table, filename, filename_len);
537                 mm_unlock(FASTXSL_G(cache)->mm);
538                 if(fallback) {
539                         ShmCache_Stylesheet_Free(wrapper);
540                         wrapper = fallback;
541                 }
542         }
543
544         return wrapper;
545 }
546
547 static void
548 PrmCache_Stylesheet_Free(php_ss_wrapper *wrapper TSRMLS_DC)
549 {
550         if (wrapper->data_type == FASTXSL_STYLESHEET) {
551                 if (wrapper->data.ss) {
552                         xsltFreeStylesheet(wrapper->data.ss);
553                 }
554                 free(wrapper);
555         }
556 }
557
558 static void
559 PrmCache_XPathObject_Free(php_ss_wrapper *wrapper TSRMLS_DC)
560 {
561         if (wrapper->data_type == FASTXSL_XPATHOBJ) {
562                 if (wrapper->data.op) {
563                         xmlXPathFreeObject(wrapper->data.op);
564                 }
565                 free(wrapper);
566         }
567 }
568
569 static void
570 PrmCache_Document_Delete(char *filename, size_t filename_len TSRMLS_DC)
571 {
572         php_ss_wrapper *wrapper;
573
574         wrapper = fl_hash_find(FASTXSL_G(cache)->prmtable, filename, filename_len);
575         if (wrapper) {
576                 fl_hash_delete(FASTXSL_G(cache)->prmtable, filename, filename_len);
577                 switch(wrapper->data_type) {
578                         case FASTXSL_STYLESHEET:
579                                 PrmCache_Stylesheet_Free(wrapper TSRMLS_CC);
580                                 break;
581                         case FASTXSL_XPATHOBJ:
582                                 PrmCache_XPathObject_Free(wrapper TSRMLS_CC);
583                                 break;
584                         default:
585                                 break;
586                 }
587         }
588 }
589
590 /* {{{ proto array fastxsl_prmcache_getstatistics(void)
591    Get an array of statistics regarding the fastxsl documents in the process resident memory cache */
592 PHP_FUNCTION(fastxsl_prmcache_getstatistics)
593 {
594         php_ss_wrapper *wrapper;       
595
596         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
597                 return;
598         }
599
600 }
601 /* }}} */
602
603 /* {{{ proto array fastxsl_shmcache_getstatistics(void)
604    Get an array of statistics regarding the documents in the shared memory cache */
605 #ifdef FASTXSL_MM
606 PHP_FUNCTION(fastxsl_shmcache_getstatistics)
607 {
608         php_ss_wrapper *ss_wrapper;
609         FL_Bucket      *bucket;
610         zval           *files_array;
611         zval           *info_array;
612         int             i;
613         long            allocated_bytes = 0;
614        
615         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
616                 return;
617         }
618
619         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
620        
621         array_init(return_value);
622
623         MAKE_STD_ZVAL(files_array);
624         array_init(files_array);
625
626         for (i = 0; i < FL_HASH_SIZE; i++) {
627                 for (bucket = FASTXSL_G(cache)->table->buckets[i]; bucket != NULL; bucket = bucket->next) {
628                         ss_wrapper = (php_ss_wrapper *) bucket->data;
629
630                         MAKE_STD_ZVAL(info_array);
631                         array_init(info_array);
632
633                         add_assoc_long(info_array, "allocated", ss_wrapper->allocsize);
634                         add_assoc_long(info_array, "hits", ss_wrapper->hits);
635                         add_assoc_long(info_array, "mtime", ss_wrapper->mtime);
636
637                         add_assoc_zval(files_array, bucket->key, info_array);
638
639                         allocated_bytes += ss_wrapper->allocsize;
640                 }
641         }
642         add_assoc_zval(return_value, "files", files_array);
643
644         add_assoc_long(return_value, "apparent_allocated", allocated_bytes);
645         add_assoc_long(return_value, "real_allocated", mm_maxsize() - mm_available(FASTXSL_G(cache)->mm));
646         add_assoc_long(return_value, "shm_maxsize", (long) mm_maxsize());
647         mm_unlock(FASTXSL_G(cache)->mm);
648 }
649
650 /* {{{ proto array fastxsl_version(void)
651    Returns the version number */
652 PHP_FUNCTION(fastxsl_version)
653 {
654         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
655                 return;
656         }
657         RETURN_STRING(PHP_FASTXSL_VERSION, 1);
658 }
659
660 PHP_FUNCTION(fastxsl_xmlMemoryDump)
661 {
662   chdir("/tmp");
663   xmlMemDisplay(stderr);
664 }
665 #endif
666 /* }}} */
667
668 /* {{{ proto resource fastxsl_stylesheet_parsefile(string filename)
669    Parse a stylesheet file located at filename. */
670 PHP_FUNCTION(fastxsl_stylesheet_parsefile)
671 {
672         php_ss_wrapper *wrapper;
673         char           *filename;
674         size_t          filename_len;
675
676         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename,
677                                 &filename_len) == FAILURE) {
678                 return;
679         }
680
681         wrapper = (php_ss_wrapper *) SS_Wrapper_Alloc(0 TSRMLS_CC);
682         wrapper->alloc_type = FASTXSL_PRMALLOC;
683         Xml_UseAllocationFunctions();
684         wrapper->data.ss = xsltParseStylesheetFile((xmlChar*)filename);
685         if (!wrapper->data.ss) {
686                 RETURN_FALSE;
687         }
688
689         ZEND_REGISTER_RESOURCE(return_value, wrapper, le_fastxsl_stylesheet);
690 }
691 /* }}} */
692
693 /* {{{ proto resource fastxsl_xml_parsestring(string text)
694   Parse a string containing an XML document and return a resource pointer to the resulting libxml2 tree */
695 PHP_FUNCTION(fastxsl_xml_parsestring)
696 {
697         php_xd_wrapper *wrapper;
698         char           *text;
699         size_t          text_len;
700
701         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &text, &text_len) == FAILURE) {
702                 return;
703         }
704
705         wrapper = XD_Wrapper_Alloc();
706         wrapper->alloc_type = FASTXSL_PRMALLOC;
707         Xml_UseAllocationFunctions();
708         wrapper->xd = xmlParseDoc((unsigned char *)text);
709         if (!wrapper->xd) {
710                 _XD_Wrapper_Dtor(wrapper);
711                 RETURN_FALSE;
712         }
713
714         ZEND_REGISTER_RESOURCE(return_value, wrapper, le_fastxsl_document);
715 }
716 /* }}} */
717
718 /* {{{ proto resource fastxsl_xml_parsefile(string filename)
719    Parse an XML file into a FastXSL resource */
720 PHP_FUNCTION(fastxsl_xml_parsefile)
721 {
722         php_xd_wrapper *wrapper;
723         char           *filename;
724         size_t          filename_len;
725
726         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename,
727                                 &filename_len) == FAILURE) {
728                 return;
729         }
730
731         wrapper = XD_Wrapper_Alloc();
732         wrapper->alloc_type = FASTXSL_PRMALLOC;
733         wrapper->xd = xmlParseFile((const char *) filename);
734         if (!wrapper->xd) {
735                 _XD_Wrapper_Dtor(wrapper);
736                 RETURN_FALSE;
737         }
738
739         ZEND_REGISTER_RESOURCE(return_value, wrapper, le_fastxsl_document);
740 }
741 /* }}} */
742
743 static int
744 ParseTransformParameters(zval *z_parameters, char ***parameters TSRMLS_DC)
745 {
746         zval         **current;
747         HashTable     *h_parameters;
748         HashPosition   pos;
749         char          *key;
750         unsigned int   key_length;
751         unsigned long  ival;
752         int            index = 0;
753
754         h_parameters = Z_ARRVAL_P(z_parameters);
755
756         if (zend_hash_num_elements(h_parameters) == 0) {
757                 *parameters = NULL;
758                 return SUCCESS;
759         }
760        
761         *parameters = calloc(1, (1 + zend_hash_num_elements(h_parameters) * 2) * sizeof(char *));
762         if (!*parameters) {
763                 php_error(E_WARNING, "Cannot allocate parameters array to pass to FastXSL");
764                 return FAILURE;
765         }
766        
767         for (zend_hash_internal_pointer_reset_ex(h_parameters, &pos);
768              zend_hash_get_current_data_ex(h_parameters, (void **) &current, &pos) == SUCCESS;
769                  zend_hash_move_forward_ex(h_parameters, &pos)) {
770                 if (zend_hash_get_current_key_ex(h_parameters, &key, &key_length,
771                                         &ival, 0, &pos) == HASH_KEY_IS_LONG) {
772                         efree(*parameters);
773                         *parameters = NULL;
774
775                         php_error(E_WARNING,
776                                         "Parameters array passed to %s() may not contain numeric keys",
777                                         get_active_function_name(TSRMLS_C));
778                         return FAILURE;
779                 }
780
781                 convert_to_string_ex(current);
782
783                 (*parameters)[index++] = key;
784                 (*parameters)[index++] = Z_STRVAL_PP(current);
785         }
786         (*parameters)[index] = NULL;
787
788         return SUCCESS;
789 }
790
791 /* {{{ proto resource fastxsl_shmcache_transform(string filename, resource xmldoc[, array parameters])
792    Transform a XML document, "xmldoc", by a XSL stylesheet "filename" with transform "parameters." */
793 #ifdef FASTXSL_MM
794 PHP_FUNCTION(fastxsl_shmcache_transform)
795 {
796         xsltTransformContextPtr ctxt;
797         char            **parameters = NULL;
798         php_xd_wrapper   *xd_wrapper;
799         php_xd_wrapper   *result_wrapper;
800         php_ss_wrapper   *ss_wrapper;
801         char             *ss_filename;
802         size_t            ss_filename_len;
803         zval             *z_xd_wrapper;
804         zval             *z_parameters;
805         struct stat       sb;
806        
807         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|z", &ss_filename, &ss_filename_len,
808                                 &z_xd_wrapper, &z_parameters) == FAILURE) {
809                 return;
810         }
811        
812         ZEND_FETCH_RESOURCE(xd_wrapper, php_xd_wrapper *, &z_xd_wrapper, -1, "FastXSL XML Document",
813                         le_fastxsl_document);
814
815         if (ZEND_NUM_ARGS() > 2 && Z_TYPE_P(z_parameters) == IS_ARRAY) {
816                 if (ParseTransformParameters(z_parameters, &parameters TSRMLS_CC) == FAILURE) {
817                         RETURN_FALSE;
818                 }
819         }
820
821         result_wrapper = XD_Wrapper_Alloc();
822         result_wrapper->alloc_type = FASTXSL_PRMALLOC;
823
824         sb.st_mtime = 0;
825
826         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RW);
827         ss_wrapper = fl_hash_find(FASTXSL_G(cache)->table, ss_filename, ss_filename_len);
828         if(ss_wrapper) ss_wrapper->hits++;
829         mm_unlock(FASTXSL_G(cache)->mm);
830
831         if (!ss_wrapper) {
832                 int lockfd;
833                 lockfd = open(ss_filename, O_RDONLY);
834                 if(lockfd < 0) RETURN_FALSE;
835
836                 /* It would be really bad if we longjmp'd out with the lock */
837                 zend_set_timeout(0);
838                 /* Create a wait queue -- no herds */
839                 ACQUIRE(lockfd);
840
841                 /* One last check */
842                 mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RW);
843                 ss_wrapper = fl_hash_find(FASTXSL_G(cache)->table, ss_filename, ss_filename_len);
844                 if(ss_wrapper) ss_wrapper->hits++;
845                 mm_unlock(FASTXSL_G(cache)->mm);
846
847                 if(ss_wrapper) {
848                         /* Someone beat us to it */
849                 }
850                 else {
851                         if (fstat(lockfd, &sb) != -1) {
852                                 ShmCache_UseAllocationFunctions();
853                                 ss_wrapper = ShmCache_Stylesheet_ParseAndStore(ss_filename, ss_filename_len, sb.st_mtime);
854                                 Xml_UseAllocationFunctions();
855                         }
856                         if (!ss_wrapper) {
857                                 RELEASE(lockfd);
858                                 close(lockfd);
859                                 goto error;
860                         }
861                 }
862                 RELEASE(lockfd);
863                 close(lockfd);
864         } else {
865                 if (!FASTXSL_G(nostat)) {
866                         int lockfd;
867                         lockfd = open(ss_filename, O_RDONLY);
868                         if(lockfd < 0) RETURN_FALSE;
869                        
870                         if (fstat(lockfd, &sb) == -1) {
871                                 ShmCache_UseAllocationFunctions();
872                                 ShmCache_Document_Delete(ss_filename, ss_filename_len TSRMLS_CC);
873                                 Xml_UseAllocationFunctions();
874                                 close(lockfd);
875                                 goto error;
876                         }
877
878                         /* It would be really bad if we longjmp'd out with the lock */
879                         zend_set_timeout(0);
880                         ACQUIRE(lockfd);
881                         if (ss_wrapper->mtime != sb.st_mtime) {
882                                 ShmCache_UseAllocationFunctions();
883                                 ShmCache_Document_Delete(ss_filename, ss_filename_len TSRMLS_CC);
884                                 ss_wrapper = ShmCache_Stylesheet_ParseAndStore(ss_filename, ss_filename_len, sb.st_mtime TSRMLS_CC);
885                                 Xml_UseAllocationFunctions();
886                                 if (!ss_wrapper) {
887                                         RELEASE(lockfd);
888                                         close(lockfd);
889                                         goto error;
890                                 }
891                         }
892                         RELEASE(lockfd);
893                         close(lockfd);
894                 }
895         }
896
897         ctxt = xsltNewTransformContext(ss_wrapper->data.ss, xd_wrapper->xd);
898 #ifdef FASTXSL_MM
899         if(FASTXSL_G(replace_document_function)) {
900                 xmlXPathFunction func;
901                 func = xmlXPathFunctionLookup(ctxt->xpathCtxt, (const xmlChar *)"document");
902                 xmlXPathRegisterFunc(ctxt->xpathCtxt, (const xmlChar *) "original_document", func);
903                 xmlXPathRegisterFunc(ctxt->xpathCtxt, (const xmlChar *) "document", NULL);
904                 xmlXPathRegisterFunc(ctxt->xpathCtxt, (const xmlChar *) "document",
905                                         fastxsl_CachedDocumentFunction);
906         }
907         xmlXPathRegisterFunc(ctxt->xpathCtxt, (const xmlChar *) "cached_document",
908                                 fastxsl_CachedDocumentFunction);
909 #endif
910         result_wrapper->xd = xsltApplyStylesheetUser(ss_wrapper->data.ss, xd_wrapper->xd,
911                         (const char **) parameters, NULL, NULL, ctxt);
912         xsltFreeTransformContext(ctxt);
913        
914         if (parameters)
915                 free(parameters);
916        
917         if (!result_wrapper->xd) {
918                 RETURN_FALSE;
919         }       
920        
921         ZEND_REGISTER_RESOURCE(return_value, result_wrapper, le_fastxsl_document);
922         return;
923
924         error:
925                 Xml_UseAllocationFunctions();
926                 if (parameters) free(parameters);
927                 _XD_Wrapper_Dtor(result_wrapper);
928                 RETURN_FALSE;
929 }
930 #endif
931 /* }}} */
932
933 /* {{{ proto resource fastxsl_prmcache_transform(string filename, resource xmldoc[, array parameters])
934    Transform a XML document, "xmldoc", by a XSL stylesheet "filename" with transform "parameters." */
935 PHP_FUNCTION(fastxsl_prmcache_transform)
936 {
937         char            **parameters = NULL;
938         php_xd_wrapper   *xd_wrapper;
939         php_xd_wrapper   *result_wrapper;
940         php_ss_wrapper   *ss_wrapper;
941         char             *ss_filename;
942         size_t            ss_filename_len;
943         zval             *z_xd_wrapper;
944         zval             *z_parameters;
945         struct stat       sb;
946        
947         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|z", &ss_filename, &ss_filename_len,
948                                 &z_xd_wrapper, &z_parameters) == FAILURE) {
949                 return;
950         }
951         ZEND_FETCH_RESOURCE(xd_wrapper, php_xd_wrapper *, &z_xd_wrapper, -1, "FastXSL XML Document",
952                         le_fastxsl_document);
953
954         if (ZEND_NUM_ARGS() > 2 && Z_TYPE_P(z_parameters) == IS_ARRAY) {
955                 if (ParseTransformParameters(z_parameters, &parameters TSRMLS_CC) == FAILURE) {
956                         RETURN_FALSE;
957                 }
958         }
959
960         result_wrapper = XD_Wrapper_Alloc();
961         result_wrapper->alloc_type = FASTXSL_PRMALLOC;
962
963         if (!FASTXSL_G(nostat)) {
964                 if (stat(ss_filename, &sb) == -1) {
965                         PrmCache_Document_Delete(ss_filename, ss_filename_len TSRMLS_CC);
966                         _XD_Wrapper_Dtor(result_wrapper);
967                         free(parameters);
968                         RETURN_FALSE;
969                 }
970         } else {
971                 sb.st_mtime = 0;
972         }
973        
974         ss_wrapper = fl_hash_find(FASTXSL_G(cache)->prmtable, ss_filename, ss_filename_len);
975         if (!ss_wrapper) {
976                 ss_wrapper = PrmCache_Stylesheet_ParseAndStore(ss_filename, ss_filename_len, sb.st_mtime TSRMLS_CC);
977                 if (!ss_wrapper) {
978                         _XD_Wrapper_Dtor(result_wrapper);
979                         free(parameters);
980                         RETURN_FALSE;
981                 }
982         } else {
983                 if (!FASTXSL_G(nostat)) {
984                         if (ss_wrapper->mtime != sb.st_mtime) {
985                                 PrmCache_Document_Delete(ss_filename, ss_filename_len TSRMLS_CC);
986                                 ss_wrapper = PrmCache_Stylesheet_ParseAndStore(ss_filename, ss_filename_len, sb.st_mtime TSRMLS_CC);
987                                 if (!ss_wrapper) {
988                                         _XD_Wrapper_Dtor(result_wrapper);
989                                         free(parameters);
990                                         RETURN_FALSE;
991                                 }
992                         }
993                 }
994         }
995         ss_wrapper->hits++;
996         result_wrapper->xd = xsltApplyStylesheet(ss_wrapper->data.ss, xd_wrapper->xd,
997                         (const char **) parameters);
998         ////xmlCleanupParserr();
999
1000         if (parameters)
1001                 free(parameters);
1002        
1003         if (!result_wrapper->xd) {
1004                 _XD_Wrapper_Dtor(result_wrapper);
1005                 RETURN_FALSE;
1006         }       
1007        
1008         ZEND_REGISTER_RESOURCE(return_value, result_wrapper, le_fastxsl_document);
1009 }
1010
1011 /* {{{ proto void fastxsl_nocache_transform(resource stylesheet, resource xmldoc[, array parameters])
1012    Transform the stylesheet document by the xml document with parameters. */
1013 PHP_FUNCTION(fastxsl_nocache_transform)
1014 {
1015         char           **parameters = NULL;
1016         php_xd_wrapper  *xd_wrapper;
1017         php_xd_wrapper  *result_wrapper;
1018         php_ss_wrapper  *ss_wrapper;
1019         zval            *z_xd_wrapper;
1020         zval            *z_ss_wrapper;
1021         zval            *z_parameters;
1022
1023         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|z", &z_ss_wrapper,
1024                                 &z_xd_wrapper, &z_parameters) == FAILURE) {
1025                 return;
1026         }
1027         ZEND_FETCH_RESOURCE(ss_wrapper, php_ss_wrapper *, &z_ss_wrapper, -1, "FastXSL Stylesheet",
1028                         le_fastxsl_stylesheet);
1029         ZEND_FETCH_RESOURCE(xd_wrapper, php_xd_wrapper *, &z_xd_wrapper, -1, "FastXSL XML Document",
1030                         le_fastxsl_document);
1031
1032         if (ZEND_NUM_ARGS() > 2 && Z_TYPE_P(z_parameters) == IS_ARRAY) {
1033                 if (ParseTransformParameters(z_parameters, &parameters TSRMLS_CC) == FAILURE) {
1034                         RETURN_FALSE;
1035                 }
1036         }
1037
1038         result_wrapper = XD_Wrapper_Alloc();
1039         result_wrapper->alloc_type = FASTXSL_PRMALLOC;
1040         result_wrapper->xd = xsltApplyStylesheet(ss_wrapper->data.ss, xd_wrapper->xd,
1041                         (const char **) parameters);
1042         if (parameters)
1043                 free(parameters);
1044
1045         if (!result_wrapper->xd) {
1046                 _XD_Wrapper_Dtor(result_wrapper);
1047                 RETURN_FALSE;
1048         }       
1049
1050        
1051         ZEND_REGISTER_RESOURCE(return_value, result_wrapper, le_fastxsl_document);
1052 }
1053 /* }}} */
1054
1055 /* {{{ proto void fastxsl_nocache_profile(resource stylesheet, resource xmldoc[, array parameters, string filename])
1056    Profile the stylesheet document by the xml document with parameters and output the results to filename (or stderr, if filename doesn't exist). */
1057 PHP_FUNCTION(fastxsl_nocache_profile)
1058 {
1059         char           **parameters = NULL;
1060         char            *filename = "php://stderr";
1061         php_xd_wrapper  *xd_wrapper;
1062         php_xd_wrapper  *result_wrapper;
1063         php_ss_wrapper  *ss_wrapper;
1064         zval            *z_xd_wrapper;
1065         zval            *z_ss_wrapper;
1066         zval            *z_parameters;
1067         FILE            *dbgprof;
1068         int              filename_len;
1069
1070         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|zs", &z_ss_wrapper,
1071                                 &z_xd_wrapper, &z_parameters, &filename, &filename_len) == FAILURE) {
1072                 return;
1073         }
1074         ZEND_FETCH_RESOURCE(ss_wrapper, php_ss_wrapper *, &z_ss_wrapper, -1, "FastXSL Stylesheet",
1075                         le_fastxsl_stylesheet);
1076         ZEND_FETCH_RESOURCE(xd_wrapper, php_xd_wrapper *, &z_xd_wrapper, -1, "FastXSL XML Document",
1077                         le_fastxsl_document);
1078
1079         if (ZEND_NUM_ARGS() > 2 && Z_TYPE_P(z_parameters) == IS_ARRAY) {
1080                 if (ParseTransformParameters(z_parameters, &parameters TSRMLS_CC) == FAILURE) {
1081                         RETURN_FALSE;
1082                 }
1083         }
1084
1085         if (!strcmp(filename, "php://stdout")) {
1086                 dbgprof = stdout;
1087         } else if (!strcmp(filename, "php://stderr")) {
1088                 dbgprof = stderr;
1089         } else {
1090                 dbgprof = fopen(filename, "w");
1091         }
1092
1093         result_wrapper = XD_Wrapper_Alloc();
1094         result_wrapper->alloc_type = FASTXSL_PRMALLOC;
1095
1096         result_wrapper->xd = xsltProfileStylesheet(ss_wrapper->data.ss, xd_wrapper->xd,
1097                         (const char **) parameters, dbgprof);
1098         if (parameters)
1099                 free(parameters);
1100
1101         fclose(dbgprof);
1102        
1103         if (!result_wrapper->xd) {
1104                 _XD_Wrapper_Dtor(result_wrapper);
1105                 RETURN_FALSE;
1106         }       
1107        
1108         ZEND_REGISTER_RESOURCE(return_value, result_wrapper, le_fastxsl_document);
1109 }
1110 /* }}} */
1111
1112 /* {{{ proto string fastxsl_nocache_tostring(resource stylesheet, resource xmldoc)
1113    Return the contents of an XML stylesheet result as a string */
1114 PHP_FUNCTION(fastxsl_nocache_tostring)
1115 {
1116         zval           *z_xd_wrapper;
1117         zval           *z_ss_wrapper;
1118         php_ss_wrapper *ss_wrapper;
1119         php_xd_wrapper *xd_wrapper;
1120         xmlChar        *result = NULL;
1121         int             length;
1122
1123         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &z_ss_wrapper,
1124                                 &z_xd_wrapper) == FAILURE) {
1125                 return;
1126         }
1127         ZEND_FETCH_RESOURCE(ss_wrapper, php_ss_wrapper *, &z_ss_wrapper, -1, "FastXSL XML Stylesheet",
1128                         le_fastxsl_stylesheet);
1129         ZEND_FETCH_RESOURCE(xd_wrapper, php_xd_wrapper *, &z_xd_wrapper, -1, "FastXSL XML Document",
1130                         le_fastxsl_document);
1131
1132         xsltSaveResultToString(&result, &length, xd_wrapper->xd, ss_wrapper->data.ss);
1133
1134         if (result) {
1135                 RETVAL_STRINGL((char *) result, length, 1);
1136                 xmlFree(result);
1137         } else {
1138                 RETURN_FALSE;
1139         }
1140 }
1141 /* }}} */
1142
1143 /* {{{ proto string fastxsl_shmcache_tostring(string filename, resource xmldoc)
1144    Return the string representation of xmldoc which is the result of an XSLT transformation on filename */
1145 #ifdef FASTXSL_MM
1146 PHP_FUNCTION(fastxsl_shmcache_tostring)
1147 {
1148         zval           *z_xd_wrapper;
1149         php_ss_wrapper *ss_wrapper;
1150         php_xd_wrapper *xd_wrapper;
1151         xmlChar        *result = NULL;
1152         char           *ss_filename;
1153         size_t          ss_filename_len;
1154         int             length;
1155
1156         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &ss_filename, &ss_filename_len,
1157                                 &z_xd_wrapper) == FAILURE) {
1158                 return;
1159         }
1160         ZEND_FETCH_RESOURCE(xd_wrapper, php_xd_wrapper *, &z_xd_wrapper, -1, "FastXSL XML Document",
1161                         le_fastxsl_document);
1162         Xml_UseAllocationFunctions();
1163         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
1164         ss_wrapper = fl_hash_find(FASTXSL_G(cache)->table, ss_filename, ss_filename_len);
1165         mm_unlock(FASTXSL_G(cache)->mm);
1166         if (!ss_wrapper) {
1167                 RETURN_FALSE;
1168         }
1169         ss_wrapper->hits++;
1170         xsltSaveResultToString(&result, &length, xd_wrapper->xd, ss_wrapper->data.ss);
1171         if (result) {
1172                 RETVAL_STRINGL((char *) result, length, 1);
1173                 xmlFree(result);
1174         } else {
1175                 RETVAL_FALSE;
1176         }
1177         Xml_UseAllocationFunctions();
1178 }
1179 #endif
1180 /* }}} */
1181
1182 /* {{{ proto string fastxsl_prmcache_tostring(string filename, resource xmldoc)
1183    Return the string representation of xmldoc which is the result of an XSLT transformation on filename */
1184 PHP_FUNCTION(fastxsl_prmcache_tostring)
1185 {
1186         zval           *z_xd_wrapper;
1187         php_ss_wrapper *ss_wrapper;
1188         php_xd_wrapper *xd_wrapper;
1189         xmlChar        *result = NULL;
1190         char           *ss_filename;
1191         size_t          ss_filename_len;
1192         int             length;
1193
1194         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &ss_filename, &ss_filename_len,
1195                                 &z_xd_wrapper) == FAILURE) {
1196                 return;
1197         }
1198         ZEND_FETCH_RESOURCE(xd_wrapper, php_xd_wrapper *, &z_xd_wrapper, -1, "FastXSL XML Document",
1199                         le_fastxsl_document);
1200
1201         ss_wrapper = fl_hash_find(FASTXSL_G(cache)->prmtable, ss_filename, ss_filename_len);
1202         if (!ss_wrapper) {
1203                 RETURN_FALSE;
1204         }
1205         ss_wrapper->hits++;
1206         xsltSaveResultToString(&result, &length, xd_wrapper->xd, ss_wrapper->data.ss);
1207        
1208         if (result) {
1209                 RETVAL_STRINGL((char *) result, length, 1);
1210                 xmlFree(result);
1211         } else {
1212                 RETURN_FALSE;
1213         }
1214 }
1215 /* }}} */
1216
1217 function_entry fastxsl_functions[] = {
1218         PHP_FE(fastxsl_stylesheet_parsefile,         NULL)
1219         PHP_FE(fastxsl_xml_parsefile,                NULL)
1220         PHP_FE(fastxsl_xml_parsestring,              NULL)
1221         PHP_FE(fastxsl_version,                      NULL)
1222 #ifdef FASTXSL_MM
1223         PHP_FE(fastxsl_shmcache_transform,           NULL)
1224         PHP_FE(fastxsl_shmcache_tostring,            NULL)
1225         PHP_FE(fastxsl_shmcache_getstatistics,       NULL)
1226         PHP_FE(fastxsl_xmlMemoryDump,                NULL)
1227 #endif
1228         PHP_FE(fastxsl_prmcache_transform,           NULL)
1229         PHP_FE(fastxsl_nocache_transform,            NULL)
1230         PHP_FE(fastxsl_nocache_profile,              NULL)
1231         PHP_FE(fastxsl_nocache_tostring,             NULL)
1232         PHP_FE(fastxsl_prmcache_tostring,            NULL)
1233         PHP_FE(fastxsl_prmcache_getstatistics,       NULL)
1234         {NULL, NULL, NULL}
1235 };
1236
1237
1238 zend_module_entry fastxsl_module_entry = {
1239 #if ZEND_MODULE_API_NO >= 20010901
1240         STANDARD_MODULE_HEADER,
1241 #endif
1242         "fastxsl",
1243         fastxsl_functions,
1244         PHP_MINIT(fastxsl),
1245         PHP_MSHUTDOWN(fastxsl),
1246         PHP_RINIT(fastxsl),
1247         PHP_RSHUTDOWN(fastxsl),
1248         PHP_MINFO(fastxsl),
1249 #if ZEND_MODULE_API_NO >= 20010901
1250         "0.1",
1251 #endif
1252         STANDARD_MODULE_PROPERTIES
1253 };
1254
1255
1256 #ifdef COMPILE_DL_FASTXSL
1257 ZEND_GET_MODULE(fastxsl)
1258 #endif
1259
1260 static void
1261 _SS_Wrapper_Dtor(php_ss_wrapper *wrapper)
1262 {
1263         if(wrapper->data.ss) {
1264                 if(wrapper->alloc_type == FASTXSL_SHMALLOC) {
1265                         //xmlCleanupParserr();
1266                         ShmCache_UseAllocationFunctions();
1267                 } else {
1268                         Xml_UseAllocationFunctions();
1269                 }
1270                 xsltFreeStylesheet(wrapper->data.ss);
1271                 if(wrapper->alloc_type == FASTXSL_SHMALLOC) {
1272                         //xmlCleanupParserr();
1273                         Xml_UseAllocationFunctions();
1274                 }
1275         }
1276         if(wrapper->persistant) {
1277                 mm_free(FASTXSL_G(cache)->mm, wrapper);
1278         } else {
1279                 free(wrapper);
1280         }
1281 }
1282
1283 static void
1284 SS_Wrapper_Dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
1285 {
1286         php_ss_wrapper *wrapper = (php_ss_wrapper *) rsrc->ptr;
1287         if (wrapper->persistant) {
1288                 return;
1289         }
1290         _SS_Wrapper_Dtor(wrapper);
1291 }
1292
1293 static void _XD_Wrapper_Dtor(php_xd_wrapper *wrapper) {
1294         if (wrapper->xd) {
1295                 if(wrapper->alloc_type == FASTXSL_SHMALLOC) {
1296                         ShmCache_UseAllocationFunctions();
1297                 } else {
1298                         Xml_UseAllocationFunctions();
1299                 }
1300                 xmlFreeDoc(wrapper->xd);
1301                 Xml_UseAllocationFunctions();
1302         }
1303         free(wrapper);
1304 }
1305
1306 static void
1307 XD_Wrapper_Dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
1308 {
1309         php_xd_wrapper *wrapper = (php_xd_wrapper *) rsrc->ptr;
1310         _XD_Wrapper_Dtor(wrapper);
1311 }
1312
1313 void fastxsl_errorfunc(void *ctx, const char *msg, ...)
1314 {
1315         char *frag;
1316         int fraglen;
1317         int output = 0;
1318         va_list args;
1319         TSRMLS_FETCH();
1320
1321         va_start(args, msg);
1322         fraglen = vspprintf(&frag, 0, msg, args);
1323         while(fraglen && frag[fraglen - 1] == '\n') {
1324                 frag[--fraglen] = '\0';
1325                 output = 1;
1326         }
1327         if(fraglen) {
1328                 if(FASTXSL_G(errbuf)) {
1329                         FASTXSL_G(errbuf) = erealloc(FASTXSL_G(errbuf), fraglen + strlen(FASTXSL_G(errbuf)));
1330                         strcat(FASTXSL_G(errbuf), frag);
1331                 } else {
1332                         FASTXSL_G(errbuf) = frag;
1333                 }
1334         }
1335         va_end(args);
1336         if(output) {
1337                 php_error_docref(NULL TSRMLS_CC, E_WARNING, FASTXSL_G(errbuf));
1338                 efree(FASTXSL_G(errbuf));
1339                 FASTXSL_G(errbuf) = NULL;
1340         }
1341 }
1342
1343 static int
1344 Stream_MatchWrapper(const char *filename)
1345 {
1346         TSRMLS_FETCH();
1347         return php_stream_locate_url_wrapper(filename, NULL, STREAM_LOCATE_WRAPPERS_ONLY TSRMLS_CC) ? 1 : 0;
1348 }
1349
1350 static void *
1351 Stream_XmlWrite_OpenWrapper(const char *filename)
1352 {
1353         TSRMLS_FETCH();
1354         return php_stream_open_wrapper((char *) filename, "wb", ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL);
1355 }
1356
1357 static int
1358 Stream_XmlWrite_WriteWrapper(void *context, const char *buffer, int length)
1359 {
1360         TSRMLS_FETCH();
1361         return php_stream_write((php_stream *) context, (char *) buffer, length);
1362 }
1363
1364 static int
1365 Stream_CloseWrapper(void *context)
1366 {
1367         TSRMLS_FETCH();
1368         return php_stream_close((php_stream *) context);
1369 }
1370
1371
1372 extern int xmlLoadExtDtdDefaultValue;
1373
1374 /**
1375  * Allocators for the fl_hash storage
1376  */
1377 #ifdef FASTXSL_MM
1378 static FL_Allocator mm_allocators = {ShmCache_Free, ShmCache_Malloc, ShmCache_Calloc};
1379 #endif
1380 static FL_Allocator normal_allocators = {free, malloc, calloc};
1381
1382 static void
1383 php_fastxsl_init_globals(zend_fastxsl_globals *globals)
1384 {
1385         memset(globals, 0, sizeof(zend_fastxsl_globals));
1386        
1387         globals->cache = calloc(1, sizeof(fl_cache));
1388 }
1389
1390
1391 static void
1392 php_fastxsl_destroy_globals(zend_fastxsl_globals *globals)
1393 {
1394         fl_cache *cache;
1395        
1396         cache = globals->cache;
1397         if (cache) {
1398                 if (cache->owner != getpid()) {
1399                         return;
1400                 }
1401                 fl_hash_free(cache->prmtable);
1402         }
1403 }
1404
1405 /* {{{ php function -> xslt exporting
1406  */
1407  
1408 static void fastxsl_ext_function(xmlXPathParserContextPtr ctxt, int nargs)
1409 {
1410         xsltTransformContextPtr tctxt;
1411         zval **params;
1412         zval *param;
1413         zval *function = NULL;
1414         zval *ret = NULL;
1415         xmlChar *fname;
1416         int param_count = nargs - 1;
1417         int i;
1418         TSRMLS_FETCH();
1419        
1420         tctxt = (xsltTransformContextPtr) xsltXPathGetTransformContext(ctxt);
1421         ////xmlCleanupParserr();
1422         if (tctxt == NULL) {
1423                 xsltGenericError(xsltGenericErrorContext,
1424                 "fastxsl extension functions: failed to get the transformation context\n");
1425                 return;
1426         }
1427         /* allocate for args.  first position is function name */
1428         params = emalloc(sizeof(zval *) * param_count);
1429         for(i = param_count - 1; i >=0; i--) {
1430                 xmlXPathObjectPtr obj;
1431                 xmlChar *tmp;
1432                 obj = valuePop(ctxt);
1433                 MAKE_STD_ZVAL(param);
1434                 switch(obj->type) {
1435                         case XPATH_UNDEFINED:
1436                                 ZVAL_NULL(param);
1437                                 break;
1438                         case XPATH_NODESET:
1439                                 tmp = xmlXPathCastToString(obj);
1440                                 ZVAL_STRING(param, (char *) tmp, 1);
1441                                 xmlFree(tmp);
1442                                 break;
1443                         case XPATH_BOOLEAN:
1444                                 ZVAL_BOOL(param, obj->boolval);
1445                                 break;
1446                         case XPATH_NUMBER:
1447                                 ZVAL_DOUBLE(param, obj->floatval);
1448                                 break;
1449                         case XPATH_STRING:
1450                                 ZVAL_STRING(param, (char *)obj->stringval, 1);
1451                                 break;
1452                         default:
1453                                 zend_error(E_WARNING, "inexact type conversion %d", obj->type);
1454                                 tmp = xmlXPathCastToString(obj);
1455                                 ZVAL_STRING(param, (char *)tmp, 1);
1456                                 xmlFree(tmp);
1457                                 break;
1458                 }
1459                 params[i] = param;
1460                 xmlXPathFreeObject(obj);
1461         }
1462         fname = xmlXPathPopString(ctxt);
1463         if(!fname) {
1464                 xsltGenericError(xsltGenericDebugContext,
1465                         "passed function name is not a string");
1466                 xmlXPathReturnEmptyString(ctxt);
1467                 goto cleanup;
1468         }
1469         MAKE_STD_ZVAL(function);
1470         ZVAL_STRING(function, (char *)fname, 1);
1471         xmlFree(fname);
1472         MAKE_STD_ZVAL(ret);
1473         ZVAL_FALSE(ret);
1474         if(call_user_function(EG(function_table), NULL, function, ret,
1475                                  param_count, params TSRMLS_CC) == FAILURE) {
1476                         xsltGenericError(xsltGenericDebugContext,
1477                                 "function evaluation error");
1478                 xmlXPathReturnEmptyString(ctxt);
1479                 goto cleanup;
1480         }
1481         switch(ret->type) {
1482                 case IS_BOOL:
1483                         xmlXPathReturnBoolean(ctxt, Z_BVAL_P(ret));
1484                         break;
1485                 case IS_LONG:
1486                         xmlXPathReturnNumber(ctxt, (float) Z_LVAL_P(ret));
1487                         break;
1488                 case IS_DOUBLE:
1489                         xmlXPathReturnNumber(ctxt, Z_DVAL_P(ret));
1490                         break;
1491                 case IS_STRING:
1492                         xmlXPathReturnString(ctxt, xmlStrdup((xmlChar *) Z_STRVAL_P(ret)));
1493                         break;
1494                 default:
1495                         convert_to_string_ex(&ret);
1496                         xmlXPathReturnString(ctxt, xmlStrdup((xmlChar *) Z_STRVAL_P(ret)));
1497                         break;
1498         }
1499 cleanup:
1500         if(params) {
1501                 for(i=0; i < param_count; i++) {
1502                         zval_ptr_dtor(&params[i]);
1503                 }
1504                 efree(params); params = NULL;
1505         }
1506         if(function) {
1507                 efree(function); function = NULL;
1508         }
1509         if(ret) {
1510                 efree(ret); ret = NULL;
1511         }
1512         return;
1513 }               
1514 /* }}} */
1515
1516
1517 PHP_INI_BEGIN()
1518         STD_PHP_INI_ENTRY("fastxsl.shmpath", "/tmp/fastxsl_mem", PHP_INI_SYSTEM, OnUpdateString, shmpath, zend_fastxsl_globals, fastxsl_globals)
1519         STD_PHP_INI_BOOLEAN("fastxsl.nostat", "0", PHP_INI_ALL, OnUpdateLong, nostat, zend_fastxsl_globals, fastxsl_globals)
1520         STD_PHP_INI_BOOLEAN("fastxsl.replace_document_function", "0", PHP_INI_ALL, OnUpdateLong, replace_document_function, zend_fastxsl_globals, fastxsl_globals)
1521         STD_PHP_INI_BOOLEAN("fastxsl.memalloc", "0", PHP_INI_SYSTEM, OnUpdateLong, memalloc, zend_fastxsl_globals, fastxsl_globals)
1522         STD_PHP_INI_BOOLEAN("fastxsl.register_functions", "0", PHP_INI_ALL, OnUpdateLong, register_functions, zend_fastxsl_globals, fastxsl_globals)
1523 PHP_INI_END()
1524
1525 PHP_MINIT_FUNCTION(fastxsl)
1526 {
1527         char   *shmpath;
1528         size_t  shmpath_len;
1529         char    euid[30];
1530
1531         ZEND_INIT_MODULE_GLOBALS(fastxsl, php_fastxsl_init_globals, php_fastxsl_destroy_globals);
1532        
1533         REGISTER_INI_ENTRIES();
1534        
1535         le_fastxsl_stylesheet = zend_register_list_destructors_ex(SS_Wrapper_Dtor, NULL,
1536         le_fastxsl_stylesheet_name, module_number);
1537         le_fastxsl_document   = zend_register_list_destructors_ex(XD_Wrapper_Dtor, NULL,
1538                         le_fastxsl_document_name,   module_number);
1539 #ifdef FASTXSL_MM
1540         if (!sprintf(euid, "%d", geteuid())) {
1541                 return FAILURE;
1542         }
1543
1544         shmpath_len = strlen(FASTXSL_G(shmpath)) + strlen(euid);
1545         shmpath = do_alloca(shmpath_len + 1);
1546
1547         strcpy(shmpath, FASTXSL_G(shmpath));
1548         strcat(shmpath, euid);
1549        
1550         FASTXSL_G(cache)->owner = getpid();
1551         FASTXSL_G(cache)->mm = mm_create(FASTXSL_G(memalloc), shmpath);
1552         free_alloca(shmpath);
1553         if (!FASTXSL_G(cache)->mm) {
1554                 return FAILURE;
1555         }
1556
1557         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RW);
1558         FASTXSL_G(cache)->table = fl_hash_new(&mm_allocators, NULL);
1559         mm_unlock(FASTXSL_G(cache)->mm);
1560 #endif
1561         FASTXSL_G(cache)->prmtable = fl_hash_new(&normal_allocators, NULL);
1562         //xmlGcMemGet(&free_ptr, &malloc_ptr, &mallocatomic_ptr, &realloc_ptr, &strdup_ptr);
1563         xmlMemGet(&free_ptr, &malloc_ptr, &realloc_ptr, &strdup_ptr);
1564         //xmlCleanupParserr();
1565         ShmCache_UseAllocationFunctions();
1566         xsltRegisterAllExtras();
1567 #if HAVE_DOMEXSLT
1568         exsltRegisterAll();
1569 #endif
1570         xmlSubstituteEntitiesDefault(1);
1571         xmlLoadExtDtdDefaultValue = 1;
1572
1573         xmlRegisterOutputCallbacks(Stream_MatchWrapper, Stream_XmlWrite_OpenWrapper,
1574                                            Stream_XmlWrite_WriteWrapper, Stream_CloseWrapper);
1575         xsltSetGenericErrorFunc(NULL, fastxsl_errorfunc);
1576         xmlSetGenericErrorFunc(NULL, fastxsl_errorfunc);
1577        
1578         if(FASTXSL_G(register_functions)) {
1579                 xsltRegisterExtModuleFunction ((const xmlChar *) "function",
1580                                            (const xmlChar *) "http://php.net/fastxsl",
1581                                            fastxsl_ext_function);
1582         }
1583         xsltRegisterExtModuleFunction ((const xmlChar *) "cached_document",
1584                                    (const xmlChar *) "http://php.net/fastxsl/cached_document",
1585                                    fastxsl_CachedDocumentFunction);
1586         //xmlCleanupParserr();
1587         Xml_UseAllocationFunctions();
1588         return SUCCESS;
1589 }
1590
1591 PHP_MSHUTDOWN_FUNCTION(fastxsl)
1592 {
1593   UNREGISTER_INI_ENTRIES();
1594 }
1595 PHP_RINIT_FUNCTION(fastxsl)
1596 {
1597 #ifdef FASTXSL_MM
1598   /* just in case, set back the allocators */
1599   Xml_UseAllocationFunctions();
1600 #endif
1601 }
1602 PHP_RSHUTDOWN_FUNCTION(fastxsl)
1603 {
1604 #ifdef FASTXSL_MM
1605   /* just in case, set back the allocators */
1606   Xml_UseAllocationFunctions();
1607 #endif
1608 }
1609
1610 PHP_MINFO_FUNCTION(fastxsl)
1611 {
1612         php_info_print_table_start();
1613         php_info_print_table_header(2, "fastxsl support", "enabled");
1614         php_info_print_table_row(2, "libxml Version", LIBXML_DOTTED_VERSION);
1615         php_info_print_table_row(2, "libxslt Version", LIBXSLT_DOTTED_VERSION);
1616 #if HAVE_DOMEXSLT
1617         php_info_print_table_row(2, "libexslt Version", LIBEXSLT_DOTTED_VERSION);
1618 #endif
1619         php_info_print_table_end();
1620 }
Note: See TracBrowser for help on using the browser.