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