summaryrefslogtreecommitdiff
path: root/system/libraries/drivers/Cache
diff options
context:
space:
mode:
Diffstat (limited to 'system/libraries/drivers/Cache')
-rw-r--r--system/libraries/drivers/Cache/File.php255
-rw-r--r--system/libraries/drivers/Cache/Memcache.php132
-rw-r--r--system/libraries/drivers/Cache/Xcache.php161
3 files changed, 548 insertions, 0 deletions
diff --git a/system/libraries/drivers/Cache/File.php b/system/libraries/drivers/Cache/File.php
new file mode 100644
index 0000000..d6ec037
--- /dev/null
+++ b/system/libraries/drivers/Cache/File.php
@@ -0,0 +1,255 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * Memcache-based Cache driver.
+ *
+ * $Id: File.php 4605 2009-09-14 17:22:21Z kiall $
+ *
+ * @package Cache
+ * @author Kohana Team
+ * @copyright (c) 2007-2009 Kohana Team
+ * @license http://kohanaphp.com/license
+ */
+class Cache_File_Driver extends Cache_Driver {
+ protected $config;
+ protected $backend;
+
+ public function __construct($config)
+ {
+ $this->config = $config;
+ $this->config['directory'] = str_replace('\\', '/', realpath($this->config['directory'])).'/';
+
+ if ( ! is_dir($this->config['directory']) OR ! is_writable($this->config['directory']))
+ throw new Cache_Exception('The configured cache directory, :directory:, is not writable.', array(':directory:' => $this->config['directory']));
+ }
+
+ /**
+ * Finds an array of files matching the given id or tag.
+ *
+ * @param string cache key or tag
+ * @param bool search for tags
+ * @return array of filenames matching the id or tag
+ */
+ public function exists($keys, $tag = FALSE)
+ {
+ if ($keys === TRUE)
+ {
+ // Find all the files
+ return glob($this->config['directory'].'*~*~*');
+ }
+ elseif ($tag === TRUE)
+ {
+ // Find all the files that have the tag name
+ $paths = array();
+
+ foreach ( (array) $keys as $tag)
+ {
+ $paths = array_merge($paths, glob($this->config['directory'].'*~*'.$tag.'*~*'));
+ }
+
+ // Find all tags matching the given tag
+ $files = array();
+
+ foreach ($paths as $path)
+ {
+ // Split the files
+ $tags = explode('~', basename($path));
+
+ // Find valid tags
+ if (count($tags) !== 3 OR empty($tags[1]))
+ continue;
+
+ // Split the tags by plus signs, used to separate tags
+ $item_tags = explode('+', $tags[1]);
+
+ // Check each supplied tag, and match aginst the tags on each item.
+ foreach ($keys as $tag)
+ {
+ if (in_array($tag, $item_tags))
+ {
+ // Add the file to the array, it has the requested tag
+ $files[] = $path;
+ }
+ }
+ }
+
+ return $files;
+ }
+ else
+ {
+ $paths = array();
+
+ foreach ( (array) $keys as $key)
+ {
+ // Find the file matching the given key
+ $paths = array_merge($paths, glob($this->config['directory'].str_replace(array('/', '\\', ' '), '_', $key).'~*'));
+ }
+
+ return $paths;
+ }
+ }
+
+ public function set($items, $tags = NULL, $lifetime = NULL)
+ {
+ if ($lifetime !== 0)
+ {
+ // File driver expects unix timestamp
+ $lifetime += time();
+ }
+
+
+ if ( ! is_null($tags) AND ! empty($tags))
+ {
+ // Convert the tags into a string list
+ $tags = implode('+', (array) $tags);
+ }
+
+ $success = TRUE;
+
+ foreach ($items as $key => $value)
+ {
+ if (is_resource($value))
+ throw new Cache_Exception('Caching of resources is impossible, because resources cannot be serialised.');
+
+ // Remove old cache file
+ $this->delete($key);
+
+ if ( ! (bool) file_put_contents($this->config['directory'].str_replace(array('/', '\\', ' '), '_', $key).'~'.$tags.'~'.$lifetime, serialize($value)))
+ {
+ $success = FALSE;
+ }
+ }
+
+ return $success;
+ }
+
+ public function get($keys, $single = FALSE)
+ {
+ $items = array();
+
+ if ($files = $this->exists($keys))
+ {
+ // Turn off errors while reading the files
+ $ER = error_reporting(0);
+
+ foreach ($files as $file)
+ {
+ // Validate that the item has not expired
+ if ($this->expired($file))
+ continue;
+
+ list($key, $junk) = explode('~', basename($file), 2);
+
+ if (($data = file_get_contents($file)) !== FALSE)
+ {
+ // Unserialize the data
+ $data = unserialize($data);
+ }
+ else
+ {
+ $data = NULL;
+ }
+
+ $items[$key] = $data;
+ }
+
+ // Turn errors back on
+ error_reporting($ER);
+ }
+
+ // Reutrn a single item if only one key was requested
+ if ($single)
+ {
+ return (count($items) > 0) ? current($items) : NULL;
+ }
+ else
+ {
+ return $items;
+ }
+ }
+
+ /**
+ * Get cache items by tag
+ */
+ public function get_tag($tags)
+ {
+ // An array will always be returned
+ $result = array();
+
+ if ($paths = $this->exists($tags, TRUE))
+ {
+ // Find all the files with the given tag
+ foreach ($paths as $path)
+ {
+ // Get the id from the filename
+ list($key, $junk) = explode('~', basename($path), 2);
+
+ if (($data = $this->get($key, TRUE)) !== FALSE)
+ {
+ // Add the result to the array
+ $result[$key] = $data;
+ }
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Delete cache items by keys or tags
+ */
+ public function delete($keys, $tag = FALSE)
+ {
+ $success = TRUE;
+
+ $paths = $this->exists($keys, $tag);
+
+ // Disable all error reporting while deleting
+ $ER = error_reporting(0);
+
+ foreach ($paths as $path)
+ {
+ // Remove the cache file
+ if ( ! unlink($path))
+ {
+ Kohana_Log::add('error', 'Cache: Unable to delete cache file: '.$path);
+ $success = FALSE;
+ }
+ }
+
+ // Turn on error reporting again
+ error_reporting($ER);
+
+ return $success;
+ }
+
+ /**
+ * Delete cache items by tag
+ */
+ public function delete_tag($tags)
+ {
+ return $this->delete($tags, TRUE);
+ }
+
+ /**
+ * Empty the cache
+ */
+ public function delete_all()
+ {
+ return $this->delete(TRUE);
+ }
+
+ /**
+ * Check if a cache file has expired by filename.
+ *
+ * @param string|array array of filenames
+ * @return bool
+ */
+ protected function expired($file)
+ {
+ // Get the expiration time
+ $expires = (int) substr($file, strrpos($file, '~') + 1);
+
+ // Expirations of 0 are "never expire"
+ return ($expires !== 0 AND $expires <= time());
+ }
+} // End Cache Memcache Driver
diff --git a/system/libraries/drivers/Cache/Memcache.php b/system/libraries/drivers/Cache/Memcache.php
new file mode 100644
index 0000000..13d61d8
--- /dev/null
+++ b/system/libraries/drivers/Cache/Memcache.php
@@ -0,0 +1,132 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * Memcache-based Cache driver.
+ *
+ * $Id$
+ *
+ * @package Cache
+ * @author Kohana Team
+ * @copyright (c) 2007-2009 Kohana Team
+ * @license http://kohanaphp.com/license
+ */
+class Cache_Memcache_Driver extends Cache_Driver {
+ protected $config;
+ protected $backend;
+ protected $flags;
+
+ public function __construct($config)
+ {
+ if ( ! extension_loaded('memcache'))
+ throw new Cache_Exception('The memcache PHP extension must be loaded to use this driver.');
+
+ ini_set('memcache.allow_failover', (isset($config['allow_failover']) AND $config['allow_failover']) ? TRUE : FALSE);
+
+ $this->config = $config;
+ $this->backend = new Memcache;
+
+ $this->flags = (isset($config['compression']) AND $config['compression']) ? MEMCACHE_COMPRESSED : FALSE;
+
+ foreach ($config['servers'] as $server)
+ {
+ // Make sure all required keys are set
+ $server += array('host' => '127.0.0.1',
+ 'port' => 11211,
+ 'persistent' => FALSE,
+ 'weight' => 1,
+ 'timeout' => 1,
+ 'retry_interval' => 15
+ );
+
+ // Add the server to the pool
+ $this->backend->addServer($server['host'], $server['port'], (bool) $server['persistent'], (int) $server['weight'], (int) $server['timeout'], (int) $server['retry_interval'], TRUE, array($this,'_memcache_failure_callback'));
+ }
+ }
+
+ public function _memcache_failure_callback($host, $port)
+ {
+ $this->backend->setServerParams($host, $port, 1, -1, FALSE);
+ Kohana_Log::add('error', __('Cache: Memcache server down: :host:::port:',array(':host:' => $host,':port:' => $port)));
+ }
+
+ public function set($items, $tags = NULL, $lifetime = NULL)
+ {
+ if ($lifetime !== 0)
+ {
+ // Memcache driver expects unix timestamp
+ $lifetime += time();
+ }
+
+ if ($tags !== NULL)
+ throw new Cache_Exception('Memcache driver does not support tags');
+
+ foreach ($items as $key => $value)
+ {
+ if (is_resource($value))
+ throw new Cache_Exception('Caching of resources is impossible, because resources cannot be serialised.');
+
+ if ( ! $this->backend->set($key, $value, $this->flags, $lifetime))
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+ }
+
+ public function get($keys, $single = FALSE)
+ {
+ $items = $this->backend->get($keys);
+
+ if ($single)
+ {
+ if ($items === FALSE)
+ return NULL;
+
+ return (count($items) > 0) ? current($items) : NULL;
+ }
+ else
+ {
+ return ($items === FALSE) ? array() : $items;
+ }
+ }
+
+ /**
+ * Get cache items by tag
+ */
+ public function get_tag($tags)
+ {
+ throw new Cache_Exception('Memcache driver does not support tags');
+ }
+
+ /**
+ * Delete cache item by key
+ */
+ public function delete($keys)
+ {
+ foreach ($keys as $key)
+ {
+ if ( ! $this->backend->delete($key))
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+ }
+
+ /**
+ * Delete cache items by tag
+ */
+ public function delete_tag($tags)
+ {
+ throw new Cache_Exception('Memcache driver does not support tags');
+ }
+
+ /**
+ * Empty the cache
+ */
+ public function delete_all()
+ {
+ return $this->backend->flush();
+ }
+} // End Cache Memcache Driver
diff --git a/system/libraries/drivers/Cache/Xcache.php b/system/libraries/drivers/Cache/Xcache.php
new file mode 100644
index 0000000..6761983
--- /dev/null
+++ b/system/libraries/drivers/Cache/Xcache.php
@@ -0,0 +1,161 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * XCache-based Cache driver.
+ *
+ * $Id: Memcache.php 4605 2009-09-14 17:22:21Z kiall $
+ *
+ * @package Cache
+ * @author Kohana Team
+ * @copyright (c) 2007-2009 Kohana Team
+ * @license http://kohanaphp.com/license
+ * @TODO Check if XCache cleans its own keys.
+ */
+class Cache_Xcache_Driver extends Cache_Driver {
+ protected $config;
+
+ public function __construct($config)
+ {
+ if ( ! extension_loaded('xcache'))
+ throw new Cache_Exception('The xcache PHP extension must be loaded to use this driver.');
+
+ $this->config = $config;
+ }
+
+ public function set($items, $tags = NULL, $lifetime = NULL)
+ {
+ if ($tags !== NULL)
+ {
+ Kohana_Log::add('debug', __('Cache: XCache driver does not support tags'));
+ }
+
+ foreach ($items as $key => $value)
+ {
+ if (is_resource($value))
+ throw new Cache_Exception('Caching of resources is impossible, because resources cannot be serialised.');
+
+ if ( ! xcache_set($key, $value, $lifetime))
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+ }
+
+ public function get($keys, $single = FALSE)
+ {
+ $items = array();
+
+ foreach ($keys as $key)
+ {
+ if (xcache_isset($key))
+ {
+ $items[$key] = xcache_get($key);
+ }
+ else
+ {
+ $items[$key] = NULL;
+ }
+ }
+
+ if ($single)
+ {
+ return ($items === FALSE OR count($items) > 0) ? current($items) : NULL;
+ }
+ else
+ {
+ return ($items === FALSE) ? array() : $items;
+ }
+ }
+
+ /**
+ * Get cache items by tag
+ */
+ public function get_tag($tags)
+ {
+ Kohana_Log::add('debug', __('Cache: XCache driver does not support tags'));
+ return NULL;
+ }
+
+ /**
+ * Delete cache item by key
+ */
+ public function delete($keys)
+ {
+ foreach ($keys as $key)
+ {
+ if ( ! xcache_unset($key))
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+ }
+
+ /**
+ * Delete cache items by tag
+ */
+ public function delete_tag($tags)
+ {
+ Kohana_Log::add('debug', __('Cache: XCache driver does not support tags'));
+ return NULL;
+ }
+
+ /**
+ * Empty the cache
+ */
+ public function delete_all()
+ {
+ $this->auth();
+ $result = TRUE;
+
+ for ($i = 0, $max = xcache_count(XC_TYPE_VAR); $i < $max; $i++)
+ {
+ if (xcache_clear_cache(XC_TYPE_VAR, $i) !== NULL)
+ {
+ $result = FALSE;
+ break;
+ }
+ }
+
+ // Undo the login
+ $this->auth(TRUE);
+
+ return $result;
+ }
+
+ private function auth($reverse = FALSE)
+ {
+ static $backup = array();
+
+ $keys = array('PHP_AUTH_USER', 'PHP_AUTH_PW');
+
+ foreach ($keys as $key)
+ {
+ if ($reverse)
+ {
+ if (isset($backup[$key]))
+ {
+ $_SERVER[$key] = $backup[$key];
+ unset($backup[$key]);
+ }
+ else
+ {
+ unset($_SERVER[$key]);
+ }
+ }
+ else
+ {
+ $value = getenv($key);
+
+ if ( ! empty($value))
+ {
+ $backup[$key] = $value;
+ }
+
+ $_SERVER[$key] = $this->config->{$key};
+ }
+ }
+ }
+} // End Cache XCache Driver