From bde25d971bfbf4a54f1d40eedfd3290ebb5f91e5 Mon Sep 17 00:00:00 2001 From: Greg Aker Date: Tue, 21 Dec 2010 09:31:21 -0600 Subject: Initial commit of Caching Driver. --- system/libraries/Cache/Cache.php | 216 +++++++++++++++++++++ system/libraries/Cache/drivers/Cache_apc.php | 151 ++++++++++++++ system/libraries/Cache/drivers/Cache_dummy.php | 129 ++++++++++++ system/libraries/Cache/drivers/Cache_file.php | 196 +++++++++++++++++++ system/libraries/Cache/drivers/Cache_memcached.php | 209 ++++++++++++++++++++ user_guide/libraries/caching.html | 193 ++++++++++++++++++ 6 files changed, 1094 insertions(+) create mode 100644 system/libraries/Cache/Cache.php create mode 100644 system/libraries/Cache/drivers/Cache_apc.php create mode 100644 system/libraries/Cache/drivers/Cache_dummy.php create mode 100644 system/libraries/Cache/drivers/Cache_file.php create mode 100644 system/libraries/Cache/drivers/Cache_memcached.php create mode 100644 user_guide/libraries/caching.html diff --git a/system/libraries/Cache/Cache.php b/system/libraries/Cache/Cache.php new file mode 100644 index 000000000..ea3194237 --- /dev/null +++ b/system/libraries/Cache/Cache.php @@ -0,0 +1,216 @@ +_initialize($config); + } + } + + // ------------------------------------------------------------------------ + + /** + * Get + * + * Look for a value in the cache. If it exists, return the data + * if not, return FALSE + * + * @param string + * @return mixed value that is stored/FALSE on failure + */ + public function get($id) + { + return $this->{$this->_adapter}->get($id); + } + + // ------------------------------------------------------------------------ + + /** + * Cache Save + * + * @param string Unique Key + * @param mixed Data to store + * @param int Length of time (in seconds) to cache the data + * + * @return boolean true on success/false on failure + */ + public function save($id, $data, $ttl = 60) + { + return $this->{$this->_adapter}->save($id, $data, $ttl); + } + + // ------------------------------------------------------------------------ + + /** + * Delete from Cache + * + * @param mixed unique identifier of the item in the cache + * @return boolean true on success/false on failure + */ + public function delete($id) + { + return $this->{$this->_adapter}->delete($id); + } + + // ------------------------------------------------------------------------ + + /** + * Clean the cache + * + * @return boolean false on failure/true on success + */ + public function clean() + { + return $this->{$this->_adapter}->clean(); + } + + // ------------------------------------------------------------------------ + + /** + * Cache Info + * + * @param string user/filehits + * @return mixed array on success, false on failure + */ + public function cache_info($type = 'user') + { + return $this->{$this->_adapter}->cache_info($type); + } + + // ------------------------------------------------------------------------ + + /** + * Get Cache Metadata + * + * @param mixed key to get cache metadata on + * @return mixed return value from child method + */ + public function get_metadata($id) + { + return $this->{$this->_adapter}->get_metadata($id); + } + + // ------------------------------------------------------------------------ + + /** + * Initialize + * + * Initialize class properties based on the configuration array. + * + * @param array + * @return void + */ + private function _initialize($config) + { + $default_config = array( + 'adapter', + 'memcached' + ); + + foreach ($default_config as $key) + { + if (isset($config[$key])) + { + $param = '_'.$key; + + $this->{$param} = $config[$key]; + } + } + + if (isset($config['backup'])) + { + if (in_array('cache_'.$config['backup'], $this->valid_drivers)) + { + $this->_backup_driver = $config['backup']; + } + } + } + + // ------------------------------------------------------------------------ + + /** + * Is the requested driver supported in this environment? + * + * @param string The driver to test. + * @return array + */ + public function is_supported($driver) + { + static $support = array(); + + if ( ! isset($support[$driver])) + { + $support[$driver] = $this->{$driver}->is_supported(); + } + + return $support[$driver]; + } + + // ------------------------------------------------------------------------ + + /** + * __get() + * + * @param child + * @return object + */ + public function __get($child) + { + $obj = parent::__get($child); + + if ( ! $this->is_supported($child)) + { + $this->_adapter = $this->_backup_driver; + } + + return $obj; + } + + // ------------------------------------------------------------------------ +} +// End Class + +/* End of file Cache.php */ +/* Location: ./system/libraries/Cache/Cache.php */ \ No newline at end of file diff --git a/system/libraries/Cache/drivers/Cache_apc.php b/system/libraries/Cache/drivers/Cache_apc.php new file mode 100644 index 000000000..9c716a971 --- /dev/null +++ b/system/libraries/Cache/drivers/Cache_apc.php @@ -0,0 +1,151 @@ + $time + $ttl, + 'mtime' => $time, + 'data' => $data + ); + } + + // ------------------------------------------------------------------------ + + /** + * is_supported() + * + * Check to see if APC is available on this system, bail if it isn't. + */ + public function is_supported() + { + if ( ! extension_loaded('apc') OR ! function_exists('apc_store')) + { + log_message('error', 'The APC PHP extension must be loaded to use APC Cache.'); + return FALSE; + } + + return TRUE; + } + + // ------------------------------------------------------------------------ + + +} +// End Class + +/* End of file Cache_apc.php */ +/* Location: ./system/libraries/Cache/drivers/Cache_apc.php */ \ No newline at end of file diff --git a/system/libraries/Cache/drivers/Cache_dummy.php b/system/libraries/Cache/drivers/Cache_dummy.php new file mode 100644 index 000000000..13c1f5cde --- /dev/null +++ b/system/libraries/Cache/drivers/Cache_dummy.php @@ -0,0 +1,129 @@ +load->helper('file'); + + $path = $CI->config->item('cache_path'); + + $this->_cache_path = ($path == '') ? BASEPATH.'cache/' : $path; + } + + // ------------------------------------------------------------------------ + + /** + * Fetch from cache + * + * @param mixed unique key id + * @return mixed data on success/false on failure + */ + public function get($id) + { + if ( ! file_exists($this->_cache_path.$id)) + { + return FALSE; + } + + $data = read_file($this->_cache_path.$id); + $data = unserialize($data); + + if (time() > $data['time'] + $data['ttl']) + { + unlink($this->_cache_path.$id); + return FALSE; + } + + return $data['data']; + } + + // ------------------------------------------------------------------------ + + /** + * Save into cache + * + * @param string unique key + * @param mixed data to store + * @param int length of time (in seconds) the cache is valid + * - Default is 60 seconds + * @return boolean true on success/false on failure + */ + public function save($id, $data, $ttl = 60) + { + $contents = array( + 'time' => time(), + 'ttl' => $ttl, + 'data' => $data + ); + + if (write_file($this->_cache_path.$id, serialize($contents))) + { + @chmod($this->_cache_path.$id, 0777); + return TRUE; + } + + return FALSE; + } + + // ------------------------------------------------------------------------ + + /** + * Delete from Cache + * + * @param mixed unique identifier of item in cache + * @return boolean true on success/false on failure + */ + public function delete($id) + { + return unlink($this->_cache_path.$id); + } + + // ------------------------------------------------------------------------ + + /** + * Clean the Cache + * + * @return boolean false on failure/true on success + */ + public function clean() + { + return delete_files($this->_cache_path); + } + + // ------------------------------------------------------------------------ + + /** + * Cache Info + * + * Not supported by file-based caching + * + * @param string user/filehits + * @return mixed FALSE + */ + public function cache_info($type = NULL) + { + return get_dir_file_info($this->_cache_path); + } + + // ------------------------------------------------------------------------ + + /** + * Get Cache Metadata + * + * @param mixed key to get cache metadata on + * @return mixed FALSE on failure, array on success. + */ + public function get_metadata($id) + { + if ( ! file_exists($this->_cache_path.$id)) + { + return FALSE; + } + + $data = read_file($this->_cache_path.$id); + $data = unserialize($data); + + if (is_array($data)) + { + $data = $data['data']; + $mtime = filemtime($this->_cache_path.$id); + + if ( ! isset($data['ttl'])) + { + return FALSE; + } + + return array( + 'expire' => $mtime + $data['ttl'], + 'mtime' => $mtime + ); + } + + return FALSE; + } + + // ------------------------------------------------------------------------ + + /** + * Is supported + * + * In the file driver, check to see that the cache directory is indeed writable + * + * @return boolean + */ + public function is_supported() + { + return is_really_writable($this->_cache_path); + } + + // ------------------------------------------------------------------------ +} +// End Class + +/* End of file Cache_file.php */ +/* Location: ./system/libraries/Cache/drivers/Cache_file.php */ \ No newline at end of file diff --git a/system/libraries/Cache/drivers/Cache_memcached.php b/system/libraries/Cache/drivers/Cache_memcached.php new file mode 100644 index 000000000..adc7fbf44 --- /dev/null +++ b/system/libraries/Cache/drivers/Cache_memcached.php @@ -0,0 +1,209 @@ + array( + 'default_host' => '127.0.0.1', + 'default_port' => 11211, + 'default_weight' => 1 + ) + ); + + // ------------------------------------------------------------------------ + + /** + * Fetch from cache + * + * @param mixed unique key id + * @return mixed data on success/false on failure + */ + public function get($id) + { + $data = $this->_memcached->get($id); + + return (is_array($data)) ? $data[0] : FALSE; + } + + // ------------------------------------------------------------------------ + + /** + * Save + * + * @param string unique identifier + * @param mixed data being cached + * @param int time to live + * @return boolean true on success, false on failure + */ + public function save($id, $data, $ttl = 60) + { + return $this->_memcached->add($id, array($data, time(), $ttl), $ttl); + } + + // ------------------------------------------------------------------------ + + /** + * Delete from Cache + * + * @param mixed key to be deleted. + * @return boolean true on success, false on failure + */ + public function delete($id) + { + return $this->_memcached->delete($id); + } + + // ------------------------------------------------------------------------ + + /** + * Clean the Cache + * + * @return boolean false on failure/true on success + */ + public function clean() + { + return $this->_memcached->flush(); + } + + // ------------------------------------------------------------------------ + + /** + * Cache Info + * + * @param null type not supported in memcached + * @return mixed array on success, false on failure + */ + public function cache_info($type = NULL) + { + return $this->_memcached->getStats(); + } + + // ------------------------------------------------------------------------ + + /** + * Get Cache Metadata + * + * @param mixed key to get cache metadata on + * @return mixed FALSE on failure, array on success. + */ + public function get_metadata($id) + { + $stored = $this->_memcached->get($id); + + if (count($stored) !== 3) + { + return FALSE; + } + + list($value, $time, $ttl) = $stored; + + return array( + 'expire' => $time + $ttl, + 'mtime' => $time, + 'data' => $data + ); + } + + // ------------------------------------------------------------------------ + + /** + * Setup memcached. + */ + private function _setup_memcached() + { + // Try to load memcached server info from the config file. + $CI =& get_instance(); + if ($CI->config->load('memcached', TRUE, TRUE)) + { + if (is_array($CI->config->config['memcached'])) + { + $this->_memcache_conf = NULL; + + foreach ($CI->config->config['memcached'] as $name => $conf) + { + $this->_memcache_conf[$name] = $conf; + } + } + } + + $this->_memcached = new Memcached(); + + foreach ($this->_memcache_conf as $name => $cache_server) + { + if ( ! array_key_exists('hostname', $cache_server)) + { + $cache_server['hostname'] = $this->_default_options['default_host']; + } + + if ( ! array_key_exists('port', $cache_server)) + { + $cache_server['port'] = $this->_default_options['default_port']; + } + + if ( ! array_key_exists('weight', $cache_server)) + { + $cache_server['weight'] = $this->_default_options['default_weight']; + } + + $this->_memcached->addServer( + $cache_server['hostname'], $cache_server['port'], $cache_server['weight'] + ); + } + } + + // ------------------------------------------------------------------------ + + + /** + * Is supported + * + * Returns FALSE if memcached is not supported on the system. + * If it is, we setup the memcached object & return TRUE + */ + public function is_supported() + { + if ( ! extension_loaded('memcached')) + { + log_message('error', 'The Memcached Extension must be loaded to use Memcached Cache.'); + + return FALSE; + } + + $this->_setup_memcached(); + return TRUE; + } + + // ------------------------------------------------------------------------ + +} +// End Class + +/* End of file Cache_memcached.php */ +/* Location: ./system/libraries/Cache/drivers/Cache_memcached.php */ \ No newline at end of file diff --git a/user_guide/libraries/caching.html b/user_guide/libraries/caching.html new file mode 100644 index 000000000..e4651dc4a --- /dev/null +++ b/user_guide/libraries/caching.html @@ -0,0 +1,193 @@ + + + + + +Caching Driver : CodeIgniter User Guide + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +

