#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "apc_cache.h"
#include "apc_iterator.h"
#include "apc_sma.h"
#include "apc_lock.h"
#include "apc_mutex.h"
#include "apc_strings.h"
#include "php_globals.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "ext/standard/file.h"
#include "ext/standard/flock_compat.h"
#include "ext/standard/md5.h"
#include "ext/standard/php_var.h"
#if PHP_VERSION_ID >= 80000
# include "php_apc_arginfo.h"
#else
# include "php_apc_legacy_arginfo.h"
#endif
#include "php74_shim.h"
#ifdef HAVE_SYS_FILE_H
#include
#endif
#include "SAPI.h"
#include "php_apc.h"
#if HAVE_SIGACTION
#include "apc_signal.h"
#endif
ZEND_DECLARE_MODULE_GLOBALS(apcu)
apc_cache_t* apc_user_cache = NULL;
apc_sma_t apc_sma;
#define X(str) zend_string *apc_str_ ## str;
APC_STRINGS
#undef X
static void php_apc_init_globals(zend_apcu_globals* apcu_globals)
{
apcu_globals->initialized = 0;
apcu_globals->slam_defense = 0;
apcu_globals->smart = 0;
apcu_globals->preload_path = NULL;
apcu_globals->coredump_unmap = 0;
apcu_globals->use_request_time = 0;
apcu_globals->serializer_name = NULL;
apcu_globals->entry_level = 0;
}
static PHP_INI_MH(OnUpdateShmSegments)
{
#if APC_MMAP
if (zend_atoi(new_value->val, new_value->len)!=1) {
php_error_docref(NULL, E_WARNING, "apc.shm_segments setting ignored in MMAP mode");
}
APCG(shm_segments) = 1;
#else
APCG(shm_segments) = zend_atoi(new_value->val, new_value->len);
#endif
return SUCCESS;
}
static PHP_INI_MH(OnUpdateShmSize)
{
zend_long s = zend_atol(new_value->val, new_value->len);
if (s <= 0) {
return FAILURE;
}
if (s < Z_L(1048576)) {
php_error_docref(
NULL, E_WARNING, "apc.shm_size now uses M/G suffixes, please update your ini files");
s = s * Z_L(1048576);
}
APCG(shm_size) = s;
return SUCCESS;
}
PHP_INI_BEGIN()
STD_PHP_INI_BOOLEAN("apc.enabled", "1", PHP_INI_SYSTEM, OnUpdateBool, enabled, zend_apcu_globals, apcu_globals)
STD_PHP_INI_ENTRY("apc.shm_segments", "1", PHP_INI_SYSTEM, OnUpdateShmSegments, shm_segments, zend_apcu_globals, apcu_globals)
STD_PHP_INI_ENTRY("apc.shm_size", "32M", PHP_INI_SYSTEM, OnUpdateShmSize, shm_size, zend_apcu_globals, apcu_globals)
STD_PHP_INI_ENTRY("apc.entries_hint", "4096", PHP_INI_SYSTEM, OnUpdateLong, entries_hint, zend_apcu_globals, apcu_globals)
STD_PHP_INI_ENTRY("apc.gc_ttl", "3600", PHP_INI_SYSTEM, OnUpdateLong, gc_ttl, zend_apcu_globals, apcu_globals)
STD_PHP_INI_ENTRY("apc.ttl", "0", PHP_INI_SYSTEM, OnUpdateLong, ttl, zend_apcu_globals, apcu_globals)
STD_PHP_INI_ENTRY("apc.smart", "0", PHP_INI_SYSTEM, OnUpdateLong, smart, zend_apcu_globals, apcu_globals)
#if APC_MMAP
STD_PHP_INI_ENTRY("apc.mmap_file_mask", NULL, PHP_INI_SYSTEM, OnUpdateString, mmap_file_mask, zend_apcu_globals, apcu_globals)
#endif
STD_PHP_INI_BOOLEAN("apc.enable_cli", "0", PHP_INI_SYSTEM, OnUpdateBool, enable_cli, zend_apcu_globals, apcu_globals)
STD_PHP_INI_BOOLEAN("apc.slam_defense", "0", PHP_INI_SYSTEM, OnUpdateBool, slam_defense, zend_apcu_globals, apcu_globals)
STD_PHP_INI_ENTRY("apc.preload_path", (char*)NULL, PHP_INI_SYSTEM, OnUpdateString, preload_path, zend_apcu_globals, apcu_globals)
STD_PHP_INI_BOOLEAN("apc.coredump_unmap", "0", PHP_INI_SYSTEM, OnUpdateBool, coredump_unmap, zend_apcu_globals, apcu_globals)
STD_PHP_INI_BOOLEAN("apc.use_request_time", "0", PHP_INI_ALL, OnUpdateBool, use_request_time, zend_apcu_globals, apcu_globals)
STD_PHP_INI_ENTRY("apc.serializer", "php", PHP_INI_SYSTEM, OnUpdateStringUnempty, serializer_name, zend_apcu_globals, apcu_globals)
PHP_INI_END()
zend_bool apc_is_enabled(void)
{
return APCG(enabled);
}
static PHP_MINFO_FUNCTION(apcu)
{
php_info_print_table_start();
php_info_print_table_row(2, "APCu Support", APCG(enabled) ? "Enabled" : "Disabled");
php_info_print_table_row(2, "Version", PHP_APCU_VERSION);
#ifdef APC_DEBUG
php_info_print_table_row(2, "APCu Debugging", "Enabled");
#else
php_info_print_table_row(2, "APCu Debugging", "Disabled");
#endif
#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 (APCG(enabled)) {
apc_serializer_t *serializer = NULL;
smart_str names = {0,};
int i;
for( i = 0, serializer = apc_get_serializers();
serializer->name != NULL;
serializer++, i++) {
if (i != 0) {
smart_str_appends(&names, ", ");
}
smart_str_appends(&names, serializer->name);
}
if (names.s) {
smart_str_0(&names);
php_info_print_table_row(2, "Serialization Support", names.s->val);
smart_str_free(&names);
} else {
php_info_print_table_row(2, "Serialization Support", "Broken");
}
} else {
php_info_print_table_row(2, "Serialization Support", "Disabled");
}
php_info_print_table_row(2, "Build Date", __DATE__ " " __TIME__);
php_info_print_table_end();
DISPLAY_INI_ENTRIES();
}
static PHP_MINIT_FUNCTION(apcu)
{
#if defined(ZTS) && defined(COMPILE_DL_APCU)
ZEND_TSRMLS_CACHE_UPDATE();
#endif
ZEND_INIT_MODULE_GLOBALS(apcu, php_apc_init_globals, NULL);
REGISTER_INI_ENTRIES();
#define X(str) \
apc_str_ ## str = zend_new_interned_string( \
zend_string_init(#str, sizeof(#str) - 1, 1));
APC_STRINGS
#undef X
apc_lock_init();
APC_MUTEX_INIT();
if (!APCG(enable_cli) && !strcmp(sapi_module.name, "cli")) {
APCG(enabled) = 0;
}
if (APCG(enabled)) {
if (!APCG(initialized)) {
#if APC_MMAP
char *mmap_file_mask = APCG(mmap_file_mask);
#else
char *mmap_file_mask = NULL;
#endif
APCG(initialized) = 1;
apc_sma_init(
&apc_sma, (void **) &apc_user_cache, (apc_sma_expunge_f) apc_cache_default_expunge,
APCG(shm_segments), APCG(shm_size), mmap_file_mask);
REGISTER_LONG_CONSTANT(APC_SERIALIZER_CONSTANT, (zend_long)&_apc_register_serializer, CONST_PERSISTENT | CONST_CS);
_apc_register_serializer(
"php", APC_SERIALIZER_NAME(php), APC_UNSERIALIZER_NAME(php), NULL);
assert(apc_get_serializers()->name != NULL);
apc_user_cache = apc_cache_create(
&apc_sma,
apc_find_serializer(APCG(serializer_name)),
APCG(entries_hint), APCG(gc_ttl), APCG(ttl), APCG(smart), APCG(slam_defense));
if (APCG(preload_path)) {
apc_cache_preload(
apc_user_cache, APCG(preload_path));
}
}
}
apc_iterator_init(module_number);
return SUCCESS;
}
static PHP_MSHUTDOWN_FUNCTION(apcu)
{
#define X(str) zend_string_release(apc_str_ ## str);
APC_STRINGS
#undef X
apc_lock_cleanup();
APC_MUTEX_CLEANUP();
if (APCG(enabled)) {
if (APCG(initialized)) {
apc_cache_detach(apc_user_cache);
apc_sma_detach(&apc_sma);
APCG(initialized) = 0;
}
#if HAVE_SIGACTION
apc_shutdown_signals();
#endif
}
apc_iterator_shutdown(module_number);
UNREGISTER_INI_ENTRIES();
return SUCCESS;
}
static PHP_RINIT_FUNCTION(apcu)
{
#if defined(ZTS) && defined(COMPILE_DL_APCU)
ZEND_TSRMLS_CACHE_UPDATE();
#endif
APCG(request_time) = 0;
if (APCG(enabled)) {
if (APCG(serializer_name)) {
apc_cache_serializer(apc_user_cache, APCG(serializer_name));
}
#if HAVE_SIGACTION
apc_set_signals();
#endif
}
return SUCCESS;
}
PHP_FUNCTION(apcu_clear_cache)
{
if (zend_parse_parameters_none() == FAILURE) {
return;
}
apc_cache_clear(apc_user_cache);
RETURN_TRUE;
}
PHP_FUNCTION(apcu_cache_info)
{
zend_bool limited = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &limited) == FAILURE) {
return;
}
if (!apc_cache_info(return_value, apc_user_cache, limited)) {
php_error_docref(NULL, E_WARNING, "No APC info available. Perhaps APC is not enabled? Check apc.enabled in your ini file");
RETURN_FALSE;
}
}
PHP_FUNCTION(apcu_key_info)
{
zend_string *key;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &key) == FAILURE) {
return;
}
apc_cache_stat(apc_user_cache, key, return_value);
}
PHP_FUNCTION(apcu_sma_info)
{
apc_sma_info_t* info;
zval block_lists;
int i;
zend_bool limited = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &limited) == FAILURE) {
return;
}
info = apc_sma_info(&apc_sma, limited);
if (!info) {
php_error_docref(NULL, 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_double(return_value, "seg_size", (double)info->seg_size);
add_assoc_double(return_value, "avail_mem", (double)apc_sma_get_avail_mem(&apc_sma));
if (limited) {
apc_sma_free_info(&apc_sma, info);
return;
}
array_init(&block_lists);
for (i = 0; i < info->num_seg; i++) {
apc_sma_link_t* p;
zval list;
array_init(&list);
for (p = info->list[i]; p != NULL; p = p->next) {
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(&apc_sma, info);
}
zend_bool php_apc_update(
zend_string *key, apc_cache_atomic_updater_t updater, void *data,
zend_bool insert_if_not_found, time_t ttl)
{
if (APCG(serializer_name)) {
apc_cache_serializer(apc_user_cache, APCG(serializer_name));
}
return apc_cache_atomic_update_long(apc_user_cache, key, updater, data, insert_if_not_found, ttl);
}
static void apc_store_helper(INTERNAL_FUNCTION_PARAMETERS, const zend_bool exclusive)
{
zval *key;
zval *val = NULL;
zend_long ttl = 0L;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|zl", &key, &val, &ttl) == FAILURE) {
return;
}
if (APCG(serializer_name)) {
apc_cache_serializer(apc_user_cache, APCG(serializer_name));
}
if (Z_TYPE_P(key) == IS_ARRAY) {
zval *hentry;
zend_string *hkey;
zend_ulong hkey_idx;
HashTable* hash = Z_ARRVAL_P(key);
zval fail_zv;
ZVAL_LONG(&fail_zv, -1);
array_init(return_value);
ZEND_HASH_FOREACH_KEY_VAL(hash, hkey_idx, hkey, hentry) {
ZVAL_DEREF(hentry);
if (hkey) {
zend_string_addref(hkey);
} else {
hkey = zend_long_to_str(hkey_idx);
}
if (!apc_cache_store(apc_user_cache, hkey, hentry, (uint32_t) ttl, exclusive)) {
zend_symtable_add_new(Z_ARRVAL_P(return_value), hkey, &fail_zv);
}
zend_string_release(hkey);
} ZEND_HASH_FOREACH_END();
return;
} else if (Z_TYPE_P(key) == IS_STRING) {
if (!val) {
RETURN_FALSE;
}
RETURN_BOOL(apc_cache_store(apc_user_cache, Z_STR_P(key), val, (uint32_t) ttl, exclusive));
} else {
apc_warning("apc_store expects key parameter to be a string or an array of key/value pairs.");
RETURN_FALSE;
}
}
PHP_FUNCTION(apcu_enabled) {
if (zend_parse_parameters_none() == FAILURE) {
return;
}
RETURN_BOOL(APCG(enabled));
}
PHP_FUNCTION(apcu_store) {
apc_store_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
}
PHP_FUNCTION(apcu_add) {
apc_store_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
}
struct php_inc_updater_args {
zend_long step;
zend_long rval;
};
static zend_bool php_inc_updater(apc_cache_t *cache, zend_long *entry, void *data) {
struct php_inc_updater_args *args = (struct php_inc_updater_args *) data;
args->rval = ATOMIC_ADD(*entry, args->step);
return 1;
}
PHP_FUNCTION(apcu_inc) {
zend_string *key;
struct php_inc_updater_args args;
zend_long step = 1, ttl = 0;
zval *success = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|lzl", &key, &step, &success, &ttl) == FAILURE) {
return;
}
args.step = step;
if (php_apc_update(key, php_inc_updater, &args, 1, ttl)) {
if (success) {
ZEND_TRY_ASSIGN_REF_TRUE(success);
}
RETURN_LONG(args.rval);
}
if (success) {
ZEND_TRY_ASSIGN_REF_FALSE(success);
}
RETURN_FALSE;
}
PHP_FUNCTION(apcu_dec) {
zend_string *key;
struct php_inc_updater_args args;
zend_long step = 1, ttl = 0;
zval *success = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|lzl", &key, &step, &success, &ttl) == FAILURE) {
return;
}
args.step = 0 - step;
if (php_apc_update(key, php_inc_updater, &args, 1, ttl)) {
if (success) {
ZEND_TRY_ASSIGN_REF_TRUE(success);
}
RETURN_LONG(args.rval);
}
if (success) {
ZEND_TRY_ASSIGN_REF_FALSE(success);
}
RETURN_FALSE;
}
static zend_bool php_cas_updater(apc_cache_t *cache, zend_long *entry, void *data) {
zend_long *vals = (zend_long *) data;
zend_long old = vals[0];
zend_long new = vals[1];
return ATOMIC_CAS(*entry, old, new);
}
PHP_FUNCTION(apcu_cas) {
zend_string *key;
zend_long vals[2];
if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sll", &key, &vals[0], &vals[1]) == FAILURE) {
return;
}
if (APCG(serializer_name)) {
apc_cache_serializer(apc_user_cache, APCG(serializer_name));
}
RETURN_BOOL(apc_cache_atomic_update_long(apc_user_cache, key, php_cas_updater, &vals, 0, 0));
}
PHP_FUNCTION(apcu_fetch) {
zval *key;
zval *success = NULL;
time_t t;
int result;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|z", &key, &success) == FAILURE) {
return;
}
t = apc_time();
if (Z_TYPE_P(key) != IS_STRING && Z_TYPE_P(key) != IS_ARRAY) {
convert_to_string(key);
}
if (Z_TYPE_P(key) == IS_STRING) {
result = apc_cache_fetch(apc_user_cache, Z_STR_P(key), t, return_value);
} else if (Z_TYPE_P(key) == IS_ARRAY) {
zval *hentry;
array_init(return_value);
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(key), hentry) {
ZVAL_DEREF(hentry);
if (Z_TYPE_P(hentry) == IS_STRING) {
zval result_entry;
ZVAL_UNDEF(&result_entry);
if (apc_cache_fetch(apc_user_cache, Z_STR_P(hentry), t, &result_entry)) {
zend_hash_update(Z_ARRVAL_P(return_value), Z_STR_P(hentry), &result_entry);
}
} else {
apc_warning("apc_fetch() expects a string or array of strings.");
}
} ZEND_HASH_FOREACH_END();
result = 1;
} else {
apc_warning("apc_fetch() expects a string or array of strings.");
result = 0;
}
if (success) {
ZEND_TRY_ASSIGN_REF_BOOL(success, result);
}
if (!result) {
RETURN_FALSE;
}
}
PHP_FUNCTION(apcu_exists) {
zval *key;
time_t t;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &key) == FAILURE) {
return;
}
t = apc_time();
if (Z_TYPE_P(key) != IS_STRING && Z_TYPE_P(key) != IS_ARRAY) {
convert_to_string(key);
}
if (Z_TYPE_P(key) == IS_STRING) {
RETURN_BOOL(apc_cache_exists(apc_user_cache, Z_STR_P(key), t));
} else if (Z_TYPE_P(key) == IS_ARRAY) {
zval *hentry;
zval true_zv;
ZVAL_TRUE(&true_zv);
array_init(return_value);
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(key), hentry) {
ZVAL_DEREF(hentry);
if (Z_TYPE_P(hentry) == IS_STRING) {
if (apc_cache_exists(apc_user_cache, Z_STR_P(hentry), t)) {
zend_hash_add_new(Z_ARRVAL_P(return_value), Z_STR_P(hentry), &true_zv);
}
} else {
apc_warning(
"apc_exists() expects a string or array of strings.");
}
} ZEND_HASH_FOREACH_END();
} else {
apc_warning("apc_exists() expects a string or array of strings.");
RETURN_FALSE;
}
}
PHP_FUNCTION(apcu_delete) {
zval *keys;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &keys) == FAILURE) {
return;
}
if (Z_TYPE_P(keys) == IS_STRING) {
RETURN_BOOL(apc_cache_delete(apc_user_cache, Z_STR_P(keys)));
} else if (Z_TYPE_P(keys) == IS_ARRAY) {
zval *hentry;
array_init(return_value);
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(keys), hentry) {
ZVAL_DEREF(hentry);
if (Z_TYPE_P(hentry) != IS_STRING) {
apc_warning("apc_delete() expects a string, array of strings, or APCIterator instance");
add_next_index_zval(return_value, hentry);
Z_TRY_ADDREF_P(hentry);
} else if (apc_cache_delete(apc_user_cache, Z_STR_P(hentry)) != 1) {
add_next_index_zval(return_value, hentry);
Z_TRY_ADDREF_P(hentry);
}
} ZEND_HASH_FOREACH_END();
} else if (Z_TYPE_P(keys) == IS_OBJECT) {
RETURN_BOOL(apc_iterator_delete(keys) != 0);
} else {
apc_warning("apc_delete() expects a string, array of strings, or APCIterator instance");
RETURN_FALSE;
}
}
PHP_FUNCTION(apcu_entry) {
zend_string *key;
zend_fcall_info fci = empty_fcall_info;
zend_fcall_info_cache fcc = empty_fcall_info_cache;
zend_long ttl = 0L;
zend_long now = apc_time();
if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sf|l", &key, &fci, &fcc, &ttl) != SUCCESS) {
return;
}
apc_cache_entry(apc_user_cache, key, &fci, &fcc, ttl, now, return_value);
}
#ifdef APC_DEBUG
PHP_FUNCTION(apcu_inc_request_time) {
zend_long by = 1;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &by) != SUCCESS) {
return;
}
if (!APCG(use_request_time)) {
php_error_docref(NULL, E_WARNING,
"Trying to increment request time while use_request_time is disabled");
return;
}
(void) apc_time();
APCG(request_time) += by;
}
#endif
zend_module_entry apcu_module_entry = {
STANDARD_MODULE_HEADER,
PHP_APCU_EXTNAME,
ext_functions,
PHP_MINIT(apcu),
PHP_MSHUTDOWN(apcu),
PHP_RINIT(apcu),
NULL,
PHP_MINFO(apcu),
PHP_APCU_VERSION,
STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_APCU
ZEND_GET_MODULE(apcu)
#ifdef ZTS
ZEND_TSRMLS_CACHE_DEFINE();
#endif
#endif
一鍵複制
編輯
Web IDE
原始資料
按行檢視
曆史