diff --git a/inc/mod/pages.php b/inc/mod/pages.php index f109b194..e8b43a62 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -9,57 +9,57 @@ defined('TINYBOARD') or exit; require_once 'inc/anti-bot.php'; // DELETE ME THIS IS FOR print_err function only! function mod_page($title, $template, $args, $subtitle = false) { - global $config, $mod; - - echo Element('page.html', array( - 'config' => $config, - 'mod' => $mod, - 'hide_dashboard_link' => $template == 'mod/dashboard.html', - 'title' => $title, - 'subtitle' => $subtitle, - 'boardlist' => createBoardlist($mod), - 'body' => Element($template, - array_merge( - array('config' => $config, 'mod' => $mod), - $args - ) - ) - ) - ); + global $config, $mod; + + echo Element('page.html', array( + 'config' => $config, + 'mod' => $mod, + 'hide_dashboard_link' => $template == 'mod/dashboard.html', + 'title' => $title, + 'subtitle' => $subtitle, + 'boardlist' => createBoardlist($mod), + 'body' => Element($template, + array_merge( + array('config' => $config, 'mod' => $mod), + $args + ) + ) + ) + ); } 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'] == '') { - $args['error'] = $config['error']['invalid']; - } 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']; - - mod_page(_('Login'), 'mod/login.html', $args); + 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'] == '') { + $args['error'] = $config['error']['invalid']; + } 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']; + + mod_page(_('Login'), 'mod/login.html', $args); } function mod_confirm($request) { @@ -67,929 +67,929 @@ function mod_confirm($request) { if(isset($_GET['thread'])) { $args['rest'] = 'thread=' . $_GET['thread']; } - mod_page(_('Confirm action'), 'mod/confirm.html', $args); + mod_page(_('Confirm action'), 'mod/confirm.html', $args); } function mod_logout() { - global $config; - destroyCookies(); - - header('Location: ?/', true, $config['redirect_http']); + 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], - 'major' => $matches[2], - 'minor' => $matches[3] - ); - if (preg_match('/(\d+)\.(\d)\.(\d+)(-dev.+)?$/', $config['version'], $matches)) { - $current = array( - 'massive' => (int) $matches[1], - 'major' => (int) $matches[2], - 'minor' => (int) $matches[3] - ); - if (isset($m[4])) { - // Development versions are always ahead in the versioning numbers - $current['minor'] --; - } - // Check if it's newer - if (!( $latest['massive'] > $current['massive'] || - $latest['major'] > $current['major'] || - ($latest['massive'] == $current['massive'] && - $latest['major'] == $current['major'] && - $latest['minor'] > $current['minor'] - ))) - $latest = false; - } else { - $latest = false; - } - } else { - // Couldn't get latest version - $latest = false; - } - } else { - // 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); + 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], + 'major' => $matches[2], + 'minor' => $matches[3] + ); + if (preg_match('/(\d+)\.(\d)\.(\d+)(-dev.+)?$/', $config['version'], $matches)) { + $current = array( + 'massive' => (int) $matches[1], + 'major' => (int) $matches[2], + 'minor' => (int) $matches[3] + ); + if (isset($m[4])) { + // Development versions are always ahead in the versioning numbers + $current['minor'] --; + } + // Check if it's newer + if (!( $latest['massive'] > $current['massive'] || + $latest['major'] > $current['major'] || + ($latest['massive'] == $current['massive'] && + $latest['major'] == $current['major'] && + $latest['minor'] > $current['minor'] + ))) + $latest = false; + } else { + $latest = false; + } + } else { + // Couldn't get latest version + $latest = false; + } + } else { + // 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']); - } + 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']); + } } 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(); - - // Exact phrases ("like this") - if (preg_match_all('/"(.+?)"/', $query, $exact_phrases)) { - $exact_phrases = $exact_phrases[1]; - foreach ($exact_phrases as $phrase) { - $query = str_replace("\"{$phrase}\"", '', $query); - $match[] = $pdo->quote($phrase); - } - } - - // Non-exact phrases (ie. plain keywords) - $keywords = explode(' ', $query); - foreach ($keywords as $word) { - if (empty($word)) - continue; - $match[] = $pdo->quote($word); - } - - // Which `field` to search? - if ($type == 'posts') - $sql_field = array('body_nomarkup', 'files', 'subject', 'filehash', 'ip', 'name', 'trip'); - if ($type == 'IP_notes') - $sql_field = 'body'; - if ($type == 'bans') - $sql_field = 'reason'; - if ($type == 'log') - $sql_field = 'text'; - - // Build the "LIKE 'this' AND LIKE 'that'" etc. part of the SQL query - $sql_like = ''; - foreach ($match as $phrase) { - if (!empty($sql_like)) - $sql_like .= ' AND '; - $phrase = preg_replace('/^\'(.+)\'$/', '\'%$1%\'', $phrase); - if (is_array($sql_field)) { - foreach ($sql_field as $field) { - $sql_like .= '`' . $field . '` LIKE ' . $phrase . ' ESCAPE \'!\' OR'; - } - $sql_like = preg_replace('/ OR$/', '', $sql_like); - } else { - $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()); - $result_count = $q->fetchColumn(); - } else { - $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'])); - if (filter_var($ban['mask'], FILTER_VALIDATE_IP) !== false) - $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, - 'search_query_escaped' => $search_query_escaped, - 'result_count' => $result_count, - 'results' => $results - )); + 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(); + + // Exact phrases ("like this") + if (preg_match_all('/"(.+?)"/', $query, $exact_phrases)) { + $exact_phrases = $exact_phrases[1]; + foreach ($exact_phrases as $phrase) { + $query = str_replace("\"{$phrase}\"", '', $query); + $match[] = $pdo->quote($phrase); + } + } + + // Non-exact phrases (ie. plain keywords) + $keywords = explode(' ', $query); + foreach ($keywords as $word) { + if (empty($word)) + continue; + $match[] = $pdo->quote($word); + } + + // Which `field` to search? + if ($type == 'posts') + $sql_field = array('body_nomarkup', 'files', 'subject', 'filehash', 'ip', 'name', 'trip'); + if ($type == 'IP_notes') + $sql_field = 'body'; + if ($type == 'bans') + $sql_field = 'reason'; + if ($type == 'log') + $sql_field = 'text'; + + // Build the "LIKE 'this' AND LIKE 'that'" etc. part of the SQL query + $sql_like = ''; + foreach ($match as $phrase) { + if (!empty($sql_like)) + $sql_like .= ' AND '; + $phrase = preg_replace('/^\'(.+)\'$/', '\'%$1%\'', $phrase); + if (is_array($sql_field)) { + foreach ($sql_field as $field) { + $sql_like .= '`' . $field . '` LIKE ' . $phrase . ' ESCAPE \'!\' OR'; + } + $sql_like = preg_replace('/ OR$/', '', $sql_like); + } else { + $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()); + $result_count = $q->fetchColumn(); + } else { + $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'])); + if (filter_var($ban['mask'], FILTER_VALIDATE_IP) !== false) + $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, + 'search_query_escaped' => $search_query_escaped, + 'result_count' => $result_count, + 'results' => $results + )); } 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)); - while ($cite = $query->fetch(PDO::FETCH_ASSOC)) { - if ($board['uri'] != $cite['board']) { - if (!isset($tmp_board)) - $tmp_board = $board; - openBoard($cite['board']); - 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)) { - $user_boards = explode(',', $user['boards']); - if (in_array($board['uri'], $user_boards)) { - unset($user_boards[array_search($board['uri'], $user_boards)]); - $_query = prepare('UPDATE ``mods`` SET `boards` = :boards WHERE `id` = :id'); - $_query->bindValue(':boards', implode(',', $user_boards)); - $_query->bindValue(':id', $user['id']); - $_query->execute() or error(db_error($_query)); - } - } - - // Delete entire board directory - rrmdir($board['uri'] . '/'); - } else { - $query = prepare('UPDATE ``boards`` SET `title` = :title, `subtitle` = :subtitle WHERE `uri` = :uri'); - $query->bindValue(':uri', $board['uri']); - $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( - 'board' => $board, - 'token' => make_secure_link_token('edit/' . $board['uri']) - )); - } + 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)); + while ($cite = $query->fetch(PDO::FETCH_ASSOC)) { + if ($board['uri'] != $cite['board']) { + if (!isset($tmp_board)) + $tmp_board = $board; + openBoard($cite['board']); + 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)) { + $user_boards = explode(',', $user['boards']); + if (in_array($board['uri'], $user_boards)) { + unset($user_boards[array_search($board['uri'], $user_boards)]); + $_query = prepare('UPDATE ``mods`` SET `boards` = :boards WHERE `id` = :id'); + $_query->bindValue(':boards', implode(',', $user_boards)); + $_query->bindValue(':id', $user['id']); + $_query->execute() or error(db_error($_query)); + } + } + + // Delete entire board directory + rrmdir($board['uri'] . '/'); + } else { + $query = prepare('UPDATE ``boards`` SET `title` = :title, `subtitle` = :subtitle WHERE `uri` = :uri'); + $query->bindValue(':uri', $board['uri']); + $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( + 'board' => $board, + 'token' => make_secure_link_token('edit/' . $board['uri']) + )); + } } 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) { - $o = 0; - $ord = ordutf8($char, $o); - if ($ord > 0x0080) - $bytes += 5; // @01ff - else - $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'))); + 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) { + $o = 0; + $ord = ordutf8($char, $o); + if ($ord > 0x0080) + $bytes += 5; // @01ff + else + $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, - 'token' => make_secure_link_token('noticeboard') - )); + 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, + 'token' => make_secure_link_token('noticeboard') + )); } 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']); + 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'))); + 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']); + 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)); + 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)); + 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 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']); - } - } - - $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)); + 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']); + } + } + + $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']; - require_once("templates/themes/$type/theme.php"); - global $mod; - - $overboard = new $type(); - $overboard->settings = array(); - $overboard->settings['uri'] = $boardName; - $overboard->settings['title'] = $config['overboards'][$boardName]['title']; - $overboard->settings['subtitle'] = $config['overboards'][$boardName]['subtitle']; - $overboard->settings['thread_limit'] = $config['overboards'][$boardName]['thread_limit']; - if (array_key_exists('exclude',$config['overboards'][$boardName])) { - $overboard->settings['exclude'] = $config['overboards'][$boardName]['exclude']; - } - if (array_key_exists('include',$config['overboards'][$boardName])) { - $overboard->settings['include'] = $config['overboards'][$boardName]['include']; - } - $overboard->settings['boards'] = listBoards(); - echo $overboard->build($mod); - return; - } - elseif (in_array($boardName,array_keys($config['boards_alias']))){ - $boardName = $config['boards_alias'][$boardName]; - openBoard($boardName); - } - else { - 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); + global $config, $mod; + + if (!openBoard($boardName)){ + if (in_array($boardName,array_keys($config['overboards']))){ + $type = $config['overboards'][$boardName]['type']; + require_once("templates/themes/$type/theme.php"); + global $mod; + + $overboard = new $type(); + $overboard->settings = array(); + $overboard->settings['uri'] = $boardName; + $overboard->settings['title'] = $config['overboards'][$boardName]['title']; + $overboard->settings['subtitle'] = $config['overboards'][$boardName]['subtitle']; + $overboard->settings['thread_limit'] = $config['overboards'][$boardName]['thread_limit']; + if (array_key_exists('exclude',$config['overboards'][$boardName])) { + $overboard->settings['exclude'] = $config['overboards'][$boardName]['exclude']; + } + if (array_key_exists('include',$config['overboards'][$boardName])) { + $overboard->settings['include'] = $config['overboards'][$boardName]['include']; + } + $overboard->settings['boards'] = listBoards(); + echo $overboard->build($mod); + return; + } + elseif (in_array($boardName,array_keys($config['boards_alias']))){ + $boardName = $config['boards_alias'][$boardName]; + openBoard($boardName); + } + else { + 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; + 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; + 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']); + 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)'); - $query->bindValue(':ip', $ip); - $query->bindValue(':mod', $mod['id']); - $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']); - if (!hasPermission($config['mod']['show_ip'], $board['uri'])) - continue; - $query = prepare(sprintf('SELECT * FROM ``posts_%s`` WHERE `ip` = :ip ORDER BY `sticky` DESC, `id` DESC LIMIT :limit', $board['uri'])); - $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 . '%'); - $query->execute() or error(db_error($query)); - $args['logs'] = $query->fetchAll(PDO::FETCH_ASSOC); - } 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']); + 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)'); + $query->bindValue(':ip', $ip); + $query->bindValue(':mod', $mod['id']); + $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']); + if (!hasPermission($config['mod']['show_ip'], $board['uri'])) + continue; + $query = prepare(sprintf('SELECT * FROM ``posts_%s`` WHERE `ip` = :ip ORDER BY `sticky` DESC, `id` DESC LIMIT :limit', $board['uri'])); + $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 . '%'); + $query->execute() or error(db_error($query)); + $args['logs'] = $query->fetchAll(PDO::FETCH_ASSOC); + } 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'])) - header('Location: ' . $_POST['redirect'], true, $config['redirect_http']); - else - header('Location: ?/', true, $config['redirect_http']); + 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'])) + header('Location: ' . $_POST['redirect'], true, $config['redirect_http']); + else + header('Location: ?/', true, $config['redirect_http']); } 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 - header('Location: ?/', true, $config['redirect_http']); + 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 + header('Location: ?/', true, $config['redirect_http']); } 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)) - $unban[] = $match[1]; - } - 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); - } + 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)) + $unban[] = $match[1]; + } + 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); + } rebuildThemes('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']), - 'token' => make_secure_link_token('bans'), - 'token_json' => make_secure_link_token('bans.json') - )); + header('Location: ?/bans', true, $config['redirect_http']); + return; + } + + mod_page(_('Ban list'), 'mod/ban_list.html', array( + 'mod' => $mod, + 'boards' => json_encode($mod['boards']), + 'token' => make_secure_link_token('bans'), + 'token_json' => make_secure_link_token('bans.json') + )); } function mod_bans_json() { @@ -998,1097 +998,1097 @@ function mod_bans_json() { if (!hasPermission($config['mod']['ban'])) error($config['error']['noaccess']); - // Compress the json for faster loads - if (substr_count($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip')) ob_start("ob_gzhandler"); + // Compress the json for faster loads + if (substr_count($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip')) ob_start("ob_gzhandler"); - Bans::stream_json(false, false, !hasPermission($config['mod']['view_banstaff']), $mod['boards']); + Bans::stream_json(false, false, !hasPermission($config['mod']['view_banstaff']), $mod['boards']); } 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); - query("DELETE FROM ``ban_appeals`` WHERE `id` = " . $ban['id']) or error(db_error()); - } else { - 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` - WHERE `denied` != 1 ORDER BY `time`") or error(db_error()); - $ban_appeals = $query->fetchAll(PDO::FETCH_ASSOC); - foreach ($ban_appeals as &$ban) { - 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` = " . - (int)$ban['post']['id'], $board['uri'])); - if ($_post = $query->fetch(PDO::FETCH_ASSOC)) { - $_post['files'] = $_post['files'] ? json_decode($_post['files']) : array(); - $ban['post'] = array_merge($ban['post'], $_post); - } else { - $ban['post']['files'] = array(array()); - $ban['post']['files'][0]['file'] = 'deleted'; - $ban['post']['files'][0]['thumb'] = false; - $ban['post']['num_files'] = 1; - } - } else { - $ban['post']['files'] = array(array()); - $ban['post']['files'][0]['file'] = 'deleted'; - $ban['post']['files'][0]['thumb'] = false; - $ban['post']['num_files'] = 1; - } - - if ($ban['post']['thread']) { - $ban['post'] = new Post($ban['post']); - } else { - $ban['post'] = new Thread($ban['post'], null, false, false); - } - } - } - - mod_page(_('Ban appeals'), 'mod/ban_appeals.html', array( - 'ban_appeals' => $ban_appeals, - 'token' => make_secure_link_token('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); + query("DELETE FROM ``ban_appeals`` WHERE `id` = " . $ban['id']) or error(db_error()); + } else { + 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` + WHERE `denied` != 1 ORDER BY `time`") or error(db_error()); + $ban_appeals = $query->fetchAll(PDO::FETCH_ASSOC); + foreach ($ban_appeals as &$ban) { + 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` = " . + (int)$ban['post']['id'], $board['uri'])); + if ($_post = $query->fetch(PDO::FETCH_ASSOC)) { + $_post['files'] = $_post['files'] ? json_decode($_post['files']) : array(); + $ban['post'] = array_merge($ban['post'], $_post); + } else { + $ban['post']['files'] = array(array()); + $ban['post']['files'][0]['file'] = 'deleted'; + $ban['post']['files'][0]['thumb'] = false; + $ban['post']['num_files'] = 1; + } + } else { + $ban['post']['files'] = array(array()); + $ban['post']['files'][0]['file'] = 'deleted'; + $ban['post']['files'][0]['thumb'] = false; + $ban['post']['num_files'] = 1; + } + + if ($ban['post']['thread']) { + $ban['post'] = new Post($ban['post']); + } else { + $ban['post'] = new Thread($ban['post'], null, false, false); + } + } + } + + mod_page(_('Ban appeals'), 'mod/ban_appeals.html', array( + 'ban_appeals' => $ban_appeals, + 'token' => make_secure_link_token('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); - $query->execute() or error(db_error($query)); - if ($query->rowCount()) { - modLog(($unlock ? 'Unlocked' : 'Locked') . " thread #{$post}"); - buildThread($post); - buildIndex(); - // 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 - event('lock', $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); + $query->execute() or error(db_error($query)); + if ($query->rowCount()) { + modLog(($unlock ? 'Unlocked' : 'Locked') . " thread #{$post}"); + buildThread($post); + buildIndex(); + // 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 + event('lock', $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); - $query->execute() or error(db_error($query)); - if ($query->rowCount()) { - modLog(($unsticky ? 'Unstickied' : 'Stickied') . " thread #{$post}"); - buildThread($post); - buildIndex(); - // trigger themes - rebuildThemes('sticky', $board); - } - - header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']); + 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); + $query->execute() or error(db_error($query)); + if ($query->rowCount()) { + modLog(($unsticky ? 'Unstickied' : 'Stickied') . " thread #{$post}"); + buildThread($post); + buildIndex(); + // 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); - $query->execute() or error(db_error($query)); - if ($query->rowCount()) { - modLog(($uncycle ? 'Made not cyclical' : 'Made cyclical') . " thread #{$post}"); - buildThread($post); - buildIndex(); - } - - header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']); + 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); + $query->execute() or error(db_error($query)); + if ($query->rowCount()) { + modLog(($uncycle ? 'Made not cyclical' : 'Made cyclical') . " thread #{$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); - $query->execute() or error(db_error($query)); - if ($query->rowCount()) { - modLog(($unbumplock ? 'Unbumplocked' : 'Bumplocked') . " thread #{$post}"); - buildThread($post); - buildIndex(); - } - - header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']); + 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); + $query->execute() or error(db_error($query)); + if ($query->rowCount()) { + modLog(($unbumplock ? 'Unbumplocked' : 'Bumplocked') . " thread #{$post}"); + buildThread($post); + buildIndex(); + } + + header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']); } 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']); - - $query = prepare(sprintf('SELECT * FROM ``posts_%s`` WHERE `id` = :id', $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']; - - if ($_POST['target_thread']) { - $query = prepare(sprintf('SELECT * FROM ``posts_%s`` WHERE `id` = :id', $targetBoard)); - $query->bindValue(':id', $_POST['target_thread']); - $query->execute() or error(db_error($query)); // If it fails, thread probably does not exist - $post['op'] = false; - $post['thread'] = $_POST['target_thread']; - } - else { - $post['op'] = true; - } - - if ($post['files']) { - $post['files'] = json_decode($post['files'], TRUE); - $post['has_file'] = true; - foreach ($post['files'] as $i => &$file) { - $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']; - } - } 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 - $newID = post($post); - - if ($post['has_file']) { - foreach ($post['files'] as $i => &$file) { - // move the image - rename($file['file_path'], sprintf($config['board_path'], $board['uri']) . $config['dir']['img'] . $file['file']); - if ($file['thumb'] != 'spoiler') { //trying to move/copy the spoiler thumb raises an error - rename($file['thumb_path'], sprintf($config['board_path'], $board['uri']) . $config['dir']['thumb'] . $file['thumb']); - } - } - } - - // build index - buildIndex(); - - // 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); - - // delete original post - deletePost($postID); - buildIndex(); - - // open target board for redirect - openBoard($targetBoard); - - // Find new thread on our target board - $query = prepare(sprintf('SELECT thread, id FROM ``posts_%s`` WHERE `id` = :id', $targetBoard)); - $query->bindValue(':id', $newID); - $query->execute() or error(db_error($query)); - $post = $query->fetch(PDO::FETCH_ASSOC); - - // redirect - header('Location: ?/' . sprintf($config['board_path'], $board['uri']) . $config['dir']['res'] . link_for($post) . '#' . $newID, true, $config['redirect_http']); - } - - 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)); - - } + global $board, $config, $mod; + + 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', $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']; + + if ($_POST['target_thread']) { + $query = prepare(sprintf('SELECT * FROM ``posts_%s`` WHERE `id` = :id', $targetBoard)); + $query->bindValue(':id', $_POST['target_thread']); + $query->execute() or error(db_error($query)); // If it fails, thread probably does not exist + $post['op'] = false; + $post['thread'] = $_POST['target_thread']; + } + else { + $post['op'] = true; + } + + if ($post['files']) { + $post['files'] = json_decode($post['files'], TRUE); + $post['has_file'] = true; + foreach ($post['files'] as $i => &$file) { + $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']; + } + } 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 + $newID = post($post); + + if ($post['has_file']) { + foreach ($post['files'] as $i => &$file) { + // move the image + rename($file['file_path'], sprintf($config['board_path'], $board['uri']) . $config['dir']['img'] . $file['file']); + if ($file['thumb'] != 'spoiler') { //trying to move/copy the spoiler thumb raises an error + rename($file['thumb_path'], sprintf($config['board_path'], $board['uri']) . $config['dir']['thumb'] . $file['thumb']); + } + } + } + + // build index + buildIndex(); + + // 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); + + // delete original post + deletePost($postID); + buildIndex(); + + // open target board for redirect + openBoard($targetBoard); + + // Find new thread on our target board + $query = prepare(sprintf('SELECT thread, id FROM ``posts_%s`` WHERE `id` = :id', $targetBoard)); + $query->bindValue(':id', $newID); + $query->execute() or error(db_error($query)); + $post = $query->fetch(PDO::FETCH_ASSOC); + + // redirect + header('Location: ?/' . sprintf($config['board_path'], $board['uri']) . $config['dir']['res'] . link_for($post) . '#' . $newID, true, $config['redirect_http']); + } + + 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)); + + } } 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') - 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']; - } - } 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') - $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; - foreach ($post['files'] as $i => &$file) { - $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']; - } - } 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']])) { - $post['body_nomarkup'] = preg_replace( - '/(>>(>\/' . 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) { - $clone($file['file_path'], sprintf($config['board_path'], $board['uri']) . $config['dir']['img'] . $file['file']); - $clone($file['thumb_path'], sprintf($config['board_path'], $board['uri']) . $config['dir']['thumb'] . $file['thumb']); - } - } - // insert reply - $newIDs[$post['id']] = $newPostID = post($post); - - - if (!empty($post['tracked_cites'])) { - $insert_rows = array(); - foreach ($post['tracked_cites'] as $cite) { - $insert_rows[] = '(' . - $pdo->quote($board['uri']) . ', ' . $newPostID . ', ' . - $pdo->quote($cite[0]) . ', ' . (int)$cite[1] . ')'; - } - 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, - 'subject' => '', - 'email' => '', - 'name' => (!$config['mod']['shadow_name'] ? $config['anonymous'] : $config['mod']['shadow_name']), - 'capcode' => $config['mod']['shadow_capcode'], - 'trip' => '', - 'password' => '', - 'has_file' => false, - // attach to original thread - 'thread' => $postID, - 'op' => false - ); - - $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)); + 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') + 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']; + } + } 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') + $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; + foreach ($post['files'] as $i => &$file) { + $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']; + } + } 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']])) { + $post['body_nomarkup'] = preg_replace( + '/(>>(>\/' . 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) { + $clone($file['file_path'], sprintf($config['board_path'], $board['uri']) . $config['dir']['img'] . $file['file']); + $clone($file['thumb_path'], sprintf($config['board_path'], $board['uri']) . $config['dir']['thumb'] . $file['thumb']); + } + } + // insert reply + $newIDs[$post['id']] = $newPostID = post($post); + + + if (!empty($post['tracked_cites'])) { + $insert_rows = array(); + foreach ($post['tracked_cites'] as $cite) { + $insert_rows[] = '(' . + $pdo->quote($board['uri']) . ', ' . $newPostID . ', ' . + $pdo->quote($cite[0]) . ', ' . (int)$cite[1] . ')'; + } + 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, + 'subject' => '', + 'email' => '', + 'name' => (!$config['mod']['shadow_name'] ? $config['anonymous'] : $config['mod']['shadow_name']), + 'capcode' => $config['mod']['shadow_capcode'], + 'trip' => '', + 'password' => '', + 'has_file' => false, + // attach to original thread + 'thread' => $postID, + 'op' => false + ); + + $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 = ""; - if ($post['thread']){ - $sourceOp = $post['thread']; - } - else{ - $sourceOp = $post['id']; - } - $newpost = ""; - $boards = listBoards(); - - if (isset($_POST['board'])) { - $targetBoard = $_POST['board']; - $shadow = isset($_POST['shadow']); - $targetOp = ""; - if ($_POST['target_thread']) { - $query = prepare(sprintf('SELECT * FROM ``posts_%s`` WHERE `id` = :id', $targetBoard)); - $query->bindValue(':id', $_POST['target_thread']); - $query->execute() or error(db_error($query)); // If it fails, thread probably does not exist - if (!$newpost = $query->fetch(PDO::FETCH_ASSOC)){ - error($config['error']['404']); - } - else - { - if ($newpost['thread']){ - $targetOp = $newpost['thread']; - } - else{ - $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)); - $query->bindValue(':newthread', $targetOp, PDO::PARAM_INT); - $query->bindValue(':oldthread', $sourceOp, PDO::PARAM_INT); - $query->execute() or error(db_error($query)); - // build index - // Delete thread HTML page - file_unlink($board['dir'] . $config['dir']['res'] . link_for($post) ); - file_unlink($board['dir'] . $config['dir']['res'] . link_for($post, true) ); // noko50 - file_unlink($board['dir'] . $config['dir']['res'] . sprintf('%d.json', $post['id'])); - //deletePost($postID); - //modLog("Deleted post #{$postID}"); - buildIndex(); - - // build new thread - buildThread($targetOp); - - // trigger themes - rebuildThemes('post', $targetBoard); - modLog("Merged thread with #${sourceOp} to " . sprintf($config['board_abbreviation'], $targetBoard) . " (#${targetOp})", $originBoard); - - // redirect - 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 - // 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') - 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']; - } - } 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') - $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; - foreach ($post['files'] as $i => &$file) { - $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']; - } - } 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']])) { - $post['body_nomarkup'] = preg_replace( - '/(>>(>\/' . 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) { - $clone($file['file_path'], sprintf($config['board_path'], $board['uri']) . $config['dir']['img'] . $file['file']); - $clone($file['thumb_path'], sprintf($config['board_path'], $board['uri']) . $config['dir']['thumb'] . $file['thumb']); - } - } - // insert reply - $newIDs[$post['id']] = $newPostID = post($post); - - - if (!empty($post['tracked_cites'])) { - $insert_rows = array(); - foreach ($post['tracked_cites'] as $cite) { - $insert_rows[] = '(' . - $pdo->quote($board['uri']) . ', ' . $newPostID . ', ' . - $pdo->quote($cite[0]) . ', ' . (int)$cite[1] . ')'; - } - 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)); - $query->bindValue(':newthread', $targetOp, PDO::PARAM_INT); - $query->bindValue(':oldthread', $newID, PDO::PARAM_INT); - $query->execute() or error(db_error($query)); - // build index - buildIndex(); - - // 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)); + 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 = ""; + if ($post['thread']){ + $sourceOp = $post['thread']; + } + else{ + $sourceOp = $post['id']; + } + $newpost = ""; + $boards = listBoards(); + + if (isset($_POST['board'])) { + $targetBoard = $_POST['board']; + $shadow = isset($_POST['shadow']); + $targetOp = ""; + if ($_POST['target_thread']) { + $query = prepare(sprintf('SELECT * FROM ``posts_%s`` WHERE `id` = :id', $targetBoard)); + $query->bindValue(':id', $_POST['target_thread']); + $query->execute() or error(db_error($query)); // If it fails, thread probably does not exist + if (!$newpost = $query->fetch(PDO::FETCH_ASSOC)){ + error($config['error']['404']); + } + else + { + if ($newpost['thread']){ + $targetOp = $newpost['thread']; + } + else{ + $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)); + $query->bindValue(':newthread', $targetOp, PDO::PARAM_INT); + $query->bindValue(':oldthread', $sourceOp, PDO::PARAM_INT); + $query->execute() or error(db_error($query)); + // build index + // Delete thread HTML page + file_unlink($board['dir'] . $config['dir']['res'] . link_for($post) ); + file_unlink($board['dir'] . $config['dir']['res'] . link_for($post, true) ); // noko50 + file_unlink($board['dir'] . $config['dir']['res'] . sprintf('%d.json', $post['id'])); + //deletePost($postID); + //modLog("Deleted post #{$postID}"); + buildIndex(); + + // build new thread + buildThread($targetOp); + + // trigger themes + rebuildThemes('post', $targetBoard); + modLog("Merged thread with #${sourceOp} to " . sprintf($config['board_abbreviation'], $targetBoard) . " (#${targetOp})", $originBoard); + + // redirect + 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 + // 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') + 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']; + } + } 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') + $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; + foreach ($post['files'] as $i => &$file) { + $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']; + } + } 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']])) { + $post['body_nomarkup'] = preg_replace( + '/(>>(>\/' . 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) { + $clone($file['file_path'], sprintf($config['board_path'], $board['uri']) . $config['dir']['img'] . $file['file']); + $clone($file['thumb_path'], sprintf($config['board_path'], $board['uri']) . $config['dir']['thumb'] . $file['thumb']); + } + } + // insert reply + $newIDs[$post['id']] = $newPostID = post($post); + + + if (!empty($post['tracked_cites'])) { + $insert_rows = array(); + foreach ($post['tracked_cites'] as $cite) { + $insert_rows[] = '(' . + $pdo->quote($board['uri']) . ', ' . $newPostID . ', ' . + $pdo->quote($cite[0]) . ', ' . (int)$cite[1] . ')'; + } + 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)); + $query->bindValue(':newthread', $targetOp, PDO::PARAM_INT); + $query->bindValue(':oldthread', $newID, PDO::PARAM_INT); + $query->execute() or error(db_error($query)); + // build index + buildIndex(); + + // 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'; - $_POST['message'] = preg_replace('/[\r\n]/', '', $_POST['message']); - $_POST['message'] = str_replace('%length%', $length_english, $_POST['message']); - $_POST['message'] = str_replace('%LENGTH%', strtoupper($length_english), $_POST['message']); - $query = prepare(sprintf('UPDATE ``posts_%s`` SET `body_nomarkup` = CONCAT(`body_nomarkup`, :body_nomarkup) WHERE `id` = :id', $board)); - $query->bindValue(':id', $post); - $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(); - } elseif (isset($_POST['delete']) && (int) $_POST['delete']) { - // Delete post - if ($config['autotagging']){ - $query = prepare(sprintf("SELECT * FROM ``posts_%s`` WHERE id = :id", $board)); - $query->bindValue(':id', $post ); - $query->execute() or error(db_error($query)); - $ip = ""; - $time = ""; - $filename = ""; - $filehash = ""; - $subject = ""; - $name = ""; - $body = ""; - while ($mypost = $query->fetch(PDO::FETCH_ASSOC)) { - $time = $mypost["time"]; - $ip = $mypost["ip"]; - $body = $mypost["body_nomarkup"]; - $name = $mypost["name"]; - $subject = $mypost["subject"]; - $filehash = $mypost["filehash"]; - $mypost['files'] = $mypost['files'] ? json_decode($mypost['files']) : array(); - // For each file append file name - 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"); - $autotag = ""; - $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); - markup($autotag); - $query = prepare('INSERT INTO ``ip_notes`` VALUES (NULL, :ip, :mod, :time, :body)'); - $query->bindValue(':ip', $ip); - $query->bindValue(':mod', $mod['id']); - $query->bindValue(':time', time()); - $query->bindValue(':body', $autotag); - $query->execute() or error(db_error($query)); - modLog("Added a note for {$ip}"); - } - } - deletePost($post); - modLog("Deleted post #{$post}"); - // Rebuild board - buildIndex(); - // Rebuild themes - rebuildThemes('post-delete', $board); - } + 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'; + $_POST['message'] = preg_replace('/[\r\n]/', '', $_POST['message']); + $_POST['message'] = str_replace('%length%', $length_english, $_POST['message']); + $_POST['message'] = str_replace('%LENGTH%', strtoupper($length_english), $_POST['message']); + $query = prepare(sprintf('UPDATE ``posts_%s`` SET `body_nomarkup` = CONCAT(`body_nomarkup`, :body_nomarkup) WHERE `id` = :id', $board)); + $query->bindValue(':id', $post); + $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(); + } elseif (isset($_POST['delete']) && (int) $_POST['delete']) { + // Delete post + if ($config['autotagging']){ + $query = prepare(sprintf("SELECT * FROM ``posts_%s`` WHERE id = :id", $board)); + $query->bindValue(':id', $post ); + $query->execute() or error(db_error($query)); + $ip = ""; + $time = ""; + $filename = ""; + $filehash = ""; + $subject = ""; + $name = ""; + $body = ""; + while ($mypost = $query->fetch(PDO::FETCH_ASSOC)) { + $time = $mypost["time"]; + $ip = $mypost["ip"]; + $body = $mypost["body_nomarkup"]; + $name = $mypost["name"]; + $subject = $mypost["subject"]; + $filehash = $mypost["filehash"]; + $mypost['files'] = $mypost['files'] ? json_decode($mypost['files']) : array(); + // For each file append file name + 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"); + $autotag = ""; + $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); + markup($autotag); + $query = prepare('INSERT INTO ``ip_notes`` VALUES (NULL, :ip, :mod, :time, :body)'); + $query->bindValue(':ip', $ip); + $query->bindValue(':mod', $mod['id']); + $query->bindValue(':time', time()); + $query->bindValue(':body', $autotag); + $query->execute() or error(db_error($query)); + modLog("Added a note for {$ip}"); + } + } + deletePost($post); + modLog("Deleted post #{$post}"); + // Rebuild board + buildIndex(); + // Rebuild themes + rebuildThemes('post-delete', $board); + } if(isset($_POST['thread'])) { // Redirect to thread header('Location: ?/' . sprintf($config['board_path'], $board) . $config['dir']['res'] . str_replace('%d', $_POST['thread'], $config['file_page']), true, $config['redirect_http']); } else { // 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), - 'post' => $post, - 'board' => $board, - 'delete' => (bool)$delete, - 'boards' => listBoards(), - 'token' => $security_token - ); - - if($_GET['thread']) { + 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), + 'post' => $post, + 'board' => $board, + 'delete' => (bool)$delete, + 'boards' => listBoards(), + 'token' => $security_token + ); + + if(isset($_GET['thread']) && $_GET['thread']) { $args['thread'] = $_GET['thread']; } - - mod_page(_('New ban'), 'mod/ban_form.html', $args); + + 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']); - $query = prepare(sprintf('UPDATE ``posts_%s`` SET `body_nomarkup` = CONCAT(`body_nomarkup`, :body_nomarkup) WHERE `id` = :id', $board)); - $query->bindValue(':id', $post); - $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(); - - if ($config['autotagging']){ - $query = prepare(sprintf("SELECT * FROM ``posts_%s`` WHERE id = :id", $board)); - $query->bindValue(':id', $post ); - $query->execute() or error(db_error($query)); - $ip = ""; - $time = ""; - $filename = ""; - $filehash = ""; - $subject = ""; - $name = ""; - $body = ""; - while ($mypost = $query->fetch(PDO::FETCH_ASSOC)) { - $time = $mypost["time"]; - $ip = $mypost["ip"]; - $body = $mypost["body_nomarkup"]; - $name = $mypost["name"]; - $subject = $mypost["subject"]; - $filehash = $mypost["filehash"]; - $mypost['files'] = $mypost['files'] ? json_decode($mypost['files']) : array(); - // For each file append file name - 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"); - $autotag = "Post warned\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); - markup($autotag); - $query = prepare('INSERT INTO ``ip_notes`` VALUES (NULL, :ip, :mod, :time, :body)'); - $query->bindValue(':ip', $ip); - $query->bindValue(':mod', $mod['id']); - $query->bindValue(':time', time()); - $query->bindValue(':body', $autotag); - $query->execute() or error(db_error($query)); - modLog("Added a note for {$ip}"); - } - } - } + 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']); + $query = prepare(sprintf('UPDATE ``posts_%s`` SET `body_nomarkup` = CONCAT(`body_nomarkup`, :body_nomarkup) WHERE `id` = :id', $board)); + $query->bindValue(':id', $post); + $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(); + + if ($config['autotagging']){ + $query = prepare(sprintf("SELECT * FROM ``posts_%s`` WHERE id = :id", $board)); + $query->bindValue(':id', $post ); + $query->execute() or error(db_error($query)); + $ip = ""; + $time = ""; + $filename = ""; + $filehash = ""; + $subject = ""; + $name = ""; + $body = ""; + while ($mypost = $query->fetch(PDO::FETCH_ASSOC)) { + $time = $mypost["time"]; + $ip = $mypost["ip"]; + $body = $mypost["body_nomarkup"]; + $name = $mypost["name"]; + $subject = $mypost["subject"]; + $filehash = $mypost["filehash"]; + $mypost['files'] = $mypost['files'] ? json_decode($mypost['files']) : array(); + // For each file append file name + 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"); + $autotag = "Post warned\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); + markup($autotag); + $query = prepare('INSERT INTO ``ip_notes`` VALUES (NULL, :ip, :mod, :time, :body)'); + $query->bindValue(':ip', $ip); + $query->bindValue(':mod', $mod['id']); + $query->bindValue(':time', time()); + $query->bindValue(':body', $autotag); + $query->execute() or error(db_error($query)); + modLog("Added a note for {$ip}"); + } + } + } if(isset($_POST['thread'])) { // Redirect to thread header('Location: ?/' . sprintf($config['board_path'], $board) . $config['dir']['res'] . str_replace('%d', $_POST['thread'], $config['file_page']), true, $config['redirect_http']); } else { // Redirect to board index. - header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']); + 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), - 'post' => $post, - 'board' => $board, - 'token' => $security_token - ); + } + $args = array( + 'ip' => $ip, + 'hide_ip' => !hasPermission($config['mod']['show_ip'], $board), + 'post' => $post, + 'board' => $board, + 'token' => $security_token + ); if(isset($_GET['thread'])) { $args['thread'] = $_GET['thread']; } - - mod_page(_('New warning'), 'mod/warning_form.html', $args); + + mod_page(_('New warning'), 'mod/warning_form.html', $args); } function mod_edit_post($board, $edit_raw_html, $postID) { - global $config, $mod; - - if (!openBoard($board)) - error($config['error']['noboard']); - - 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']); - - // Add back modifiers in the original post - $modifiers = extract_modifiers($post['body_nomarkup']); - foreach ($modifiers as $key => $value) { - $_POST['body'] .= "$value"; - } - - if ($edit_raw_html) - $query = prepare(sprintf('UPDATE ``posts_%s`` SET `name` = :name, `email` = :email, `subject` = :subject, `body` = :body, `body_nomarkup` = :body_nomarkup WHERE `id` = :id', $board)); - else - $query = prepare(sprintf('UPDATE ``posts_%s`` SET `name` = :name, `email` = :email, `subject` = :subject, `body_nomarkup` = :body WHERE `id` = :id', $board)); - $query->bindValue(':id', $postID); - $query->bindValue('name', $_POST['name']); - $query->bindValue(':email', $_POST['email']); - $query->bindValue(':subject', $_POST['subject']); - $query->bindValue(':body', $_POST['body']); - if ($edit_raw_html) { - $body_nomarkup = $_POST['body'] . "\n1"; - $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'] = 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)); - } + global $config, $mod; + + if (!openBoard($board)) + error($config['error']['noboard']); + + 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']); + + // Add back modifiers in the original post + $modifiers = extract_modifiers($post['body_nomarkup']); + foreach ($modifiers as $key => $value) { + $_POST['body'] .= "$value"; + } + + if ($edit_raw_html) + $query = prepare(sprintf('UPDATE ``posts_%s`` SET `name` = :name, `email` = :email, `subject` = :subject, `body` = :body, `body_nomarkup` = :body_nomarkup WHERE `id` = :id', $board)); + else + $query = prepare(sprintf('UPDATE ``posts_%s`` SET `name` = :name, `email` = :email, `subject` = :subject, `body_nomarkup` = :body WHERE `id` = :id', $board)); + $query->bindValue(':id', $postID); + $query->bindValue('name', $_POST['name']); + $query->bindValue(':email', $_POST['email']); + $query->bindValue(':subject', $_POST['subject']); + $query->bindValue(':body', $_POST['body']); + if ($edit_raw_html) { + $body_nomarkup = $_POST['body'] . "\n1"; + $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'] = 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)); + } } 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)); - $query->bindValue(':id', $post ); - $query->execute() or error(db_error($query)); - $ip = ""; - $time = ""; - $filename = ""; - $filehash = ""; - $subject = ""; - $name = ""; - $body = ""; - while ($mypost = $query->fetch(PDO::FETCH_ASSOC)) { - $time = $mypost["time"]; - $ip = $mypost["ip"]; - $body = $mypost["body_nomarkup"]; - $name = $mypost["name"]; - $subject = $mypost["subject"]; - $filehash = $mypost["filehash"]; - $mypost['files'] = $mypost['files'] ? json_decode($mypost['files']) : array(); - // For each file append file name - 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"); - $autotag = ""; - $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); - markup($autotag); - $query = prepare('INSERT INTO ``ip_notes`` VALUES (NULL, :ip, :mod, :time, :body)'); - $query->bindValue(':ip', $ip); - $query->bindValue(':mod', $mod['id']); - $query->bindValue(':time', time()); - $query->bindValue(':body', $autotag); - $query->execute() or error(db_error($query)); - modLog("Added a note for {$ip}"); - } - } - deletePost($post); - // Record the action - modLog("Deleted post #{$post}"); - // Rebuild board - buildIndex(); - // Rebuild themes - rebuildThemes('post-delete', $board); - // Redirect + 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)); + $query->bindValue(':id', $post ); + $query->execute() or error(db_error($query)); + $ip = ""; + $time = ""; + $filename = ""; + $filehash = ""; + $subject = ""; + $name = ""; + $body = ""; + while ($mypost = $query->fetch(PDO::FETCH_ASSOC)) { + $time = $mypost["time"]; + $ip = $mypost["ip"]; + $body = $mypost["body_nomarkup"]; + $name = $mypost["name"]; + $subject = $mypost["subject"]; + $filehash = $mypost["filehash"]; + $mypost['files'] = $mypost['files'] ? json_decode($mypost['files']) : array(); + // For each file append file name + 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"); + $autotag = ""; + $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); + markup($autotag); + $query = prepare('INSERT INTO ``ip_notes`` VALUES (NULL, :ip, :mod, :time, :body)'); + $query->bindValue(':ip', $ip); + $query->bindValue(':mod', $mod['id']); + $query->bindValue(':time', time()); + $query->bindValue(':body', $autotag); + $query->execute() or error(db_error($query)); + modLog("Added a note for {$ip}"); + } + } + deletePost($post); + // Record the action + modLog("Deleted post #{$post}"); + // Rebuild board + buildIndex(); + // Rebuild themes + rebuildThemes('post-delete', $board); + // Redirect if(isset($_GET['thread'])) { header('Location: ?/' . sprintf($config['board_path'], $board) . $config['dir']['res'] . str_replace('%d', $_GET['thread'], $config['file_page']), true, $config['redirect_http']); } else { @@ -2097,1411 +2097,1411 @@ 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']); + 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']); - - // Delete file thumbnail - $query = prepare(sprintf("SELECT `files`, `thread` FROM ``posts_%s`` WHERE id = :id", $board)); - $query->bindValue(':id', $post, PDO::PARAM_INT); - $query->execute() or error(db_error($query)); - $result = $query->fetch(PDO::FETCH_ASSOC); - $files = json_decode($result['files']); - - - $size_spoiler_image = @getimagesize($config['spoiler_image']); - file_unlink($board . '/' . $config['dir']['thumb'] . $files[$file]->thumb); - $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)); - $query->bindValue(':id', $post, PDO::PARAM_INT); - $query->execute() or error(db_error($query)); - - // Record the action - modLog("Spoilered file from post #{$post}"); - - // Rebuild thread - buildThread($result['thread'] ? $result['thread'] : $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']); + global $config, $mod; + + if (!openBoard($board)) + error($config['error']['noboard']); + + if (!hasPermission($config['mod']['spoilerimage'], $board)) + error($config['error']['noaccess']); + + // Delete file thumbnail + $query = prepare(sprintf("SELECT `files`, `thread` FROM ``posts_%s`` WHERE id = :id", $board)); + $query->bindValue(':id', $post, PDO::PARAM_INT); + $query->execute() or error(db_error($query)); + $result = $query->fetch(PDO::FETCH_ASSOC); + $files = json_decode($result['files']); + + + $size_spoiler_image = @getimagesize($config['spoiler_image']); + file_unlink($board . '/' . $config['dir']['thumb'] . $files[$file]->thumb); + $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)); + $query->bindValue(':id', $post, PDO::PARAM_INT); + $query->execute() or error(db_error($query)); + + // Record the action + modLog("Spoilered file from post #{$post}"); + + // Rebuild thread + buildThread($result['thread'] ? $result['thread'] : $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_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)) { - openBoard($post['board']); - if ($config['autotagging']){ - $query2 = prepare(sprintf("SELECT * FROM ``posts_%s`` WHERE id = :id", $post['board'])); - $query2->bindValue(':id', $post['id'] ); - $query2->execute() or error(db_error($query2)); - $ip = ""; - $time = ""; - $filename = ""; - $filehash = ""; - $subject = ""; - $name = ""; - $body = ""; - while ($mypost = $query2->fetch(PDO::FETCH_ASSOC)) { - $time = $mypost["time"]; - $ip = $mypost["ip"]; - $body = $mypost["body_nomarkup"]; - $name = $mypost["name"]; - $subject = $mypost["subject"]; - $filehash = $mypost["filehash"]; - $mypost['files'] = $mypost['files'] ? json_decode($mypost['files']) : array(); - // For each file append file name - 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"); - $autotag = ""; - $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); - markup($autotag); - $query2 = prepare('INSERT INTO ``ip_notes`` VALUES (NULL, :ip, :mod, :time, :body)'); - $query2->bindValue(':ip', $ip); - $query2->bindValue(':mod', $mod['id']); - $query2->bindValue(':time', time()); - $query2->bindValue(':body', $autotag); - $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']) - $threads_to_rebuild[$post['board']][$post['thread']] = true; - else - $threads_deleted[$post['board']][$post['id']] = true; - } - - foreach ($threads_to_rebuild as $_board => $_threads) { - openBoard($_board); - foreach ($_threads as $_thread => $_dummy) { - if ($_dummy && !isset($threads_deleted[$_board][$_thread])) - buildThread($_thread); - } - 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']); + 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)) { + openBoard($post['board']); + if ($config['autotagging']){ + $query2 = prepare(sprintf("SELECT * FROM ``posts_%s`` WHERE id = :id", $post['board'])); + $query2->bindValue(':id', $post['id'] ); + $query2->execute() or error(db_error($query2)); + $ip = ""; + $time = ""; + $filename = ""; + $filehash = ""; + $subject = ""; + $name = ""; + $body = ""; + while ($mypost = $query2->fetch(PDO::FETCH_ASSOC)) { + $time = $mypost["time"]; + $ip = $mypost["ip"]; + $body = $mypost["body_nomarkup"]; + $name = $mypost["name"]; + $subject = $mypost["subject"]; + $filehash = $mypost["filehash"]; + $mypost['files'] = $mypost['files'] ? json_decode($mypost['files']) : array(); + // For each file append file name + 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"); + $autotag = ""; + $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); + markup($autotag); + $query2 = prepare('INSERT INTO ``ip_notes`` VALUES (NULL, :ip, :mod, :time, :body)'); + $query2->bindValue(':ip', $ip); + $query2->bindValue(':mod', $mod['id']); + $query2->bindValue(':time', time()); + $query2->bindValue(':body', $autotag); + $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']) + $threads_to_rebuild[$post['board']][$post['thread']] = true; + else + $threads_deleted[$post['board']][$post['id']] = true; + } + + foreach ($threads_to_rebuild as $_board => $_threads) { + openBoard($_board); + foreach ($_threads as $_thread => $_dummy) { + if ($_dummy && !isset($threads_deleted[$_board][$_thread])) + buildThread($_thread); + } + 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('*'); - } else { - $_boards = listBoards(); - 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']); - - $query = prepare('UPDATE ``mods`` SET `password` = :password, `version` = :version WHERE `id` = :id'); - $query->bindValue(':id', $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']); - - $query = prepare('UPDATE ``mods`` SET `password` = :password, `version` = :version WHERE `id` = :id'); - $query->bindValue(':id', $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); - $query->execute() or error(db_error($query)); - $log = $query->fetchAll(PDO::FETCH_ASSOC); - } else { - $log = array(); - } - - $user['boards'] = explode(',', $user['boards']); - - mod_page(_('Edit user'), 'mod/user.html', array( - 'user' => $user, - 'logs' => $log, - 'boards' => listBoards(), - 'token' => make_secure_link_token('users/' . $user['id']) - )); + 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('*'); + } else { + $_boards = listBoards(); + 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']); + + $query = prepare('UPDATE ``mods`` SET `password` = :password, `version` = :version WHERE `id` = :id'); + $query->bindValue(':id', $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']); + + $query = prepare('UPDATE ``mods`` SET `password` = :password, `version` = :version WHERE `id` = :id'); + $query->bindValue(':id', $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); + $query->execute() or error(db_error($query)); + $log = $query->fetchAll(PDO::FETCH_ASSOC); + } else { + $log = array(); + } + + $user['boards'] = explode(',', $user['boards']); + + mod_page(_('Edit user'), 'mod/user.html', array( + 'user' => $user, + 'logs' => $log, + 'boards' => listBoards(), + 'token' => make_secure_link_token('users/' . $user['id']) + )); } 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 { - $_boards = listBoards(); - 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); - $query->bindValue(':version', $version); - $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'))); + 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 { + $_boards = listBoards(); + 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); + $query->bindValue(':version', $version); + $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)); + 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; - break; - } elseif ($action == 'demote' && $group_value < $mod['type']) { - $new_group = $group_value; - 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']); + 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; + break; + } elseif ($action == 'demote' && $group_value < $mod['type']) { + $new_group = $group_value; + 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'], - 'message' => quote($pm['message']), - 'token' => make_secure_link_token('new_PM/' . $pm['username']) - )); - } else { - mod_page(sprintf('%s – #%d', _('Private message'), $id), 'mod/pm.html', $pm); - } + 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'], + 'message' => quote($pm['message']), + 'token' => make_secure_link_token('new_PM/' . $pm['username']) + )); + } else { + mod_page(sprintf('%s – #%d', _('Private message'), $id), 'mod/pm.html', $pm); + } } 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 - )); + 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 + )); } 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)); - if (!$id = $query->fetchColumn()) { - // Old style ?/PM: by user ID - $query = prepare("SELECT `username` FROM ``mods`` WHERE `id` = :username"); - $query->bindValue(':username', $username); - $query->execute() or error(db_error($query)); - if ($username = $query->fetchColumn()) - header('Location: ?/new_PM/' . $username, true, $config['redirect_http']); - 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, - 'token' => make_secure_link_token('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)); + if (!$id = $query->fetchColumn()) { + // Old style ?/PM: by user ID + $query = prepare("SELECT `username` FROM ``mods`` WHERE `id` = :username"); + $query->bindValue(':username', $username); + $query->execute() or error(db_error($query)); + if ($username = $query->fetchColumn()) + header('Location: ?/new_PM/' . $username, true, $config['redirect_http']); + 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, + 'token' => make_secure_link_token('new_PM/' . $username) + )); } function mod_rebuild() { - global $config, $twig; + 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'; + + 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'); + 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)) { - $log[] = '' . sprintf($config['board_abbreviation'], $board['uri']) . ': Rebuilding thread #' . $post['id']; - buildThread($post['id']); - } - } - } - - 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') - )); + } + + 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)) { + $log[] = '' . sprintf($config['board_abbreviation'], $board['uri']) . ': Rebuilding thread #' . $post['id']; + buildThread($post['id']); + } + } + } + + 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') + )); } 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) { - if (!isset($report_posts[$report['board']][$report['post']])) { - // // Invalid report (post has since been deleted) - $query = prepare("DELETE FROM ``reports`` WHERE `post` = :id AND `board` = :board"); - $query->bindValue(':id', $report['post'], PDO::PARAM_INT); - $query->bindValue(':board', $report['board']); - $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, - 'config' => $config, - 'mod' => $mod, - '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)); + 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) { + if (!isset($report_posts[$report['board']][$report['post']])) { + // // Invalid report (post has since been deleted) + $query = prepare("DELETE FROM ``reports`` WHERE `post` = :id AND `board` = :board"); + $query->bindValue(':id', $report['post'], PDO::PARAM_INT); + $query->bindValue(':board', $report['board']); + $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, + 'config' => $config, + 'mod' => $mod, + '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)); - if ($report = $query->fetch(PDO::FETCH_ASSOC)) { - $ip = $report['ip']; - $board = $report['board']; - $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); - } else { - $query = prepare("DELETE FROM ``reports`` WHERE `id` = :id"); - $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']); + global $config; + + $query = prepare("SELECT `post`, `board`, `ip` FROM ``reports`` WHERE `id` = :id"); + $query->bindValue(':id', $id); + $query->execute() or error(db_error($query)); + if ($report = $query->fetch(PDO::FETCH_ASSOC)) { + $ip = $report['ip']; + $board = $report['board']; + $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); + } else { + $query = prepare("DELETE FROM ``reports`` WHERE `id` = :id"); + $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']); - - $limit = (is_numeric($lim))? $lim : 25; - $last_time = (isset($_GET['last']) && is_numeric($_GET['last'])) ? $_GET['last'] : 0; - - $mod_boards = array(); - $boards = listBoards(); - - //if not all boards - if ($mod['boards'][0]!='*') { - foreach ($boards as $board) { - if (in_array($board['uri'], $mod['boards'])) - $mod_boards[] = $board; - } - } else { - $mod_boards = $boards; - } - if ($board_list != false){ - $board_array = explode(",",$board_list); - $new_board_array = array(); - foreach ($board_array as $board) { - if (array_key_exists($board,$config['boards_alias'])){ - $newboard = $config['boards_alias'][$board]; - } - else{ - $newboard = $board; - } - $new_board_array[] = $newboard; - } - $mod_boards = array(); - foreach ($boards as $board) { - if (in_array($board['uri'], $new_board_array)){ - $mod_boards[] = $board; - } - } - } - - // Manually build an SQL query - $query = 'SELECT * FROM ('; - foreach ($mod_boards as $board) { - $query .= sprintf('SELECT *, %s AS `board` FROM ``posts_%s`` UNION ALL ', $pdo->quote($board['uri']), $board['uri']); - } - // Remove the last "UNION ALL" seperator and complete the query - $query = preg_replace('/UNION ALL $/', ') AS `all_posts` WHERE (`time` < :last_time OR NOT :last_time) ORDER BY `time` DESC LIMIT ' . $limit, $query); - $query = prepare($query); - $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(); - } - - foreach ($posts as &$post) { - openBoard($post['board']); - if (!$post['thread']) { - // Still need to fix this: - $po = new Thread($post, '?/', $mod, false); - $post['built'] = $po->build(true); - 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); - $apithreads[] = $pot; - } - } - $last_time = $post['time']; - } - if ($config['api']['enabled']) { - require_once __DIR__. '/../../inc/api.php'; - $api = new Api(); - $jsonFilename = 'mod/' . 'recent.json'; - $jsondata = json_encode($api->translatePage($apithreads)); - } - - if ($json){ - echo $jsondata; - } - else { - echo mod_page(_('Recent posts'), 'mod/recent_posts.html', array( - 'posts' => $posts, - 'limit' => $limit, - 'last_time' => $last_time - ) - ); - } + global $config, $mod, $pdo; + + if (!hasPermission($config['mod']['recent'])) + error($config['error']['noaccess']); + + $limit = (is_numeric($lim))? $lim : 25; + $last_time = (isset($_GET['last']) && is_numeric($_GET['last'])) ? $_GET['last'] : 0; + + $mod_boards = array(); + $boards = listBoards(); + + //if not all boards + if ($mod['boards'][0]!='*') { + foreach ($boards as $board) { + if (in_array($board['uri'], $mod['boards'])) + $mod_boards[] = $board; + } + } else { + $mod_boards = $boards; + } + if ($board_list != false){ + $board_array = explode(",",$board_list); + $new_board_array = array(); + foreach ($board_array as $board) { + if (array_key_exists($board,$config['boards_alias'])){ + $newboard = $config['boards_alias'][$board]; + } + else{ + $newboard = $board; + } + $new_board_array[] = $newboard; + } + $mod_boards = array(); + foreach ($boards as $board) { + if (in_array($board['uri'], $new_board_array)){ + $mod_boards[] = $board; + } + } + } + + // Manually build an SQL query + $query = 'SELECT * FROM ('; + foreach ($mod_boards as $board) { + $query .= sprintf('SELECT *, %s AS `board` FROM ``posts_%s`` UNION ALL ', $pdo->quote($board['uri']), $board['uri']); + } + // Remove the last "UNION ALL" seperator and complete the query + $query = preg_replace('/UNION ALL $/', ') AS `all_posts` WHERE (`time` < :last_time OR NOT :last_time) ORDER BY `time` DESC LIMIT ' . $limit, $query); + $query = prepare($query); + $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(); + } + + foreach ($posts as &$post) { + openBoard($post['board']); + if (!$post['thread']) { + // Still need to fix this: + $po = new Thread($post, '?/', $mod, false); + $post['built'] = $po->build(true); + 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); + $apithreads[] = $pot; + } + } + $last_time = $post['time']; + } + if ($config['api']['enabled']) { + require_once __DIR__. '/../../inc/api.php'; + $api = new Api(); + $jsonFilename = 'mod/' . 'recent.json'; + $jsondata = json_encode($api->translatePage($apithreads)); + } + + if ($json){ + echo $jsondata; + } + else { + echo mod_page(_('Recent posts'), 'mod/recent_posts.html', array( + 'posts' => $posts, + 'limit' => $limit, + 'last_time' => $last_time + ) + ); + } } 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 - $old_code = file_get_contents($config_file); - file_put_contents($config_file, $code); - $resp = shell_exec_error('php -l ' . $config_file); - if (preg_match('/No syntax errors detected/', $resp)) { - header('Location: ?/config' . ($board_config ? '/' . $board_config : ''), true, $config['redirect_http']); - return; - } - 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, - 'boards' => listBoards(), - 'board' => $board_config, - 'file' => $config_file, - 'token' => make_secure_link_token('config' . ($board_config ? '/' . $board_config : '')) - )); - return; - } - - require_once 'inc/mod/config-editor.php'; - - $conf = config_vars(); - - foreach ($conf as &$var) { - if (is_array($var['name'])) { - $c = &$config; - foreach ($var['name'] as $n) - $c = &$c[$n]; - } 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]; - } else { - $config_append .= var_export($value, true); - } - $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 = "Tinyboard could not write to ' . $config_file . ' with the ammended configuration, probably due to a permissions error.

