* @link */ class CI_Cache_redis extends CI_Driver { /** * Default config * * @static * @var array */ protected static $_default_config = array( 'socket_type' => 'tcp', 'host' => '127.0.0.1', 'password' => null, 'port' => 6379, 'timeout' => 0 ); /** * Redis connection * * @var Redis */ protected $_redis; /** * An internal cache for storing keys of serialized values. * * @var array */ protected $_serialized = array(); /** * del()/delete() method name depending on phpRedis version * * @var string */ protected static $_delete_name; /** * sRem()/sRemove() method name depending on phpRedis version * * @var string */ protected static $_sRemove_name; // ------------------------------------------------------------------------ /** * Class constructor * * Setup Redis * * Loads Redis config file if present. Will halt execution * if a Redis connection can't be established. * * @return void * @see Redis::connect() */ public function __construct() { if (! $this->is_supported()) { log_message('error', 'Cache: Failed to create Redis object; extension not loaded?'); return; } if (! isset(static::$_delete_name, static::$_sRemove_name)) { if (version_compare(phpversion('redis'), '5', '>=')) { static::$_delete_name = 'del'; static::$_sRemove_name = 'sRem'; } else { static::$_delete_name = 'delete'; static::$_sRemove_name = 'sRemove'; } } $CI = & get_instance(); if ($CI->config->load('redis', true, true)) { $config = array_merge(self::$_default_config, $CI->config->item('redis')); } else { $config = self::$_default_config; } $this->_redis = new Redis(); try { if ($config['socket_type'] === 'unix') { $success = $this->_redis->connect($config['socket']); } else { // tcp socket $success = $this->_redis->connect($config['host'], $config['port'], $config['timeout']); } if (! $success) { log_message('error', 'Cache: Redis connection failed. Check your configuration.'); } if (isset($config['password']) && ! $this->_redis->auth($config['password'])) { log_message('error', 'Cache: Redis authentication failed.'); } } catch (RedisException $e) { log_message('error', 'Cache: Redis connection refused (' . $e->getMessage() . ')'); } } // ------------------------------------------------------------------------ /** * Get cache * * @param string $key Cache ID * @return mixed */ public function get($key) { $value = $this->_redis->get($key); if ($value !== false && $this->_redis->sIsMember('_ci_redis_serialized', $key)) { return unserialize($value); } return $value; } // ------------------------------------------------------------------------ /** * Save cache * * @param string $id Cache ID * @param mixed $data Data to save * @param int $ttl Time to live in seconds * @param bool $raw Whether to store the raw value (unused) * @return bool TRUE on success, FALSE on failure */ public function save($id, $data, $ttl = 60, $raw = false) { if (is_array($data) or is_object($data)) { if (! $this->_redis->sIsMember('_ci_redis_serialized', $id) && ! $this->_redis->sAdd('_ci_redis_serialized', $id)) { return false; } isset($this->_serialized[$id]) or $this->_serialized[$id] = true; $data = serialize($data); } else { $this->_redis->{static::$_sRemove_name}('_ci_redis_serialized', $id); } return $this->_redis->set($id, $data, $ttl); } // ------------------------------------------------------------------------ /** * Delete from cache * * @param string $key Cache key * @return bool */ public function delete($key) { if ($this->_redis->{static::$_delete_name}($key) !== 1) { return false; } $this->_redis->{static::$_sRemove_name}('_ci_redis_serialized', $key); return true; } // ------------------------------------------------------------------------ /** * Increment a raw value * * @param string $id Cache ID * @param int $offset Step/value to add * @return mixed New value on success or FALSE on failure */ public function increment($id, $offset = 1) { return $this->_redis->incrBy($id, $offset); } // ------------------------------------------------------------------------ /** * Decrement a raw value * * @param string $id Cache ID * @param int $offset Step/value to reduce by * @return mixed New value on success or FALSE on failure */ public function decrement($id, $offset = 1) { return $this->_redis->decrBy($id, $offset); } // ------------------------------------------------------------------------ /** * Clean cache * * @return bool * @see Redis::flushDB() */ public function clean() { return $this->_redis->flushDB(); } // ------------------------------------------------------------------------ /** * Get cache driver info * * @param string $type Not supported in Redis. * Only included in order to offer a * consistent cache API. * @return array * @see Redis::info() */ public function cache_info($type = null) { return $this->_redis->info(); } // ------------------------------------------------------------------------ /** * Get cache metadata * * @param string $key Cache key * @return array */ public function get_metadata($key) { $value = $this->get($key); if ($value !== false) { return array( 'expire' => time() + $this->_redis->ttl($key), 'data' => $value ); } return false; } // ------------------------------------------------------------------------ /** * Check if Redis driver is supported * * @return bool */ public function is_supported() { return extension_loaded('redis'); } // ------------------------------------------------------------------------ /** * Class destructor * * Closes the connection to Redis if present. * * @return void */ public function __destruct() { if ($this->_redis) { $this->_redis->close(); } } }