--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | APC |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2006 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Daniel Cowgill <dcowgill@communityconnect.com> |
+ | Rasmus Lerdorf <rasmus@php.net> |
+ +----------------------------------------------------------------------+
+
+ This software was contributed to PHP by Community Connect Inc. in 2002
+ and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
+ Future revisions and derivatives of this source code must acknowledge
+ Community Connect Inc. as the original contributor of this module by
+ leaving this note intact in the source code.
+
+ All other licensing and usage conditions are those of the PHP Group.
+
+ */
+
+/* $Id: php_apc.c,v 3.154 2007/12/26 22:31:20 rasmus Exp $ */
+
+#include "apc_zend.h"
+#include "apc_cache.h"
+#include "apc_main.h"
+#include "apc_sma.h"
+#include "apc_lock.h"
+#include "php_globals.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "SAPI.h"
+#include "rfc1867.h"
+#include "php_apc.h"
+#if PHP_API_VERSION <= 20020918
+#if HAVE_APACHE
+#ifdef APC_PHP4_STAT
+#undef XtOffsetOf
+#include "httpd.h"
+#endif
+#endif
+#endif
+
+#if HAVE_SIGACTION
+#include "apc_signal.h"
+#endif
+
+/* {{{ PHP_FUNCTION declarations */
+PHP_FUNCTION(apc_cache_info);
+PHP_FUNCTION(apc_clear_cache);
+PHP_FUNCTION(apc_sma_info);
+PHP_FUNCTION(apc_store);
+PHP_FUNCTION(apc_fetch);
+PHP_FUNCTION(apc_delete);
+PHP_FUNCTION(apc_compile_file);
+PHP_FUNCTION(apc_define_constants);
+PHP_FUNCTION(apc_load_constants);
+PHP_FUNCTION(apc_add);
+/* }}} */
+
+/* {{{ ZEND_DECLARE_MODULE_GLOBALS(apc) */
+ZEND_DECLARE_MODULE_GLOBALS(apc)
+
+/* True globals */
+apc_cache_t* apc_cache = NULL;
+apc_cache_t* apc_user_cache = NULL;
+void* apc_compiled_filters = NULL;
+
+static void php_apc_init_globals(zend_apc_globals* apc_globals TSRMLS_DC)
+{
+ apc_globals->filters = NULL;
+ apc_globals->initialized = 0;
+ apc_globals->cache_stack = apc_stack_create(0);
+ apc_globals->cache_by_default = 1;
+ apc_globals->slam_defense = 0;
+ apc_globals->mem_size_ptr = NULL;
+ apc_globals->fpstat = 1;
+ apc_globals->stat_ctime = 0;
+ apc_globals->write_lock = 1;
+ apc_globals->report_autofilter = 0;
+ apc_globals->apc_optimize_function = NULL;
+#ifdef MULTIPART_EVENT_FORMDATA
+ apc_globals->rfc1867 = 0;
+#endif
+ apc_globals->copied_zvals = NULL;
+#ifdef ZEND_ENGINE_2
+ apc_globals->reserved_offset = -1;
+#endif
+ apc_globals->localcache = 0;
+ apc_globals->localcache_size = 0;
+ apc_globals->lcache = NULL;
+ apc_globals->force_file_update = 0;
+ apc_globals->coredump_unmap = 0;
+}
+
+static void php_apc_shutdown_globals(zend_apc_globals* apc_globals TSRMLS_DC)
+{
+ /* deallocate the ignore patterns */
+ if (apc_globals->filters != NULL) {
+ int i;
+ for (i=0; apc_globals->filters[i] != NULL; i++) {
+ apc_efree(apc_globals->filters[i]);
+ }
+ apc_efree(apc_globals->filters);
+ }
+
+ /* the stack should be empty */
+ assert(apc_stack_size(apc_globals->cache_stack) == 0);
+
+ /* apc cleanup */
+ apc_stack_destroy(apc_globals->cache_stack);
+
+ /* the rest of the globals are cleaned up in apc_module_shutdown() */
+}
+
+/* }}} */
+
+/* {{{ PHP_INI */
+
+static PHP_INI_MH(OnUpdate_filters) /* {{{ */
+{
+ APCG(filters) = apc_tokenize(new_value, ',');
+ return SUCCESS;
+}
+/* }}} */
+
+static PHP_INI_MH(OnUpdateShmSegments) /* {{{ */
+{
+#if APC_MMAP
+ if(atoi(new_value)!=1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "apc.shm_segments setting ignored in MMAP mode");
+ }
+ APCG(shm_segments) = 1;
+#else
+ APCG(shm_segments) = atoi(new_value);
+#endif
+ return SUCCESS;
+}
+/* }}} */
+
+#ifdef MULTIPART_EVENT_FORMDATA
+static PHP_INI_MH(OnUpdateRfc1867Freq) /* {{{ */
+{
+ int tmp;
+ tmp = zend_atoi(new_value, new_value_length);
+ if(tmp < 0) {
+ apc_eprint("rfc1867_freq must be greater than or equal to zero.");
+ return FAILURE;
+ }
+ if(new_value[new_value_length-1] == '%') {
+ if(tmp > 100) {
+ apc_eprint("rfc1867_freq cannot be over 100%%");
+ return FAILURE;
+ }
+ APCG(rfc1867_freq) = tmp / 100.0;
+ } else {
+ APCG(rfc1867_freq) = tmp;
+ }
+ return SUCCESS;
+}
+/* }}} */
+#endif
+
+#ifdef ZEND_ENGINE_2
+#define OnUpdateInt OnUpdateLong
+#endif
+
+PHP_INI_BEGIN()
+STD_PHP_INI_BOOLEAN("apc.enabled", "1", PHP_INI_SYSTEM, OnUpdateBool, enabled, zend_apc_globals, apc_globals)
+STD_PHP_INI_ENTRY("apc.shm_segments", "1", PHP_INI_SYSTEM, OnUpdateShmSegments, shm_segments, zend_apc_globals, apc_globals)
+STD_PHP_INI_ENTRY("apc.shm_size", "30", PHP_INI_SYSTEM, OnUpdateInt, shm_size, zend_apc_globals, apc_globals)
+STD_PHP_INI_BOOLEAN("apc.include_once_override", "0", PHP_INI_SYSTEM, OnUpdateBool, include_once, zend_apc_globals, apc_globals)
+STD_PHP_INI_ENTRY("apc.num_files_hint", "1000", PHP_INI_SYSTEM, OnUpdateInt, num_files_hint, zend_apc_globals, apc_globals)
+STD_PHP_INI_ENTRY("apc.user_entries_hint", "4096", PHP_INI_SYSTEM, OnUpdateInt, user_entries_hint, zend_apc_globals, apc_globals)
+STD_PHP_INI_ENTRY("apc.gc_ttl", "3600", PHP_INI_SYSTEM, OnUpdateInt, gc_ttl, zend_apc_globals, apc_globals)
+STD_PHP_INI_ENTRY("apc.ttl", "0", PHP_INI_SYSTEM, OnUpdateInt, ttl, zend_apc_globals, apc_globals)
+STD_PHP_INI_ENTRY("apc.user_ttl", "0", PHP_INI_SYSTEM, OnUpdateInt, user_ttl, zend_apc_globals, apc_globals)
+#if APC_MMAP
+STD_PHP_INI_ENTRY("apc.mmap_file_mask", NULL, PHP_INI_SYSTEM, OnUpdateString, mmap_file_mask, zend_apc_globals, apc_globals)
+#endif
+PHP_INI_ENTRY("apc.filters", NULL, PHP_INI_SYSTEM, OnUpdate_filters)
+STD_PHP_INI_BOOLEAN("apc.cache_by_default", "1", PHP_INI_ALL, OnUpdateBool, cache_by_default, zend_apc_globals, apc_globals)
+STD_PHP_INI_ENTRY("apc.slam_defense", "0", PHP_INI_SYSTEM, OnUpdateInt, slam_defense, zend_apc_globals, apc_globals)
+STD_PHP_INI_ENTRY("apc.file_update_protection", "2", PHP_INI_SYSTEM, OnUpdateInt,file_update_protection, zend_apc_globals, apc_globals)
+STD_PHP_INI_BOOLEAN("apc.enable_cli", "0", PHP_INI_SYSTEM, OnUpdateBool, enable_cli, zend_apc_globals, apc_globals)
+STD_PHP_INI_ENTRY("apc.max_file_size", "1M", PHP_INI_SYSTEM, OnUpdateInt, max_file_size, zend_apc_globals, apc_globals)
+STD_PHP_INI_BOOLEAN("apc.stat", "1", PHP_INI_SYSTEM, OnUpdateBool, fpstat, zend_apc_globals, apc_globals)
+STD_PHP_INI_BOOLEAN("apc.stat_ctime", "0", PHP_INI_SYSTEM, OnUpdateBool, stat_ctime, zend_apc_globals, apc_globals)
+STD_PHP_INI_BOOLEAN("apc.write_lock", "1", PHP_INI_SYSTEM, OnUpdateBool, write_lock, zend_apc_globals, apc_globals)
+STD_PHP_INI_BOOLEAN("apc.report_autofilter", "0", PHP_INI_SYSTEM, OnUpdateBool, report_autofilter,zend_apc_globals, apc_globals)
+#ifdef MULTIPART_EVENT_FORMDATA
+STD_PHP_INI_BOOLEAN("apc.rfc1867", "0", PHP_INI_SYSTEM, OnUpdateBool, rfc1867, zend_apc_globals, apc_globals)
+STD_PHP_INI_ENTRY("apc.rfc1867_prefix", "upload_", PHP_INI_SYSTEM, OnUpdateStringUnempty, rfc1867_prefix, zend_apc_globals, apc_globals)
+STD_PHP_INI_ENTRY("apc.rfc1867_name", "APC_UPLOAD_PROGRESS", PHP_INI_SYSTEM, OnUpdateStringUnempty, rfc1867_name, zend_apc_globals, apc_globals)
+STD_PHP_INI_ENTRY("apc.rfc1867_freq", "0", PHP_INI_SYSTEM, OnUpdateRfc1867Freq, rfc1867_freq, zend_apc_globals, apc_globals)
+#endif
+STD_PHP_INI_BOOLEAN("apc.localcache", "0", PHP_INI_SYSTEM, OnUpdateBool, localcache, zend_apc_globals, apc_globals)
+STD_PHP_INI_ENTRY("apc.localcache.size", "512", PHP_INI_SYSTEM, OnUpdateInt, localcache_size, zend_apc_globals, apc_globals)
+STD_PHP_INI_BOOLEAN("apc.coredump_unmap", "0", PHP_INI_SYSTEM, OnUpdateBool, coredump_unmap, zend_apc_globals, apc_globals)
+PHP_INI_END()
+
+/* }}} */
+
+/* {{{ PHP_MINFO_FUNCTION(apc) */
+static PHP_MINFO_FUNCTION(apc)
+{
+ php_info_print_table_start();
+ php_info_print_table_row(2, "APC Support", APCG(enabled) ? "enabled" : "disabled");
+ php_info_print_table_row(2, "Version", APC_VERSION);
+#if APC_MMAP
+ php_info_print_table_row(2, "MMAP Support", "Enabled");
+ php_info_print_table_row(2, "MMAP File Mask", APCG(mmap_file_mask));
+#else
+ php_info_print_table_row(2, "MMAP Support", "Disabled");
+#endif
+#if APC_SEM_LOCKS
+ php_info_print_table_row(2, "Locking type", "IPC Semaphore");
+#elif APC_FUTEX_LOCKS
+ php_info_print_table_row(2, "Locking type", "Linux Futex Locks");
+#elif APC_PTHREADMUTEX_LOCKS
+ php_info_print_table_row(2, "Locking type", "pthread mutex Locks");
+#elif APC_SPIN_LOCKS
+ php_info_print_table_row(2, "Locking type", "spin Locks");
+#else
+ php_info_print_table_row(2, "Locking type", "File Locks");
+#endif
+ php_info_print_table_row(2, "Revision", "$Revision: 3.154 $");
+ php_info_print_table_row(2, "Build Date", __DATE__ " " __TIME__);
+ php_info_print_table_end();
+ DISPLAY_INI_ENTRIES();
+}
+/* }}} */
+
+#ifdef MULTIPART_EVENT_FORMDATA
+extern int apc_rfc1867_progress(unsigned int event, void *event_data, void **extra TSRMLS_DC);
+#endif
+
+/* {{{ PHP_MINIT_FUNCTION(apc) */
+static PHP_MINIT_FUNCTION(apc)
+{
+ ZEND_INIT_MODULE_GLOBALS(apc, php_apc_init_globals, php_apc_shutdown_globals);
+
+ REGISTER_INI_ENTRIES();
+
+ /* Disable APC in cli mode unless overridden by apc.enable_cli */
+ if(!APCG(enable_cli) && !strcmp(sapi_module.name, "cli")) {
+ APCG(enabled) = 0;
+ }
+
+ if (APCG(enabled)) {
+ if(APCG(initialized)) {
+ apc_process_init(module_number TSRMLS_CC);
+ } else {
+ apc_module_init(module_number TSRMLS_CC);
+ apc_zend_init(TSRMLS_C);
+ apc_process_init(module_number TSRMLS_CC);
+#ifdef MULTIPART_EVENT_FORMDATA
+ /* File upload progress tracking */
+ if(APCG(rfc1867)) {
+ php_rfc1867_callback = apc_rfc1867_progress;
+ }
+#endif
+ }
+ }
+
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_MSHUTDOWN_FUNCTION(apc) */
+static PHP_MSHUTDOWN_FUNCTION(apc)
+{
+ if(APCG(enabled)) {
+ apc_process_shutdown(TSRMLS_C);
+ apc_zend_shutdown(TSRMLS_C);
+ apc_module_shutdown(TSRMLS_C);
+#ifndef ZTS
+ php_apc_shutdown_globals(&apc_globals);
+#endif
+ }
+#ifdef ZTS
+ ts_free_id(apc_globals_id);
+#endif
+ UNREGISTER_INI_ENTRIES();
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_RINIT_FUNCTION(apc) */
+static PHP_RINIT_FUNCTION(apc)
+{
+ if(APCG(enabled)) {
+ apc_request_init(TSRMLS_C);
+
+#if HAVE_SIGACTION
+ apc_set_signals();
+#endif
+ }
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_RSHUTDOWN_FUNCTION(apc) */
+static PHP_RSHUTDOWN_FUNCTION(apc)
+{
+ if(APCG(enabled)) {
+ apc_request_shutdown(TSRMLS_C);
+ }
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ proto array apc_cache_info([string type] [, bool limited]) */
+PHP_FUNCTION(apc_cache_info)
+{
+ apc_cache_info_t* info;
+ apc_cache_link_t* p;
+ zval* list;
+ char *cache_type;
+ int ct_len;
+ zend_bool limited=0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sb", &cache_type, &ct_len, &limited) == FAILURE) {
+ return;
+ }
+
+ if(ZEND_NUM_ARGS()) {
+ if(!strcasecmp(cache_type,"user")) {
+ info = apc_cache_info(apc_user_cache, limited);
+ } else if(!strcasecmp(cache_type,"filehits")) {
+#ifdef APC_FILEHITS
+ RETVAL_ZVAL(APCG(filehits), 1, 0);
+ return;
+#else
+ RETURN_FALSE;
+#endif
+ } else {
+ info = apc_cache_info(apc_cache, limited);
+ }
+ } else info = apc_cache_info(apc_cache, limited);
+
+ if(!info) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "No APC info available. Perhaps APC is not enabled? Check apc.enabled in your ini file");
+ RETURN_FALSE;
+ }
+
+ array_init(return_value);
+ add_assoc_long(return_value, "num_slots", info->num_slots);
+ add_assoc_long(return_value, "ttl", info->ttl);
+ add_assoc_long(return_value, "num_hits", info->num_hits);
+ add_assoc_long(return_value, "num_misses", info->num_misses);
+ add_assoc_long(return_value, "start_time", info->start_time);
+ add_assoc_long(return_value, "expunges", info->expunges);
+ add_assoc_long(return_value, "mem_size", info->mem_size);
+ add_assoc_long(return_value, "num_entries", info->num_entries);
+ add_assoc_long(return_value, "num_inserts", info->num_inserts);
+#ifdef MULTIPART_EVENT_FORMDATA
+ add_assoc_long(return_value, "file_upload_progress", 1);
+#else
+ add_assoc_long(return_value, "file_upload_progress", 0);
+#endif
+#if APC_MMAP
+ add_assoc_stringl(return_value, "memory_type", "mmap", sizeof("mmap")-1, 1);
+#else
+ add_assoc_stringl(return_value, "memory_type", "IPC shared", sizeof("IPC shared")-1, 1);
+#endif
+#if APC_SEM_LOCKS
+ add_assoc_stringl(return_value, "locking_type", "IPC semaphore", sizeof("IPC semaphore")-1, 1);
+#elif APC_FUTEX_LOCKS
+ add_assoc_stringl(return_value, "locking_type", "Linux Futex", sizeof("Linux Futex")-1, 1);
+#elif APC_PTHREADMUTEX_LOCKS
+ add_assoc_stringl(return_value, "locking_type", "pthread mutex", sizeof("pthread mutex")-1, 1);
+#elif APC_SPIN_LOCKS
+ add_assoc_stringl(return_value, "locking_type", "spin", sizeof("spin")-1, 1);
+#else
+ add_assoc_stringl(return_value, "locking_type", "file", sizeof("file")-1, 1);
+#endif
+ if(limited) {
+ apc_cache_free_info(info);
+ return;
+ }
+
+ ALLOC_INIT_ZVAL(list);
+ array_init(list);
+
+ for (p = info->list; p != NULL; p = p->next) {
+ zval* link;
+
+ ALLOC_INIT_ZVAL(link);
+ array_init(link);
+
+ if(p->type == APC_CACHE_ENTRY_FILE) {
+ add_assoc_string(link, "filename", p->data.file.filename, 1);
+ add_assoc_long(link, "device", p->data.file.device);
+ add_assoc_long(link, "inode", p->data.file.inode);
+ add_assoc_string(link, "type", "file", 1);
+ } else if(p->type == APC_CACHE_ENTRY_USER) {
+ add_assoc_string(link, "info", p->data.user.info, 1);
+ add_assoc_long(link, "ttl", (long)p->data.user.ttl);
+ add_assoc_string(link, "type", "user", 1);
+ }
+ add_assoc_long(link, "num_hits", p->num_hits);
+ add_assoc_long(link, "mtime", p->mtime);
+ add_assoc_long(link, "creation_time", p->creation_time);
+ add_assoc_long(link, "deletion_time", p->deletion_time);
+ add_assoc_long(link, "access_time", p->access_time);
+ add_assoc_long(link, "ref_count", p->ref_count);
+ add_assoc_long(link, "mem_size", p->mem_size);
+ add_next_index_zval(list, link);
+ }
+ add_assoc_zval(return_value, "cache_list", list);
+
+ ALLOC_INIT_ZVAL(list);
+ array_init(list);
+
+ for (p = info->deleted_list; p != NULL; p = p->next) {
+ zval* link;
+
+ ALLOC_INIT_ZVAL(link);
+ array_init(link);
+
+ if(p->type == APC_CACHE_ENTRY_FILE) {
+ add_assoc_string(link, "filename", p->data.file.filename, 1);
+ add_assoc_long(link, "device", p->data.file.device);
+ add_assoc_long(link, "inode", p->data.file.inode);
+ add_assoc_string(link, "type", "file", 1);
+ } else if(p->type == APC_CACHE_ENTRY_USER) {
+ add_assoc_string(link, "info", p->data.user.info, 1);
+ add_assoc_long(link, "ttl", (long)p->data.user.ttl);
+ add_assoc_string(link, "type", "user", 1);
+ }
+ add_assoc_long(link, "num_hits", p->num_hits);
+ add_assoc_long(link, "mtime", p->mtime);
+ add_assoc_long(link, "creation_time", p->creation_time);
+ add_assoc_long(link, "deletion_time", p->deletion_time);
+ add_assoc_long(link, "access_time", p->access_time);
+ add_assoc_long(link, "ref_count", p->ref_count);
+ add_assoc_long(link, "mem_size", p->mem_size);
+ add_next_index_zval(list, link);
+ }
+ add_assoc_zval(return_value, "deleted_list", list);
+
+ apc_cache_free_info(info);
+}
+/* }}} */
+
+/* {{{ proto void apc_clear_cache() */
+PHP_FUNCTION(apc_clear_cache)
+{
+ char *cache_type;
+ int ct_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &cache_type, &ct_len) == FAILURE) {
+ return;
+ }
+
+ if(ZEND_NUM_ARGS()) {
+ if(!strcasecmp(cache_type,"user")) {
+ apc_cache_clear(apc_user_cache);
+ RETURN_TRUE;
+ }
+ }
+ apc_cache_clear(apc_cache);
+}
+/* }}} */
+
+/* {{{ proto array apc_sma_info([bool limited]) */
+PHP_FUNCTION(apc_sma_info)
+{
+ apc_sma_info_t* info;
+ zval* block_lists;
+ int i;
+ zend_bool limited = 0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &limited) == FAILURE) {
+ return;
+ }
+
+ info = apc_sma_info(limited);
+
+ if(!info) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "No APC SMA info available. Perhaps APC is disabled via apc.enabled?");
+ RETURN_FALSE;
+ }
+
+ array_init(return_value);
+ add_assoc_long(return_value, "num_seg", info->num_seg);
+ add_assoc_long(return_value, "seg_size", info->seg_size);
+ add_assoc_long(return_value, "avail_mem", apc_sma_get_avail_mem());
+
+ if(limited) {
+ apc_sma_free_info(info);
+ return;
+ }
+
+#if ALLOC_DISTRIBUTION
+ {
+ size_t *adist = apc_sma_get_alloc_distribution();
+ zval* list;
+ ALLOC_INIT_ZVAL(list);
+ array_init(list);
+ for(i=0; i<30; i++) {
+ add_next_index_long(list, adist[i]);
+ }
+ add_assoc_zval(return_value, "adist", list);
+ }
+#endif
+ ALLOC_INIT_ZVAL(block_lists);
+ array_init(block_lists);
+
+ for (i = 0; i < info->num_seg; i++) {
+ apc_sma_link_t* p;
+ zval* list;
+
+ ALLOC_INIT_ZVAL(list);
+ array_init(list);
+
+ for (p = info->list[i]; p != NULL; p = p->next) {
+ zval* link;
+
+ ALLOC_INIT_ZVAL(link);
+ array_init(link);
+
+ add_assoc_long(link, "size", p->size);
+ add_assoc_long(link, "offset", p->offset);
+ add_next_index_zval(list, link);
+ }
+ add_next_index_zval(block_lists, list);
+ }
+ add_assoc_zval(return_value, "block_lists", block_lists);
+ apc_sma_free_info(info);
+}
+/* }}} */
+
+/* {{{ _apc_store */
+int _apc_store(char *strkey, int strkey_len, const zval *val, const unsigned int ttl, const int exclusive TSRMLS_DC) {
+ apc_cache_entry_t *entry;
+ apc_cache_key_t key;
+ time_t t;
+ size_t mem_size = 0;
+
+#if PHP_API_VERSION < 20041225
+#if HAVE_APACHE && defined(APC_PHP4_STAT)
+ t = ((request_rec *)SG(server_context))->request_time;
+#else
+ t = time(0);
+#endif
+#else
+ t = sapi_get_request_time(TSRMLS_C);
+#endif
+
+ if(!APCG(enabled)) return 0;
+
+ HANDLE_BLOCK_INTERRUPTIONS();
+
+ APCG(mem_size_ptr) = &mem_size;
+ if (!(entry = apc_cache_make_user_entry(strkey, strkey_len + 1, val, ttl))) {
+ APCG(mem_size_ptr) = NULL;
+ apc_cache_expunge(apc_cache,t);
+ apc_cache_expunge(apc_user_cache,t);
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+ return 0;
+ }
+
+ if (!apc_cache_make_user_key(&key, strkey, strkey_len + 1, t)) {
+ APCG(mem_size_ptr) = NULL;
+ apc_cache_free_entry(entry);
+ apc_cache_expunge(apc_cache,t);
+ apc_cache_expunge(apc_user_cache,t);
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+ return 0;
+ }
+
+ if (!apc_cache_user_insert(apc_user_cache, key, entry, t, exclusive TSRMLS_CC)) {
+ APCG(mem_size_ptr) = NULL;
+ apc_cache_free_entry(entry);
+ apc_cache_expunge(apc_cache,t);
+ apc_cache_expunge(apc_user_cache,t);
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+ return 0;
+ }
+
+ APCG(mem_size_ptr) = NULL;
+
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+
+ return 1;
+}
+/* }}} */
+
+/* {{{ proto int apc_store(string key, zval var [, ttl ])
+ */
+PHP_FUNCTION(apc_store) {
+ zval *val;
+ char *strkey;
+ int strkey_len;
+ long ttl = 0L;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &strkey, &strkey_len, &val, &ttl) == FAILURE) {
+ return;
+ }
+
+ if(!strkey_len) RETURN_FALSE;
+
+ if(_apc_store(strkey, strkey_len, val, (unsigned int)ttl, 0 TSRMLS_CC)) RETURN_TRUE;
+ RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto int apc_add(string key, zval var [, ttl ])
+ */
+PHP_FUNCTION(apc_add) {
+ zval *val;
+ char *strkey;
+ int strkey_len;
+ long ttl = 0L;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &strkey, &strkey_len, &val, &ttl) == FAILURE) {
+ return;
+ }
+
+ if(!strkey_len) RETURN_FALSE;
+
+ if(_apc_store(strkey, strkey_len, val, (unsigned int)ttl, 1 TSRMLS_CC)) RETURN_TRUE;
+ RETURN_FALSE;
+}
+/* }}} */
+
+void *apc_erealloc_wrapper(void *ptr, size_t size) {
+ return _erealloc(ptr, size, 0 ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
+}
+
+/* {{{ RETURN_ZVAL for php4 */
+#if !defined(ZEND_ENGINE_2) && !defined(RETURN_ZVAL)
+#define RETURN_ZVAL(zv, copy, dtor) { RETVAL_ZVAL(zv, copy, dtor); return; }
+#define RETVAL_ZVAL(zv, copy, dtor) ZVAL_ZVAL(return_value, zv, copy, dtor)
+#define ZVAL_ZVAL(z, zv, copy, dtor) { \
+ int is_ref, refcount; \
+ is_ref = (z)->is_ref; \
+ refcount = (z)->refcount; \
+ *(z) = *(zv); \
+ if (copy) { \
+ zval_copy_ctor(z); \
+ } \
+ if (dtor) { \
+ if (!copy) { \
+ ZVAL_NULL(zv); \
+ } \
+ zval_ptr_dtor(&zv); \
+ } \
+ (z)->is_ref = is_ref; \
+ (z)->refcount = refcount; \
+ }
+#endif
+/* }}} */
+
+/* {{{ proto mixed apc_fetch(mixed key)
+ */
+PHP_FUNCTION(apc_fetch) {
+ zval *key;
+ HashTable *hash;
+ HashPosition hpos;
+ zval **hentry;
+ zval *result;
+ zval *result_entry;
+ char *strkey;
+ int strkey_len;
+ apc_cache_entry_t* entry;
+ time_t t;
+
+ if(!APCG(enabled)) RETURN_FALSE;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &key) == FAILURE) {
+ return;
+ }
+
+#if PHP_API_VERSION < 20041225
+#if HAVE_APACHE && defined(APC_PHP4_STAT)
+ t = ((request_rec *)SG(server_context))->request_time;
+#else
+ t = time(0);
+#endif
+#else
+ t = sapi_get_request_time(TSRMLS_C);
+#endif
+
+ if(Z_TYPE_P(key) != IS_STRING && Z_TYPE_P(key) != IS_ARRAY) {
+ convert_to_string(key);
+ }
+
+ if(Z_TYPE_P(key) == IS_STRING) {
+ strkey = Z_STRVAL_P(key);
+ strkey_len = Z_STRLEN_P(key);
+ if(!strkey_len) RETURN_FALSE;
+ entry = apc_cache_user_find(apc_user_cache, strkey, strkey_len + 1, t);
+ if(entry) {
+ /* deep-copy returned shm zval to emalloc'ed return_value */
+ apc_cache_fetch_zval(return_value, entry->data.user.val, apc_php_malloc, apc_php_free);
+ apc_cache_release(apc_user_cache, entry);
+ } else {
+ RETURN_FALSE;
+ }
+ } else if(Z_TYPE_P(key) == IS_ARRAY) {
+ hash = Z_ARRVAL_P(key);
+ MAKE_STD_ZVAL(result);
+ array_init(result);
+ zend_hash_internal_pointer_reset_ex(hash, &hpos);
+ while(zend_hash_get_current_data_ex(hash, (void**)&hentry, &hpos) == SUCCESS) {
+ if(Z_TYPE_PP(hentry) != IS_STRING) {
+ apc_wprint("apc_fetch() expects a string or array of strings.");
+ RETURN_FALSE;
+ }
+ entry = apc_cache_user_find(apc_user_cache, Z_STRVAL_PP(hentry), Z_STRLEN_PP(hentry) + 1, t);
+ if(entry) {
+ /* deep-copy returned shm zval to emalloc'ed return_value */
+ MAKE_STD_ZVAL(result_entry);
+ apc_cache_fetch_zval(result_entry, entry->data.user.val, apc_php_malloc, apc_php_free);
+ apc_cache_release(apc_user_cache, entry);
+ zend_hash_add(Z_ARRVAL_P(result), Z_STRVAL_PP(hentry), Z_STRLEN_PP(hentry) +1, &result_entry, sizeof(zval*), NULL);
+ } /* don't set values we didn't find */
+ zend_hash_move_forward_ex(hash, &hpos);
+ }
+ RETURN_ZVAL(result, 0, 1);
+ } else {
+ apc_wprint("apc_fetch() expects a string or array of strings.");
+ RETURN_FALSE;
+ }
+
+ return;
+}
+/* }}} */
+
+/* {{{ proto mixed apc_delete(string key)
+ */
+PHP_FUNCTION(apc_delete) {
+ char *strkey;
+ int strkey_len;
+
+ if(!APCG(enabled)) RETURN_FALSE;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &strkey, &strkey_len) == FAILURE) {
+ return;
+ }
+
+ if(!strkey_len) RETURN_FALSE;
+
+ if(apc_cache_user_delete(apc_user_cache, strkey, strkey_len + 1)) {
+ RETURN_TRUE;
+ } else {
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+static void _apc_define_constants(zval *constants, zend_bool case_sensitive TSRMLS_DC) {
+ char *const_key;
+ unsigned int const_key_len;
+ zval **entry;
+ HashPosition pos;
+
+ zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(constants), &pos);
+ while (zend_hash_get_current_data_ex(Z_ARRVAL_P(constants), (void**)&entry, &pos) == SUCCESS) {
+ zend_constant c;
+ int key_type;
+ ulong num_key;
+
+ key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(constants), &const_key, &const_key_len, &num_key, 0, &pos);
+ if(key_type != HASH_KEY_IS_STRING) {
+ zend_hash_move_forward_ex(Z_ARRVAL_P(constants), &pos);
+ continue;
+ }
+ switch(Z_TYPE_PP(entry)) {
+ case IS_LONG:
+ case IS_DOUBLE:
+ case IS_STRING:
+ case IS_BOOL:
+ case IS_RESOURCE:
+ case IS_NULL:
+ break;
+ default:
+ zend_hash_move_forward_ex(Z_ARRVAL_P(constants), &pos);
+ continue;
+ }
+ c.value = **entry;
+ zval_copy_ctor(&c.value);
+ c.flags = case_sensitive;
+ c.name = zend_strndup(const_key, const_key_len);
+ c.name_len = const_key_len;
+#ifdef ZEND_ENGINE_2
+ c.module_number = PHP_USER_CONSTANT;
+#endif
+ zend_register_constant(&c TSRMLS_CC);
+
+ zend_hash_move_forward_ex(Z_ARRVAL_P(constants), &pos);
+ }
+}
+
+/* {{{ proto mixed apc_define_constants(string key, array constants [,bool case-sensitive])
+ */
+PHP_FUNCTION(apc_define_constants) {
+ char *strkey;
+ int strkey_len;
+ zval *constants = NULL;
+ zend_bool case_sensitive = 1;
+ int argc = ZEND_NUM_ARGS();
+
+ if (zend_parse_parameters(argc TSRMLS_CC, "sa|b", &strkey, &strkey_len, &constants, &case_sensitive) == FAILURE) {
+ return;
+ }
+
+ if(!strkey_len) RETURN_FALSE;
+
+ _apc_define_constants(constants, case_sensitive TSRMLS_CC);
+ if(_apc_store(strkey, strkey_len, constants, 0, 0 TSRMLS_CC)) RETURN_TRUE;
+ RETURN_FALSE;
+} /* }}} */
+
+/* {{{ proto mixed apc_load_constants(string key [, bool case-sensitive])
+ */
+PHP_FUNCTION(apc_load_constants) {
+ char *strkey;
+ int strkey_len;
+ apc_cache_entry_t* entry;
+ time_t t;
+ zend_bool case_sensitive = 1;
+
+ if(!APCG(enabled)) RETURN_FALSE;
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &strkey, &strkey_len, &case_sensitive) == FAILURE) {
+ return;
+ }
+
+ if(!strkey_len) RETURN_FALSE;
+
+#if PHP_API_VERSION < 20041225
+#if HAVE_APACHE && defined(APC_PHP4_STAT)
+ t = ((request_rec *)SG(server_context))->request_time;
+#else
+ t = time(0);
+#endif
+#else
+ t = sapi_get_request_time(TSRMLS_C);
+#endif
+
+ entry = apc_cache_user_find(apc_user_cache, strkey, strkey_len + 1, t);
+
+ if(entry) {
+ _apc_define_constants(entry->data.user.val, case_sensitive TSRMLS_CC);
+ apc_cache_release(apc_user_cache, entry);
+ RETURN_TRUE;
+ } else {
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+/* {{{ proto boolean apc_compile_file(string filename)
+ */
+PHP_FUNCTION(apc_compile_file) {
+ char *filename;
+ int filename_len;
+ zend_file_handle file_handle;
+ zend_op_array *op_array;
+ long slam_defense = 0;
+ char** filters = NULL;
+ zend_bool cache_by_default = 1;
+ HashTable cg_function_table, cg_class_table, eg_function_table, eg_class_table;
+ HashTable *cg_orig_function_table, *cg_orig_class_table, *eg_orig_function_table, *eg_orig_class_table;
+
+ if(!APCG(enabled)) RETURN_FALSE;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
+ return;
+ }
+
+ if(!filename) RETURN_FALSE;
+
+ /* reset slam defense, filters, and cache_by_default */
+ slam_defense = APCG(slam_defense);
+ APCG(slam_defense) = 0;
+
+ filters = APCG(filters);
+ APCG(filters) = NULL;
+
+ cache_by_default = APCG(cache_by_default);
+ APCG(cache_by_default) = 1;
+
+ /* Replace function/class tables to avoid namespace conflicts */
+ zend_hash_init_ex(&cg_function_table, 100, NULL, ZEND_FUNCTION_DTOR, 1, 0);
+ cg_orig_function_table = CG(function_table);
+ CG(function_table) = &cg_function_table;
+ zend_hash_init_ex(&cg_class_table, 10, NULL, ZEND_CLASS_DTOR, 1, 0);
+ cg_orig_class_table = CG(class_table);
+ CG(class_table) = &cg_class_table;
+ eg_orig_function_table = EG(function_table);
+ EG(function_table) = CG(function_table);
+ eg_orig_class_table = EG(class_table);
+ EG(class_table) = CG(class_table);
+ APCG(force_file_update) = 1;
+
+ /* Compile the file, loading it into the cache */
+ file_handle.type = ZEND_HANDLE_FILENAME;
+ file_handle.filename = filename;
+ file_handle.free_filename = 0;
+ file_handle.opened_path = NULL;
+ zend_try {
+ op_array = zend_compile_file(&file_handle, ZEND_INCLUDE TSRMLS_CC);
+ } zend_catch {
+ apc_wprint("Error compiling %s in apc_compile_file.", filename);
+ op_array = NULL;
+ } zend_end_try();
+
+ /* Return class/function tables to previous states, destroy temp tables */
+ APCG(force_file_update) = 0;
+ CG(function_table) = cg_orig_function_table;
+ zend_hash_destroy(&cg_function_table);
+ CG(class_table) = cg_orig_class_table;
+ zend_hash_destroy(&cg_class_table);
+ EG(function_table) = eg_orig_function_table;
+ EG(class_table) = eg_orig_class_table;
+
+ /* Restore global settings */
+ APCG(slam_defense) = slam_defense;
+ APCG(filters) = filters;
+ APCG(cache_by_default) = cache_by_default;
+
+ if(op_array == NULL) { RETURN_FALSE; }
+
+ /* Free up everything */
+ zend_destroy_file_handle(&file_handle TSRMLS_CC);
+#ifdef ZEND_ENGINE_2
+ destroy_op_array(op_array TSRMLS_CC);
+#else
+ destroy_op_array(op_array);
+#endif
+ efree(op_array);
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ apc_functions[] */
+function_entry apc_functions[] = {
+ PHP_FE(apc_cache_info, NULL)
+ PHP_FE(apc_clear_cache, NULL)
+ PHP_FE(apc_sma_info, NULL)
+ PHP_FE(apc_store, NULL)
+ PHP_FE(apc_fetch, NULL)
+ PHP_FE(apc_delete, NULL)
+ PHP_FE(apc_define_constants, NULL)
+ PHP_FE(apc_load_constants, NULL)
+ PHP_FE(apc_compile_file, NULL)
+ PHP_FE(apc_add, NULL)
+ {NULL, NULL, NULL}
+};
+/* }}} */
+
+/* {{{ module definition structure */
+
+zend_module_entry apc_module_entry = {
+ STANDARD_MODULE_HEADER,
+ "apc",
+ apc_functions,
+ PHP_MINIT(apc),
+ PHP_MSHUTDOWN(apc),
+ PHP_RINIT(apc),
+ PHP_RSHUTDOWN(apc),
+ PHP_MINFO(apc),
+ APC_VERSION,
+ STANDARD_MODULE_PROPERTIES
+};
+
+#ifdef COMPILE_DL_APC
+ZEND_GET_MODULE(apc)
+#endif
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
+ * vim<600: expandtab sw=4 ts=4 sts=4
+ */