Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
43.57% |
61 / 140 |
|
41.67% |
5 / 12 |
CRAP | |
0.00% |
0 / 1 |
service | |
43.57% |
61 / 140 |
|
41.67% |
5 / 12 |
443.91 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
1 | |||
get_driver | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
deferred_purge | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
set_driver | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
__call | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
obtain_word_list | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
12 | |||
obtain_icons | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
20 | |||
obtain_ranks | |
71.43% |
10 / 14 |
|
0.00% |
0 / 1 |
4.37 | |||
obtain_attach_extensions | |
82.98% |
39 / 47 |
|
0.00% |
0 / 1 |
16.11 | |||
obtain_bots | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
42 | |||
obtain_cfg_items | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
42 | |||
obtain_disallowed_usernames | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
12 |
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; |
15 | |
16 | use phpbb\cache\driver\driver_interface; |
17 | use phpbb\config\config; |
18 | use phpbb\event\dispatcher; |
19 | use phpbb\json\sanitizer as json_sanitizer; |
20 | |
21 | /** |
22 | * Class for grabbing/handling cached entries |
23 | */ |
24 | class service |
25 | { |
26 | /** @var string Name of event used for cache purging */ |
27 | private const PURGE_DEFERRED_ON_EVENT = 'core.garbage_collection'; |
28 | |
29 | /** @var bool Flag whether cache purge has been deferred */ |
30 | private $cache_purge_deferred = false; |
31 | |
32 | /** |
33 | * Cache driver. |
34 | * |
35 | * @var driver_interface |
36 | */ |
37 | protected $driver; |
38 | |
39 | /** |
40 | * The config. |
41 | * |
42 | * @var config |
43 | */ |
44 | protected $config; |
45 | |
46 | /** |
47 | * Database connection. |
48 | * |
49 | * @var \phpbb\db\driver\driver_interface |
50 | */ |
51 | protected $db; |
52 | |
53 | /** @var dispatcher phpBB Event dispatcher */ |
54 | protected $dispatcher; |
55 | |
56 | /** |
57 | * Root path. |
58 | * |
59 | * @var string |
60 | */ |
61 | protected $phpbb_root_path; |
62 | |
63 | /** |
64 | * PHP file extension. |
65 | * |
66 | * @var string |
67 | */ |
68 | protected $php_ext; |
69 | |
70 | /** |
71 | * Creates a cache service around a cache driver |
72 | * |
73 | * @param driver_interface $driver The cache driver |
74 | * @param config $config The config |
75 | * @param \phpbb\db\driver\driver_interface $db Database connection |
76 | * @param dispatcher $dispatcher Event dispatcher |
77 | * @param string $phpbb_root_path Root path |
78 | * @param string $php_ext PHP file extension |
79 | */ |
80 | public function __construct(driver_interface $driver, config $config, \phpbb\db\driver\driver_interface $db, dispatcher $dispatcher, $phpbb_root_path, $php_ext) |
81 | { |
82 | $this->set_driver($driver); |
83 | $this->config = $config; |
84 | $this->db = $db; |
85 | $this->dispatcher = $dispatcher; |
86 | $this->phpbb_root_path = $phpbb_root_path; |
87 | $this->php_ext = $php_ext; |
88 | } |
89 | |
90 | /** |
91 | * Returns the cache driver used by this cache service. |
92 | * |
93 | * @return driver_interface The cache driver |
94 | */ |
95 | public function get_driver() |
96 | { |
97 | return $this->driver; |
98 | } |
99 | |
100 | /** |
101 | * Deferred purge of the cache. |
102 | * |
103 | * A deferred purge will be executed after rendering a page. |
104 | * It is recommended to be used in cases where an instant purge of the cache |
105 | * is not required, i.e. when the goal of a cache purge is to start from a |
106 | * clear cache at the next page load. |
107 | * |
108 | * @return void |
109 | */ |
110 | public function deferred_purge(): void |
111 | { |
112 | if (!$this->cache_purge_deferred) |
113 | { |
114 | $this->dispatcher->addListener(self::PURGE_DEFERRED_ON_EVENT, [$this, 'purge']); |
115 | $this->cache_purge_deferred = true; |
116 | } |
117 | } |
118 | |
119 | /** |
120 | * Replaces the cache driver used by this cache service. |
121 | * |
122 | * @param driver_interface $driver The cache driver |
123 | */ |
124 | public function set_driver(driver_interface $driver) |
125 | { |
126 | $this->driver = $driver; |
127 | } |
128 | |
129 | public function __call($method, $arguments) |
130 | { |
131 | return call_user_func_array(array($this->driver, $method), $arguments); |
132 | } |
133 | |
134 | /** |
135 | * Obtain list of naughty words and build preg style replacement arrays for use by the |
136 | * calling script |
137 | */ |
138 | function obtain_word_list() |
139 | { |
140 | if (($censors = $this->driver->get('_word_censors')) === false) |
141 | { |
142 | $sql = 'SELECT word, replacement |
143 | FROM ' . WORDS_TABLE; |
144 | $result = $this->db->sql_query($sql); |
145 | |
146 | $censors = array(); |
147 | while ($row = $this->db->sql_fetchrow($result)) |
148 | { |
149 | $censors['match'][] = get_censor_preg_expression($row['word']); |
150 | $censors['replace'][] = $row['replacement']; |
151 | } |
152 | $this->db->sql_freeresult($result); |
153 | |
154 | $this->driver->put('_word_censors', $censors); |
155 | } |
156 | |
157 | return $censors; |
158 | } |
159 | |
160 | /** |
161 | * Obtain currently listed icons |
162 | */ |
163 | function obtain_icons() |
164 | { |
165 | if (($icons = $this->driver->get('_icons')) === false) |
166 | { |
167 | // Topic icons |
168 | $sql = 'SELECT * |
169 | FROM ' . ICONS_TABLE . ' |
170 | ORDER BY icons_order'; |
171 | $result = $this->db->sql_query($sql); |
172 | |
173 | $icons = array(); |
174 | while ($row = $this->db->sql_fetchrow($result)) |
175 | { |
176 | $icons[$row['icons_id']]['img'] = $row['icons_url']; |
177 | $icons[$row['icons_id']]['width'] = (int) $row['icons_width']; |
178 | $icons[$row['icons_id']]['height'] = (int) $row['icons_height']; |
179 | $icons[$row['icons_id']]['alt'] = ($row['icons_alt']) ? $row['icons_alt'] : ''; |
180 | $icons[$row['icons_id']]['display'] = (bool) $row['display_on_posting']; |
181 | } |
182 | $this->db->sql_freeresult($result); |
183 | |
184 | $this->driver->put('_icons', $icons); |
185 | } |
186 | |
187 | return $icons; |
188 | } |
189 | |
190 | /** |
191 | * Obtain ranks |
192 | */ |
193 | function obtain_ranks() |
194 | { |
195 | if (($ranks = $this->driver->get('_ranks')) === false) |
196 | { |
197 | $sql = 'SELECT * |
198 | FROM ' . RANKS_TABLE . ' |
199 | ORDER BY rank_min DESC'; |
200 | $result = $this->db->sql_query($sql); |
201 | |
202 | $ranks = array(); |
203 | while ($row = $this->db->sql_fetchrow($result)) |
204 | { |
205 | if ($row['rank_special']) |
206 | { |
207 | unset($row['rank_min']); |
208 | $ranks['special'][$row['rank_id']] = $row; |
209 | } |
210 | else |
211 | { |
212 | $ranks['normal'][$row['rank_id']] = $row; |
213 | } |
214 | } |
215 | $this->db->sql_freeresult($result); |
216 | |
217 | $this->driver->put('_ranks', $ranks); |
218 | } |
219 | |
220 | return $ranks; |
221 | } |
222 | |
223 | /** |
224 | * Obtain allowed extensions |
225 | * |
226 | * @param mixed $forum_id If false then check for private messaging, if int then check for forum id. If true, then only return extension informations. |
227 | * |
228 | * @return array allowed extensions array. |
229 | */ |
230 | function obtain_attach_extensions($forum_id) |
231 | { |
232 | if (($extensions = $this->driver->get('_extensions')) === false) |
233 | { |
234 | $extensions = array( |
235 | '_allowed_post' => array(), |
236 | '_allowed_pm' => array(), |
237 | ); |
238 | |
239 | // The rule is to only allow those extensions defined. ;) |
240 | $sql = 'SELECT e.extension, g.* |
241 | FROM ' . EXTENSIONS_TABLE . ' e, ' . EXTENSION_GROUPS_TABLE . ' g |
242 | WHERE e.group_id = g.group_id |
243 | AND (g.allow_group = 1 OR g.allow_in_pm = 1)'; |
244 | $result = $this->db->sql_query($sql); |
245 | |
246 | while ($row = $this->db->sql_fetchrow($result)) |
247 | { |
248 | $extension = strtolower(trim($row['extension'])); |
249 | |
250 | $extensions[$extension] = array( |
251 | 'display_cat' => (int) $row['cat_id'], |
252 | 'upload_icon' => trim($row['upload_icon']), |
253 | 'max_filesize' => (int) $row['max_filesize'], |
254 | 'allow_group' => $row['allow_group'], |
255 | 'allow_in_pm' => $row['allow_in_pm'], |
256 | 'group_name' => $row['group_name'], |
257 | ); |
258 | |
259 | $allowed_forums = ($row['allowed_forums']) ? unserialize(trim($row['allowed_forums'])) : array(); |
260 | |
261 | // Store allowed extensions forum wise |
262 | if ($row['allow_group']) |
263 | { |
264 | $extensions['_allowed_post'][$extension] = (!count($allowed_forums)) ? 0 : $allowed_forums; |
265 | } |
266 | |
267 | if ($row['allow_in_pm']) |
268 | { |
269 | $extensions['_allowed_pm'][$extension] = 0; |
270 | } |
271 | } |
272 | $this->db->sql_freeresult($result); |
273 | |
274 | $this->driver->put('_extensions', $extensions); |
275 | } |
276 | |
277 | // Forum post |
278 | if ($forum_id === false) |
279 | { |
280 | // We are checking for private messages, therefore we only need to get the pm extensions... |
281 | $return = array('_allowed_' => array()); |
282 | |
283 | foreach ($extensions['_allowed_pm'] as $extension => $check) |
284 | { |
285 | $return['_allowed_'][$extension] = 0; |
286 | $return[$extension] = $extensions[$extension]; |
287 | } |
288 | |
289 | $extensions = $return; |
290 | } |
291 | else if ($forum_id === true) |
292 | { |
293 | return $extensions; |
294 | } |
295 | else |
296 | { |
297 | $forum_id = (int) $forum_id; |
298 | $return = array('_allowed_' => array()); |
299 | |
300 | foreach ($extensions['_allowed_post'] as $extension => $check) |
301 | { |
302 | // Check for allowed forums |
303 | if (is_array($check)) |
304 | { |
305 | $allowed = (!in_array($forum_id, $check)) ? false : true; |
306 | } |
307 | else |
308 | { |
309 | $allowed = true; |
310 | } |
311 | |
312 | if ($allowed) |
313 | { |
314 | $return['_allowed_'][$extension] = 0; |
315 | $return[$extension] = $extensions[$extension]; |
316 | } |
317 | } |
318 | |
319 | $extensions = $return; |
320 | } |
321 | |
322 | if (!isset($extensions['_allowed_'])) |
323 | { |
324 | $extensions['_allowed_'] = array(); |
325 | } |
326 | |
327 | return $extensions; |
328 | } |
329 | |
330 | /** |
331 | * Obtain active bots |
332 | */ |
333 | function obtain_bots() |
334 | { |
335 | if (($bots = $this->driver->get('_bots')) === false) |
336 | { |
337 | switch ($this->db->get_sql_layer()) |
338 | { |
339 | case 'mssql_odbc': |
340 | case 'mssqlnative': |
341 | $sql = 'SELECT user_id, bot_agent, bot_ip |
342 | FROM ' . BOTS_TABLE . ' |
343 | WHERE bot_active = 1 |
344 | ORDER BY LEN(bot_agent) DESC'; |
345 | break; |
346 | |
347 | // LENGTH supported by MySQL, IBM DB2 and Oracle for sure... |
348 | default: |
349 | $sql = 'SELECT user_id, bot_agent, bot_ip |
350 | FROM ' . BOTS_TABLE . ' |
351 | WHERE bot_active = 1 |
352 | ORDER BY LENGTH(bot_agent) DESC'; |
353 | break; |
354 | } |
355 | $result = $this->db->sql_query($sql); |
356 | |
357 | $bots = array(); |
358 | while ($row = $this->db->sql_fetchrow($result)) |
359 | { |
360 | $bots[] = $row; |
361 | } |
362 | $this->db->sql_freeresult($result); |
363 | |
364 | $this->driver->put('_bots', $bots); |
365 | } |
366 | |
367 | return $bots; |
368 | } |
369 | |
370 | /** |
371 | * Obtain cfg file data |
372 | */ |
373 | function obtain_cfg_items($style) |
374 | { |
375 | $parsed_array = $this->driver->get('_cfg_' . $style['style_path']); |
376 | |
377 | if ($parsed_array === false) |
378 | { |
379 | $parsed_array = array(); |
380 | } |
381 | |
382 | $filename = $this->phpbb_root_path . 'styles/' . $style['style_path'] . '/composer.json'; |
383 | |
384 | if (!file_exists($filename)) |
385 | { |
386 | return $parsed_array; |
387 | } |
388 | |
389 | if (!isset($parsed_array['filetime']) || (($this->config['load_tplcompile'] && @filemtime($filename) > $parsed_array['filetime']))) |
390 | { |
391 | // Re-parse cfg file |
392 | $json = file_get_contents($filename); |
393 | $parsed_array = json_sanitizer::decode($json); |
394 | $parsed_array['filetime'] = @filemtime($filename); |
395 | |
396 | $this->driver->put('_cfg_' . $style['style_path'], $parsed_array); |
397 | } |
398 | |
399 | return $parsed_array; |
400 | } |
401 | |
402 | /** |
403 | * Obtain disallowed usernames |
404 | */ |
405 | function obtain_disallowed_usernames() |
406 | { |
407 | if (($usernames = $this->driver->get('_disallowed_usernames')) === false) |
408 | { |
409 | $sql = 'SELECT disallow_username |
410 | FROM ' . DISALLOW_TABLE; |
411 | $result = $this->db->sql_query($sql); |
412 | |
413 | $usernames = array(); |
414 | while ($row = $this->db->sql_fetchrow($result)) |
415 | { |
416 | $usernames[] = str_replace('%', '.*?', preg_quote(utf8_clean_string($row['disallow_username']), '#')); |
417 | } |
418 | $this->db->sql_freeresult($result); |
419 | |
420 | $this->driver->put('_disallowed_usernames', $usernames); |
421 | } |
422 | |
423 | return $usernames; |
424 | } |
425 | } |