source: eaccelerator/trunk/eaccelerator.c @ 406

Revision 406, 74.5 KB checked in by hans, 7 months ago (diff)

php_check_open_basedir only needs to be called when restoring

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2   +----------------------------------------------------------------------+
3   | eAccelerator project                                                 |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 2004 - 2010 eAccelerator                               |
6   | http://eaccelerator.net                                              |
7   +----------------------------------------------------------------------+
8   | This program is free software; you can redistribute it and/or        |
9   | modify it under the terms of the GNU General Public License          |
10   | as published by the Free Software Foundation; either version 2       |
11   | of the License, or (at your option) any later version.               |
12   |                                                                      |
13   | This program is distributed in the hope that it will be useful,      |
14   | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
15   | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        |
16   | GNU General Public License for more details.                         |
17   |                                                                      |
18   | You should have received a copy of the GNU General Public License    |
19   | along with this program; if not, write to the Free Software          |
20   | Foundation, Inc., 59 Temple Place - Suite 330, Boston,               |
21   | MA  02111-1307, USA.                                                 |
22   |                                                                      |
23   | A copy is availble at http://www.gnu.org/copyleft/gpl.txt            |
24   +----------------------------------------------------------------------+
25   $Id$
26*/
27
28#include "eaccelerator.h"
29#include "eaccelerator_version.h"
30
31#ifdef HAVE_EACCELERATOR
32
33#include "opcodes.h"
34
35#include "zend.h"
36#include "zend_API.h"
37#include "zend_extensions.h"
38
39#include "debug.h"
40#include "ea_store.h"
41#include "ea_restore.h"
42#include "ea_info.h"
43#include "ea_dasm.h"
44
45#include <sys/types.h>
46#include <sys/stat.h>
47#ifdef ZEND_WIN32
48#  include "fnmatch.h"
49#  include "win32/time.h"
50#  include <time.h>
51#  include <sys/utime.h>
52#else
53#  include <fnmatch.h>
54#  include <sys/file.h>
55#  include <sys/time.h>
56#  include <utime.h>
57#endif
58#include <fcntl.h>
59
60#ifndef O_BINARY
61#  define O_BINARY 0
62#endif
63
64#include "php.h"
65#include "php_ini.h"
66#include "php_logos.h"
67#include "main/fopen_wrappers.h"
68#include "ext/standard/info.h"
69#include "ext/standard/php_incomplete_class.h"
70#include "ext/standard/md5.h"
71
72#include "SAPI.h"
73
74#define MAX_DUP_STR_LEN 256
75
76/* Globals (different for each process/thread) */
77ZEND_DECLARE_MODULE_GLOBALS(eaccelerator)
78
79/* Globals (common for each process/thread) */
80static long ea_shm_size = 0;
81long ea_shm_max = 0;
82static long ea_shm_ttl = 0;
83static long ea_shm_prune_period = 0;
84extern long ea_debug;
85zend_bool ea_scripts_shm_only = 0;
86
87eaccelerator_mm* ea_mm_instance = NULL;
88static int ea_is_zend_extension = 0;
89static int ea_is_extension      = 0;
90zend_extension* ZendOptimizer = NULL;
91
92static HashTable ea_global_function_table;
93static HashTable ea_global_class_table;
94
95int binary_eaccelerator_version[2];
96int binary_php_version[2];
97int binary_zend_version[2];
98
99/* pointer to the properties_info hashtable destructor */
100extern dtor_func_t properties_info_dtor;
101
102/* saved original functions */
103static zend_op_array *(*ea_saved_zend_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
104
105#ifdef DEBUG
106static void (*ea_saved_zend_execute)(zend_op_array *op_array TSRMLS_DC);
107#endif
108
109/* external declarations */
110PHPAPI void php_stripslashes(char *str, int *len TSRMLS_DC);
111
112ZEND_DLEXPORT zend_op_array* eaccelerator_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC);
113
114/******************************************************************************/
115/* hash mm functions                                                          */
116/******************************************************************************/
117
118/* Find a script entry with the given hash key */
119static ea_cache_entry* hash_find_mm(const char  *key,
120                                    struct stat *buf,
121                                    int         *nreloads,
122                                    time_t      ttl TSRMLS_DC) {
123  unsigned int hv, slot;
124  ea_cache_entry *p, *q;
125
126  hv = zend_get_hash_value((char *)key, strlen(key));
127  slot = hv & EA_HASH_MAX;
128
129  EACCELERATOR_LOCK_RW();
130  q = NULL;
131  p = ea_mm_instance->hash[slot];
132  while (p != NULL) {
133    if ((p->hv == hv) && (strcmp(p->realfilename, key) == 0)) {
134      if (EAG(check_mtime_enabled) && ea_mm_instance->check_mtime_enabled &&
135          (buf->st_mtime != p->mtime || buf->st_size != p->filesize)) {
136        /* key is invalid. Remove it. */
137        *nreloads = p->nreloads+1;
138        if (q == NULL) {
139          ea_mm_instance->hash[slot] = p->next;
140        } else {
141          q->next = p->next;
142        }
143        ea_mm_instance->hash_cnt--;
144        if (p->use_cnt > 0) {
145          /* key is used by other process/thread. Schedule it for removal */
146          p->removed = 1;
147          p->next = ea_mm_instance->removed;
148          ea_mm_instance->removed = p;
149          ea_mm_instance->rem_cnt++;
150          EACCELERATOR_UNLOCK_RW();
151          return NULL;
152        } else {
153          /* key is unused. Remove it. */
154          eaccelerator_free_nolock(p);
155          EACCELERATOR_UNLOCK_RW();
156          return NULL;
157        }
158      } else {
159        /* key is valid */
160        p->nhits++;
161        p->use_cnt++;
162        p->ttl = ttl;
163        EACCELERATOR_UNLOCK_RW();
164        return p;
165      }
166    }
167    q = p;
168    p = p->next;
169  }
170  EACCELERATOR_UNLOCK_RW();
171  return NULL;
172}
173
174/* Add a new entry to the hashtable */
175static void hash_add_mm(ea_cache_entry *x) {
176  ea_cache_entry *p,*q;
177  unsigned int slot;
178  x->hv = zend_get_hash_value(x->realfilename, strlen(x->realfilename));
179  slot = x->hv & EA_HASH_MAX;
180
181  EACCELERATOR_LOCK_RW();
182  x->next = ea_mm_instance->hash[slot];
183  ea_mm_instance->hash[slot] = x;
184  ea_mm_instance->hash_cnt++;
185  q = x;
186  p = x->next;
187  while (p != NULL) {
188    if ((p->hv == x->hv) &&
189        (strcmp(p->realfilename, x->realfilename) == 0)) {
190      q->next = p->next;
191      ea_mm_instance->hash_cnt--;
192      ea_mm_instance->hash[slot]->nreloads += p->nreloads;
193      if (p->use_cnt > 0) {
194        /* key is used by other process/thread. Shedule it to remove */
195        p->removed = 1;
196        p->next = ea_mm_instance->removed;
197        ea_mm_instance->removed = p;
198        ea_mm_instance->rem_cnt++;
199        EACCELERATOR_UNLOCK_RW();
200        return;
201      } else {
202        /* key is unused. Remove it. */
203        eaccelerator_free_nolock(p);
204        EACCELERATOR_UNLOCK_RW();
205        return;
206      }
207    }
208    q = p;
209    p = p->next;
210  }
211  EACCELERATOR_UNLOCK_RW();
212}
213
214/* Initialise the shared memory */
215static int init_mm(TSRMLS_D) {
216  pid_t  owner = getpid();
217  MM     *mm;
218  size_t total;
219  char   mm_path[MAXPATHLEN];
220
221#ifdef ZEND_WIN32
222    snprintf(mm_path, MAXPATHLEN, "%s.%s", EACCELERATOR_MM_FILE, sapi_module.name);
223#else
224    snprintf(mm_path, MAXPATHLEN, "%s.%s%d", EACCELERATOR_MM_FILE, sapi_module.name, owner);
225#endif
226/*  snprintf(mm_path, MAXPATHLEN, "%s.%s%d", EACCELERATOR_MM_FILE, sapi_module.name, geteuid());*/
227  if ((ea_mm_instance = (eaccelerator_mm*)mm_attach(ea_shm_size*1024*1024, mm_path)) != NULL) {
228#ifdef ZTS
229    ea_mutex = tsrm_mutex_alloc();
230#endif
231    return SUCCESS;
232  }
233  mm = mm_create(ea_shm_size*1024*1024, mm_path);
234  if (!mm) {
235    return FAILURE;
236  }
237#ifdef ZEND_WIN32
238  DBG(ea_debug_printf, (EA_DEBUG, "init_mm [%d]\n", owner));
239#else
240  DBG(ea_debug_printf, (EA_DEBUG, "init_mm [%d,%d]\n", owner, getppid()));
241#endif
242#ifdef ZTS
243  ea_mutex = tsrm_mutex_alloc();
244#endif
245  total = mm_available(mm);
246  ea_mm_instance = mm_malloc_lock(mm, sizeof(*ea_mm_instance));
247  if (!ea_mm_instance) {
248    return FAILURE;
249  }
250  mm_set_attach(mm, ea_mm_instance);
251  memset(ea_mm_instance, 0, sizeof(*ea_mm_instance));
252  ea_mm_instance->owner = owner;
253  ea_mm_instance->mm    = mm;
254  ea_mm_instance->total = total;
255  ea_mm_instance->hash_cnt = 0;
256  ea_mm_instance->rem_cnt  = 0;
257  ea_mm_instance->enabled = 1;
258  ea_mm_instance->optimizer_enabled = 1;
259  ea_mm_instance->check_mtime_enabled = 1;
260  ea_mm_instance->removed = NULL;
261  ea_mm_instance->last_prune = time(NULL);      /* this time() call is harmless since this is init phase */
262  EACCELERATOR_PROTECT();
263  return SUCCESS;
264}
265
266/* Clean up the shared memory */
267static void shutdown_mm(TSRMLS_D) {
268  if (ea_mm_instance) {
269#ifdef ZEND_WIN32
270    if (ea_mm_instance->owner == getpid()) {
271#else
272    if (getpgrp() == getpid()) {
273#endif
274      MM *mm = ea_mm_instance->mm;
275#ifdef ZEND_WIN32
276      DBG(ea_debug_printf, (EA_DEBUG, "shutdown_mm [%d]\n", getpid()));
277#else
278      DBG(ea_debug_printf, (EA_DEBUG, "shutdown_mm [%d,%d]\n", getpid(), getppid()));
279#endif
280#ifdef ZTS
281      tsrm_mutex_free(ea_mutex);
282#endif
283      if (mm) {
284        mm_destroy(mm);
285      }
286      ea_mm_instance = NULL;
287    }
288  }
289}
290
291void encode_version(const char *str, int *version, int *extra)
292{
293    unsigned int a = 0;
294    unsigned int b = 0;
295    unsigned int c = 0;
296    unsigned int d = 0;
297    size_t len;
298    char s[255];
299    char buf[255];
300
301    len = strlen(str);
302    memcpy(buf, str, (len > 255) ? 255 : len);
303    buf[254] = '\0';
304
305    memset(s, 0, 255);
306    sscanf(str, "%u.%u.%u%s", &a, &b, &c, s);
307
308    if (s[0] == '.') {
309        sscanf(s, ".%u-%s", &d, buf);
310    } else if (s[0] == '-') {
311        memcpy(buf, &s[1], 254);
312    } else {
313        memcpy(buf, s, 255);
314    }
315
316    *version = ((a & 0xff) << 24) | ((b & 0xff) << 16) | ((c & 0xff) << 8) | (d & 0xff);
317
318    if (buf[0] == 0) {
319        a = 0;
320        b = 0;
321    } else if (strncasecmp(buf, "rev", 3) == 0) {
322        a = 1;
323        sscanf(buf, "rev%u", &b);
324    } else if (strncasecmp(buf, "rc", 2) == 0) {
325        a = 2;
326        sscanf(buf, "rc%u", &b);
327    } else if (strncasecmp(buf, "beta", 4) == 0) {
328        a = 3;
329        sscanf(buf, "beta%u", &b);
330    } else {
331        a = 0xf;
332        // just encode the first 4 bytes
333        b = ((buf[0] & 0x7f) << 21) | ((buf[1] & 0x7f) << 14) | ((buf[2] & 0x7f) << 7) | (buf[3] & 0x7f);
334    }
335
336    *extra = ((a & 0xf) << 28) | (0x0fffffff & b);
337}
338
339#ifdef DEBUG
340static void decode_version(int version, int extra, char *str, size_t len)
341{
342    int number;
343
344    if ((version & 0xff) == 0) {
345        number = snprintf(str, len, "%u.%u.%u", (version >> 24), ((version >> 16) & 0xff), ((version >> 8) & 0xff));
346    } else {
347        number = snprintf(str, len, "%u.%u.%u.%u", (version >> 24), ((version >> 16) & 0xff), ((version >> 8) & 0xff), (version & 0xff));
348    }
349
350    if (extra != 0) {
351        unsigned int type = ((extra >> 28) & 0xf);
352        extra = (extra & 0x0fffffff);
353        switch (type) {
354            case 1:
355                snprintf(&str[number], len, "-rev%u", extra);
356                break;
357            case 2:
358                snprintf(&str[number], len, "-rc%u", extra);
359                break;
360            case 3:
361                snprintf(&str[number], len, "-beta%u", extra);
362                break;
363            case 15:
364                if ((int)len >= number + 5) {
365                    str[number] = '-';
366                    str[number + 1] = (extra >> 21) & 0x7f;
367                    str[number + 2] = (extra >> 14) & 0x7f;
368                    str[number + 3] = (extra >> 7) & 0x7f;
369                    str[number + 4] = extra & 0x7f;
370                    str[number + 5] = '\0';
371                }
372                break;
373            default:
374                break;
375        }
376    }
377}
378#endif
379
380static char num2hex[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
381
382/* Function to create a hash key when filenames are used */
383int eaccelerator_md5(char* s, const char* prefix, const char* key TSRMLS_DC) {
384  char md5str[33];
385  PHP_MD5_CTX context;
386  unsigned char digest[16];
387  int i;
388  int n;
389
390  md5str[0] = '\0';
391  PHP_MD5Init(&context);
392  PHP_MD5Update(&context, (unsigned char*)key, strlen(key));
393  PHP_MD5Final(digest, &context);
394  make_digest(md5str, digest);
395  snprintf(s, MAXPATHLEN-1, "%s/", EAG(cache_dir));
396  n = strlen(s);
397  for (i = 0; i < EACCELERATOR_HASH_LEVEL && n < MAXPATHLEN - 1; i++) {
398    s[n++] = md5str[i];
399    s[n++] = '/';
400  }
401  s[n] = 0;
402  snprintf(&s[n], MAXPATHLEN-1-n, "%s%s", prefix, md5str);
403  return 1;
404}
405
406/* Remove expired keys, content and scripts from the memory cache */
407void eaccelerator_prune(time_t t) {
408  unsigned int i;
409
410  EACCELERATOR_LOCK_RW();
411  ea_mm_instance->last_prune = t;
412  for (i = 0; i < EA_HASH_SIZE; i++) {
413    ea_cache_entry **p = &ea_mm_instance->hash[i];
414    while (*p != NULL) {
415      struct stat buf;
416      if (((*p)->ttl != 0 && (*p)->ttl < t && (*p)->use_cnt <= 0) ||
417          stat((*p)->realfilename,&buf) != 0 ||
418          (*p)->mtime != buf.st_mtime ||
419          (*p)->filesize != buf.st_size) {
420        ea_cache_entry *r = *p;
421        *p = (*p)->next;
422        ea_mm_instance->hash_cnt--;
423        eaccelerator_free_nolock(r);
424      } else {
425        p = &(*p)->next;
426      }
427    }
428  }
429  EACCELERATOR_UNLOCK_RW();
430}
431
432/* Allocate a new cache chunk */
433void* eaccelerator_malloc2(size_t size TSRMLS_DC) {
434  void *p = NULL;
435
436  if (ea_shm_prune_period > 0) {
437    if (EAG(req_start) - ea_mm_instance->last_prune > ea_shm_prune_period) {
438      eaccelerator_prune(EAG(req_start));
439      p = eaccelerator_malloc(size);
440    }
441  }
442  return p;
443}
444
445#define EACCELERATOR_CRC32(crc, ch)   (crc = (crc >> 8) ^ crc32tab[(crc ^ (ch)) & 0xff])
446
447static const unsigned int crc32tab[256] = {
448  0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
449  0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
450  0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
451  0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
452  0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
453  0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
454  0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
455  0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
456  0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
457  0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
458  0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
459  0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
460  0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
461  0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
462  0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
463  0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
464  0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
465  0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
466  0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
467  0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
468  0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
469  0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
470  0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
471  0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
472  0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
473  0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
474  0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
475  0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
476  0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
477  0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
478  0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
479  0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
480  0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
481  0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
482  0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
483  0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
484  0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
485  0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
486  0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
487  0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
488  0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
489  0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
490  0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
491  0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
492  0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
493  0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
494  0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
495  0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
496  0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
497  0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
498  0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
499  0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
500  0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
501  0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
502  0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
503  0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
504  0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
505  0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
506  0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
507  0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
508  0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
509  0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
510  0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
511  0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
512};
513
514unsigned int eaccelerator_crc32(const char *p, size_t n) {
515  unsigned int crc = ~0;
516  for (; n--; ++p) {
517    EACCELERATOR_CRC32(crc, *p);
518  }
519  return ~crc;
520}
521
522/******************************************************************************/
523/* Cache file functions.                                                                                                                */
524/******************************************************************************/
525
526/* A function to check if the header of a cache file valid is.
527 */
528inline int check_header(ea_file_header *hdr)
529{
530#ifdef DEBUG
531  char current[255];
532  char cache[255];
533#endif
534       
535  if (strncmp(hdr->magic, EA_MAGIC, 8) != 0) {
536#ifdef DEBUG
537    ea_debug_printf(EA_DEBUG, "Magic header mismatch.");
538#endif
539        return 0;       
540  }
541  if (hdr->eaccelerator_version[0] != binary_eaccelerator_version[0]
542      || hdr->eaccelerator_version[1] != binary_eaccelerator_version[1]) {
543#ifdef DEBUG
544    decode_version(hdr->eaccelerator_version[0], hdr->eaccelerator_version[1], cache, 255);
545    decode_version(binary_eaccelerator_version[0], binary_eaccelerator_version[1], current, 255);
546    ea_debug_printf(EA_DEBUG, "eAccelerator version mismatch, cache file %s and current version %s\n", cache, current);
547#endif
548    return 0;
549  }
550  if (hdr->zend_version[0] != binary_zend_version[0]
551      || hdr->zend_version[1] != binary_zend_version[1]) {
552#ifdef DEBUG
553    decode_version(hdr->zend_version[0], hdr->zend_version[1], cache, 255);
554    decode_version(binary_zend_version[0], binary_zend_version[1], current, 255);
555    ea_debug_printf(EA_DEBUG, "Zend version mismatch, cache file %s and current version %s\n", cache, current);
556#endif
557    return 0;
558  }
559  if (hdr->php_version[0] != binary_php_version[0]
560      || hdr->php_version[1] != binary_php_version[1]) {
561#ifdef DEBUG
562    decode_version(hdr->php_version[0], hdr->php_version[1], cache, 255);
563    decode_version(binary_php_version[0], binary_php_version[1], current, 255);
564    ea_debug_printf(EA_DEBUG, "PHP version mismatch, cache file %s and current version %s\n", cache, current);
565#endif
566    return 0;
567  }
568  return 1;
569}
570
571/* A function to create the header for a cache file.
572 */
573inline void init_header(ea_file_header *hdr)
574{
575  strncpy(hdr->magic, EA_MAGIC, 8);
576  hdr->eaccelerator_version[0] = binary_eaccelerator_version[0];
577  hdr->eaccelerator_version[1] = binary_eaccelerator_version[1];
578  hdr->zend_version[0] = binary_zend_version[0];
579  hdr->zend_version[1] = binary_zend_version[1];
580  hdr->php_version[0] = binary_php_version[0]; 
581  hdr->php_version[1] = binary_php_version[1];
582}
583/* Retrieve a cache entry from the cache directory */
584static ea_cache_entry* hash_find_file(const char  *key, struct stat *buf TSRMLS_DC) {
585  int f;
586  char s[MAXPATHLEN];
587  ea_file_header hdr;
588  ea_cache_entry *p = NULL;
589  int use_shm = 1;
590
591  if (!eaccelerator_md5(s, "/eaccelerator-", key TSRMLS_CC)) {
592    return NULL;
593  }
594
595  if ((f = open(s, O_RDONLY | O_BINARY)) > 0) {
596    EACCELERATOR_FLOCK(f, LOCK_SH);
597    if (read(f, &hdr, sizeof(hdr)) != sizeof(hdr)) {
598      EACCELERATOR_FLOCK(f, LOCK_UN);
599      close(f);
600      return NULL;
601    }
602    if (!check_header(&hdr)) {
603      EACCELERATOR_FLOCK(f, LOCK_UN);
604      close(f);
605      unlink(s);
606      return NULL;
607    }
608    p = eaccelerator_malloc(hdr.size);
609    if (p == NULL) {
610      p = eaccelerator_malloc2(hdr.size TSRMLS_CC);
611    }
612    if (p == NULL) {
613      p = emalloc(hdr.size);
614      use_shm = 0;
615    }
616    if (p == NULL) {
617      EACCELERATOR_FLOCK(f, LOCK_UN);
618      close(f);
619      return NULL;
620    }
621    if (read(f, p, hdr.size) != hdr.size ||
622        p->size != hdr.size ||
623        hdr.crc32 != eaccelerator_crc32((const char*)p,p->size)) {
624      EACCELERATOR_FLOCK(f, LOCK_UN);
625      close(f);
626      unlink(s);
627      if (use_shm) eaccelerator_free(p); else efree(p);
628                        DBG(ea_debug_printf, (EA_DEBUG, "cache file is corrupted\n"));
629      return NULL;
630    }
631    EACCELERATOR_FLOCK(f, LOCK_UN);
632    close(f);
633    if (strcmp(key,p->realfilename) != 0) {
634      if (use_shm) eaccelerator_free(p); else efree(p);
635      return NULL;
636    }
637    if ((EAG(check_mtime_enabled) && ea_mm_instance->check_mtime_enabled &&
638        (buf->st_mtime != p->mtime || buf->st_size != p->filesize))
639       ) {
640      /* key is invalid. Remove it. */
641      if (use_shm) eaccelerator_free(p); else efree(p);
642      unlink(s);
643      return NULL;
644    }
645    eaccelerator_fixup(p TSRMLS_CC);
646    if (use_shm) {
647      p->nhits    = 1;
648      p->nreloads = 1;
649      p->use_cnt  = 1;
650      p->removed  = 0;
651      if (ea_shm_ttl > 0) {
652        p->ttl = EAG(req_start) + ea_shm_ttl;
653      } else {
654        p->ttl = 0;
655      }
656      p->ts       = hdr.ts;     /* get cached item creation timestamp from cache file */
657      hash_add_mm(p);
658    } else {
659      p->use_cnt  = 0;
660      p->removed  = 1;
661    }
662    mm_check_mem(p);
663    return p;
664  }
665  return NULL;
666}
667
668/* Add a cache entry to the cache directory */
669static int hash_add_file(ea_cache_entry *p TSRMLS_DC) {
670  int f;
671  int ret = 0;
672  char s[MAXPATHLEN];
673  ea_file_header hdr;
674
675  if (!eaccelerator_md5(s, "/eaccelerator-", p->realfilename TSRMLS_CC)) {
676    return 0;
677  }
678
679  unlink(s);
680  f = open(s, O_CREAT | O_WRONLY | O_EXCL | O_BINARY, S_IRUSR | S_IWUSR);
681  if (f > 0) {
682    EACCELERATOR_FLOCK(f, LOCK_EX);
683    init_header(&hdr);
684    hdr.size  = p->size;
685    hdr.mtime = p->mtime;
686    hdr.ts    = p->ts;
687    p->next = p;
688    hdr.crc32 = eaccelerator_crc32((const char*)p,p->size);
689    ret = (write(f, &hdr, sizeof(hdr)) == sizeof(hdr));
690    if (ret) ret = (write(f, p, p->size) == p->size);
691    EACCELERATOR_FLOCK(f, LOCK_UN);
692    close(f);
693  } else {
694    ea_debug_log("EACCELERATOR: Open for write failed for \"%s\": %s\n", s, strerror(errno));
695  }
696  return ret;
697}
698
699/* called after succesful compilation, from eaccelerator_compile file */
700/* Adds the data from the compilation of the script to the cache */
701static int eaccelerator_store(char* key, struct stat *buf, int nreloads,
702                         zend_op_array* op_array,
703                         Bucket* f, Bucket *c TSRMLS_DC) {
704  ea_cache_entry *p;
705  int len = strlen(key);
706  int use_shm = 1;
707  int ret = 0;
708  int size = 0;
709  void *data = NULL;
710
711  zend_try {
712    size = calc_size(key, op_array, f, c TSRMLS_CC);
713  } zend_catch {
714    size =  0;
715  } zend_end_try();
716  if (size == 0) {
717    return 0;
718  }
719
720  DBG(ea_debug_pad, (EA_DEBUG TSRMLS_CC));
721  DBG(ea_debug_printf, (EA_DEBUG, "[%d] eaccelerator_store:  returned %d, mm=%x\n", getpid(), size, ea_mm_instance->mm));
722 
723  EACCELERATOR_UNPROTECT();
724  EAG(mem) = eaccelerator_malloc(size);
725  if (EAG(mem) == NULL) {
726    EAG(mem) = eaccelerator_malloc2(size TSRMLS_CC);
727  }
728  if (!EAG(mem) && !ea_scripts_shm_only) {
729    EACCELERATOR_PROTECT();
730    EAG(mem) = emalloc(size);
731    use_shm = 0;
732  }
733  if (EAG(mem)) {
734    data = EAG(mem);
735    memset(EAG(mem), 0, size);
736                p = (ea_cache_entry *)EAG(mem);
737    eaccelerator_store_int(p, key, len, op_array, f, c TSRMLS_CC);
738    p->mtime    = buf->st_mtime;
739    p->ts       = EAG(req_start);
740    p->filesize = buf->st_size;
741    p->size     = size;
742    p->nreloads = nreloads;
743    if (use_shm) {
744      if (ea_shm_ttl > 0) {
745        p->ttl = EAG(req_start) + ea_shm_ttl;
746      } else {
747        p->ttl = 0;
748      }
749      if (!ea_scripts_shm_only) {
750        hash_add_file(p TSRMLS_CC);
751      }
752      hash_add_mm(p);
753      EACCELERATOR_PROTECT();
754      ret = 1;
755      mm_check_mem(data);
756    } else {
757      ret =  hash_add_file(p TSRMLS_CC);
758      efree(p);
759    }
760  }
761  return ret;
762}
763
764/* Try to restore a file from the cache. If the file isn't found in memory, the
765   the disk cache is checked */
766static zend_op_array* eaccelerator_restore(char *realname, struct stat *buf,
767                                      int *nreloads, time_t compile_time TSRMLS_DC) {
768  ea_cache_entry *p;
769  zend_op_array *op_array = NULL;
770
771  *nreloads = 1;
772  EACCELERATOR_UNPROTECT();
773  p = hash_find_mm(realname, buf, nreloads, ((ea_shm_ttl > 0)?(compile_time + ea_shm_ttl):0) TSRMLS_CC);
774  if (p == NULL && !ea_scripts_shm_only) {
775    p = hash_find_file(realname, buf TSRMLS_CC);
776  }
777  EACCELERATOR_PROTECT();
778  if (p != NULL && p->op_array != NULL) {
779    /* only restore file when open_basedir allows it */
780    if (php_check_open_basedir(realname TSRMLS_CC)) {
781      return NULL;
782    }
783    EAG(class_entry) = NULL;
784    op_array = restore_op_array(NULL, p->op_array TSRMLS_CC);
785    if (op_array != NULL) {
786      ea_fc_entry *e;
787      ea_used_entry *used = emalloc(sizeof(ea_used_entry));
788      used->entry  = p;
789      used->next   = (ea_used_entry*)EAG(used_entries);
790      EAG(used_entries) = (void*)used;
791      EAG(mem) = op_array->filename;
792                        /* only restore the classes and functions when we restore this script
793                         * for the first time.
794                         */
795      if (!zend_hash_exists(&EAG(restored), p->realfilename, strlen(p->realfilename))) {
796                                for (e = p->c_head; e!=NULL; e = e->next) {
797          restore_class(e TSRMLS_CC);
798        }
799        for (e = p->f_head; e!=NULL; e = e->next) {
800          restore_function(e TSRMLS_CC);
801        }
802                                zend_hash_add(&EAG(restored), p->realfilename, strlen(p->realfilename), NULL, 0, NULL); 
803                        }
804                        EAG(mem) = p->realfilename;
805    }
806#ifdef ZEND_COMPILE_DELAYED_BINDING
807    zend_do_delayed_early_binding(op_array TSRMLS_CC);
808#endif
809  }
810  return op_array;
811}
812
813/*
814 * Returns the realpath for given filename according to include path
815 */
816static char *ea_resolve_path(const char *filename, int filename_length, const char *path TSRMLS_DC)
817{
818        char resolved_path[MAXPATHLEN];
819        char trypath[MAXPATHLEN];
820        const char *ptr, *end, *p;
821        char *actual_path;
822        php_stream_wrapper *wrapper;
823
824        if (!filename) {
825                return NULL;
826        }
827
828        /* Don't resolve paths which contain protocol (except of file://) */
829        for (p = filename; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++);
830        if ((*p == ':') && (p - filename > 1) && (p[1] == '/') && (p[2] == '/')) {
831                wrapper = php_stream_locate_url_wrapper(filename, &actual_path, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
832                if (wrapper == &php_plain_files_wrapper) {
833                        if (tsrm_realpath(actual_path, resolved_path TSRMLS_CC)) {
834                                return estrdup(resolved_path);
835                        }
836                }
837                return NULL;
838        }
839
840        if ((*filename == '.' &&
841             (IS_SLASH(filename[1]) ||
842              ((filename[1] == '.') && IS_SLASH(filename[2])))) ||
843            IS_ABSOLUTE_PATH(filename, filename_length) ||
844            !path ||
845            !*path) {
846                if (tsrm_realpath(filename, resolved_path TSRMLS_CC)) {
847                        return estrdup(resolved_path);
848                } else {
849                        return NULL;
850                }
851        }
852
853        ptr = path;
854        while (ptr && *ptr) {
855                /* Check for stream wrapper */
856                int is_stream_wrapper = 0;
857
858                for (p = ptr; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++);
859                if ((*p == ':') && (p - ptr > 1) && (p[1] == '/') && (p[2] == '/')) {
860                        /* .:// or ..:// is not a stream wrapper */
861                        if (p[-1] != '.' || p[-2] != '.' || p - 2 != ptr) {
862                                p += 3;
863                                is_stream_wrapper = 1;
864                        }
865                }
866                end = strchr(p, DEFAULT_DIR_SEPARATOR);
867                if (end) {
868                        if ((end-ptr) + 1 + filename_length + 1 >= MAXPATHLEN) {
869                                ptr = end + 1;
870                                continue;
871                        }
872                        memcpy(trypath, ptr, end-ptr);
873                        trypath[end-ptr] = '/';
874                        memcpy(trypath+(end-ptr)+1, filename, filename_length+1);
875                        ptr = end+1;
876                } else {
877                        int len = strlen(ptr);
878
879                        if (len + 1 + filename_length + 1 >= MAXPATHLEN) {
880                                break;
881                        }
882                        memcpy(trypath, ptr, len);
883                        trypath[len] = '/';
884                        memcpy(trypath+len+1, filename, filename_length+1);
885                        ptr = NULL;
886                }
887                actual_path = trypath;
888                if (is_stream_wrapper) {
889                        wrapper = php_stream_locate_url_wrapper(trypath, &actual_path, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
890                        if (!wrapper) {
891                                continue;
892                        } else if (wrapper != &php_plain_files_wrapper) {
893                                if (wrapper->wops->url_stat) {
894                                        php_stream_statbuf ssb;
895
896                                        if (SUCCESS == wrapper->wops->url_stat(wrapper, trypath, 0, &ssb, NULL TSRMLS_CC)) {
897                                                return estrdup(trypath);
898                                        }
899                                }
900                                continue;
901                        }
902                }
903                if (tsrm_realpath(actual_path, resolved_path TSRMLS_CC)) {
904                        return estrdup(resolved_path);
905                }
906        } /* end provided path */
907
908        /* check in calling scripts' current working directory as a fall back case
909         */
910        if (zend_is_executing(TSRMLS_C)) {
911                char *exec_fname = zend_get_executed_filename(TSRMLS_C);
912                int exec_fname_length = strlen(exec_fname);
913
914                while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length]));
915                if (exec_fname && exec_fname[0] != '[' &&
916                    exec_fname_length > 0 &&
917                    exec_fname_length + 1 + filename_length + 1 < MAXPATHLEN) {
918                        memcpy(trypath, exec_fname, exec_fname_length + 1);
919                        memcpy(trypath+exec_fname_length + 1, filename, filename_length+1);
920                        actual_path = trypath;
921
922                        /* Check for stream wrapper */
923                        for (p = trypath; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++);
924                        if ((*p == ':') && (p - trypath > 1) && (p[1] == '/') && (p[2] == '/')) {
925                                wrapper = php_stream_locate_url_wrapper(trypath, &actual_path, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
926                                if (!wrapper) {
927                                        return NULL;
928                                } else if (wrapper != &php_plain_files_wrapper) {
929                                        if (wrapper->wops->url_stat) {
930                                                php_stream_statbuf ssb;
931
932                                                if (SUCCESS == wrapper->wops->url_stat(wrapper, trypath, 0, &ssb, NULL TSRMLS_CC)) {
933                                                        return estrdup(trypath);
934                                                }
935                                        }
936                                        return NULL;
937                                }
938                        }
939
940                        if (tsrm_realpath(actual_path, resolved_path TSRMLS_CC)) {
941                                return estrdup(resolved_path);
942                        }
943                }
944        }
945
946        return NULL;
947}
948
949/**
950 * Get the real filename of the file represented by the given file_handle.
951 * If unable to determine the realfilename this function returns 0, otherwise
952 * it returns 1.
953 *
954 * realfilename should be MAXPATHLEN long.
955 */
956static int ea_get_realname(zend_file_handle *file_handle, char* realname TSRMLS_DC) {
957        // at least one of these should have value
958  if (file_handle->opened_path == NULL && file_handle->filename == NULL) {
959                return 0;
960        }
961
962        if (file_handle->opened_path != NULL) {
963                strcpy(realname, file_handle->opened_path);
964                return 1;
965        }
966
967        if (PG(include_path) == NULL ||
968                        file_handle->filename[0] == '.' ||
969      IS_SLASH(file_handle->filename[0]) ||
970      IS_ABSOLUTE_PATH(file_handle->filename, strlen(file_handle->filename))) {
971   
972                return VCWD_REALPATH(file_handle->filename, realname) != NULL;
973        } else {
974    int filename_len = strlen(file_handle->filename);
975                char* temp_name = ea_resolve_path(file_handle->filename, filename_len, PG(include_path) TSRMLS_CC);
976
977                if (temp_name == NULL) {
978                        return 0;
979                }
980
981                strcpy(realname, temp_name);
982                efree(temp_name);
983                return 1;
984        }
985
986        return 0;
987}
988
989static int ea_get_phar_name(const char* filename, size_t filename_len, char* phar_name) {
990        size_t i = 0;
991
992        for (i = sizeof("phar://"); i < filename_len - sizeof(".phar"); ++i) {
993                if (filename[i] == '.' && filename[i + 1] == 'p' && filename[i + 2] == 'h' &&
994                                filename[i + 3] == 'a' && filename[i + 4] == 'r') {
995                        int copy_len = (i - sizeof("phar://") + sizeof(".phar"));
996                        if (copy_len >= MAXPATHLEN - 1) {
997                                return 0;
998                        }
999                        memcpy(phar_name, &filename[sizeof("phar://") - 1], copy_len);
1000                        phar_name[copy_len] = '\0';
1001                        return 1;
1002                }
1003        }
1004        return 0;
1005}
1006
1007/*
1008 * Stat the file that belongs to file_handle. It puts result of the stat call
1009 * in buf and the real filename in realname.
1010 *
1011 * Returns 0 when the stat failed or if unable to perform a stat call. If successful
1012 * it returns 1
1013 */
1014static int eaccelerator_stat(zend_file_handle *file_handle,
1015                        char* realname, struct stat* buf TSRMLS_DC) {
1016        if (!ea_get_realname(file_handle, realname TSRMLS_CC)) {
1017#ifdef ZEND_ENGINE_2_3
1018                if (strncmp(file_handle->filename, "phar://", sizeof("phar://"))) {
1019                        // Determine the name of the phar archive and use this filename to do the
1020                        // stat call. Return filename as realname.
1021                        char phar_name[MAXPATHLEN];
1022                        size_t filename_len = strlen(file_handle->filename);
1023
1024                        if (!ea_get_phar_name(file_handle->filename, filename_len, phar_name)) {
1025                                return 0;
1026                        }
1027                        // TODO: resolve this problem
1028                        if (filename_len >= MAXPATHLEN) {
1029                                return 0;
1030                        }
1031                        strcpy(realname, file_handle->filename);
1032                  return (stat(phar_name, buf) == 0 && S_ISREG(buf->st_mode));
1033                }
1034#endif
1035                return 0;
1036        }
1037
1038
1039  if (EAG(check_mtime_enabled) && ea_mm_instance->check_mtime_enabled) {
1040                return (stat(realname, buf) == 0 && S_ISREG(buf->st_mode));
1041        }
1042        return 1;
1043}
1044
1045static int ea_match(struct ea_pattern_t *list, const char *path)
1046{
1047        struct ea_pattern_t *p;
1048        char result, positive;
1049
1050        // apply all patterns
1051        //  - when not patterns are given, *accept*
1052        //  - when a pattern with a ! matches, *reject*
1053        //  - when no negative pattern matches and a positive pattern match, *accept*
1054        //  - when no negative pattern matches and there are no possitive patterns, *accept*
1055        //  - *reject*
1056
1057        if (list == NULL) {
1058                // there are no patterns, accept
1059                return 1;
1060        }
1061
1062        result = 0; // there are patterns, so if no positive pattern matches, reject
1063        positive = 0;
1064        p = list;
1065        while (p != NULL) {
1066                if (p->pattern[0] == '!') {
1067                        if ((fnmatch((const char *)(p->pattern + 1), path, 0) == 0)) {
1068                                // a negative pattern matches, accept
1069                                return 0;
1070                        }
1071                } else {
1072                        result |= (fnmatch((const char *)p->pattern, path, 0) == 0);
1073                        positive = 1;
1074                }
1075                p = p->next;
1076        }
1077
1078  return result | !positive;
1079}
1080
1081/* copy of zend_class_add_ref, the linker isn't able to link to it any more
1082 * in php 5.3
1083 * TODO: see if we can steal the pointer
1084 */
1085void ea_class_add_ref(zend_class_entry **ce)
1086{
1087        (*ce)->refcount++;
1088}
1089
1090/*
1091 * Intercept compilation of PHP file.  If we already have the file in
1092 * our cache, restore it.  Otherwise call the original Zend compilation
1093 * function and store the compiled zend_op_array in out cache.
1094 * This function is called again for each PHP file included in the
1095 * main PHP file.
1096 */
1097ZEND_DLEXPORT zend_op_array* eaccelerator_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC) {
1098  zend_op_array *t;
1099  struct stat buf;
1100  char  realname[MAXPATHLEN];
1101  int   nreloads;
1102  int stat_result = 0;
1103#ifdef DEBUG
1104  struct timeval tv_start;
1105#endif
1106  int ok_to_cache = 0;
1107#ifdef ZEND_ENGINE_2_3
1108  zend_uint orig_compiler_options;
1109#endif
1110
1111  DBG(ea_debug_start_time, (&tv_start));
1112  DBG(ea_debug_printf, (EA_DEBUG, "[%d] Enter COMPILE\n",getpid()));
1113  DBG(ea_debug_printf, (EA_DEBUG, "[%d] compile_file: \"%s\"\n",getpid(), file_handle->filename));
1114#ifdef DEBUG
1115  EAG(xpad)+=2;
1116#endif
1117
1118  stat_result = eaccelerator_stat(file_handle, realname, &buf TSRMLS_CC);
1119
1120  ok_to_cache = ea_match(EAG(pattern_list), file_handle->filename);
1121
1122  // eAccelerator isn't working, so just compile the file
1123  if (!EAG(enabled) || (ea_mm_instance == NULL) ||
1124      !ea_mm_instance->enabled || file_handle == NULL ||
1125      file_handle->filename == NULL || stat_result == 0 || !ok_to_cache) {
1126    DBG(ea_debug_printf, (EA_DEBUG, "\t[%d] compile_file: compiling\n", getpid()));
1127    t = ea_saved_zend_compile_file(file_handle, type TSRMLS_CC);
1128    DBG(ea_debug_printf, (EA_TEST_PERFORMANCE, "\t[%d] compile_file: end (%ld)\n", getpid(), ea_debug_elapsed_time(&tv_start)));
1129    DBG(ea_debug_printf, (EA_DEBUG, "\t[%d] compile_file: end\n", getpid()));
1130#ifdef DEBUG
1131    EAG(xpad)-=2;
1132#endif
1133    DBG(ea_debug_printf, (EA_DEBUG, "[%d] Leave COMPILE\n", getpid()));
1134    return t;
1135  }
1136
1137  if (buf.st_mtime >= EAG(req_start) && ea_debug > 0) {
1138                ea_debug_log("EACCELERATOR: Warning: \"%s\" is cached but it's mtime is in the future.\n", file_handle->filename);
1139  }
1140
1141  t = eaccelerator_restore(realname, &buf, &nreloads, EAG(req_start) TSRMLS_CC);
1142
1143// segv74: really cheap work around to auto_global problem.
1144//         it makes just in time to every time.
1145  zend_is_auto_global("_GET", sizeof("_GET")-1 TSRMLS_CC);
1146  zend_is_auto_global("_POST", sizeof("_POST")-1 TSRMLS_CC);
1147  zend_is_auto_global("_COOKIE", sizeof("_COOKIE")-1 TSRMLS_CC);
1148  zend_is_auto_global("_SERVER", sizeof("_SERVER")-1 TSRMLS_CC);
1149  zend_is_auto_global("_ENV", sizeof("_ENV")-1 TSRMLS_CC);
1150  zend_is_auto_global("_REQUEST", sizeof("_REQUEST")-1 TSRMLS_CC);
1151  zend_is_auto_global("_FILES", sizeof("_FILES")-1 TSRMLS_CC);
1152
1153  if (t != NULL) { // restore from cache
1154#ifdef DEBUG
1155    ea_debug_log("[%d] EACCELERATOR hit: \"%s\"\n", getpid(), t->filename);
1156#else
1157    ea_debug_log("EACCELERATOR hit: \"%s\"\n", t->filename);
1158#endif
1159
1160    zend_llist_add_element(&CG(open_files), file_handle);
1161    if (file_handle->opened_path == NULL && file_handle->type != ZEND_HANDLE_STREAM) {
1162      file_handle->handle.stream.handle = (void*)1;
1163      file_handle->opened_path = EAG(mem);      /* EAG(mem) = p->realfilename from eaccelerator_restore here */
1164    }
1165
1166    DBG(ea_debug_printf, (EA_TEST_PERFORMANCE, "\t[%d] compile_file: restored (%ld)\n", getpid(), ea_debug_elapsed_time(&tv_start)));
1167    DBG(ea_debug_printf, (EA_DEBUG, "\t[%d] compile_file: restored\n", getpid()));
1168#ifdef DEBUG
1169    EAG(xpad)-=2;
1170#endif
1171    DBG(ea_debug_printf, (EA_DEBUG, "[%d] Leave COMPILE\n", getpid()));
1172
1173    return t;
1174
1175  } else { // not in cache or must be recompiled
1176                Bucket *function_table_tail;
1177                Bucket *class_table_tail;
1178                HashTable* orig_function_table;
1179                HashTable* orig_class_table;
1180                HashTable* orig_eg_class_table = NULL;
1181                HashTable tmp_function_table;
1182                HashTable tmp_class_table;
1183                zend_function tmp_func;
1184                zend_class_entry tmp_class;
1185                int ea_bailout;
1186
1187#ifdef DEBUG
1188    ea_debug_printf(EA_DEBUG, "\t[%d] compile_file: marking\n", getpid());
1189    if (CG(class_table) != EG(class_table)) {
1190      ea_debug_printf(EA_DEBUG, "\t[%d] oops, CG(class_table)[%08x] != EG(class_table)[%08x]\n", getpid(), CG(class_table), EG(class_table));
1191      ea_debug_log_hashkeys("CG(class_table)\n", CG(class_table));
1192      ea_debug_log_hashkeys("EG(class_table)\n", EG(class_table));
1193    } else {
1194      ea_debug_printf(EA_DEBUG, "\t[%d] OKAY. That what I thought, CG(class_table)[%08x] == EG(class_table)[%08x]\n", getpid(), CG(class_table), EG(class_table));
1195      ea_debug_log_hashkeys("CG(class_table)\n", CG(class_table));
1196    }
1197#endif
1198
1199    zend_hash_init_ex(&tmp_function_table, 100, NULL, ZEND_FUNCTION_DTOR, 1, 0);
1200    zend_hash_copy(&tmp_function_table, &ea_global_function_table, NULL, &tmp_func, sizeof(zend_function));
1201    orig_function_table = CG(function_table);
1202    CG(function_table) = &tmp_function_table;
1203
1204    zend_hash_init_ex(&tmp_class_table, 10, NULL, ZEND_CLASS_DTOR, 1, 0);
1205                zend_hash_copy(&tmp_class_table, &ea_global_class_table, (copy_ctor_func_t)ea_class_add_ref, &tmp_class, sizeof(zend_class_entry *));
1206
1207    orig_class_table = CG(class_table);;
1208    CG(class_table) = &tmp_class_table;
1209    orig_eg_class_table = EG(class_table);;
1210    EG(class_table) = &tmp_class_table;
1211
1212    /* Storing global pre-compiled functions and classes */
1213    function_table_tail = CG(function_table)->pListTail;
1214    class_table_tail = CG(class_table)->pListTail;
1215
1216    DBG(ea_debug_printf, (EA_TEST_PERFORMANCE, "\t[%d] compile_file: compiling (%ld)\n", getpid(), ea_debug_elapsed_time(&tv_start)));
1217   
1218                if (EAG(optimizer_enabled) && ea_mm_instance->optimizer_enabled) {
1219                        EAG(compiler) = 1;
1220                }
1221
1222        /* try to compile the script */
1223    ea_bailout = 0;
1224    zend_try {
1225#ifdef ZEND_ENGINE_2_3
1226      orig_compiler_options = CG(compiler_options);
1227      CG(compiler_options) |= ZEND_COMPILE_IGNORE_INTERNAL_CLASSES | ZEND_COMPILE_DELAYED_BINDING; 
1228#endif
1229      t = ea_saved_zend_compile_file(file_handle, type TSRMLS_CC);
1230#ifdef ZEND_ENGINE_2_3
1231      CG(compiler_options) = orig_compiler_options;
1232#endif
1233    } zend_catch {
1234      CG(function_table) = orig_function_table;
1235      CG(class_table) = orig_class_table;
1236      EG(class_table) = orig_eg_class_table;
1237      ea_bailout = 1;
1238    } zend_end_try();
1239    if (ea_bailout) {
1240      zend_bailout();
1241    }
1242    DBG(ea_debug_log_hashkeys, ("class_table\n", CG(class_table)));
1243
1244    EAG(compiler) = 0;
1245    if (t != NULL && file_handle->opened_path != NULL && ((EAG(check_mtime_enabled) && ea_mm_instance->check_mtime_enabled) ||
1246         ((stat(file_handle->opened_path, &buf) == 0) && S_ISREG(buf.st_mode)))) {
1247
1248      DBG(ea_debug_printf, (EA_TEST_PERFORMANCE, "\t[%d] compile_file: storing in cache (%ld)\n", getpid(), ea_debug_elapsed_time(&tv_start)));
1249      DBG(ea_debug_printf, (EA_DEBUG, "\t[%d] compile_file: storing in cache\n", getpid()));
1250      function_table_tail = function_table_tail ? function_table_tail->pListNext : CG(function_table)->pListHead;
1251      class_table_tail = class_table_tail ? class_table_tail->pListNext : CG(class_table)->pListHead;
1252
1253      if (eaccelerator_store(file_handle->opened_path, &buf, nreloads, t, function_table_tail, class_table_tail TSRMLS_CC)) {
1254#ifdef DEBUG
1255        ea_debug_log("[%d] EACCELERATOR %s: \"%s\"\n", getpid(), (nreloads == 1) ? "cached" : "re-cached", file_handle->opened_path);
1256#else
1257        ea_debug_log("EACCELERATOR %s: \"%s\"\n", (nreloads == 1) ? "cached" : "re-cached", file_handle->opened_path);
1258#endif
1259      } else {
1260#ifdef DEBUG
1261        ea_debug_log("[%d] EACCELERATOR can't cache: \"%s\"\n", getpid(), file_handle->opened_path);
1262#else
1263        ea_debug_log("EACCELERATOR can't cache: \"%s\"\n", file_handle->opened_path);
1264#endif
1265      }
1266    } else {
1267      function_table_tail = function_table_tail ? function_table_tail->pListNext : CG(function_table)->pListHead;
1268      class_table_tail = class_table_tail ? class_table_tail->pListNext : CG(class_table)->pListHead;
1269    }
1270    CG(function_table) = orig_function_table;
1271    CG(class_table) = orig_class_table;
1272    EG(class_table) = orig_eg_class_table;
1273    DBG(ea_debug_printf, (EA_DEBUG, "\t[%d] restoring CG(class_table)[%08x] != EG(class_table)[%08x]\n",
1274                getpid(), CG(class_table), EG(class_table)));
1275    while (function_table_tail != NULL) {
1276      zend_op_array *op_array = (zend_op_array*)function_table_tail->pData;
1277      if (op_array->type == ZEND_USER_FUNCTION) {
1278        if (zend_hash_add(CG(function_table), function_table_tail->arKey, function_table_tail->nKeyLength, op_array,
1279                    sizeof(zend_op_array), NULL) == FAILURE && function_table_tail->arKey[0] != '\000') {
1280          CG(in_compilation) = 1;
1281          CG(compiled_filename) = file_handle->opened_path;
1282          CG(zend_lineno) = op_array->line_start;
1283          zend_error(E_ERROR, "Cannot redeclare %s()", function_table_tail->arKey);
1284        }
1285      }
1286      function_table_tail = function_table_tail->pListNext;
1287    }
1288    while (class_table_tail != NULL) {
1289      zend_class_entry **ce = (zend_class_entry**)class_table_tail->pData;
1290      if ((*ce)->type == ZEND_USER_CLASS) {
1291        if (zend_hash_add(CG(class_table), class_table_tail->arKey, class_table_tail->nKeyLength,
1292                    ce, sizeof(zend_class_entry*), NULL) == FAILURE && class_table_tail->arKey[0] != '\000') {
1293          CG(in_compilation) = 1;
1294          CG(compiled_filename) = file_handle->opened_path;
1295          CG(zend_lineno) = (*ce)->line_start;
1296          zend_error(E_ERROR, "Cannot redeclare class %s", class_table_tail->arKey);
1297        }
1298      }
1299      class_table_tail = class_table_tail->pListNext;
1300    }
1301    tmp_function_table.pDestructor = NULL;
1302    tmp_class_table.pDestructor = NULL;
1303    zend_hash_destroy(&tmp_function_table);
1304    zend_hash_destroy(&tmp_class_table);
1305  }
1306  DBG(ea_debug_printf, (EA_TEST_PERFORMANCE, "\t[%d] compile_file: end (%ld)\n", getpid(), ea_debug_elapsed_time(&tv_start)));
1307  DBG(ea_debug_printf, (EA_DEBUG, "\t[%d] compile_file: end\n", getpid()));
1308#ifdef DEBUG
1309  EAG(xpad)-=2;
1310#endif
1311  DBG(ea_debug_printf, (EA_DEBUG, "[%d] Leave COMPILE\n", getpid()));
1312  #ifdef ZEND_COMPILE_DELAYED_BINDING
1313      zend_do_delayed_early_binding(t TSRMLS_CC);
1314  #endif
1315  return t;
1316}
1317
1318#ifdef DEBUG
1319static void profile_execute(zend_op_array *op_array TSRMLS_DC)
1320{
1321  int i;
1322  struct timeval tv_start;
1323  long usec;
1324
1325  for (i=0;i<EAG(profile_level);i++)
1326    DBG(ea_debug_put, (EA_PROFILE_OPCODES, "  "));
1327  ea_debug_printf(EA_PROFILE_OPCODES, "enter profile_execute: %s:%s\n", op_array->filename, op_array->function_name);
1328  ea_debug_start_time(&tv_start);
1329  EAG(self_time)[EAG(profile_level)] = 0;
1330  EAG(profile_level)++;
1331  ea_debug_printf(EA_PROFILE_OPCODES, "About to enter zend_execute...\n");
1332  ea_saved_zend_execute(op_array TSRMLS_CC);
1333  ea_debug_printf(EA_PROFILE_OPCODES, "Finished zend_execute...\n");
1334  usec = ea_debug_elapsed_time(&tv_start);
1335  EAG(profile_level)--;
1336  if (EAG(profile_level) > 0)
1337    EAG(self_time)[EAG(profile_level)-1] += usec;
1338  for (i=0;i<EAG(profile_level);i++)
1339    DBG(ea_debug_put, (EA_PROFILE_OPCODES, "  "));
1340  ea_debug_printf(EA_PROFILE_OPCODES, "leave profile_execute: %s:%s (%ld,%ld)\n", op_array->filename, op_array->function_name, usec, usec-EAG(self_time)[EAG(profile_level)]);
1341}
1342
1343ZEND_DLEXPORT zend_op_array* profile_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC) {
1344  zend_op_array *t;
1345  int i;
1346  struct timeval tv_start;
1347  long usec;
1348
1349  ea_debug_start_time(&tv_start);
1350  EAG(self_time)[EAG(profile_level)] = 0;
1351  t = eaccelerator_compile_file(file_handle, type TSRMLS_CC);
1352  usec = ea_debug_elapsed_time(&tv_start);
1353  if (EAG(profile_level) > 0)
1354    EAG(self_time)[EAG(profile_level)-1] += usec;
1355  for (i=0;i<EAG(profile_level);i++)
1356    DBG(ea_debug_put, (EA_PROFILE_OPCODES, "  "));
1357  return t;
1358}
1359
1360#endif  /* DEBUG */
1361
1362/* Format Bytes */
1363void format_size(char* s, unsigned int size, int legend) {
1364  unsigned int i = 0;
1365  unsigned int n = 0;
1366  char ch;
1367  do {
1368    if ((n != 0) && (n % 3 == 0)) {
1369      s[i++] = ',';
1370    }
1371    s[i++] = (char)((int)'0' + (size % 10));
1372    n++;
1373    size = size / 10;
1374  } while (size != 0);
1375  s[i] = '\0';
1376  n = 0; i--;
1377  while (n < i) {
1378    ch = s[n];
1379    s[n] = s[i];
1380    s[i] = ch;
1381    n++, i--;
1382  }
1383  if (legend) {
1384    strcat(s, " Bytes");
1385  }
1386}
1387
1388/* eAccelerator entry for phpinfo() */
1389PHP_MINFO_FUNCTION(eaccelerator) {
1390  char s[32];
1391
1392  php_info_print_table_start();
1393  php_info_print_table_header(2, "eAccelerator support", "enabled");
1394  php_info_print_table_row(2, "Version", EACCELERATOR_VERSION);
1395  php_info_print_table_row(2, "Caching Enabled", (EAG(enabled) && (ea_mm_instance != NULL) &&
1396              ea_mm_instance->enabled)?"true":"false");
1397  php_info_print_table_row(2, "Optimizer Enabled", (EAG(optimizer_enabled) &&
1398                                                        (ea_mm_instance != NULL) && ea_mm_instance->optimizer_enabled)?"true":"false");
1399  php_info_print_table_row(2, "Check mtime Enabled", (EAG(check_mtime_enabled) &&
1400                                                        (ea_mm_instance != NULL) && ea_mm_instance->check_mtime_enabled)?"true":"false");
1401  if (ea_mm_instance != NULL) {
1402    size_t available;
1403    EACCELERATOR_UNPROTECT();
1404    available = mm_available(ea_mm_instance->mm);
1405    EACCELERATOR_LOCK_RD();
1406    EACCELERATOR_PROTECT();
1407    format_size(s, ea_mm_instance->total, 1);
1408    php_info_print_table_row(2, "Memory Size", s);
1409    format_size(s, available, 1);
1410    php_info_print_table_row(2, "Memory Available", s);
1411    format_size(s, ea_mm_instance->total - available, 1);
1412    php_info_print_table_row(2, "Memory Allocated", s);
1413    snprintf(s, 32, "%u", ea_mm_instance->hash_cnt);
1414    php_info_print_table_row(2, "Cached Scripts", s);
1415    snprintf(s, 32, "%u", ea_mm_instance->rem_cnt);
1416    php_info_print_table_row(2, "Removed Scripts", s);
1417    EACCELERATOR_UNPROTECT();
1418    EACCELERATOR_UNLOCK_RD();
1419    EACCELERATOR_PROTECT();
1420  }
1421  php_info_print_table_end();
1422
1423  DISPLAY_INI_ENTRIES();
1424}
1425
1426/*
1427 * Parse a list of filters which is seperated by a " "
1428 */
1429static struct ea_pattern_t *ea_parse_filter(char *filter)
1430{
1431        char *saveptr = NULL, *token = NULL;
1432        struct ea_pattern_t *list_head = NULL, *p = NULL;
1433        size_t len;
1434
1435        // tokenize the filter string on a space
1436        while ((token = php_strtok_r(filter, " ", &saveptr)) != NULL) {
1437                filter = NULL;
1438                list_head = malloc(sizeof(struct ea_pattern_t));
1439                memset(list_head, 0, sizeof(struct ea_pattern_t));
1440
1441                len = strlen(token);
1442                list_head->pattern = malloc(len + 1);
1443                strncpy(list_head->pattern, token, len + 1);
1444                list_head->next = p;
1445                p = list_head;
1446        }
1447
1448        return list_head;
1449}
1450
1451/******************************************************************************/
1452/*
1453 * Begin of dynamic loadable module interfaces.
1454 * There are two interfaces:
1455 *  - standard php module,
1456 *  - zend extension.
1457 */
1458PHP_INI_MH(eaccelerator_filter) {
1459  EAG(pattern_list) = ea_parse_filter(new_value);
1460  return SUCCESS;
1461}
1462
1463static PHP_INI_MH(eaccelerator_OnUpdateLong) {
1464  long *p = (long*)mh_arg1;
1465  *p = zend_atoi(new_value, new_value_length);
1466  return SUCCESS;
1467}
1468
1469static PHP_INI_MH(eaccelerator_OnUpdateBool) {
1470  zend_bool *p = (zend_bool*)mh_arg1;
1471  if (strncasecmp("on", new_value, sizeof("on"))) {
1472    *p = (zend_bool) atoi(new_value);
1473  } else {
1474    *p = (zend_bool) 1;
1475  }
1476  return SUCCESS;
1477}
1478
1479PHP_INI_BEGIN()
1480STD_PHP_INI_ENTRY("eaccelerator.enable",         "1", PHP_INI_ALL, OnUpdateBool, enabled, zend_eaccelerator_globals, eaccelerator_globals)
1481STD_PHP_INI_ENTRY("eaccelerator.optimizer",      "1", PHP_INI_ALL, OnUpdateBool, optimizer_enabled, zend_eaccelerator_globals, eaccelerator_globals)
1482ZEND_INI_ENTRY1("eaccelerator.shm_size",        "0", PHP_INI_SYSTEM, eaccelerator_OnUpdateLong, &ea_shm_size)
1483ZEND_INI_ENTRY1("eaccelerator.shm_max",         "0", PHP_INI_SYSTEM, eaccelerator_OnUpdateLong, &ea_shm_max)
1484ZEND_INI_ENTRY1("eaccelerator.shm_ttl",         "0", PHP_INI_SYSTEM, eaccelerator_OnUpdateLong, &ea_shm_ttl)
1485ZEND_INI_ENTRY1("eaccelerator.shm_prune_period", "0", PHP_INI_SYSTEM, eaccelerator_OnUpdateLong, &ea_shm_prune_period)
1486ZEND_INI_ENTRY1("eaccelerator.debug",           "1", PHP_INI_SYSTEM, eaccelerator_OnUpdateLong, &ea_debug)
1487STD_PHP_INI_ENTRY("eaccelerator.log_file",      "", PHP_INI_SYSTEM, OnUpdateString, ea_log_file, zend_eaccelerator_globals, eaccelerator_globals)
1488STD_PHP_INI_ENTRY("eaccelerator.check_mtime",     "1", PHP_INI_SYSTEM, OnUpdateBool, check_mtime_enabled, zend_eaccelerator_globals, eaccelerator_globals)
1489ZEND_INI_ENTRY1("eaccelerator.shm_only",        "0", PHP_INI_SYSTEM, eaccelerator_OnUpdateBool, &ea_scripts_shm_only)
1490#ifdef WITH_EACCELERATOR_INFO
1491STD_PHP_INI_ENTRY("eaccelerator.allowed_admin_path",       "", PHP_INI_SYSTEM, OnUpdateString, allowed_admin_path, zend_eaccelerator_globals, eaccelerator_globals)
1492#endif
1493STD_PHP_INI_ENTRY("eaccelerator.cache_dir",      "/tmp/eaccelerator", PHP_INI_SYSTEM, OnUpdateString, cache_dir, zend_eaccelerator_globals, eaccelerator_globals)
1494PHP_INI_ENTRY("eaccelerator.filter",             "",  PHP_INI_ALL, eaccelerator_filter)
1495PHP_INI_END()
1496
1497static void eaccelerator_clean_request(TSRMLS_D) {
1498  ea_used_entry  *p = (ea_used_entry*)EAG(used_entries);
1499  if (ea_mm_instance != NULL) {
1500    EACCELERATOR_UNPROTECT();
1501    if (p != NULL) {
1502      EACCELERATOR_LOCK_RW();
1503      while (p != NULL) {
1504        p->entry->use_cnt--;
1505        if (p->entry->removed && p->entry->use_cnt <= 0) {
1506          if (ea_mm_instance->removed == p->entry) {
1507            ea_mm_instance->removed = p->entry->next;
1508            ea_mm_instance->rem_cnt--;
1509            eaccelerator_free_nolock(p->entry);
1510            p->entry = NULL;
1511          } else {
1512            ea_cache_entry *q = ea_mm_instance->removed;
1513            while (q != NULL && q->next != p->entry) {
1514              q = q->next;
1515            }
1516            if (q != NULL) {
1517              q->next = p->entry->next;
1518              ea_mm_instance->rem_cnt--;
1519              eaccelerator_free_nolock(p->entry);
1520              p->entry = NULL;
1521            }
1522          }
1523        }
1524        p = p->next;
1525      }
1526      EACCELERATOR_UNLOCK_RW();
1527    }
1528    EACCELERATOR_PROTECT();
1529    p = (ea_used_entry*)EAG(used_entries);
1530    while (p != NULL) {
1531      ea_used_entry* r = p;
1532      p = p->next;
1533      if (r->entry != NULL && r->entry->use_cnt < 0) {
1534        eaccelerator_free(r->entry);
1535      }
1536      efree(r);
1537    }
1538  }
1539  EAG(used_entries) = NULL;
1540  EAG(in_request) = 0;
1541}
1542
1543/* signal handlers */
1544#ifdef WITH_EACCELERATOR_CRASH_DETECTION
1545static void eaccelerator_crash_handler(int dummy) {
1546  struct tm *loctime;
1547
1548  TSRMLS_FETCH();
1549  fflush(stdout);
1550  fflush(stderr);
1551#ifdef SIGSEGV
1552  if (EAG(original_sigsegv_handler) != eaccelerator_crash_handler) {
1553    signal(SIGSEGV, EAG(original_sigsegv_handler));
1554  } else {
1555    signal(SIGSEGV, SIG_DFL);
1556  }
1557#endif
1558#ifdef SIGFPE
1559  if (EAG(original_sigfpe_handler) != eaccelerator_crash_handler) {
1560    signal(SIGFPE, EAG(original_sigfpe_handler));
1561  } else {
1562    signal(SIGFPE, SIG_DFL);
1563  }
1564#endif
1565#ifdef SIGBUS
1566  if (EAG(original_sigbus_handler) != eaccelerator_crash_handler) {
1567    signal(SIGBUS, EAG(original_sigbus_handler));
1568  } else {
1569    signal(SIGBUS, SIG_DFL);
1570  }
1571#endif
1572#ifdef SIGILL
1573  if (EAG(original_sigill_handler) != eaccelerator_crash_handler) {
1574    signal(SIGILL, EAG(original_sigill_handler));
1575  } else {
1576    signal(SIGILL, SIG_DFL);
1577  }
1578#endif
1579#ifdef SIGABRT
1580  if (EAG(original_sigabrt_handler) != eaccelerator_crash_handler) {
1581    signal(SIGABRT, EAG(original_sigabrt_handler));
1582  } else {
1583    signal(SIGABRT, SIG_DFL);
1584  }
1585#endif
1586  eaccelerator_clean_request(TSRMLS_C);
1587
1588  loctime = localtime(&EAG(req_start));
1589
1590  if (EG(active_op_array)) {
1591    fprintf(stderr, "[%s] [notice] EACCELERATOR(%d): PHP crashed on opline %ld of %s() at %s:%u\n\n",
1592      asctime(loctime),
1593      getpid(),
1594      (long)(active_opline-EG(active_op_array)->opcodes),
1595      get_active_function_name(TSRMLS_C),
1596      zend_get_executed_filename(TSRMLS_C),
1597      zend_get_executed_lineno(TSRMLS_C));
1598  } else {
1599    fprintf(stderr, "[%s] [notice] EACCELERATOR(%d): PHP crashed\n\n", asctime(loctime), getpid());
1600  }
1601#if !defined(WIN32) && !defined(NETWARE)
1602  kill(getpid(), dummy);
1603#else
1604  raise(dummy);
1605#endif
1606}
1607#endif
1608
1609static void eaccelerator_init_globals(zend_eaccelerator_globals *eag)
1610{
1611        eag->used_entries = NULL;
1612        eag->enabled = 1;
1613        eag->cache_dir = NULL;
1614        eag->optimizer_enabled = 1;
1615        eag->check_mtime_enabled = 1;
1616        eag->compiler = 0;
1617        eag->ea_log_file = '\000';
1618        eag->in_request = 0;
1619        eag->allowed_admin_path= NULL;
1620        eag->pattern_list = NULL;
1621}
1622
1623static void eaccelerator_globals_dtor(zend_eaccelerator_globals *eag)
1624{
1625        struct ea_pattern_t *p, *q;
1626
1627        /* free the list of patterns */
1628        p = eag->pattern_list;
1629        while (p != NULL) {
1630                q = p;
1631                free(p->pattern);
1632                free(p);
1633                p = q->next;
1634        }
1635        eag->pattern_list = NULL;
1636}
1637
1638static void register_eaccelerator_as_zend_extension();
1639
1640static int eaccelerator_check_php_version(TSRMLS_D) {
1641  zval v;
1642  int ret = 0;
1643  if (zend_get_constant("PHP_VERSION", sizeof("PHP_VERSION")-1, &v TSRMLS_CC)) {
1644    if (Z_TYPE(v) == IS_STRING &&
1645        Z_STRLEN(v) == sizeof(PHP_VERSION)-1 &&
1646        strcmp(Z_STRVAL(v),PHP_VERSION) == 0) {
1647      ret = 1;
1648    } else {
1649      ea_debug_error("[%s] This build of \"%s\" was compiled for PHP version %s. Rebuild it for your PHP version (%s) or download precompiled binaries.\n",
1650                                        EACCELERATOR_EXTENSION_NAME, EACCELERATOR_EXTENSION_NAME,PHP_VERSION,Z_STRVAL(v));
1651    }
1652    zval_dtor(&v);
1653  } else {
1654    ea_debug_error("[%s] This build of \"%s\" was compiled for PHP version %s. Rebuild it for your PHP version.\n",
1655                                EACCELERATOR_EXTENSION_NAME, EACCELERATOR_EXTENSION_NAME, PHP_VERSION);
1656  }
1657  return ret;
1658}
1659
1660static void make_hash_dirs(char *fullpath, int lvl) {
1661  int j;
1662  int n = strlen(fullpath);
1663  mode_t old_umask = umask(0);
1664 
1665  if (lvl < 1)
1666    return;
1667  if (fullpath[n-1] != '/')
1668    fullpath[n++] = '/';
1669 
1670  for (j = 0; j < 16; j++) {
1671    fullpath[n] = num2hex[j];       
1672    fullpath[n+1] = 0;
1673    mkdir(fullpath, 0777);
1674    make_hash_dirs(fullpath, lvl-1);
1675  }
1676  fullpath[n+2] = 0;
1677  umask(old_umask);
1678}
1679
1680
1681PHP_MINIT_FUNCTION(eaccelerator) {
1682  char fullpath[MAXPATHLEN];
1683
1684  if (type == MODULE_PERSISTENT) {
1685#ifndef ZEND_WIN32
1686    if (strcmp(sapi_module.name,"apache") == 0) {
1687      if (getpid() != getpgrp()) {
1688        return SUCCESS;
1689      }
1690    }
1691#endif
1692  }
1693  if (!eaccelerator_check_php_version(TSRMLS_C)) {
1694    /*
1695                 * do not return FAILURE, because it causes PHP to completely fail.
1696                 * Just disable eAccelerator instead of making eA fail starting php
1697                 */
1698    return SUCCESS;
1699  }
1700  ZEND_INIT_MODULE_GLOBALS(eaccelerator, eaccelerator_init_globals, NULL);
1701  REGISTER_INI_ENTRIES();
1702  REGISTER_STRING_CONSTANT("EACCELERATOR_VERSION", EACCELERATOR_VERSION, CONST_CS | CONST_PERSISTENT);
1703  REGISTER_LONG_CONSTANT("EACCELERATOR_SHM_AND_DISK", ea_shm_and_disk, CONST_CS | CONST_PERSISTENT);
1704  REGISTER_LONG_CONSTANT("EACCELERATOR_SHM", ea_shm, CONST_CS | CONST_PERSISTENT);
1705  REGISTER_LONG_CONSTANT("EACCELERATOR_SHM_ONLY", ea_shm_only, CONST_CS | CONST_PERSISTENT);
1706  REGISTER_LONG_CONSTANT("EACCELERATOR_DISK_ONLY", ea_disk_only, CONST_CS | CONST_PERSISTENT);
1707  REGISTER_LONG_CONSTANT("EACCELERATOR_NONE", ea_none, CONST_CS | CONST_PERSISTENT);
1708  encode_version(EACCELERATOR_VERSION, &binary_eaccelerator_version[0], &binary_eaccelerator_version[1]);
1709  encode_version(PHP_VERSION, &binary_php_version[0], &binary_php_version[1]);
1710  encode_version(ZEND_VERSION, &binary_zend_version[0], &binary_zend_version[1]);
1711  ea_is_extension = 1;
1712
1713  ea_debug_init(TSRMLS_C);
1714
1715  if(!ea_scripts_shm_only) {
1716    snprintf(fullpath, MAXPATHLEN-1, "%s/", EAG(cache_dir));
1717    make_hash_dirs(fullpath, EACCELERATOR_HASH_LEVEL);
1718  }
1719
1720  if (type == MODULE_PERSISTENT &&
1721      strcmp(sapi_module.name, "cgi") != 0 &&
1722      strcmp(sapi_module.name, "cli") != 0) {
1723    DBG(ea_debug_put, (EA_DEBUG, "\n=======================================\n"));
1724    DBG(ea_debug_printf, (EA_DEBUG, "[%d] EACCELERATOR STARTED\n", getpid()));
1725    DBG(ea_debug_put, (EA_DEBUG, "=======================================\n"));
1726
1727    if (init_mm(TSRMLS_C) == FAILURE) {
1728      zend_error(E_CORE_WARNING,"[%s] Can not create shared memory area", EACCELERATOR_EXTENSION_NAME);
1729      return FAILURE;
1730    }
1731    ea_saved_zend_compile_file = zend_compile_file;
1732
1733#ifdef DEBUG
1734    zend_compile_file = profile_compile_file;
1735    ea_saved_zend_execute = zend_execute;
1736    zend_execute = profile_execute;
1737#else
1738    zend_compile_file = eaccelerator_compile_file;
1739#endif
1740  }
1741 
1742  if (!ea_is_zend_extension) {
1743    register_eaccelerator_as_zend_extension();
1744  }
1745 
1746  /* cache the properties_info destructor */
1747  properties_info_dtor = get_zend_destroy_property_info(TSRMLS_C);
1748  return SUCCESS;
1749}
1750
1751PHP_MSHUTDOWN_FUNCTION(eaccelerator) {
1752  if (ea_mm_instance == NULL || !ea_is_extension) {
1753    return SUCCESS;
1754  }
1755  zend_compile_file = ea_saved_zend_compile_file;
1756  shutdown_mm(TSRMLS_C);
1757  DBG(ea_debug_put, (EA_DEBUG, "========================================\n"));
1758  DBG(ea_debug_printf, (EA_DEBUG, "[%d] EACCELERATOR STOPPED\n", getpid()));
1759  DBG(ea_debug_put, (EA_DEBUG, "========================================\n\n"));
1760  ea_debug_shutdown();
1761  UNREGISTER_INI_ENTRIES();
1762#ifdef ZTS
1763  ts_free_id(eaccelerator_globals_id);
1764#else
1765  eaccelerator_globals_dtor(&eaccelerator_globals TSRMLS_CC);
1766#endif
1767  ea_is_zend_extension = 0;
1768  ea_is_extension = 0;
1769  return SUCCESS;
1770}
1771
1772PHP_RINIT_FUNCTION(eaccelerator)
1773{
1774        if (ea_mm_instance == NULL) {
1775                return SUCCESS;
1776        }
1777
1778        DBG(ea_debug_printf, (EA_DEBUG, "[%d] Enter RINIT\n",getpid()));
1779        DBG(ea_debug_put, (EA_PROFILE_OPCODES, "\n========================================\n"));
1780
1781        EAG(in_request) = 1;
1782        EAG(used_entries) = NULL;
1783        EAG(compiler) = 0;
1784        EAG(refcount_helper) = 1;
1785        EAG(req_start) = sapi_get_request_time(TSRMLS_C);       /* record request start time for later use */
1786
1787        zend_hash_init(&EAG(restored), 0, NULL, NULL, 0);
1788
1789#ifdef DEBUG
1790        EAG(xpad) = 0;
1791        EAG(profile_level) = 0;
1792#endif
1793
1794#ifdef WITH_EACCELERATOR_CRASH_DETECTION
1795#ifdef SIGSEGV
1796        EAG(original_sigsegv_handler) = signal(SIGSEGV, eaccelerator_crash_handler);
1797#endif
1798#ifdef SIGFPE
1799        EAG(original_sigfpe_handler) = signal(SIGFPE, eaccelerator_crash_handler);
1800#endif
1801#ifdef SIGBUS
1802        EAG(original_sigbus_handler) = signal(SIGBUS, eaccelerator_crash_handler);
1803#endif
1804#ifdef SIGILL
1805        EAG(original_sigill_handler) = signal(SIGILL, eaccelerator_crash_handler);
1806#endif
1807#ifdef SIGABRT
1808        EAG(original_sigabrt_handler) = signal(SIGABRT, eaccelerator_crash_handler);
1809#endif
1810#endif
1811
1812        DBG(ea_debug_printf, (EA_DEBUG, "[%d] Leave RINIT\n",getpid()));
1813       
1814        return SUCCESS;
1815}
1816
1817PHP_RSHUTDOWN_FUNCTION(eaccelerator)
1818{
1819        if (ea_mm_instance == NULL) {
1820                return SUCCESS;
1821        }
1822        zend_hash_destroy(&EAG(restored));
1823#ifdef WITH_EACCELERATOR_CRASH_DETECTION
1824#ifdef SIGSEGV
1825        if (EAG(original_sigsegv_handler) != eaccelerator_crash_handler) {
1826                signal(SIGSEGV, EAG(original_sigsegv_handler));
1827        } else {
1828                signal(SIGSEGV, SIG_DFL);
1829        }
1830#endif
1831#ifdef SIGFPE
1832        if (EAG(original_sigfpe_handler) != eaccelerator_crash_handler) {
1833                signal(SIGFPE, EAG(original_sigfpe_handler));
1834        } else {
1835                signal(SIGFPE, SIG_DFL);
1836        }
1837#endif
1838#ifdef SIGBUS
1839        if (EAG(original_sigbus_handler) != eaccelerator_crash_handler) {
1840                signal(SIGBUS, EAG(original_sigbus_handler));
1841        } else {
1842                signal(SIGBUS, SIG_DFL);
1843        }
1844#endif
1845#ifdef SIGILL
1846        if (EAG(original_sigill_handler) != eaccelerator_crash_handler) {
1847                signal(SIGILL, EAG(original_sigill_handler));
1848        } else {
1849                signal(SIGILL, SIG_DFL);
1850        }
1851#endif
1852#ifdef SIGABRT
1853        if (EAG(original_sigabrt_handler) != eaccelerator_crash_handler) {
1854                signal(SIGABRT, EAG(original_sigabrt_handler));
1855        } else {
1856                signal(SIGABRT, SIG_DFL);
1857        }
1858#endif
1859#endif
1860        DBG(ea_debug_printf, (EA_DEBUG, "[%d] Enter RSHUTDOWN\n",getpid()));
1861        eaccelerator_clean_request(TSRMLS_C);
1862        DBG(ea_debug_printf, (EA_DEBUG, "[%d] Leave RSHUTDOWN\n",getpid()));
1863        return SUCCESS;
1864}
1865
1866ZEND_BEGIN_ARG_INFO(eaccelerator_second_arg_force_ref, 0)
1867  ZEND_ARG_PASS_INFO(0)
1868  ZEND_ARG_PASS_INFO(1)
1869ZEND_END_ARG_INFO();
1870
1871function_entry eaccelerator_functions[] = {
1872#ifdef WITH_EACCELERATOR_INFO
1873  PHP_FE(eaccelerator_caching, NULL)
1874  PHP_FE(eaccelerator_clear, NULL)
1875        PHP_FE(eaccelerator_clean, NULL)
1876  PHP_FE(eaccelerator_info, NULL)
1877  PHP_FE(eaccelerator_purge, NULL)
1878  PHP_FE(eaccelerator_cached_scripts, NULL)
1879  PHP_FE(eaccelerator_removed_scripts, NULL)
1880  PHP_FE(eaccelerator_check_mtime, NULL)
1881  #ifdef WITH_EACCELERATOR_OPTIMIZER
1882    PHP_FE(eaccelerator_optimizer, NULL)
1883  #endif
1884#endif
1885#ifdef WITH_EACCELERATOR_DISASSEMBLER
1886  PHP_FE(eaccelerator_dasm_file, NULL)
1887#endif
1888  {NULL, NULL, NULL, 0U, 0U}
1889};
1890
1891zend_module_entry eaccelerator_module_entry = {
1892#if ZEND_MODULE_API_NO >= 20010901
1893  STANDARD_MODULE_HEADER,
1894#endif
1895  EACCELERATOR_EXTENSION_NAME,
1896  eaccelerator_functions,
1897  PHP_MINIT(eaccelerator),
1898  PHP_MSHUTDOWN(eaccelerator),
1899  PHP_RINIT(eaccelerator),
1900  PHP_RSHUTDOWN(eaccelerator),
1901  PHP_MINFO(eaccelerator),
1902#if ZEND_MODULE_API_NO >= 20010901
1903  EACCELERATOR_VERSION,          /* extension version number (string) */
1904#endif
1905  STANDARD_MODULE_PROPERTIES
1906};
1907
1908#if defined(COMPILE_DL_EACCELERATOR)
1909ZEND_GET_MODULE(eaccelerator)
1910#endif
1911
1912static startup_func_t last_startup;
1913static zend_llist_element *eaccelerator_el;
1914
1915static const unsigned char eaccelerator_logo[] = {
1916      71,  73,  70,  56,  57,  97,  88,   0,  31,   0,
1917     213,   0,   0, 150, 153, 196, 237, 168,  86, 187,
1918     206, 230,   4,   4,   4, 108, 110, 144,  99, 144,
1919     199, 136, 138, 184,  87,  88, 109, 165, 165, 167,
1920     163, 166, 202, 240, 151,  44, 149,  91,  21, 225,
1921     225, 229,   4,  76, 164, 252, 215, 171, 255, 255,
1922     255, 212, 212, 224, 241, 200, 149, 141, 144, 192,
1923     216, 216, 226, 251, 230, 205, 192, 193, 218, 207,
1924     221, 238, 181, 188, 216, 130, 132, 168, 150, 152,
1925     185, 152, 152, 154, 180, 181, 198, 215, 184, 147,
1926      40, 102, 177, 224, 232, 242, 244, 244, 244, 235,
1927     236, 239, 118, 121, 157, 193, 193, 194, 146, 148,
1928     174, 181, 143,  96, 154, 183, 219, 156, 159, 200,
1929     126, 128, 170, 174, 175, 193,  65,  39,   7, 232,
1930     214, 192, 254, 241, 226, 246, 246, 248, 108,  65,
1931      13, 142, 144, 185, 252, 224, 189, 138, 171, 213,
1932      69, 122, 188, 239, 244, 249,  48,  49,  60, 176,
1933     178, 209, 200, 201, 222, 252, 252, 253, 251, 251,
1934     251, 162, 163, 187, 208, 208, 213, 169, 171, 205,
1935     241, 234, 225, 255, 252, 249, 254, 248, 241, 140,
1936     142, 169, 249, 186, 111,  33, 249,   4,   0,   0,
1937       0,   0,   0,  44,   0,   0,   0,   0,  88,   0,
1938      31,   0,   0,   6, 255,  64, 137, 112,  72,  44,
1939      26, 143, 200, 164, 114, 201,  92,  62, 158, 208,
1940     168, 116,  74, 173,  90, 175, 216, 108,  85, 168,
1941     237, 122, 191,  15,  25, 163, 118, 209, 153,   0,
1942      68, 128,  73, 119, 169,  49, 100,  86,  46, 120,
1943      78, 127, 216,  60,  21,  93,  83,   8, 208,  85,
1944      60,  54,  83, 114, 117, 132,  89,  32,  23,  38,
1945      73,  38, 103,  72,  38,  23,  32,  82, 123, 146,
1946     147,  69, 106,   9,  52,  21,  19,  53, 137, 138,
1947      51,  51, 156, 141,  21, 100,  52,   9, 148, 166,
1948     123,   0, 106, 126,  16,  21, 104,  67, 169, 106,
1949     140,   9,   3, 159, 140,  18, 176, 182,   0,  23,
1950      21, 101,  67,  21,  80,  32,  52, 192,  52,  44,
1951       6,  16,  15,   6,  23,  44,  81,  24,  81,  25,
1952      81, 194,  80,  25,   6,  18,  12,  80,  23,  15,
1953     169,  15, 172, 155, 105,  33,   7,   4, 158,  46,
1954       0,  33,   3,   7,   7,  51,   7, 139, 231, 225,
1955       7,  25, 124,  23,  23,  52, 190,  19,   4, 205,
1956      44,  27,   4,   4,  19,  57,  15,  33,  15,  32,
1957      54,  64, 168, 241,   0,   5,  10,  28, 255,  54,
1958     160, 120, 128, 163, 160,  65,   2,  15, 244, 229,
1959     200, 113, 162,  26,   4,  20, 252,  22, 130, 128,
1960      48,  98, 131,  30,  34,  38, 102, 208,  58,  64,
1961     203,   4,  73, 115,   3,   6, 184, 152,  69,  75,
1962     228,   1,  87,  38,  80, 204,  19, 242, 235,   9,
1963      54,  31,   4,  78, 212, 152, 192, 128,   1,   8,
1964     255,  31,  79,  78, 108,  99, 245, 239,  24,   3,
1965     136,  16,  32, 212, 139,  24,  34,  83,   8,   3,
1966      62,  33, 128,  56,  90,   3,  68, 136,  17, 173,
1967     138, 176,  76,  16, 114,  64,   2, 145,   4,   0,
1968     136, 196, 128, 129,  22, 215, 146,  66,  50, 224,
1969     248,  40,  33, 147,  62,   2,  11,  39, 120, 120,
1970      48, 162,  33,  10,   2,  44,  62,  64, 156, 144,
1971     244,  31, 129,  17,  12,  31, 240, 157, 240,  76,
1972     238, 131,  12,   4, 160, 110,   4,   1, 130, 192,
1973       6,   6,  33, 112, 212,  48, 226, 195, 220,  25,
1974     145,  95, 189, 118,  77,  64,  50, 236, 172,  79,
1975      66,  92, 140,  96,  11,   0,  71,  78,  12,  39,
1976      12, 108, 200,  71,  32,  68, 190,  16,  38,  70,
1977      56,  54, 120,  87,  71, 136,  16,  25,  70,  36,
1978     160, 141,  65,  33,  10,  12,  57,  13,  36, 240,
1979     173,  15,  64,   2,  31,  58, 186, 189,  34,  96,
1980     238,  86,  73,  90, 198,  75, 146,  12,   1, 128,
1981     249, 203, 208,  62,  74,   9,  49,  96,   0,   3,
1982      53,   9,   6,  78, 220,  78, 141, 218, 251, 137,
1983      19, 168, 199, 163, 230,  46, 254, 246, 120, 247,
1984     169, 193, 183, 127, 234,  34,  67,   6,  63,  51,
1985     249, 156,  12,  55, 160, 181,  57, 114, 255, 137,
1986      52,   3, 127,  62,  12, 129,  65, 118,  74, 112,
1987     247,  29, 120, 219,  81, 163, 224, 130, 224,  61,
1988      40, 225, 130,  15, 222, 162,  74,  60, 160, 116,
1989     181,  95,   6,  36, 189, 212, 255, 225, 103,  39,
1990      97, 224,  74, 119, 186, 157,  98, 162,  18, 169,
1991     172,  65,   3,  13,  40, 184, 178, 149,  14,   9,
1992     160,  97,   2,  87,  18, 204, 104,  66,  89,  51,
1993      24,  23, 163,  16,  62, 132, 224, 195,  90,  39,
1994       6, 121, 132,  37,  58, 176, 136, 195,  59,  46,
1995     152, 133,  98, 135, 174,   8, 129, 129, 143,  56,
1996      36, 160,  93,  33,  84,  82,  97,   3,  11,  12,
1997     136, 128,   3,  66, 227,  44,  49,   2, 110,  67,
1998     248, 224, 131,   6,  34,  48, 176, 204,   3, 131,
1999      84, 169, 230,  19,  44, 128, 144, 195,   6,  71,
2000     190, 179,   4,  26,  46, 136, 169,   1,  10,  57,
2001     236, 192,   2,  15,  79, 164, 185, 166, 154,  55,
2002     124, 192, 192, 155,   8, 228,  54, 130,  11, 136,
2003     134,  86, 167, 152,  99,  34, 176,  65,  14,  12,
2004     124,  16,   8,  20, 126,  62, 176,   2,   5,  20,
2005     188, 160, 233, 166, 155,  58, 224, 105,   4,  61,
2006     252,  73,  69, 160,  59,  12,  42,   2,  10,   8,
2007      32, 160, 193, 170, 171, 166, 138, 130,   8, 144,
2008     238, 240,   1, 159, 145,  72,   0,   5,  15,  20,
2009      56,  16,  65,   4,  63,   4, 224, 171,   2,   1,
2010       0, 171, 192, 176, 195,   6,  32, 234,  21, 129,
2011     126,  48,  85,  79, 204,  50,  43, 235,   7,  55,
2012     196,  97, 171, 165, 159, 254, 240, 195, 176,  63,
2013     188, 240,   0, 173,  80, 244, 192, 194, 153,   2,
2014     192, 113, 236, 184, 114, 172,  96, 174, 185, 152,
2015      82, 160, 255, 133,   7,  13,  20, 240, 132,  12,
2016       5, 196,  80, 192,  92,  15, 192,  32, 175,   0,
2017      15,  88,  16, 195, 190,  22, 148, 224, 238,  19,
2018     250, 242,  27, 176, 188, 226, 198, 128, 205, 190,
2019     252, 202,  96, 111,   1, 248,  62, 128, 112,   1,
2020      22,  80, 106, 235,  11,  14,  80, 188, 107, 175,
2021     190, 250, 106,  45, 198,   1, 144, 192, 193,  19,
2022       5,  52, 208,  64,  24,  29, 116,  96, 111,   3,
2023     240,  54,   0,  67, 200,   2,   8, 160,  50,  12,
2024      30, 216,  11, 133, 203,  48, 192,  76,  51,  12,
2025     237,  62, 112,  65, 187,  54, 216, 107, 178,   7,
2026      49, 168,  28,  52, 190, 237, 194,  80, 178, 196,
2027      43, 108,  28, 172,   2,  11, 120, 204, 193, 211,
2028      17, 112, 176, 235, 211,  28, 236, 240,  68,   7,
2029      33, 151, 128, 179, 184,  45,  55,  32,  64, 180,
2030      22, 120, 224, 114, 203,  10, 199,  48, 179, 215,
2031     225, 186,  12, 178, 217,  33, 163,  92, 175, 217,
2032      22, 120, 125, 131,  13, 242,  62, 224, 117, 189,
2033      35, 247,  41, 129,   3, 196,  50, 189,  64,  11,
2034      36, 216,  48, 183,  29,  79,   4,  98, 195, 164,
2035      46, 119,  80, 180, 217, 103,  75, 225, 178, 200,
2036       2, 200, 252, 196, 227, 104, 139,  44, 242,   5,
2037      50,  52, 160,  56,  12, 111,  63, 160, 246,  19,
2038     246, 218,  96, 121, 206, 122, 191, 224, 247, 223,
2039      45, 164, 238, 244, 174, 172,  63, 173, 238,   3,
2040       5, 152,  28,  50, 206,  17,  43,  76, 154,  51,
2041     232,  93,  67,  33, 185, 231, 121, 243,  46,  64,
2042      12,  29,  60,  80, 130, 208, 193, 203, 204,  46,
2043     231,  50,  96, 109, 119, 205,  13, 208, 139, 166,
2044     173,  42, 144, 176,  64,  10, 212,  87, 159, 250,
2045       2, 216, 103, 191, 192,  14, 129, 168, 252, 132,
2046     202,  33,   7,  93, 188, 230, 138, 139, 221,   0,
2047     191,  56, 239, 203, 240, 249,  49,  88, 160, 118,
2048     220,  43, 155, 189, 115, 204, 140, 227, 172, 120,
2049     243, 118, 135, 139, 245, 164, 149,  78,  74, 248,
2050     220, 130, 187, 193, 224,  30,  16,  51, 113, 149,
2051     160,   4,  54, 208,  90,   9, 102,  86,  51,  56,
2052     196, 172, 102,  98, 171,  25,  12,  74, 240,  64,
2053     152, 197, 204,  38,  53, 139,  88, 189,  90, 182,
2054     192, 201, 213, 236,  76,  48, 179, 129,   5,  96,
2055     166, 183, 113, 153,  80,  77,  66,  74, 161,  10,
2056      41,  17,   4,   0,  59,   0 };
2057 
2058static int eaccelerator_last_startup(zend_extension *extension) {
2059  int ret;
2060  extension->startup = last_startup;
2061  ret = extension->startup(extension);
2062  zend_extensions.count++;
2063  eaccelerator_el->next = zend_extensions.head;
2064  eaccelerator_el->prev = NULL;
2065  zend_extensions.head->prev = eaccelerator_el;
2066  zend_extensions.head = eaccelerator_el;
2067  if (ZendOptimizer) {
2068    if ((ZendOptimizer = zend_get_extension("Zend Optimizer")) != NULL) {
2069      ZendOptimizer->op_array_handler = NULL;
2070    }
2071  }
2072  return ret;
2073}
2074
2075/*
2076static int eaccelerator_ioncube_startup(zend_extension *extension) {
2077  int ret;
2078  zend_extension* last_ext = (zend_extension*)zend_extensions.tail->data;
2079  extension->startup = last_startup;
2080  ret = extension->startup(extension);
2081  last_startup = last_ext->startup;
2082  last_ext->startup = eaccelerator_last_startup;
2083  return ret;
2084}
2085*/
2086
2087
2088ZEND_DLEXPORT int eaccelerator_zend_startup(zend_extension *extension) {
2089 ea_is_zend_extension = 1;
2090  eaccelerator_el   = NULL;
2091  last_startup = NULL;
2092
2093  if (!ea_is_extension) {
2094    if (zend_startup_module(&eaccelerator_module_entry) != SUCCESS) {
2095      return FAILURE;
2096    }
2097  }
2098
2099  if (zend_llist_count(&zend_extensions) > 1) {
2100    zend_llist_element *p = zend_extensions.head;
2101    while (p != NULL) {
2102      zend_extension* ext = (zend_extension*)(p->data);
2103      if (strcmp(ext->name, EACCELERATOR_EXTENSION_NAME) == 0) {
2104        /* temporary removing eAccelerator extension */
2105        zend_extension* last_ext = (zend_extension*)zend_extensions.tail->data;
2106        if (eaccelerator_el != NULL) {
2107          zend_error(E_CORE_ERROR,"[%s] %s %s can not be loaded twice",
2108                   EACCELERATOR_EXTENSION_NAME,
2109                   EACCELERATOR_EXTENSION_NAME,
2110                   EACCELERATOR_VERSION);
2111          exit(1);
2112        }
2113        if (last_ext != ext) {
2114          eaccelerator_el = p;
2115          last_startup = last_ext->startup;
2116          last_ext->startup = eaccelerator_last_startup;
2117          zend_extensions.count--;
2118          if (p->prev != NULL) {
2119            p->prev->next = p->next;
2120          } else {
2121            zend_extensions.head = p->next;
2122          }
2123          if (p->next != NULL) {
2124            p->next->prev = p->prev;
2125          } else {
2126            zend_extensions.tail = p->prev;
2127          }
2128        }
2129      } else if (strcmp(ext->name, "Zend Extension Manager") == 0 ||
2130                 strcmp(ext->name, "Zend Optimizer") == 0) {
2131        /* Disable ZendOptimizer Optimizations */
2132        ZendOptimizer = ext;
2133        ext->op_array_handler = NULL;
2134      }
2135      p = p->next;
2136    }
2137  }
2138
2139  php_register_info_logo(EACCELERATOR_VERSION_GUID, "text/plain", (unsigned char*)EACCELERATOR_VERSION_STRING, sizeof(EACCELERATOR_VERSION_STRING));
2140  php_register_info_logo(EACCELERATOR_LOGO_GUID,    "image/gif",  (unsigned char*)eaccelerator_logo, sizeof(eaccelerator_logo));
2141
2142  return SUCCESS;
2143}
2144
2145#ifndef ZEND_EXT_API
2146#  define ZEND_EXT_API    ZEND_DLEXPORT
2147#endif
2148
2149ZEND_EXTENSION();
2150
2151ZEND_DLEXPORT zend_extension zend_extension_entry = {
2152  EACCELERATOR_EXTENSION_NAME,
2153  EACCELERATOR_VERSION,
2154  "eAccelerator",
2155  "http://eaccelerator.net",
2156  "Copyright (c) 2004-2010 eAccelerator",
2157  eaccelerator_zend_startup,
2158  NULL,
2159  NULL,   /* void (*activate)() */
2160  NULL,   /* void (*deactivate)() */
2161  NULL,   /* void (*message_handle)(int message, void *arg) */
2162#ifdef WITH_EACCELERATOR_OPTIMIZER
2163  eaccelerator_optimize,   /* void (*op_array_handler)(zend_op_array *o_a); */
2164#else
2165  NULL,   /* void (*op_array_handler)(zend_op_array *o_a); */
2166#endif
2167  NULL,   /* void (*statement_handler)(zend_op_array *o_a); */
2168  NULL,   /* void (*fcall_begin_handler)(zend_op_array *o_a); */
2169  NULL,   /* void (*fcall_end_handler)(zend_op_array *o_a); */
2170  NULL,   /* void (*op_array_ctor)(zend_op_array *o_a); */
2171  NULL,   /* void (*op_array_dtor)(zend_op_array *o_a); */
2172#ifdef COMPAT_ZEND_EXTENSION_PROPERTIES
2173  NULL,   /* api_no_check */
2174  COMPAT_ZEND_EXTENSION_PROPERTIES
2175#else
2176  STANDARD_ZEND_EXTENSION_PROPERTIES
2177#endif
2178};
2179
2180static zend_extension eaccelerator_extension_entry = {
2181  EACCELERATOR_EXTENSION_NAME,
2182  EACCELERATOR_VERSION,
2183  "eAccelerator",
2184  "http://eaccelerator.net",
2185  "Copyright (c) 2004-2010 eAccelerator",
2186  eaccelerator_zend_startup,
2187  NULL,
2188  NULL,   /* void (*activate)() */
2189  NULL,   /* void (*deactivate)() */
2190  NULL,   /* void (*message_handle)(int message, void *arg) */
2191#ifdef WITH_EACCELERATOR_OPTIMIZER
2192  eaccelerator_optimize,   /* void (*op_array_handler)(zend_op_array *o_a); */
2193#else
2194  NULL,   /* void (*op_array_handler)(zend_op_array *o_a); */
2195#endif
2196  NULL,   /* void (*statement_handler)(zend_op_array *o_a); */
2197  NULL,   /* void (*fcall_begin_handler)(zend_op_array *o_a); */
2198  NULL,   /* void (*fcall_end_handler)(zend_op_array *o_a); */
2199  NULL,   /* void (*op_array_ctor)(zend_op_array *o_a); */
2200  NULL,   /* void (*op_array_dtor)(zend_op_array *o_a); */
2201#ifdef COMPAT_ZEND_EXTENSION_PROPERTIES
2202  NULL,   /* api_no_check */
2203  COMPAT_ZEND_EXTENSION_PROPERTIES
2204#else
2205  STANDARD_ZEND_EXTENSION_PROPERTIES
2206#endif
2207};
2208
2209static void register_eaccelerator_as_zend_extension() {
2210  zend_extension extension = eaccelerator_extension_entry;
2211  extension.handle = 0;
2212  zend_llist_prepend_element(&zend_extensions, &extension);
2213}
2214
2215/******************************************************************************/
2216
2217#endif  /* #ifdef HAVE_EACCELERATOR */
2218
2219/*
2220 * Local variables:
2221 * tab-width: 2
2222 * c-basic-offset: 2
2223 * End:
2224 * vim: noet sw=2 ts=2 fdm=marker
2225 */
Note: See TracBrowser for help on using the repository browser.