1: <?php
2: /**
3: * APC storage engine for cache.
4: *
5: * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
6: * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
7: *
8: * Licensed under The MIT License
9: * For full copyright and license information, please see the LICENSE.txt
10: * Redistributions of files must retain the above copyright notice.
11: *
12: * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
13: * @link http://cakephp.org CakePHP(tm) Project
14: * @package Cake.Cache.Engine
15: * @since CakePHP(tm) v 1.2.0.4933
16: * @license http://www.opensource.org/licenses/mit-license.php MIT License
17: */
18:
19: /**
20: * APC storage engine for cache
21: *
22: * @package Cake.Cache.Engine
23: */
24: class ApcEngine extends CacheEngine {
25:
26: /**
27: * Contains the compiled group names
28: * (prefixed with the global configuration prefix)
29: *
30: * @var array
31: */
32: protected $_compiledGroupNames = array();
33:
34: /**
35: * Initialize the Cache Engine
36: *
37: * Called automatically by the cache frontend
38: * To reinitialize the settings call Cache::engine('EngineName', [optional] settings = array());
39: *
40: * @param array $settings array of setting for the engine
41: * @return bool True if the engine has been successfully initialized, false if not
42: * @see CacheEngine::__defaults
43: */
44: public function init($settings = array()) {
45: if (!isset($settings['prefix'])) {
46: $settings['prefix'] = Inflector::slug(APP_DIR) . '_';
47: }
48: $settings += array('engine' => 'Apc');
49: parent::init($settings);
50: return function_exists('apc_dec');
51: }
52:
53: /**
54: * Write data for key into cache
55: *
56: * @param string $key Identifier for the data
57: * @param mixed $value Data to be cached
58: * @param int $duration How long to cache the data, in seconds
59: * @return bool True if the data was successfully cached, false on failure
60: */
61: public function write($key, $value, $duration) {
62: $expires = 0;
63: if ($duration) {
64: $expires = time() + $duration;
65: }
66: apc_store($key . '_expires', $expires, $duration);
67: return apc_store($key, $value, $duration);
68: }
69:
70: /**
71: * Read a key from the cache
72: *
73: * @param string $key Identifier for the data
74: * @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it
75: */
76: public function read($key) {
77: $time = time();
78: $cachetime = (int)apc_fetch($key . '_expires');
79: if ($cachetime !== 0 && ($cachetime < $time || ($time + $this->settings['duration']) < $cachetime)) {
80: return false;
81: }
82: return apc_fetch($key);
83: }
84:
85: /**
86: * Increments the value of an integer cached key
87: *
88: * @param string $key Identifier for the data
89: * @param int $offset How much to increment
90: * @return New incremented value, false otherwise
91: */
92: public function increment($key, $offset = 1) {
93: return apc_inc($key, $offset);
94: }
95:
96: /**
97: * Decrements the value of an integer cached key
98: *
99: * @param string $key Identifier for the data
100: * @param int $offset How much to subtract
101: * @return New decremented value, false otherwise
102: */
103: public function decrement($key, $offset = 1) {
104: return apc_dec($key, $offset);
105: }
106:
107: /**
108: * Delete a key from the cache
109: *
110: * @param string $key Identifier for the data
111: * @return bool True if the value was successfully deleted, false if it didn't exist or couldn't be removed
112: */
113: public function delete($key) {
114: return apc_delete($key);
115: }
116:
117: /**
118: * Delete all keys from the cache. This will clear every cache config using APC.
119: *
120: * @param bool $check If true, nothing will be cleared, as entries are removed
121: * from APC as they expired. This flag is really only used by FileEngine.
122: * @return bool True Returns true.
123: */
124: public function clear($check) {
125: if ($check) {
126: return true;
127: }
128: if (class_exists('APCIterator', false)) {
129: $iterator = new APCIterator(
130: 'user',
131: '/^' . preg_quote($this->settings['prefix'], '/') . '/',
132: APC_ITER_NONE
133: );
134: apc_delete($iterator);
135: return true;
136: }
137: $cache = apc_cache_info('user');
138: foreach ($cache['cache_list'] as $key) {
139: if (strpos($key['info'], $this->settings['prefix']) === 0) {
140: apc_delete($key['info']);
141: }
142: }
143: return true;
144: }
145:
146: /**
147: * Returns the `group value` for each of the configured groups
148: * If the group initial value was not found, then it initializes
149: * the group accordingly.
150: *
151: * @return array
152: */
153: public function groups() {
154: if (empty($this->_compiledGroupNames)) {
155: foreach ($this->settings['groups'] as $group) {
156: $this->_compiledGroupNames[] = $this->settings['prefix'] . $group;
157: }
158: }
159:
160: $groups = apc_fetch($this->_compiledGroupNames);
161: if (count($groups) !== count($this->settings['groups'])) {
162: foreach ($this->_compiledGroupNames as $group) {
163: if (!isset($groups[$group])) {
164: apc_store($group, 1);
165: $groups[$group] = 1;
166: }
167: }
168: ksort($groups);
169: }
170:
171: $result = array();
172: $groups = array_values($groups);
173: foreach ($this->settings['groups'] as $i => $group) {
174: $result[] = $group . $groups[$i];
175: }
176: return $result;
177: }
178:
179: /**
180: * Increments the group value to simulate deletion of all keys under a group
181: * old values will remain in storage until they expire.
182: *
183: * @param string $group The group to clear.
184: * @return bool success
185: */
186: public function clearGroup($group) {
187: apc_inc($this->settings['prefix'] . $group, 1, $success);
188: return $success;
189: }
190:
191: }
192: