Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
43.04% |
34 / 79 |
|
0.00% |
0 / 10 |
CRAP | |
0.00% |
0 / 1 |
memory | |
43.04% |
34 / 79 |
|
0.00% |
0 / 10 |
320.12 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
30 | |||
load | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
save | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
tidy | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
get | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
20 | |||
put | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
destroy | |
52.63% |
10 / 19 |
|
0.00% |
0 / 1 |
20.63 | |||
_exists | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
12 | |||
sql_save | |
96.00% |
24 / 25 |
|
0.00% |
0 / 1 |
9 | |||
_isset | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
_delete | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
_write | n/a |
0 / 0 |
n/a |
0 / 0 |
0 |
1 | <?php |
2 | /** |
3 | * |
4 | * This file is part of the phpBB Forum Software package. |
5 | * |
6 | * @copyright (c) phpBB Limited <https://www.phpbb.com> |
7 | * @license GNU General Public License, version 2 (GPL-2.0) |
8 | * |
9 | * For full copyright and license information, please see |
10 | * the docs/CREDITS.txt file. |
11 | * |
12 | */ |
13 | |
14 | namespace phpbb\cache\driver; |
15 | |
16 | /** |
17 | * ACM Abstract Memory Class |
18 | */ |
19 | abstract class memory extends \phpbb\cache\driver\base |
20 | { |
21 | var $key_prefix; |
22 | |
23 | /** |
24 | * Set cache path |
25 | */ |
26 | function __construct() |
27 | { |
28 | global $dbname, $table_prefix, $phpbb_container; |
29 | |
30 | $this->cache_dir = $phpbb_container->getParameter('core.cache_dir'); |
31 | $this->key_prefix = substr(md5($dbname . $table_prefix), 0, 8) . '_'; |
32 | |
33 | if (!isset($this->extension) || !extension_loaded($this->extension)) |
34 | { |
35 | global $acm_type; |
36 | |
37 | trigger_error("Could not find required extension [{$this->extension}] for the ACM module $acm_type.", E_USER_ERROR); |
38 | } |
39 | |
40 | if (isset($this->function) && !function_exists($this->function)) |
41 | { |
42 | global $acm_type; |
43 | |
44 | trigger_error("The required function [{$this->function}] is not available for the ACM module $acm_type.", E_USER_ERROR); |
45 | } |
46 | } |
47 | |
48 | /** |
49 | * {@inheritDoc} |
50 | */ |
51 | function load() |
52 | { |
53 | // grab the global cache |
54 | $data = $this->_read('global'); |
55 | |
56 | if ($data !== false) |
57 | { |
58 | $this->vars = $data; |
59 | return true; |
60 | } |
61 | |
62 | return false; |
63 | } |
64 | |
65 | /** |
66 | * {@inheritDoc} |
67 | */ |
68 | function save() |
69 | { |
70 | if (!$this->is_modified) |
71 | { |
72 | return; |
73 | } |
74 | |
75 | $this->_write('global', $this->vars, 2592000); |
76 | |
77 | $this->is_modified = false; |
78 | } |
79 | |
80 | /** |
81 | * {@inheritDoc} |
82 | */ |
83 | function tidy() |
84 | { |
85 | global $config; |
86 | |
87 | // cache has auto GC, no need to have any code here :) |
88 | $config->set('cache_last_gc', time(), false); |
89 | } |
90 | |
91 | /** |
92 | * {@inheritDoc} |
93 | */ |
94 | function get($var_name) |
95 | { |
96 | if ($var_name[0] == '_') |
97 | { |
98 | if (!$this->_exists($var_name)) |
99 | { |
100 | return false; |
101 | } |
102 | |
103 | return $this->_read($var_name); |
104 | } |
105 | else |
106 | { |
107 | return ($this->_exists($var_name)) ? $this->vars[$var_name] : false; |
108 | } |
109 | } |
110 | |
111 | /** |
112 | * {@inheritDoc} |
113 | */ |
114 | function put($var_name, $var, $ttl = 2592000) |
115 | { |
116 | if ($var_name[0] == '_') |
117 | { |
118 | $this->_write($var_name, $var, $ttl); |
119 | } |
120 | else |
121 | { |
122 | $this->vars[$var_name] = $var; |
123 | $this->is_modified = true; |
124 | } |
125 | } |
126 | |
127 | /** |
128 | * {@inheritDoc} |
129 | */ |
130 | function destroy($var_name, $table = '') |
131 | { |
132 | if ($var_name == 'sql' && !empty($table)) |
133 | { |
134 | if (!is_array($table)) |
135 | { |
136 | $table = array($table); |
137 | } |
138 | |
139 | foreach ($table as $table_name) |
140 | { |
141 | // gives us the md5s that we want |
142 | $temp = $this->_read('sql_' . $table_name); |
143 | |
144 | if ($temp === false) |
145 | { |
146 | continue; |
147 | } |
148 | |
149 | // delete each query ref |
150 | foreach ($temp as $md5_id => $void) |
151 | { |
152 | $this->_delete('sql_' . $md5_id); |
153 | } |
154 | |
155 | // delete the table ref |
156 | $this->_delete('sql_' . $table_name); |
157 | } |
158 | |
159 | return; |
160 | } |
161 | |
162 | if (!$this->_exists($var_name)) |
163 | { |
164 | return; |
165 | } |
166 | |
167 | if ($var_name[0] == '_') |
168 | { |
169 | $this->_delete($var_name); |
170 | } |
171 | else if (isset($this->vars[$var_name])) |
172 | { |
173 | $this->is_modified = true; |
174 | unset($this->vars[$var_name]); |
175 | |
176 | // We save here to let the following cache hits succeed |
177 | $this->save(); |
178 | } |
179 | } |
180 | |
181 | /** |
182 | * {@inheritDoc} |
183 | */ |
184 | function _exists($var_name) |
185 | { |
186 | if ($var_name[0] == '_') |
187 | { |
188 | return $this->_isset($var_name); |
189 | } |
190 | else |
191 | { |
192 | if (!count($this->vars)) |
193 | { |
194 | $this->load(); |
195 | } |
196 | |
197 | return isset($this->vars[$var_name]); |
198 | } |
199 | } |
200 | |
201 | /** |
202 | * {@inheritDoc} |
203 | */ |
204 | function sql_save(\phpbb\db\driver\driver_interface $db, $query, $query_result, $ttl) |
205 | { |
206 | // Remove extra spaces and tabs |
207 | $query = preg_replace('/[\n\r\s\t]+/', ' ', $query); |
208 | $query_id = md5($query); |
209 | |
210 | // determine which tables this query belongs to |
211 | // Some queries use backticks, namely the get_database_size() query |
212 | // don't check for conformity, the SQL would error and not reach here. |
213 | if (!preg_match_all('/(?:FROM \\(?(`?\\w+`?(?: \\w+)?(?:, ?`?\\w+`?(?: \\w+)?)*)\\)?)|(?:JOIN (`?\\w+`?(?: \\w+)?))/', $query, $regs, PREG_SET_ORDER)) |
214 | { |
215 | // Bail out if the match fails. |
216 | return $query_result; |
217 | } |
218 | |
219 | $tables = array(); |
220 | foreach ($regs as $match) |
221 | { |
222 | if ($match[0][0] == 'F') |
223 | { |
224 | $tables = array_merge($tables, array_map('trim', explode(',', $match[1]))); |
225 | } |
226 | else |
227 | { |
228 | $tables[] = $match[2]; |
229 | } |
230 | } |
231 | |
232 | foreach ($tables as $table_name) |
233 | { |
234 | // Remove backticks |
235 | $table_name = ($table_name[0] == '`') ? substr($table_name, 1, -1) : $table_name; |
236 | |
237 | if (($pos = strpos($table_name, ' ')) !== false) |
238 | { |
239 | $table_name = substr($table_name, 0, $pos); |
240 | } |
241 | |
242 | $temp = $this->_read('sql_' . $table_name); |
243 | |
244 | if ($temp === false) |
245 | { |
246 | $temp = array(); |
247 | } |
248 | |
249 | $temp[$query_id] = true; |
250 | |
251 | // This must never expire |
252 | $this->_write('sql_' . $table_name, $temp, 0); |
253 | } |
254 | |
255 | // store them in the right place |
256 | $this->sql_rowset[$query_id] = array(); |
257 | $this->sql_row_pointer[$query_id] = 0; |
258 | |
259 | while ($row = $db->sql_fetchrow($query_result)) |
260 | { |
261 | $this->sql_rowset[$query_id][] = $row; |
262 | } |
263 | $db->sql_freeresult($query_result); |
264 | |
265 | $this->_write('sql_' . $query_id, $this->sql_rowset[$query_id], $ttl); |
266 | |
267 | return $query_id; |
268 | } |
269 | |
270 | /** |
271 | * Check if a cache var exists |
272 | * |
273 | * @param string $var Cache key |
274 | * |
275 | * @return bool True if it exists, otherwise false |
276 | */ |
277 | protected function _isset(string $var): bool |
278 | { |
279 | // Most caches don't need to check |
280 | return true; |
281 | } |
282 | |
283 | /** |
284 | * Remove an item from the cache |
285 | * |
286 | * @param string $var Cache key |
287 | * |
288 | * @return bool True if the operation succeeded |
289 | */ |
290 | abstract protected function _delete(string $var): bool; |
291 | |
292 | /** |
293 | * Store data in the cache |
294 | * |
295 | * @param string $var Cache key |
296 | * @param mixed $data Data to store |
297 | * @param int $ttl Time-to-live of cached data |
298 | * |
299 | * @return bool True if the operation succeeded |
300 | */ |
301 | abstract protected function _write(string $var, $data, int $ttl = 2592000): bool; |
302 | } |