Backup of current cakephp version

This commit is contained in:
Brm Ko 2017-02-26 15:27:58 +01:00
parent b8f82da6f8
commit 5a580df460
925 changed files with 238041 additions and 1 deletions

501
lib/Cake/Cache/Cache.php Normal file
View file

@ -0,0 +1,501 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Cache
* @since CakePHP(tm) v 1.2.0.4933
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::uses('Inflector', 'Utility');
App::uses('CacheEngine', 'Cache');
/**
* Cache provides a consistent interface to Caching in your application. It allows you
* to use several different Cache engines, without coupling your application to a specific
* implementation. It also allows you to change out cache storage or configuration without effecting
* the rest of your application.
*
* You can configure Cache engines in your application's `bootstrap.php` file. A sample configuration would
* be
*
* {{{
* Cache::config('shared', array(
* 'engine' => 'Apc',
* 'prefix' => 'my_app_'
* ));
* }}}
*
* This would configure an APC cache engine to the 'shared' alias. You could then read and write
* to that cache alias by using it for the `$config` parameter in the various Cache methods. In
* general all Cache operations are supported by all cache engines. However, Cache::increment() and
* Cache::decrement() are not supported by File caching.
*
* @package Cake.Cache
*/
class Cache {
/**
* Cache configuration stack
* Keeps the permanent/default settings for each cache engine.
* These settings are used to reset the engines after temporary modification.
*
* @var array
*/
protected static $_config = array();
/**
* Whether to reset the settings with the next call to Cache::set();
*
* @var array
*/
protected static $_reset = false;
/**
* Engine instances keyed by configuration name.
*
* @var array
*/
protected static $_engines = array();
/**
* Set the cache configuration to use. config() can
* both create new configurations, return the settings for already configured
* configurations.
*
* To create a new configuration, or to modify an existing configuration permanently:
*
* `Cache::config('my_config', array('engine' => 'File', 'path' => TMP));`
*
* If you need to modify a configuration temporarily, use Cache::set().
* To get the settings for a configuration:
*
* `Cache::config('default');`
*
* There are 5 built-in caching engines:
*
* - `FileEngine` - Uses simple files to store content. Poor performance, but good for
* storing large objects, or things that are not IO sensitive.
* - `ApcEngine` - Uses the APC object cache, one of the fastest caching engines.
* - `MemcacheEngine` - Uses the PECL::Memcache extension and Memcached for storage.
* Fast reads/writes, and benefits from memcache being distributed.
* - `XcacheEngine` - Uses the Xcache extension, an alternative to APC.
* - `WincacheEngine` - Uses Windows Cache Extension for PHP. Supports wincache 1.1.0 and higher.
*
* The following keys are used in core cache engines:
*
* - `duration` Specify how long items in this cache configuration last.
* - `groups` List of groups or 'tags' associated to every key stored in this config.
* handy for deleting a complete group from cache.
* - `prefix` Prefix appended to all entries. Good for when you need to share a keyspace
* with either another cache config or another application.
* - `probability` Probability of hitting a cache gc cleanup. Setting to 0 will disable
* cache::gc from ever being called automatically.
* - `servers' Used by memcache. Give the address of the memcached servers to use.
* - `compress` Used by memcache. Enables memcache's compressed format.
* - `serialize` Used by FileCache. Should cache objects be serialized first.
* - `path` Used by FileCache. Path to where cachefiles should be saved.
* - `lock` Used by FileCache. Should files be locked before writing to them?
* - `user` Used by Xcache. Username for XCache
* - `password` Used by Xcache. Password for XCache
*
* @see app/Config/core.php for configuration settings
* @param string $name Name of the configuration
* @param array $settings Optional associative array of settings passed to the engine
* @return array(engine, settings) on success, false on failure
* @throws CacheException
*/
public static function config($name = null, $settings = array()) {
if (is_array($name)) {
$settings = $name;
}
$current = array();
if (isset(self::$_config[$name])) {
$current = self::$_config[$name];
}
if (!empty($settings)) {
self::$_config[$name] = array_merge($current, $settings);
}
if (empty(self::$_config[$name]['engine'])) {
return false;
}
$engine = self::$_config[$name]['engine'];
if (!isset(self::$_engines[$name])) {
self::_buildEngine($name);
$settings = self::$_config[$name] = self::settings($name);
} elseif ($settings = self::set(self::$_config[$name], null, $name)) {
self::$_config[$name] = $settings;
}
return compact('engine', 'settings');
}
/**
* Finds and builds the instance of the required engine class.
*
* @param string $name Name of the config array that needs an engine instance built
* @return boolean
* @throws CacheException
*/
protected static function _buildEngine($name) {
$config = self::$_config[$name];
list($plugin, $class) = pluginSplit($config['engine'], true);
$cacheClass = $class . 'Engine';
App::uses($cacheClass, $plugin . 'Cache/Engine');
if (!class_exists($cacheClass)) {
return false;
}
$cacheClass = $class . 'Engine';
if (!is_subclass_of($cacheClass, 'CacheEngine')) {
throw new CacheException(__d('cake_dev', 'Cache engines must use CacheEngine as a base class.'));
}
self::$_engines[$name] = new $cacheClass();
if (self::$_engines[$name]->init($config)) {
if (self::$_engines[$name]->settings['probability'] && time() % self::$_engines[$name]->settings['probability'] === 0) {
self::$_engines[$name]->gc();
}
return true;
}
return false;
}
/**
* Returns an array containing the currently configured Cache settings.
*
* @return array Array of configured Cache config names.
*/
public static function configured() {
return array_keys(self::$_config);
}
/**
* Drops a cache engine. Deletes the cache configuration information
* If the deleted configuration is the last configuration using an certain engine,
* the Engine instance is also unset.
*
* @param string $name A currently configured cache config you wish to remove.
* @return boolean success of the removal, returns false when the config does not exist.
*/
public static function drop($name) {
if (!isset(self::$_config[$name])) {
return false;
}
unset(self::$_config[$name], self::$_engines[$name]);
return true;
}
/**
* Temporarily change the settings on a cache config. The settings will persist for the next write
* operation (write, decrement, increment, clear). Any reads that are done before the write, will
* use the modified settings. If `$settings` is empty, the settings will be reset to the
* original configuration.
*
* Can be called with 2 or 3 parameters. To set multiple values at once.
*
* `Cache::set(array('duration' => '+30 minutes'), 'my_config');`
*
* Or to set one value.
*
* `Cache::set('duration', '+30 minutes', 'my_config');`
*
* To reset a config back to the originally configured values.
*
* `Cache::set(null, 'my_config');`
*
* @param string|array $settings Optional string for simple name-value pair or array
* @param string $value Optional for a simple name-value pair
* @param string $config The configuration name you are changing. Defaults to 'default'
* @return array Array of settings.
*/
public static function set($settings = array(), $value = null, $config = 'default') {
if (is_array($settings) && $value !== null) {
$config = $value;
}
if (!isset(self::$_config[$config]) || !isset(self::$_engines[$config])) {
return false;
}
if (!empty($settings)) {
self::$_reset = true;
}
if (self::$_reset === true) {
if (empty($settings)) {
self::$_reset = false;
$settings = self::$_config[$config];
} else {
if (is_string($settings) && $value !== null) {
$settings = array($settings => $value);
}
$settings = array_merge(self::$_config[$config], $settings);
if (isset($settings['duration']) && !is_numeric($settings['duration'])) {
$settings['duration'] = strtotime($settings['duration']) - time();
}
}
self::$_engines[$config]->settings = $settings;
}
return self::settings($config);
}
/**
* Garbage collection
*
* Permanently remove all expired and deleted data
*
* @param string $config [optional] The config name you wish to have garbage collected. Defaults to 'default'
* @param integer $expires [optional] An expires timestamp. Defaults to NULL
* @return void
*/
public static function gc($config = 'default', $expires = null) {
self::$_engines[$config]->gc($expires);
}
/**
* Write data for key into cache. Will automatically use the currently
* active cache configuration. To set the currently active configuration use
* Cache::config()
*
* ### Usage:
*
* Writing to the active cache config:
*
* `Cache::write('cached_data', $data);`
*
* Writing to a specific cache config:
*
* `Cache::write('cached_data', $data, 'long_term');`
*
* @param string $key Identifier for the data
* @param mixed $value Data to be cached - anything except a resource
* @param string $config Optional string configuration name to write to. Defaults to 'default'
* @return boolean True if the data was successfully cached, false on failure
*/
public static function write($key, $value, $config = 'default') {
$settings = self::settings($config);
if (empty($settings)) {
return false;
}
if (!self::isInitialized($config)) {
return false;
}
$key = self::$_engines[$config]->key($key);
if (!$key || is_resource($value)) {
return false;
}
$success = self::$_engines[$config]->write($settings['prefix'] . $key, $value, $settings['duration']);
self::set(null, $config);
if ($success === false && $value !== '') {
trigger_error(
__d('cake_dev',
"%s cache was unable to write '%s' to %s cache",
$config,
$key,
self::$_engines[$config]->settings['engine']
),
E_USER_WARNING
);
}
return $success;
}
/**
* Read a key from the cache. Will automatically use the currently
* active cache configuration. To set the currently active configuration use
* Cache::config()
*
* ### Usage:
*
* Reading from the active cache configuration.
*
* `Cache::read('my_data');`
*
* Reading from a specific cache configuration.
*
* `Cache::read('my_data', 'long_term');`
*
* @param string $key Identifier for the data
* @param string $config optional name of the configuration to use. Defaults to 'default'
* @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it
*/
public static function read($key, $config = 'default') {
$settings = self::settings($config);
if (empty($settings)) {
return false;
}
if (!self::isInitialized($config)) {
return false;
}
$key = self::$_engines[$config]->key($key);
if (!$key) {
return false;
}
return self::$_engines[$config]->read($settings['prefix'] . $key);
}
/**
* Increment a number under the key and return incremented value.
*
* @param string $key Identifier for the data
* @param integer $offset How much to add
* @param string $config Optional string configuration name. Defaults to 'default'
* @return mixed new value, or false if the data doesn't exist, is not integer,
* or if there was an error fetching it.
*/
public static function increment($key, $offset = 1, $config = 'default') {
$settings = self::settings($config);
if (empty($settings)) {
return false;
}
if (!self::isInitialized($config)) {
return false;
}
$key = self::$_engines[$config]->key($key);
if (!$key || !is_integer($offset) || $offset < 0) {
return false;
}
$success = self::$_engines[$config]->increment($settings['prefix'] . $key, $offset);
self::set(null, $config);
return $success;
}
/**
* Decrement a number under the key and return decremented value.
*
* @param string $key Identifier for the data
* @param integer $offset How much to subtract
* @param string $config Optional string configuration name. Defaults to 'default'
* @return mixed new value, or false if the data doesn't exist, is not integer,
* or if there was an error fetching it
*/
public static function decrement($key, $offset = 1, $config = 'default') {
$settings = self::settings($config);
if (empty($settings)) {
return false;
}
if (!self::isInitialized($config)) {
return false;
}
$key = self::$_engines[$config]->key($key);
if (!$key || !is_integer($offset) || $offset < 0) {
return false;
}
$success = self::$_engines[$config]->decrement($settings['prefix'] . $key, $offset);
self::set(null, $config);
return $success;
}
/**
* Delete a key from the cache.
*
* ### Usage:
*
* Deleting from the active cache configuration.
*
* `Cache::delete('my_data');`
*
* Deleting from a specific cache configuration.
*
* `Cache::delete('my_data', 'long_term');`
*
* @param string $key Identifier for the data
* @param string $config name of the configuration to use. Defaults to 'default'
* @return boolean True if the value was successfully deleted, false if it didn't exist or couldn't be removed
*/
public static function delete($key, $config = 'default') {
$settings = self::settings($config);
if (empty($settings)) {
return false;
}
if (!self::isInitialized($config)) {
return false;
}
$key = self::$_engines[$config]->key($key);
if (!$key) {
return false;
}
$success = self::$_engines[$config]->delete($settings['prefix'] . $key);
self::set(null, $config);
return $success;
}
/**
* Delete all keys from the cache.
*
* @param boolean $check if true will check expiration, otherwise delete all
* @param string $config name of the configuration to use. Defaults to 'default'
* @return boolean True if the cache was successfully cleared, false otherwise
*/
public static function clear($check = false, $config = 'default') {
if (!self::isInitialized($config)) {
return false;
}
$success = self::$_engines[$config]->clear($check);
self::set(null, $config);
return $success;
}
/**
* Delete all keys from the cache belonging to the same group.
*
* @param string $group name of the group to be cleared
* @param string $config name of the configuration to use. Defaults to 'default'
* @return boolean True if the cache group was successfully cleared, false otherwise
*/
public static function clearGroup($group, $config = 'default') {
if (!self::isInitialized($config)) {
return false;
}
$success = self::$_engines[$config]->clearGroup($group);
self::set(null, $config);
return $success;
}
/**
* Check if Cache has initialized a working config for the given name.
*
* @param string $config name of the configuration to use. Defaults to 'default'
* @return boolean Whether or not the config name has been initialized.
*/
public static function isInitialized($config = 'default') {
if (Configure::read('Cache.disable')) {
return false;
}
return isset(self::$_engines[$config]);
}
/**
* Return the settings for the named cache engine.
*
* @param string $name Name of the configuration to get settings for. Defaults to 'default'
* @return array list of settings for this engine
* @see Cache::config()
*/
public static function settings($name = 'default') {
if (!empty(self::$_engines[$name])) {
return self::$_engines[$name]->settings();
}
return array();
}
}

