blob: 33a28de7151d706811cd995b5e48182daa7c0edc [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 /**
Ivan Tcholakov927e5082014-08-14 04:07:39 +030041 * The name of the Redis set that is to store keys of serialized values.
42 */
43 const KEY_SET_FOR_SERIALIZATION = '_ci_redis_serialization_set';
44
45 /**
Anton Lindqvist1e8be292012-01-21 12:25:08 +010046 * Default config
47 *
Anton Lindqvist1e8be292012-01-21 12:25:08 +010048 * @static
Andrey Andreev9e674f72012-06-09 21:02:52 +030049 * @var array
Anton Lindqvist1e8be292012-01-21 12:25:08 +010050 */
Anton Lindqvist3573af82012-01-21 20:33:12 +010051 protected static $_default_config = array(
Kakysha80d663a2013-10-28 01:39:17 +040052 'socket_type' => 'tcp',
Anton Lindqvist1e8be292012-01-21 12:25:08 +010053 'host' => '127.0.0.1',
Anton Lindqvist5ccf5ce2012-06-08 11:47:17 +020054 'password' => NULL,
Anton Lindqvist1e8be292012-01-21 12:25:08 +010055 'port' => 6379,
56 'timeout' => 0
57 );
58
59 /**
60 * Redis connection
61 *
Andrey Andreev9e674f72012-06-09 21:02:52 +030062 * @var Redis
Anton Lindqvist1e8be292012-01-21 12:25:08 +010063 */
Anton Lindqvist3573af82012-01-21 20:33:12 +010064 protected $_redis;
Anton Lindqvist1e8be292012-01-21 12:25:08 +010065
Ivan Tcholakov927e5082014-08-14 04:07:39 +030066 /**
67 * An internal cache for storing keys of serialized values.
68 *
69 * @var array
70 */
71 protected $_serialized;
72
Andrey Andreev9e674f72012-06-09 21:02:52 +030073 // ------------------------------------------------------------------------
Anton Lindqvist1e8be292012-01-21 12:25:08 +010074
75 /**
76 * Get cache
77 *
Andrey Andreev43d7fa72014-01-09 17:29:45 +020078 * @param string Cache ID
Andrey Andreev9e674f72012-06-09 21:02:52 +030079 * @return mixed
Anton Lindqvist1e8be292012-01-21 12:25:08 +010080 */
81 public function get($key)
82 {
Ivan Tcholakov927e5082014-08-14 04:07:39 +030083 $value = $this->_redis->get($key);
84
85 if ($value !== FALSE AND in_array($key, $this->_serialized))
86 {
87 return unserialize($value);
88 }
89
90 return $value;
Anton Lindqvist1e8be292012-01-21 12:25:08 +010091 }
92
Andrey Andreev9e674f72012-06-09 21:02:52 +030093 // ------------------------------------------------------------------------
94
Anton Lindqvist1e8be292012-01-21 12:25:08 +010095 /**
96 * Save cache
97 *
Andrey Andreev43d7fa72014-01-09 17:29:45 +020098 * @param string $id Cache ID
99 * @param mixed $data Data to save
100 * @param int $ttl Time to live in seconds
101 * @param bool $raw Whether to store the raw value (unused)
102 * @return bool TRUE on success, FALSE on failure
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100103 */
Andrey Andreev43d7fa72014-01-09 17:29:45 +0200104 public function save($id, $data, $ttl = 60, $raw = FALSE)
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100105 {
Ivan Tcholakov927e5082014-08-14 04:07:39 +0300106 if (is_array($data) OR is_object($data))
107 {
108 $data = serialize($data);
109
110 if (($index_key = array_search($id, $this->_serialized)) === FALSE)
111 {
112 $this->_serialized[] = $id;
113 }
114
115 $this->_redis->sAdd(self::KEY_SET_FOR_SERIALIZATION, $id);
116 }
117 else
118 {
119 if (($index_key = array_search($id, $this->_serialized)) !== FALSE)
120 {
121 unset($this->_serialized[$index_key]);
122 }
123
124 $this->_redis->sRemove(self::KEY_SET_FOR_SERIALIZATION, $id);
125 }
126
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100127 return ($ttl)
Andrey Andreev43d7fa72014-01-09 17:29:45 +0200128 ? $this->_redis->setex($id, $ttl, $data)
129 : $this->_redis->set($id, $data);
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100130 }
131
Andrey Andreev9e674f72012-06-09 21:02:52 +0300132 // ------------------------------------------------------------------------
133
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100134 /**
135 * Delete from cache
136 *
Andrey Andreev9e674f72012-06-09 21:02:52 +0300137 * @param string Cache key
138 * @return bool
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100139 */
140 public function delete($key)
141 {
Ivan Tcholakov927e5082014-08-14 04:07:39 +0300142 if (($index_key = array_search($key, $this->_serialized)) !== FALSE)
143 {
144 unset($this->_serialized[$index_key]);
145 }
146
147 $this->_redis->sRemove(self::KEY_SET_FOR_SERIALIZATION, $key);
148
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100149 return ($this->_redis->delete($key) === 1);
150 }
151
Andrey Andreev9e674f72012-06-09 21:02:52 +0300152 // ------------------------------------------------------------------------
153
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100154 /**
Andrey Andreev43d7fa72014-01-09 17:29:45 +0200155 * Increment a raw value
156 *
157 * @param string $id Cache ID
158 * @param int $offset Step/value to add
159 * @return mixed New value on success or FALSE on failure
160 */
161 public function increment($id, $offset = 1)
162 {
Andrey Andreev5f0799a2014-07-31 13:32:41 +0300163 return $this->_redis->incr($id, $offset);
Andrey Andreev43d7fa72014-01-09 17:29:45 +0200164 }
165
166 // ------------------------------------------------------------------------
167
168 /**
169 * Decrement a raw value
170 *
171 * @param string $id Cache ID
172 * @param int $offset Step/value to reduce by
173 * @return mixed New value on success or FALSE on failure
174 */
175 public function decrement($id, $offset = 1)
176 {
Andrey Andreev5f0799a2014-07-31 13:32:41 +0300177 return $this->_redis->decr($id, $offset);
Andrey Andreev43d7fa72014-01-09 17:29:45 +0200178 }
179
180 // ------------------------------------------------------------------------
181
182 /**
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100183 * Clean cache
184 *
Andrey Andreev9e674f72012-06-09 21:02:52 +0300185 * @return bool
186 * @see Redis::flushDB()
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100187 */
188 public function clean()
189 {
190 return $this->_redis->flushDB();
191 }
192
Andrey Andreev9e674f72012-06-09 21:02:52 +0300193 // ------------------------------------------------------------------------
194
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100195 /**
196 * Get cache driver info
197 *
Andrey Andreev9e674f72012-06-09 21:02:52 +0300198 * @param string Not supported in Redis.
199 * Only included in order to offer a
200 * consistent cache API.
201 * @return array
202 * @see Redis::info()
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100203 */
204 public function cache_info($type = NULL)
205 {
206 return $this->_redis->info();
207 }
208
Andrey Andreev9e674f72012-06-09 21:02:52 +0300209 // ------------------------------------------------------------------------
210
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100211 /**
212 * Get cache metadata
213 *
Andrey Andreev9e674f72012-06-09 21:02:52 +0300214 * @param string Cache key
215 * @return array
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100216 */
217 public function get_metadata($key)
218 {
219 $value = $this->get($key);
220
221 if ($value)
Andrey Andreev9e674f72012-06-09 21:02:52 +0300222 {
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100223 return array(
224 'expire' => time() + $this->_redis->ttl($key),
225 'data' => $value
226 );
227 }
Andrey Andreev9e674f72012-06-09 21:02:52 +0300228
229 return FALSE;
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100230 }
231
Andrey Andreev9e674f72012-06-09 21:02:52 +0300232 // ------------------------------------------------------------------------
233
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100234 /**
235 * Check if Redis driver is supported
236 *
Andrey Andreev9e674f72012-06-09 21:02:52 +0300237 * @return bool
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100238 */
239 public function is_supported()
240 {
241 if (extension_loaded('redis'))
Andrey Andreev9e674f72012-06-09 21:02:52 +0300242 {
Kakysha2d146732013-10-28 20:20:24 +0400243 return $this->_setup_redis();
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100244 }
245 else
246 {
Tyler Brownelld967f722013-07-29 19:06:52 -0400247 log_message('debug', 'The Redis extension must be loaded to use Redis cache.');
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100248 return FALSE;
249 }
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100250 }
251
Andrey Andreev9e674f72012-06-09 21:02:52 +0300252 // ------------------------------------------------------------------------
253
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100254 /**
255 * Setup Redis config and connection
256 *
Andrey Andreev9e674f72012-06-09 21:02:52 +0300257 * Loads Redis config file if present. Will halt execution
258 * if a Redis connection can't be established.
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100259 *
Andrey Andreev9e674f72012-06-09 21:02:52 +0300260 * @return bool
261 * @see Redis::connect()
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100262 */
Anton Lindqvist5ccf5ce2012-06-08 11:47:17 +0200263 protected function _setup_redis()
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100264 {
265 $config = array();
266 $CI =& get_instance();
267
268 if ($CI->config->load('redis', TRUE, TRUE))
Anton Lindqvist5ccf5ce2012-06-08 11:47:17 +0200269 {
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100270 $config += $CI->config->item('redis');
271 }
272
273 $config = array_merge(self::$_default_config, $config);
274
275 $this->_redis = new Redis();
276
277 try
278 {
Kakysha80d663a2013-10-28 01:39:17 +0400279 if ($config['socket_type'] === 'unix')
280 {
Kakyshaffe21302013-10-28 21:30:05 +0400281 $success = $this->_redis->connect($config['socket']);
Kakysha8f3f1f92013-10-28 23:14:08 +0400282 }
283 else // tcp socket
Kakysha80d663a2013-10-28 01:39:17 +0400284 {
Kakyshaffe21302013-10-28 21:30:05 +0400285 $success = $this->_redis->connect($config['host'], $config['port'], $config['timeout']);
Kakysha2d146732013-10-28 20:20:24 +0400286 }
Andrey Andreev119d8a72014-01-08 15:27:53 +0200287
Kakyshaffe21302013-10-28 21:30:05 +0400288 if ( ! $success)
Kakysha2d146732013-10-28 20:20:24 +0400289 {
Kakysha333b69b2013-10-29 03:49:56 +0400290 log_message('debug', 'Cache: Redis connection refused. Check the config.');
Kakysha2d146732013-10-28 20:20:24 +0400291 return FALSE;
Kakysha80d663a2013-10-28 01:39:17 +0400292 }
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100293 }
294 catch (RedisException $e)
295 {
Kakysha333b69b2013-10-29 03:49:56 +0400296 log_message('debug', 'Cache: Redis connection refused ('.$e->getMessage().')');
Kakysha2d146732013-10-28 20:20:24 +0400297 return FALSE;
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100298 }
Anton Lindqvist210e6642012-04-23 10:13:46 +0200299
Anton Lindqvist5ccf5ce2012-06-08 11:47:17 +0200300 if (isset($config['password']))
301 {
Anton Lindqvist210e6642012-04-23 10:13:46 +0200302 $this->_redis->auth($config['password']);
303 }
Andrey Andreev119d8a72014-01-08 15:27:53 +0200304
Ivan Tcholakov927e5082014-08-14 04:07:39 +0300305 // Initialize the index of selialized values.
306 $this->_serialized = $this->_redis->sMembers(self::KEY_SET_FOR_SERIALIZATION);
307
308 if (empty($this->_serialized))
309 {
310 // On error FALSE is returned, ensure array type for empty index.
311 $this->_serialized = array();
312 }
313
Kakysha2d146732013-10-28 20:20:24 +0400314 return TRUE;
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100315 }
316
Andrey Andreev9e674f72012-06-09 21:02:52 +0300317 // ------------------------------------------------------------------------
318
319 /**
Andrey Andreev9e674f72012-06-09 21:02:52 +0300320 * Class destructor
321 *
322 * Closes the connection to Redis if present.
323 *
324 * @return void
325 */
326 public function __destruct()
327 {
328 if ($this->_redis)
329 {
330 $this->_redis->close();
331 }
332 }
333
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100334}
Anton Lindqvist1e8be292012-01-21 12:25:08 +0100335
336/* End of file Cache_redis.php */
337/* Location: ./system/libraries/Cache/drivers/Cache_redis.php */