Added KH 3.3.0
This commit is contained in:
3
includes/kohana/modules/cache/classes/Cache.php
vendored
Normal file
3
includes/kohana/modules/cache/classes/Cache.php
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
abstract class Cache extends Kohana_Cache {}
|
3
includes/kohana/modules/cache/classes/Cache/Apc.php
vendored
Normal file
3
includes/kohana/modules/cache/classes/Cache/Apc.php
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Cache_Apc extends Kohana_Cache_Apc {}
|
3
includes/kohana/modules/cache/classes/Cache/Arithmetic.php
vendored
Normal file
3
includes/kohana/modules/cache/classes/Cache/Arithmetic.php
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
interface Cache_Arithmetic extends Kohana_Cache_Arithmetic {}
|
3
includes/kohana/modules/cache/classes/Cache/Exception.php
vendored
Normal file
3
includes/kohana/modules/cache/classes/Cache/Exception.php
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Cache_Exception extends Kohana_Cache_Exception {}
|
3
includes/kohana/modules/cache/classes/Cache/File.php
vendored
Normal file
3
includes/kohana/modules/cache/classes/Cache/File.php
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Cache_File extends Kohana_Cache_File {}
|
3
includes/kohana/modules/cache/classes/Cache/GarbageCollect.php
vendored
Normal file
3
includes/kohana/modules/cache/classes/Cache/GarbageCollect.php
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
interface Cache_GarbageCollect extends Kohana_Cache_GarbageCollect {}
|
3
includes/kohana/modules/cache/classes/Cache/Memcache.php
vendored
Normal file
3
includes/kohana/modules/cache/classes/Cache/Memcache.php
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Cache_Memcache extends Kohana_Cache_Memcache {}
|
3
includes/kohana/modules/cache/classes/Cache/MemcacheTag.php
vendored
Normal file
3
includes/kohana/modules/cache/classes/Cache/MemcacheTag.php
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Cache_MemcacheTag extends Kohana_Cache_MemcacheTag {}
|
3
includes/kohana/modules/cache/classes/Cache/Sqlite.php
vendored
Normal file
3
includes/kohana/modules/cache/classes/Cache/Sqlite.php
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Cache_Sqlite extends Kohana_Cache_Sqlite {}
|
3
includes/kohana/modules/cache/classes/Cache/Tagging.php
vendored
Normal file
3
includes/kohana/modules/cache/classes/Cache/Tagging.php
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
interface Cache_Tagging extends Kohana_Cache_Tagging {}
|
3
includes/kohana/modules/cache/classes/Cache/Wincache.php
vendored
Normal file
3
includes/kohana/modules/cache/classes/Cache/Wincache.php
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Cache_Wincache extends Kohana_Cache_Wincache {}
|
3
includes/kohana/modules/cache/classes/HTTP/Cache.php
vendored
Normal file
3
includes/kohana/modules/cache/classes/HTTP/Cache.php
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class HTTP_Cache extends Kohana_HTTP_Cache {}
|
300
includes/kohana/modules/cache/classes/Kohana/Cache.php
vendored
Normal file
300
includes/kohana/modules/cache/classes/Kohana/Cache.php
vendored
Normal file
@@ -0,0 +1,300 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* Kohana Cache provides a common interface to a variety of caching engines. Tags are
|
||||
* supported where available natively to the cache system. Kohana Cache supports multiple
|
||||
* instances of cache engines through a grouped singleton pattern.
|
||||
*
|
||||
* ### Supported cache engines
|
||||
*
|
||||
* * [APC](http://php.net/manual/en/book.apc.php)
|
||||
* * [eAccelerator](http://eaccelerator.net/)
|
||||
* * File
|
||||
* * [Memcache](http://memcached.org/)
|
||||
* * [Memcached-tags](http://code.google.com/p/memcached-tags/)
|
||||
* * [SQLite](http://www.sqlite.org/)
|
||||
* * [Xcache](http://xcache.lighttpd.net/)
|
||||
*
|
||||
* ### Introduction to caching
|
||||
*
|
||||
* Caching should be implemented with consideration. Generally, caching the result of resources
|
||||
* is faster than reprocessing them. Choosing what, how and when to cache is vital. PHP APC is
|
||||
* presently one of the fastest caching systems available, closely followed by Memcache. SQLite
|
||||
* and File caching are two of the slowest cache methods, however usually faster than reprocessing
|
||||
* a complex set of instructions.
|
||||
*
|
||||
* Caching engines that use memory are considerably faster than the file based alternatives. But
|
||||
* memory is limited whereas disk space is plentiful. If caching large datasets it is best to use
|
||||
* file caching.
|
||||
*
|
||||
* ### Configuration settings
|
||||
*
|
||||
* Kohana Cache uses configuration groups to create cache instances. A configuration group can
|
||||
* use any supported driver, with successive groups using the same driver type if required.
|
||||
*
|
||||
* #### Configuration example
|
||||
*
|
||||
* Below is an example of a _memcache_ server configuration.
|
||||
*
|
||||
* return array(
|
||||
* 'default' => array( // Default group
|
||||
* 'driver' => 'memcache', // using Memcache driver
|
||||
* 'servers' => array( // Available server definitions
|
||||
* array(
|
||||
* 'host' => 'localhost',
|
||||
* 'port' => 11211,
|
||||
* 'persistent' => FALSE
|
||||
* )
|
||||
* ),
|
||||
* 'compression' => FALSE, // Use compression?
|
||||
* ),
|
||||
* )
|
||||
*
|
||||
* In cases where only one cache group is required, if the group is named `default` there is
|
||||
* no need to pass the group name when instantiating a cache instance.
|
||||
*
|
||||
* #### General cache group configuration settings
|
||||
*
|
||||
* Below are the settings available to all types of cache driver.
|
||||
*
|
||||
* Name | Required | Description
|
||||
* -------------- | -------- | ---------------------------------------------------------------
|
||||
* driver | __YES__ | (_string_) The driver type to use
|
||||
*
|
||||
* Details of the settings specific to each driver are available within the drivers documentation.
|
||||
*
|
||||
* ### System requirements
|
||||
*
|
||||
* * Kohana 3.0.x
|
||||
* * PHP 5.2.4 or greater
|
||||
*
|
||||
* @package Kohana/Cache
|
||||
* @category Base
|
||||
* @version 2.0
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2009-2012 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
abstract class Kohana_Cache {
|
||||
|
||||
const DEFAULT_EXPIRE = 3600;
|
||||
|
||||
/**
|
||||
* @var string default driver to use
|
||||
*/
|
||||
public static $default = 'file';
|
||||
|
||||
/**
|
||||
* @var Kohana_Cache instances
|
||||
*/
|
||||
public static $instances = array();
|
||||
|
||||
/**
|
||||
* Creates a singleton of a Kohana Cache group. If no group is supplied
|
||||
* the __default__ cache group is used.
|
||||
*
|
||||
* // Create an instance of the default group
|
||||
* $default_group = Cache::instance();
|
||||
*
|
||||
* // Create an instance of a group
|
||||
* $foo_group = Cache::instance('foo');
|
||||
*
|
||||
* // Access an instantiated group directly
|
||||
* $foo_group = Cache::$instances['default'];
|
||||
*
|
||||
* @param string $group the name of the cache group to use [Optional]
|
||||
* @return Cache
|
||||
* @throws Cache_Exception
|
||||
*/
|
||||
public static function instance($group = NULL)
|
||||
{
|
||||
// If there is no group supplied
|
||||
if ($group === NULL)
|
||||
{
|
||||
// Use the default setting
|
||||
$group = Cache::$default;
|
||||
}
|
||||
|
||||
if (isset(Cache::$instances[$group]))
|
||||
{
|
||||
// Return the current group if initiated already
|
||||
return Cache::$instances[$group];
|
||||
}
|
||||
|
||||
$config = Kohana::$config->load('cache');
|
||||
|
||||
if ( ! $config->offsetExists($group))
|
||||
{
|
||||
throw new Cache_Exception(
|
||||
'Failed to load Kohana Cache group: :group',
|
||||
array(':group' => $group)
|
||||
);
|
||||
}
|
||||
|
||||
$config = $config->get($group);
|
||||
|
||||
// Create a new cache type instance
|
||||
$cache_class = 'Cache_'.ucfirst($config['driver']);
|
||||
Cache::$instances[$group] = new $cache_class($config);
|
||||
|
||||
// Return the instance
|
||||
return Cache::$instances[$group];
|
||||
}
|
||||
|
||||
/**
|
||||
* @var Config
|
||||
*/
|
||||
protected $_config = array();
|
||||
|
||||
/**
|
||||
* Ensures singleton pattern is observed, loads the default expiry
|
||||
*
|
||||
* @param array $config configuration
|
||||
*/
|
||||
protected function __construct(array $config)
|
||||
{
|
||||
$this->config($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter and setter for the configuration. If no argument provided, the
|
||||
* current configuration is returned. Otherwise the configuration is set
|
||||
* to this class.
|
||||
*
|
||||
* // Overwrite all configuration
|
||||
* $cache->config(array('driver' => 'memcache', '...'));
|
||||
*
|
||||
* // Set a new configuration setting
|
||||
* $cache->config('servers', array(
|
||||
* 'foo' => 'bar',
|
||||
* '...'
|
||||
* ));
|
||||
*
|
||||
* // Get a configuration setting
|
||||
* $servers = $cache->config('servers);
|
||||
*
|
||||
* @param mixed key to set to array, either array or config path
|
||||
* @param mixed value to associate with key
|
||||
* @return mixed
|
||||
*/
|
||||
public function config($key = NULL, $value = NULL)
|
||||
{
|
||||
if ($key === NULL)
|
||||
return $this->_config;
|
||||
|
||||
if (is_array($key))
|
||||
{
|
||||
$this->_config = $key;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($value === NULL)
|
||||
return Arr::get($this->_config, $key);
|
||||
|
||||
$this->_config[$key] = $value;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overload the __clone() method to prevent cloning
|
||||
*
|
||||
* @return void
|
||||
* @throws Cache_Exception
|
||||
*/
|
||||
final public function __clone()
|
||||
{
|
||||
throw new Cache_Exception('Cloning of Kohana_Cache objects is forbidden');
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a cached value entry by id.
|
||||
*
|
||||
* // Retrieve cache entry from default group
|
||||
* $data = Cache::instance()->get('foo');
|
||||
*
|
||||
* // Retrieve cache entry from default group and return 'bar' if miss
|
||||
* $data = Cache::instance()->get('foo', 'bar');
|
||||
*
|
||||
* // Retrieve cache entry from memcache group
|
||||
* $data = Cache::instance('memcache')->get('foo');
|
||||
*
|
||||
* @param string $id id of cache to entry
|
||||
* @param string $default default value to return if cache miss
|
||||
* @return mixed
|
||||
* @throws Cache_Exception
|
||||
*/
|
||||
abstract public function get($id, $default = NULL);
|
||||
|
||||
/**
|
||||
* Set a value to cache with id and lifetime
|
||||
*
|
||||
* $data = 'bar';
|
||||
*
|
||||
* // Set 'bar' to 'foo' in default group, using default expiry
|
||||
* Cache::instance()->set('foo', $data);
|
||||
*
|
||||
* // Set 'bar' to 'foo' in default group for 30 seconds
|
||||
* Cache::instance()->set('foo', $data, 30);
|
||||
*
|
||||
* // Set 'bar' to 'foo' in memcache group for 10 minutes
|
||||
* if (Cache::instance('memcache')->set('foo', $data, 600))
|
||||
* {
|
||||
* // Cache was set successfully
|
||||
* return
|
||||
* }
|
||||
*
|
||||
* @param string $id id of cache entry
|
||||
* @param string $data data to set to cache
|
||||
* @param integer $lifetime lifetime in seconds
|
||||
* @return boolean
|
||||
*/
|
||||
abstract public function set($id, $data, $lifetime = 3600);
|
||||
|
||||
/**
|
||||
* Delete a cache entry based on id
|
||||
*
|
||||
* // Delete 'foo' entry from the default group
|
||||
* Cache::instance()->delete('foo');
|
||||
*
|
||||
* // Delete 'foo' entry from the memcache group
|
||||
* Cache::instance('memcache')->delete('foo')
|
||||
*
|
||||
* @param string $id id to remove from cache
|
||||
* @return boolean
|
||||
*/
|
||||
abstract public function delete($id);
|
||||
|
||||
/**
|
||||
* Delete all cache entries.
|
||||
*
|
||||
* Beware of using this method when
|
||||
* using shared memory cache systems, as it will wipe every
|
||||
* entry within the system for all clients.
|
||||
*
|
||||
* // Delete all cache entries in the default group
|
||||
* Cache::instance()->delete_all();
|
||||
*
|
||||
* // Delete all cache entries in the memcache group
|
||||
* Cache::instance('memcache')->delete_all();
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
abstract public function delete_all();
|
||||
|
||||
/**
|
||||
* Replaces troublesome characters with underscores.
|
||||
*
|
||||
* // Sanitize a cache id
|
||||
* $id = $this->_sanitize_id($id);
|
||||
*
|
||||
* @param string $id id of cache to sanitize
|
||||
* @return string
|
||||
*/
|
||||
protected function _sanitize_id($id)
|
||||
{
|
||||
// Change slashes and spaces to underscores
|
||||
return str_replace(array('/', '\\', ' '), '_', $id);
|
||||
}
|
||||
}
|
||||
// End Kohana_Cache
|
166
includes/kohana/modules/cache/classes/Kohana/Cache/Apc.php
vendored
Normal file
166
includes/kohana/modules/cache/classes/Kohana/Cache/Apc.php
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* [Kohana Cache](api/Kohana_Cache) APC driver. Provides an opcode based
|
||||
* driver for the Kohana Cache library.
|
||||
*
|
||||
* ### Configuration example
|
||||
*
|
||||
* Below is an example of an _apc_ server configuration.
|
||||
*
|
||||
* return array(
|
||||
* 'apc' => array( // Driver group
|
||||
* 'driver' => 'apc', // using APC driver
|
||||
* ),
|
||||
* )
|
||||
*
|
||||
* In cases where only one cache group is required, if the group is named `default` there is
|
||||
* no need to pass the group name when instantiating a cache instance.
|
||||
*
|
||||
* #### General cache group configuration settings
|
||||
*
|
||||
* Below are the settings available to all types of cache driver.
|
||||
*
|
||||
* Name | Required | Description
|
||||
* -------------- | -------- | ---------------------------------------------------------------
|
||||
* driver | __YES__ | (_string_) The driver type to use
|
||||
*
|
||||
* ### System requirements
|
||||
*
|
||||
* * Kohana 3.0.x
|
||||
* * PHP 5.2.4 or greater
|
||||
* * APC PHP extension
|
||||
*
|
||||
* @package Kohana/Cache
|
||||
* @category Base
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2009-2012 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Cache_Apc extends Cache implements Cache_Arithmetic {
|
||||
|
||||
/**
|
||||
* Check for existence of the APC extension This method cannot be invoked externally. The driver must
|
||||
* be instantiated using the `Cache::instance()` method.
|
||||
*
|
||||
* @param array $config configuration
|
||||
* @throws Cache_Exception
|
||||
*/
|
||||
protected function __construct(array $config)
|
||||
{
|
||||
if ( ! extension_loaded('apc'))
|
||||
{
|
||||
throw new Cache_Exception('PHP APC extension is not available.');
|
||||
}
|
||||
|
||||
parent::__construct($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a cached value entry by id.
|
||||
*
|
||||
* // Retrieve cache entry from apc group
|
||||
* $data = Cache::instance('apc')->get('foo');
|
||||
*
|
||||
* // Retrieve cache entry from apc group and return 'bar' if miss
|
||||
* $data = Cache::instance('apc')->get('foo', 'bar');
|
||||
*
|
||||
* @param string $id id of cache to entry
|
||||
* @param string $default default value to return if cache miss
|
||||
* @return mixed
|
||||
* @throws Cache_Exception
|
||||
*/
|
||||
public function get($id, $default = NULL)
|
||||
{
|
||||
$data = apc_fetch($this->_sanitize_id($id), $success);
|
||||
|
||||
return $success ? $data : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a value to cache with id and lifetime
|
||||
*
|
||||
* $data = 'bar';
|
||||
*
|
||||
* // Set 'bar' to 'foo' in apc group, using default expiry
|
||||
* Cache::instance('apc')->set('foo', $data);
|
||||
*
|
||||
* // Set 'bar' to 'foo' in apc group for 30 seconds
|
||||
* Cache::instance('apc')->set('foo', $data, 30);
|
||||
*
|
||||
* @param string $id id of cache entry
|
||||
* @param string $data data to set to cache
|
||||
* @param integer $lifetime lifetime in seconds
|
||||
* @return boolean
|
||||
*/
|
||||
public function set($id, $data, $lifetime = NULL)
|
||||
{
|
||||
if ($lifetime === NULL)
|
||||
{
|
||||
$lifetime = Arr::get($this->_config, 'default_expire', Cache::DEFAULT_EXPIRE);
|
||||
}
|
||||
|
||||
return apc_store($this->_sanitize_id($id), $data, $lifetime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a cache entry based on id
|
||||
*
|
||||
* // Delete 'foo' entry from the apc group
|
||||
* Cache::instance('apc')->delete('foo');
|
||||
*
|
||||
* @param string $id id to remove from cache
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete($id)
|
||||
{
|
||||
return apc_delete($this->_sanitize_id($id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all cache entries.
|
||||
*
|
||||
* Beware of using this method when
|
||||
* using shared memory cache systems, as it will wipe every
|
||||
* entry within the system for all clients.
|
||||
*
|
||||
* // Delete all cache entries in the apc group
|
||||
* Cache::instance('apc')->delete_all();
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete_all()
|
||||
{
|
||||
return apc_clear_cache('user');
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments a given value by the step value supplied.
|
||||
* Useful for shared counters and other persistent integer based
|
||||
* tracking.
|
||||
*
|
||||
* @param string id of cache entry to increment
|
||||
* @param int step value to increment by
|
||||
* @return integer
|
||||
* @return boolean
|
||||
*/
|
||||
public function increment($id, $step = 1)
|
||||
{
|
||||
return apc_inc($id, $step);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements a given value by the step value supplied.
|
||||
* Useful for shared counters and other persistent integer based
|
||||
* tracking.
|
||||
*
|
||||
* @param string id of cache entry to decrement
|
||||
* @param int step value to decrement by
|
||||
* @return integer
|
||||
* @return boolean
|
||||
*/
|
||||
public function decrement($id, $step = 1)
|
||||
{
|
||||
return apc_dec($id, $step);
|
||||
}
|
||||
|
||||
} // End Kohana_Cache_Apc
|
39
includes/kohana/modules/cache/classes/Kohana/Cache/Arithmetic.php
vendored
Normal file
39
includes/kohana/modules/cache/classes/Kohana/Cache/Arithmetic.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* Kohana Cache Arithmetic Interface, for basic cache integer based
|
||||
* arithmetic, addition and subtraction
|
||||
*
|
||||
* @package Kohana/Cache
|
||||
* @category Base
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2009-2012 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
* @since 3.2.0
|
||||
*/
|
||||
interface Kohana_Cache_Arithmetic {
|
||||
|
||||
/**
|
||||
* Increments a given value by the step value supplied.
|
||||
* Useful for shared counters and other persistent integer based
|
||||
* tracking.
|
||||
*
|
||||
* @param string id of cache entry to increment
|
||||
* @param int step value to increment by
|
||||
* @return integer
|
||||
* @return boolean
|
||||
*/
|
||||
public function increment($id, $step = 1);
|
||||
|
||||
/**
|
||||
* Decrements a given value by the step value supplied.
|
||||
* Useful for shared counters and other persistent integer based
|
||||
* tracking.
|
||||
*
|
||||
* @param string id of cache entry to decrement
|
||||
* @param int step value to decrement by
|
||||
* @return integer
|
||||
* @return boolean
|
||||
*/
|
||||
public function decrement($id, $step = 1);
|
||||
|
||||
} // End Kohana_Cache_Arithmetic
|
11
includes/kohana/modules/cache/classes/Kohana/Cache/Exception.php
vendored
Normal file
11
includes/kohana/modules/cache/classes/Kohana/Cache/Exception.php
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* Kohana Cache Exception
|
||||
*
|
||||
* @package Kohana/Cache
|
||||
* @category Base
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2009-2012 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Cache_Exception extends Kohana_Exception {}
|
466
includes/kohana/modules/cache/classes/Kohana/Cache/File.php
vendored
Normal file
466
includes/kohana/modules/cache/classes/Kohana/Cache/File.php
vendored
Normal file
@@ -0,0 +1,466 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* [Kohana Cache](api/Kohana_Cache) File driver. Provides a file based
|
||||
* driver for the Kohana Cache library. This is one of the slowest
|
||||
* caching methods.
|
||||
*
|
||||
* ### Configuration example
|
||||
*
|
||||
* Below is an example of a _file_ server configuration.
|
||||
*
|
||||
* return array(
|
||||
* 'file' => array( // File driver group
|
||||
* 'driver' => 'file', // using File driver
|
||||
* 'cache_dir' => APPPATH.'cache/.kohana_cache', // Cache location
|
||||
* ),
|
||||
* )
|
||||
*
|
||||
* In cases where only one cache group is required, if the group is named `default` there is
|
||||
* no need to pass the group name when instantiating a cache instance.
|
||||
*
|
||||
* #### General cache group configuration settings
|
||||
*
|
||||
* Below are the settings available to all types of cache driver.
|
||||
*
|
||||
* Name | Required | Description
|
||||
* -------------- | -------- | ---------------------------------------------------------------
|
||||
* driver | __YES__ | (_string_) The driver type to use
|
||||
* cache_dir | __NO__ | (_string_) The cache directory to use for this cache instance
|
||||
*
|
||||
* ### System requirements
|
||||
*
|
||||
* * Kohana 3.0.x
|
||||
* * PHP 5.2.4 or greater
|
||||
*
|
||||
* @package Kohana/Cache
|
||||
* @category Base
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2009-2012 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Cache_File extends Cache implements Cache_GarbageCollect {
|
||||
|
||||
/**
|
||||
* Creates a hashed filename based on the string. This is used
|
||||
* to create shorter unique IDs for each cache filename.
|
||||
*
|
||||
* // Create the cache filename
|
||||
* $filename = Cache_File::filename($this->_sanitize_id($id));
|
||||
*
|
||||
* @param string $string string to hash into filename
|
||||
* @return string
|
||||
*/
|
||||
protected static function filename($string)
|
||||
{
|
||||
return sha1($string).'.cache';
|
||||
}
|
||||
|
||||
/**
|
||||
* @var string the caching directory
|
||||
*/
|
||||
protected $_cache_dir;
|
||||
|
||||
/**
|
||||
* Constructs the file cache driver. This method cannot be invoked externally. The file cache driver must
|
||||
* be instantiated using the `Cache::instance()` method.
|
||||
*
|
||||
* @param array $config config
|
||||
* @throws Cache_Exception
|
||||
*/
|
||||
protected function __construct(array $config)
|
||||
{
|
||||
// Setup parent
|
||||
parent::__construct($config);
|
||||
|
||||
try
|
||||
{
|
||||
$directory = Arr::get($this->_config, 'cache_dir', Kohana::$cache_dir);
|
||||
$this->_cache_dir = new SplFileInfo($directory);
|
||||
}
|
||||
// PHP < 5.3 exception handle
|
||||
catch (ErrorException $e)
|
||||
{
|
||||
$this->_cache_dir = $this->_make_directory($directory, 0777, TRUE);
|
||||
}
|
||||
// PHP >= 5.3 exception handle
|
||||
catch (UnexpectedValueException $e)
|
||||
{
|
||||
$this->_cache_dir = $this->_make_directory($directory, 0777, TRUE);
|
||||
}
|
||||
|
||||
// If the defined directory is a file, get outta here
|
||||
if ($this->_cache_dir->isFile())
|
||||
{
|
||||
throw new Cache_Exception('Unable to create cache directory as a file already exists : :resource', array(':resource' => $this->_cache_dir->getRealPath()));
|
||||
}
|
||||
|
||||
// Check the read status of the directory
|
||||
if ( ! $this->_cache_dir->isReadable())
|
||||
{
|
||||
throw new Cache_Exception('Unable to read from the cache directory :resource', array(':resource' => $this->_cache_dir->getRealPath()));
|
||||
}
|
||||
|
||||
// Check the write status of the directory
|
||||
if ( ! $this->_cache_dir->isWritable())
|
||||
{
|
||||
throw new Cache_Exception('Unable to write to the cache directory :resource', array(':resource' => $this->_cache_dir->getRealPath()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a cached value entry by id.
|
||||
*
|
||||
* // Retrieve cache entry from file group
|
||||
* $data = Cache::instance('file')->get('foo');
|
||||
*
|
||||
* // Retrieve cache entry from file group and return 'bar' if miss
|
||||
* $data = Cache::instance('file')->get('foo', 'bar');
|
||||
*
|
||||
* @param string $id id of cache to entry
|
||||
* @param string $default default value to return if cache miss
|
||||
* @return mixed
|
||||
* @throws Cache_Exception
|
||||
*/
|
||||
public function get($id, $default = NULL)
|
||||
{
|
||||
$filename = Cache_File::filename($this->_sanitize_id($id));
|
||||
$directory = $this->_resolve_directory($filename);
|
||||
|
||||
// Wrap operations in try/catch to handle notices
|
||||
try
|
||||
{
|
||||
// Open file
|
||||
$file = new SplFileInfo($directory.$filename);
|
||||
|
||||
// If file does not exist
|
||||
if ( ! $file->isFile())
|
||||
{
|
||||
// Return default value
|
||||
return $default;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Open the file and parse data
|
||||
$created = $file->getMTime();
|
||||
$data = $file->openFile();
|
||||
$lifetime = $data->fgets();
|
||||
|
||||
// If we're at the EOF at this point, corrupted!
|
||||
if ($data->eof())
|
||||
{
|
||||
throw new Cache_Exception(__METHOD__.' corrupted cache file!');
|
||||
}
|
||||
|
||||
$cache = '';
|
||||
|
||||
while ($data->eof() === FALSE)
|
||||
{
|
||||
$cache .= $data->fgets();
|
||||
}
|
||||
|
||||
// Test the expiry
|
||||
if (($created + (int) $lifetime) < time())
|
||||
{
|
||||
// Delete the file
|
||||
$this->_delete_file($file, NULL, TRUE);
|
||||
return $default;
|
||||
}
|
||||
else
|
||||
{
|
||||
return unserialize($cache);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (ErrorException $e)
|
||||
{
|
||||
// Handle ErrorException caused by failed unserialization
|
||||
if ($e->getCode() === E_NOTICE)
|
||||
{
|
||||
throw new Cache_Exception(__METHOD__.' failed to unserialize cached object with message : '.$e->getMessage());
|
||||
}
|
||||
|
||||
// Otherwise throw the exception
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a value to cache with id and lifetime
|
||||
*
|
||||
* $data = 'bar';
|
||||
*
|
||||
* // Set 'bar' to 'foo' in file group, using default expiry
|
||||
* Cache::instance('file')->set('foo', $data);
|
||||
*
|
||||
* // Set 'bar' to 'foo' in file group for 30 seconds
|
||||
* Cache::instance('file')->set('foo', $data, 30);
|
||||
*
|
||||
* @param string $id id of cache entry
|
||||
* @param string $data data to set to cache
|
||||
* @param integer $lifetime lifetime in seconds
|
||||
* @return boolean
|
||||
*/
|
||||
public function set($id, $data, $lifetime = NULL)
|
||||
{
|
||||
$filename = Cache_File::filename($this->_sanitize_id($id));
|
||||
$directory = $this->_resolve_directory($filename);
|
||||
|
||||
// If lifetime is NULL
|
||||
if ($lifetime === NULL)
|
||||
{
|
||||
// Set to the default expiry
|
||||
$lifetime = Arr::get($this->_config, 'default_expire', Cache::DEFAULT_EXPIRE);
|
||||
}
|
||||
|
||||
// Open directory
|
||||
$dir = new SplFileInfo($directory);
|
||||
|
||||
// If the directory path is not a directory
|
||||
if ( ! $dir->isDir())
|
||||
{
|
||||
// Create the directory
|
||||
if ( ! mkdir($directory, 0777, TRUE))
|
||||
{
|
||||
throw new Cache_Exception(__METHOD__.' unable to create directory : :directory', array(':directory' => $directory));
|
||||
}
|
||||
|
||||
// chmod to solve potential umask issues
|
||||
chmod($directory, 0777);
|
||||
}
|
||||
|
||||
// Open file to inspect
|
||||
$resouce = new SplFileInfo($directory.$filename);
|
||||
$file = $resouce->openFile('w');
|
||||
|
||||
try
|
||||
{
|
||||
$data = $lifetime."\n".serialize($data);
|
||||
$file->fwrite($data, strlen($data));
|
||||
return (bool) $file->fflush();
|
||||
}
|
||||
catch (ErrorException $e)
|
||||
{
|
||||
// If serialize through an error exception
|
||||
if ($e->getCode() === E_NOTICE)
|
||||
{
|
||||
// Throw a caching error
|
||||
throw new Cache_Exception(__METHOD__.' failed to serialize data for caching with message : '.$e->getMessage());
|
||||
}
|
||||
|
||||
// Else rethrow the error exception
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a cache entry based on id
|
||||
*
|
||||
* // Delete 'foo' entry from the file group
|
||||
* Cache::instance('file')->delete('foo');
|
||||
*
|
||||
* @param string $id id to remove from cache
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete($id)
|
||||
{
|
||||
$filename = Cache_File::filename($this->_sanitize_id($id));
|
||||
$directory = $this->_resolve_directory($filename);
|
||||
|
||||
return $this->_delete_file(new SplFileInfo($directory.$filename), NULL, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all cache entries.
|
||||
*
|
||||
* Beware of using this method when
|
||||
* using shared memory cache systems, as it will wipe every
|
||||
* entry within the system for all clients.
|
||||
*
|
||||
* // Delete all cache entries in the file group
|
||||
* Cache::instance('file')->delete_all();
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete_all()
|
||||
{
|
||||
return $this->_delete_file($this->_cache_dir, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Garbage collection method that cleans any expired
|
||||
* cache entries from the cache.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function garbage_collect()
|
||||
{
|
||||
$this->_delete_file($this->_cache_dir, TRUE, FALSE, TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes files recursively and returns FALSE on any errors
|
||||
*
|
||||
* // Delete a file or folder whilst retaining parent directory and ignore all errors
|
||||
* $this->_delete_file($folder, TRUE, TRUE);
|
||||
*
|
||||
* @param SplFileInfo $file file
|
||||
* @param boolean $retain_parent_directory retain the parent directory
|
||||
* @param boolean $ignore_errors ignore_errors to prevent all exceptions interrupting exec
|
||||
* @param boolean $only_expired only expired files
|
||||
* @return boolean
|
||||
* @throws Cache_Exception
|
||||
*/
|
||||
protected function _delete_file(SplFileInfo $file, $retain_parent_directory = FALSE, $ignore_errors = FALSE, $only_expired = FALSE)
|
||||
{
|
||||
// Allow graceful error handling
|
||||
try
|
||||
{
|
||||
// If is file
|
||||
if ($file->isFile())
|
||||
{
|
||||
try
|
||||
{
|
||||
// Handle ignore files
|
||||
if (in_array($file->getFilename(), $this->config('ignore_on_delete')))
|
||||
{
|
||||
$delete = FALSE;
|
||||
}
|
||||
// If only expired is not set
|
||||
elseif ($only_expired === FALSE)
|
||||
{
|
||||
// We want to delete the file
|
||||
$delete = TRUE;
|
||||
}
|
||||
// Otherwise...
|
||||
else
|
||||
{
|
||||
// Assess the file expiry to flag it for deletion
|
||||
$json = $file->openFile('r')->current();
|
||||
$data = json_decode($json);
|
||||
$delete = $data->expiry < time();
|
||||
}
|
||||
|
||||
// If the delete flag is set delete file
|
||||
if ($delete === TRUE)
|
||||
return unlink($file->getRealPath());
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
catch (ErrorException $e)
|
||||
{
|
||||
// Catch any delete file warnings
|
||||
if ($e->getCode() === E_WARNING)
|
||||
{
|
||||
throw new Cache_Exception(__METHOD__.' failed to delete file : :file', array(':file' => $file->getRealPath()));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Else, is directory
|
||||
elseif ($file->isDir())
|
||||
{
|
||||
// Create new DirectoryIterator
|
||||
$files = new DirectoryIterator($file->getPathname());
|
||||
|
||||
// Iterate over each entry
|
||||
while ($files->valid())
|
||||
{
|
||||
// Extract the entry name
|
||||
$name = $files->getFilename();
|
||||
|
||||
// If the name is not a dot
|
||||
if ($name != '.' AND $name != '..')
|
||||
{
|
||||
// Create new file resource
|
||||
$fp = new SplFileInfo($files->getRealPath());
|
||||
// Delete the file
|
||||
$this->_delete_file($fp);
|
||||
}
|
||||
|
||||
// Move the file pointer on
|
||||
$files->next();
|
||||
}
|
||||
|
||||
// If set to retain parent directory, return now
|
||||
if ($retain_parent_directory)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Remove the files iterator
|
||||
// (fixes Windows PHP which has permission issues with open iterators)
|
||||
unset($files);
|
||||
|
||||
// Try to remove the parent directory
|
||||
return rmdir($file->getRealPath());
|
||||
}
|
||||
catch (ErrorException $e)
|
||||
{
|
||||
// Catch any delete directory warnings
|
||||
if ($e->getCode() === E_WARNING)
|
||||
{
|
||||
throw new Cache_Exception(__METHOD__.' failed to delete directory : :directory', array(':directory' => $file->getRealPath()));
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// We get here if a file has already been deleted
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
// Catch all exceptions
|
||||
catch (Exception $e)
|
||||
{
|
||||
// If ignore_errors is on
|
||||
if ($ignore_errors === TRUE)
|
||||
{
|
||||
// Return
|
||||
return FALSE;
|
||||
}
|
||||
// Throw exception
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the cache directory real path from the filename
|
||||
*
|
||||
* // Get the realpath of the cache folder
|
||||
* $realpath = $this->_resolve_directory($filename);
|
||||
*
|
||||
* @param string $filename filename to resolve
|
||||
* @return string
|
||||
*/
|
||||
protected function _resolve_directory($filename)
|
||||
{
|
||||
return $this->_cache_dir->getRealPath().DIRECTORY_SEPARATOR.$filename[0].$filename[1].DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the cache directory if it doesn't exist. Simply a wrapper for
|
||||
* `mkdir` to ensure DRY principles
|
||||
*
|
||||
* @link http://php.net/manual/en/function.mkdir.php
|
||||
* @param string $directory
|
||||
* @param integer $mode
|
||||
* @param boolean $recursive
|
||||
* @param resource $context
|
||||
* @return SplFileInfo
|
||||
* @throws Cache_Exception
|
||||
*/
|
||||
protected function _make_directory($directory, $mode = 0777, $recursive = FALSE, $context = NULL)
|
||||
{
|
||||
if ( ! mkdir($directory, $mode, $recursive, $context))
|
||||
{
|
||||
throw new Cache_Exception('Failed to create the defined cache directory : :directory', array(':directory' => $directory));
|
||||
}
|
||||
chmod($directory, $mode);
|
||||
|
||||
return new SplFileInfo($directory);
|
||||
}
|
||||
}
|
23
includes/kohana/modules/cache/classes/Kohana/Cache/GarbageCollect.php
vendored
Normal file
23
includes/kohana/modules/cache/classes/Kohana/Cache/GarbageCollect.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* Garbage Collection interface for caches that have no GC methods
|
||||
* of their own, such as [Cache_File] and [Cache_Sqlite]. Memory based
|
||||
* cache systems clean their own caches periodically.
|
||||
*
|
||||
* @package Kohana/Cache
|
||||
* @category Base
|
||||
* @version 2.0
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2009-2012 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
* @since 3.0.8
|
||||
*/
|
||||
interface Kohana_Cache_GarbageCollect {
|
||||
/**
|
||||
* Garbage collection method that cleans any expired
|
||||
* cache entries from the cache.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function garbage_collect();
|
||||
}
|
354
includes/kohana/modules/cache/classes/Kohana/Cache/Memcache.php
vendored
Normal file
354
includes/kohana/modules/cache/classes/Kohana/Cache/Memcache.php
vendored
Normal file
@@ -0,0 +1,354 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* [Kohana Cache](api/Kohana_Cache) Memcache driver,
|
||||
*
|
||||
* ### Supported cache engines
|
||||
*
|
||||
* * [Memcache](http://www.php.net/manual/en/book.memcache.php)
|
||||
* * [Memcached-tags](http://code.google.com/p/memcached-tags/)
|
||||
*
|
||||
* ### Configuration example
|
||||
*
|
||||
* Below is an example of a _memcache_ server configuration.
|
||||
*
|
||||
* return array(
|
||||
* 'default' => array( // Default group
|
||||
* 'driver' => 'memcache', // using Memcache driver
|
||||
* 'servers' => array( // Available server definitions
|
||||
* // First memcache server server
|
||||
* array(
|
||||
* 'host' => 'localhost',
|
||||
* 'port' => 11211,
|
||||
* 'persistent' => FALSE
|
||||
* 'weight' => 1,
|
||||
* 'timeout' => 1,
|
||||
* 'retry_interval' => 15,
|
||||
* 'status' => TRUE,
|
||||
* 'instant_death' => TRUE,
|
||||
* 'failure_callback' => array('className', 'classMethod')
|
||||
* ),
|
||||
* // Second memcache server
|
||||
* array(
|
||||
* 'host' => '192.168.1.5',
|
||||
* 'port' => 22122,
|
||||
* 'persistent' => TRUE
|
||||
* )
|
||||
* ),
|
||||
* 'compression' => FALSE, // Use compression?
|
||||
* ),
|
||||
* )
|
||||
*
|
||||
* In cases where only one cache group is required, if the group is named `default` there is
|
||||
* no need to pass the group name when instantiating a cache instance.
|
||||
*
|
||||
* #### General cache group configuration settings
|
||||
*
|
||||
* Below are the settings available to all types of cache driver.
|
||||
*
|
||||
* Name | Required | Description
|
||||
* -------------- | -------- | ---------------------------------------------------------------
|
||||
* driver | __YES__ | (_string_) The driver type to use
|
||||
* servers | __YES__ | (_array_) Associative array of server details, must include a __host__ key. (see _Memcache server configuration_ below)
|
||||
* compression | __NO__ | (_boolean_) Use data compression when caching
|
||||
*
|
||||
* #### Memcache server configuration
|
||||
*
|
||||
* The following settings should be used when defining each memcache server
|
||||
*
|
||||
* Name | Required | Description
|
||||
* ---------------- | -------- | ---------------------------------------------------------------
|
||||
* host | __YES__ | (_string_) The host of the memcache server, i.e. __localhost__; or __127.0.0.1__; or __memcache.domain.tld__
|
||||
* port | __NO__ | (_integer_) Point to the port where memcached is listening for connections. Set this parameter to 0 when using UNIX domain sockets. Default __11211__
|
||||
* persistent | __NO__ | (_boolean_) Controls the use of a persistent connection. Default __TRUE__
|
||||
* weight | __NO__ | (_integer_) Number of buckets to create for this server which in turn control its probability of it being selected. The probability is relative to the total weight of all servers. Default __1__
|
||||
* timeout | __NO__ | (_integer_) Value in seconds which will be used for connecting to the daemon. Think twice before changing the default value of 1 second - you can lose all the advantages of caching if your connection is too slow. Default __1__
|
||||
* retry_interval | __NO__ | (_integer_) Controls how often a failed server will be retried, the default value is 15 seconds. Setting this parameter to -1 disables automatic retry. Default __15__
|
||||
* status | __NO__ | (_boolean_) Controls if the server should be flagged as online. Default __TRUE__
|
||||
* failure_callback | __NO__ | (_[callback](http://www.php.net/manual/en/language.pseudo-types.php#language.types.callback)_) Allows the user to specify a callback function to run upon encountering an error. The callback is run before failover is attempted. The function takes two parameters, the hostname and port of the failed server. Default __NULL__
|
||||
*
|
||||
* ### System requirements
|
||||
*
|
||||
* * Kohana 3.0.x
|
||||
* * PHP 5.2.4 or greater
|
||||
* * Memcache (plus Memcached-tags for native tagging support)
|
||||
* * Zlib
|
||||
*
|
||||
* @package Kohana/Cache
|
||||
* @category Base
|
||||
* @version 2.0
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2009-2012 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Cache_Memcache extends Cache implements Cache_Arithmetic {
|
||||
|
||||
// Memcache has a maximum cache lifetime of 30 days
|
||||
const CACHE_CEILING = 2592000;
|
||||
|
||||
/**
|
||||
* Memcache resource
|
||||
*
|
||||
* @var Memcache
|
||||
*/
|
||||
protected $_memcache;
|
||||
|
||||
/**
|
||||
* Flags to use when storing values
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_flags;
|
||||
|
||||
/**
|
||||
* The default configuration for the memcached server
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_default_config = array();
|
||||
|
||||
/**
|
||||
* Constructs the memcache Kohana_Cache object
|
||||
*
|
||||
* @param array $config configuration
|
||||
* @throws Cache_Exception
|
||||
*/
|
||||
protected function __construct(array $config)
|
||||
{
|
||||
// Check for the memcache extention
|
||||
if ( ! extension_loaded('memcache'))
|
||||
{
|
||||
throw new Cache_Exception('Memcache PHP extention not loaded');
|
||||
}
|
||||
|
||||
parent::__construct($config);
|
||||
|
||||
// Setup Memcache
|
||||
$this->_memcache = new Memcache;
|
||||
|
||||
// Load servers from configuration
|
||||
$servers = Arr::get($this->_config, 'servers', NULL);
|
||||
|
||||
if ( ! $servers)
|
||||
{
|
||||
// Throw an exception if no server found
|
||||
throw new Cache_Exception('No Memcache servers defined in configuration');
|
||||
}
|
||||
|
||||
// Setup default server configuration
|
||||
$this->_default_config = array(
|
||||
'host' => 'localhost',
|
||||
'port' => 11211,
|
||||
'persistent' => FALSE,
|
||||
'weight' => 1,
|
||||
'timeout' => 1,
|
||||
'retry_interval' => 15,
|
||||
'status' => TRUE,
|
||||
'instant_death' => TRUE,
|
||||
'failure_callback' => array($this, '_failed_request'),
|
||||
);
|
||||
|
||||
// Add the memcache servers to the pool
|
||||
foreach ($servers as $server)
|
||||
{
|
||||
// Merge the defined config with defaults
|
||||
$server += $this->_default_config;
|
||||
|
||||
if ( ! $this->_memcache->addServer($server['host'], $server['port'], $server['persistent'], $server['weight'], $server['timeout'], $server['retry_interval'], $server['status'], $server['failure_callback']))
|
||||
{
|
||||
throw new Cache_Exception('Memcache could not connect to host \':host\' using port \':port\'', array(':host' => $server['host'], ':port' => $server['port']));
|
||||
}
|
||||
}
|
||||
|
||||
// Setup the flags
|
||||
$this->_flags = Arr::get($this->_config, 'compression', FALSE) ? MEMCACHE_COMPRESSED : FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a cached value entry by id.
|
||||
*
|
||||
* // Retrieve cache entry from memcache group
|
||||
* $data = Cache::instance('memcache')->get('foo');
|
||||
*
|
||||
* // Retrieve cache entry from memcache group and return 'bar' if miss
|
||||
* $data = Cache::instance('memcache')->get('foo', 'bar');
|
||||
*
|
||||
* @param string $id id of cache to entry
|
||||
* @param string $default default value to return if cache miss
|
||||
* @return mixed
|
||||
* @throws Cache_Exception
|
||||
*/
|
||||
public function get($id, $default = NULL)
|
||||
{
|
||||
// Get the value from Memcache
|
||||
$value = $this->_memcache->get($this->_sanitize_id($id));
|
||||
|
||||
// If the value wasn't found, normalise it
|
||||
if ($value === FALSE)
|
||||
{
|
||||
$value = (NULL === $default) ? NULL : $default;
|
||||
}
|
||||
|
||||
// Return the value
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a value to cache with id and lifetime
|
||||
*
|
||||
* $data = 'bar';
|
||||
*
|
||||
* // Set 'bar' to 'foo' in memcache group for 10 minutes
|
||||
* if (Cache::instance('memcache')->set('foo', $data, 600))
|
||||
* {
|
||||
* // Cache was set successfully
|
||||
* return
|
||||
* }
|
||||
*
|
||||
* @param string $id id of cache entry
|
||||
* @param mixed $data data to set to cache
|
||||
* @param integer $lifetime lifetime in seconds, maximum value 2592000
|
||||
* @return boolean
|
||||
*/
|
||||
public function set($id, $data, $lifetime = 3600)
|
||||
{
|
||||
// If the lifetime is greater than the ceiling
|
||||
if ($lifetime > Cache_Memcache::CACHE_CEILING)
|
||||
{
|
||||
// Set the lifetime to maximum cache time
|
||||
$lifetime = Cache_Memcache::CACHE_CEILING + time();
|
||||
}
|
||||
// Else if the lifetime is greater than zero
|
||||
elseif ($lifetime > 0)
|
||||
{
|
||||
$lifetime += time();
|
||||
}
|
||||
// Else
|
||||
else
|
||||
{
|
||||
// Normalise the lifetime
|
||||
$lifetime = 0;
|
||||
}
|
||||
|
||||
// Set the data to memcache
|
||||
return $this->_memcache->set($this->_sanitize_id($id), $data, $this->_flags, $lifetime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a cache entry based on id
|
||||
*
|
||||
* // Delete the 'foo' cache entry immediately
|
||||
* Cache::instance('memcache')->delete('foo');
|
||||
*
|
||||
* // Delete the 'bar' cache entry after 30 seconds
|
||||
* Cache::instance('memcache')->delete('bar', 30);
|
||||
*
|
||||
* @param string $id id of entry to delete
|
||||
* @param integer $timeout timeout of entry, if zero item is deleted immediately, otherwise the item will delete after the specified value in seconds
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete($id, $timeout = 0)
|
||||
{
|
||||
// Delete the id
|
||||
return $this->_memcache->delete($this->_sanitize_id($id), $timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all cache entries.
|
||||
*
|
||||
* Beware of using this method when
|
||||
* using shared memory cache systems, as it will wipe every
|
||||
* entry within the system for all clients.
|
||||
*
|
||||
* // Delete all cache entries in the default group
|
||||
* Cache::instance('memcache')->delete_all();
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete_all()
|
||||
{
|
||||
$result = $this->_memcache->flush();
|
||||
|
||||
// We must sleep after flushing, or overwriting will not work!
|
||||
// @see http://php.net/manual/en/function.memcache-flush.php#81420
|
||||
sleep(1);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback method for Memcache::failure_callback to use if any Memcache call
|
||||
* on a particular server fails. This method switches off that instance of the
|
||||
* server if the configuration setting `instant_death` is set to `TRUE`.
|
||||
*
|
||||
* @param string $hostname
|
||||
* @param integer $port
|
||||
* @return void|boolean
|
||||
* @since 3.0.8
|
||||
*/
|
||||
public function _failed_request($hostname, $port)
|
||||
{
|
||||
if ( ! $this->_config['instant_death'])
|
||||
return;
|
||||
|
||||
// Setup non-existent host
|
||||
$host = FALSE;
|
||||
|
||||
// Get host settings from configuration
|
||||
foreach ($this->_config['servers'] as $server)
|
||||
{
|
||||
// Merge the defaults, since they won't always be set
|
||||
$server += $this->_default_config;
|
||||
// We're looking at the failed server
|
||||
if ($hostname == $server['host'] and $port == $server['port'])
|
||||
{
|
||||
// Server to disable, since it failed
|
||||
$host = $server;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $host)
|
||||
return;
|
||||
else
|
||||
{
|
||||
return $this->_memcache->setServerParams(
|
||||
$host['host'],
|
||||
$host['port'],
|
||||
$host['timeout'],
|
||||
$host['retry_interval'],
|
||||
FALSE, // Server is offline
|
||||
array($this, '_failed_request'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments a given value by the step value supplied.
|
||||
* Useful for shared counters and other persistent integer based
|
||||
* tracking.
|
||||
*
|
||||
* @param string id of cache entry to increment
|
||||
* @param int step value to increment by
|
||||
* @return integer
|
||||
* @return boolean
|
||||
*/
|
||||
public function increment($id, $step = 1)
|
||||
{
|
||||
return $this->_memcache->increment($id, $step);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements a given value by the step value supplied.
|
||||
* Useful for shared counters and other persistent integer based
|
||||
* tracking.
|
||||
*
|
||||
* @param string id of cache entry to decrement
|
||||
* @param int step value to decrement by
|
||||
* @return integer
|
||||
* @return boolean
|
||||
*/
|
||||
public function decrement($id, $step = 1)
|
||||
{
|
||||
return $this->_memcache->decrement($id, $step);
|
||||
}
|
||||
}
|
78
includes/kohana/modules/cache/classes/Kohana/Cache/MemcacheTag.php
vendored
Normal file
78
includes/kohana/modules/cache/classes/Kohana/Cache/MemcacheTag.php
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* See [Kohana_Cache_Memcache]
|
||||
*
|
||||
* @package Kohana/Cache
|
||||
* @category Base
|
||||
* @version 2.0
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2009-2012 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Cache_MemcacheTag extends Cache_Memcache implements Cache_Tagging {
|
||||
|
||||
/**
|
||||
* Constructs the memcache object
|
||||
*
|
||||
* @param array $config configuration
|
||||
* @throws Cache_Exception
|
||||
*/
|
||||
protected function __construct(array $config)
|
||||
{
|
||||
parent::__construct($config);
|
||||
|
||||
if ( ! method_exists($this->_memcache, 'tag_add'))
|
||||
{
|
||||
throw new Cache_Exception('Memcached-tags PHP plugin not present. Please see http://code.google.com/p/memcached-tags/ for more information');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a value based on an id with tags
|
||||
*
|
||||
* @param string $id id
|
||||
* @param mixed $data data
|
||||
* @param integer $lifetime lifetime [Optional]
|
||||
* @param array $tags tags [Optional]
|
||||
* @return boolean
|
||||
*/
|
||||
public function set_with_tags($id, $data, $lifetime = NULL, array $tags = NULL)
|
||||
{
|
||||
$id = $this->_sanitize_id($id);
|
||||
|
||||
$result = $this->set($id, $data, $lifetime);
|
||||
|
||||
if ($result and $tags)
|
||||
{
|
||||
foreach ($tags as $tag)
|
||||
{
|
||||
$this->_memcache->tag_add($tag, $id);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete cache entries based on a tag
|
||||
*
|
||||
* @param string $tag tag
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete_tag($tag)
|
||||
{
|
||||
return $this->_memcache->tag_delete($tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find cache entries based on a tag
|
||||
*
|
||||
* @param string $tag tag
|
||||
* @return void
|
||||
* @throws Cache_Exception
|
||||
*/
|
||||
public function find($tag)
|
||||
{
|
||||
throw new Cache_Exception('Memcached-tags does not support finding by tag');
|
||||
}
|
||||
}
|
334
includes/kohana/modules/cache/classes/Kohana/Cache/Sqlite.php
vendored
Normal file
334
includes/kohana/modules/cache/classes/Kohana/Cache/Sqlite.php
vendored
Normal file
@@ -0,0 +1,334 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* Kohana Cache Sqlite Driver
|
||||
*
|
||||
* Requires SQLite3 and PDO
|
||||
*
|
||||
* @package Kohana/Cache
|
||||
* @category Base
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2009-2012 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Cache_Sqlite extends Cache implements Cache_Tagging, Cache_GarbageCollect {
|
||||
|
||||
/**
|
||||
* Database resource
|
||||
*
|
||||
* @var PDO
|
||||
*/
|
||||
protected $_db;
|
||||
|
||||
/**
|
||||
* Sets up the PDO SQLite table and
|
||||
* initialises the PDO connection
|
||||
*
|
||||
* @param array $config configuration
|
||||
* @throws Cache_Exception
|
||||
*/
|
||||
protected function __construct(array $config)
|
||||
{
|
||||
parent::__construct($config);
|
||||
|
||||
$database = Arr::get($this->_config, 'database', NULL);
|
||||
|
||||
if ($database === NULL)
|
||||
{
|
||||
throw new Cache_Exception('Database path not available in Kohana Cache configuration');
|
||||
}
|
||||
|
||||
// Load new Sqlite DB
|
||||
$this->_db = new PDO('sqlite:'.$database);
|
||||
|
||||
// Test for existing DB
|
||||
$result = $this->_db->query("SELECT * FROM sqlite_master WHERE name = 'caches' AND type = 'table'")->fetchAll();
|
||||
|
||||
// If there is no table, create a new one
|
||||
if (0 == count($result))
|
||||
{
|
||||
$database_schema = Arr::get($this->_config, 'schema', NULL);
|
||||
|
||||
if ($database_schema === NULL)
|
||||
{
|
||||
throw new Cache_Exception('Database schema not found in Kohana Cache configuration');
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Create the caches table
|
||||
$this->_db->query(Arr::get($this->_config, 'schema', NULL));
|
||||
}
|
||||
catch (PDOException $e)
|
||||
{
|
||||
throw new Cache_Exception('Failed to create new SQLite caches table with the following error : :error', array(':error' => $e->getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a value based on an id
|
||||
*
|
||||
* @param string $id id
|
||||
* @param string $default default [Optional] Default value to return if id not found
|
||||
* @return mixed
|
||||
* @throws Cache_Exception
|
||||
*/
|
||||
public function get($id, $default = NULL)
|
||||
{
|
||||
// Prepare statement
|
||||
$statement = $this->_db->prepare('SELECT id, expiration, cache FROM caches WHERE id = :id LIMIT 0, 1');
|
||||
|
||||
// Try and load the cache based on id
|
||||
try
|
||||
{
|
||||
$statement->execute(array(':id' => $this->_sanitize_id($id)));
|
||||
}
|
||||
catch (PDOException $e)
|
||||
{
|
||||
throw new Cache_Exception('There was a problem querying the local SQLite3 cache. :error', array(':error' => $e->getMessage()));
|
||||
}
|
||||
|
||||
if ( ! $result = $statement->fetch(PDO::FETCH_OBJ))
|
||||
{
|
||||
return $default;
|
||||
}
|
||||
|
||||
// If the cache has expired
|
||||
if ($result->expiration != 0 and $result->expiration <= time())
|
||||
{
|
||||
// Delete it and return default value
|
||||
$this->delete($id);
|
||||
return $default;
|
||||
}
|
||||
// Otherwise return cached object
|
||||
else
|
||||
{
|
||||
// Disable notices for unserializing
|
||||
$ER = error_reporting(~E_NOTICE);
|
||||
|
||||
// Return the valid cache data
|
||||
$data = unserialize($result->cache);
|
||||
|
||||
// Turn notices back on
|
||||
error_reporting($ER);
|
||||
|
||||
// Return the resulting data
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a value based on an id. Optionally add tags.
|
||||
*
|
||||
* @param string $id id
|
||||
* @param mixed $data data
|
||||
* @param integer $lifetime lifetime [Optional]
|
||||
* @return boolean
|
||||
*/
|
||||
public function set($id, $data, $lifetime = NULL)
|
||||
{
|
||||
return (bool) $this->set_with_tags($id, $data, $lifetime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a cache entry based on id
|
||||
*
|
||||
* @param string $id id
|
||||
* @return boolean
|
||||
* @throws Cache_Exception
|
||||
*/
|
||||
public function delete($id)
|
||||
{
|
||||
// Prepare statement
|
||||
$statement = $this->_db->prepare('DELETE FROM caches WHERE id = :id');
|
||||
|
||||
// Remove the entry
|
||||
try
|
||||
{
|
||||
$statement->execute(array(':id' => $this->_sanitize_id($id)));
|
||||
}
|
||||
catch (PDOException $e)
|
||||
{
|
||||
throw new Cache_Exception('There was a problem querying the local SQLite3 cache. :error', array(':error' => $e->getMessage()));
|
||||
}
|
||||
|
||||
return (bool) $statement->rowCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all cache entries
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete_all()
|
||||
{
|
||||
// Prepare statement
|
||||
$statement = $this->_db->prepare('DELETE FROM caches');
|
||||
|
||||
// Remove the entry
|
||||
try
|
||||
{
|
||||
$statement->execute();
|
||||
}
|
||||
catch (PDOException $e)
|
||||
{
|
||||
throw new Cache_Exception('There was a problem querying the local SQLite3 cache. :error', array(':error' => $e->getMessage()));
|
||||
}
|
||||
|
||||
return (bool) $statement->rowCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a value based on an id. Optionally add tags.
|
||||
*
|
||||
* @param string $id id
|
||||
* @param mixed $data data
|
||||
* @param integer $lifetime lifetime [Optional]
|
||||
* @param array $tags tags [Optional]
|
||||
* @return boolean
|
||||
* @throws Cache_Exception
|
||||
*/
|
||||
public function set_with_tags($id, $data, $lifetime = NULL, array $tags = NULL)
|
||||
{
|
||||
// Serialize the data
|
||||
$data = serialize($data);
|
||||
|
||||
// Normalise tags
|
||||
$tags = (NULL === $tags) ? NULL : ('<'.implode('>,<', $tags).'>');
|
||||
|
||||
// Setup lifetime
|
||||
if ($lifetime === NULL)
|
||||
{
|
||||
$lifetime = (0 === Arr::get($this->_config, 'default_expire', NULL)) ? 0 : (Arr::get($this->_config, 'default_expire', Cache::DEFAULT_EXPIRE) + time());
|
||||
}
|
||||
else
|
||||
{
|
||||
$lifetime = (0 === $lifetime) ? 0 : ($lifetime + time());
|
||||
}
|
||||
|
||||
// Prepare statement
|
||||
// $this->exists() may throw Cache_Exception, no need to catch/rethrow
|
||||
$statement = $this->exists($id) ? $this->_db->prepare('UPDATE caches SET expiration = :expiration, cache = :cache, tags = :tags WHERE id = :id') : $this->_db->prepare('INSERT INTO caches (id, cache, expiration, tags) VALUES (:id, :cache, :expiration, :tags)');
|
||||
|
||||
// Try to insert
|
||||
try
|
||||
{
|
||||
$statement->execute(array(':id' => $this->_sanitize_id($id), ':cache' => $data, ':expiration' => $lifetime, ':tags' => $tags));
|
||||
}
|
||||
catch (PDOException $e)
|
||||
{
|
||||
throw new Cache_Exception('There was a problem querying the local SQLite3 cache. :error', array(':error' => $e->getMessage()));
|
||||
}
|
||||
|
||||
return (bool) $statement->rowCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete cache entries based on a tag
|
||||
*
|
||||
* @param string $tag tag
|
||||
* @return boolean
|
||||
* @throws Cache_Exception
|
||||
*/
|
||||
public function delete_tag($tag)
|
||||
{
|
||||
// Prepare the statement
|
||||
$statement = $this->_db->prepare('DELETE FROM caches WHERE tags LIKE :tag');
|
||||
|
||||
// Try to delete
|
||||
try
|
||||
{
|
||||
$statement->execute(array(':tag' => "%<{$tag}>%"));
|
||||
}
|
||||
catch (PDOException $e)
|
||||
{
|
||||
throw new Cache_Exception('There was a problem querying the local SQLite3 cache. :error', array(':error' => $e->getMessage()));
|
||||
}
|
||||
|
||||
return (bool) $statement->rowCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find cache entries based on a tag
|
||||
*
|
||||
* @param string $tag tag
|
||||
* @return array
|
||||
* @throws Cache_Exception
|
||||
*/
|
||||
public function find($tag)
|
||||
{
|
||||
// Prepare the statement
|
||||
$statement = $this->_db->prepare('SELECT id, cache FROM caches WHERE tags LIKE :tag');
|
||||
|
||||
// Try to find
|
||||
try
|
||||
{
|
||||
if ( ! $statement->execute(array(':tag' => "%<{$tag}>%")))
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
catch (PDOException $e)
|
||||
{
|
||||
throw new Cache_Exception('There was a problem querying the local SQLite3 cache. :error', array(':error' => $e->getMessage()));
|
||||
}
|
||||
|
||||
$result = array();
|
||||
|
||||
while ($row = $statement->fetchObject())
|
||||
{
|
||||
// Disable notices for unserializing
|
||||
$ER = error_reporting(~E_NOTICE);
|
||||
|
||||
$result[$row->id] = unserialize($row->cache);
|
||||
|
||||
// Turn notices back on
|
||||
error_reporting($ER);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Garbage collection method that cleans any expired
|
||||
* cache entries from the cache.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function garbage_collect()
|
||||
{
|
||||
// Create the sequel statement
|
||||
$statement = $this->_db->prepare('DELETE FROM caches WHERE expiration < :expiration');
|
||||
|
||||
try
|
||||
{
|
||||
$statement->execute(array(':expiration' => time()));
|
||||
}
|
||||
catch (PDOException $e)
|
||||
{
|
||||
throw new Cache_Exception('There was a problem querying the local SQLite3 cache. :error', array(':error' => $e->getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether an id exists or not
|
||||
*
|
||||
* @param string $id id
|
||||
* @return boolean
|
||||
* @throws Cache_Exception
|
||||
*/
|
||||
protected function exists($id)
|
||||
{
|
||||
$statement = $this->_db->prepare('SELECT id FROM caches WHERE id = :id');
|
||||
try
|
||||
{
|
||||
$statement->execute(array(':id' => $this->_sanitize_id($id)));
|
||||
}
|
||||
catch (PDOExeption $e)
|
||||
{
|
||||
throw new Cache_Exception('There was a problem querying the local SQLite3 cache. :error', array(':error' => $e->getMessage()));
|
||||
}
|
||||
|
||||
return (bool) $statement->fetchAll();
|
||||
}
|
||||
}
|
41
includes/kohana/modules/cache/classes/Kohana/Cache/Tagging.php
vendored
Normal file
41
includes/kohana/modules/cache/classes/Kohana/Cache/Tagging.php
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* Kohana Cache Tagging Interface
|
||||
*
|
||||
* @package Kohana/Cache
|
||||
* @category Base
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2009-2012 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
interface Kohana_Cache_Tagging {
|
||||
|
||||
/**
|
||||
* Set a value based on an id. Optionally add tags.
|
||||
*
|
||||
* Note : Some caching engines do not support
|
||||
* tagging
|
||||
*
|
||||
* @param string $id id
|
||||
* @param mixed $data data
|
||||
* @param integer $lifetime lifetime [Optional]
|
||||
* @param array $tags tags [Optional]
|
||||
* @return boolean
|
||||
*/
|
||||
public function set_with_tags($id, $data, $lifetime = NULL, array $tags = NULL);
|
||||
|
||||
/**
|
||||
* Delete cache entries based on a tag
|
||||
*
|
||||
* @param string $tag tag
|
||||
*/
|
||||
public function delete_tag($tag);
|
||||
|
||||
/**
|
||||
* Find cache entries based on a tag
|
||||
*
|
||||
* @param string $tag tag
|
||||
* @return array
|
||||
*/
|
||||
public function find($tag);
|
||||
}
|
140
includes/kohana/modules/cache/classes/Kohana/Cache/Wincache.php
vendored
Normal file
140
includes/kohana/modules/cache/classes/Kohana/Cache/Wincache.php
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* [Kohana Cache](api/Kohana_Cache) Wincache driver. Provides an opcode based
|
||||
* driver for the Kohana Cache library.
|
||||
*
|
||||
* ### Configuration example
|
||||
*
|
||||
* Below is an example of an _wincache_ server configuration.
|
||||
*
|
||||
* return array(
|
||||
* 'wincache' => array( // Driver group
|
||||
* 'driver' => 'wincache', // using wincache driver
|
||||
* ),
|
||||
* )
|
||||
*
|
||||
* In cases where only one cache group is required, if the group is named `default` there is
|
||||
* no need to pass the group name when instantiating a cache instance.
|
||||
*
|
||||
* #### General cache group configuration settings
|
||||
*
|
||||
* Below are the settings available to all types of cache driver.
|
||||
*
|
||||
* Name | Required | Description
|
||||
* -------------- | -------- | ---------------------------------------------------------------
|
||||
* driver | __YES__ | (_string_) The driver type to use
|
||||
*
|
||||
* ### System requirements
|
||||
*
|
||||
* * Windows XP SP3 with IIS 5.1 and » FastCGI Extension
|
||||
* * Windows Server 2003 with IIS 6.0 and » FastCGI Extension
|
||||
* * Windows Vista SP1 with IIS 7.0 and FastCGI Module
|
||||
* * Windows Server 2008 with IIS 7.0 and FastCGI Module
|
||||
* * Windows 7 with IIS 7.5 and FastCGI Module
|
||||
* * Windows Server 2008 R2 with IIS 7.5 and FastCGI Module
|
||||
* * PHP 5.2.X, Non-thread-safe build
|
||||
* * PHP 5.3 X86, Non-thread-safe VC9 build
|
||||
*
|
||||
* @package Kohana/Cache
|
||||
* @category Base
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2009-2012 Kohana Team
|
||||
* @license http://kohanaphp.com/license
|
||||
*/
|
||||
class Kohana_Cache_Wincache extends Cache {
|
||||
|
||||
/**
|
||||
* Check for existence of the wincache extension This method cannot be invoked externally. The driver must
|
||||
* be instantiated using the `Cache::instance()` method.
|
||||
*
|
||||
* @param array $config configuration
|
||||
* @throws Cache_Exception
|
||||
*/
|
||||
protected function __construct(array $config)
|
||||
{
|
||||
if ( ! extension_loaded('wincache'))
|
||||
{
|
||||
throw new Cache_Exception('PHP wincache extension is not available.');
|
||||
}
|
||||
|
||||
parent::__construct($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a cached value entry by id.
|
||||
*
|
||||
* // Retrieve cache entry from wincache group
|
||||
* $data = Cache::instance('wincache')->get('foo');
|
||||
*
|
||||
* // Retrieve cache entry from wincache group and return 'bar' if miss
|
||||
* $data = Cache::instance('wincache')->get('foo', 'bar');
|
||||
*
|
||||
* @param string $id id of cache to entry
|
||||
* @param string $default default value to return if cache miss
|
||||
* @return mixed
|
||||
* @throws Cache_Exception
|
||||
*/
|
||||
public function get($id, $default = NULL)
|
||||
{
|
||||
$data = wincache_ucache_get($this->_sanitize_id($id), $success);
|
||||
|
||||
return $success ? $data : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a value to cache with id and lifetime
|
||||
*
|
||||
* $data = 'bar';
|
||||
*
|
||||
* // Set 'bar' to 'foo' in wincache group, using default expiry
|
||||
* Cache::instance('wincache')->set('foo', $data);
|
||||
*
|
||||
* // Set 'bar' to 'foo' in wincache group for 30 seconds
|
||||
* Cache::instance('wincache')->set('foo', $data, 30);
|
||||
*
|
||||
* @param string $id id of cache entry
|
||||
* @param string $data data to set to cache
|
||||
* @param integer $lifetime lifetime in seconds
|
||||
* @return boolean
|
||||
*/
|
||||
public function set($id, $data, $lifetime = NULL)
|
||||
{
|
||||
if ($lifetime === NULL)
|
||||
{
|
||||
$lifetime = Arr::get($this->_config, 'default_expire', Cache::DEFAULT_EXPIRE);
|
||||
}
|
||||
|
||||
return wincache_ucache_set($this->_sanitize_id($id), $data, $lifetime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a cache entry based on id
|
||||
*
|
||||
* // Delete 'foo' entry from the wincache group
|
||||
* Cache::instance('wincache')->delete('foo');
|
||||
*
|
||||
* @param string $id id to remove from cache
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete($id)
|
||||
{
|
||||
return wincache_ucache_delete($this->_sanitize_id($id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all cache entries.
|
||||
*
|
||||
* Beware of using this method when
|
||||
* using shared memory cache systems, as it will wipe every
|
||||
* entry within the system for all clients.
|
||||
*
|
||||
* // Delete all cache entries in the wincache group
|
||||
* Cache::instance('wincache')->delete_all();
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete_all()
|
||||
{
|
||||
return wincache_ucache_clear();
|
||||
}
|
||||
}
|
503
includes/kohana/modules/cache/classes/Kohana/HTTP/Cache.php
vendored
Normal file
503
includes/kohana/modules/cache/classes/Kohana/HTTP/Cache.php
vendored
Normal file
@@ -0,0 +1,503 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* HTTT Caching adaptor class that provides caching services to the
|
||||
* [Request_Client] class, using HTTP cache control logic as defined in
|
||||
* RFC 2616.
|
||||
*
|
||||
* @package Kohana
|
||||
* @category Base
|
||||
* @author Kohana Team
|
||||
* @copyright (c) 2008-2012 Kohana Team
|
||||
* @license http://kohanaframework.org/license
|
||||
* @since 3.2.0
|
||||
*/
|
||||
class Kohana_HTTP_Cache {
|
||||
|
||||
const CACHE_STATUS_KEY = 'x-cache-status';
|
||||
const CACHE_STATUS_SAVED = 'SAVED';
|
||||
const CACHE_STATUS_HIT = 'HIT';
|
||||
const CACHE_STATUS_MISS = 'MISS';
|
||||
const CACHE_HIT_KEY = 'x-cache-hits';
|
||||
|
||||
/**
|
||||
* Factory method for HTTP_Cache that provides a convenient dependency
|
||||
* injector for the Cache library.
|
||||
*
|
||||
* // Create HTTP_Cache with named cache engine
|
||||
* $http_cache = HTTP_Cache::factory('memcache', array(
|
||||
* 'allow_private_cache' => FALSE
|
||||
* )
|
||||
* );
|
||||
*
|
||||
* // Create HTTP_Cache with supplied cache engine
|
||||
* $http_cache = HTTP_Cache::factory(Cache::instance('memcache'),
|
||||
* array(
|
||||
* 'allow_private_cache' => FALSE
|
||||
* )
|
||||
* );
|
||||
*
|
||||
* @uses [Cache]
|
||||
* @param mixed $cache cache engine to use
|
||||
* @param array $options options to set to this class
|
||||
* @return HTTP_Cache
|
||||
*/
|
||||
public static function factory($cache, array $options = array())
|
||||
{
|
||||
if ( ! $cache instanceof Cache)
|
||||
{
|
||||
$cache = Cache::instance($cache);
|
||||
}
|
||||
|
||||
$options['cache'] = $cache;
|
||||
|
||||
return new HTTP_Cache($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic cache key generator that hashes the entire request and returns
|
||||
* it. This is fine for static content, or dynamic content where user
|
||||
* specific information is encoded into the request.
|
||||
*
|
||||
* // Generate cache key
|
||||
* $cache_key = HTTP_Cache::basic_cache_key_generator($request);
|
||||
*
|
||||
* @param Request $request
|
||||
* @return string
|
||||
*/
|
||||
public static function basic_cache_key_generator(Request $request)
|
||||
{
|
||||
$uri = $request->uri();
|
||||
$query = $request->query();
|
||||
$headers = $request->headers()->getArrayCopy();
|
||||
$body = $request->body();
|
||||
|
||||
return sha1($uri.'?'.http_build_query($query, NULL, '&').'~'.implode('~', $headers).'~'.$body);
|
||||
}
|
||||
|
||||
/**
|
||||
* @var Cache cache driver to use for HTTP caching
|
||||
*/
|
||||
protected $_cache;
|
||||
|
||||
/**
|
||||
* @var callback Cache key generator callback
|
||||
*/
|
||||
protected $_cache_key_callback;
|
||||
|
||||
/**
|
||||
* @var boolean Defines whether this client should cache `private` cache directives
|
||||
* @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
|
||||
*/
|
||||
protected $_allow_private_cache = FALSE;
|
||||
|
||||
/**
|
||||
* @var int The timestamp of the request
|
||||
*/
|
||||
protected $_request_time;
|
||||
|
||||
/**
|
||||
* @var int The timestamp of the response
|
||||
*/
|
||||
protected $_response_time;
|
||||
|
||||
/**
|
||||
* Constructor method for this class. Allows dependency injection of the
|
||||
* required components such as `Cache` and the cache key generator.
|
||||
*
|
||||
* @param array $options
|
||||
*/
|
||||
public function __construct(array $options = array())
|
||||
{
|
||||
foreach ($options as $key => $value)
|
||||
{
|
||||
if (method_exists($this, $key))
|
||||
{
|
||||
$this->$key($value);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->_cache_key_callback === NULL)
|
||||
{
|
||||
$this->cache_key_callback('HTTP_Cache::basic_cache_key_generator');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the supplied [Request] with the supplied [Request_Client].
|
||||
* Before execution, the HTTP_Cache adapter checks the request type,
|
||||
* destructive requests such as `POST`, `PUT` and `DELETE` will bypass
|
||||
* cache completely and ensure the response is not cached. All other
|
||||
* Request methods will allow caching, if the rules are met.
|
||||
*
|
||||
* @param Request_Client $client client to execute with Cache-Control
|
||||
* @param Request $request request to execute with client
|
||||
* @return [Response]
|
||||
*/
|
||||
public function execute(Request_Client $client, Request $request, Response $response)
|
||||
{
|
||||
if ( ! $this->_cache instanceof Cache)
|
||||
return $client->execute_request($request, $response);
|
||||
|
||||
// If this is a destructive request, by-pass cache completely
|
||||
if (in_array($request->method(), array(
|
||||
HTTP_Request::POST,
|
||||
HTTP_Request::PUT,
|
||||
HTTP_Request::DELETE)))
|
||||
{
|
||||
// Kill existing caches for this request
|
||||
$this->invalidate_cache($request);
|
||||
|
||||
$response = $client->execute_request($request, $response);
|
||||
|
||||
$cache_control = HTTP_Header::create_cache_control(array(
|
||||
'no-cache',
|
||||
'must-revalidate'
|
||||
));
|
||||
|
||||
// Ensure client respects destructive action
|
||||
return $response->headers('cache-control', $cache_control);
|
||||
}
|
||||
|
||||
// Create the cache key
|
||||
$cache_key = $this->create_cache_key($request, $this->_cache_key_callback);
|
||||
|
||||
// Try and return cached version
|
||||
if (($cached_response = $this->cache_response($cache_key, $request)) instanceof Response)
|
||||
return $cached_response;
|
||||
|
||||
// Start request time
|
||||
$this->_request_time = time();
|
||||
|
||||
// Execute the request with the Request client
|
||||
$response = $client->execute_request($request, $response);
|
||||
|
||||
// Stop response time
|
||||
$this->_response_time = (time() - $this->_request_time);
|
||||
|
||||
// Cache the response
|
||||
$this->cache_response($cache_key, $request, $response);
|
||||
|
||||
$response->headers(HTTP_Cache::CACHE_STATUS_KEY,
|
||||
HTTP_Cache::CACHE_STATUS_MISS);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate a cached response for the [Request] supplied.
|
||||
* This has the effect of deleting the response from the
|
||||
* [Cache] entry.
|
||||
*
|
||||
* @param Request $request Response to remove from cache
|
||||
* @return void
|
||||
*/
|
||||
public function invalidate_cache(Request $request)
|
||||
{
|
||||
if (($cache = $this->cache()) instanceof Cache)
|
||||
{
|
||||
$cache->delete($this->create_cache_key($request, $this->_cache_key_callback));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter and setter for the internal caching engine,
|
||||
* used to cache responses if available and valid.
|
||||
*
|
||||
* @param Kohana_Cache $cache engine to use for caching
|
||||
* @return Kohana_Cache
|
||||
* @return Kohana_Request_Client
|
||||
*/
|
||||
public function cache(Cache $cache = NULL)
|
||||
{
|
||||
if ($cache === NULL)
|
||||
return $this->_cache;
|
||||
|
||||
$this->_cache = $cache;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or sets the [Request_Client::allow_private_cache] setting.
|
||||
* If set to `TRUE`, the client will also cache cache-control directives
|
||||
* that have the `private` setting.
|
||||
*
|
||||
* @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
|
||||
* @param boolean $setting allow caching of privately marked responses
|
||||
* @return boolean
|
||||
* @return [Request_Client]
|
||||
*/
|
||||
public function allow_private_cache($setting = NULL)
|
||||
{
|
||||
if ($setting === NULL)
|
||||
return $this->_allow_private_cache;
|
||||
|
||||
$this->_allow_private_cache = (bool) $setting;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets or gets the cache key generator callback for this caching
|
||||
* class. The cache key generator provides a unique hash based on the
|
||||
* `Request` object passed to it.
|
||||
*
|
||||
* The default generator is [HTTP_Cache::basic_cache_key_generator()], which
|
||||
* serializes the entire `HTTP_Request` into a unique sha1 hash. This will
|
||||
* provide basic caching for static and simple dynamic pages. More complex
|
||||
* algorithms can be defined and then passed into `HTTP_Cache` using this
|
||||
* method.
|
||||
*
|
||||
* // Get the cache key callback
|
||||
* $callback = $http_cache->cache_key_callback();
|
||||
*
|
||||
* // Set the cache key callback
|
||||
* $http_cache->cache_key_callback('Foo::cache_key');
|
||||
*
|
||||
* // Alternatively, in PHP 5.3 use a closure
|
||||
* $http_cache->cache_key_callback(function (Request $request) {
|
||||
* return sha1($request->render());
|
||||
* });
|
||||
*
|
||||
* @param callback $callback
|
||||
* @return mixed
|
||||
* @throws HTTP_Exception
|
||||
*/
|
||||
public function cache_key_callback($callback = NULL)
|
||||
{
|
||||
if ($callback === NULL)
|
||||
return $this->_cache_key_callback;
|
||||
|
||||
if ( ! is_callable($callback))
|
||||
throw new Kohana_Exception('cache_key_callback must be callable!');
|
||||
|
||||
$this->_cache_key_callback = $callback;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a cache key for the request to use for caching
|
||||
* [Kohana_Response] returned by [Request::execute].
|
||||
*
|
||||
* This is the default cache key generating logic, but can be overridden
|
||||
* by setting [HTTP_Cache::cache_key_callback()].
|
||||
*
|
||||
* @param Request $request request to create key for
|
||||
* @param callback $callback optional callback to use instead of built-in method
|
||||
* @return string
|
||||
*/
|
||||
public function create_cache_key(Request $request, $callback = FALSE)
|
||||
{
|
||||
if (is_callable($callback))
|
||||
return call_user_func($callback, $request);
|
||||
else
|
||||
return HTTP_Cache::basic_cache_key_generator($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Controls whether the response can be cached. Uses HTTP
|
||||
* protocol to determine whether the response can be cached.
|
||||
*
|
||||
* @link RFC 2616 http://www.w3.org/Protocols/rfc2616/
|
||||
* @param Response $response The Response
|
||||
* @return boolean
|
||||
*/
|
||||
public function set_cache(Response $response)
|
||||
{
|
||||
$headers = $response->headers()->getArrayCopy();
|
||||
|
||||
if ($cache_control = Arr::get($headers, 'cache-control'))
|
||||
{
|
||||
// Parse the cache control
|
||||
$cache_control = HTTP_Header::parse_cache_control($cache_control);
|
||||
|
||||
// If the no-cache or no-store directive is set, return
|
||||
if (array_intersect($cache_control, array('no-cache', 'no-store')))
|
||||
return FALSE;
|
||||
|
||||
// Check for private cache and get out of here if invalid
|
||||
if ( ! $this->_allow_private_cache AND in_array('private', $cache_control))
|
||||
{
|
||||
if ( ! isset($cache_control['s-maxage']))
|
||||
return FALSE;
|
||||
|
||||
// If there is a s-maxage directive we can use that
|
||||
$cache_control['max-age'] = $cache_control['s-maxage'];
|
||||
}
|
||||
|
||||
// Check that max-age has been set and if it is valid for caching
|
||||
if (isset($cache_control['max-age']) AND $cache_control['max-age'] < 1)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ($expires = Arr::get($headers, 'expires') AND ! isset($cache_control['max-age']))
|
||||
{
|
||||
// Can't cache things that have expired already
|
||||
if (strtotime($expires) <= time())
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches a [Response] using the supplied [Cache]
|
||||
* and the key generated by [Request_Client::_create_cache_key].
|
||||
*
|
||||
* If not response is supplied, the cache will be checked for an existing
|
||||
* one that is available.
|
||||
*
|
||||
* @param string $key the cache key to use
|
||||
* @param Request $request the HTTP Request
|
||||
* @param Response $response the HTTP Response
|
||||
* @return mixed
|
||||
*/
|
||||
public function cache_response($key, Request $request, Response $response = NULL)
|
||||
{
|
||||
if ( ! $this->_cache instanceof Cache)
|
||||
return FALSE;
|
||||
|
||||
// Check for Pragma: no-cache
|
||||
if ($pragma = $request->headers('pragma'))
|
||||
{
|
||||
if ($pragma == 'no-cache')
|
||||
return FALSE;
|
||||
elseif (is_array($pragma) AND in_array('no-cache', $pragma))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// If there is no response, lookup an existing cached response
|
||||
if ($response === NULL)
|
||||
{
|
||||
$response = $this->_cache->get($key);
|
||||
|
||||
if ( ! $response instanceof Response)
|
||||
return FALSE;
|
||||
|
||||
// Do cache hit arithmetic, using fast arithmetic if available
|
||||
if ($this->_cache instanceof Cache_Arithmetic)
|
||||
{
|
||||
$hit_count = $this->_cache->increment(HTTP_Cache::CACHE_HIT_KEY.$key);
|
||||
}
|
||||
else
|
||||
{
|
||||
$hit_count = $this->_cache->get(HTTP_Cache::CACHE_HIT_KEY.$key);
|
||||
$this->_cache->set(HTTP_Cache::CACHE_HIT_KEY.$key, ++$hit_count);
|
||||
}
|
||||
|
||||
// Update the header to have correct HIT status and count
|
||||
$response->headers(HTTP_Cache::CACHE_STATUS_KEY,
|
||||
HTTP_Cache::CACHE_STATUS_HIT)
|
||||
->headers(HTTP_Cache::CACHE_HIT_KEY, $hit_count);
|
||||
|
||||
return $response;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (($ttl = $this->cache_lifetime($response)) === FALSE)
|
||||
return FALSE;
|
||||
|
||||
$response->headers(HTTP_Cache::CACHE_STATUS_KEY,
|
||||
HTTP_Cache::CACHE_STATUS_SAVED);
|
||||
|
||||
// Set the hit count to zero
|
||||
$this->_cache->set(HTTP_Cache::CACHE_HIT_KEY.$key, 0);
|
||||
|
||||
return $this->_cache->set($key, $response, $ttl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the total Time To Live based on the specification
|
||||
* RFC 2616 cache lifetime rules.
|
||||
*
|
||||
* @param Response $response Response to evaluate
|
||||
* @return mixed TTL value or false if the response should not be cached
|
||||
*/
|
||||
public function cache_lifetime(Response $response)
|
||||
{
|
||||
// Get out of here if this cannot be cached
|
||||
if ( ! $this->set_cache($response))
|
||||
return FALSE;
|
||||
|
||||
// Calculate apparent age
|
||||
if ($date = $response->headers('date'))
|
||||
{
|
||||
$apparent_age = max(0, $this->_response_time - strtotime($date));
|
||||
}
|
||||
else
|
||||
{
|
||||
$apparent_age = max(0, $this->_response_time);
|
||||
}
|
||||
|
||||
// Calculate corrected received age
|
||||
if ($age = $response->headers('age'))
|
||||
{
|
||||
$corrected_received_age = max($apparent_age, intval($age));
|
||||
}
|
||||
else
|
||||
{
|
||||
$corrected_received_age = $apparent_age;
|
||||
}
|
||||
|
||||
// Corrected initial age
|
||||
$corrected_initial_age = $corrected_received_age + $this->request_execution_time();
|
||||
|
||||
// Resident time
|
||||
$resident_time = time() - $this->_response_time;
|
||||
|
||||
// Current age
|
||||
$current_age = $corrected_initial_age + $resident_time;
|
||||
|
||||
// Prepare the cache freshness lifetime
|
||||
$ttl = NULL;
|
||||
|
||||
// Cache control overrides
|
||||
if ($cache_control = $response->headers('cache-control'))
|
||||
{
|
||||
// Parse the cache control header
|
||||
$cache_control = HTTP_Header::parse_cache_control($cache_control);
|
||||
|
||||
if (isset($cache_control['max-age']))
|
||||
{
|
||||
$ttl = $cache_control['max-age'];
|
||||
}
|
||||
|
||||
if (isset($cache_control['s-maxage']) AND isset($cache_control['private']) AND $this->_allow_private_cache)
|
||||
{
|
||||
$ttl = $cache_control['s-maxage'];
|
||||
}
|
||||
|
||||
if (isset($cache_control['max-stale']) AND ! isset($cache_control['must-revalidate']))
|
||||
{
|
||||
$ttl = $current_age + $cache_control['max-stale'];
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a TTL at this point, return
|
||||
if ($ttl !== NULL)
|
||||
return $ttl;
|
||||
|
||||
if ($expires = $response->headers('expires'))
|
||||
return strtotime($expires) - $current_age;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the duration of the last request execution.
|
||||
* Either returns the time of completed requests or
|
||||
* `FALSE` if the request hasn't finished executing, or
|
||||
* is yet to be run.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function request_execution_time()
|
||||
{
|
||||
if ($this->_request_time === NULL OR $this->_response_time === NULL)
|
||||
return FALSE;
|
||||
|
||||
return $this->_response_time - $this->_request_time;
|
||||
}
|
||||
|
||||
} // End Kohana_HTTP_Cache
|
Reference in New Issue
Block a user