View file

@ -0,0 +1,179 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Cache
* @since CakePHP(tm) v 1.2.0.4933
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
/**
* Storage engine for CakePHP caching
*
* @package Cake.Cache
*/
abstract class CacheEngine {
/**
* Settings of current engine instance
*
* @var array
*/
public $settings = array();
/**
* Contains the compiled string with all groups
* prefixes to be prepeded to every key in this cache engine
*
* @var string
**/
protected $_groupPrefix = null;
/**
* Initialize the cache engine
*
* Called automatically by the cache frontend
*
* @param array $settings Associative array of parameters for the engine
* @return boolean True if the engine has been successfully initialized, false if not
*/
public function init($settings = array()) {
$settings += $this->settings + array(
'prefix' => 'cake_',
'duration' => 3600,
'probability' => 100,
'groups' => array()
);
$this->settings = $settings;
if (!empty($this->settings['groups'])) {
sort($this->settings['groups']);
$this->_groupPrefix = str_repeat('%s_', count($this->settings['groups']));
}
if (!is_numeric($this->settings['duration'])) {
$this->settings['duration'] = strtotime($this->settings['duration']) - time();
}
return true;
}
/**
* Garbage collection
*
* Permanently remove all expired and deleted data
*
* @param integer $expires [optional] An expires timestamp, invalidataing all data before.
* @return void
*/
public function gc($expires = null) {
}
/**
* Write value for a key into cache
*
* @param string $key Identifier for the data
* @param mixed $value Data to be cached
* @param integer $duration How long to cache for.
* @return boolean True if the data was successfully cached, false on failure
*/
abstract public function write($key, $value, $duration);
/**
* Read a key from the cache
*
* @param string $key Identifier for the data
* @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it
*/
abstract public function read($key);
/**
* Increment a number under the key and return incremented value
*
* @param string $key Identifier for the data
* @param integer $offset How much to add
* @return New incremented value, false otherwise
*/
abstract public function increment($key, $offset = 1);
/**
* Decrement a number under the key and return decremented value
*
* @param string $key Identifier for the data
* @param integer $offset How much to subtract
* @return New incremented value, false otherwise
*/
abstract public function decrement($key, $offset = 1);
/**
* Delete a key from the cache
*
* @param string $key Identifier for the data
* @return boolean True if the value was successfully deleted, false if it didn't exist or couldn't be removed
*/
abstract public function delete($key);
/**
* Delete all keys from the cache
*
* @param boolean $check if true will check expiration, otherwise delete all
* @return boolean True if the cache was successfully cleared, false otherwise
*/
abstract public function clear($check);
/**
* Clears all values belonging to a group. Is upt to the implementing engine
* to decide whether actually deete the keys or just simulate it to acheive
* the same result.
*
* @param string $groups name of the group to be cleared
* @return boolean
*/
public function clearGroup($group) {
return false;
}
/**
* Does whatever initialization for each group is required
* and returns the `group value` for each of them, this is
* the token representing each group in the cache key
*
* @return array
*/
public function groups() {
return $this->settings['groups'];
}
/**
* Cache Engine settings
*
* @return array settings
*/
public function settings() {
return $this->settings;
}
/**
* Generates a safe key for use with cache engine storage engines.
*
* @param string $key the key passed over
* @return mixed string $key or false
*/
public function key($key) {
if (empty($key)) {
return false;
}
$prefix = '';
if (!empty($this->_groupPrefix)) {
$prefix = vsprintf($this->_groupPrefix, $this->groups());
}
$key = preg_replace('/[\s]+/', '_', strtolower(trim(str_replace(array(DS, '/', '.'), '_', strval($key)))));
return $prefix . $key;
}
}

