1: <?php
2: /**
3: * Xcache 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.4947
16: * @license http://www.opensource.org/licenses/mit-license.php MIT License
17: */
18:
19: /**
20: * Xcache storage engine for cache
21: *
22: * @link http://trac.lighttpd.net/xcache/ Xcache
23: * @package Cake.Cache.Engine
24: */
25: class XcacheEngine extends CacheEngine {
26:
27: /**
28: * Settings
29: *
30: * - PHP_AUTH_USER = xcache.admin.user, default cake
31: * - PHP_AUTH_PW = xcache.admin.password, default cake
32: *
33: * @var array
34: */
35: public $settings = array();
36:
37: /**
38: * Initialize the Cache Engine
39: *
40: * Called automatically by the cache frontend
41: * To reinitialize the settings call Cache::engine('EngineName', [optional] settings = array());
42: *
43: * @param array $settings array of setting for the engine
44: * @return bool True if the engine has been successfully initialized, false if not
45: */
46: public function init($settings = array()) {
47: if (PHP_SAPI !== 'cli') {
48: parent::init(array_merge(array(
49: 'engine' => 'Xcache',
50: 'prefix' => Inflector::slug(APP_DIR) . '_',
51: 'PHP_AUTH_USER' => 'user',
52: 'PHP_AUTH_PW' => 'password'
53: ), $settings)
54: );
55: return function_exists('xcache_info');
56: }
57: return false;
58: }
59:
60: /**
61: * Write data for key into cache
62: *
63: * @param string $key Identifier for the data
64: * @param mixed $value Data to be cached
65: * @param int $duration How long to cache the data, in seconds
66: * @return bool True if the data was successfully cached, false on failure
67: */
68: public function write($key, $value, $duration) {
69: $expires = time() + $duration;
70: xcache_set($key . '_expires', $expires, $duration);
71: return xcache_set($key, $value, $duration);
72: }
73:
74: /**
75: * Read a key from the cache
76: *
77: * @param string $key Identifier for the data
78: * @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it
79: */
80: public function read($key) {
81: if (xcache_isset($key)) {
82: $time = time();
83: $cachetime = (int)xcache_get($key . '_expires');
84: if ($cachetime < $time || ($time + $this->settings['duration']) < $cachetime) {
85: return false;
86: }
87: return xcache_get($key);
88: }
89: return false;
90: }
91:
92: /**
93: * Increments the value of an integer cached key
94: * If the cache key is not an integer it will be treated as 0
95: *
96: * @param string $key Identifier for the data
97: * @param int $offset How much to increment
98: * @return New incremented value, false otherwise
99: */
100: public function increment($key, $offset = 1) {
101: return xcache_inc($key, $offset);
102: }
103:
104: /**
105: * Decrements the value of an integer cached key.
106: * If the cache key is not an integer it will be treated as 0
107: *
108: * @param string $key Identifier for the data
109: * @param int $offset How much to subtract
110: * @return New decremented value, false otherwise
111: */
112: public function decrement($key, $offset = 1) {
113: return xcache_dec($key, $offset);
114: }
115:
116: /**
117: * Delete a key from the cache
118: *
119: * @param string $key Identifier for the data
120: * @return bool True if the value was successfully deleted, false if it didn't exist or couldn't be removed
121: */
122: public function delete($key) {
123: return xcache_unset($key);
124: }
125:
126: /**
127: * Delete all keys from the cache
128: *
129: * @param bool $check If true no deletes will occur and instead CakePHP will rely
130: * on key TTL values.
131: * @return bool True if the cache was successfully cleared, false otherwise
132: */
133: public function clear($check) {
134: $this->_auth();
135: $max = xcache_count(XC_TYPE_VAR);
136: for ($i = 0; $i < $max; $i++) {
137: xcache_clear_cache(XC_TYPE_VAR, $i);
138: }
139: $this->_auth(true);
140: return true;
141: }
142:
143: /**
144: * Returns the `group value` for each of the configured groups
145: * If the group initial value was not found, then it initializes
146: * the group accordingly.
147: *
148: * @return array
149: */
150: public function groups() {
151: $result = array();
152: foreach ($this->settings['groups'] as $group) {
153: $value = xcache_get($this->settings['prefix'] . $group);
154: if (!$value) {
155: $value = 1;
156: xcache_set($this->settings['prefix'] . $group, $value, 0);
157: }
158: $result[] = $group . $value;
159: }
160: return $result;
161: }
162:
163: /**
164: * Increments the group value to simulate deletion of all keys under a group
165: * old values will remain in storage until they expire.
166: *
167: * @param string $group The group to clear.
168: * @return bool success
169: */
170: public function clearGroup($group) {
171: return (bool)xcache_inc($this->settings['prefix'] . $group, 1);
172: }
173:
174: /**
175: * Populates and reverses $_SERVER authentication values
176: * Makes necessary changes (and reverting them back) in $_SERVER
177: *
178: * This has to be done because xcache_clear_cache() needs to pass Basic Http Auth
179: * (see xcache.admin configuration settings)
180: *
181: * @param bool $reverse Revert changes
182: * @return void
183: */
184: protected function _auth($reverse = false) {
185: static $backup = array();
186: $keys = array('PHP_AUTH_USER' => 'user', 'PHP_AUTH_PW' => 'password');
187: foreach ($keys as $key => $setting) {
188: if ($reverse) {
189: if (isset($backup[$key])) {
190: $_SERVER[$key] = $backup[$key];
191: unset($backup[$key]);
192: } else {
193: unset($_SERVER[$key]);
194: }
195: } else {
196: $value = env($key);
197: if (!empty($value)) {
198: $backup[$key] = $value;
199: }
200: if (!empty($this->settings[$setting])) {
201: $_SERVER[$key] = $this->settings[$setting];
202: } elseif (!empty($this->settings[$key])) {
203: $_SERVER[$key] = $this->settings[$key];
204: } else {
205: $_SERVER[$key] = $value;
206: }
207: }
208: }
209: }
210:
211: /**
212: * Write data for key into cache if it doesn't exist already.
213: * If it already exists, it fails and returns false.
214: *
215: * @param string $key Identifier for the data.
216: * @param mixed $value Data to be cached.
217: * @param int $duration How long to cache the data, in seconds.
218: * @return bool True if the data was successfully cached, false on failure.
219: */
220: public function add($key, $value, $duration) {
221: $cachedValue = $this->read($key);
222: if ($cachedValue === false) {
223: return $this->write($key, $value, $duration);
224: }
225: return false;
226: }
227: }
228: