From 6d43a7f62bafc8a86405d43de7c30d469825b9bf Mon Sep 17 00:00:00 2001 From: Dedushka Date: Sun, 17 Jan 2021 13:03:17 -0500 Subject: [PATCH] Protect IPs in public moderation logs. As reported, IPv6 addresses were not properly hidden in the public facing moderation logs. This commit filters both IPv4 and IPv6 addresses. We broke out into a separate function so that it can be tested with the test suite. A rudimentary test has been added to test the newly added protect_ip($entry) function. --- inc/mod/pages.php | 1182 ++++++++++++++++++++------------------- tests/ProtectIPTest.php | 32 ++ 2 files changed, 626 insertions(+), 588 deletions(-) create mode 100644 tests/ProtectIPTest.php diff --git a/inc/mod/pages.php b/inc/mod/pages.php index e8b43a62..0ea5328d 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -10,7 +10,7 @@ require_once 'inc/anti-bot.php'; // DELETE ME THIS IS FOR print_err function onl function mod_page($title, $template, $args, $subtitle = false) { global $config, $mod; - + echo Element('page.html', array( 'config' => $config, 'mod' => $mod, @@ -20,7 +20,7 @@ function mod_page($title, $template, $args, $subtitle = false) { 'boardlist' => createBoardlist($mod), 'body' => Element($template, array_merge( - array('config' => $config, 'mod' => $mod), + array('config' => $config, 'mod' => $mod), $args ) ) @@ -30,9 +30,9 @@ function mod_page($title, $template, $args, $subtitle = false) { function mod_login($redirect = false) { global $config; - + $args = array(); - + if (isset($_POST['login'])) { // Check if inputs are set and not empty if (!isset($_POST['username'], $_POST['password']) || $_POST['username'] == '' || $_POST['password'] == '') { @@ -40,22 +40,22 @@ function mod_login($redirect = false) { } elseif (!login($_POST['username'], $_POST['password'])) { if ($config['syslog']) _syslog(LOG_WARNING, 'Unauthorized login attempt!'); - + $args['error'] = $config['error']['invalid']; } else { modLog('Logged in'); - + // Login successful // Set cookies setCookies(); - + if ($redirect) header('Location: ?' . $redirect, true, $config['redirect_http']); else header('Location: ?/', true, $config['redirect_http']); } } - + if (isset($_POST['username'])) $args['username'] = $_POST['username']; @@ -73,53 +73,53 @@ function mod_confirm($request) { function mod_logout() { global $config; destroyCookies(); - + header('Location: ?/', true, $config['redirect_http']); } function mod_dashboard() { global $config, $mod; - + $args = array(); - + $args['boards'] = listBoards(); - + if (hasPermission($config['mod']['noticeboard'])) { if (!$config['cache']['enabled'] || !$args['noticeboard'] = cache::get('noticeboard_preview')) { $query = prepare("SELECT ``noticeboard``.*, `username` FROM ``noticeboard`` LEFT JOIN ``mods`` ON ``mods``.`id` = `mod` ORDER BY `id` DESC LIMIT :limit"); $query->bindValue(':limit', $config['mod']['noticeboard_dashboard'], PDO::PARAM_INT); $query->execute() or error(db_error($query)); $args['noticeboard'] = $query->fetchAll(PDO::FETCH_ASSOC); - + if ($config['cache']['enabled']) cache::set('noticeboard_preview', $args['noticeboard']); } } - + if (!$config['cache']['enabled'] || ($args['unread_pms'] = cache::get('pm_unreadcount_' . $mod['id'])) === false) { $query = prepare('SELECT COUNT(*) FROM ``pms`` WHERE `to` = :id AND `unread` = 1'); $query->bindValue(':id', $mod['id']); $query->execute() or error(db_error($query)); $args['unread_pms'] = $query->fetchColumn(); - + if ($config['cache']['enabled']) cache::set('pm_unreadcount_' . $mod['id'], $args['unread_pms']); } - + $query = query('SELECT COUNT(*) FROM ``reports``') or error(db_error($query)); $args['reports'] = $query->fetchColumn(); - + if ($mod['type'] >= ADMIN && $config['check_updates']) { if (!$config['version']) error(_('Could not find current version! (Check .installed)')); - + if (isset($_COOKIE['update'])) { $latest = unserialize($_COOKIE['update']); } else { $ctx = stream_context_create(array('http' => array('timeout' => 5))); if ($code = @file_get_contents('http://engine.vichan.net/version.txt', 0, $ctx)) { $ver = strtok($code, "\n"); - + if (preg_match('@^// v(\d+)\.(\d+)\.(\d+)\s*?$@', $ver, $matches)) { $latest = array( 'massive' => $matches[1], @@ -132,7 +132,7 @@ function mod_dashboard() { 'major' => (int) $matches[2], 'minor' => (int) $matches[3] ); - if (isset($m[4])) { + if (isset($m[4])) { // Development versions are always ahead in the versioning numbers $current['minor'] --; } @@ -155,36 +155,36 @@ function mod_dashboard() { // Couldn't get latest version $latest = false; } - + setcookie('update', serialize($latest), time() + $config['check_updates_time'], $config['cookies']['jail'] ? $config['cookies']['path'] : '/', null, !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off', true); } - + if ($latest) $args['newer_release'] = $latest; } - + $args['logout_token'] = make_secure_link_token('logout'); - + mod_page(_('Dashboard'), 'mod/dashboard.html', $args); } function mod_search_redirect() { global $config; - + if (!hasPermission($config['mod']['search'])) error($config['error']['noaccess']); - + if (isset($_POST['query'], $_POST['type']) && in_array($_POST['type'], array('posts', 'IP_notes', 'bans', 'log'))) { $query = $_POST['query']; $query = urlencode($query); $query = str_replace('_', '%5F', $query); $query = str_replace('+', '_', $query); - + if ($query === '') { header('Location: ?/', true, $config['redirect_http']); return; } - + header('Location: ?/search/' . $_POST['type'] . '/' . $query, true, $config['redirect_http']); } else { header('Location: ?/', true, $config['redirect_http']); @@ -193,29 +193,29 @@ function mod_search_redirect() { function mod_search($type, $search_query_escaped, $page_no = 1) { global $pdo, $config; - + if (!hasPermission($config['mod']['search'])) error($config['error']['noaccess']); - + // Unescape query $query = str_replace('_', ' ', $search_query_escaped); $query = urldecode($query); $search_query = $query; - + // Form a series of LIKE clauses for the query. // This gets a little complicated. - + // Escape "escape" character $query = str_replace('!', '!!', $query); - + // Escape SQL wildcard $query = str_replace('%', '!%', $query); - + // Use asterisk as wildcard instead $query = str_replace('*', '%', $query); - + $query = str_replace('`', '!`', $query); - + // Array of phrases to match $match = array(); @@ -227,7 +227,7 @@ function mod_search($type, $search_query_escaped, $page_no = 1) { $match[] = $pdo->quote($phrase); } } - + // Non-exact phrases (ie. plain keywords) $keywords = explode(' ', $query); foreach ($keywords as $word) { @@ -235,7 +235,7 @@ function mod_search($type, $search_query_escaped, $page_no = 1) { continue; $match[] = $pdo->quote($word); } - + // Which `field` to search? if ($type == 'posts') $sql_field = array('body_nomarkup', 'files', 'subject', 'filehash', 'ip', 'name', 'trip'); @@ -261,57 +261,57 @@ function mod_search($type, $search_query_escaped, $page_no = 1) { $sql_like .= '`' . $sql_field . '` LIKE ' . $phrase . ' ESCAPE \'!\''; } } - + // Compile SQL query - + if ($type == 'posts') { $query = ''; $boards = listBoards(); if (empty($boards)) error(_('There are no boards to search!')); - + foreach ($boards as $board) { openBoard($board['uri']); if (!hasPermission($config['mod']['search_posts'], $board['uri'])) continue; - + if (!empty($query)) $query .= ' UNION ALL '; $query .= sprintf("SELECT *, '%s' AS `board` FROM ``posts_%s`` WHERE %s", $board['uri'], $board['uri'], $sql_like); } - + // You weren't allowed to search any boards if (empty($query)) error($config['error']['noaccess']); - + $query .= ' ORDER BY `sticky` DESC, `id` DESC'; } - + if ($type == 'IP_notes') { $query = 'SELECT * FROM ``ip_notes`` LEFT JOIN ``mods`` ON `mod` = ``mods``.`id` WHERE ' . $sql_like . ' ORDER BY `time` DESC'; $sql_table = 'ip_notes'; if (!hasPermission($config['mod']['view_notes']) || !hasPermission($config['mod']['show_ip'])) error($config['error']['noaccess']); } - + if ($type == 'bans') { $query = 'SELECT ``bans``.*, `username` FROM ``bans`` LEFT JOIN ``mods`` ON `creator` = ``mods``.`id` WHERE ' . $sql_like . ' ORDER BY (`expires` IS NOT NULL AND `expires` < UNIX_TIMESTAMP()), `created` DESC'; $sql_table = 'bans'; if (!hasPermission($config['mod']['view_banlist'])) error($config['error']['noaccess']); } - + if ($type == 'log') { $query = 'SELECT `username`, `mod`, `ip`, `board`, `time`, `text` FROM ``modlogs`` LEFT JOIN ``mods`` ON `mod` = ``mods``.`id` WHERE ' . $sql_like . ' ORDER BY `time` DESC'; $sql_table = 'modlogs'; if (!hasPermission($config['mod']['modlog'])) error($config['error']['noaccess']); } - + // Execute SQL query (with pages) $q = query($query . ' LIMIT ' . (($page_no - 1) * $config['mod']['search_page']) . ', ' . $config['mod']['search_page']) or error(db_error()); $results = $q->fetchAll(PDO::FETCH_ASSOC); - + // Get total result count if ($type == 'posts') { $q = query("SELECT COUNT(*) FROM ($query) AS `tmp_table`") or error(db_error()); @@ -320,7 +320,7 @@ function mod_search($type, $search_query_escaped, $page_no = 1) { $q = query('SELECT COUNT(*) FROM `' . $sql_table . '` WHERE ' . $sql_like) or error(db_error()); $result_count = $q->fetchColumn(); } - + if ($type == 'bans') { foreach ($results as &$ban) { $ban['mask'] = Bans::range_to_string(array($ban['ipstart'], $ban['ipend'])); @@ -328,15 +328,15 @@ function mod_search($type, $search_query_escaped, $page_no = 1) { $ban['single_addr'] = true; } } - + if ($type == 'posts') { foreach ($results as &$post) { $post['snippet'] = pm_snippet($post['body']); } } - + // $results now contains the search results - + mod_page(_('Search results'), 'mod/search_results.html', array( 'search_type' => $type, 'search_query' => $search_query, @@ -348,42 +348,42 @@ function mod_search($type, $search_query_escaped, $page_no = 1) { function mod_edit_board($boardName) { global $board, $config; - + if (!openBoard($boardName)) error($config['error']['noboard']); - + if (!hasPermission($config['mod']['manageboards'], $board['uri'])) error($config['error']['noaccess']); - + if (isset($_POST['title'], $_POST['subtitle'])) { if (isset($_POST['delete'])) { if (!hasPermission($config['mod']['manageboards'], $board['uri'])) error($config['error']['deleteboard']); - + $query = prepare('DELETE FROM ``boards`` WHERE `uri` = :uri'); $query->bindValue(':uri', $board['uri']); $query->execute() or error(db_error($query)); - + if ($config['cache']['enabled']) { cache::delete('board_' . $board['uri']); cache::delete('all_boards'); } - + modLog('Deleted board: ' . sprintf($config['board_abbreviation'], $board['uri']), false); - + // Delete posting table $query = query(sprintf('DROP TABLE IF EXISTS ``posts_%s``', $board['uri'])) or error(db_error()); - + // Clear reports $query = prepare('DELETE FROM ``reports`` WHERE `board` = :id'); $query->bindValue(':id', $board['uri'], PDO::PARAM_STR); $query->execute() or error(db_error($query)); - + // Delete from table $query = prepare('DELETE FROM ``boards`` WHERE `uri` = :uri'); $query->bindValue(':uri', $board['uri'], PDO::PARAM_STR); $query->execute() or error(db_error($query)); - + $query = prepare("SELECT `board`, `post` FROM ``cites`` WHERE `target_board` = :board ORDER BY `board`"); $query->bindValue(':board', $board['uri']); $query->execute() or error(db_error($query)); @@ -395,18 +395,18 @@ function mod_edit_board($boardName) { rebuildPost($cite['post']); } } - + if (isset($tmp_board)) $board = $tmp_board; - + $query = prepare('DELETE FROM ``cites`` WHERE `board` = :board OR `target_board` = :board'); $query->bindValue(':board', $board['uri']); $query->execute() or error(db_error($query)); - + $query = prepare('DELETE FROM ``antispam`` WHERE `board` = :board'); $query->bindValue(':board', $board['uri']); $query->execute() or error(db_error($query)); - + // Remove board from users/permissions table $query = query('SELECT `id`,`boards` FROM ``mods``') or error(db_error()); while ($user = $query->fetch(PDO::FETCH_ASSOC)) { @@ -419,7 +419,7 @@ function mod_edit_board($boardName) { $_query->execute() or error(db_error($_query)); } } - + // Delete entire board directory rrmdir($board['uri'] . '/'); } else { @@ -428,17 +428,17 @@ function mod_edit_board($boardName) { $query->bindValue(':title', $_POST['title']); $query->bindValue(':subtitle', $_POST['subtitle']); $query->execute() or error(db_error($query)); - + modLog('Edited board information for ' . sprintf($config['board_abbreviation'], $board['uri']), false); } - + if ($config['cache']['enabled']) { cache::delete('board_' . $board['uri']); cache::delete('all_boards'); } - + rebuildThemes('boards'); - + header('Location: ?/', true, $config['redirect_http']); } else { mod_page(sprintf('%s: ' . $config['board_abbreviation'], _('Edit board'), $board['uri']), 'mod/board.html', array( @@ -450,20 +450,20 @@ function mod_edit_board($boardName) { function mod_new_board() { global $config, $board; - + if (!hasPermission($config['mod']['newboard'])) error($config['error']['noaccess']); - + if (isset($_POST['uri'], $_POST['title'], $_POST['subtitle'])) { if ($_POST['uri'] == '') error(sprintf($config['error']['required'], 'URI')); - + if ($_POST['title'] == '') error(sprintf($config['error']['required'], 'title')); - + if (!preg_match('/^' . $config['board_regex'] . '$/u', $_POST['uri'])) error(sprintf($config['error']['invalidfield'], 'URI')); - + $bytes = 0; $chars = preg_split('//u', $_POST['uri'], -1, PREG_SPLIT_NO_EMPTY); foreach ($chars as $char) { @@ -475,96 +475,96 @@ function mod_new_board() { $bytes ++; } $bytes + strlen('posts_.frm'); - + if ($bytes > 255) { error('Your filesystem cannot handle a board URI of that length (' . $bytes . '/255 bytes)'); exit; } - + if (openBoard($_POST['uri'])) { error(sprintf($config['error']['boardexists'], $board['url'])); } - + $query = prepare('INSERT INTO ``boards`` VALUES (:uri, :title, :subtitle)'); $query->bindValue(':uri', $_POST['uri']); $query->bindValue(':title', $_POST['title']); $query->bindValue(':subtitle', $_POST['subtitle']); $query->execute() or error(db_error($query)); - + modLog('Created a new board: ' . sprintf($config['board_abbreviation'], $_POST['uri'])); - + if (!openBoard($_POST['uri'])) error(_("Couldn't open board after creation.")); - + $query = Element('posts.sql', array('board' => $board['uri'])); - + if (mysql_version() < 50503) $query = preg_replace('/(CHARSET=|CHARACTER SET )utf8mb4/', '$1utf8', $query); - + query($query) or error(db_error()); - + if ($config['cache']['enabled']) cache::delete('all_boards'); - + // Build the board buildIndex(); - + rebuildThemes('boards'); - + header('Location: ?/' . $board['uri'] . '/' . $config['file_index'], true, $config['redirect_http']); } - + mod_page(_('New board'), 'mod/board.html', array('new' => true, 'token' => make_secure_link_token('new-board'))); } function mod_noticeboard($page_no = 1) { global $config, $pdo, $mod; - + if ($page_no < 1) error($config['error']['404']); - + if (!hasPermission($config['mod']['noticeboard'])) error($config['error']['noaccess']); - + if (isset($_POST['subject'], $_POST['body'])) { if (!hasPermission($config['mod']['noticeboard_post'])) error($config['error']['noaccess']); - + $_POST['body'] = escape_markup_modifiers($_POST['body']); markup($_POST['body']); - + $query = prepare('INSERT INTO ``noticeboard`` VALUES (NULL, :mod, :time, :subject, :body)'); $query->bindValue(':mod', $mod['id']); $query->bindvalue(':time', time()); $query->bindValue(':subject', $_POST['subject']); $query->bindValue(':body', $_POST['body']); $query->execute() or error(db_error($query)); - + if ($config['cache']['enabled']) cache::delete('noticeboard_preview'); - + modLog('Posted a noticeboard entry'); - + header('Location: ?/noticeboard#' . $pdo->lastInsertId(), true, $config['redirect_http']); } - + $query = prepare("SELECT ``noticeboard``.*, `username` FROM ``noticeboard`` LEFT JOIN ``mods`` ON ``mods``.`id` = `mod` ORDER BY `id` DESC LIMIT :offset, :limit"); $query->bindValue(':limit', $config['mod']['noticeboard_page'], PDO::PARAM_INT); $query->bindValue(':offset', ($page_no - 1) * $config['mod']['noticeboard_page'], PDO::PARAM_INT); $query->execute() or error(db_error($query)); $noticeboard = $query->fetchAll(PDO::FETCH_ASSOC); - + if (empty($noticeboard) && $page_no > 1) error($config['error']['404']); - + foreach ($noticeboard as &$entry) { $entry['delete_token'] = make_secure_link_token('noticeboard/delete/' . $entry['id']); } - + $query = prepare("SELECT COUNT(*) FROM ``noticeboard``"); $query->execute() or error(db_error($query)); $count = $query->fetchColumn(); - + mod_page(_('Noticeboard'), 'mod/noticeboard.html', array( 'noticeboard' => $noticeboard, 'count' => $count, @@ -574,175 +574,182 @@ function mod_noticeboard($page_no = 1) { function mod_noticeboard_delete($id) { global $config; - + if (!hasPermission($config['mod']['noticeboard_delete'])) error($config['error']['noaccess']); - + $query = prepare('DELETE FROM ``noticeboard`` WHERE `id` = :id'); $query->bindValue(':id', $id); $query->execute() or error(db_error($query)); - + modLog('Deleted a noticeboard entry'); - + if ($config['cache']['enabled']) cache::delete('noticeboard_preview'); - + header('Location: ?/noticeboard', true, $config['redirect_http']); } function mod_news($page_no = 1) { global $config, $pdo, $mod; - + if ($page_no < 1) error($config['error']['404']); - + if (isset($_POST['subject'], $_POST['body'])) { if (!hasPermission($config['mod']['news'])) error($config['error']['noaccess']); - + $_POST['body'] = escape_markup_modifiers($_POST['body']); markup($_POST['body']); - + $query = prepare('INSERT INTO ``news`` VALUES (NULL, :name, :time, :subject, :body)'); $query->bindValue(':name', isset($_POST['name']) && hasPermission($config['mod']['news_custom']) ? $_POST['name'] : $mod['username']); $query->bindvalue(':time', time()); $query->bindValue(':subject', $_POST['subject']); $query->bindValue(':body', $_POST['body']); $query->execute() or error(db_error($query)); - + modLog('Posted a news entry'); - + rebuildThemes('news'); - + header('Location: ?/edit_news#' . $pdo->lastInsertId(), true, $config['redirect_http']); } - + $query = prepare("SELECT * FROM ``news`` ORDER BY `id` DESC LIMIT :offset, :limit"); $query->bindValue(':limit', $config['mod']['news_page'], PDO::PARAM_INT); $query->bindValue(':offset', ($page_no - 1) * $config['mod']['news_page'], PDO::PARAM_INT); $query->execute() or error(db_error($query)); $news = $query->fetchAll(PDO::FETCH_ASSOC); - + if (empty($news) && $page_no > 1) error($config['error']['404']); - + foreach ($news as &$entry) { $entry['delete_token'] = make_secure_link_token('edit_news/delete/' . $entry['id']); } - + $query = prepare("SELECT COUNT(*) FROM ``news``"); $query->execute() or error(db_error($query)); $count = $query->fetchColumn(); - + mod_page(_('News'), 'mod/news.html', array('news' => $news, 'count' => $count, 'token' => make_secure_link_token('edit_news'))); } function mod_news_delete($id) { global $config; - + if (!hasPermission($config['mod']['news_delete'])) error($config['error']['noaccess']); - + $query = prepare('DELETE FROM ``news`` WHERE `id` = :id'); $query->bindValue(':id', $id); $query->execute() or error(db_error($query)); - + modLog('Deleted a news entry'); - + header('Location: ?/edit_news', true, $config['redirect_http']); } function mod_log($page_no = 1) { global $config; - + if ($page_no < 1) error($config['error']['404']); - + if (!hasPermission($config['mod']['modlog'])) error($config['error']['noaccess']); - + $query = prepare("SELECT `username`, `mod`, `ip`, `board`, `time`, `text` FROM ``modlogs`` LEFT JOIN ``mods`` ON `mod` = ``mods``.`id` ORDER BY `time` DESC LIMIT :offset, :limit"); $query->bindValue(':limit', $config['mod']['modlog_page'], PDO::PARAM_INT); $query->bindValue(':offset', ($page_no - 1) * $config['mod']['modlog_page'], PDO::PARAM_INT); $query->execute() or error(db_error($query)); $logs = $query->fetchAll(PDO::FETCH_ASSOC); - + if (empty($logs) && $page_no > 1) error($config['error']['404']); - + $query = prepare("SELECT COUNT(*) FROM ``modlogs``"); $query->execute() or error(db_error($query)); $count = $query->fetchColumn(); - + mod_page(_('Moderation log'), 'mod/log.html', array('logs' => $logs, 'count' => $count)); } function mod_user_log($username, $page_no = 1) { global $config; - + if ($page_no < 1) error($config['error']['404']); - + if (!hasPermission($config['mod']['modlog'])) error($config['error']['noaccess']); - + $query = prepare("SELECT `username`, `mod`, `ip`, `board`, `time`, `text` FROM ``modlogs`` LEFT JOIN ``mods`` ON `mod` = ``mods``.`id` WHERE `username` = :username ORDER BY `time` DESC LIMIT :offset, :limit"); $query->bindValue(':username', $username); $query->bindValue(':limit', $config['mod']['modlog_page'], PDO::PARAM_INT); $query->bindValue(':offset', ($page_no - 1) * $config['mod']['modlog_page'], PDO::PARAM_INT); $query->execute() or error(db_error($query)); $logs = $query->fetchAll(PDO::FETCH_ASSOC); - + if (empty($logs) && $page_no > 1) error($config['error']['404']); - + $query = prepare("SELECT COUNT(*) FROM ``modlogs`` LEFT JOIN ``mods`` ON `mod` = ``mods``.`id` WHERE `username` = :username"); $query->bindValue(':username', $username); $query->execute() or error(db_error($query)); $count = $query->fetchColumn(); - + mod_page(_('Moderation log'), 'mod/log.html', array('logs' => $logs, 'count' => $count, 'username' => $username)); } +function protect_ip($entry) { + $ipv4_regex = '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'; + $ipv6_regex = '(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))'; + + $ipv4_link_regex = '/(?:)?(' . $ipv4_regex . ')(?:<\/a>)?/'; + $ipv6_link_regex = '/(?:)?(' . $ipv6_regex . ')(?:<\/a>)?/'; + + return preg_replace(array($ipv4_link_regex, $ipv6_link_regex), "xxxx", $entry); +} + function mod_board_log($board, $page_no = 1, $hide_names = false, $public = false) { global $config; - + if ($page_no < 1) error($config['error']['404']); - + if (!hasPermission($config['mod']['mod_board_log'], $board) && !$public) error($config['error']['noaccess']); - + $query = prepare("SELECT `username`, `mod`, `ip`, `board`, `time`, `text` FROM ``modlogs`` LEFT JOIN ``mods`` ON `mod` = ``mods``.`id` WHERE `board` = :board ORDER BY `time` DESC LIMIT :offset, :limit"); $query->bindValue(':board', $board); $query->bindValue(':limit', $config['mod']['modlog_page'], PDO::PARAM_INT); $query->bindValue(':offset', ($page_no - 1) * $config['mod']['modlog_page'], PDO::PARAM_INT); $query->execute() or error(db_error($query)); $logs = $query->fetchAll(PDO::FETCH_ASSOC); - + if (empty($logs) && $page_no > 1) error($config['error']['404']); if (!hasPermission($config['mod']['show_ip'])) { - // Supports ipv4 only! foreach ($logs as $i => &$log) { - $log['text'] = preg_replace_callback('/(?:)?(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(?:<\/a>)?/', function($matches) { - return "xxxx";//less_ip($matches[1]); - }, $log['text']); + $log['text'] = protect_ip($log['text']); } } - + $query = prepare("SELECT COUNT(*) FROM ``modlogs`` LEFT JOIN ``mods`` ON `mod` = ``mods``.`id` WHERE `board` = :board"); $query->bindValue(':board', $board); $query->execute() or error(db_error($query)); $count = $query->fetchColumn(); - + mod_page(_('Board log'), 'mod/log.html', array('logs' => $logs, 'count' => $count, 'board' => $board, 'hide_names' => $hide_names, 'public' => $public)); } function mod_view_board($boardName, $page_no = 1) { global $config, $mod; - + if (!openBoard($boardName)){ if (in_array($boardName,array_keys($config['overboards']))){ $type = $config['overboards'][$boardName]['type']; @@ -773,79 +780,79 @@ function mod_view_board($boardName, $page_no = 1) { error($config['error']['noboard']); } } - + if (!$page = index($page_no, $mod)) { error($config['error']['404']); } - + $page['pages'] = getPages(true); $page['pages'][$page_no-1]['selected'] = true; $page['btn'] = getPageButtons($page['pages'], true); $page['mod'] = true; $page['config'] = $config; - + echo Element('index.html', $page); } function mod_view_thread($boardName, $thread) { global $config, $mod; - + if (!openBoard($boardName)) error($config['error']['noboard']); - + $page = buildThread($thread, true, $mod); echo $page; } function mod_view_thread50($boardName, $thread) { global $config, $mod; - + if (!openBoard($boardName)) error($config['error']['noboard']); - + $page = buildThread50($thread, true, $mod); echo $page; } function mod_ip_remove_note($ip, $id) { global $config, $mod; - + if (!hasPermission($config['mod']['remove_notes'])) error($config['error']['noaccess']); - + if (filter_var($ip, FILTER_VALIDATE_IP) === false) error("Invalid IP address."); - + $query = prepare('DELETE FROM ``ip_notes`` WHERE `ip` = :ip AND `id` = :id'); $query->bindValue(':ip', $ip); $query->bindValue(':id', $id); $query->execute() or error(db_error($query)); - + modLog("Removed a note for {$ip}"); - + header('Location: ?/IP/' . $ip . '#notes', true, $config['redirect_http']); } function mod_page_ip($ip) { global $config, $mod; - + if (filter_var($ip, FILTER_VALIDATE_IP) === false) error("Invalid IP address."); - + if (isset($_POST['ban_id'], $_POST['unban'])) { if (!hasPermission($config['mod']['unban'])) error($config['error']['noaccess']); - + Bans::delete($_POST['ban_id'], true, $mod['boards']); - + header('Location: ?/IP/' . $ip . '#bans', true, $config['redirect_http']); return; } - + if (isset($_POST['note'])) { if (!hasPermission($config['mod']['create_notes'])) error($config['error']['noaccess']); - + $_POST['note'] = escape_markup_modifiers($_POST['note']); markup($_POST['note']); $query = prepare('INSERT INTO ``ip_notes`` VALUES (NULL, :ip, :mod, :time, :body)'); @@ -854,20 +861,20 @@ function mod_page_ip($ip) { $query->bindValue(':time', time()); $query->bindValue(':body', $_POST['note']); $query->execute() or error(db_error($query)); - + modLog("Added a note for {$ip}"); - + header('Location: ?/IP/' . $ip . '#notes', true, $config['redirect_http']); return; } - + $args = array(); $args['ip'] = $ip; $args['posts'] = array(); - + if ($config['mod']['dns_lookup']) $args['hostname'] = rDNS($ip); - + $boards = listBoards(); foreach ($boards as $board) { openBoard($board['uri']); @@ -877,34 +884,34 @@ function mod_page_ip($ip) { $query->bindValue(':ip', $ip); $query->bindValue(':limit', $config['mod']['ip_recentposts'], PDO::PARAM_INT); $query->execute() or error(db_error($query)); - + while ($post = $query->fetch(PDO::FETCH_ASSOC)) { if (!$post['thread']) { $po = new Thread($post, '?/', $mod, false); } else { $po = new Post($post, '?/', $mod); } - + if (!isset($args['posts'][$board['uri']])) $args['posts'][$board['uri']] = array('board' => $board, 'posts' => array()); $args['posts'][$board['uri']]['posts'][] = $po->build(true); } } - + $args['boards'] = $boards; $args['token'] = make_secure_link_token('ban'); - + if (hasPermission($config['mod']['view_ban'])) { $args['bans'] = Bans::find($ip, false, true); } - + if (hasPermission($config['mod']['view_notes'])) { $query = prepare("SELECT ``ip_notes``.*, `username` FROM ``ip_notes`` LEFT JOIN ``mods`` ON `mod` = ``mods``.`id` WHERE `ip` = :ip ORDER BY `time` DESC"); $query->bindValue(':ip', $ip); $query->execute() or error(db_error($query)); $args['notes'] = $query->fetchAll(PDO::FETCH_ASSOC); } - + if (hasPermission($config['mod']['modlog_ip'])) { $query = prepare("SELECT `username`, `mod`, `ip`, `board`, `time`, `text` FROM ``modlogs`` LEFT JOIN ``mods`` ON `mod` = ``mods``.`id` WHERE `text` LIKE :search ORDER BY `time` DESC LIMIT 50"); $query->bindValue(':search', '%' . $ip . '%'); @@ -913,25 +920,25 @@ function mod_page_ip($ip) { } else { $args['logs'] = array(); } - + $args['security_token'] = make_secure_link_token('IP/' . $ip); - + mod_page(sprintf('%s: %s', _('IP'), htmlspecialchars($ip)), 'mod/view_ip.html', $args, $args['hostname']); } function mod_ban() { global $config; - + if (!hasPermission($config['mod']['ban'])) error($config['error']['noaccess']); - + if (!isset($_POST['ip'], $_POST['reason'], $_POST['length'], $_POST['board'])) { mod_page(_('New ban'), 'mod/ban_form.html', array('token' => make_secure_link_token('ban'))); return; } - + require_once 'inc/mod/ban.php'; - + Bans::new_ban($_POST['ip'], $_POST['reason'], $_POST['length'], $_POST['board'] == '*' ? false : $_POST['board']); if (isset($_POST['redirect'])) @@ -942,15 +949,15 @@ function mod_ban() { function mod_warning() { global $config; - + if (!hasPermission($config['mod']['warning'])) error($config['error']['noaccess']); - + if (!isset( $_POST['board'])) { mod_page(_('New warning'), 'mod/warning_form.html', array('token' => make_secure_link_token('ban'))); return; } - + if (isset($_POST['redirect'])) header('Location: ' . $_POST['redirect'], true, $config['redirect_http']); else @@ -960,14 +967,14 @@ function mod_warning() { function mod_bans() { global $config; global $mod; - + if (!hasPermission($config['mod']['view_banlist'])) error($config['error']['noaccess']); - + if (isset($_POST['unban'])) { if (!hasPermission($config['mod']['unban'])) error($config['error']['noaccess']); - + $unban = array(); foreach ($_POST as $name => $unused) { if (preg_match('/^ban_(\d+)$/', $name, $match)) @@ -975,7 +982,7 @@ function mod_bans() { } if (isset($config['mod']['unban_limit']) && $config['mod']['unban_limit'] && count($unban) > $config['mod']['unban_limit']) error(sprintf($config['error']['toomanyunban'], $config['mod']['unban_limit'], count($unban))); - + foreach ($unban as $id) { Bans::delete($id, true, $mod['boards'], true); } @@ -983,7 +990,7 @@ function mod_bans() { header('Location: ?/bans', true, $config['redirect_http']); return; } - + mod_page(_('Ban list'), 'mod/ban_list.html', array( 'mod' => $mod, 'boards' => json_encode($mod['boards']), @@ -1006,27 +1013,27 @@ function mod_bans_json() { function mod_ban_appeals() { global $config, $board; - + if (!hasPermission($config['mod']['view_ban_appeals'])) error($config['error']['noaccess']); - + // Remove stale ban appeals query("DELETE FROM ``ban_appeals`` WHERE NOT EXISTS (SELECT 1 FROM ``bans`` WHERE `ban_id` = ``bans``.`id`)") or error(db_error()); - + if (isset($_POST['appeal_id']) && (isset($_POST['unban']) || isset($_POST['deny']))) { if (!hasPermission($config['mod']['ban_appeals'])) error($config['error']['noaccess']); - + $query = query("SELECT *, ``ban_appeals``.`id` AS `id` FROM ``ban_appeals`` LEFT JOIN ``bans`` ON `ban_id` = ``bans``.`id` WHERE ``ban_appeals``.`id` = " . (int)$_POST['appeal_id']) or error(db_error()); if (!$ban = $query->fetch(PDO::FETCH_ASSOC)) { error(_('Ban appeal not found!')); } - + $ban['mask'] = Bans::range_to_string(array($ban['ipstart'], $ban['ipend'])); - + if (isset($_POST['unban'])) { modLog('Accepted ban appeal #' . $ban['id'] . ' for ' . $ban['mask']); Bans::delete($ban['ban_id'], true); @@ -1035,11 +1042,11 @@ function mod_ban_appeals() { modLog('Denied ban appeal #' . $ban['id'] . ' for ' . $ban['mask']); query("UPDATE ``ban_appeals`` SET `denied` = 1 WHERE `id` = " . $ban['id']) or error(db_error()); } - + header('Location: ?/ban-appeals', true, $config['redirect_http']); return; } - + $query = query("SELECT *, ``ban_appeals``.`id` AS `id` FROM ``ban_appeals`` LEFT JOIN ``bans`` ON `ban_id` = ``bans``.`id` LEFT JOIN ``mods`` ON ``bans``.`creator` = ``mods``.`id` @@ -1049,7 +1056,7 @@ function mod_ban_appeals() { if ($ban['post']) $ban['post'] = json_decode($ban['post'], true); $ban['mask'] = Bans::range_to_string(array($ban['ipstart'], $ban['ipend'])); - + if ($ban['post'] && isset($ban['post']['board'], $ban['post']['id'])) { if (openBoard($ban['post']['board'])) { $query = query(sprintf("SELECT `num_files`, `files` FROM ``posts_%s`` WHERE `id` = " . @@ -1069,7 +1076,7 @@ function mod_ban_appeals() { $ban['post']['files'][0]['thumb'] = false; $ban['post']['num_files'] = 1; } - + if ($ban['post']['thread']) { $ban['post'] = new Post($ban['post']); } else { @@ -1086,13 +1093,13 @@ function mod_ban_appeals() { function mod_lock($board, $unlock, $post) { global $config; - + if (!openBoard($board)) error($config['error']['noboard']); - + if (!hasPermission($config['mod']['lock'], $board)) error($config['error']['noaccess']); - + $query = prepare(sprintf('UPDATE ``posts_%s`` SET `locked` = :locked WHERE `id` = :id AND `thread` IS NULL', $board)); $query->bindValue(':id', $post); $query->bindValue(':locked', $unlock ? 0 : 1); @@ -1104,16 +1111,16 @@ function mod_lock($board, $unlock, $post) { // trigger themes rebuildThemes('lock', $board); } - + if ($config['mod']['dismiss_reports_on_lock']) { $query = prepare('DELETE FROM ``reports`` WHERE `board` = :board AND `post` = :id'); $query->bindValue(':board', $board); $query->bindValue(':id', $post); $query->execute() or error(db_error($query)); } - + header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']); - + if ($unlock) event('unlock', $post); else @@ -1122,13 +1129,13 @@ function mod_lock($board, $unlock, $post) { function mod_sticky($board, $unsticky, $post) { global $config; - + if (!openBoard($board)) error($config['error']['noboard']); - + if (!hasPermission($config['mod']['sticky'], $board)) error($config['error']['noaccess']); - + $query = prepare(sprintf('UPDATE ``posts_%s`` SET `sticky` = :sticky WHERE `id` = :id AND `thread` IS NULL', $board)); $query->bindValue(':id', $post); $query->bindValue(':sticky', $unsticky ? 0 : 1); @@ -1140,19 +1147,19 @@ function mod_sticky($board, $unsticky, $post) { // trigger themes rebuildThemes('sticky', $board); } - + header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']); } function mod_cycle($board, $uncycle, $post) { global $config; - + if (!openBoard($board)) error($config['error']['noboard']); - + if (!hasPermission($config['mod']['cycle'], $board)) error($config['error']['noaccess']); - + $query = prepare(sprintf('UPDATE ``posts_%s`` SET `cycle` = :cycle WHERE `id` = :id AND `thread` IS NULL', $board)); $query->bindValue(':id', $post); $query->bindValue(':cycle', $uncycle ? 0 : 1); @@ -1162,19 +1169,19 @@ function mod_cycle($board, $uncycle, $post) { buildThread($post); buildIndex(); } - + header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']); } function mod_bumplock($board, $unbumplock, $post) { global $config; - + if (!openBoard($board)) error($config['error']['noboard']); - + if (!hasPermission($config['mod']['bumplock'], $board)) error($config['error']['noaccess']); - + $query = prepare(sprintf('UPDATE ``posts_%s`` SET `sage` = :bumplock WHERE `id` = :id AND `thread` IS NULL', $board)); $query->bindValue(':id', $post); $query->bindValue(':bumplock', $unbumplock ? 0 : 1); @@ -1184,16 +1191,16 @@ function mod_bumplock($board, $unbumplock, $post) { buildThread($post); buildIndex(); } - + header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']); } -function mod_move_reply($originBoard, $postID) { +function mod_move_reply($originBoard, $postID) { global $board, $config, $mod; if (!openBoard($originBoard)) error($config['error']['noboard']); - + if (!hasPermission($config['mod']['move'], $originBoard)) error($config['error']['noaccess']); @@ -1216,7 +1223,7 @@ function mod_move_reply($originBoard, $postID) { else { $post['op'] = true; } - + if ($post['files']) { $post['files'] = json_decode($post['files'], TRUE); $post['has_file'] = true; @@ -1227,16 +1234,16 @@ function mod_move_reply($originBoard, $postID) { } else { $post['has_file'] = false; } - + // allow thread to keep its same traits (stickied, locked, etc.) $post['mod'] = true; - + if (!openBoard($targetBoard)) error($config['error']['noboard']); - - // create the new post + + // create the new post $newID = post($post); - + if ($post['has_file']) { foreach ($post['files'] as $i => &$file) { // move the image @@ -1252,12 +1259,12 @@ function mod_move_reply($originBoard, $postID) { // build new thread buildThread($post['op'] ? $newID : $post['thread']); - + // trigger themes rebuildThemes('post', $targetBoard); // mod log modLog("Moved post #${postID} to " . sprintf($config['board_abbreviation'], $targetBoard) . " (#${newID})", $originBoard); - + // return to original board openBoard($originBoard); @@ -1280,9 +1287,9 @@ function mod_move_reply($originBoard, $postID) { else { $boards = listBoards(); - + $security_token = make_secure_link_token($originBoard . '/move_reply/' . $postID); - + mod_page(_('Move reply'), 'mod/move_reply.html', array('post' => $postID, 'board' => $originBoard, 'boards' => $boards, 'token' => $security_token)); } @@ -1291,37 +1298,37 @@ function mod_move_reply($originBoard, $postID) { function mod_move($originBoard, $postID) { global $board, $config, $mod, $pdo; - + if (!openBoard($originBoard)) error($config['error']['noboard']); - + if (!hasPermission($config['mod']['move'], $originBoard)) error($config['error']['noaccess']); - + $query = prepare(sprintf('SELECT * FROM ``posts_%s`` WHERE `id` = :id AND `thread` IS NULL', $originBoard)); $query->bindValue(':id', $postID); $query->execute() or error(db_error($query)); if (!$post = $query->fetch(PDO::FETCH_ASSOC)) error($config['error']['404']); - + if (isset($_POST['board'])) { $targetBoard = $_POST['board']; $shadow = isset($_POST['shadow']); - + if ($targetBoard === $originBoard) error(_('Target and source board are the same.')); - + // copy() if leaving a shadow thread behind; else, rename(). $clone = $shadow ? 'copy' : 'rename'; - + // indicate that the post is a thread $post['op'] = true; - + if ($post['files']) { $post['files'] = json_decode($post['files'], TRUE); $post['has_file'] = true; foreach ($post['files'] as $i => &$file) { - if ($file['file'] === 'deleted') + if ($file['file'] === 'deleted') continue; $file['file_path'] = sprintf($config['board_path'], $board['uri']) . $config['dir']['img'] . $file['file']; $file['thumb_path'] = sprintf($config['board_path'], $board['uri']) . $config['dir']['thumb'] . $file['thumb']; @@ -1329,42 +1336,42 @@ function mod_move($originBoard, $postID) { } else { $post['has_file'] = false; } - + // allow thread to keep its same traits (stickied, locked, etc.) $post['mod'] = true; - + if (!openBoard($targetBoard)) error($config['error']['noboard']); - + // create the new thread $newID = post($post); - + $op = $post; $op['id'] = $newID; - + if ($post['has_file']) { // copy image foreach ($post['files'] as $i => &$file) { - if ($file['file'] !== 'deleted') + if ($file['file'] !== 'deleted') $clone($file['file_path'], sprintf($config['board_path'], $board['uri']) . $config['dir']['img'] . $file['file']); if (isset($file['thumb']) && !in_array($file['thumb'], array('spoiler', 'deleted', 'file'))) $clone($file['thumb_path'], sprintf($config['board_path'], $board['uri']) . $config['dir']['thumb'] . $file['thumb']); } } - + // go back to the original board to fetch replies openBoard($originBoard); - + $query = prepare(sprintf('SELECT * FROM ``posts_%s`` WHERE `thread` = :id ORDER BY `id`', $originBoard)); $query->bindValue(':id', $postID, PDO::PARAM_INT); $query->execute() or error(db_error($query)); - + $replies = array(); - + while ($post = $query->fetch(PDO::FETCH_ASSOC)) { $post['mod'] = true; $post['thread'] = $newID; - + if ($post['files']) { $post['files'] = json_decode($post['files'], TRUE); $post['has_file'] = true; @@ -1375,20 +1382,20 @@ function mod_move($originBoard, $postID) { } else { $post['has_file'] = false; } - + $replies[] = $post; } - + $newIDs = array($postID => $newID); - + openBoard($targetBoard); - + foreach ($replies as &$post) { $query = prepare('SELECT `target` FROM ``cites`` WHERE `target_board` = :board AND `board` = :board AND `post` = :post'); $query->bindValue(':board', $originBoard); $query->bindValue(':post', $post['id'], PDO::PARAM_INT); $query->execute() or error(db_error($query)); - + // correct >>X links while ($cite = $query->fetch(PDO::FETCH_ASSOC)) { if (isset($newIDs[$cite['target']])) { @@ -1396,16 +1403,16 @@ function mod_move($originBoard, $postID) { '/(>>(>\/' . preg_quote($originBoard, '/') . '\/)?)' . preg_quote($cite['target'], '/') . '/', '>>' . $newIDs[$cite['target']], $post['body_nomarkup']); - + $post['body'] = $post['body_nomarkup']; } } - + $post['body'] = $post['body_nomarkup']; - + $post['op'] = false; $post['tracked_cites'] = markup($post['body'], true); - + if ($post['has_file']) { // copy image foreach ($post['files'] as $i => &$file) { @@ -1415,8 +1422,8 @@ function mod_move($originBoard, $postID) { } // insert reply $newIDs[$post['id']] = $newPostID = post($post); - - + + if (!empty($post['tracked_cites'])) { $insert_rows = array(); foreach ($post['tracked_cites'] as $cite) { @@ -1427,29 +1434,29 @@ function mod_move($originBoard, $postID) { query('INSERT INTO ``cites`` VALUES ' . implode(', ', $insert_rows)) or error(db_error()); } } - + modLog("Moved thread #${postID} to " . sprintf($config['board_abbreviation'], $targetBoard) . " (#${newID})", $originBoard); - + // build new thread buildThread($newID); - + clean(); buildIndex(); - + // trigger themes rebuildThemes('post', $targetBoard); - + $newboard = $board; // return to original board openBoard($originBoard); - + if ($shadow) { // lock old thread $query = prepare(sprintf('UPDATE ``posts_%s`` SET `locked` = 1 WHERE `id` = :id', $originBoard)); $query->bindValue(':id', $postID, PDO::PARAM_INT); $query->execute() or error(db_error($query)); - + // leave a reply, linking to the new thread $spost = array( 'mod' => true, @@ -1466,62 +1473,62 @@ function mod_move($originBoard, $postID) { ); $spost['body'] = $spost['body_nomarkup'] = sprintf($config['mod']['shadow_mesage'], '>>>/' . $targetBoard . '/' . $newID); - + markup($spost['body']); - + $botID = post($spost); buildThread($postID); - + buildIndex(); - + header('Location: ?/' . sprintf($config['board_path'], $newboard['uri']) . $config['dir']['res'] . link_for($op, false, $newboard) . '#' . $botID, true, $config['redirect_http']); } else { deletePost($postID); buildIndex(); - + openBoard($targetBoard); header('Location: ?/' . sprintf($config['board_path'], $newboard['uri']) . $config['dir']['res'] . link_for($op, false, $newboard), true, $config['redirect_http']); } } - + $boards = listBoards(); if (count($boards) <= 1) error(_('Impossible to move thread; there is only one board.')); - + $security_token = make_secure_link_token($originBoard . '/move/' . $postID); - + mod_page(_('Move thread'), 'mod/move.html', array('post' => $postID, 'board' => $originBoard, 'boards' => $boards, 'token' => $security_token)); } function mod_merge($originBoard, $postID) { global $board, $config, $mod, $pdo; - + if (!openBoard($originBoard)) error($config['error']['noboard']); - + if (!hasPermission($config['mod']['merge'], $originBoard)) error($config['error']['noaccess']); - + $query = prepare(sprintf('SELECT * FROM ``posts_%s`` WHERE `id` = :id AND `thread` IS NULL', $originBoard)); $query->bindValue(':id', $postID); $query->execute() or error(db_error($query)); if (!$post = $query->fetch(PDO::FETCH_ASSOC)) error($config['error']['404']); - $sourceOp = ""; + $sourceOp = ""; if ($post['thread']){ - $sourceOp = $post['thread']; + $sourceOp = $post['thread']; } else{ - $sourceOp = $post['id']; - } - $newpost = ""; + $sourceOp = $post['id']; + } + $newpost = ""; $boards = listBoards(); - + if (isset($_POST['board'])) { $targetBoard = $_POST['board']; $shadow = isset($_POST['shadow']); - $targetOp = ""; + $targetOp = ""; if ($_POST['target_thread']) { $query = prepare(sprintf('SELECT * FROM ``posts_%s`` WHERE `id` = :id', $targetBoard)); $query->bindValue(':id', $_POST['target_thread']); @@ -1532,14 +1539,14 @@ function mod_merge($originBoard, $postID) { else { if ($newpost['thread']){ - $targetOp = $newpost['thread']; + $targetOp = $newpost['thread']; } else{ - $targetOp = $newpost['id']; - } + $targetOp = $newpost['id']; + } } } - + if ($targetBoard === $originBoard){ // Just update the thread id for all posts in the original thread to new op $query = prepare(sprintf('UPDATE ``posts_%s`` SET `thread` = :newthread WHERE `id` = :oldthread OR `thread` = :oldthread', $originBoard)); @@ -1557,7 +1564,7 @@ function mod_merge($originBoard, $postID) { // build new thread buildThread($targetOp); - + // trigger themes rebuildThemes('post', $targetBoard); modLog("Merged thread with #${sourceOp} to " . sprintf($config['board_abbreviation'], $targetBoard) . " (#${targetOp})", $originBoard); @@ -1566,17 +1573,17 @@ function mod_merge($originBoard, $postID) { header('Location: ?/' . sprintf($config['board_path'], $board['uri']) . $config['dir']['res'] . link_for($newpost) . '#' . $targetOp, true, $config['redirect_http']); } else { - // Move thread to new board without shadow thread and then update the thread id for all posts in that thread to new op + // Move thread to new board without shadow thread and then update the thread id for all posts in that thread to new op // indicate that the post is a thread if (count($boards) <= 1) error(_('Impossible to merge thread to different board; there is only one board.')); $post['op'] = true; - + if ($post['files']) { $post['files'] = json_decode($post['files'], TRUE); $post['has_file'] = true; foreach ($post['files'] as $i => &$file) { - if ($file['file'] === 'deleted') + if ($file['file'] === 'deleted') continue; $file['file_path'] = sprintf($config['board_path'], $board['uri']) . $config['dir']['img'] . $file['file']; $file['thumb_path'] = sprintf($config['board_path'], $board['uri']) . $config['dir']['thumb'] . $file['thumb']; @@ -1584,44 +1591,44 @@ function mod_merge($originBoard, $postID) { } else { $post['has_file'] = false; } - + // allow thread to keep its same traits (stickied, locked, etc.) $post['mod'] = true; - + if (!openBoard($targetBoard)) error($config['error']['noboard']); - + // create the new thread $newID = post($post); - + $op = $post; $op['id'] = $newID; - + $clone = $shadow ? 'copy' : 'rename'; - + if ($post['has_file']) { // copy image foreach ($post['files'] as $i => &$file) { - if ($file['file'] !== 'deleted') + if ($file['file'] !== 'deleted') $clone($file['file_path'], sprintf($config['board_path'], $board['uri']) . $config['dir']['img'] . $file['file']); if (isset($file['thumb']) && !in_array($file['thumb'], array('spoiler', 'deleted', 'file'))) $clone($file['thumb_path'], sprintf($config['board_path'], $board['uri']) . $config['dir']['thumb'] . $file['thumb']); } } - + // go back to the original board to fetch replies openBoard($originBoard); - + $query = prepare(sprintf('SELECT * FROM ``posts_%s`` WHERE `thread` = :id ORDER BY `id`', $originBoard)); $query->bindValue(':id', $postID, PDO::PARAM_INT); $query->execute() or error(db_error($query)); - + $replies = array(); - + while ($post = $query->fetch(PDO::FETCH_ASSOC)) { $post['mod'] = true; $post['thread'] = $newID; - + if ($post['files']) { $post['files'] = json_decode($post['files'], TRUE); $post['has_file'] = true; @@ -1632,20 +1639,20 @@ function mod_merge($originBoard, $postID) { } else { $post['has_file'] = false; } - + $replies[] = $post; } - + $newIDs = array($postID => $newID); - + openBoard($targetBoard); - + foreach ($replies as &$post) { $query = prepare('SELECT `target` FROM ``cites`` WHERE `target_board` = :board AND `board` = :board AND `post` = :post'); $query->bindValue(':board', $originBoard); $query->bindValue(':post', $post['id'], PDO::PARAM_INT); $query->execute() or error(db_error($query)); - + // correct >>X links while ($cite = $query->fetch(PDO::FETCH_ASSOC)) { if (isset($newIDs[$cite['target']])) { @@ -1653,16 +1660,16 @@ function mod_merge($originBoard, $postID) { '/(>>(>\/' . preg_quote($originBoard, '/') . '\/)?)' . preg_quote($cite['target'], '/') . '/', '>>' . $newIDs[$cite['target']], $post['body_nomarkup']); - + $post['body'] = $post['body_nomarkup']; } } - + $post['body'] = $post['body_nomarkup']; - + $post['op'] = false; $post['tracked_cites'] = markup($post['body'], true); - + if ($post['has_file']) { // copy image foreach ($post['files'] as $i => &$file) { @@ -1672,8 +1679,8 @@ function mod_merge($originBoard, $postID) { } // insert reply $newIDs[$post['id']] = $newPostID = post($post); - - + + if (!empty($post['tracked_cites'])) { $insert_rows = array(); foreach ($post['tracked_cites'] as $cite) { @@ -1684,27 +1691,27 @@ function mod_merge($originBoard, $postID) { query('INSERT INTO ``cites`` VALUES ' . implode(', ', $insert_rows)) or error(db_error()); } } - + modLog("Moved thread #${postID} to " . sprintf($config['board_abbreviation'], $targetBoard) . " (#${newID})", $originBoard); - + // build new thread buildThread($newID); - + clean(); buildIndex(); - + // trigger themes rebuildThemes('post', $targetBoard); - + $newboard = $board; // return to original board openBoard($originBoard); - + deletePost($postID); modLog("Deleted post #{$postID}"); buildIndex(); - + openBoard($targetBoard); // Just update the thread id for all posts in the original thread to new op $query = prepare(sprintf('UPDATE ``posts_%s`` SET `thread` = :newthread WHERE `id` = :oldthread OR `thread` = :oldthread', $targetBoard)); @@ -1716,51 +1723,51 @@ function mod_merge($originBoard, $postID) { // build new thread buildThread($targetOp); - + // trigger themes rebuildThemes('post', $targetBoard); modLog("Merged thread with #${newID} to " . sprintf($config['board_abbreviation'], $targetBoard) . " (#${targetOp})", $targetBoard); // redirect header('Location: ?/' . sprintf($config['board_path'], $board['uri']) . $config['dir']['res'] . link_for($newpost) . '#' . $targetOp, true, $config['redirect_http']); - } + } } - + $security_token = make_secure_link_token($originBoard . '/merge/' . $postID); - + mod_page(_('Merge thread'), 'mod/merge.html', array('post' => $postID, 'board' => $originBoard, 'boards' => $boards, 'token' => $security_token)); } function mod_ban_post($board, $delete, $post, $token = false) { global $config, $mod; - + if (!openBoard($board)) error($config['error']['noboard']); - + if (!hasPermission($config['mod']['delete'], $board)) error($config['error']['noaccess']); - + $security_token = make_secure_link_token($board . '/ban/' . $post); - + $query = prepare(sprintf('SELECT ' . ($config['ban_show_post'] ? '*' : '`ip`, `thread`') . ' FROM ``posts_%s`` WHERE `id` = :id', $board)); $query->bindValue(':id', $post); $query->execute() or error(db_error($query)); if (!$_post = $query->fetch(PDO::FETCH_ASSOC)) error($config['error']['404']); - + $thread = $_post['thread']; $ip = $_post['ip']; if (isset($_POST['new_ban'], $_POST['reason'], $_POST['length'], $_POST['board'])) { require_once 'inc/mod/ban.php'; - + if (isset($_POST['ip'])) $ip = $_POST['ip']; - + Bans::new_ban($_POST['ip'], $_POST['reason'], $_POST['length'], $_POST['board'] == '*' ? false : $_POST['board'], false, $config['ban_show_post'] ? $_post : false); - + if (isset($_POST['public_message'], $_POST['message'])) { // public ban message $length_english = Bans::parse_time($_POST['length']) ? 'for ' . until(Bans::parse_time($_POST['length'])) : 'permanently'; @@ -1772,7 +1779,7 @@ function mod_ban_post($board, $delete, $post, $token = false) { $query->bindValue(':body_nomarkup', sprintf("\n%s", utf8tohtml($_POST['message']))); $query->execute() or error(db_error($query)); rebuildPost($post); - + modLog("Attached a public ban message to post #{$post}: " . utf8tohtml($_POST['message'])); buildThread($thread ? $thread : $post); buildIndex(); @@ -1801,11 +1808,11 @@ function mod_ban_post($board, $delete, $post, $token = false) { for ($file_count = 0; $file_count < $mypost["num_files"];$file_count++){ $filename .= $mypost['files'][$file_count]->name . "\r\n"; } - } - if ($time !== ''){ - $dt = new DateTime("@$time"); + } + if ($time !== ''){ + $dt = new DateTime("@$time"); $autotag = ""; - $autotag .= $name . " " . $subject . " " . $dt->format('Y-m-d H:i:s') . " No.". $post . "\r\n"; + $autotag .= $name . " " . $subject . " " . $dt->format('Y-m-d H:i:s') . " No.". $post . "\r\n"; $autotag .= "/${board}/" . " " . $filehash . " " . $filename ."\r\n"; $autotag .= $body . "\r\n"; $autotag = escape_markup_modifiers($autotag); @@ -1818,7 +1825,7 @@ function mod_ban_post($board, $delete, $post, $token = false) { $query->execute() or error(db_error($query)); modLog("Added a note for {$ip}"); } - } + } deletePost($post); modLog("Deleted post #{$post}"); // Rebuild board @@ -1835,7 +1842,7 @@ function mod_ban_post($board, $delete, $post, $token = false) { header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']); } } - + $args = array( 'ip' => $ip, 'hide_ip' => !hasPermission($config['mod']['show_ip'], $board), @@ -1849,32 +1856,32 @@ function mod_ban_post($board, $delete, $post, $token = false) { if(isset($_GET['thread']) && $_GET['thread']) { $args['thread'] = $_GET['thread']; } - + mod_page(_('New ban'), 'mod/ban_form.html', $args); } function mod_warning_post($board,$post, $token = false) { global $config, $mod; - + if (!openBoard($board)) error($config['error']['noboard']); - + $security_token = make_secure_link_token($board . '/warning/' . $post); - + $query = prepare(sprintf('SELECT ' . ('`ip`, `thread`') . ' FROM ``posts_%s`` WHERE `id` = :id', $board)); $query->bindValue(':id', $post); $query->execute() or error(db_error($query)); if (!$_post = $query->fetch(PDO::FETCH_ASSOC)) error($config['error']['404']); - + $thread = $_post['thread']; $ip = $_post['ip']; if (isset($_POST['new_warning'])) { if (isset($_POST['ip'])) $ip = $_POST['ip']; - + if (isset($_POST['public_message'], $_POST['message'])) { // public warning message $_POST['message'] = preg_replace('/[\r\n]/', '', $_POST['message']); @@ -1883,7 +1890,7 @@ function mod_warning_post($board,$post, $token = false) { $query->bindValue(':body_nomarkup', sprintf("\n%s", utf8tohtml($_POST['message']))); $query->execute() or error(db_error($query)); rebuildPost($post); - + modLog("Attached a public warning message to post #{$post}: " . utf8tohtml($_POST['message'])); buildThread($thread ? $thread : $post); buildIndex(); @@ -1911,11 +1918,11 @@ function mod_warning_post($board,$post, $token = false) { for ($file_count = 0; $file_count < $mypost["num_files"];$file_count++){ $filename .= $mypost['files'][$file_count]->name . "\r\n"; } - } - if ($time !== ''){ - $dt = new DateTime("@$time"); + } + if ($time !== ''){ + $dt = new DateTime("@$time"); $autotag = "Post warned\r\n"; - $autotag .= $name . " " . $subject . " " . $dt->format('Y-m-d H:i:s') . " No.". $post . "\r\n"; + $autotag .= $name . " " . $subject . " " . $dt->format('Y-m-d H:i:s') . " No.". $post . "\r\n"; $autotag .= "/${board}/" . " " . $filehash . " " . $filename ."\r\n"; $autotag .= $body . "\r\n"; $autotag = escape_markup_modifiers($autotag); @@ -1928,7 +1935,7 @@ function mod_warning_post($board,$post, $token = false) { $query->execute() or error(db_error($query)); modLog("Added a note for {$ip}"); } - } + } } if(isset($_POST['thread'])) { // Redirect to thread @@ -1937,7 +1944,7 @@ function mod_warning_post($board,$post, $token = false) { // Redirect to board index. header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']); } - } + } $args = array( 'ip' => $ip, 'hide_ip' => !hasPermission($config['mod']['show_ip'], $board), @@ -1949,7 +1956,7 @@ function mod_warning_post($board,$post, $token = false) { if(isset($_GET['thread'])) { $args['thread'] = $_GET['thread']; } - + mod_page(_('New warning'), 'mod/warning_form.html', $args); } @@ -1961,19 +1968,19 @@ function mod_edit_post($board, $edit_raw_html, $postID) { if (!hasPermission($config['mod']['editpost'], $board)) error($config['error']['noaccess']); - + if ($edit_raw_html && !hasPermission($config['mod']['rawhtml'], $board)) error($config['error']['noaccess']); $security_token = make_secure_link_token($board . '/edit' . ($edit_raw_html ? '_raw' : '') . '/' . $postID); - + $query = prepare(sprintf('SELECT * FROM ``posts_%s`` WHERE `id` = :id', $board)); $query->bindValue(':id', $postID); $query->execute() or error(db_error($query)); if (!$post = $query->fetch(PDO::FETCH_ASSOC)) error($config['error']['404']); - + if (isset($_POST['name'], $_POST['email'], $_POST['subject'], $_POST['body'])) { // Remove any modifiers they may have put in $_POST['body'] = remove_modifiers($_POST['body']); @@ -1998,33 +2005,33 @@ function mod_edit_post($board, $edit_raw_html, $postID) { $query->bindValue(':body_nomarkup', $body_nomarkup); } $query->execute() or error(db_error($query)); - + if ($edit_raw_html) { modLog("Edited raw HTML of post #{$postID}"); } else { modLog("Edited post #{$postID}"); rebuildPost($postID); } - + buildIndex(); rebuildThemes('post', $board); - + header('Location: ?/' . sprintf($config['board_path'], $board) . $config['dir']['res'] . link_for($post) . '#' . $postID, true, $config['redirect_http']); } else { // Remove modifiers - $post['body_nomarkup'] = remove_modifiers($post['body_nomarkup']); - - $post['body_nomarkup'] = utf8tohtml($post['body_nomarkup']); - $post['body'] = utf8tohtml($post['body']); - if ($config['minify_html']) { + //$post['body_nomarkup'] = remove_modifiers($post['body_nomarkup']); + + //$post['body_nomarkup'] = utf8tohtml($post['body_nomarkup']); + //$post['body'] = utf8tohtml($post['body']); + /*if ($config['minify_html']) { $post['body_nomarkup'] = str_replace("\n", ' ', $post['body_nomarkup']); $post['body'] = str_replace("\n", ' ', $post['body']); $post['body_nomarkup'] = str_replace("\r", '', $post['body_nomarkup']); $post['body'] = str_replace("\r", '', $post['body']); $post['body_nomarkup'] = str_replace("\t", ' ', $post['body_nomarkup']); $post['body'] = str_replace("\t", ' ', $post['body']); - } + }*/ mod_page(_('Edit post'), 'mod/edit_post_form.html', array('token' => $security_token, 'board' => $board, 'raw' => $edit_raw_html, 'post' => $post)); } @@ -2032,13 +2039,13 @@ function mod_edit_post($board, $edit_raw_html, $postID) { function mod_delete($board, $post) { global $config, $mod; - + if (!openBoard($board)) error($config['error']['noboard']); - + if (!hasPermission($config['mod']['delete'], $board)) error($config['error']['noaccess']); - + // Delete post if ($config['autotagging']){ $query = prepare(sprintf("SELECT * FROM ``posts_%s`` WHERE id = :id", $board)); @@ -2064,10 +2071,10 @@ function mod_delete($board, $post) { $filename .= $mypost['files'][$file_count]->name . "\r\n"; } } - if ($time !== ''){ - $dt = new DateTime("@$time"); + if ($time !== ''){ + $dt = new DateTime("@$time"); $autotag = ""; - $autotag .= $name . " " . $subject . " " . $dt->format('Y-m-d H:i:s') . " No.". $post . "\r\n"; + $autotag .= $name . " " . $subject . " " . $dt->format('Y-m-d H:i:s') . " No.". $post . "\r\n"; $autotag .= "/${board}/" . " " . $filehash . " " . $filename ."\r\n"; $autotag .= $body . "\r\n"; $autotag = escape_markup_modifiers($autotag); @@ -2080,7 +2087,7 @@ function mod_delete($board, $post) { $query->execute() or error(db_error($query)); modLog("Added a note for {$ip}"); } - } + } deletePost($post); // Record the action modLog("Deleted post #{$post}"); @@ -2098,33 +2105,33 @@ function mod_delete($board, $post) { function mod_deletefile($board, $post, $file) { global $config, $mod; - + if (!openBoard($board)) error($config['error']['noboard']); - + if (!hasPermission($config['mod']['deletefile'], $board)) error($config['error']['noaccess']); - + // Delete file deleteFile($post, TRUE, $file); // Record the action modLog("Deleted file from post #{$post}"); - + // Rebuild board buildIndex(); // Rebuild themes rebuildThemes('post-delete', $board); - + // Redirect header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']); } function mod_spoiler_image($board, $post, $file) { global $config, $mod; - + if (!openBoard($board)) error($config['error']['noboard']); - + if (!hasPermission($config['mod']['spoilerimage'], $board)) error($config['error']['noaccess']); @@ -2141,7 +2148,7 @@ function mod_spoiler_image($board, $post, $file) { $files[$file]->thumb = 'spoiler'; $files[$file]->thumbwidth = $size_spoiler_image[0]; $files[$file]->thumbheight = $size_spoiler_image[1]; - + // Make thumbnail spoiler $query = prepare(sprintf("UPDATE ``posts_%s`` SET `files` = :files WHERE `id` = :id", $board)); $query->bindValue(':files', json_encode($files)); @@ -2159,49 +2166,49 @@ function mod_spoiler_image($board, $post, $file) { // Rebuild themes rebuildThemes('post-delete', $board); - + // Redirect header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']); } function mod_deletebyip($boardName, $post, $global = false) { global $config, $mod, $board; - + $global = (bool)$global; - + if (!openBoard($boardName)) error($config['error']['noboard']); - + if (!$global && !hasPermission($config['mod']['deletebyip'], $boardName)) error($config['error']['noaccess']); - + if ($global && !hasPermission($config['mod']['deletebyip_global'], $boardName)) error($config['error']['noaccess']); - + // Find IP address $query = prepare(sprintf('SELECT `ip` FROM ``posts_%s`` WHERE `id` = :id', $boardName)); $query->bindValue(':id', $post); $query->execute() or error(db_error($query)); if (!$ip = $query->fetchColumn()) error($config['error']['invalidpost']); - + $boards = $global ? listBoards() : array(array('uri' => $boardName)); - + $query = ''; foreach ($boards as $_board) { $query .= sprintf("SELECT `thread`, `id`, '%s' AS `board` FROM ``posts_%s`` WHERE `ip` = :ip UNION ALL ", $_board['uri'], $_board['uri']); } $query = preg_replace('/UNION ALL $/', '', $query); - + $query = prepare($query); $query->bindValue(':ip', $ip); $query->execute() or error(db_error($query)); - + if ($query->rowCount() < 1) error($config['error']['invalidpost']); - + @set_time_limit($config['mod']['rebuild_timelimit']); - + $threads_to_rebuild = array(); $threads_deleted = array(); while ($post = $query->fetch(PDO::FETCH_ASSOC)) { @@ -2229,11 +2236,11 @@ function mod_deletebyip($boardName, $post, $global = false) { for ($file_count = 0; $file_count < $mypost["num_files"];$file_count++){ $filename .= $mypost['files'][$file_count]->name . "\r\n"; } - } - if ($time !== ''){ - $dt = new DateTime("@$time"); + } + if ($time !== ''){ + $dt = new DateTime("@$time"); $autotag = ""; - $autotag .= $name . " " . $subject . " " . $dt->format('Y-m-d H:i:s') . " No.". $post['id'] . "\r\n"; + $autotag .= $name . " " . $subject . " " . $dt->format('Y-m-d H:i:s') . " No.". $post['id'] . "\r\n"; $autotag .= "/${post['board']}/" . " " . $filehash . " " . $filename ."\r\n"; $autotag .= $body . "\r\n"; $autotag = escape_markup_modifiers($autotag); @@ -2246,12 +2253,12 @@ function mod_deletebyip($boardName, $post, $global = false) { $query2->execute() or error(db_error($query2)); modLog("Added a note for {$ip}"); } - } - + } + deletePost($post['id'], false, false); rebuildThemes('post-delete', $board['uri']); - + buildIndex(); if ($post['thread']) @@ -2259,7 +2266,7 @@ function mod_deletebyip($boardName, $post, $global = false) { else $threads_deleted[$post['board']][$post['id']] = true; } - + foreach ($threads_to_rebuild as $_board => $_threads) { openBoard($_board); foreach ($_threads as $_thread => $_dummy) { @@ -2268,30 +2275,30 @@ function mod_deletebyip($boardName, $post, $global = false) { } buildIndex(); } - + if ($global) { $board = false; } - + // Record the action modLog("Deleted all posts by IP address: $ip"); - + // Redirect header('Location: ?/' . sprintf($config['board_path'], $boardName) . $config['file_index'], true, $config['redirect_http']); } function mod_user($uid) { global $config, $mod; - + if (!hasPermission($config['mod']['editusers']) && !(hasPermission($config['mod']['change_password']) && $uid == $mod['id'])) error($config['error']['noaccess']); - + $query = prepare('SELECT * FROM ``mods`` WHERE `id` = :id'); $query->bindValue(':id', $uid); $query->execute() or error(db_error($query)); if (!$user = $query->fetch(PDO::FETCH_ASSOC)) error($config['error']['404']); - + if (hasPermission($config['mod']['editusers']) && isset($_POST['username'], $_POST['password'])) { if (isset($_POST['allboards'])) { $boards = array('*'); @@ -2300,43 +2307,43 @@ function mod_user($uid) { foreach ($_boards as &$board) { $board = $board['uri']; } - + $boards = array(); foreach ($_POST as $name => $value) { if (preg_match('/^board_(' . $config['board_regex'] . ')$/u', $name, $matches) && in_array($matches[1], $_boards)) $boards[] = $matches[1]; } } - + if (isset($_POST['delete'])) { if (!hasPermission($config['mod']['deleteusers'])) error($config['error']['noaccess']); - + $query = prepare('DELETE FROM ``mods`` WHERE `id` = :id'); $query->bindValue(':id', $uid); $query->execute() or error(db_error($query)); - + modLog('Deleted user ' . utf8tohtml($user['username']) . ' (#' . $user['id'] . ')'); - + header('Location: ?/users', true, $config['redirect_http']); - + return; } - + if ($_POST['username'] == '') error(sprintf($config['error']['required'], 'username')); - + $query = prepare('UPDATE ``mods`` SET `username` = :username, `boards` = :boards WHERE `id` = :id'); $query->bindValue(':id', $uid); $query->bindValue(':username', $_POST['username']); $query->bindValue(':boards', implode(',', $boards)); $query->execute() or error(db_error($query)); - + if ($user['username'] !== $_POST['username']) { // account was renamed modLog('Renamed user "' . utf8tohtml($user['username']) . '" (#' . $user['id'] . ') to "' . utf8tohtml($_POST['username']) . '"'); } - + if ($_POST['password'] != '') { list($version, $password) = crypt_password($_POST['password']); @@ -2345,23 +2352,23 @@ function mod_user($uid) { $query->bindValue(':password', $password); $query->bindValue(':version', $version); $query->execute() or error(db_error($query)); - + modLog('Changed password for ' . utf8tohtml($_POST['username']) . ' (#' . $user['id'] . ')'); - + if ($uid == $mod['id']) { login($_POST['username'], $_POST['password']); setCookies(); } } - + if (hasPermission($config['mod']['manageusers'])) header('Location: ?/users', true, $config['redirect_http']); else header('Location: ?/', true, $config['redirect_http']); - + return; } - + if (hasPermission($config['mod']['change_password']) && $uid == $mod['id'] && isset($_POST['password'])) { if ($_POST['password'] != '') { list($version, $password) = crypt_password($_POST['password']); @@ -2371,21 +2378,21 @@ function mod_user($uid) { $query->bindValue(':password', $password); $query->bindValue(':version', $version); $query->execute() or error(db_error($query)); - + modLog('Changed own password'); - + login($user['username'], $_POST['password']); setCookies(); } - + if (hasPermission($config['mod']['manageusers'])) header('Location: ?/users', true, $config['redirect_http']); else header('Location: ?/', true, $config['redirect_http']); - + return; } - + if (hasPermission($config['mod']['modlog'])) { $query = prepare('SELECT * FROM ``modlogs`` WHERE `mod` = :id ORDER BY `time` DESC LIMIT 5'); $query->bindValue(':id', $uid); @@ -2394,9 +2401,9 @@ function mod_user($uid) { } else { $log = array(); } - + $user['boards'] = explode(',', $user['boards']); - + mod_page(_('Edit user'), 'mod/user.html', array( 'user' => $user, 'logs' => $log, @@ -2407,16 +2414,16 @@ function mod_user($uid) { function mod_user_new() { global $pdo, $config; - + if (!hasPermission($config['mod']['createusers'])) error($config['error']['noaccess']); - + if (isset($_POST['username'], $_POST['password'], $_POST['type'])) { if ($_POST['username'] == '') error(sprintf($config['error']['required'], 'username')); if ($_POST['password'] == '') error(sprintf($config['error']['required'], 'password')); - + if (isset($_POST['allboards'])) { $boards = array('*'); } else { @@ -2424,20 +2431,20 @@ function mod_user_new() { foreach ($_boards as &$board) { $board = $board['uri']; } - + $boards = array(); foreach ($_POST as $name => $value) { if (preg_match('/^board_(' . $config['board_regex'] . ')$/u', $name, $matches) && in_array($matches[1], $_boards)) $boards[] = $matches[1]; } } - + $type = (int)$_POST['type']; if (!isset($config['mod']['groups'][$type]) || $type == DISABLED) error(sprintf($config['error']['invalidfield'], 'type')); - + list($version, $password) = crypt_password($_POST['password']); - + $query = prepare('INSERT INTO ``mods`` VALUES (NULL, :username, :password, :version, :type, :boards)'); $query->bindValue(':username', $_POST['username']); $query->bindValue(':password', $password); @@ -2445,59 +2452,59 @@ function mod_user_new() { $query->bindValue(':type', $type); $query->bindValue(':boards', implode(',', $boards)); $query->execute() or error(db_error($query)); - + $userID = $pdo->lastInsertId(); - + modLog('Created a new user: ' . utf8tohtml($_POST['username']) . ' (#' . $userID . ')'); - + header('Location: ?/users', true, $config['redirect_http']); return; } - + mod_page(_('New user'), 'mod/user.html', array('new' => true, 'boards' => listBoards(), 'token' => make_secure_link_token('users/new'))); } function mod_users() { global $config; - + if (!hasPermission($config['mod']['manageusers'])) error($config['error']['noaccess']); - + $query = query("SELECT *, (SELECT `time` FROM ``modlogs`` WHERE `mod` = `id` ORDER BY `time` DESC LIMIT 1) AS `last`, (SELECT `text` FROM ``modlogs`` WHERE `mod` = `id` ORDER BY `time` DESC LIMIT 1) AS `action` FROM ``mods`` ORDER BY `type` DESC,`id`") or error(db_error()); $users = $query->fetchAll(PDO::FETCH_ASSOC); - + foreach ($users as &$user) { $user['promote_token'] = make_secure_link_token("users/{$user['id']}/promote"); $user['demote_token'] = make_secure_link_token("users/{$user['id']}/demote"); } - + mod_page(sprintf('%s (%d)', _('Manage users'), count($users)), 'mod/users.html', array('users' => $users)); } function mod_user_promote($uid, $action) { global $config; - + if (!hasPermission($config['mod']['promoteusers'])) error($config['error']['noaccess']); - + $query = prepare("SELECT `type`, `username` FROM ``mods`` WHERE `id` = :id"); $query->bindValue(':id', $uid); $query->execute() or error(db_error($query)); - + if (!$mod = $query->fetch(PDO::FETCH_ASSOC)) error($config['error']['404']); - + $new_group = false; - + $groups = $config['mod']['groups']; if ($action == 'demote') $groups = array_reverse($groups, true); - + foreach ($groups as $group_value => $group_name) { if ($action == 'promote' && $group_value > $mod['type']) { $new_group = $group_value; @@ -2507,65 +2514,65 @@ function mod_user_promote($uid, $action) { break; } } - + if ($new_group === false || $new_group == DISABLED) error(_('Impossible to promote/demote user.')); - + $query = prepare("UPDATE ``mods`` SET `type` = :group_value WHERE `id` = :id"); $query->bindValue(':id', $uid); $query->bindValue(':group_value', $new_group); $query->execute() or error(db_error($query)); - + modLog(($action == 'promote' ? 'Promoted' : 'Demoted') . ' user "' . utf8tohtml($mod['username']) . '" to ' . $config['mod']['groups'][$new_group]); - + header('Location: ?/users', true, $config['redirect_http']); } function mod_pm($id, $reply = false) { global $mod, $config; - + if ($reply && !hasPermission($config['mod']['create_pm'])) error($config['error']['noaccess']); - + $query = prepare("SELECT ``mods``.`username`, `mods_to`.`username` AS `to_username`, ``pms``.* FROM ``pms`` LEFT JOIN ``mods`` ON ``mods``.`id` = `sender` LEFT JOIN ``mods`` AS `mods_to` ON `mods_to`.`id` = `to` WHERE ``pms``.`id` = :id"); $query->bindValue(':id', $id); $query->execute() or error(db_error($query)); - + if ((!$pm = $query->fetch(PDO::FETCH_ASSOC)) || ($pm['to'] != $mod['id'] && !hasPermission($config['mod']['master_pm']))) error($config['error']['404']); - + if (isset($_POST['delete'])) { $query = prepare("DELETE FROM ``pms`` WHERE `id` = :id"); $query->bindValue(':id', $id); $query->execute() or error(db_error($query)); - + if ($config['cache']['enabled']) { cache::delete('pm_unread_' . $mod['id']); cache::delete('pm_unreadcount_' . $mod['id']); } - + header('Location: ?/', true, $config['redirect_http']); return; } - + if ($pm['unread'] && $pm['to'] == $mod['id']) { $query = prepare("UPDATE ``pms`` SET `unread` = 0 WHERE `id` = :id"); $query->bindValue(':id', $id); $query->execute() or error(db_error($query)); - + if ($config['cache']['enabled']) { cache::delete('pm_unread_' . $mod['id']); cache::delete('pm_unreadcount_' . $mod['id']); } - + modLog('Read a PM'); } - + if ($reply) { if (!$pm['to_username']) error($config['error']['404']); // deleted? - + mod_page(sprintf('%s %s', _('New PM for'), $pm['to_username']), 'mod/new_pm.html', array( 'username' => $pm['username'], 'id' => $pm['sender'], @@ -2579,21 +2586,21 @@ function mod_pm($id, $reply = false) { function mod_inbox() { global $config, $mod; - + $query = prepare('SELECT `unread`,``pms``.`id`, `time`, `sender`, `to`, `message`, `username` FROM ``pms`` LEFT JOIN ``mods`` ON ``mods``.`id` = `sender` WHERE `to` = :mod ORDER BY `unread` DESC, `time` DESC'); $query->bindValue(':mod', $mod['id']); $query->execute() or error(db_error($query)); $messages = $query->fetchAll(PDO::FETCH_ASSOC); - + $query = prepare('SELECT COUNT(*) FROM ``pms`` WHERE `to` = :mod AND `unread` = 1'); $query->bindValue(':mod', $mod['id']); $query->execute() or error(db_error($query)); $unread = $query->fetchColumn(); - + foreach ($messages as &$message) { $message['snippet'] = pm_snippet($message['message']); } - + mod_page(sprintf('%s (%s)', _('PM inbox'), count($messages) > 0 ? $unread . ' unread' : 'empty'), 'mod/inbox.html', array( 'messages' => $messages, 'unread' => $unread @@ -2603,10 +2610,10 @@ function mod_inbox() { function mod_new_pm($username) { global $config, $mod; - + if (!hasPermission($config['mod']['create_pm'])) error($config['error']['noaccess']); - + $query = prepare("SELECT `id` FROM ``mods`` WHERE `username` = :username"); $query->bindValue(':username', $username); $query->execute() or error(db_error($query)); @@ -2620,28 +2627,28 @@ function mod_new_pm($username) { else error($config['error']['404']); } - + if (isset($_POST['message'])) { $_POST['message'] = escape_markup_modifiers($_POST['message']); markup($_POST['message']); - + $query = prepare("INSERT INTO ``pms`` VALUES (NULL, :me, :id, :message, :time, 1)"); $query->bindValue(':me', $mod['id']); $query->bindValue(':id', $id); $query->bindValue(':message', $_POST['message']); $query->bindValue(':time', time()); $query->execute() or error(db_error($query)); - + if ($config['cache']['enabled']) { cache::delete('pm_unread_' . $id); cache::delete('pm_unreadcount_' . $id); } - + modLog('Sent a PM to ' . utf8tohtml($username)); - + header('Location: ?/', true, $config['redirect_http']); } - + mod_page(sprintf('%s %s', _('New PM for'), $username), 'mod/new_pm.html', array( 'username' => $username, 'id' => $id, @@ -2652,59 +2659,59 @@ function mod_new_pm($username) { function mod_rebuild() { global $config, $twig; print_err("mod_rebuild"); - + if (!hasPermission($config['mod']['rebuild'])) error($config['error']['noaccess']); - + if (isset($_POST['rebuild'])) { @set_time_limit($config['mod']['rebuild_timelimit']); - + $log = array(); $boards = listBoards(); $rebuilt_scripts = array(); - + if (isset($_POST['rebuild_cache'])) { if ($config['cache']['enabled']) { $log[] = 'Flushing cache'; Cache::flush(); } - + $log[] = 'Clearing template cache'; load_twig(); $twig->clearCacheFiles(); } - + if (isset($_POST['rebuild_themes'])) { $log[] = 'Regenerating theme files'; print_err("mod_rebuild calling rebuildThemes"); rebuildThemes('all'); print_err("mod_rebuild calling rebuildThemes ok"); } - + if (isset($_POST['rebuild_javascript'])) { $log[] = 'Rebuilding ' . $config['file_script'] . ''; buildJavascript(); $rebuilt_scripts[] = $config['file_script']; } - + foreach ($boards as $board) { if (!(isset($_POST['boards_all']) || isset($_POST['board_' . $board['uri']]))) continue; - + openBoard($board['uri']); $config['try_smarter'] = false; - + if (isset($_POST['rebuild_index'])) { buildIndex(); $log[] = '' . sprintf($config['board_abbreviation'], $board['uri']) . ': Creating index pages'; } - + if (isset($_POST['rebuild_javascript']) && !in_array($config['file_script'], $rebuilt_scripts)) { $log[] = '' . sprintf($config['board_abbreviation'], $board['uri']) . ': Rebuilding ' . $config['file_script'] . ''; buildJavascript(); $rebuilt_scripts[] = $config['file_script']; } - + if (isset($_POST['rebuild_thread'])) { $query = query(sprintf("SELECT `id` FROM ``posts_%s`` WHERE `thread` IS NULL", $board['uri'])) or error(db_error()); while ($post = $query->fetch(PDO::FETCH_ASSOC)) { @@ -2713,11 +2720,11 @@ function mod_rebuild() { } } } - + mod_page(_('Rebuild'), 'mod/rebuilt.html', array('logs' => $log)); return; } - + mod_page(_('Rebuild'), 'mod/rebuild.html', array( 'boards' => listBoards(), 'token' => make_secure_link_token('rebuild') @@ -2726,32 +2733,32 @@ function mod_rebuild() { function mod_reports() { global $config, $mod; - + if (!hasPermission($config['mod']['reports'])) error($config['error']['noaccess']); - + $query = prepare("SELECT * FROM ``reports`` ORDER BY `time` DESC LIMIT :limit"); $query->bindValue(':limit', $config['mod']['recent_reports'], PDO::PARAM_INT); $query->execute() or error(db_error($query)); $reports = $query->fetchAll(PDO::FETCH_ASSOC); - + $report_queries = array(); foreach ($reports as $report) { if (!isset($report_queries[$report['board']])) $report_queries[$report['board']] = array(); $report_queries[$report['board']][] = $report['post']; } - + $report_posts = array(); foreach ($report_queries as $board => $posts) { $report_posts[$board] = array(); - + $query = query(sprintf('SELECT * FROM ``posts_%s`` WHERE `id` = ' . implode(' OR `id` = ', $posts), $board)) or error(db_error()); while ($post = $query->fetch(PDO::FETCH_ASSOC)) { $report_posts[$board][$post['id']] = $post; } } - + $count = 0; $body = ''; foreach ($reports as $report) { @@ -2763,18 +2770,18 @@ function mod_reports() { $query->execute() or error(db_error($query)); continue; } - + openBoard($report['board']); - + $post = &$report_posts[$report['board']][$report['post']]; - + if (!$post['thread']) { // Still need to fix this: $po = new Thread($post, '?/', $mod, false); } else { $po = new Post($post, '?/', $mod); } - + // a little messy and inefficient $append_html = Element('mod/report.html', array( 'report' => $report, @@ -2783,32 +2790,32 @@ function mod_reports() { 'token' => make_secure_link_token('reports/' . $report['id'] . '/dismiss'), 'token_all' => make_secure_link_token('reports/' . $report['id'] . '/dismissall') )); - + // Bug fix for https://github.com/savetheinternet/Tinyboard/issues/21 $po->body = truncate($po->body, $po->link(), $config['body_truncate'] - substr_count($append_html, '
')); - + if (mb_strlen($po->body) + mb_strlen($append_html) > $config['body_truncate_char']) { // still too long; temporarily increase limit in the config $__old_body_truncate_char = $config['body_truncate_char']; $config['body_truncate_char'] = mb_strlen($po->body) + mb_strlen($append_html); } - + $po->body .= $append_html; - + $body .= $po->build(true) . '
'; - + if (isset($__old_body_truncate_char)) $config['body_truncate_char'] = $__old_body_truncate_char; - + $count++; } - + mod_page(sprintf('%s (%d)', _('Report queue'), $count), 'mod/reports.html', array('reports' => $body, 'count' => $count)); } function mod_report_dismiss($id, $all = false) { global $config; - + $query = prepare("SELECT `post`, `board`, `ip` FROM ``reports`` WHERE `id` = :id"); $query->bindValue(':id', $id); $query->execute() or error(db_error($query)); @@ -2818,13 +2825,13 @@ function mod_report_dismiss($id, $all = false) { $post = $report['post']; } else error($config['error']['404']); - + if (!$all && !hasPermission($config['mod']['report_dismiss'], $board)) error($config['error']['noaccess']); - + if ($all && !hasPermission($config['mod']['report_dismiss_ip'], $board)) error($config['error']['noaccess']); - + if ($all) { $query = prepare("DELETE FROM ``reports`` WHERE `ip` = :ip"); $query->bindValue(':ip', $ip); @@ -2833,19 +2840,19 @@ function mod_report_dismiss($id, $all = false) { $query->bindValue(':id', $id); } $query->execute() or error(db_error($query)); - - + + if ($all) modLog("Dismissed all reports by $ip"); else modLog("Dismissed a report for post #{$id}", $board); - + header('Location: ?/reports', true, $config['redirect_http']); } function mod_recent_posts($lim,$board_list = false,$json=false) { global $config, $mod, $pdo; - + if (!hasPermission($config['mod']['recent'])) error($config['error']['noaccess']); @@ -2882,7 +2889,7 @@ function mod_recent_posts($lim,$board_list = false,$json=false) { $mod_boards[] = $board; } } - } + } // Manually build an SQL query $query = 'SELECT * FROM ('; @@ -2895,7 +2902,7 @@ function mod_recent_posts($lim,$board_list = false,$json=false) { $query->bindValue(':last_time', $last_time); $query->execute() or error(db_error($query)); $posts = $query->fetchAll(PDO::FETCH_ASSOC); - + if ($config['api']['enabled']) { $apithreads = array(); } @@ -2909,13 +2916,13 @@ function mod_recent_posts($lim,$board_list = false,$json=false) { if ($config['api']['enabled']) { $apithreads[] = $po; } - + } else { $po = new Post($post, '?/', $mod); $post['built'] = $po->build(true); if ($config['api']['enabled']) { $pot = new Thread($post, '?/', $mod, false); - $pot->add($po); + $pot->add($po); $apithreads[] = $pot; } } @@ -2927,11 +2934,11 @@ function mod_recent_posts($lim,$board_list = false,$json=false) { $jsonFilename = 'mod/' . 'recent.json'; $jsondata = json_encode($api->translatePage($apithreads)); } - + if ($json){ echo $jsondata; } - else { + else { echo mod_page(_('Recent posts'), 'mod/recent_posts.html', array( 'posts' => $posts, 'limit' => $limit, @@ -2943,18 +2950,18 @@ function mod_recent_posts($lim,$board_list = false,$json=false) { function mod_config($board_config = false) { global $config, $mod, $board; - + if ($board_config && !openBoard($board_config)) error($config['error']['noboard']); - + if (!hasPermission($config['mod']['edit_config'], $board_config)) error($config['error']['noaccess']); - + $config_file = $board_config ? $board['dir'] . 'config.php' : 'inc/instance-config.php'; - + if ($config['mod']['config_editor_php']) { $readonly = !(is_file($config_file) ? is_writable($config_file) : is_writable(dirname($config_file))); - + if (!$readonly && isset($_POST['code'])) { $code = $_POST['code']; // Save previous instance_config if php_check_syntax fails @@ -2968,15 +2975,15 @@ function mod_config($board_config = false) { else { file_put_contents($config_file, $old_code); error($config['error']['badsyntax'] . $resp); - } + } } - + $instance_config = @file_get_contents($config_file); if ($instance_config === false) { $instance_config = " $instance_config, 'readonly' => $readonly, @@ -2987,11 +2994,11 @@ function mod_config($board_config = false) { )); return; } - + require_once 'inc/mod/config-editor.php'; - + $conf = config_vars(); - + foreach ($conf as &$var) { if (is_array($var['name'])) { $c = &$config; @@ -3000,40 +3007,40 @@ function mod_config($board_config = false) { } else { $c = @$config[$var['name']]; } - + $var['value'] = $c; } unset($var); - + if (isset($_POST['save'])) { $config_append = ''; - + foreach ($conf as $var) { $field_name = 'cf_' . (is_array($var['name']) ? implode('/', $var['name']) : $var['name']); - + if ($var['type'] == 'boolean') $value = isset($_POST[$field_name]); elseif (isset($_POST[$field_name])) $value = $_POST[$field_name]; else continue; // ??? - + if (!settype($value, $var['type'])) continue; // invalid - + if ($value != $var['value']) { // This value has been changed. - + $config_append .= '$config'; - + if (is_array($var['name'])) { foreach ($var['name'] as $name) $config_append .= '[' . var_export($name, true) . ']'; } else { $config_append .= '[' . var_export($var['name'], true) . ']'; } - - + + $config_append .= ' = '; if (@$var['permissions'] && isset($config['mod']['groups'][$value])) { $config_append .= $config['mod']['groups'][$value]; @@ -3043,14 +3050,14 @@ function mod_config($board_config = false) { $config_append .= ";\n"; } } - + if (!empty($config_append)) { $config_append = "\n// Changes made via web editor by \"" . $mod['username'] . "\" @ " . date('r') . ":\n" . $config_append . "\n"; if (!is_file($config_file)) $config_append = " &$theme) { $theme['rebuild_token'] = make_secure_link_token('themes/' . $theme_name . '/rebuild'); $theme['uninstall_token'] = make_secure_link_token('themes/' . $theme_name . '/uninstall'); @@ -3131,12 +3138,12 @@ function mod_theme_configure($theme_name) { if (!isset($_POST[$conf['name']]) && $conf['type'] != 'checkbox') error(sprintf($config['error']['required'], $c['title'])); } - + // Clear previous settings $query = prepare("DELETE FROM ``theme_settings`` WHERE `theme` = :theme"); $query->bindValue(':theme', $theme_name); $query->execute() or error(db_error($query)); - + foreach ($theme['config'] as &$conf) { $query = prepare("INSERT INTO ``theme_settings`` VALUES(:theme, :name, :value)"); $query->bindValue(':theme', $theme_name); @@ -3155,7 +3162,7 @@ function mod_theme_configure($theme_name) { // Clean cache Cache::delete("themes"); Cache::delete("theme_settings_".$theme_name); - + $result = true; $message = false; if (isset($theme['install_callback'])) { @@ -3167,17 +3174,17 @@ function mod_theme_configure($theme_name) { } } } - + if (!$result) { // Install failed $query = prepare("DELETE FROM ``theme_settings`` WHERE `theme` = :theme"); $query->bindValue(':theme', $theme_name); $query->execute() or error(db_error($query)); } - + // Build themes rebuildThemes('all'); - + mod_page(sprintf(_($result ? 'Installed theme: %s' : 'Installation failed: %s'), $theme['name']), 'mod/theme_installed.html', array( 'theme_name' => $theme_name, 'theme' => $theme, @@ -3219,7 +3226,7 @@ function mod_theme_rebuild($theme_name) { if (!hasPermission($config['mod']['themes'])) error($config['error']['noaccess']); - + rebuildTheme($theme_name, 'all'); mod_page(sprintf(_('Rebuilt theme: %s'), $theme_name), 'mod/theme_rebuilt.html', array( @@ -3270,7 +3277,7 @@ function mod_edit_page($id) { $query->bindValue(':id', $id); $query->execute() or error(db_error($query)); $page = $query->fetch(); - + if (!$page) error(_('Could not find the page you are trying to edit.')); @@ -3287,12 +3294,12 @@ function mod_edit_page($id) { $content = $_POST['content']; $method = $_POST['method']; $page['type'] = $method; - + if (!in_array($method, array('markdown', 'html', 'infinity'))) error(_('Unrecognized page markup method.')); - + switch ($method) { - case 'markdown': + case 'markdown': $write = markdown($content); break; case 'html': @@ -3330,7 +3337,7 @@ function mod_edit_page($id) { $query->execute() or error(db_error($query)); $content = $query->fetchColumn(); } - + mod_page(sprintf(_('Editing static page: %s'), $page['name']), 'mod/edit_page.html', array('page' => $page, 'token' => make_secure_link_token("edit_page/$id"), 'content' => prettify_textarea($content), 'board' => $board)); } @@ -3390,48 +3397,48 @@ function mod_pages($board = false) { function mod_debug_antispam() { global $pdo, $config; - + $args = array(); - + if (isset($_POST['board'], $_POST['thread'])) { $where = '`board` = ' . $pdo->quote($_POST['board']); if ($_POST['thread'] != '') $where .= ' AND `thread` = ' . $pdo->quote($_POST['thread']); - + if (isset($_POST['purge'])) { $query = prepare(', DATE ``antispam`` SET `expires` = UNIX_TIMESTAMP() + :expires WHERE' . $where); $query->bindValue(':expires', $config['spam']['hidden_inputs_expire']); $query->execute() or error(db_error()); } - + $args['board'] = $_POST['board']; $args['thread'] = $_POST['thread']; } else { $where = ''; } - + $query = query('SELECT COUNT(*) FROM ``antispam``' . ($where ? " WHERE $where" : '')) or error(db_error()); $args['total'] = number_format($query->fetchColumn()); - + $query = query('SELECT COUNT(*) FROM ``antispam`` WHERE `expires` IS NOT NULL' . ($where ? " AND $where" : '')) or error(db_error()); $args['expiring'] = number_format($query->fetchColumn()); - + $query = query('SELECT * FROM ``antispam`` ' . ($where ? "WHERE $where" : '') . ' ORDER BY `passed` DESC LIMIT 40') or error(db_error()); $args['top'] = $query->fetchAll(PDO::FETCH_ASSOC); - + $query = query('SELECT * FROM ``antispam`` ' . ($where ? "WHERE $where" : '') . ' ORDER BY `created` DESC LIMIT 20') or error(db_error()); $args['recent'] = $query->fetchAll(PDO::FETCH_ASSOC); - + mod_page(_('Debug: Anti-spam'), 'mod/debug/antispam.html', $args); } function mod_debug_recent_posts() { global $pdo, $config; - + $limit = 500; - + $boards = listBoards(); - + // Manually build an SQL query $query = 'SELECT * FROM ('; foreach ($boards as $board) { @@ -3441,11 +3448,11 @@ function mod_debug_recent_posts() { $query = preg_replace('/UNION ALL $/', ') AS `all_posts` ORDER BY `time` DESC LIMIT ' . $limit, $query); $query = query($query) or error(db_error()); $posts = $query->fetchAll(PDO::FETCH_ASSOC); - + // Fetch recent posts from flood prevention cache $query = query("SELECT * FROM ``flood`` ORDER BY `time` DESC") or error(db_error()); $flood_posts = $query->fetchAll(PDO::FETCH_ASSOC); - + foreach ($posts as &$post) { $post['snippet'] = pm_snippet($post['body']); foreach ($flood_posts as $flood_post) { @@ -3455,18 +3462,18 @@ function mod_debug_recent_posts() { $post['in_flood_table'] = true; } } - + mod_page(_('Debug: Recent posts'), 'mod/debug/recent_posts.html', array('posts' => $posts, 'flood_posts' => $flood_posts)); } function mod_debug_sql() { global $config; - + if (!hasPermission($config['mod']['debug_sql'])) error($config['error']['noaccess']); - + $args['security_token'] = make_secure_link_token('debug/sql'); - + if (isset($_POST['query'])) { $args['query'] = $_POST['query']; if ($query = query($_POST['query'])) { @@ -3479,21 +3486,21 @@ function mod_debug_sql() { $args['error'] = db_error(); } } - + mod_page(_('Debug: SQL'), 'mod/debug/sql.html', $args); } function mod_debug_apc() { global $config; - + if (!hasPermission($config['mod']['debug_apc'])) error($config['error']['noaccess']); - + if ($config['cache']['enabled'] != 'apc') error('APC is not enabled.'); - + $cache_info = apc_cache_info('user'); - + // $cached_vars = new APCIterator('user', '/^' . $config['cache']['prefix'] . '/'); $cached_vars = array(); foreach ($cache_info['cache_list'] as $var) { @@ -3501,7 +3508,6 @@ function mod_debug_apc() { continue; $cached_vars[] = $var; } - + mod_page(_('Debug: APC'), 'mod/debug/apc.html', array('cached_vars' => $cached_vars)); } - diff --git a/tests/ProtectIPTest.php b/tests/ProtectIPTest.php new file mode 100644 index 00000000..878eaa06 --- /dev/null +++ b/tests/ProtectIPTest.php @@ -0,0 +1,32 @@ +33.57.252.246'; + $output = protect_ip($input); + $this->assertEquals($output, $expected); + } + + public function testProtectsIpv6Address(){ + $expected = 'Some ban message: xxxx'; + + // Random IP, hope it's not yours + $input = 'Some ban message: 5e85:f252:9baf:2131:8984:6ab2:3db0:fa48'; + $output = protect_ip($input); + + $this->assertEquals($output, $expected); + } +}