View file

@ -0,0 +1,186 @@
<?php
/**
* APC storage engine for cache.
*
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Cache.Engine
* @since CakePHP(tm) v 1.2.0.4933
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
/**
* APC storage engine for cache
*
* @package Cake.Cache.Engine
*/
class ApcEngine extends CacheEngine {
/**
* Contains the compiled group names
* (prefixed witht the global configuration prefix)
*
* @var array
**/
protected $_compiledGroupNames = array();
/**
* Initialize the Cache Engine
*
* Called automatically by the cache frontend
* To reinitialize the settings call Cache::engine('EngineName', [optional] settings = array());
*
* @param array $settings array of setting for the engine
* @return boolean True if the engine has been successfully initialized, false if not
* @see CacheEngine::__defaults
*/
public function init($settings = array()) {
if (!isset($settings['prefix'])) {
$settings['prefix'] = Inflector::slug(APP_DIR) . '_';
}
$settings += array('engine' => 'Apc');
parent::init($settings);
return function_exists('apc_dec');
}
/**
* Write data for key into cache
*
* @param string $key Identifier for the data
* @param mixed $value Data to be cached
* @param integer $duration How long to cache the data, in seconds
* @return boolean True if the data was successfully cached, false on failure
*/
public function write($key, $value, $duration) {
if ($duration == 0) {
$expires = 0;
} else {
$expires = time() + $duration;
}
apc_store($key . '_expires', $expires, $duration);
return apc_store($key, $value, $duration);
}
/**
* Read a key from the cache
*
* @param string $key Identifier for the data
* @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it
*/
public function read($key) {
$time = time();
$cachetime = intval(apc_fetch($key . '_expires'));
if ($cachetime !== 0 && ($cachetime < $time || ($time + $this->settings['duration']) < $cachetime)) {
return false;
}
return apc_fetch($key);
}
/**
* Increments the value of an integer cached key
*
* @param string $key Identifier for the data
* @param integer $offset How much to increment
* @return New incremented value, false otherwise
*/
public function increment($key, $offset = 1) {
return apc_inc($key, $offset);
}
/**
* Decrements the value of an integer cached key
*
* @param string $key Identifier for the data
* @param integer $offset How much to subtract
* @return New decremented value, false otherwise
*/
public function decrement($key, $offset = 1) {
return apc_dec($key, $offset);
}
/**
* Delete a key from the cache
*
* @param string $key Identifier for the data
* @return boolean True if the value was successfully deleted, false if it didn't exist or couldn't be removed
*/
public function delete($key) {
return apc_delete($key);
}
/**
* Delete all keys from the cache. This will clear every cache config using APC.
*
* @param boolean $check If true, nothing will be cleared, as entries are removed
* from APC as they expired. This flag is really only used by FileEngine.
* @return boolean True Returns true.
*/
public function clear($check) {
if ($check) {
return true;
}
$info = apc_cache_info('user');
$cacheKeys = $info['cache_list'];
unset($info);
foreach ($cacheKeys as $key) {
if (strpos($key['info'], $this->settings['prefix']) === 0) {
apc_delete($key['info']);
}
}
return true;
}
/**
* Returns the `group value` for each of the configured groups
* If the group initial value was not found, then it initializes
* the group accordingly.
*
* @return array
**/
public function groups() {
if (empty($this->_compiledGroupNames)) {
foreach ($this->settings['groups'] as $group) {
$this->_compiledGroupNames[] = $this->settings['prefix'] . $group;
}
}
$groups = apc_fetch($this->_compiledGroupNames);
if (count($groups) !== count($this->settings['groups'])) {
foreach ($this->_compiledGroupNames as $group) {
if (!isset($groups[$group])) {
apc_store($group, 1);
$groups[$group] = 1;
}
}
ksort($groups);
}
$result = array();
$groups = array_values($groups);
foreach ($this->settings['groups'] as $i => $group) {
$result[] = $group . $groups[$i];
}
return $result;
}
/**
* Increments the group value to simulate deletion of all keys under a group
* old values will remain in storage until they expire.
*
* @return boolean success
**/
public function clearGroup($group) {
apc_inc($this->settings['prefix'] . $group, 1, $success);
return $success;
}
}

