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