1 | <?php |
||
2 | /** |
||
3 | * @link http://www.yiiframework.com/ |
||
4 | * @copyright Copyright (c) 2008 Yii Software LLC |
||
5 | * @license http://www.yiiframework.com/license/ |
||
6 | */ |
||
7 | |||
8 | namespace yii\caching; |
||
9 | |||
10 | use Yii; |
||
11 | use yii\base\InvalidConfigException; |
||
12 | |||
13 | /** |
||
14 | * MemCache implements a cache application component based on [memcache](https://pecl.php.net/package/memcache) |
||
15 | * and [memcached](https://pecl.php.net/package/memcached). |
||
16 | * |
||
17 | * MemCache supports both [memcache](https://pecl.php.net/package/memcache) and |
||
18 | * [memcached](https://pecl.php.net/package/memcached). By setting [[useMemcached]] to be true or false, |
||
19 | * one can let MemCache to use either memcached or memcache, respectively. |
||
20 | * |
||
21 | * MemCache can be configured with a list of memcache servers by settings its [[servers]] property. |
||
22 | * By default, MemCache assumes there is a memcache server running on localhost at port 11211. |
||
23 | * |
||
24 | * See [[Cache]] for common cache operations that MemCache supports. |
||
25 | * |
||
26 | * Note, there is no security measure to protected data in memcache. |
||
27 | * All data in memcache can be accessed by any process running in the system. |
||
28 | * |
||
29 | * To use MemCache as the cache application component, configure the application as follows, |
||
30 | * |
||
31 | * ```php |
||
32 | * [ |
||
33 | * 'components' => [ |
||
34 | * 'cache' => [ |
||
35 | * 'class' => 'yii\caching\MemCache', |
||
36 | * 'servers' => [ |
||
37 | * [ |
||
38 | * 'host' => 'server1', |
||
39 | * 'port' => 11211, |
||
40 | * 'weight' => 60, |
||
41 | * ], |
||
42 | * [ |
||
43 | * 'host' => 'server2', |
||
44 | * 'port' => 11211, |
||
45 | * 'weight' => 40, |
||
46 | * ], |
||
47 | * ], |
||
48 | * ], |
||
49 | * ], |
||
50 | * ] |
||
51 | * ``` |
||
52 | * |
||
53 | * In the above, two memcache servers are used: server1 and server2. You can configure more properties of |
||
54 | * each server, such as `persistent`, `weight`, `timeout`. Please see [[MemCacheServer]] for available options. |
||
55 | * |
||
56 | * For more details and usage information on Cache, see the [guide article on caching](guide:caching-overview). |
||
57 | * |
||
58 | * @property-read \Memcache|\Memcached $memcache The memcache (or memcached) object used by this cache |
||
59 | * component. This property is read-only. |
||
60 | * @property MemCacheServer[] $servers List of memcache server configurations. Note that the type of this |
||
61 | * property differs in getter and setter. See [[getServers()]] and [[setServers()]] for details. |
||
62 | * |
||
63 | * @author Qiang Xue <[email protected]> |
||
64 | * @since 2.0 |
||
65 | */ |
||
66 | class MemCache extends Cache |
||
67 | { |
||
68 | /** |
||
69 | * @var bool whether to use memcached or memcache as the underlying caching extension. |
||
70 | * If true, [memcached](https://pecl.php.net/package/memcached) will be used. |
||
71 | * If false, [memcache](https://pecl.php.net/package/memcache) will be used. |
||
72 | * Defaults to false. |
||
73 | */ |
||
74 | public $useMemcached = false; |
||
75 | /** |
||
76 | * @var string an ID that identifies a Memcached instance. This property is used only when [[useMemcached]] is true. |
||
77 | * By default the Memcached instances are destroyed at the end of the request. To create an instance that |
||
78 | * persists between requests, you may specify a unique ID for the instance. All instances created with the |
||
79 | * same ID will share the same connection. |
||
80 | * @see https://secure.php.net/manual/en/memcached.construct.php |
||
81 | */ |
||
82 | public $persistentId; |
||
83 | /** |
||
84 | * @var array options for Memcached. This property is used only when [[useMemcached]] is true. |
||
85 | * @see https://secure.php.net/manual/en/memcached.setoptions.php |
||
86 | */ |
||
87 | public $options; |
||
88 | /** |
||
89 | * @var string memcached sasl username. This property is used only when [[useMemcached]] is true. |
||
90 | * @see https://secure.php.net/manual/en/memcached.setsaslauthdata.php |
||
91 | */ |
||
92 | public $username; |
||
93 | /** |
||
94 | * @var string memcached sasl password. This property is used only when [[useMemcached]] is true. |
||
95 | * @see https://secure.php.net/manual/en/memcached.setsaslauthdata.php |
||
96 | */ |
||
97 | public $password; |
||
98 | |||
99 | /** |
||
100 | * @var \Memcache|\Memcached the Memcache instance |
||
101 | */ |
||
102 | private $_cache; |
||
103 | /** |
||
104 | * @var array list of memcache server configurations |
||
105 | */ |
||
106 | private $_servers = []; |
||
107 | |||
108 | |||
109 | /** |
||
110 | * Initializes this application component. |
||
111 | * It creates the memcache instance and adds memcache servers. |
||
112 | */ |
||
113 | 32 | public function init() |
|
114 | { |
||
115 | 32 | parent::init(); |
|
116 | 32 | $this->addServers($this->getMemcache(), $this->getServers()); |
|
117 | 32 | } |
|
118 | |||
119 | /** |
||
120 | * Add servers to the server pool of the cache specified. |
||
121 | * |
||
122 | * @param \Memcache|\Memcached $cache |
||
123 | * @param MemCacheServer[] $servers |
||
124 | * @throws InvalidConfigException |
||
125 | */ |
||
126 | 32 | protected function addServers($cache, $servers) |
|
127 | { |
||
128 | 32 | if (empty($servers)) { |
|
129 | 32 | $servers = [new MemCacheServer([ |
|
130 | 32 | 'host' => '127.0.0.1', |
|
131 | 'port' => 11211, |
||
132 | ])]; |
||
133 | } else { |
||
134 | foreach ($servers as $server) { |
||
135 | if ($server->host === null) { |
||
136 | throw new InvalidConfigException("The 'host' property must be specified for every memcache server."); |
||
137 | } |
||
138 | } |
||
139 | } |
||
140 | 32 | if ($this->useMemcached) { |
|
141 | 16 | $this->addMemcachedServers($cache, $servers); |
|
142 | } else { |
||
143 | 16 | $this->addMemcacheServers($cache, $servers); |
|
144 | } |
||
145 | 32 | } |
|
146 | |||
147 | /** |
||
148 | * Add servers to the server pool of the cache specified |
||
149 | * Used for memcached PECL extension. |
||
150 | * |
||
151 | * @param \Memcached $cache |
||
152 | * @param MemCacheServer[] $servers |
||
153 | */ |
||
154 | 16 | protected function addMemcachedServers($cache, $servers) |
|
155 | { |
||
156 | 16 | $existingServers = []; |
|
157 | 16 | if ($this->persistentId !== null) { |
|
158 | foreach ($cache->getServerList() as $s) { |
||
159 | $existingServers[$s['host'] . ':' . $s['port']] = true; |
||
160 | } |
||
161 | } |
||
162 | 16 | foreach ($servers as $server) { |
|
163 | 16 | if (empty($existingServers) || !isset($existingServers[$server->host . ':' . $server->port])) { |
|
164 | 16 | $cache->addServer($server->host, $server->port, $server->weight); |
|
165 | } |
||
166 | } |
||
167 | 16 | } |
|
168 | |||
169 | /** |
||
170 | * Add servers to the server pool of the cache specified |
||
171 | * Used for memcache PECL extension. |
||
172 | * |
||
173 | * @param \Memcache $cache |
||
174 | * @param MemCacheServer[] $servers |
||
175 | */ |
||
176 | 16 | protected function addMemcacheServers($cache, $servers) |
|
177 | { |
||
178 | 16 | $class = new \ReflectionClass($cache); |
|
179 | 16 | $paramCount = $class->getMethod('addServer')->getNumberOfParameters(); |
|
180 | 16 | foreach ($servers as $server) { |
|
181 | // $timeout is used for memcache versions that do not have $timeoutms parameter |
||
182 | 16 | $timeout = (int) ($server->timeout / 1000) + (($server->timeout % 1000 > 0) ? 1 : 0); |
|
183 | 16 | if ($paramCount === 9) { |
|
184 | $cache->addserver( |
||
185 | $server->host, |
||
186 | $server->port, |
||
187 | $server->persistent, |
||
188 | $server->weight, |
||
189 | $timeout, |
||
190 | $server->retryInterval, |
||
191 | $server->status, |
||
192 | $server->failureCallback, |
||
193 | $server->timeout |
||
194 | ); |
||
195 | } else { |
||
196 | 16 | $cache->addserver( |
|
197 | 16 | $server->host, |
|
198 | 16 | $server->port, |
|
199 | 16 | $server->persistent, |
|
200 | 16 | $server->weight, |
|
201 | 16 | $timeout, |
|
202 | 16 | $server->retryInterval, |
|
203 | 16 | $server->status, |
|
204 | 16 | $server->failureCallback |
|
205 | ); |
||
206 | } |
||
207 | } |
||
208 | 16 | } |
|
209 | |||
210 | /** |
||
211 | * Returns the underlying memcache (or memcached) object. |
||
212 | * @return \Memcache|\Memcached the memcache (or memcached) object used by this cache component. |
||
213 | * @throws InvalidConfigException if memcache or memcached extension is not loaded |
||
214 | */ |
||
215 | 32 | public function getMemcache() |
|
216 | { |
||
217 | 32 | if ($this->_cache === null) { |
|
218 | 32 | $extension = $this->useMemcached ? 'memcached' : 'memcache'; |
|
219 | 32 | if (!extension_loaded($extension)) { |
|
220 | throw new InvalidConfigException("MemCache requires PHP $extension extension to be loaded."); |
||
221 | } |
||
222 | |||
223 | 32 | if ($this->useMemcached) { |
|
224 | 16 | $this->_cache = $this->persistentId !== null ? new \Memcached($this->persistentId) : new \Memcached(); |
|
225 | 16 | if ($this->username !== null || $this->password !== null) { |
|
226 | $this->_cache->setOption(\Memcached::OPT_BINARY_PROTOCOL, true); |
||
227 | $this->_cache->setSaslAuthData($this->username, $this->password); |
||
228 | } |
||
229 | 16 | if (!empty($this->options)) { |
|
230 | 16 | $this->_cache->setOptions($this->options); |
|
231 | } |
||
232 | } else { |
||
233 | 16 | $this->_cache = new \Memcache(); |
|
234 | } |
||
235 | } |
||
236 | |||
237 | 32 | return $this->_cache; |
|
238 | } |
||
239 | |||
240 | /** |
||
241 | * Returns the memcache or memcached server configurations. |
||
242 | * @return MemCacheServer[] list of memcache server configurations. |
||
243 | */ |
||
244 | 32 | public function getServers() |
|
245 | { |
||
246 | 32 | return $this->_servers; |
|
247 | } |
||
248 | |||
249 | /** |
||
250 | * @param array $config list of memcache or memcached server configurations. Each element must be an array |
||
251 | * with the following keys: host, port, persistent, weight, timeout, retryInterval, status. |
||
252 | * @see https://secure.php.net/manual/en/memcache.addserver.php |
||
253 | * @see https://secure.php.net/manual/en/memcached.addserver.php |
||
254 | */ |
||
255 | public function setServers($config) |
||
256 | { |
||
257 | foreach ($config as $c) { |
||
258 | $this->_servers[] = new MemCacheServer($c); |
||
259 | } |
||
260 | } |
||
261 | |||
262 | /** |
||
263 | * Retrieves a value from cache with a specified key. |
||
264 | * This is the implementation of the method declared in the parent class. |
||
265 | * @param string $key a unique key identifying the cached value |
||
266 | * @return mixed|false the value stored in cache, false if the value is not in the cache or expired. |
||
267 | */ |
||
268 | 26 | protected function getValue($key) |
|
269 | { |
||
270 | 26 | return $this->_cache->get($key); |
|
271 | } |
||
272 | |||
273 | /** |
||
274 | * Retrieves multiple values from cache with the specified keys. |
||
275 | * @param array $keys a list of keys identifying the cached values |
||
276 | * @return array a list of cached values indexed by the keys |
||
277 | */ |
||
278 | 4 | protected function getValues($keys) |
|
279 | { |
||
280 | 4 | return $this->useMemcached ? $this->_cache->getMulti($keys) : $this->_cache->get($keys); |
|
281 | } |
||
282 | |||
283 | /** |
||
284 | * Stores a value identified by a key in cache. |
||
285 | * This is the implementation of the method declared in the parent class. |
||
286 | * |
||
287 | * @param string $key the key identifying the value to be cached |
||
288 | * @param mixed $value the value to be cached. |
||
289 | * @see [Memcache::set()](https://secure.php.net/manual/en/memcache.set.php) |
||
290 | * @param int $duration the number of seconds in which the cached value will expire. 0 means never expire. |
||
291 | * @return bool true if the value is successfully stored into cache, false otherwise |
||
292 | */ |
||
293 | 26 | protected function setValue($key, $value, $duration) |
|
294 | { |
||
295 | 26 | $expire = $this->normalizeDuration($duration); |
|
296 | 26 | return $this->useMemcached ? $this->_cache->set($key, $value, $expire) : $this->_cache->set($key, $value, 0, $expire); |
|
297 | } |
||
298 | |||
299 | /** |
||
300 | * Stores multiple key-value pairs in cache. |
||
301 | * @param array $data array where key corresponds to cache key while value is the value stored |
||
302 | * @param int $duration the number of seconds in which the cached values will expire. 0 means never expire. |
||
303 | * @return array array of failed keys. |
||
304 | */ |
||
305 | 6 | protected function setValues($data, $duration) |
|
306 | { |
||
307 | 6 | if ($this->useMemcached) { |
|
308 | 3 | $expire = $this->normalizeDuration($duration); |
|
309 | |||
310 | // Memcached::setMulti() returns boolean |
||
311 | // @see https://secure.php.net/manual/en/memcached.setmulti.php |
||
312 | 3 | return $this->_cache->setMulti($data, $expire) ? [] : array_keys($data); |
|
0 ignored issues
–
show
|
|||
313 | } |
||
314 | |||
315 | 3 | return parent::setValues($data, $duration); |
|
316 | } |
||
317 | |||
318 | /** |
||
319 | * Stores a value identified by a key into cache if the cache does not contain this key. |
||
320 | * This is the implementation of the method declared in the parent class. |
||
321 | * |
||
322 | * @param string $key the key identifying the value to be cached |
||
323 | * @param mixed $value the value to be cached |
||
324 | * @see [Memcache::set()](https://secure.php.net/manual/en/memcache.set.php) |
||
325 | * @param int $duration the number of seconds in which the cached value will expire. 0 means never expire. |
||
326 | * @return bool true if the value is successfully stored into cache, false otherwise |
||
327 | */ |
||
328 | 4 | protected function addValue($key, $value, $duration) |
|
329 | { |
||
330 | 4 | $expire = $this->normalizeDuration($duration); |
|
331 | 4 | return $this->useMemcached ? $this->_cache->add($key, $value, $expire) : $this->_cache->add($key, $value, 0, $expire); |
|
332 | } |
||
333 | |||
334 | /** |
||
335 | * Deletes a value with the specified key from cache |
||
336 | * This is the implementation of the method declared in the parent class. |
||
337 | * @param string $key the key of the value to be deleted |
||
338 | * @return bool if no error happens during deletion |
||
339 | */ |
||
340 | 2 | protected function deleteValue($key) |
|
341 | { |
||
342 | 2 | return $this->_cache->delete($key, 0); |
|
343 | } |
||
344 | |||
345 | /** |
||
346 | * Deletes all values from cache. |
||
347 | * This is the implementation of the method declared in the parent class. |
||
348 | * @return bool whether the flush operation was successful. |
||
349 | */ |
||
350 | 22 | protected function flushValues() |
|
351 | { |
||
352 | 22 | return $this->_cache->flush(); |
|
353 | } |
||
354 | |||
355 | /** |
||
356 | * Normalizes duration value |
||
357 | * |
||
358 | * @see https://github.com/yiisoft/yii2/issues/17710 |
||
359 | * @see https://secure.php.net/manual/en/memcache.set.php |
||
360 | * @see https://secure.php.net/manual/en/memcached.expiration.php |
||
361 | * |
||
362 | * @since 2.0.31 |
||
363 | * @param int $duration |
||
364 | * @return int |
||
365 | */ |
||
366 | 28 | protected function normalizeDuration($duration) |
|
367 | { |
||
368 | 28 | if ($duration < 0) { |
|
369 | return 0; |
||
370 | } |
||
371 | |||
372 | 28 | if ($duration < 2592001) { |
|
373 | 28 | return $duration; |
|
374 | } |
||
375 | |||
376 | return $duration + time(); |
||
377 | } |
||
378 | } |
||
379 |
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.
This is most likely a typographical error or the method has been renamed.