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 | } |