View file

@ -0,0 +1,373 @@
<?php
/**
* File Storage engine for cache. Filestorage is the slowest cache storage
* to read and write. However, it is good for servers that don't have other storage
* engine available, or have content which is not performance sensitive.
*
* You can configure a FileEngine cache, using Cache::config()
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since CakePHP(tm) v 1.2.0.4933
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
/**
* File Storage engine for cache. Filestorage is the slowest cache storage
* to read and write. However, it is good for servers that don't have other storage
* engine available, or have content which is not performance sensitive.
*
* You can configure a FileEngine cache, using Cache::config()
*
* @package Cake.Cache.Engine
*/
class FileEngine extends CacheEngine {
/**
* Instance of SplFileObject class
*
* @var File
*/
protected $_File = null;
/**
* Settings
*
* - path = absolute path to cache directory, default => CACHE
* - prefix = string prefix for filename, default => cake_
* - lock = enable file locking on write, default => false
* - serialize = serialize the data, default => true
*
* @var array
* @see CacheEngine::__defaults
*/
public $settings = array();
/**
* True unless FileEngine::__active(); fails
*
* @var boolean
*/
protected $_init = true;
/**
* Initialize the Cache Engine
*
* Called automatically by the cache frontend
* To reinitialize the settings call Cache::engine('EngineName', [optional] settings = array());
*
* @param array $settings array of setting for the engine
* @return boolean True if the engine has been successfully initialized, false if not
*/
public function init($settings = array()) {
$settings += array(
'engine' => 'File',
'path' => CACHE,
'prefix' => 'cake_',
'lock' => true,
'serialize' => true,
'isWindows' => false,
'mask' => 0664
);
parent::init($settings);
if (DS === '\\') {
$this->settings['isWindows'] = true;
}
if (substr($this->settings['path'], -1) !== DS) {
$this->settings['path'] .= DS;
}
if (!empty($this->_groupPrefix)) {
$this->_groupPrefix = str_replace('_', DS, $this->_groupPrefix);
}
return $this->_active();
}
/**
* Garbage collection. Permanently remove all expired and deleted data
*
* @param integer $expires [optional] An expires timestamp, invalidataing all data before.
* @return boolean True if garbage collection was successful, false on failure
*/
public function gc($expires = null) {
return $this->clear(true);
}
/**
* Write data for key into cache
*
* @param string $key Identifier for the data
* @param mixed $data Data to be cached
* @param integer $duration How long to cache the data, in seconds
* @return boolean True if the data was successfully cached, false on failure
*/
public function write($key, $data, $duration) {
if ($data === '' || !$this->_init) {
return false;
}
if ($this->_setKey($key, true) === false) {
return false;
}
$lineBreak = "\n";
if ($this->settings['isWindows']) {
$lineBreak = "\r\n";
}
if (!empty($this->settings['serialize'])) {
if ($this->settings['isWindows']) {
$data = str_replace('\\', '\\\\\\\\', serialize($data));
} else {
$data = serialize($data);
}
}
$expires = time() + $duration;
$contents = $expires . $lineBreak . $data . $lineBreak;
if ($this->settings['lock']) {
$this->_File->flock(LOCK_EX);
}
$this->_File->rewind();
$success = $this->_File->ftruncate(0) && $this->_File->fwrite($contents) && $this->_File->fflush();
if ($this->settings['lock']) {
$this->_File->flock(LOCK_UN);
}
return $success;
}
/**
* Read a key from the cache
*
* @param string $key Identifier for the data
* @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it
*/
public function read($key) {
if (!$this->_init || $this->_setKey($key) === false) {
return false;
}
if ($this->settings['lock']) {
$this->_File->flock(LOCK_SH);
}
$this->_File->rewind();
$time = time();
$cachetime = intval($this->_File->current());
if ($cachetime !== false && ($cachetime < $time || ($time + $this->settings['duration']) < $cachetime)) {
if ($this->settings['lock']) {
$this->_File->flock(LOCK_UN);
}
return false;
}
$data = '';
$this->_File->next();
while ($this->_File->valid()) {
$data .= $this->_File->current();
$this->_File->next();
}
if ($this->settings['lock']) {
$this->_File->flock(LOCK_UN);
}
$data = trim($data);
if ($data !== '' && !empty($this->settings['serialize'])) {
if ($this->settings['isWindows']) {
$data = str_replace('\\\\\\\\', '\\', $data);
}
$data = unserialize((string)$data);
}
return $data;
}
/**
* Delete a key from the cache
*
* @param string $key Identifier for the data
* @return boolean True if the value was successfully deleted, false if it didn't exist or couldn't be removed
*/
public function delete($key) {
if ($this->_setKey($key) === false || !$this->_init) {
return false;
}
$path = $this->_File->getRealPath();
$this->_File = null;
return unlink($path);
}
/**
* Delete all values from the cache
*
* @param boolean $check Optional - only delete expired cache items
* @return boolean True if the cache was successfully cleared, false otherwise
*/
public function clear($check) {
if (!$this->_init) {
return false;
}
$dir = dir($this->settings['path']);
if ($check) {
$now = time();
$threshold = $now - $this->settings['duration'];
}
$prefixLength = strlen($this->settings['prefix']);
while (($entry = $dir->read()) !== false) {
if (substr($entry, 0, $prefixLength) !== $this->settings['prefix']) {
continue;
}
if ($this->_setKey($entry) === false) {
continue;
}
if ($check) {
$mtime = $this->_File->getMTime();
if ($mtime > $threshold) {
continue;
}
$expires = (int)$this->_File->current();
if ($expires > $now) {
continue;
}
}
$path = $this->_File->getRealPath();
$this->_File = null;
if (file_exists($path)) {
unlink($path);
}
}
$dir->close();
return true;
}
/**
* Not implemented
*
* @param string $key
* @param integer $offset
* @return void
* @throws CacheException
*/
public function decrement($key, $offset = 1) {
throw new CacheException(__d('cake_dev', 'Files cannot be atomically decremented.'));
}
/**
* Not implemented
*
* @param string $key
* @param integer $offset
* @return void
* @throws CacheException
*/
public function increment($key, $offset = 1) {
throw new CacheException(__d('cake_dev', 'Files cannot be atomically incremented.'));
}
/**
* Sets the current cache key this class is managing, and creates a writable SplFileObject
* for the cache file the key is referring to.
*
* @param string $key The key
* @param boolean $createKey Whether the key should be created if it doesn't exists, or not
* @return boolean true if the cache key could be set, false otherwise
*/
protected function _setKey($key, $createKey = false) {
$groups = null;
if (!empty($this->_groupPrefix)) {
$groups = vsprintf($this->_groupPrefix, $this->groups());
}
$dir = $this->settings['path'] . $groups;
if (!is_dir($dir)) {
mkdir($dir, 0777, true);
}
$path = new SplFileInfo($dir . $key);
if (!$createKey && !$path->isFile()) {
return false;
}
if (empty($this->_File) || $this->_File->getBaseName() !== $key) {
$exists = file_exists($path->getPathname());
try {
$this->_File = $path->openFile('c+');
} catch (Exception $e) {
trigger_error($e->getMessage(), E_USER_WARNING);
return false;
}
unset($path);
if (!$exists && !chmod($this->_File->getPathname(), (int)$this->settings['mask'])) {
trigger_error(__d(
'cake_dev', 'Could not apply permission mask "%s" on cache file "%s"',
array($this->_File->getPathname(), $this->settings['mask'])), E_USER_WARNING);
}
}
return true;
}
/**
* Determine is cache directory is writable
*
* @return boolean
*/
protected function _active() {
$dir = new SplFileInfo($this->settings['path']);
if ($this->_init && !($dir->isDir() && $dir->isWritable())) {
$this->_init = false;
trigger_error(__d('cake_dev', '%s is not writable', $this->settings['path']), E_USER_WARNING);
return false;
}
return true;
}
/**
* Generates a safe key for use with cache engine storage engines.
*
* @param string $key the key passed over
* @return mixed string $key or false
*/
public function key($key) {
if (empty($key)) {
return false;
}
$key = Inflector::underscore(str_replace(array(DS, '/', '.'), '_', strval($key)));
return $key;
}
/**
* Recursively deletes all files under any directory named as $group
*
* @return boolean success
**/
public function clearGroup($group) {
$directoryIterator = new RecursiveDirectoryIterator($this->settings['path']);
$contents = new RecursiveIteratorIterator($directoryIterator, RecursiveIteratorIterator::CHILD_FIRST);
foreach ($contents as $object) {
$containsGroup = strpos($object->getPathName(), DS . $group . DS) !== false;
if ($object->isFile() && $containsGroup) {
unlink($object->getPathName());
}
}
return true;
}
}

