1 | <?php |
||
2 | /** |
||
3 | * EGroupware API: Caching provider storing data in PHP's APCu extension |
||
4 | * |
||
5 | * @link http://www.egroupware.org |
||
6 | * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License |
||
7 | * @package api |
||
8 | * @subpackage cache |
||
9 | * @author Ralf Becker <RalfBecker-AT-outdoor-training.de> |
||
10 | * @copyright (c) 2010-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de> |
||
11 | * @version $Id$ |
||
12 | */ |
||
13 | |||
14 | namespace EGroupware\Api\Cache; |
||
15 | |||
16 | /** |
||
17 | * Caching provider storing data in PHP's APCu extension / shared memory. |
||
18 | * |
||
19 | * The provider concats all $keys with '::' to get a single string. |
||
20 | * |
||
21 | * This provider is used by default, if it is available or explicit enabled in your header.inc.php: |
||
22 | * $GLOBALS['egw_info']['server']['cache_provider_instance'] = array('EGroupware\Api\Cache\Apc'); |
||
23 | * and optional also $GLOBALS['egw_info']['server']['cache_provider_tree'] (defaults to instance) |
||
24 | * |
||
25 | * APC(u) and CLI: |
||
26 | * -------------- |
||
27 | * APC(u) is not enabled by default for CLI (apc.enable_cli), nor would it access same shared memory! |
||
28 | * It makes no sense to fall back to files cache, as this is probably quite outdated, |
||
29 | * if PHP via Webserver uses APC. Better to use no cache at all. |
||
30 | * Api\Cache::get*() will return NULL for not found and Api\Cache::[un]set*() |
||
31 | * false for not being able to (un)set anything. |
||
32 | * It also does not make sense to report failure by throwing an Exception and filling |
||
33 | * up cron logs. |
||
34 | * --> if APC(u) is available for Webserver, we report availability for CLI too, |
||
35 | * but use no cache at all! |
||
36 | */ |
||
37 | class Apcu extends Base implements Provider |
||
38 | { |
||
39 | /** |
||
40 | * Constructor, eg. opens the connection to the backend |
||
41 | * |
||
42 | * @throws Exception if connection to backend could not be established |
||
43 | * @param array $params eg. array('localhost'[,'localhost:11211',...]) |
||
44 | */ |
||
45 | function __construct(array $params) |
||
46 | { |
||
47 | if (!function_exists('apcu_fetch')) // apc >= 3.0 |
||
48 | { |
||
49 | throw new Exception (__METHOD__.'('.array2string($params).") No function apcu_fetch()!"); |
||
50 | } |
||
51 | } |
||
52 | |||
53 | /** |
||
54 | * Check if APC is available for caching user data |
||
55 | * |
||
56 | * Default shared memory size of 32M, which is used only for user data in APCu. |
||
57 | * Unlike APC which shares the total memory with it's opcode cache 32M is ok |
||
58 | * for a small install. |
||
59 | * |
||
60 | * @return boolean true: apc available, false: not |
||
61 | */ |
||
62 | public static function available() |
||
63 | { |
||
64 | if (($available = (bool)ini_get('apc.enabled') && function_exists('apcu_fetch'))) |
||
65 | { |
||
66 | $size = ini_get('apc.shm_size'); |
||
67 | |||
68 | switch(strtoupper(substr($size, -1))) |
||
69 | { |
||
70 | case 'G': |
||
71 | $size *= 1024; |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
![]() |
|||
72 | case 'M': |
||
73 | $size *= 1024; |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
|
|||
74 | case 'K': |
||
75 | $size *= 1024; |
||
76 | } |
||
77 | $size *= ini_get('apc.shm_segments'); |
||
78 | |||
79 | // only cache in APCu, if we have at least 32M available (default is 32M) |
||
80 | $available = $size >= 33554432; |
||
81 | } |
||
82 | //error_log(__METHOD__."() size=$size returning ".array2string($available)); |
||
83 | return $available; |
||
84 | } |
||
85 | |||
86 | /** |
||
87 | * Stores some data in the cache, if it does NOT already exists there |
||
88 | * |
||
89 | * @param array $keys eg. array($level,$app,$location) |
||
90 | * @param mixed $data |
||
91 | * @param int $expiration =0 |
||
92 | * @return boolean true on success, false on error, incl. key already exists in cache |
||
93 | */ |
||
94 | function add(array $keys,$data,$expiration=0) |
||
95 | { |
||
96 | return apcu_add(self::key($keys),$data,$expiration); |
||
97 | } |
||
98 | |||
99 | /** |
||
100 | * Stores some data in the cache |
||
101 | * |
||
102 | * @param array $keys eg. array($level,$app,$location) |
||
103 | * @param mixed $data |
||
104 | * @param int $expiration =0 |
||
105 | * @return boolean true on success, false on error |
||
106 | */ |
||
107 | function set(array $keys,$data,$expiration=0) |
||
108 | { |
||
109 | return apcu_store(self::key($keys),$data,$expiration); |
||
110 | } |
||
111 | |||
112 | /** |
||
113 | * Get some data from the cache |
||
114 | * |
||
115 | * @param array $keys eg. array($level,$app,$location) |
||
116 | * @return mixed data stored or NULL if not found in cache |
||
117 | */ |
||
118 | function get(array $keys) |
||
119 | { |
||
120 | $success = null; |
||
121 | $data = apcu_fetch($key=self::key($keys),$success); |
||
122 | |||
123 | if (!$success) |
||
124 | { |
||
125 | //error_log(__METHOD__."(".array2string($keys).") key='$key' NOT found!"); |
||
126 | return null; |
||
127 | } |
||
128 | //error_log(__METHOD__."(".array2string($keys).") key='$key' found ".bytes(serialize($data))." bytes)."); |
||
129 | return $data; |
||
130 | } |
||
131 | |||
132 | /** |
||
133 | * Delete some data from the cache |
||
134 | * |
||
135 | * @param array $keys eg. array($level,$app,$location) |
||
136 | * @return boolean true on success, false on error (eg. $key not set) |
||
137 | */ |
||
138 | function delete(array $keys) |
||
139 | { |
||
140 | return apcu_delete(self::key($keys)); |
||
141 | } |
||
142 | |||
143 | /** |
||
144 | * Delete all data under given keys |
||
145 | * |
||
146 | * If no keys are given whole APCu cache is cleared, which should allways |
||
147 | * work and can not run out of memory as the iterator sometimes does. |
||
148 | * |
||
149 | * @param array $keys eg. array($level,$app,$location) or array() to clear whole cache |
||
150 | * @return boolean true on success, false on error (eg. on iterator available) |
||
151 | */ |
||
152 | function flush(array $keys) |
||
153 | { |
||
154 | // do NOT try instanciating APCuIterator, if APCu is not enabled, as it gives a PHP Fatal Error |
||
155 | if (!ini_get('apc.enabled') || php_sapi_name() === 'cli' && !ini_get('apc.cli_enabled')) |
||
156 | { |
||
157 | return false; |
||
158 | } |
||
159 | if (!$keys && function_exists('apcu_clear_cache')) |
||
0 ignored issues
–
show
The expression
$keys of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||
160 | { |
||
161 | apcu_clear_cache(); |
||
162 | |||
163 | return true; |
||
164 | } |
||
165 | // APCu > 5 has APCUIterator |
||
166 | if (class_exists('APCUIterator')) |
||
167 | { |
||
168 | $iterator = new \APCUIterator($preg='/^'.preg_quote(self::key($keys).'/')); |
||
169 | } |
||
170 | // APC >= 3.1.1, but also seems to be missing if apc is disabled eg. for cli |
||
171 | elseif(class_exists('APCIterator')) |
||
172 | { |
||
173 | $iterator = new \APCIterator('user', $preg='/^'.preg_quote(self::key($keys).'/')); |
||
174 | } |
||
175 | else |
||
176 | { |
||
177 | if (function_exists('apcu_clear_cache')) apcu_clear_cache(); |
||
178 | |||
179 | return false; |
||
180 | } |
||
181 | foreach($iterator as $item) |
||
182 | { |
||
183 | //error_log(__METHOD__."(".array2string($keys).") preg='$preg': calling apcu_delete('$item[key]')"); |
||
184 | apcu_delete($item['key']); |
||
185 | } |
||
186 | return true; |
||
187 | } |
||
188 | |||
189 | /** |
||
190 | * Create a single key from $keys |
||
191 | * |
||
192 | * @param array $keys |
||
193 | * @return string |
||
194 | */ |
||
195 | private static function key(array $keys) |
||
196 | { |
||
197 | return implode('::',$keys); |
||
198 | } |
||
199 | } |
||
200 |