-

You may proceed with these changes manually by copying and pasting the following code to the end of ' . $config_file . ':

- - '; - echo Element('page.html', $page); - exit; - } - } - - header('Location: ?/config' . ($board_config ? '/' . $board_config : ''), true, $config['redirect_http']); - - exit; - } - - mod_page(_('Config editor') . ($board_config ? ': ' . sprintf($config['board_abbreviation'], $board_config) : ''), - 'mod/config-editor.html', array( - 'boards' => listBoards(), - 'board' => $board_config, - 'conf' => $conf, - 'file' => $config_file, - 'token' => make_secure_link_token('config' . ($board_config ? '/' . $board_config : '')) - )); + 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 + $old_code = file_get_contents($config_file); + file_put_contents($config_file, $code); + $resp = shell_exec_error('php -l ' . $config_file); + if (preg_match('/No syntax errors detected/', $resp)) { + header('Location: ?/config' . ($board_config ? '/' . $board_config : ''), true, $config['redirect_http']); + return; + } + 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, + 'boards' => listBoards(), + 'board' => $board_config, + 'file' => $config_file, + 'token' => make_secure_link_token('config' . ($board_config ? '/' . $board_config : '')) + )); + return; + } + + require_once 'inc/mod/config-editor.php'; + + $conf = config_vars(); + + foreach ($conf as &$var) { + if (is_array($var['name'])) { + $c = &$config; + foreach ($var['name'] as $n) + $c = &$c[$n]; + } 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]; + } else { + $config_append .= var_export($value, true); + } + $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 = "Tinyboard could not write to ' . $config_file . ' with the ammended configuration, probably due to a permissions error.

