1: <?php
2: /**
3: * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
4: * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
5: *
6: * Licensed under The MIT License
7: * For full copyright and license information, please see the LICENSE.txt
8: * Redistributions of files must retain the above copyright notice.
9: *
10: * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
11: * @link https://cakephp.org CakePHP(tm) Project
12: * @since 1.2.0
13: * @license https://opensource.org/licenses/mit-license.php MIT License
14: */
15: namespace Cake\Cache\Engine;
16:
17: use Cake\Cache\CacheEngine;
18:
19: /**
20: * Xcache storage engine for cache
21: *
22: * @link http://trac.lighttpd.net/xcache/ Xcache
23: * @deprecated 3.6.0 Xcache engine has been deprecated and will be removed in 4.0.0.
24: */
25: class XcacheEngine extends CacheEngine
26: {
27:
28: /**
29: * The default config used unless overridden by runtime configuration
30: *
31: * - `duration` Specify how long items in this cache configuration last.
32: * - `groups` List of groups or 'tags' associated to every key stored in this config.
33: * handy for deleting a complete group from cache.
34: * - `prefix` Prefix appended to all entries. Good for when you need to share a keyspace
35: * with either another cache config or another application.
36: * - `probability` Probability of hitting a cache gc cleanup. Setting to 0 will disable
37: * cache::gc from ever being called automatically.
38: * - `PHP_AUTH_USER` xcache.admin.user
39: * - `PHP_AUTH_PW` xcache.admin.password
40: *
41: * @var array
42: */
43: protected $_defaultConfig = [
44: 'duration' => 3600,
45: 'groups' => [],
46: 'prefix' => null,
47: 'probability' => 100,
48: 'PHP_AUTH_USER' => 'user',
49: 'PHP_AUTH_PW' => 'password'
50: ];
51:
52: /**
53: * Initialize the Cache Engine
54: *
55: * Called automatically by the cache frontend
56: *
57: * @param array $config array of setting for the engine
58: * @return bool True if the engine has been successfully initialized, false if not
59: */
60: public function init(array $config = [])
61: {
62: if (!extension_loaded('xcache')) {
63: return false;
64: }
65:
66: parent::init($config);
67:
68: return true;
69: }
70:
71: /**
72: * Write data for key into cache
73: *
74: * @param string $key Identifier for the data
75: * @param mixed $value Data to be cached
76: * @return bool True if the data was successfully cached, false on failure
77: */
78: public function write($key, $value)
79: {
80: $key = $this->_key($key);
81:
82: if (!is_numeric($value)) {
83: $value = serialize($value);
84: }
85:
86: $duration = $this->_config['duration'];
87: $expires = time() + $duration;
88: xcache_set($key . '_expires', $expires, $duration);
89:
90: return xcache_set($key, $value, $duration);
91: }
92:
93: /**
94: * Read a key from the cache
95: *
96: * @param string $key Identifier for the data
97: * @return mixed The cached data, or false if the data doesn't exist,
98: * has expired, or if there was an error fetching it
99: */
100: public function read($key)
101: {
102: $key = $this->_key($key);
103:
104: if (xcache_isset($key)) {
105: $time = time();
106: $cachetime = (int)xcache_get($key . '_expires');
107: if ($cachetime < $time || ($time + $this->_config['duration']) < $cachetime) {
108: return false;
109: }
110:
111: $value = xcache_get($key);
112: if (is_string($value) && !is_numeric($value)) {
113: $value = unserialize($value);
114: }
115:
116: return $value;
117: }
118:
119: return false;
120: }
121:
122: /**
123: * Increments the value of an integer cached key
124: * If the cache key is not an integer it will be treated as 0
125: *
126: * @param string $key Identifier for the data
127: * @param int $offset How much to increment
128: * @return bool|int New incremented value, false otherwise
129: */
130: public function increment($key, $offset = 1)
131: {
132: $key = $this->_key($key);
133:
134: return xcache_inc($key, $offset);
135: }
136:
137: /**
138: * Decrements the value of an integer cached key.
139: * If the cache key is not an integer it will be treated as 0
140: *
141: * @param string $key Identifier for the data
142: * @param int $offset How much to subtract
143: * @return bool|int New decremented value, false otherwise
144: */
145: public function decrement($key, $offset = 1)
146: {
147: $key = $this->_key($key);
148:
149: return xcache_dec($key, $offset);
150: }
151:
152: /**
153: * Delete a key from the cache
154: *
155: * @param string $key Identifier for the data
156: * @return bool True if the value was successfully deleted, false if it didn't exist or couldn't be removed
157: */
158: public function delete($key)
159: {
160: $key = $this->_key($key);
161:
162: return xcache_unset($key);
163: }
164:
165: /**
166: * Delete all keys from the cache
167: *
168: * @param bool $check If true no deletes will occur and instead CakePHP will rely
169: * on key TTL values.
170: * Unused for Xcache engine.
171: * @return bool True if the cache was successfully cleared, false otherwise
172: */
173: public function clear($check)
174: {
175: $this->_auth();
176: $max = xcache_count(XC_TYPE_VAR);
177: for ($i = 0; $i < $max; $i++) {
178: xcache_clear_cache(XC_TYPE_VAR, $i);
179: }
180: $this->_auth(true);
181:
182: return true;
183: }
184:
185: /**
186: * Returns the `group value` for each of the configured groups
187: * If the group initial value was not found, then it initializes
188: * the group accordingly.
189: *
190: * @return array
191: */
192: public function groups()
193: {
194: $result = [];
195: foreach ($this->_config['groups'] as $group) {
196: $value = xcache_get($this->_config['prefix'] . $group);
197: if (!$value) {
198: $value = 1;
199: xcache_set($this->_config['prefix'] . $group, $value, 0);
200: }
201: $result[] = $group . $value;
202: }
203:
204: return $result;
205: }
206:
207: /**
208: * Increments the group value to simulate deletion of all keys under a group
209: * old values will remain in storage until they expire.
210: *
211: * @param string $group The group to clear.
212: * @return bool success
213: */
214: public function clearGroup($group)
215: {
216: return (bool)xcache_inc($this->_config['prefix'] . $group, 1);
217: }
218:
219: /**
220: * Populates and reverses $_SERVER authentication values
221: * Makes necessary changes (and reverting them back) in $_SERVER
222: *
223: * This has to be done because xcache_clear_cache() needs to pass Basic Http Auth
224: * (see xcache.admin configuration config)
225: *
226: * @param bool $reverse Revert changes
227: * @return void
228: */
229: protected function _auth($reverse = false)
230: {
231: static $backup = [];
232: $keys = ['PHP_AUTH_USER' => 'user', 'PHP_AUTH_PW' => 'password'];
233: foreach ($keys as $key => $value) {
234: if ($reverse) {
235: if (isset($backup[$key])) {
236: $_SERVER[$key] = $backup[$key];
237: unset($backup[$key]);
238: } else {
239: unset($_SERVER[$key]);
240: }
241: } else {
242: $value = env($key);
243: if (!empty($value)) {
244: $backup[$key] = $value;
245: }
246: if (!empty($this->_config[$value])) {
247: $_SERVER[$key] = $this->_config[$value];
248: } elseif (!empty($this->_config[$key])) {
249: $_SERVER[$key] = $this->_config[$key];
250: } else {
251: $_SERVER[$key] = $value;
252: }
253: }
254: }
255: }
256: }
257: