blob: ab4fd0da956fecd2fbd398a2447916d4d44ed358 [file] [log] [blame]
Andrey Andreevc5536aa2012-11-01 17:33:58 +02001<?php
Anton Lindqvist1e8be292012-01-21 12:25:08 +01002/**
3 * CodeIgniter
4 *
Anton Lindqvist5ccf5ce2012-06-08 11:47:17 +02005 * An open source application development framework for PHP 5.2.4 or newer
Anton Lindqvist1e8be292012-01-21 12:25:08 +01006 *
Anton Lindqvist5a1d9532012-01-23 23:20:26 +01007 * NOTICE OF LICENSE
8 *
9 * Licensed under the Open Software License version 3.0
10 *
11 * This source file is subject to the Open Software License (OSL 3.0) that is
12 * bundled with this package in the files license.txt / license.rst. It is
13 * also available through the world wide web at this URL:
14 * http://opensource.org/licenses/OSL-3.0
15 * If you did not receive a copy of the license and are unable to obtain it
16 * through the world wide web, please send an email to
17 * licensing@ellislab.com so we can send you a copy immediately.
18 *
19 * @package CodeIgniter
20 * @author EllisLab Dev Team
darwinel871754a2014-02-11 17:34:57 +010021 * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (http://ellislab.com/)
Anton Lindqvist5a1d9532012-01-23 23:20:26 +010022 * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
23 * @link http://codeigniter.com
Andrey Andreev9e674f72012-06-09 21:02:52 +030024 * @since Version 3.0
Anton Lindqvist1e8be292012-01-21 12:25:08 +010025 * @filesource
26 */
Andrey Andreevc5536aa2012-11-01 17:33:58 +020027defined('BASEPATH') OR exit('No direct script access allowed');
Anton Lindqvist1e8be292012-01-21 12:25:08 +010028
Anton Lindqvist1e8be292012-01-21 12:25:08 +010029/**
30 * CodeIgniter Redis Caching Class
31 *
32 * @package CodeIgniter
33 * @subpackage Libraries
34 * @category Core
35 * @author Anton Lindqvist <anton@qvister.se>
36 * @link
37 */
38class CI_Cache_redis extends CI_Driver
39{
Anton Lindqvist1e8be292012-01-21 12:25:08 +010040 /**
41 * Default config
42 *
Anton Lindqvist1e8be292012-01-21 12:25:08 +010043 * @static
Andrey Andreev9e674f72012-06-09 21:02:52 +030044 * @var array
Anton Lindqvist1e8be292012-01-21 12:25:08 +010045 */
Anton Lindqvist3573af82012-01-21 20:33:12 +010046 protected static $_default_config = array(
Kakysha80d663a2013-10-28 01:39:17 +040047 'socket_type' => 'tcp',
Anton Lindqvist1e8be292012-01-21 12:25:08 +010048 'host' => '127.0.0.1',
Anton Lindqvist5ccf5ce2012-06-08 11:47:17 +020049 'password' => NULL,
Anton Lindqvist1e8be292012-01-21 12:25:08 +010050 'port' => 6379,
51 'timeout' => 0
52 );
53
54 /**
55 * Redis connection
56 *
Andrey Andreev9e674f72012-06-09 21:02:52 +030057 * @var Redis
Anton Lindqvist1e8be292012-01-21 12:25:08 +010058 */
Anton Lindqvist3573af82012-01-21 20:33:12 +010059 protected $_redis;
Anton Lindqvist1e8be292012-01-21 12:25:08 +010060
Ivan Tcholakov927e5082014-08-14 04:07:39 +030061 /**
62 * An internal cache for storing keys of serialized values.
63 *
64 * @var array
65 */
Andrey Andreev2492b502014-08-18 16:20:05 +030066 protected $_serialized = array();
Ivan Tcholakov927e5082014-08-14 04:07:39 +030067
Andrey Andreev9e674f72012-06-09 21:02:52 +030068 // ------------------------------------------------------------------------
Anton Lindqvist1e8be292012-01-21 12:25:08 +010069
70 /**
71 * Get cache
72 *
Andrey Andreev43d7fa72014-01-09 17:29:45 +020073 * @param string Cache ID
Andrey Andreev9e674f72012-06-09 21:02:52 +030074 * @return mixed
Anton Lindqvist1e8be292012-01-21 12:25:08 +010075 */
76 public function get($key)
77 {
Ivan Tcholakov927e5082014-08-14 04:07:39 +030078 $value = $this->_redis->get($key);
79
Andrey Andreev2492b502014-08-18 16:20:05 +030080 if ($value !== FALSE && isset($this->_serialized[$key]))
Ivan Tcholakov927e5082014-08-14 04:07:39 +030081 {
82 return unserialize($value);
83 }
84
85 return $value;
Anton Lindqvist1e8be292012-01-21 12:25:08 +010086 }
87
Andrey Andreev9e674f72012-06-09 21:02:52 +030088 // ------------------------------------------------------------------------
89
Anton Lindqvist1e8be292012-01-21 12:25:08 +010090 /**
91 * Save cache
92 *
Andrey Andreev43d7fa72014-01-09 17:29:45 +020093 * @param string $id Cache ID
94 * @param mixed $data Data to save
95 * @param int $ttl Time to live in seconds
96 * @param bool $raw Whether to store the raw value (unused)
97 * @return bool TRUE on success, FALSE on failure
Anton Lindqvist1e8be292012-01-21 12:25:08 +010098 */
Andrey Andreev43d7fa72014-01-09 17:29:45 +020099 public function save($id, $data, $ttl = 60, $raw = FALSE)
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100100 {
Ivan Tcholakov927e5082014-08-14 04:07:39 +0300101 if (is_array($data) OR is_object($data))
102 {
Andrey Andreev2492b502014-08-18 16:20:05 +0300103 if ( ! $this->_redis->sAdd('_ci_redis_serialized', $id))
Ivan Tcholakov927e5082014-08-14 04:07:39 +0300104 {
Andrey Andreev2492b502014-08-18 16:20:05 +0300105 return FALSE;
Ivan Tcholakov927e5082014-08-14 04:07:39 +0300106 }
107
Andrey Andreev2492b502014-08-18 16:20:05 +0300108 isset($this->_serialized[$id]) OR $this->_serialized[$id] = TRUE;
109 $data = serialize($data);
Ivan Tcholakov927e5082014-08-14 04:07:39 +0300110 }
Andrey Andreev2492b502014-08-18 16:20:05 +0300111 elseif (isset($this->_serialized[$id]))
Ivan Tcholakov927e5082014-08-14 04:07:39 +0300112 {
Andrey Andreev2492b502014-08-18 16:20:05 +0300113 $this->_serialized[$id] = NULL;
Ivan Tcholakovd245f062014-08-18 13:52:44 +0300114 $this->_redis->sRemove('_ci_redis_serialized', $id);
Ivan Tcholakov927e5082014-08-14 04:07:39 +0300115 }
116
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100117 return ($ttl)
Andrey Andreev43d7fa72014-01-09 17:29:45 +0200118 ? $this->_redis->setex($id, $ttl, $data)
119 : $this->_redis->set($id, $data);
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100120 }
121
Andrey Andreev9e674f72012-06-09 21:02:52 +0300122 // ------------------------------------------------------------------------
123
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100124 /**
125 * Delete from cache
126 *
Andrey Andreev9e674f72012-06-09 21:02:52 +0300127 * @param string Cache key
128 * @return bool
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100129 */
130 public function delete($key)
131 {
Andrey Andreev2492b502014-08-18 16:20:05 +0300132 if ($this->_redis->delete($key) !== 1)
Ivan Tcholakovd514d5c2014-08-18 12:04:27 +0300133 {
Andrey Andreev2492b502014-08-18 16:20:05 +0300134 return FALSE;
Ivan Tcholakovd514d5c2014-08-18 12:04:27 +0300135 }
Ivan Tcholakovbc417612014-08-18 11:11:39 +0300136
Andrey Andreev2492b502014-08-18 16:20:05 +0300137 if (isset($this->_serialized[$key]))
138 {
139 $this->_serialized[$key] = NULL;
140 $this->_redis->sRemove('_ci_redis_serialized', $key);
141 }
142
143 return TRUE;
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100144 }
145
Andrey Andreev9e674f72012-06-09 21:02:52 +0300146 // ------------------------------------------------------------------------
147
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100148 /**
Andrey Andreev43d7fa72014-01-09 17:29:45 +0200149 * Increment a raw value
150 *
151 * @param string $id Cache ID
152 * @param int $offset Step/value to add
153 * @return mixed New value on success or FALSE on failure
154 */
155 public function increment($id, $offset = 1)
156 {
Andrey Andreev5f0799a2014-07-31 13:32:41 +0300157 return $this->_redis->incr($id, $offset);
Andrey Andreev43d7fa72014-01-09 17:29:45 +0200158 }
159
160 // ------------------------------------------------------------------------
161
162 /**
163 * Decrement a raw value
164 *
165 * @param string $id Cache ID
166 * @param int $offset Step/value to reduce by
167 * @return mixed New value on success or FALSE on failure
168 */
169 public function decrement($id, $offset = 1)
170 {
Andrey Andreev5f0799a2014-07-31 13:32:41 +0300171 return $this->_redis->decr($id, $offset);
Andrey Andreev43d7fa72014-01-09 17:29:45 +0200172 }
173
174 // ------------------------------------------------------------------------
175
176 /**
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100177 * Clean cache
178 *
Andrey Andreev9e674f72012-06-09 21:02:52 +0300179 * @return bool
180 * @see Redis::flushDB()
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100181 */
182 public function clean()
183 {
184 return $this->_redis->flushDB();
185 }
186
Andrey Andreev9e674f72012-06-09 21:02:52 +0300187 // ------------------------------------------------------------------------
188
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100189 /**
190 * Get cache driver info
191 *
Andrey Andreev9e674f72012-06-09 21:02:52 +0300192 * @param string Not supported in Redis.
193 * Only included in order to offer a
194 * consistent cache API.
195 * @return array
196 * @see Redis::info()
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100197 */
198 public function cache_info($type = NULL)
199 {
200 return $this->_redis->info();
201 }
202
Andrey Andreev9e674f72012-06-09 21:02:52 +0300203 // ------------------------------------------------------------------------
204
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100205 /**
206 * Get cache metadata
207 *
Andrey Andreev9e674f72012-06-09 21:02:52 +0300208 * @param string Cache key
209 * @return array
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100210 */
211 public function get_metadata($key)
212 {
213 $value = $this->get($key);
214
215 if ($value)
Andrey Andreev9e674f72012-06-09 21:02:52 +0300216 {
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100217 return array(
218 'expire' => time() + $this->_redis->ttl($key),
219 'data' => $value
220 );
221 }
Andrey Andreev9e674f72012-06-09 21:02:52 +0300222
223 return FALSE;
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100224 }
225
Andrey Andreev9e674f72012-06-09 21:02:52 +0300226 // ------------------------------------------------------------------------
227
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100228 /**
229 * Check if Redis driver is supported
230 *
Andrey Andreev9e674f72012-06-09 21:02:52 +0300231 * @return bool
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100232 */
233 public function is_supported()
234 {
235 if (extension_loaded('redis'))
Andrey Andreev9e674f72012-06-09 21:02:52 +0300236 {
Kakysha2d146732013-10-28 20:20:24 +0400237 return $this->_setup_redis();
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100238 }
239 else
240 {
Tyler Brownelld967f722013-07-29 19:06:52 -0400241 log_message('debug', 'The Redis extension must be loaded to use Redis cache.');
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100242 return FALSE;
243 }
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100244 }
245
Andrey Andreev9e674f72012-06-09 21:02:52 +0300246 // ------------------------------------------------------------------------
247
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100248 /**
249 * Setup Redis config and connection
250 *
Andrey Andreev9e674f72012-06-09 21:02:52 +0300251 * Loads Redis config file if present. Will halt execution
252 * if a Redis connection can't be established.
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100253 *
Andrey Andreev9e674f72012-06-09 21:02:52 +0300254 * @return bool
255 * @see Redis::connect()
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100256 */
Anton Lindqvist5ccf5ce2012-06-08 11:47:17 +0200257 protected function _setup_redis()
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100258 {
259 $config = array();
260 $CI =& get_instance();
261
262 if ($CI->config->load('redis', TRUE, TRUE))
Anton Lindqvist5ccf5ce2012-06-08 11:47:17 +0200263 {
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100264 $config += $CI->config->item('redis');
265 }
266
267 $config = array_merge(self::$_default_config, $config);
268
269 $this->_redis = new Redis();
270
271 try
272 {
Kakysha80d663a2013-10-28 01:39:17 +0400273 if ($config['socket_type'] === 'unix')
274 {
Kakyshaffe21302013-10-28 21:30:05 +0400275 $success = $this->_redis->connect($config['socket']);
Kakysha8f3f1f92013-10-28 23:14:08 +0400276 }
277 else // tcp socket
Kakysha80d663a2013-10-28 01:39:17 +0400278 {
Kakyshaffe21302013-10-28 21:30:05 +0400279 $success = $this->_redis->connect($config['host'], $config['port'], $config['timeout']);
Kakysha2d146732013-10-28 20:20:24 +0400280 }
Andrey Andreev119d8a72014-01-08 15:27:53 +0200281
Kakyshaffe21302013-10-28 21:30:05 +0400282 if ( ! $success)
Kakysha2d146732013-10-28 20:20:24 +0400283 {
Kakysha333b69b2013-10-29 03:49:56 +0400284 log_message('debug', 'Cache: Redis connection refused. Check the config.');
Kakysha2d146732013-10-28 20:20:24 +0400285 return FALSE;
Kakysha80d663a2013-10-28 01:39:17 +0400286 }
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100287 }
288 catch (RedisException $e)
289 {
Kakysha333b69b2013-10-29 03:49:56 +0400290 log_message('debug', 'Cache: Redis connection refused ('.$e->getMessage().')');
Kakysha2d146732013-10-28 20:20:24 +0400291 return FALSE;
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100292 }
Anton Lindqvist210e6642012-04-23 10:13:46 +0200293
Anton Lindqvist5ccf5ce2012-06-08 11:47:17 +0200294 if (isset($config['password']))
295 {
Anton Lindqvist210e6642012-04-23 10:13:46 +0200296 $this->_redis->auth($config['password']);
297 }
Andrey Andreev119d8a72014-01-08 15:27:53 +0200298
Ivan Tcholakovd245f062014-08-18 13:52:44 +0300299 // Initialize the index of serialized values.
Andrey Andreev2492b502014-08-18 16:20:05 +0300300 $serialized = $this->_redis->sMembers('_ci_redis_serialized');
301 if ( ! empty($serialized))
Ivan Tcholakov927e5082014-08-14 04:07:39 +0300302 {
Andrey Andreev2492b502014-08-18 16:20:05 +0300303 $this->_serialized = array_flip($this->_serialized);
Ivan Tcholakov927e5082014-08-14 04:07:39 +0300304 }
305
Kakysha2d146732013-10-28 20:20:24 +0400306 return TRUE;
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100307 }
308
Andrey Andreev9e674f72012-06-09 21:02:52 +0300309 // ------------------------------------------------------------------------
310
311 /**
Andrey Andreev9e674f72012-06-09 21:02:52 +0300312 * Class destructor
313 *
314 * Closes the connection to Redis if present.
315 *
316 * @return void
317 */
318 public function __destruct()
319 {
320 if ($this->_redis)
321 {
322 $this->_redis->close();
323 }
324 }
325
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100326}
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100327
328/* End of file Cache_redis.php */
329/* Location: ./system/libraries/Cache/drivers/Cache_redis.php */