View file

@ -0,0 +1,291 @@
<?php
/**
* Memcache storage engine for cache
*
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Cache.Engine
* @since CakePHP(tm) v 1.2.0.4933
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
/**
* Memcache storage engine for cache. Memcache has some limitations in the amount of
* control you have over expire times far in the future. See MemcacheEngine::write() for
* more information.
*
* @package Cake.Cache.Engine
*/
class MemcacheEngine extends CacheEngine {
/**
* Contains the compiled group names
* (prefixed witht the global configuration prefix)
*
* @var array
**/
protected $_compiledGroupNames = array();
/**
* Memcache wrapper.
*
* @var Memcache
*/
protected $_Memcache = null;
/**
* Settings
*
* - servers = string or array of memcache servers, default => 127.0.0.1. If an
* array MemcacheEngine will use them as a pool.
* - compress = boolean, default => false
*
* @var array
*/
public $settings = array();
/**
* Initialize the Cache Engine
*
* Called automatically by the cache frontend
* To reinitialize the settings call Cache::engine('EngineName', [optional] settings = array());
*
* @param array $settings array of setting for the engine
* @return boolean True if the engine has been successfully initialized, false if not
*/
public function init($settings = array()) {
if (!class_exists('Memcache')) {
return false;
}
if (!isset($settings['prefix'])) {
$settings['prefix'] = Inflector::slug(APP_DIR) . '_';
}
$settings += array(
'engine' => 'Memcache',
'servers' => array('127.0.0.1'),
'compress' => false,
'persistent' => true
);
parent::init($settings);
if ($this->settings['compress']) {
$this->settings['compress'] = MEMCACHE_COMPRESSED;
}
if (is_string($this->settings['servers'])) {
$this->settings['servers'] = array($this->settings['servers']);
}
if (!isset($this->_Memcache)) {
$return = false;
$this->_Memcache = new Memcache();
foreach ($this->settings['servers'] as $server) {
list($host, $port) = $this->_parseServerString($server);
if ($this->_Memcache->addServer($host, $port, $this->settings['persistent'])) {
$return = true;
}
}
return $return;
}
return true;
}
/**
* Parses the server address into the host/port. Handles both IPv6 and IPv4
* addresses and Unix sockets
*
* @param string $server The server address string.
* @return array Array containing host, port
*/
protected function _parseServerString($server) {
if ($server[0] == 'u') {
return array($server, 0);
}
if (substr($server, 0, 1) == '[') {
$position = strpos($server, ']:');
if ($position !== false) {
$position++;
}
} else {
$position = strpos($server, ':');
}
$port = 11211;
$host = $server;
if ($position !== false) {
$host = substr($server, 0, $position);
$port = substr($server, $position + 1);
}
return array($host, $port);
}
/**
* Write data for key into cache. When using memcache as your cache engine
* remember that the Memcache pecl extension does not support cache expiry times greater
* than 30 days in the future. Any duration greater than 30 days will be treated as never expiring.
*
* @param string $key Identifier for the data
* @param mixed $value Data to be cached
* @param integer $duration How long to cache the data, in seconds
* @return boolean True if the data was successfully cached, false on failure
* @see http://php.net/manual/en/memcache.set.php
*/
public function write($key, $value, $duration) {
if ($duration > 30 * DAY) {
$duration = 0;
}
return $this->_Memcache->set($key, $value, $this->settings['compress'], $duration);
}
/**
* Read a key from the cache
*
* @param string $key Identifier for the data
* @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it
*/
public function read($key) {
return $this->_Memcache->get($key);
}
/**
* Increments the value of an integer cached key
*
* @param string $key Identifier for the data
* @param integer $offset How much to increment
* @return New incremented value, false otherwise
* @throws CacheException when you try to increment with compress = true
*/
public function increment($key, $offset = 1) {
if ($this->settings['compress']) {
throw new CacheException(
__d('cake_dev', 'Method increment() not implemented for compressed cache in %s', __CLASS__)
);
}
return $this->_Memcache->increment($key, $offset);
}
/**
* Decrements the value of an integer cached key
*
* @param string $key Identifier for the data
* @param integer $offset How much to subtract
* @return New decremented value, false otherwise
* @throws CacheException when you try to decrement with compress = true
*/
public function decrement($key, $offset = 1) {
if ($this->settings['compress']) {
throw new CacheException(
__d('cake_dev', 'Method decrement() not implemented for compressed cache in %s', __CLASS__)
);
}
return $this->_Memcache->decrement($key, $offset);
}
/**
* Delete a key from the cache
*
* @param string $key Identifier for the data
* @return boolean True if the value was successfully deleted, false if it didn't exist or couldn't be removed
*/
public function delete($key) {
return $this->_Memcache->delete($key);
}
/**
* Delete all keys from the cache
*
* @param boolean $check
* @return boolean True if the cache was successfully cleared, false otherwise
*/
public function clear($check) {
if ($check) {
return true;
}
foreach ($this->_Memcache->getExtendedStats('slabs') as $slabs) {
foreach (array_keys($slabs) as $slabId) {
if (!is_numeric($slabId)) {
continue;
}
foreach ($this->_Memcache->getExtendedStats('cachedump', $slabId) as $stats) {
if (!is_array($stats)) {
continue;
}
foreach (array_keys($stats) as $key) {
if (strpos($key, $this->settings['prefix']) === 0) {
$this->_Memcache->delete($key);
}
}
}
}
}
return true;
}
/**
* Connects to a server in connection pool
*
* @param string $host host ip address or name
* @param integer $port Server port
* @return boolean True if memcache server was connected
*/
public function connect($host, $port = 11211) {
if ($this->_Memcache->getServerStatus($host, $port) === 0) {
if ($this->_Memcache->connect($host, $port)) {
return true;
}
return false;
}
return true;
}
/**
* Returns the `group value` for each of the configured groups
* If the group initial value was not found, then it initializes
* the group accordingly.
*
* @return array
**/
public function groups() {
if (empty($this->_compiledGroupNames)) {
foreach ($this->settings['groups'] as $group) {
$this->_compiledGroupNames[] = $this->settings['prefix'] . $group;
}
}
$groups = $this->_Memcache->get($this->_compiledGroupNames);
if (count($groups) !== count($this->settings['groups'])) {
foreach ($this->_compiledGroupNames as $group) {
if (!isset($groups[$group])) {
$this->_Memcache->set($group, 1, false, 0);
$groups[$group] = 1;
}
}
ksort($groups);
}
$result = array();
$groups = array_values($groups);
foreach ($this->settings['groups'] as $i => $group) {
$result[] = $group . $groups[$i];
}
return $result;
}
/**
* Increments the group value to simulate deletion of all keys under a group
* old values will remain in storage until they expire.
*
* @return boolean success
**/
public function clearGroup($group) {
return (bool)$this->_Memcache->increment($this->settings['prefix'] . $group);
}
}