+

You may proceed with these changes manually by copying and pasting the following code to the end of ' . $config_file . ':

+ + '; + echo Element('page.html', $page); + exit; + } + } + + header('Location: ?/config' . ($board_config ? '/' . $board_config : ''), true, $config['redirect_http']); + + exit; + } + + mod_page(_('Config editor') . ($board_config ? ': ' . sprintf($config['board_abbreviation'], $board_config) : ''), + 'mod/config-editor.html', array( + 'boards' => listBoards(), + 'board' => $board_config, + 'conf' => $conf, + 'file' => $config_file, + 'token' => make_secure_link_token('config' . ($board_config ? '/' . $board_config : '')) + )); } function mod_themes_list() { - global $config; - - if (!hasPermission($config['mod']['themes'])) - error($config['error']['noaccess']); - - if (!is_dir($config['dir']['themes'])) - error(_('Themes directory doesn\'t exist!')); - if (!$dir = opendir($config['dir']['themes'])) - error(_('Cannot open themes directory; check permissions.')); - - $query = query('SELECT `theme` FROM ``theme_settings`` WHERE `name` IS NULL AND `value` IS NULL') or error(db_error()); - $themes_in_use = $query->fetchAll(PDO::FETCH_COLUMN); - - // Scan directory for themes - $themes = array(); - while ($file = readdir($dir)) { - if ($file[0] != '.' && is_dir($config['dir']['themes'] . '/' . $file)) { - $themes[$file] = loadThemeConfig($file); - } - } - closedir($dir); - - foreach ($themes as $theme_name => &$theme) { - $theme['rebuild_token'] = make_secure_link_token('themes/' . $theme_name . '/rebuild'); - $theme['uninstall_token'] = make_secure_link_token('themes/' . $theme_name . '/uninstall'); - } - - mod_page(_('Manage themes'), 'mod/themes.html', array( - 'themes' => $themes, - 'themes_in_use' => $themes_in_use, - )); + global $config; + + if (!hasPermission($config['mod']['themes'])) + error($config['error']['noaccess']); + + if (!is_dir($config['dir']['themes'])) + error(_('Themes directory doesn\'t exist!')); + if (!$dir = opendir($config['dir']['themes'])) + error(_('Cannot open themes directory; check permissions.')); + + $query = query('SELECT `theme` FROM ``theme_settings`` WHERE `name` IS NULL AND `value` IS NULL') or error(db_error()); + $themes_in_use = $query->fetchAll(PDO::FETCH_COLUMN); + + // Scan directory for themes + $themes = array(); + while ($file = readdir($dir)) { + if ($file[0] != '.' && is_dir($config['dir']['themes'] . '/' . $file)) { + $themes[$file] = loadThemeConfig($file); + } + } + closedir($dir); + + foreach ($themes as $theme_name => &$theme) { + $theme['rebuild_token'] = make_secure_link_token('themes/' . $theme_name . '/rebuild'); + $theme['uninstall_token'] = make_secure_link_token('themes/' . $theme_name . '/uninstall'); + } + + mod_page(_('Manage themes'), 'mod/themes.html', array( + 'themes' => $themes, + 'themes_in_use' => $themes_in_use, + )); } function mod_theme_configure($theme_name) { - global $config; - - if (!hasPermission($config['mod']['themes'])) - error($config['error']['noaccess']); - - if (!$theme = loadThemeConfig($theme_name)) { - error($config['error']['invalidtheme']); - } - - if (isset($_POST['install'])) { - // Check if everything is submitted - foreach ($theme['config'] as &$conf) { - 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); - $query->bindValue(':name', $conf['name']); - if ($conf['type'] == 'checkbox') - $query->bindValue(':value', isset($_POST[$conf['name']]) ? 1 : 0); - else - $query->bindValue(':value', $_POST[$conf['name']]); - $query->execute() or error(db_error($query)); - } - - $query = prepare("INSERT INTO ``theme_settings`` VALUES(:theme, NULL, NULL)"); - $query->bindValue(':theme', $theme_name); - $query->execute() or error(db_error($query)); - - // Clean cache - Cache::delete("themes"); - Cache::delete("theme_settings_".$theme_name); - - $result = true; - $message = false; - if (isset($theme['install_callback'])) { - $ret = $theme['install_callback'](themeSettings($theme_name)); - if ($ret && !empty($ret)) { - if (is_array($ret) && count($ret) == 2) { - $result = $ret[0]; - $message = $ret[1]; - } - } - } - - 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, - 'result' => $result, - 'message' => $message - )); - return; - } - - $settings = themeSettings($theme_name); - - mod_page(sprintf(_('Configuring theme: %s'), $theme['name']), 'mod/theme_config.html', array( - 'theme_name' => $theme_name, - 'theme' => $theme, - 'settings' => $settings, - 'token' => make_secure_link_token('themes/' . $theme_name) - )); + global $config; + + if (!hasPermission($config['mod']['themes'])) + error($config['error']['noaccess']); + + if (!$theme = loadThemeConfig($theme_name)) { + error($config['error']['invalidtheme']); + } + + if (isset($_POST['install'])) { + // Check if everything is submitted + foreach ($theme['config'] as &$conf) { + 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); + $query->bindValue(':name', $conf['name']); + if ($conf['type'] == 'checkbox') + $query->bindValue(':value', isset($_POST[$conf['name']]) ? 1 : 0); + else + $query->bindValue(':value', $_POST[$conf['name']]); + $query->execute() or error(db_error($query)); + } + + $query = prepare("INSERT INTO ``theme_settings`` VALUES(:theme, NULL, NULL)"); + $query->bindValue(':theme', $theme_name); + $query->execute() or error(db_error($query)); + + // Clean cache + Cache::delete("themes"); + Cache::delete("theme_settings_".$theme_name); + + $result = true; + $message = false; + if (isset($theme['install_callback'])) { + $ret = $theme['install_callback'](themeSettings($theme_name)); + if ($ret && !empty($ret)) { + if (is_array($ret) && count($ret) == 2) { + $result = $ret[0]; + $message = $ret[1]; + } + } + } + + 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, + 'result' => $result, + 'message' => $message + )); + return; + } + + $settings = themeSettings($theme_name); + + mod_page(sprintf(_('Configuring theme: %s'), $theme['name']), 'mod/theme_config.html', array( + 'theme_name' => $theme_name, + 'theme' => $theme, + 'settings' => $settings, + 'token' => make_secure_link_token('themes/' . $theme_name) + )); } function mod_theme_uninstall($theme_name) { - global $config; + global $config; - if (!hasPermission($config['mod']['themes'])) - error($config['error']['noaccess']); + if (!hasPermission($config['mod']['themes'])) + error($config['error']['noaccess']); - $query = prepare("DELETE FROM ``theme_settings`` WHERE `theme` = :theme"); - $query->bindValue(':theme', $theme_name); - $query->execute() or error(db_error($query)); + $query = prepare("DELETE FROM ``theme_settings`` WHERE `theme` = :theme"); + $query->bindValue(':theme', $theme_name); + $query->execute() or error(db_error($query)); - // Clean cache - Cache::delete("themes"); - Cache::delete("theme_settings_".$theme); + // Clean cache + Cache::delete("themes"); + Cache::delete("theme_settings_".$theme); - header('Location: ?/themes', true, $config['redirect_http']); + header('Location: ?/themes', true, $config['redirect_http']); } function mod_theme_rebuild($theme_name) { - global $config; + global $config; - if (!hasPermission($config['mod']['themes'])) - error($config['error']['noaccess']); - - rebuildTheme($theme_name, 'all'); + 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( - 'theme_name' => $theme_name, - )); + mod_page(sprintf(_('Rebuilt theme: %s'), $theme_name), 'mod/theme_rebuilt.html', array( + 'theme_name' => $theme_name, + )); } // This needs to be done for `secure` CSRF prevention compatibility, otherwise the $board will be read in as the token if editing global pages. function delete_page_base($page = '', $board = false) { - global $config, $mod; + global $config, $mod; - if (empty($board)) - $board = false; + if (empty($board)) + $board = false; - if (!$board && $mod['boards'][0] !== '*') - error($config['error']['noaccess']); + if (!$board && $mod['boards'][0] !== '*') + error($config['error']['noaccess']); - if (!hasPermission($config['mod']['edit_pages'], $board)) - error($config['error']['noaccess']); + if (!hasPermission($config['mod']['edit_pages'], $board)) + error($config['error']['noaccess']); - if ($board !== FALSE && !openBoard($board)) - error($config['error']['noboard']); + if ($board !== FALSE && !openBoard($board)) + error($config['error']['noboard']); - if ($board) { - $query = prepare('DELETE FROM ``pages`` WHERE `board` = :board AND `name` = :name'); - $query->bindValue(':board', ($board ? $board : NULL)); - } else { - $query = prepare('DELETE FROM ``pages`` WHERE `board` IS NULL AND `name` = :name'); - } - $query->bindValue(':name', $page); - $query->execute() or error(db_error($query)); + if ($board) { + $query = prepare('DELETE FROM ``pages`` WHERE `board` = :board AND `name` = :name'); + $query->bindValue(':board', ($board ? $board : NULL)); + } else { + $query = prepare('DELETE FROM ``pages`` WHERE `board` IS NULL AND `name` = :name'); + } + $query->bindValue(':name', $page); + $query->execute() or error(db_error($query)); - header('Location: ?/edit_pages' . ($board ? ('/' . $board) : ''), true, $config['redirect_http']); + header('Location: ?/edit_pages' . ($board ? ('/' . $board) : ''), true, $config['redirect_http']); } function mod_delete_page($page = '') { - delete_page_base($page); + delete_page_base($page); } function mod_delete_page_board($page = '', $board = false) { - delete_page_base($page, $board); + delete_page_base($page, $board); } function mod_edit_page($id) { - global $config, $mod, $board; - - $query = prepare('SELECT * FROM ``pages`` WHERE `id` = :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.')); - - if (!$page['board'] && $mod['boards'][0] !== '*') - error($config['error']['noaccess']); - - if (!hasPermission($config['mod']['edit_pages'], $page['board'])) - error($config['error']['noaccess']); - - if ($page['board'] && !openBoard($page['board'])) - error($config['error']['noboard']); - - if (isset($_POST['method'], $_POST['content'])) { - $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': - $write = markdown($content); - break; - case 'html': - if (hasPermission($config['mod']['rawhtml'])) { - $write = $content; - } else { - $write = purify_html($content); - } - break; - case 'infinity': - $c = $content; - markup($content); - $write = $content; - $content = $c; - } - - if (!isset($write) or !$write) - error(_('Failed to mark up your input for some reason...')); - - $query = prepare('UPDATE ``pages`` SET `type` = :method, `content` = :content WHERE `id` = :id'); - $query->bindValue(':method', $method); - $query->bindValue(':content', $content); - $query->bindValue(':id', $id); - $query->execute() or error(db_error($query)); - - $fn = ($board['uri'] ? ($board['uri'] . '/') : '') . $page['name'] . '.html'; - $body = "
$write
"; - $html = Element('page.html', array('config' => $config, 'body' => $body, 'title' => utf8tohtml($page['title']))); - file_write($fn, $html); - } - - if (!isset($content)) { - $query = prepare('SELECT `content` FROM ``pages`` WHERE `id` = :id'); - $query->bindValue(':id', $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)); + global $config, $mod, $board; + + $query = prepare('SELECT * FROM ``pages`` WHERE `id` = :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.')); + + if (!$page['board'] && $mod['boards'][0] !== '*') + error($config['error']['noaccess']); + + if (!hasPermission($config['mod']['edit_pages'], $page['board'])) + error($config['error']['noaccess']); + + if ($page['board'] && !openBoard($page['board'])) + error($config['error']['noboard']); + + if (isset($_POST['method'], $_POST['content'])) { + $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': + $write = markdown($content); + break; + case 'html': + if (hasPermission($config['mod']['rawhtml'])) { + $write = $content; + } else { + $write = purify_html($content); + } + break; + case 'infinity': + $c = $content; + markup($content); + $write = $content; + $content = $c; + } + + if (!isset($write) or !$write) + error(_('Failed to mark up your input for some reason...')); + + $query = prepare('UPDATE ``pages`` SET `type` = :method, `content` = :content WHERE `id` = :id'); + $query->bindValue(':method', $method); + $query->bindValue(':content', $content); + $query->bindValue(':id', $id); + $query->execute() or error(db_error($query)); + + $fn = ($board['uri'] ? ($board['uri'] . '/') : '') . $page['name'] . '.html'; + $body = "
$write
"; + $html = Element('page.html', array('config' => $config, 'body' => $body, 'title' => utf8tohtml($page['title']))); + file_write($fn, $html); + } + + if (!isset($content)) { + $query = prepare('SELECT `content` FROM ``pages`` WHERE `id` = :id'); + $query->bindValue(':id', $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)); } function mod_pages($board = false) { - global $config, $mod, $pdo; + global $config, $mod, $pdo; - if (empty($board)) - $board = false; + if (empty($board)) + $board = false; - if (!$board && $mod['boards'][0] !== '*') - error($config['error']['noaccess']); + if (!$board && $mod['boards'][0] !== '*') + error($config['error']['noaccess']); - if (!hasPermission($config['mod']['edit_pages'], $board)) - error($config['error']['noaccess']); + if (!hasPermission($config['mod']['edit_pages'], $board)) + error($config['error']['noaccess']); - if ($board !== FALSE && !openBoard($board)) - error($config['error']['noboard']); + if ($board !== FALSE && !openBoard($board)) + error($config['error']['noboard']); - if ($board) { - $query = prepare('SELECT * FROM ``pages`` WHERE `board` = :board'); - $query->bindValue(':board', $board); - } else { - $query = query('SELECT * FROM ``pages`` WHERE `board` IS NULL'); - } - $query->execute() or error(db_error($query)); - $pages = $query->fetchAll(PDO::FETCH_ASSOC); + if ($board) { + $query = prepare('SELECT * FROM ``pages`` WHERE `board` = :board'); + $query->bindValue(':board', $board); + } else { + $query = query('SELECT * FROM ``pages`` WHERE `board` IS NULL'); + } + $query->execute() or error(db_error($query)); + $pages = $query->fetchAll(PDO::FETCH_ASSOC); - if (isset($_POST['page'])) { - if ($board and sizeof($pages) > $config['pages_max']) - error(sprintf(_('Sorry, this site only allows %d pages per board.'), $config['pages_max'])); + if (isset($_POST['page'])) { + if ($board and sizeof($pages) > $config['pages_max']) + error(sprintf(_('Sorry, this site only allows %d pages per board.'), $config['pages_max'])); - if (!preg_match('/^[a-z0-9]{1,255}$/', $_POST['page'])) - error(_('Page names must be < 255 chars and may only contain lowercase letters A-Z and digits 1-9.')); + if (!preg_match('/^[a-z0-9]{1,255}$/', $_POST['page'])) + error(_('Page names must be < 255 chars and may only contain lowercase letters A-Z and digits 1-9.')); - foreach ($pages as $i => $p) { - if ($_POST['page'] === $p['name']) - error(_('Refusing to create a new page with the same name as an existing one.')); - } + foreach ($pages as $i => $p) { + if ($_POST['page'] === $p['name']) + error(_('Refusing to create a new page with the same name as an existing one.')); + } - $title = ($_POST['title'] ? $_POST['title'] : NULL); + $title = ($_POST['title'] ? $_POST['title'] : NULL); - $query = prepare('INSERT INTO ``pages``(board, title, name) VALUES(:board, :title, :name)'); - $query->bindValue(':board', ($board ? $board : NULL)); - $query->bindValue(':title', $title); - $query->bindValue(':name', $_POST['page']); - $query->execute() or error(db_error($query)); + $query = prepare('INSERT INTO ``pages``(board, title, name) VALUES(:board, :title, :name)'); + $query->bindValue(':board', ($board ? $board : NULL)); + $query->bindValue(':title', $title); + $query->bindValue(':name', $_POST['page']); + $query->execute() or error(db_error($query)); - $pages[] = array('id' => $pdo->lastInsertId(), 'name' => $_POST['page'], 'board' => $board, 'title' => $title); - } + $pages[] = array('id' => $pdo->lastInsertId(), 'name' => $_POST['page'], 'board' => $board, 'title' => $title); + } - foreach ($pages as $i => &$p) { - $p['delete_token'] = make_secure_link_token('edit_pages/delete/' . $p['name'] . ($board ? ('/' . $board) : '')); - } + foreach ($pages as $i => &$p) { + $p['delete_token'] = make_secure_link_token('edit_pages/delete/' . $p['name'] . ($board ? ('/' . $board) : '')); + } - mod_page(_('Pages'), 'mod/pages.html', array('pages' => $pages, 'token' => make_secure_link_token('edit_pages' . ($board ? ('/' . $board) : '')), 'board' => $board)); + mod_page(_('Pages'), 'mod/pages.html', array('pages' => $pages, 'token' => make_secure_link_token('edit_pages' . ($board ? ('/' . $board) : '')), 'board' => $board)); } 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); + 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) { - $query .= sprintf('SELECT *, %s AS `board` FROM ``posts_%s`` UNION ALL ', $pdo->quote($board['uri']), $board['uri']); - } - // Remove the last "UNION ALL" seperator and complete the query - $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) { - if ($flood_post['time'] == $post['time'] && - $flood_post['posthash'] == make_comment_hex($post['body_nomarkup']) && - $flood_post['filehash'] == $post['filehash']) - $post['in_flood_table'] = true; - } - } - - mod_page(_('Debug: Recent posts'), 'mod/debug/recent_posts.html', array('posts' => $posts, 'flood_posts' => $flood_posts)); + global $pdo, $config; + + $limit = 500; + + $boards = listBoards(); + + // Manually build an SQL query + $query = 'SELECT * FROM ('; + foreach ($boards as $board) { + $query .= sprintf('SELECT *, %s AS `board` FROM ``posts_%s`` UNION ALL ', $pdo->quote($board['uri']), $board['uri']); + } + // Remove the last "UNION ALL" seperator and complete the query + $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) { + if ($flood_post['time'] == $post['time'] && + $flood_post['posthash'] == make_comment_hex($post['body_nomarkup']) && + $flood_post['filehash'] == $post['filehash']) + $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'])) { - $args['result'] = $query->fetchAll(PDO::FETCH_ASSOC); - if (!empty($args['result'])) - $args['keys'] = array_keys($args['result'][0]); - else - $args['result'] = 'empty'; - } else { - $args['error'] = db_error(); - } - } - - mod_page(_('Debug: SQL'), 'mod/debug/sql.html', $args); + 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'])) { + $args['result'] = $query->fetchAll(PDO::FETCH_ASSOC); + if (!empty($args['result'])) + $args['keys'] = array_keys($args['result'][0]); + else + $args['result'] = 'empty'; + } else { + $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) { - if ($config['cache']['prefix'] != '' && strpos(isset($var['key']) ? $var['key'] : $var['info'], $config['cache']['prefix']) !== 0) - continue; - $cached_vars[] = $var; - } - - mod_page(_('Debug: APC'), 'mod/debug/apc.html', array('cached_vars' => $cached_vars)); + 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) { + if ($config['cache']['prefix'] != '' && strpos(isset($var['key']) ? $var['key'] : $var['info'], $config['cache']['prefix']) !== 0) + continue; + $cached_vars[] = $var; + } + + mod_page(_('Debug: APC'), 'mod/debug/apc.html', array('cached_vars' => $cached_vars)); }