diff --git a/phpBB/phpbb/ban/exception/no_valid_emails_exception.php b/phpBB/phpbb/ban/exception/no_valid_emails_exception.php new file mode 100644 index 0000000000..74079ccc2f --- /dev/null +++ b/phpBB/phpbb/ban/exception/no_valid_emails_exception.php @@ -0,0 +1,20 @@ + + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\ban\exception; + +use phpbb\exception\runtime_exception; + +class no_valid_emails_exception extends runtime_exception +{ +} diff --git a/phpBB/phpbb/ban/exception/no_valid_users_exception.php b/phpBB/phpbb/ban/exception/no_valid_users_exception.php new file mode 100644 index 0000000000..72e231c27e --- /dev/null +++ b/phpBB/phpbb/ban/exception/no_valid_users_exception.php @@ -0,0 +1,20 @@ + + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\ban\exception; + +use phpbb\exception\runtime_exception; + +class no_valid_users_exception extends runtime_exception +{ +} diff --git a/phpBB/phpbb/ban/manager.php b/phpBB/phpbb/ban/manager.php index 5a79f2d836..221dbef99d 100644 --- a/phpBB/phpbb/ban/manager.php +++ b/phpBB/phpbb/ban/manager.php @@ -18,6 +18,9 @@ use phpbb\ban\exception\type_not_found_exception; class manager { + const CACHE_KEY = '_ban_info'; + const CACHE_TTL = 3600; + protected $ban_table; protected $cache; @@ -51,17 +54,18 @@ class manager public function ban($mode, array $items, \DateTimeInterface $start, \DateTimeInterface $end, $reason, $display_reason = '') { - if (!isset($this->types[$mode])) - { - throw new type_not_found_exception(); // TODO - } if ($start > $end && $end->getTimestamp() !== 0) { throw new invalid_length_exception(); // TODO } /** @var \phpbb\ban\type\type_interface $ban_mode */ - $ban_mode = $this->types[$mode]; + $ban_mode = $this->find_type($mode); + if ($ban_mode === false) + { + throw new type_not_found_exception(); // TODO + } + $ban_items = $ban_mode->prepare_for_storage($items); // Prevent duplicate bans @@ -169,17 +173,17 @@ class manager } } - $this->cache->destroy('sql', $this->ban_table); + $this->cache->destroy(self::CACHE_KEY); } public function unban($mode, array $items) { - if (!isset($this->types[$mode])) + /** @var \phpbb\ban\type\type_interface $ban_mode */ + $ban_mode = $this->find_type($mode); + if ($ban_mode === false) { throw new type_not_found_exception(); // TODO } - /** @var \phpbb\ban\type\type_interface $ban_mode */ - $ban_mode = $this->types[$mode]; $sql_ids = array_map('intval', $items); $sql = 'SELECT ban_item @@ -215,15 +219,117 @@ class manager ]; $ban_mode->after_unban($unban_data); - $this->cache->destroy('sql', $this->ban_table); + $this->cache->destroy(self::CACHE_KEY); } public function check(array $user_data = []) { + if (empty($user_data)) + { + $user_data = $this->user->data; + } + + $ban_info = $this->cache->get(self::CACHE_KEY); + if ($ban_info === false) + { + $sql = 'SELECT ban_mode, ban_item, ban_end, ban_reason_display + FROM ' . $this->ban_table . ' + WHERE 1'; + $result = $this->db->sql_query($sql); + + $ban_info = []; + + while ($row = $this->db->sql_fetchrow($result)) + { + if (!isset($ban_info[$row['ban_mode']])) + { + $ban_info[$row['ban_mode']] = []; + } + + $ban_info[$row['ban_mode']][] = [ + 'item' => $row['ban_item'], + 'end' => $row['ban_end'], + 'reason' => $row['ban_reason_display'], + ]; + } + $this->db->sql_freeresult($result); + + $this->cache->put(self::CACHE_KEY, $ban_info, self::CACHE_TTL); + } + + foreach ($ban_info as $mode => $ban_rows) + { + /** @var \phpbb\ban\type\type_interface $ban_mode */ + $ban_mode = $this->find_type($mode); + if ($ban_mode === false) + { + continue; + } + + if ($ban_mode->get_user_column() === null) + { + $ban_result = $ban_mode->check($ban_rows, $user_data); + if ($ban_result !== false) + { + return $ban_result; + } + } + else + { + $user_column = $ban_mode->get_user_column(); + + foreach ($ban_rows as $ban_row) + { + if ($ban_row['end'] > 0 && $ban_row['end'] < time()) + { + if (stripos($ban_row['item'], '*') === false) + { + if ($ban_row['item'] == $user_data[$user_column]) + { + return $ban_row; + } + } + else + { + $regex = str_replace('\*', '.*?', preg_quote($ban_row['item'], '#')); + if (preg_match($regex, $user_data[$user_column])) + { + return $ban_row; + } + } + } + } + } + } + + return false; } public function tidy() { - // TODO: Delete stale bans + // Delete stale bans + $sql = 'DELETE FROM ' . $this->ban_table . ' + WHERE ban_end > 0 AND ban_end < ' . (int) time(); + $this->db->sql_query($sql); + + /** @var \phpbb\ban\type\type_interface $type */ + foreach ($this->types as $type) + { + $type->tidy(); + } + } + + protected function find_type($mode) + { + /** @var \phpbb\ban\type\type_interface $type */ + foreach ($this->types as $type) + { + if ($type->get_type() === $mode) + { + return $type; + } + } + + return false; } } diff --git a/phpBB/phpbb/ban/type/base.php b/phpBB/phpbb/ban/type/base.php index 5989e653b1..5771b02da1 100644 --- a/phpBB/phpbb/ban/type/base.php +++ b/phpBB/phpbb/ban/type/base.php @@ -52,11 +52,14 @@ abstract class base implements type_interface /** * {@inheritDoc} */ - public function check(array $data) + public function check(array $ban_rows, array $user_data) { return false; } + /** + * {@inheritDoc} + */ public function tidy() { } diff --git a/phpBB/phpbb/ban/type/email.php b/phpBB/phpbb/ban/type/email.php index 1cc5fedfea..b26d4990b6 100644 --- a/phpBB/phpbb/ban/type/email.php +++ b/phpBB/phpbb/ban/type/email.php @@ -13,6 +13,10 @@ namespace phpbb\ban\type; +use phpbb\ban\exception\no_valid_emails_exception; +use phpbb\ban\exception\no_valid_users_exception; +use phpbb\exception\runtime_exception; + class email extends base { public function get_ban_log_string() @@ -48,9 +52,9 @@ class email extends base { if (!$this->get_excluded()) { - // TODO throw exception + throw new runtime_exception(); // TODO } - $regex = get_preg_expression('email'); + $regex = '#^.*?@*|(([a-z0-9\-]+\.)+([a-z]{2,3}))$#i'; $ban_items = []; foreach ($items as $item) @@ -65,7 +69,7 @@ class email extends base if (empty($ban_items)) { - // TODO throw exception - no valid emails defined + throw new no_valid_emails_exception(); // TODO } return $ban_items; diff --git a/phpBB/phpbb/ban/type/type_interface.php b/phpBB/phpbb/ban/type/type_interface.php index 0b6b4b4ea9..143d6a3041 100644 --- a/phpBB/phpbb/ban/type/type_interface.php +++ b/phpBB/phpbb/ban/type/type_interface.php @@ -13,6 +13,8 @@ namespace phpbb\ban\type; +use phpbb\mimetype\null_guesser; + /** * Interface implemented by all ban types */ @@ -82,13 +84,17 @@ interface type_interface * Please note, that this method is basically called on every page, * so the check should perform rather fast. * - * Returns true if the person is banned and false otherwise. + * Returns an array with information about the ban, like the end or + * the reason. False if the user is not banned. * - * @param array $data The user data array + * @param array $ban_rows An array containing the ban rows retrieved + * from the database for this specific mode. + * They contain the item, reason and end of the ban. + * @param array $user_data The user data * - * @return bool + * @return array|bool */ - public function check(array $data); + public function check(array $ban_rows, array $user_data); /** * Prepares the given ban items before saving them in the database @@ -99,5 +105,11 @@ interface type_interface */ public function prepare_for_storage(array $items); - public function tidy(); // ??? + /** + * Does some cleanup work for the banning mode. + * Is called before banning and unbanning and as cron job. + * + * @return null + */ + public function tidy(); } diff --git a/phpBB/phpbb/ban/type/user.php b/phpBB/phpbb/ban/type/user.php index 85a9064399..fe0e2adbe1 100644 --- a/phpBB/phpbb/ban/type/user.php +++ b/phpBB/phpbb/ban/type/user.php @@ -13,6 +13,9 @@ namespace phpbb\ban\type; +use phpbb\ban\exception\no_valid_users_exception; +use phpbb\exception\runtime_exception; + class user extends base { /** @var array */ @@ -137,7 +140,7 @@ class user extends base { if (!$this->get_excluded()) { - // TODO throw exception + throw new runtime_exception(); // TODO } $sql_usernames = []; @@ -183,6 +186,11 @@ class user extends base } $this->db->sql_freeresult($result); + if (empty($ban_items)) + { + throw new no_valid_users_exception(); // TODO + } + return $ban_items; } }