View file

@ -0,0 +1,219 @@
<?php
/**
* Redis storage engine for cache
*
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Cache.Engine
* @since CakePHP(tm) v 2.2
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
/**
* Redis storage engine for cache.
*
* @package Cake.Cache.Engine
*/
class RedisEngine extends CacheEngine {
/**
* Redis wrapper.
*
* @var Redis
*/
protected $_Redis = null;
/**
* Settings
*
* - server = string url or ip to the Redis server host
* - port = integer port number to the Redis server (default: 6379)
* - timeout = float timeout in seconds (default: 0)
* - persistent = bool Connects to the Redis server with a persistent connection (default: true)
*
* @var array
*/
public $settings = array();
/**
* Initialize the Cache Engine
*
* Called automatically by the cache frontend
* To reinitialize the settings call Cache::engine('EngineName', [optional] settings = array());
*
* @param array $settings array of setting for the engine
* @return boolean True if the engine has been successfully initialized, false if not
*/
public function init($settings = array()) {
if (!class_exists('Redis')) {
return false;
}
parent::init(array_merge(array(
'engine' => 'Redis',
'prefix' => null,
'server' => '127.0.0.1',
'port' => 6379,
'timeout' => 0,
'persistent' => true
), $settings)
);
return $this->_connect();
}
/**
* Connects to a Redis server
*
* @return boolean True if Redis server was connected
*/
protected function _connect() {
$return = false;
try {
$this->_Redis = new Redis();
if (empty($this->settings['persistent'])) {
$return = $this->_Redis->connect($this->settings['server'], $this->settings['port'], $this->settings['timeout']);
} else {
$return = $this->_Redis->pconnect($this->settings['server'], $this->settings['port'], $this->settings['timeout']);
}
} catch (RedisException $e) {
return false;
}
return $return;
}
/**
* Write data for key into cache.
*
* @param string $key Identifier for the data
* @param mixed $value Data to be cached
* @param integer $duration How long to cache the data, in seconds
* @return boolean True if the data was successfully cached, false on failure
*/
public function write($key, $value, $duration) {
if (!is_int($value)) {
$value = serialize($value);
}
if ($duration === 0) {
return $this->_Redis->set($key, $value);
}
return $this->_Redis->setex($key, $duration, $value);
}
/**
* Read a key from the cache
*
* @param string $key Identifier for the data
* @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it
*/
public function read($key) {
$value = $this->_Redis->get($key);
if (ctype_digit($value)) {
$value = (int)$value;
}
if ($value !== false && is_string($value)) {
$value = unserialize($value);
}
return $value;
}
/**
* Increments the value of an integer cached key
*
* @param string $key Identifier for the data
* @param integer $offset How much to increment
* @return New incremented value, false otherwise
* @throws CacheException when you try to increment with compress = true
*/
public function increment($key, $offset = 1) {
return (int)$this->_Redis->incrBy($key, $offset);
}
/**
* Decrements the value of an integer cached key
*
* @param string $key Identifier for the data
* @param integer $offset How much to subtract
* @return New decremented value, false otherwise
* @throws CacheException when you try to decrement with compress = true
*/
public function decrement($key, $offset = 1) {
return (int)$this->_Redis->decrBy($key, $offset);
}
/**
* Delete a key from the cache
*
* @param string $key Identifier for the data
* @return boolean True if the value was successfully deleted, false if it didn't exist or couldn't be removed
*/
public function delete($key) {
return $this->_Redis->delete($key) > 0;
}
/**
* Delete all keys from the cache
*
* @param boolean $check
* @return boolean True if the cache was successfully cleared, false otherwise
*/
public function clear($check) {
if ($check) {
return true;
}
$keys = $this->_Redis->getKeys($this->settings['prefix'] . '*');
$this->_Redis->del($keys);
return true;
}
/**
* Returns the `group value` for each of the configured groups
* If the group initial value was not found, then it initializes
* the group accordingly.
*
* @return array
**/
public function groups() {
$result = array();
foreach ($this->settings['groups'] as $group) {
$value = $this->_Redis->get($this->settings['prefix'] . $group);
if (!$value) {
$value = 1;
$this->_Redis->set($this->settings['prefix'] . $group, $value);
}
$result[] = $group . $value;
}
return $result;
}
/**
* Increments the group value to simulate deletion of all keys under a group
* old values will remain in storage until they expire.
*
* @return boolean success
**/
public function clearGroup($group) {
return (bool)$this->_Redis->incr($this->settings['prefix'] . $group);
}
/**
* Disconnects from the redis server
*
* @return voind
**/
public function __destruct() {
if (!$this->settings['persistent']) {
$this->_Redis->close();
}
}
}