CodeIgniter User Guide Version 2.0.0

+
+ + + + + + + + + +
+ + +
+ + + +
+ +

Caching Driver

+ +

CodeIgniter features wrappers around some of the most popular forms of fast and dynamic caching. All but file-based caching require specific server requirements, and a Fatal Exception will be thrown if server requirements are not met.

+ +

Table of Contents

+ + +

Available Drivers

+ + +

Example Usage

+ +

The following example will load the cache driver, specify APC as the driver to use, and fall back to file-based caching if APC is not available in the hosting environment.

+ + +$this->load->driver('cache', array('adapter' => 'apc', 'backup' => 'file'));
+
+if ( ! $foo = $this->cache->get('foo'))
+{
+     echo 'Saving to the cache!<br />';
+     $foo = 'foobarbaz!';
+
+     // Save into the cache for 5 minutes
+     $this->cache->save('foo', $foo, 300);
+}
+
+echo $foo; +
+ +

Function Reference

+ +

is_supported(driver['string'])

+ +

This function is automatically called when accessing drivers via $this->cache->get(). However, if the individual drivers are used, make sure to call this function to ensure the driver is supported in the hosting environment.

+ + +if ($this->cache->apc->is_supported())
+{
+     if ($data = $this->cache->apc->get('my_cache'))
+     {
+          // do things.
+     }
+} +
+ +