View file

@ -0,0 +1,191 @@
<?php
/**
* Wincache storage engine for cache.
*
* Supports wincache 1.1.0 and higher.
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Cache.Engine
* @since CakePHP(tm) v 1.2.0.4933
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
/**
* Wincache storage engine for cache
*
* @package Cake.Cache.Engine
*/
class WincacheEngine extends CacheEngine {
/**
* Contains the compiled group names
* (prefixed witht the global configuration prefix)
*
* @var array
**/
protected $_compiledGroupNames = array();
/**
* Initialize the Cache Engine
*
* Called automatically by the cache frontend
* To reinitialize the settings call Cache::engine('EngineName', [optional] settings = array());
*
* @param array $settings array of setting for the engine
* @return boolean True if the engine has been successfully initialized, false if not
* @see CacheEngine::__defaults
*/
public function init($settings = array()) {
if (!isset($settings['prefix'])) {
$settings['prefix'] = Inflector::slug(APP_DIR) . '_';
}
$settings += array('engine' => 'Wincache');
parent::init($settings);
return function_exists('wincache_ucache_info');
}
/**
* Write data for key into cache
*
* @param string $key Identifier for the data
* @param mixed $value Data to be cached
* @param integer $duration How long to cache the data, in seconds
* @return boolean True if the data was successfully cached, false on failure
*/
public function write($key, $value, $duration) {
$expires = time() + $duration;
$data = array(
$key . '_expires' => $expires,
$key => $value
);
$result = wincache_ucache_set($data, null, $duration);
return empty($result);
}
/**
* Read a key from the cache
*
* @param string $key Identifier for the data
* @return mixed The cached data, or false if the data doesn't exist, has expired, or if
* there was an error fetching it
*/
public function read($key) {
$time = time();
$cachetime = intval(wincache_ucache_get($key . '_expires'));
if ($cachetime < $time || ($time + $this->settings['duration']) < $cachetime) {
return false;
}
return wincache_ucache_get($key);
}
/**
* Increments the value of an integer cached key
*
* @param string $key Identifier for the data
* @param integer $offset How much to increment
* @return New incremented value, false otherwise
*/
public function increment($key, $offset = 1) {
return wincache_ucache_inc($key, $offset);
}
/**
* Decrements the value of an integer cached key
*
* @param string $key Identifier for the data
* @param integer $offset How much to subtract
* @return New decremented value, false otherwise
*/
public function decrement($key, $offset = 1) {
return wincache_ucache_dec($key, $offset);
}
/**
* Delete a key from the cache
*
* @param string $key Identifier for the data
* @return boolean True if the value was successfully deleted, false if it didn't exist or couldn't be removed
*/
public function delete($key) {
return wincache_ucache_delete($key);
}
/**
* Delete all keys from the cache. This will clear every
* item in the cache matching the cache config prefix.
*
* @param boolean $check If true, nothing will be cleared, as entries will
* naturally expire in wincache..
* @return boolean True Returns true.
*/
public function clear($check) {
if ($check) {
return true;
}
$info = wincache_ucache_info();
$cacheKeys = $info['ucache_entries'];
unset($info);
foreach ($cacheKeys as $key) {
if (strpos($key['key_name'], $this->settings['prefix']) === 0) {
wincache_ucache_delete($key['key_name']);
}
}
return true;
}
/**
* Returns the `group value` for each of the configured groups
* If the group initial value was not found, then it initializes
* the group accordingly.
*
* @return array
**/
public function groups() {
if (empty($this->_compiledGroupNames)) {
foreach ($this->settings['groups'] as $group) {
$this->_compiledGroupNames[] = $this->settings['prefix'] . $group;
}
}
$groups = wincache_ucache_get($this->_compiledGroupNames);
if (count($groups) !== count($this->settings['groups'])) {
foreach ($this->_compiledGroupNames as $group) {
if (!isset($groups[$group])) {
wincache_ucache_set($group, 1);
$groups[$group] = 1;
}
}
ksort($groups);
}
$result = array();
$groups = array_values($groups);
foreach ($this->settings['groups'] as $i => $group) {
$result[] = $group . $groups[$i];
}
return $result;
}
/**
* Increments the group value to simulate deletion of all keys under a group
* old values will remain in storage until they expire.
*
* @return boolean success
**/
public function clearGroup($group) {
$success = null;
wincache_ucache_inc($this->settings['prefix'] . $group, 1, $success);
return $success;
}
}

View file

@ -0,0 +1,209 @@
<?php
/**
* Xcache storage engine for cache.
*
* PHP 5
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @package Cake.Cache.Engine
* @since CakePHP(tm) v 1.2.0.4947
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
/**
* Xcache storage engine for cache
*
* @link http://trac.lighttpd.net/xcache/ Xcache
* @package Cake.Cache.Engine
*/
class XcacheEngine extends CacheEngine {
/**
* Settings
*
* - PHP_AUTH_USER = xcache.admin.user, default cake
* - PHP_AUTH_PW = xcache.admin.password, default cake
*
* @var array
*/
public $settings = array();
/**
* Initialize the Cache Engine
*
* Called automatically by the cache frontend
* To reinitialize the settings call Cache::engine('EngineName', [optional] settings = array());
*
* @param array $settings array of setting for the engine
* @return boolean True if the engine has been successfully initialized, false if not
*/
public function init($settings = array()) {
if (php_sapi_name() !== 'cli') {
parent::init(array_merge(array(
'engine' => 'Xcache',
'prefix' => Inflector::slug(APP_DIR) . '_',
'PHP_AUTH_USER' => 'user',
'PHP_AUTH_PW' => 'password'
), $settings)
);
return function_exists('xcache_info');
}
return false;
}
/**
* Write data for key into cache
*
* @param string $key Identifier for the data
* @param mixed $value Data to be cached
* @param integer $duration How long to cache the data, in seconds
* @return boolean True if the data was successfully cached, false on failure
*/
public function write($key, $value, $duration) {
$expires = time() + $duration;
xcache_set($key . '_expires', $expires, $duration);
return xcache_set($key, $value, $duration);
}
/**
* Read a key from the cache
*
* @param string $key Identifier for the data
* @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it
*/
public function read($key) {
if (xcache_isset($key)) {
$time = time();
$cachetime = intval(xcache_get($key . '_expires'));
if ($cachetime < $time || ($time + $this->settings['duration']) < $cachetime) {
return false;
}
return xcache_get($key);
}
return false;
}
/**
* Increments the value of an integer cached key
* If the cache key is not an integer it will be treated as 0
*
* @param string $key Identifier for the data
* @param integer $offset How much to increment
* @return New incremented value, false otherwise
*/
public function increment($key, $offset = 1) {
return xcache_inc($key, $offset);
}
/**
* Decrements the value of an integer cached key.
* If the cache key is not an integer it will be treated as 0
*
* @param string $key Identifier for the data
* @param integer $offset How much to subtract
* @return New decremented value, false otherwise
*/
public function decrement($key, $offset = 1) {
return xcache_dec($key, $offset);
}
/**
* Delete a key from the cache
*
* @param string $key Identifier for the data
* @return boolean True if the value was successfully deleted, false if it didn't exist or couldn't be removed
*/
public function delete($key) {
return xcache_unset($key);
}
/**
* Delete all keys from the cache
*
* @param boolean $check
* @return boolean True if the cache was successfully cleared, false otherwise
*/
public function clear($check) {
$this->_auth();
$max = xcache_count(XC_TYPE_VAR);
for ($i = 0; $i < $max; $i++) {
xcache_clear_cache(XC_TYPE_VAR, $i);
}
$this->_auth(true);
return true;
}
/**
* Returns the `group value` for each of the configured groups
* If the group initial value was not found, then it initializes
* the group accordingly.
*
* @return array
**/
public function groups() {
$result = array();
foreach ($this->settings['groups'] as $group) {
$value = xcache_get($this->settings['prefix'] . $group);
if (!$value) {
$value = 1;
xcache_set($this->settings['prefix'] . $group, $value, 0);
}
$result[] = $group . $value;
}
return $result;
}
/**
* Increments the group value to simulate deletion of all keys under a group
* old values will remain in storage until they expire.
*
* @return boolean success
**/
public function clearGroup($group) {
return (bool)xcache_inc($this->settings['prefix'] . $group, 1);
}
/**
* Populates and reverses $_SERVER authentication values
* Makes necessary changes (and reverting them back) in $_SERVER
*
* This has to be done because xcache_clear_cache() needs to pass Basic Http Auth
* (see xcache.admin configuration settings)
*
* @param boolean $reverse Revert changes
* @return void
*/
protected function _auth($reverse = false) {
static $backup = array();
$keys = array('PHP_AUTH_USER' => 'user', 'PHP_AUTH_PW' => 'password');
foreach ($keys as $key => $setting) {
if ($reverse) {
if (isset($backup[$key])) {
$_SERVER[$key] = $backup[$key];
unset($backup[$key]);
} else {
unset($_SERVER[$key]);
}
} else {
$value = env($key);
if (!empty($value)) {
$backup[$key] = $value;
}
if (!empty($this->settings[$setting])) {
$_SERVER[$key] = $this->settings[$setting];
} elseif (!empty($this->settings[$key])) {
$_SERVER[$key] = $this->settings[$key];
} else {
$_SERVER[$key] = $value;
}
}
}
}
}