get(id['string'])

+ +

This function will attempt to fetch an item from the cache store. If the item does not exist, the function will return FALSE.

+$foo = $this->cache->get('my_cached_item'); + +

save(id['string'], data['mixed'], ttl['int'])

+ +

This function will save an item to the cache store. If saving fails, the function will return FALSE.

+

The optional third parameter (Time To Live) defaults to 60 seconds.

+$this->cache->save('cache_item_id', 'data_to_cache'); + +

delete(id['string'])

+ +

This function will delete a specific item from the cache store. If item deletion fails, the function will return FALSE.

+$this->cache->delete('cache_item_id'); + +

clean()

+ +

This function will 'clean' the entire cache. If the deletion of the cache files fails, the function will return FALSE.

+ +$this->cache->clean(); + +

cache_info()

+ +

This function will return information on the entire cache.

+ +var_dump($this->cache->cache_info()); + +

get_metadata(id['string'])

+ +

This function will return detailed information on a specific item in the cache.

+ +var_dump($this->cache->get_metadata('my_cached_item')); + +

Drivers

+ +

Alternative PHP Cache (APC) Caching

+ +

All of the functions listed above can be accessed without passing a specific adapter to the driver loader as follows:

+$this->load->driver('cache');
+ $this->cache->apc->save('foo', 'bar', 10);
+

For more information on APC, please see http://php.net/apc

+ +

File-based Caching

+ +

Unlike caching from the Output Class, the driver file-based caching allows for pieces of view files to be cached. Use this with care, and make sure to benchmark your application, as a point can come where disk I/O will negate positive gains by caching.

+ +

All of the functions listed above can be accessed without passing a specific adapter to the driver loader as follows:

+$this->load->driver('cache');
+ $this->cache->file->save('foo', 'bar', 10);
+ +

Memcached Caching

+ +

Multiple Memcached servers can be specified in the memcached.php configuration file, located in the application/config/ directory. + +

All of the functions listed above can be accessed without passing a specific adapter to the driver loader as follows:

+$this->load->driver('cache');
+ $this->cache->memcached->save('foo', 'bar', 10);
+ +

For more information on Memcached, please see http://php.net/memcached

+ +

Dummy Cache

+ +

This is a caching backend that will always 'miss.' It stores no data, but lets you keep your caching code in place in environments that don't support your chosen cache.

+ +
+ + + + + + + \ No newline at end of file -- cgit v1.2.3-24-g4f1b