public function build($settings, $board_name) { global $config, $board; openBoard($board_name); $recent_images = array(); $recent_posts = array(); $stats = array(); $query = query(sprintf("SELECT *, `id` AS `thread_id`,\n\t\t\t\t(SELECT COUNT(`id`) FROM ``posts_%s`` WHERE `thread` = `thread_id`) AS `reply_count`,\n\t\t\t\t(SELECT SUM(`num_files`) FROM ``posts_%s`` WHERE `thread` = `thread_id` AND `num_files` IS NOT NULL) AS `image_count`,\n\t\t\t\t'%s' AS `board` FROM ``posts_%s`` WHERE `thread` IS NULL ORDER BY `bump` DESC", $board_name, $board_name, $board_name, $board_name, $board_name)) or error(db_error()); while ($post = $query->fetch(PDO::FETCH_ASSOC)) { $post['link'] = $config['root'] . $board['dir'] . $config['dir']['res'] . sprintf($config['file_page'], $post['thread'] ? $post['thread'] : $post['id']); $post['board_name'] = $board['name']; if ($post['embed'] && preg_match('/^https?:\\/\\/(\\w+\\.)?(?:youtube\\.com\\/watch\\?v=|youtu\\.be\\/)([a-zA-Z0-9\\-_]{10,11})(&.+)?$/i', $post['embed'], $matches)) { $post['youtube'] = $matches[2]; } if (isset($post['files'])) { $files = json_decode($post['files']); if ($files[0]->file == 'deleted') { continue; } $post['file'] = $config['uri_thumb'] . $files[0]->thumb; } $recent_posts[] = $post; } $required_scripts = array('js/jquery.min.js', 'js/jquery.mixitup.min.js', 'js/catalog.js'); foreach ($required_scripts as $i => $s) { if (!in_array($s, $config['additional_javascript'])) { $config['additional_javascript'][] = $s; } } file_write($config['dir']['home'] . $board_name . '/catalog.html', Element('themes/catalog/catalog.html', array('settings' => $settings, 'config' => $config, 'boardlist' => createBoardlist(), 'recent_images' => $recent_images, 'recent_posts' => $recent_posts, 'stats' => $stats, 'board' => $board_name, 'link' => $config['root'] . $board['dir']))); }
public function build($settings, $board_name) { global $config, $board; openBoard($board_name); $recent_images = array(); $recent_posts = array(); $stats = array(); $query = query(sprintf("SELECT *, `id` AS `thread_id`, (SELECT COUNT(*) FROM ``posts_%s`` WHERE `thread` = `thread_id`) AS `reply_count`, '%s' AS `board` FROM ``posts_%s`` WHERE `thread` IS NULL ORDER BY `bump` DESC", $board_name, $board_name, $board_name)) or error(db_error()); while ($post = $query->fetch(PDO::FETCH_ASSOC)) { $post['link'] = $config['root'] . $board['dir'] . $config['dir']['res'] . sprintf($config['file_page'], $post['thread'] ? $post['thread'] : $post['id']); $post['board_name'] = $board['name']; $post['file'] = $config['uri_thumb'] . $post['thumb']; $recent_posts[] = $post; } file_write($config['dir']['home'] . $board_name . '/catalog.html', Element('themes/catalog/catalog.html', array('settings' => $settings, 'config' => $config, 'boardlist' => createBoardlist(), 'recent_images' => $recent_images, 'recent_posts' => $recent_posts, 'stats' => $stats, 'board' => $board_name, 'link' => $config['root'] . $board['dir']))); }
public static function news($settings) { global $config, $board; // HTML5 $body = '<!DOCTYPE html><html>' . '<head>' . '<meta charset="utf-8">' . '<link rel="stylesheet" href="frontpage.css" />' . '<link rel="stylesheet" media="screen" id="stylesheet" href="/stylesheets/style.css">' . '<script type="text/javascript" src="/styleswitch-sidebar.js"></script>' . '<title>' . $settings['title'] . ' - News</title>' . '</head><body>'; $boardlist = createBoardlist(); $body .= $boardlist['top'] . '<br />'; $boards = listBoards(); $body .= '<div id="maintable"><div id="logo"></div><div id="announcement">Don\'t touch the lights!</div><table style="margin-bottom: 4px; width: 100%;"><tr>'; // Recent Posts $body .= '<td style="width: 100%;"><div class="post_wrap"><div class="post_header"><b>Recent Posts</b></div><div class="post_body"><div class="post_content" style="padding-bottom: 10px;">'; $query = ''; foreach ($boards as &$_board) { // Block Board if ($_board['uri'] != "aurora") { $query .= sprintf("SELECT *, '%s' AS `board` FROM `posts_%s` UNION ALL ", $_board['uri'], $_board['uri']); } } $query = preg_replace('/UNION ALL $/', 'ORDER BY `time` DESC LIMIT 15', $query); $query = query($query) or error(db_error()); while ($post = $query->fetch()) { openBoard($post['board']); $body .= '<strong>' . $board['name'] . '</strong>: <a href="' . $config['root'] . $board['dir'] . $config['dir']['res'] . ($post['thread'] ? $post['thread'] : $post['id']) . '.html#' . $post['id'] . '">'; $snip = pm_snippet($post['body'], 95); if ($snip === "<em></em>") { $body .= '<empty>'; } else { $body .= $snip; } $body .= '</a><br />'; } // News $body .= '</div></div></div></td></tr></table>'; $query = query("SELECT * FROM `news` ORDER BY `time` DESC LIMIT 5") or error(db_error()); if ($query->rowCount() == 0) { $body .= '<p style="text-align:center" class="unimportant">(No news to show.)</p>'; } else { // List news while ($news = $query->fetch()) { $body .= '<div class="post_wrap"><div class="post_header">' . (time() - $news['time'] <= 432000 ? '<em><b><span style="color: #D03030;">*NEW*</span></b></em> ' : '') . ($news['subject'] ? $news['subject'] : '<em>no subject</em>') . ' — by ' . $news['name'] . ' at ' . strftime($config['post_date'], $news['time']) . '</div><div class="post_body"><div class="post_content">' . $news['body'] . '</div></div></div>'; } } // Finish page $body .= '<br />'; $body .= '</div></body></html>'; return $body; }
public function build($settings, $board_name) { global $config, $board; openBoard($board_name); $recent_images = array(); $recent_posts = array(); $stats = array(); $query = query(sprintf("SELECT *, `id` AS `thread_id`, (SELECT COUNT(*) FROM ``posts_%s`` WHERE `thread` = `thread_id`) AS `reply_count`, '%s' AS `board` FROM ``posts_%s`` WHERE `thread` IS NULL ORDER BY `bump` DESC", $board_name, $board_name, $board_name)) or error(db_error()); while ($post = $query->fetch(PDO::FETCH_ASSOC)) { $post['link'] = $config['root'] . $board['dir'] . $config['dir']['res'] . sprintf($config['file_page'], $post['thread'] ? $post['thread'] : $post['id']); $post['board_name'] = $board['name']; $post['file'] = $config['uri_thumb'] . $post['thumb']; if ($post['embed'] && preg_match('/^https?:\\/\\/(\\w+\\.)?(?:youtube\\.com\\/watch\\?v=|youtu\\.be\\/)([a-zA-Z0-9\\-_]{10,11})(&.+)?$/i', $post['embed'], $matches)) { $post['youtube'] = $matches[2]; } $recent_posts[] = $post; } file_write($config['dir']['home'] . $board_name . '/catalog.html', Element('themes/catalog/catalog.html', array('settings' => $settings, 'config' => $config, 'boardlist' => createBoardlist(), 'recent_images' => $recent_images, 'recent_posts' => $recent_posts, 'stats' => $stats, 'board' => $board_name, 'link' => $config['root'] . $board['dir']))); }
function doboard($board) { global $global_locale, $config, $main_js, $options; $config['mask_db_error'] = false; if (!$options['api']) { $config['api']['enabled'] = false; } echo "Opening board /{$board['uri']}/...\n"; // Reset locale to global locale $config['locale'] = $global_locale; init_locale($config['locale'], 'error'); openBoard($board['uri']); $config['try_smarter'] = false; if ($config['file_script'] != $main_js && $options['js']) { // different javascript file echo "(/{$board['uri']}/) Generating Javascript file...\n"; buildJavascript(); } if ($options['indexes']) { echo "(/{$board['uri']}/) Creating index pages...\n"; buildIndex(); } if ($options['postmarkup']) { $query = query(sprintf("SELECT `id` FROM ``posts_%s``", $board['uri'])) or error(db_error()); while ($post = $query->fetch()) { echo "(/{$board['uri']}/) Rebuilding #{$post['id']}...\n"; rebuildPost($post['id']); } } if ($options['threads']) { $query = query(sprintf("SELECT `id` FROM ``posts_%s`` WHERE `thread` IS NULL", $board['uri'])) or error(db_error()); while ($post = $query->fetch()) { echo "(/{$board['uri']}/) Rebuilding #{$post['id']}...\n"; @buildThread($post['id']); } } }
function markup(&$body, $track_cites = false) { global $board, $config, $markup_urls; $modifiers = extract_modifiers($body); $body = preg_replace('@<tinyboard (?!escape )([\\w\\s]+)>(.+?)</tinyboard>@us', '', $body); $body = preg_replace('@<(tinyboard) escape ([\\w\\s]+)>@i', '<$1 $2>', $body); if (isset($modifiers['raw html']) && $modifiers['raw html'] == '1') { return array(); } $body = str_replace("\r", '', $body); $body = utf8tohtml($body); if (mysql_version() < 50503) { $body = mb_encode_numericentity($body, array(0x10000, 0xffffff, 0, 0xffffff), 'UTF-8'); } if ($config['markup_code']) { $code_markup = array(); $body = preg_replace_callback($config['markup_code'], function ($matches) use(&$code_markup) { $d = count($code_markup); $code_markup[] = $matches; return "<code {$d}>"; }, $body); } foreach ($config['markup'] as $markup) { if (is_string($markup[1])) { $body = preg_replace($markup[0], $markup[1], $body); } elseif (is_callable($markup[1])) { $body = preg_replace_callback($markup[0], $markup[1], $body); } } if ($config['markup_urls']) { $markup_urls = array(); $body = preg_replace_callback('/((?:https?:\\/\\/|ftp:\\/\\/|irc:\\/\\/)[^\\s<>()"]+?(?:\\([^\\s<>()"]*?\\)[^\\s<>()"]*?)*)((?:\\s|<|>|"|\\.||\\]|!|\\?|,|,|")*(?:[\\s<>()"]|$))/', 'markup_url', $body, -1, $num_links); if ($num_links > $config['max_links']) { error($config['error']['toomanylinks']); } } if ($config['markup_repair_tidy']) { $body = str_replace(' ', ' ', $body); } if ($config['auto_unicode']) { $body = unicodify($body); if ($config['markup_urls']) { foreach ($markup_urls as &$url) { $body = str_replace(unicodify($url), $url, $body); } } } $tracked_cites = array(); // Cites if (isset($board) && preg_match_all('/(^|\\s)>>(\\d+?)([\\s,.)?]|$)/m', $body, $cites, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) { if (count($cites[0]) > $config['max_cites']) { error($config['error']['toomanycites']); } $skip_chars = 0; $body_tmp = $body; $search_cites = array(); foreach ($cites as $matches) { $search_cites[] = '`id` = ' . $matches[2][0]; } $search_cites = array_unique($search_cites); $query = query(sprintf('SELECT `thread`, `id` FROM ``posts_%s`` WHERE ' . implode(' OR ', $search_cites), $board['uri'])) or error(db_error()); $cited_posts = array(); while ($cited = $query->fetch(PDO::FETCH_ASSOC)) { $cited_posts[$cited['id']] = $cited['thread'] ? $cited['thread'] : false; } foreach ($cites as $matches) { $cite = $matches[2][0]; // preg_match_all is not multibyte-safe foreach ($matches as &$match) { $match[1] = mb_strlen(substr($body_tmp, 0, $match[1])); } if (isset($cited_posts[$cite])) { $replacement = '<a onclick="highlightReply(\'' . $cite . '\');" href="' . $config['root'] . $board['dir'] . $config['dir']['res'] . link_for(array('id' => $cite, 'thread' => $cited_posts[$cite])) . '#' . $cite . '">' . '>>' . $cite . '</a>'; $body = mb_substr_replace($body, $matches[1][0] . $replacement . $matches[3][0], $matches[0][1] + $skip_chars, mb_strlen($matches[0][0])); $skip_chars += mb_strlen($matches[1][0] . $replacement . $matches[3][0]) - mb_strlen($matches[0][0]); if ($track_cites && $config['track_cites']) { $tracked_cites[] = array($board['uri'], $cite); } } } } // Cross-board linking if (preg_match_all('/(^|\\s)>>>\\/(' . $config['board_regex'] . 'f?)\\/(\\d+)?([\\s,.)?]|$)/um', $body, $cites, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) { if (count($cites[0]) > $config['max_cites']) { error($config['error']['toomanycross']); } $skip_chars = 0; $body_tmp = $body; if (isset($cited_posts)) { // Carry found posts from local board >>X links foreach ($cited_posts as $cite => $thread) { $cited_posts[$cite] = $config['root'] . $board['dir'] . $config['dir']['res'] . ($thread ? $thread : $cite) . '.html#' . $cite; } $cited_posts = array($board['uri'] => $cited_posts); } else { $cited_posts = array(); } $crossboard_indexes = array(); $search_cites_boards = array(); foreach ($cites as $matches) { $_board = $matches[2][0]; $cite = @$matches[3][0]; if (!isset($search_cites_boards[$_board])) { $search_cites_boards[$_board] = array(); } $search_cites_boards[$_board][] = $cite; } $tmp_board = $board['uri']; foreach ($search_cites_boards as $_board => $search_cites) { $clauses = array(); foreach ($search_cites as $cite) { if (!$cite || isset($cited_posts[$_board][$cite])) { continue; } $clauses[] = '`id` = ' . $cite; } $clauses = array_unique($clauses); if ($board['uri'] != $_board) { if (!openBoard($_board)) { continue; } // Unknown board } if (!empty($clauses)) { $cited_posts[$_board] = array(); $query = query(sprintf('SELECT `thread`, `id`, `slug` FROM ``posts_%s`` WHERE ' . implode(' OR ', $clauses), $board['uri'])) or error(db_error()); while ($cite = $query->fetch(PDO::FETCH_ASSOC)) { $cited_posts[$_board][$cite['id']] = $config['root'] . $board['dir'] . $config['dir']['res'] . link_for($cite) . '#' . $cite['id']; } } $crossboard_indexes[$_board] = $config['root'] . $board['dir'] . $config['file_index']; } // Restore old board if ($board['uri'] != $tmp_board) { openBoard($tmp_board); } foreach ($cites as $matches) { $_board = $matches[2][0]; $cite = @$matches[3][0]; // preg_match_all is not multibyte-safe foreach ($matches as &$match) { $match[1] = mb_strlen(substr($body_tmp, 0, $match[1])); } if ($cite) { if (isset($cited_posts[$_board][$cite])) { $link = $cited_posts[$_board][$cite]; $replacement = '<a ' . ($_board == $board['uri'] ? 'onclick="highlightReply(\'' . $cite . '\');" ' : '') . 'href="' . $link . '">' . '>>>/' . $_board . '/' . $cite . '</a>'; $body = mb_substr_replace($body, $matches[1][0] . $replacement . $matches[4][0], $matches[0][1] + $skip_chars, mb_strlen($matches[0][0])); $skip_chars += mb_strlen($matches[1][0] . $replacement . $matches[4][0]) - mb_strlen($matches[0][0]); if ($track_cites && $config['track_cites']) { $tracked_cites[] = array($_board, $cite); } } } elseif (isset($crossboard_indexes[$_board])) { $replacement = '<a href="' . $crossboard_indexes[$_board] . '">' . '>>>/' . $_board . '/' . '</a>'; $body = mb_substr_replace($body, $matches[1][0] . $replacement . $matches[4][0], $matches[0][1] + $skip_chars, mb_strlen($matches[0][0])); $skip_chars += mb_strlen($matches[1][0] . $replacement . $matches[4][0]) - mb_strlen($matches[0][0]); } } } $tracked_cites = array_unique($tracked_cites, SORT_REGULAR); $body = preg_replace("/^\\s*>.*\$/m", '<span class="quote">$0</span>', $body); if ($config['strip_superfluous_returns']) { $body = preg_replace('/\\s+$/', '', $body); } $body = preg_replace("/\n/", '<br/>', $body); // Fix code markup if ($config['markup_code']) { foreach ($code_markup as $id => $val) { $code = isset($val[2]) ? $val[2] : $val[1]; $code_lang = isset($val[2]) ? $val[1] : ""; $code = "<pre class='code lang-{$code_lang}'>" . str_replace(array("\n", "\t"), array(" ", "	"), htmlspecialchars($code)) . "</pre>"; $body = str_replace("<code {$id}>", $code, $body); } } if ($config['markup_repair_tidy']) { $tidy = new tidy(); $body = str_replace("\t", '	', $body); $body = $tidy->repairString($body, array('doctype' => 'omit', 'bare' => true, 'literal-attributes' => true, 'indent' => false, 'show-body-only' => true, 'wrap' => 0, 'output-bom' => false, 'output-html' => true, 'newline' => 'LF', 'quiet' => true), 'utf8'); $body = str_replace("\n", '', $body); } // replace tabs with 8 spaces $body = str_replace("\t", ' ', $body); return $tracked_cites; }
$is_mod = isset($_POST['mod']) && $_POST['mod']; $root = $is_mod ? $config['root'] . $config['file_mod'] . '?/' : $config['root']; if (!isset($_POST['json_response'])) { $index = $root . $board['dir'] . $config['file_index']; echo Element('page.html', array('config' => $config, 'body' => '<div style="text-align:center"><a href="javascript:window.close()">[ ' . _('Close window') . " ]</a> <a href='{$index}'>[ " . _('Return') . ' ]</a></div>', 'title' => _('Report submitted!'))); } else { header('Content-Type: text/json'); echo json_encode(array('success' => true)); } } elseif (isset($_POST['post'])) { if (!isset($_POST['body'], $_POST['board'], $_POST['message']) || $_POST['message'] != '') { error($config['error']['bot']); } $post = array('board' => $_POST['board'], 'files' => array(), 'time' => time()); // Check if board exists if (!openBoard($post['board'])) { error($config['error']['noboard']); } if (!isset($_POST['name'])) { $_POST['name'] = $config['anonymous']; } if (!isset($_POST['email'])) { $_POST['email'] = ''; } if (!isset($_POST['subject'])) { $_POST['subject'] = ''; } if (!isset($_POST['password'])) { $_POST['password'] = ''; } if (isset($_POST['thread'])) {
function sb_catalog($b) { if (!openBoard($b)) { return false; } rebuildTheme("catalog", "post-thread", $b); return true; }
<?php include 'inc/functions.php'; include 'inc/mod/pages.php'; if (!isset($_GET['board']) || !preg_match("/{$config['board_regex']}/u", $_GET['board'])) { http_response_code(400); error('Bad board.'); } if (!openBoard($_GET['board'])) { http_response_code(404); error('No board.'); } if ($board['public_logs'] == 0) { error('This board has public logs disabled. Ask the board owner to enable it.'); } if ($board['public_logs'] == 1) { $hide_names = false; } if ($board['public_logs'] == 2) { $hide_names = true; } if (!isset($_GET['page'])) { $page = 1; } else { $page = (int) $_GET['page']; } mod_board_log($board['uri'], $page, $hide_names, true);
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 = "<?php\n\n// This file does not exist yet. You are creating it."; } $instance_config = str_replace("\n", '
', utf8tohtml($instance_config)); mod_page(_('Config editor'), 'mod/config-editor-php.html', array('php' => $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 = "<?php\n\n{$config_append}"; } if (!@file_put_contents($config_file, $config_append, FILE_APPEND)) { $config_append = htmlentities($config_append); if ($config['minify_html']) { $config_append = str_replace("\n", '
', $config_append); } $page = array(); $page['title'] = 'Cannot write to file!'; $page['config'] = $config; $page['body'] = ' <p style="text-align:center">Tinyboard could not write to <strong>' . $config_file . '</strong> with the ammended configuration, probably due to a permissions error.</p> <p style="text-align:center">You may proceed with these changes manually by copying and pasting the following code to the end of <strong>' . $config_file . '</strong>:</p> <textarea style="width:700px;height:370px;margin:auto;display:block;background:white;color:black" readonly>' . $config_append . '</textarea> '; 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 markup(&$body, $track_cites = false) { global $board, $config, $markup_urls; $body = utf8tohtml($body); if ($config['wiki_markup']) { $body = preg_replace("/(^|\n)==(.+?)==\n?/m", "<span class=\"heading\">\$2</span>", $body); $body = preg_replace("/'''(.+?)'''/m", "<strong>\$1</strong>", $body); $body = preg_replace("/''(.+?)''/m", "<em>\$1</em>", $body); $body = preg_replace("/\\*\\*(.+?)\\*\\*/m", "<span class=\"spoiler\">\$1</span>", $body); } if ($config['markup_urls']) { $markup_urls = array(); $body = preg_replace_callback($config['url_regex'], 'markup_url', $body, -1, $num_links); if ($num_links > $config['max_links']) { error($config['error']['toomanylinks']); } } if ($config['auto_unicode']) { $body = unicodify($body); foreach ($markup_urls as &$url) { $body = str_replace(unicodify($url), $url, $body); } } // replace tabs with 8 spaces $body = str_replace("\t", ' ', $body); $tracked_cites = array(); // Cites if (isset($board) && preg_match_all('/(^|\\s)>>(\\d+?)([\\s,.)?]|$)/', $body, $cites)) { if (count($cites[0]) > $config['max_cites']) { error($config['error']['toomanycites']); } for ($index = 0; $index < count($cites[0]); $index++) { $cite = $cites[2][$index]; $query = prepare(sprintf("SELECT `thread`,`id` FROM `posts_%s` WHERE `id` = :id LIMIT 1", $board['uri'])); $query->bindValue(':id', $cite); $query->execute() or error(db_error($query)); if ($post = $query->fetch()) { $replacement = '<a onclick="highlightReply(\'' . $cite . '\');" href="' . $config['root'] . $board['dir'] . $config['dir']['res'] . ($post['thread'] ? $post['thread'] : $post['id']) . '.html#' . $cite . '">' . '>>' . $cite . '</a>'; $body = str_replace($cites[0][$index], $cites[1][$index] . $replacement . $cites[3][$index], $body); if ($track_cites && $config['track_cites']) { $tracked_cites[] = array($board['uri'], $post['id']); } } } } // Cross-board linking if (preg_match_all('/(^|\\s)>>>\\/(\\w+?)\\/(\\d+)?([\\s,.)?]|$)/', $body, $cites)) { if (count($cites[0]) > $config['max_cites']) { error($config['error']['toomanycross']); } for ($index = 0; $index < count($cites[0]); $index++) { $_board = $cites[2][$index]; $cite = @$cites[3][$index]; // Temporarily store board information because it will be overwritten $tmp_board = $board['uri']; // Check if the board exists, and load settings if (openBoard($_board)) { if ($cite) { $query = prepare(sprintf("SELECT `thread`,`id` FROM `posts_%s` WHERE `id` = :id LIMIT 1", $board['uri'])); $query->bindValue(':id', $cite); $query->execute() or error(db_error($query)); if ($post = $query->fetch()) { $replacement = '<a onclick="highlightReply(\'' . $cite . '\');" href="' . $config['root'] . $board['dir'] . $config['dir']['res'] . ($post['thread'] ? $post['thread'] : $post['id']) . '.html#' . $cite . '">' . '>>>/' . $_board . '/' . $cite . '</a>'; $body = str_replace($cites[0][$index], $cites[1][$index] . $replacement . $cites[4][$index], $body); if ($track_cites && $config['track_cites']) { $tracked_cites[] = array($board['uri'], $post['id']); } } } else { $replacement = '<a href="' . $config['root'] . $board['dir'] . $config['file_index'] . '">' . '>>>/' . $_board . '/' . '</a>'; $body = str_replace($cites[0][$index], $cites[1][$index] . $replacement . $cites[4][$index], $body); } } // Restore main board settings openBoard($tmp_board); } } $body = str_replace("\r", '', $body); $body = preg_replace("/(^|\n)([\\s]+)?(>)([^\n]+)?(\$|\n)/m", '$1$2<span class="quote">$3$4</span>$5', $body); if ($config['strip_superfluous_returns']) { $body = preg_replace('/\\s+$/', '', $body); } $body = preg_replace("/\n/", '<br/>', $body); return $tracked_cites; }
function mod_8_settings($b) { global $config, $mod; //if ($b === 'infinity' && $mod['type'] !== ADMIN) // error('Settings temporarily disabled for this board.'); if (!in_array($b, $mod['boards']) and $mod['boards'][0] != '*') { error($config['error']['noaccess']); } if (!hasPermission($config['mod']['edit_settings'], $b)) { error($config['error']['noaccess']); } if (!openBoard($b)) { error("Could not open board!"); } $possible_languages = array_diff(scandir('inc/locale/'), array('..', '.', '.tx', 'README.md')); if ($_SERVER['REQUEST_METHOD'] == 'POST') { $board_type = $_POST['board_type']; $imgboard = $board_type == 'imgboard'; $txtboard = $board_type == 'txtboard'; $fileboard = $board_type == 'fileboard'; $title = $_POST['title']; $subtitle = $_POST['subtitle']; $country_flags = isset($_POST['country_flags']) ? 'true' : 'false'; $field_disable_name = isset($_POST['field_disable_name']) ? 'true' : 'false'; $enable_embedding = isset($_POST['enable_embedding']) ? 'true' : 'false'; $force_image_op = $imgboard && isset($_POST['force_image_op']) ? 'true' : 'false'; $disable_images = $txtboard ? 'true' : 'false'; $poster_ids = isset($_POST['poster_ids']) ? 'true' : 'false'; $show_sages = isset($_POST['show_sages']) ? 'true' : 'false'; $auto_unicode = isset($_POST['auto_unicode']) ? 'true' : 'false'; $strip_combining_chars = isset($_POST['strip_combining_chars']) ? 'true' : 'false'; $allow_roll = isset($_POST['allow_roll']) ? 'true' : 'false'; $image_reject_repost = isset($_POST['image_reject_repost']) ? 'true' : 'false'; $image_reject_repost_in_thread = isset($_POST['image_reject_repost_in_thread']) ? 'true' : 'false'; $early_404 = isset($_POST['early_404']) ? 'true' : 'false'; $allow_delete = isset($_POST['allow_delete']) ? 'true' : 'false'; $allow_flash = $imgboard && isset($_POST['allow_flash']) ? '$config[\'allowed_ext_files\'][] = \'swf\';' : ''; $allow_pdf = $imgboard && isset($_POST['allow_pdf']) ? '$config[\'allowed_ext_files\'][] = \'pdf\';' : ''; $code_tags = isset($_POST['code_tags']) ? '$config[\'additional_javascript\'][] = \'js/code_tags/run_prettify.js\';$config[\'markup\'][] = array("/\\[code\\](.+?)\\[\\/code\\]/ms", "<code><pre class=\'prettyprint\' style=\'display:inline-block\'>\\$1</pre></code>");' : ''; $katex = isset($_POST['katex']) ? '$config[\'katex\'] = true;$config[\'additional_javascript\'][] = \'js/katex/katex.min.js\'; $config[\'markup\'][] = array("/\\[tex\\](.+?)\\[\\/tex\\]/ms", "<span class=\'tex\'>\\$1</span>"); $config[\'additional_javascript\'][] = \'js/katex-enable.js\';' : ''; $user_flags = isset($_POST['user_flags']) ? "if (file_exists('{$b}/flags.php')) { include 'flags.php'; }\n" : ''; $captcha = isset($_POST['captcha']) ? 'true' : 'false'; $force_subject_op = isset($_POST['force_subject_op']) ? 'true' : 'false'; $force_flag = isset($_POST['force_flag']) ? 'true' : 'false'; $tor_posting = isset($_POST['tor_posting']) ? 'true' : 'false'; $tor_image_posting = isset($_POST['tor_image_posting']) ? 'true' : 'false'; $robot_enable = isset($_POST['robot_enable']) ? 'true' : 'false'; $new_thread_capt = isset($_POST['new_thread_capt']) ? 'true' : 'false'; $oekaki = ($imgboard || $fileboard) && isset($_POST['oekaki']) ? 'true' : 'false'; $view_bumplock = isset($_POST['view_bumplock']) ? '-1' : 'MOD'; if ($tor_image_posting === 'true' && isset($_POST['meta_noindex'])) { error('Please index your board to enable this.'); } if ($_POST['locale'] !== 'en' && in_array($_POST['locale'], $possible_languages)) { $locale = "\$config['locale'] = '{$_POST['locale']}.UTF-8';"; } else { $locale = ''; } if (isset($_POST['max_images']) && (int) $_POST['max_images'] && (int) $_POST['max_images'] <= 5) { $_POST['max_images'] = (int) $_POST['max_images']; $multiimage = "\$config['max_images'] = {$_POST['max_images']};\n\t\t\t\t\t \$config['additional_javascript'][] = 'js/multi-image.js';"; } else { $multiimage = ''; } if (isset($_POST['custom_assets'])) { $assets = "\$config['custom_assets'] = true;\n\t\t\t\t \$config['spoiler_image'] = 'static/assets/{$b}/spoiler.png';\n\t\t\t\t \$config['image_deleted'] = 'static/assets/{$b}/deleted.png';\n\t\t\t\t \$config['no_file_image'] = 'static/assets/{$b}/no-file.png';\n\t\t\t\t"; } else { $assets = ''; } $file_board = ''; if ($fileboard) { $force_image_op = true; $file_board = "\$config['threads_per_page'] = 30;\n\t\t\t\t\t \$config['file_board'] = true;\n\t\t\t\t\t \$config['threads_preview'] = 0;\n\t\t\t\t \$config['threads_preview_sticky'] = 0;\n\t\t\t\t\t \$config['allowed_ext_files'] = array();\n"; if (isset($_POST['allowed_type'])) { foreach ($_POST['allowed_type'] as $val) { if (in_array($val, $config['fileboard_allowed_types'])) { $file_board .= "\$config['allowed_ext_files'][] = '{$val}';\n"; } } } if (isset($_POST['allowed_ext_op'])) { $file_board .= "\$config['allowed_ext_op'] = \$config['allowed_ext_files'];\n"; if (isset($_POST['allowed_ext_op_video'])) { $file_board .= "\$config['allowed_ext_op'][] = 'webm';\n\t\t\t\t\t\t\t\t\$config['allowed_ext_op'][] = 'mp4';\n"; } } if (isset($_POST['tag_id'])) { $file_board .= "\$config['allowed_tags'] = array();\n"; foreach ($_POST['tag_id'] as $id => $v) { $file_board .= "\$config['allowed_tags']["; $file_board .= 'base64_decode("'; $file_board .= base64_encode($_POST['tag_id'][$id]); $file_board .= '")'; $file_board .= "] = "; $file_board .= 'base64_decode("'; $file_board .= base64_encode($_POST['tag_desc'][$id]); $file_board .= '")'; $file_board .= ";\n"; } } } $anal_filenames = $fileboard && isset($_POST['anal_filenames']) ? "\$config['filename_func'] = 'filename_func';\n" : ''; $anonymous = base64_encode($_POST['anonymous']); $blotter = base64_encode(purify_html(html_entity_decode($_POST['blotter']))); $add_to_config = @file_get_contents($b . '/extra_config.php'); $replace = ''; if (isset($_POST['replace'])) { if (sizeof($_POST['replace']) > 200 || sizeof($_POST['with']) > 200) { error(_('Sorry, max 200 wordfilters allowed.')); } if (count($_POST['replace']) == count($_POST['with'])) { foreach ($_POST['replace'] as $i => $r) { if ($r !== '') { $w = $_POST['with'][$i]; if (strlen($w) > 255) { error(sprintf(_('Sorry, %s is too long. Max replacement is 255 characters'), utf8tohtml($w))); } $replace .= '$config[\'wordfilters\'][] = array(base64_decode(\'' . base64_encode($r) . '\'), base64_decode(\'' . base64_encode($w) . '\'));'; } } } if (is_billion_laughs($_POST['replace'], $_POST['with'])) { error(_('Wordfilters may not wordfilter previous wordfilters. For example, if a filters to bb and b filters to cc, that is not allowed.')); } } if (isset($_POST['hour_max_threads']) && (int) $_POST['hour_max_threads'] > 0 && (int) $_POST['hour_max_threads'] < 101) { $hour_max_threads = (int) $_POST['hour_max_threads']; } else { $hour_max_threads = 'false'; } if (isset($_POST['max_pages'])) { $mp = (int) $_POST['max_pages']; if ($mp > 25 || $mp < 1) { $max_pages = 15; } else { $max_pages = $mp; } } else { $max_pages = 15; } if (isset($_POST['reply_limit'])) { $rl = (int) $_POST['reply_limit']; if ($rl > 750 || $rl < 250 || $rl % 25) { $reply_limit = 250; } else { $reply_limit = $rl; } } else { $reply_limit = 250; } if (isset($_POST['max_newlines'])) { $mn = (int) $_POST['max_newlines']; if ($mn < 20 || $mn > 300) { $max_newlines = 0; } else { $max_newlines = $mn; } } else { $max_newlines = 0; } if (isset($_POST['min_body'])) { $mb = (int) $_POST['min_body']; if ($mb < 0 || $mb > 1024) { $min_body = 0; } else { $min_body = $mb; } } else { $min_body = 0; } if (!(strlen($title) < 40)) { error('Invalid title'); } if (!(strlen($subtitle) < 200)) { error('Invalid subtitle'); } $query = prepare('UPDATE ``boards`` SET `title` = :title, `subtitle` = :subtitle, `indexed` = :indexed, `public_bans` = :public_bans, `public_logs` = :public_logs, `8archive` = :8archive WHERE `uri` = :uri'); $query->bindValue(':title', $title); $query->bindValue(':subtitle', $subtitle); $query->bindValue(':uri', $b); $query->bindValue(':indexed', !isset($_POST['meta_noindex'])); $query->bindValue(':public_bans', isset($_POST['public_bans'])); $query->bindValue(':public_logs', (int) $_POST['public_logs']); $query->bindValue(':8archive', isset($_POST['8archive'])); $query->execute() or error(db_error($query)); $config_file = <<<EOT <?php \$config['country_flags'] = {$country_flags}; \$config['field_disable_name'] = {$field_disable_name}; \$config['enable_embedding'] = {$enable_embedding}; \$config['force_image_op'] = {$force_image_op}; \$config['disable_images'] = {$disable_images}; \$config['poster_ids'] = {$poster_ids}; \$config['show_sages'] = {$show_sages}; \$config['auto_unicode'] = {$auto_unicode}; \$config['strip_combining_chars'] = {$strip_combining_chars}; \$config['allow_roll'] = {$allow_roll}; \$config['image_reject_repost'] = {$image_reject_repost}; \$config['image_reject_repost_in_thread'] = {$image_reject_repost_in_thread}; \$config['early_404'] = {$early_404}; \$config['allow_delete'] = {$allow_delete}; \$config['anonymous'] = base64_decode('{$anonymous}'); \$config['blotter'] = base64_decode('{$blotter}'); \$config['stylesheets']['Custom'] = 'board/{$b}.css'; \$config['default_stylesheet'] = array('Custom', \$config['stylesheets']['Custom']); \$config['captcha']['enabled'] = {$captcha}; \$config['force_subject_op'] = {$force_subject_op}; \$config['force_flag'] = {$force_flag}; \$config['tor_posting'] = {$tor_posting}; \$config['tor_image_posting'] = {$tor_image_posting}; \$config['robot_enable'] = {$robot_enable}; \$config['new_thread_capt'] = {$new_thread_capt}; \$config['hour_max_threads'] = {$hour_max_threads}; \$config['reply_limit'] = {$reply_limit}; \$config['max_pages'] = {$max_pages}; \$config['max_newlines'] = {$max_newlines}; \$config['oekaki'] = {$oekaki}; \$config['min_body'] = {$min_body}; \$config['mod']['view_bumplock'] = {$view_bumplock}; {$code_tags} {$katex} {$replace} {$multiimage} {$allow_flash} {$allow_pdf} {$user_flags} {$assets} {$locale} {$anal_filenames} {$file_board} if (\$config['disable_images']) \t\$config['max_pages'] = 10000; {$add_to_config} EOT; // Clean up our CSS...no more expression() or off-site URLs. $clean_css = preg_replace('/expression\\s*\\(/', '', $_POST['css']); $matched = array(); preg_match_all("#{$config['link_regex']}#im", $clean_css, $matched); if (isset($matched[0])) { foreach ($matched[0] as $match) { $match_okay = false; foreach ($config['allowed_offsite_urls'] as $allowed_url) { if (strpos($match, $allowed_url) !== false && strpos($match, '#') === false && strpos($match, '?') === false && strpos($match, ';') === false) { $match_okay = true; } } if ($match_okay !== true) { error(sprintf(_("Off-site link \"%s\" is not allowed in the board stylesheet"), $match)); } } } //Filter out imports from sites with potentially unsafe content $match_imports = '@import[^;]*'; $matched = array(); preg_match_all("#{$match_imports}#im", $clean_css, $matched); $unsafe_import_urls = array('https://a.pomf.se/'); if (isset($matched[0])) { foreach ($matched[0] as $match) { $match_okay = true; foreach ($unsafe_import_urls as $unsafe_import_url) { if (strpos($match, $unsafe_import_url) !== false && strpos($match, '#') === false) { $match_okay = false; } } if ($match_okay !== true) { error(sprintf(_("Potentially unsafe import \"%s\" is not allowed in the board stylesheet"), $match)); } } } $query = query('SELECT `uri`, `title`, `subtitle` FROM ``boards`` WHERE `8archive` = TRUE'); file_write('8archive.json', json_encode($query->fetchAll(PDO::FETCH_ASSOC))); file_write($b . '/config.php', $config_file); file_write('stylesheets/board/' . $b . '.css', $clean_css); $_config = $config; unset($config['wordfilters']); // Faster than openBoard and bypasses cache...we're trusting the PHP output // to be safe enough to run with every request, we can eval it here. eval(str_replace('flags.php', "{$b}/flags.php", preg_replace('/^\\<\\?php$/m', '', $config_file))); // czaks: maybe reconsider using it, now that config is cached? // be smarter about rebuilds...only some changes really require us to rebuild all threads if ($_config['captcha']['enabled'] != $config['captcha']['enabled'] || $_config['new_thread_capt'] != $config['new_thread_capt'] || $_config['captcha']['extra'] != $config['captcha']['extra'] || $_config['blotter'] != $config['blotter'] || $_config['field_disable_name'] != $config['field_disable_name'] || $_config['show_sages'] != (isset($config['show_sages']) && $config['show_sages'])) { buildIndex(); $query = query(sprintf("SELECT `id` FROM ``posts_%s`` WHERE `thread` IS NULL", $b)) or error(db_error()); while ($post = $query->fetch(PDO::FETCH_ASSOC)) { buildThread($post['id']); } } modLog('Edited board settings', $b); } $query = prepare('SELECT * FROM boards WHERE uri = :board'); $query->bindValue(':board', $b); $query->execute() or error(db_error($query)); $board = $query->fetchAll()[0]; // Clean the cache if ($config['cache']['enabled']) { cache::delete('board_' . $board['uri']); cache::delete('all_boards'); cache::delete('config_' . $board['uri']); cache::delete('events_' . $board['uri']); unlink('tmp/cache/locale_' . $board['uri']); } $css = @file_get_contents('stylesheets/board/' . $board['uri'] . '.css'); mod_page(_('Board configuration'), 'mod/settings.html', array('board' => $board, 'css' => prettify_textarea($css), 'token' => make_secure_link_token('settings/' . $board['uri']), 'languages' => $possible_languages, 'allowed_urls' => $config['allowed_offsite_urls'])); }
if (!$options['quiet']) { echo "Generating Javascript file...\n"; } buildJavascript(); $main_js = $config['file_script']; $boards = listBoards(); foreach ($boards as &$board) { if ($options['board'] && $board['uri'] != $options['board']) { continue; } if (!$options['quiet']) { echo "Opening board /{$board['uri']}/...\n"; } // Reset locale to global locale $config['locale'] = $global_locale; openBoard($board['uri']); $config['try_smarter'] = false; if ($config['file_script'] != $main_js) { // different javascript file if (!$options['quiet']) { echo "Generating Javascript file...\n"; } buildJavascript(); } if (!$options['quiet']) { echo "Creating index pages...\n"; } buildIndex(); if ($options['quick']) { continue; }
function markup(&$body, $track_cites = false, $op = false) { global $board, $config, $markup_urls; $modifiers = extract_modifiers($body); $body = preg_replace('@<tinyboard (?!escape )([\\w\\s]+)>(.+?)</tinyboard>@us', '', $body); $body = preg_replace('@<(tinyboard) escape ([\\w\\s]+)>@i', '<$1 $2>', $body); if (isset($modifiers['raw html']) && $modifiers['raw html'] == '1') { return array(); } $body = str_replace("\r", '', $body); $body = utf8tohtml($body); if (mysql_version() < 50503) { $body = mb_encode_numericentity($body, array(0x10000, 0xffffff, 0, 0xffffff), 'UTF-8'); } foreach ($config['markup'] as $markup) { if (is_string($markup[1])) { $body = preg_replace($markup[0], $markup[1], $body); } elseif (is_callable($markup[1])) { $body = preg_replace_callback($markup[0], $markup[1], $body); } } if ($config['markup_urls']) { $markup_urls = array(); $body = preg_replace_callback('/((?:https?:\\/\\/|ftp:\\/\\/|irc:\\/\\/)[^\\s<>()"]+?(?:\\([^\\s<>()"]*?\\)[^\\s<>()"]*?)*)((?:\\s|<|>|"|\\.||\\]|!|\\?|,|,|")*(?:[\\s<>()"]|$))/', 'markup_url', $body, -1, $num_links); if ($num_links > $config['max_links']) { error($config['error']['toomanylinks']); } if ($num_links < $config['min_links'] && $op) { error(sprintf($config['error']['notenoughlinks'], $config['min_links'])); } } if ($config['markup_repair_tidy']) { $body = str_replace(' ', ' ', $body); } if ($config['auto_unicode']) { $body = unicodify($body); if ($config['markup_urls']) { foreach ($markup_urls as &$url) { $body = str_replace(unicodify($url), $url, $body); } } } $tracked_cites = array(); // Cites if (isset($board) && preg_match_all('/(^|\\s)>>(\\d+?)([\\s,.)?]|$)/m', $body, $cites, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) { if (count($cites[0]) > $config['max_cites']) { error($config['error']['toomanycites']); } $skip_chars = 0; $body_tmp = $body; $search_cites = array(); foreach ($cites as $matches) { $search_cites[] = '`id` = ' . $matches[2][0]; } $search_cites = array_unique($search_cites); $query = query(sprintf('SELECT `thread`, `id` FROM ``posts_%s`` WHERE ' . implode(' OR ', $search_cites), $board['uri'])) or error(db_error()); $cited_posts = array(); while ($cited = $query->fetch(PDO::FETCH_ASSOC)) { $cited_posts[$cited['id']] = $cited['thread'] ? $cited['thread'] : false; } foreach ($cites as $matches) { $cite = $matches[2][0]; // preg_match_all is not multibyte-safe foreach ($matches as &$match) { $match[1] = mb_strlen(substr($body_tmp, 0, $match[1])); } if (isset($cited_posts[$cite])) { $replacement = '<a onclick="highlightReply(\'' . $cite . '\', event);" href="' . $config['root'] . $board['dir'] . $config['dir']['res'] . ($cited_posts[$cite] ? $cited_posts[$cite] : $cite) . '.html#' . $cite . '">' . '>>' . $cite . '</a>'; $body = mb_substr_replace($body, $matches[1][0] . $replacement . $matches[3][0], $matches[0][1] + $skip_chars, mb_strlen($matches[0][0])); $skip_chars += mb_strlen($matches[1][0] . $replacement . $matches[3][0]) - mb_strlen($matches[0][0]); if ($track_cites && $config['track_cites']) { $tracked_cites[] = array($board['uri'], $cite); } } } } // Cross-board linking if (preg_match_all('/(^|\\s)>>>\\/(' . $config['board_regex'] . 'f?)\\/(\\d+)?([\\s,.)?]|$)/um', $body, $cites, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) { if (count($cites[0]) > $config['max_cites']) { error($config['error']['toomanycross']); } $skip_chars = 0; $body_tmp = $body; if (isset($cited_posts)) { // Carry found posts from local board >>X links foreach ($cited_posts as $cite => $thread) { $cited_posts[$cite] = $config['root'] . $board['dir'] . $config['dir']['res'] . ($thread ? $thread : $cite) . '.html#' . $cite; } $cited_posts = array($board['uri'] => $cited_posts); } else { $cited_posts = array(); } $crossboard_indexes = array(); $search_cites_boards = array(); foreach ($cites as $matches) { $_board = $matches[2][0]; $cite = @$matches[3][0]; if (!isset($search_cites_boards[$_board])) { $search_cites_boards[$_board] = array(); } $search_cites_boards[$_board][] = $cite; } $tmp_board = $board['uri']; foreach ($search_cites_boards as $_board => $search_cites) { $clauses = array(); foreach ($search_cites as $cite) { if (!$cite || isset($cited_posts[$_board][$cite])) { continue; } $clauses[] = '`id` = ' . $cite; } $clauses = array_unique($clauses); if ($board['uri'] != $_board) { if (!openBoard($_board)) { continue; } // Unknown board } if (!empty($clauses)) { $cited_posts[$_board] = array(); $query = query(sprintf('SELECT `thread`, `id` FROM ``posts_%s`` WHERE ' . implode(' OR ', $clauses), $board['uri'])) or error(db_error()); while ($cite = $query->fetch(PDO::FETCH_ASSOC)) { $cited_posts[$_board][$cite['id']] = $config['root'] . $board['dir'] . $config['dir']['res'] . ($cite['thread'] ? $cite['thread'] : $cite['id']) . '.html#' . $cite['id']; } } $crossboard_indexes[$_board] = $config['root'] . $board['dir'] . $config['file_index']; } // Restore old board if (!$tmp_board) { unset($GLOBALS['board']); } elseif ($board['uri'] != $tmp_board) { openBoard($tmp_board); } foreach ($cites as $matches) { $_board = $matches[2][0]; $cite = @$matches[3][0]; // preg_match_all is not multibyte-safe foreach ($matches as &$match) { $match[1] = mb_strlen(substr($body_tmp, 0, $match[1])); } if ($cite) { if (isset($cited_posts[$_board][$cite])) { $link = $cited_posts[$_board][$cite]; $replacement = '<a ' . ($_board == $board['uri'] ? 'onclick="highlightReply(\'' . $cite . '\', event);" ' : '') . 'href="' . $link . '">' . '>>>/' . $_board . '/' . $cite . '</a>'; $body = mb_substr_replace($body, $matches[1][0] . $replacement . $matches[4][0], $matches[0][1] + $skip_chars, mb_strlen($matches[0][0])); $skip_chars += mb_strlen($matches[1][0] . $replacement . $matches[4][0]) - mb_strlen($matches[0][0]); if ($track_cites && $config['track_cites']) { $tracked_cites[] = array($_board, $cite); } } } elseif (isset($crossboard_indexes[$_board])) { $replacement = '<a href="' . $crossboard_indexes[$_board] . '">' . '>>>/' . $_board . '/' . '</a>'; $body = mb_substr_replace($body, $matches[1][0] . $replacement . $matches[4][0], $matches[0][1] + $skip_chars, mb_strlen($matches[0][0])); $skip_chars += mb_strlen($matches[1][0] . $replacement . $matches[4][0]) - mb_strlen($matches[0][0]); } } } $tracked_cites = array_unique($tracked_cites, SORT_REGULAR); if ($config['strip_superfluous_returns']) { $body = preg_replace('/\\s+$/', '', $body); } if ($config['markup_paragraphs']) { $paragraphs = explode("\n", $body); $bodyNew = ""; $tagsOpen = false; // Matches <a>, <a href="" title="">, but not <img/> and returns a $matchOpen = "#<([A-Z][A-Z0-9]*)+(?:(?:\\s+\\w+(?:\\s*=\\s*(?:\".*?\"|'.*?'|[^'\">\\s]+))?)+\\s*|\\s*)>#i"; // Matches </a> returns a $matchClose = "#</([A-Z][A-Z0-9]*/?)>#i"; $tagsOpened = array(); $tagsClosed = array(); foreach ($paragraphs as $paragraph) { // Determine if RTL based on content of line. if (strlen(trim($paragraph)) > 0) { $paragraphDirection = is_rtl($paragraph) ? "rtl" : "ltr"; } else { $paragraphDirection = "empty"; } // Add in a quote class for >quotes. if (strpos($paragraph, ">") === 0) { $quoteClass = "quote"; } else { $quoteClass = ""; } // If tags are closed, start a new line. if ($tagsOpen === false) { $bodyNew .= "<p class=\"body-line {$paragraphDirection} {$quoteClass}\">"; } // If tags are open, add the paragraph to our temporary holder instead. if ($tagsOpen !== false) { $tagsOpen .= $paragraph; // Recheck tags to see if we've formed a complete tag with this latest line. if (preg_match_all($matchOpen, $tagsOpen, $tagsOpened) === preg_match_all($matchClose, $tagsOpen, $tagsClosed)) { sort($tagsOpened[1]); sort($tagsClosed[1]); // Double-check to make sure these are the same tags. if (count(array_diff_assoc($tagsOpened[1], $tagsClosed[1])) === 0) { // Tags are closed! \o/ $bodyNew .= $tagsOpen; $tagsOpen = false; } } } else { if (preg_match_all($matchOpen, $paragraph, $tagsOpened) === preg_match_all($matchClose, $paragraph, $tagsClosed)) { sort($tagsOpened[1]); sort($tagsClosed[1]); // Double-check to make sure these are the same tags. if (count(array_diff_assoc($tagsOpened[1], $tagsClosed[1])) === 0) { $bodyNew .= $paragraph; } } else { // Tags are open! $tagsOpen = $paragraph; } } // If tags are open, do not close it. if (!$tagsOpen) { $bodyNew .= "</p>"; } else { if ($tagsOpen !== false) { $tagsOpen .= "<br />"; } } } if ($tagsOpen !== false) { $bodyNew .= $tagsOpen; } $body = $bodyNew; } else { $body = preg_replace("/^\\s*>.*\$/m", '<span class="quote">$0</span>', $body); $body = preg_replace("/\n/", '<br/>', $body); } if ($config['markup_repair_tidy']) { $tidy = new tidy(); $body = str_replace("\t", '	', $body); $body = $tidy->repairString($body, array('doctype' => 'omit', 'bare' => true, 'literal-attributes' => true, 'indent' => false, 'show-body-only' => true, 'wrap' => 0, 'output-bom' => false, 'output-html' => true, 'newline' => 'LF', 'quiet' => true), 'utf8'); $body = str_replace("\n", '', $body); } // replace tabs with 8 spaces $body = str_replace("\t", '	', $body); return $tracked_cites; }
removeBan($_POST['ban_id']); header('Location: ?/IP/' . $ip, true, $config['redirect_http']); } elseif (hasPermission($config['mod']['create_notes']) && isset($_POST['note'])) { $query = prepare("INSERT INTO `ip_notes` VALUES(NULL, :ip, :mod, :time, :body)"); $query->bindValue(':ip', $ip); $query->bindValue(':mod', $mod['id'], PDO::PARAM_INT); $query->bindValue(':time', time(), PDO::PARAM_INT); markup($_POST['note']); $query->bindValue(':body', $_POST['note']); $query->execute() or error(db_error($query)); header('Location: ?/IP/' . $ip, true, $config['redirect_http']); } else { $body = ''; $boards = listBoards(); foreach ($boards as &$_board) { openBoard($_board['uri']); $temp = ''; $query = prepare(sprintf("SELECT * FROM `posts_%s` WHERE `ip` = :ip ORDER BY `sticky` DESC, `time` 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()) { if (!$post['thread']) { $po = new Thread($post['id'], $post['subject'], $post['email'], $post['name'], $post['trip'], $post['capcode'], $post['body'], $post['time'], $post['thumb'], $post['thumbwidth'], $post['thumbheight'], $post['file'], $post['filewidth'], $post['fileheight'], $post['filesize'], $post['filename'], $post['ip'], $post['sticky'], $post['locked'], $post['sage'], $post['embed'], '?/', $mod, false); } else { $po = new Post($post['id'], $post['thread'], $post['subject'], $post['email'], $post['name'], $post['trip'], $post['capcode'], $post['body'], $post['time'], $post['thumb'], $post['thumbwidth'], $post['thumbheight'], $post['file'], $post['filewidth'], $post['fileheight'], $post['filesize'], $post['filename'], $post['ip'], $post['embed'], '?/', $mod); } $temp .= $po->build(true) . '<hr/>'; } if (!empty($temp)) { $body .= '<fieldset><legend>Last ' . $query->rowCount() . ' posts on <a href="?/' . sprintf($config['board_path'], $_board['uri']) . $config['file_index'] . '">' . sprintf($config['board_abbreviation'], $_board['uri']) . ' - ' . $_board['title'] . '</a></legend>' . $temp . '</fieldset>';
public function homepage($settings) { global $config, $board; $recent_images = array(); $recent_posts = array(); $stats = array(); $boards = listBoards(); $query = ''; foreach ($boards as &$_board) { if (in_array($_board['uri'], $this->excluded)) { continue; } $query .= sprintf("SELECT *, '%s' AS `board` FROM `posts_%s` WHERE `file` IS NOT NULL AND `file` != 'deleted' AND `thumb` != 'spoiler' UNION ALL ", $_board['uri'], $_board['uri']); } $query = preg_replace('/UNION ALL $/', 'ORDER BY `time` DESC LIMIT ' . (int) $settings['limit_images'], $query); $query = query($query) or error(db_error()); while ($post = $query->fetch()) { openBoard($post['board']); // board settings won't be available in the template file, so generate links now $post['link'] = $config['root'] . $board['dir'] . $config['dir']['res'] . sprintf($config['file_page'], $post['thread'] ? $post['thread'] : $post['id']) . '#' . $post['id']; $post['src'] = $config['uri_thumb'] . $post['thumb']; $recent_images[] = $post; } $query = ''; foreach ($boards as &$_board) { if (in_array($_board['uri'], $this->excluded)) { continue; } $query .= sprintf("SELECT *, '%s' AS `board` FROM `posts_%s` UNION ALL ", $_board['uri'], $_board['uri']); } $query = preg_replace('/UNION ALL $/', 'ORDER BY `time` DESC LIMIT ' . (int) $settings['limit_posts'], $query); $query = query($query) or error(db_error()); while ($post = $query->fetch()) { openBoard($post['board']); $post['link'] = $config['root'] . $board['dir'] . $config['dir']['res'] . sprintf($config['file_page'], $post['thread'] ? $post['thread'] : $post['id']) . '#' . $post['id']; $post['snippet'] = pm_snippet($post['body'], 30); $post['board_name'] = $board['name']; $recent_posts[] = $post; } // Total posts $query = 'SELECT SUM(`top`) AS `count` FROM ('; foreach ($boards as &$_board) { if (in_array($_board['uri'], $this->excluded)) { continue; } $query .= sprintf("SELECT MAX(`id`) AS `top` FROM `posts_%s` UNION ALL ", $_board['uri']); } $query = preg_replace('/UNION ALL $/', ') AS `posts_all`', $query); $query = query($query) or error(db_error()); $res = $query->fetch(); $stats['total_posts'] = number_format($res['count']); // Unique IPs $query = 'SELECT COUNT(DISTINCT(`ip`)) AS `count` FROM ('; foreach ($boards as &$_board) { if (in_array($_board['uri'], $this->excluded)) { continue; } $query .= sprintf("SELECT `ip` FROM `posts_%s` UNION ALL ", $_board['uri']); } $query = preg_replace('/UNION ALL $/', ') AS `posts_all`', $query); $query = query($query) or error(db_error()); $res = $query->fetch(); $stats['unique_posters'] = number_format($res['count']); // Active content $query = 'SELECT SUM(`filesize`) AS `count` FROM ('; foreach ($boards as &$_board) { if (in_array($_board['uri'], $this->excluded)) { continue; } $query .= sprintf("SELECT `filesize` FROM `posts_%s` UNION ALL ", $_board['uri']); } $query = preg_replace('/UNION ALL $/', ') AS `posts_all`', $query); $query = query($query) or error(db_error()); $res = $query->fetch(); $stats['active_content'] = $res['count']; return Element('themes/recent/recent.html', array('settings' => $settings, 'config' => $config, 'boardlist' => createBoardlist(), 'recent_images' => $recent_images, 'recent_posts' => $recent_posts, 'stats' => $stats)); }
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()) { $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['id'], $post['subject'], $post['email'], $post['name'], $post['trip'], $post['capcode'], $post['body'], $post['time'], $post['thumb'], $post['thumbwidth'], $post['thumbheight'], $post['file'], $post['filewidth'], $post['fileheight'], $post['filesize'], $post['filename'], $post['ip'], $post['sticky'], $post['locked'], $post['sage'], $post['embed'], '?/', $mod, false); } else { $po = new Post($post['id'], $post['thread'], $post['subject'], $post['email'], $post['name'], $post['trip'], $post['capcode'], $post['body'], $post['time'], $post['thumb'], $post['thumbwidth'], $post['thumbheight'], $post['file'], $post['filewidth'], $post['fileheight'], $post['filesize'], $post['filename'], $post['ip'], $post['embed'], '?/', $mod); } // a little messy and inefficient $append_html = Element('mod/report.html', array('report' => $report, 'config' => $config, 'mod' => $mod)); // Bug fix for https://github.com/savetheinternet/Tinyboard/issues/21 $po->body = truncate($po->body, $po->link(), $config['body_truncate'] - substr_count($append_html, '<br>')); 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) . '<hr>'; 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)); }
public function build($mod = false) { global $config; $boards = listBoards(); $body = ''; $overflow = array(); $board = array('url' => $this->settings['uri'], 'name' => $this->settings['title'], 'title' => sprintf($this->settings['subtitle'], $this->settings['thread_limit'])); $query = ''; foreach ($boards as &$_board) { if (in_array($_board['uri'], explode(' ', $this->settings['exclude']))) { continue; } $query .= sprintf("SELECT *, '%s' AS `board` FROM ``posts_%s`` WHERE `thread` IS NULL UNION ALL ", $_board['uri'], $_board['uri']); } $query = preg_replace('/UNION ALL $/', 'ORDER BY `bump` DESC', $query); $query = query($query) or error(db_error()); $count = 0; $threads = array(); while ($post = $query->fetch()) { if (!isset($threads[$post['board']])) { $threads[$post['board']] = 1; } else { $threads[$post['board']] += 1; } if ($count < $this->settings['thread_limit']) { openBoard($post['board']); $thread = new Thread($post, $mod ? '?/' : $config['root'], $mod); $posts = prepare(sprintf("SELECT * FROM ``posts_%s`` WHERE `thread` = :id ORDER BY `id` DESC LIMIT :limit", $post['board'])); $posts->bindValue(':id', $post['id']); $posts->bindValue(':limit', $post['sticky'] ? $config['threads_preview_sticky'] : $config['threads_preview'], PDO::PARAM_INT); $posts->execute() or error(db_error($posts)); $num_images = 0; while ($po = $posts->fetch()) { if ($po['files']) { $num_images++; } $thread->add(new Post($po, $mod ? '?/' : $config['root'], $mod)); } if ($posts->rowCount() == ($post['sticky'] ? $config['threads_preview_sticky'] : $config['threads_preview'])) { $ct = prepare(sprintf("SELECT COUNT(`id`) as `num` FROM ``posts_%s`` WHERE `thread` = :thread UNION ALL SELECT COUNT(`id`) FROM ``posts_%s`` WHERE `files` IS NOT NULL AND `thread` = :thread", $post['board'], $post['board'])); $ct->bindValue(':thread', $post['id'], PDO::PARAM_INT); $ct->execute() or error(db_error($count)); $c = $ct->fetch(); $thread->omitted = $c['num'] - ($post['sticky'] ? $config['threads_preview_sticky'] : $config['threads_preview']); $c = $ct->fetch(); $thread->omitted_images = $c['num'] - $num_images; } $thread->posts = array_reverse($thread->posts); $body .= '<h2><a href="' . $config['root'] . $post['board'] . '">/' . $post['board'] . '/</a></h2>'; $body .= $thread->build(true); } else { $page = 'index'; if (floor($threads[$post['board']] / $config['threads_per_page']) > 0) { $page = floor($threads[$post['board']] / $config['threads_per_page']) + 1; } $overflow[] = array('id' => $post['id'], 'board' => $post['board'], 'page' => $page . '.html'); } $count += 1; } $body .= '<script> var overflow = ' . json_encode($overflow) . '</script>'; $body .= '<script type="text/javascript" src="/' . $this->settings['uri'] . '/ukko.js"></script>'; return Element('index.html', array('config' => $config, 'board' => $board, 'no_post_form' => true, 'body' => $body, 'mod' => $mod, 'boardlist' => createBoardlist($mod))); }
public static function delete($ban_id, $modlog = false, $boards = false, $dont_rebuild = false) { global $config; if ($boards && $boards[0] == '*') { $boards = false; } if ($modlog) { $query = query("SELECT `ipstart`, `ipend`, `board` FROM ``bans`` WHERE `id` = " . (int) $ban_id) or error(db_error()); if (!($ban = $query->fetch(PDO::FETCH_ASSOC))) { // Ban doesn't exist return false; } if ($boards !== false && !in_array($ban['board'], $boards)) { error($config['error']['noaccess']); } if ($ban['board']) { openBoard($ban['board']); } $mask = self::range_to_string(array($ban['ipstart'], $ban['ipend'])); modLog("Removed ban #{$ban_id} for " . (filter_var($mask, FILTER_VALIDATE_IP) !== false ? "<a href=\"?/IP/{$mask}\">{$mask}</a>" : $mask)); } query("DELETE FROM ``bans`` WHERE `id` = " . (int) $ban_id) or error(db_error()); if (!$dont_rebuild || !$config['cron_bans']) { rebuildThemes('bans'); } return true; }
/** * Build the HTML of a single thread in the catalog */ private function buildOne($post, $mod = false) { global $config; openBoard($post['board']); $thread = new Thread($post, $mod ? '?/' : $config['root'], $mod); $replies = $this->fetchReplies($post['board'], $post['id']); // Number of replies to a thread that are displayed beneath it $preview_count = $post['sticky'] ? $config['threads_preview_sticky'] : $config['threads_preview']; // Chomp the last few replies $disp_replies = array_splice($replies, 0, $preview_count); $disp_img_count = 0; foreach ($disp_replies as $reply) { if ($reply['files'] !== '') { ++$disp_img_count; } // Append the reply to the thread as it's being built $thread->add(new Post($reply, $mod ? '?/' : $config['root'], $mod)); } // Count the number of omitted image replies $omitted_img_count = count(array_filter($replies, function ($p) { return $p['files'] !== ''; })); // Set the corresponding omitted numbers on the thread if (!empty($replies)) { $thread->omitted = count($replies); $thread->omitted_images = $omitted_img_count; } // Board name and link $html = '<h2><a href="' . $config['root'] . $post['board'] . '/">/' . $post['board'] . '/</a></h2>'; // The thread itself $html .= $thread->build(true); return $html; }
function markup(&$body, $track_cites = false) { global $board, $config, $markup_urls; $body = str_replace("\r", '', $body); $body = utf8tohtml($body); foreach ($config['markup'] as $markup) { if (is_string($markup[1])) { $body = preg_replace($markup[0], $markup[1], $body); } elseif (is_callable($markup[1])) { $body = preg_replace_callback($markup[0], $markup[1], $body); } } if ($config['markup_urls']) { $markup_urls = array(); $body = preg_replace_callback('/((?:https?:\\/\\/|ftp:\\/\\/|irc:\\/\\/)[^\\s<>()"]+?(?:\\([^\\s<>()"]*?\\)[^\\s<>()"]*?)*)((?:\\s|<|>|"|\\.||\\]|!|\\?|,|,|")*(?:[\\s<>()"]|$))/', 'markup_url', $body, -1, $num_links); if ($num_links > $config['max_links']) { error($config['error']['toomanylinks']); } } if ($config['auto_unicode']) { $body = unicodify($body); if ($config['markup_urls']) { foreach ($markup_urls as &$url) { $body = str_replace(unicodify($url), $url, $body); } } } // replace tabs with 8 spaces $body = str_replace("\t", ' ', $body); $tracked_cites = array(); // Cites if (isset($board) && preg_match_all('/(^|\\s)>>(\\d+?)([\\s,.)?]|$)/m', $body, $cites)) { if (count($cites[0]) > $config['max_cites']) { error($config['error']['toomanycites']); } for ($index = 0; $index < count($cites[0]); $index++) { $cite = $cites[2][$index]; $query = prepare(sprintf("SELECT `thread`,`id` FROM `posts_%s` WHERE `id` = :id LIMIT 1", $board['uri'])); $query->bindValue(':id', $cite); $query->execute() or error(db_error($query)); if ($post = $query->fetch()) { $replacement = '<a onclick="highlightReply(\'' . $cite . '\');" href="' . $config['root'] . $board['dir'] . $config['dir']['res'] . ($post['thread'] ? $post['thread'] : $post['id']) . '.html#' . $cite . '">' . '>>' . $cite . '</a>'; $body = str_replace($cites[0][$index], $cites[1][$index] . $replacement . $cites[3][$index], $body); if ($track_cites && $config['track_cites']) { $tracked_cites[] = array($board['uri'], $post['id']); } } } } // Cross-board linking if (preg_match_all('/(^|\\s)>>>\\/(\\w+?)\\/(\\d+)?([\\s,.)?]|$)/m', $body, $cites)) { if (count($cites[0]) > $config['max_cites']) { error($config['error']['toomanycross']); } for ($index = 0; $index < count($cites[0]); $index++) { $_board = $cites[2][$index]; $cite = @$cites[3][$index]; // Temporarily store board information because it will be overwritten $tmp_board = $board['uri']; // Check if the board exists, and load settings if (openBoard($_board)) { if ($cite) { $query = prepare(sprintf("SELECT `thread`,`id` FROM `posts_%s` WHERE `id` = :id LIMIT 1", $board['uri'])); $query->bindValue(':id', $cite); $query->execute() or error(db_error($query)); if ($post = $query->fetch()) { $replacement = '<a onclick="highlightReply(\'' . $cite . '\');" href="' . $config['root'] . $board['dir'] . $config['dir']['res'] . ($post['thread'] ? $post['thread'] : $post['id']) . '.html#' . $cite . '">' . '>>>/' . $_board . '/' . $cite . '</a>'; $body = str_replace($cites[0][$index], $cites[1][$index] . $replacement . $cites[4][$index], $body); if ($track_cites && $config['track_cites']) { $tracked_cites[] = array($board['uri'], $post['id']); } } } else { $replacement = '<a href="' . $config['root'] . $board['dir'] . $config['file_index'] . '">' . '>>>/' . $_board . '/' . '</a>'; $body = str_replace($cites[0][$index], $cites[1][$index] . $replacement . $cites[4][$index], $body); } } // Restore main board settings openBoard($tmp_board); } } $body = preg_replace("/^\\s*>.*\$/m", '<span class="quote">$0</span>', $body); if ($config['strip_superfluous_returns']) { $body = preg_replace('/\\s+$/', '', $body); } $body = preg_replace("/\n/", '<br/>', $body); return $tracked_cites; }
private function generateRecentPosts($threads) { global $config, $board; $posts = array(); foreach ($threads as $post) { if ($board['uri'] !== $post['board']) { openBoard($post['board']); } $post['link'] = $config['root'] . $board['dir'] . $config['dir']['res'] . link_for($post); $post['board_name'] = $board['name']; if ($post['embed'] && preg_match('/^https?:\\/\\/(\\w+\\.)?(?:youtube\\.com\\/watch\\?v=|youtu\\.be\\/)([a-zA-Z0-9\\-_]{10,11})(&.+)?$/i', $post['embed'], $matches)) { $post['youtube'] = $matches[2]; } if (isset($post['files']) && $post['files']) { $files = json_decode($post['files']); if ($files[0]) { if ($files[0]->file == 'deleted') { if (count($files) > 1) { foreach ($files as $file) { if ($file == $files[0] || $file->file == 'deleted') { continue; } $post['file'] = $config['uri_thumb'] . $file->thumb; } if (empty($post['file'])) { $post['file'] = $config['image_deleted']; } } else { $post['file'] = $config['image_deleted']; } } else { if ($files[0]->thumb == 'spoiler') { $post['file'] = '/' . $config['spoiler_image']; } else { $post['file'] = $config['uri_thumb'] . $files[0]->thumb; } } } } if (empty($post['image_count'])) { $post['image_count'] = 0; } $posts[] = $post; } return $posts; }
function mod_pages($board = false) { global $config, $mod, $pdo; if (empty($board)) { $board = false; } if (!$board && $mod['boards'][0] !== '*') { 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) { $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 (!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('/^(index|catalog|index\\+50)|(\\d+)$/', $_POST['page'])) { error(_('Nope.')); } 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; $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); } 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)); }
public function homepage($settings) { global $config, $board; $recent_images = array(); $recent_posts = array(); $stats = array(); $boards = listBoards(); $query = ''; foreach ($boards as &$_board) { if (in_array($_board['uri'], $this->excluded)) { continue; } $query .= sprintf("SELECT *, '%s' AS `board` FROM ``posts_%s`` WHERE `files` IS NOT NULL UNION ALL ", $_board['uri'], $_board['uri']); } $query = ''; foreach ($boards as &$_board) { if (in_array($_board['uri'], $this->excluded)) { continue; } $query .= sprintf("SELECT *, '%s' AS `board` FROM ``posts_%s`` UNION ALL ", $_board['uri'], $_board['uri']); } $query = preg_replace('/UNION ALL $/', 'ORDER BY `time` DESC LIMIT ' . (int) $settings['limit_posts'], $query); $query = query($query) or error(db_error()); while ($post = $query->fetch(PDO::FETCH_ASSOC)) { openBoard($post['board']); $post['link'] = $config['root'] . $board['dir'] . $config['dir']['res'] . link_for($post) . '#' . $post['id']; if ($post['body'] != "") { $post['snippet'] = pm_snippet($post['body'], 128); } else { $post['snippet'] = "<em>" . _("(no comment)") . "</em>"; } $post['board_name'] = $board['name']; $recent_posts[] = $post; } // Total posts $query = 'SELECT SUM(`top`) FROM ('; foreach ($boards as &$_board) { if (in_array($_board['uri'], $this->excluded)) { continue; } $query .= sprintf("SELECT MAX(`id`) AS `top` FROM ``posts_%s`` UNION ALL ", $_board['uri']); } $query = preg_replace('/UNION ALL $/', ') AS `posts_all`', $query); $query = query($query) or error(db_error()); $stats['total_posts'] = number_format($query->fetchColumn()); // Unique IPs $query = 'SELECT COUNT(DISTINCT(`ip`)) FROM ('; foreach ($boards as &$_board) { if (in_array($_board['uri'], $this->excluded)) { continue; } $query .= sprintf("SELECT `ip` FROM ``posts_%s`` UNION ALL ", $_board['uri']); } $query = preg_replace('/UNION ALL $/', ') AS `posts_all`', $query); $query = query($query) or error(db_error()); $stats['unique_posters'] = number_format($query->fetchColumn()); // Active content $query = 'SELECT DISTINCT(`files`) FROM ('; foreach ($boards as &$_board) { if (in_array($_board['uri'], $this->excluded)) { continue; } $query .= sprintf("SELECT `files` FROM ``posts_%s`` UNION ALL ", $_board['uri']); } $query = preg_replace('/UNION ALL $/', ' WHERE `num_files` > 0) AS `posts_all`', $query); $query = query($query) or error(db_error()); $files = $query->fetchAll(); $stats['active_content'] = 0; foreach ($files as &$file) { preg_match_all('/"size":([0-9]*)/', $file[0], $matches); $stats['active_content'] += array_sum($matches[1]); } return Element('themes/recent_textonly/recent_textonly.html', array('settings' => $settings, 'config' => $config, 'boardlist' => createBoardlist(), 'recent_posts' => $recent_posts, 'stats' => $stats)); }
public function homepage($settings) { global $config, $board; $recent_images = array(); $recent_posts = array(); $stats = array(); $boards = listBoards(); $query = ''; foreach ($boards as &$_board) { if (in_array($_board['uri'], $this->excluded)) { continue; } $query .= sprintf("SELECT *, '%s' AS `board` FROM ``posts_%s`` WHERE `files` IS NOT NULL UNION ALL ", $_board['uri'], $_board['uri']); } $query = preg_replace('/UNION ALL $/', 'ORDER BY `time` DESC LIMIT ' . (int) $settings['limit_images'], $query); if ($query == '') { error(_("Can't build the RecentPosts theme, because there are no boards to be fetched.")); } $query = query($query) or error(db_error()); while ($post = $query->fetch(PDO::FETCH_ASSOC)) { openBoard($post['board']); if (isset($post['files'])) { $files = json_decode($post['files']); } if ($files[0]->file == 'deleted') { continue; } // board settings won't be available in the template file, so generate links now $post['link'] = $config['root'] . $board['dir'] . $config['dir']['res'] . link_for($post) . '#' . $post['id']; if ($files) { if ($files[0]->thumb == 'spoiler') { $tn_size = @getimagesize($config['spoiler_image']); $post['src'] = $config['spoiler_image']; $post['thumbwidth'] = $tn_size[0]; $post['thumbheight'] = $tn_size[1]; } else { $post['src'] = $config['uri_thumb'] . $files[0]->thumb; } } $recent_images[] = $post; } $query = ''; foreach ($boards as &$_board) { if (in_array($_board['uri'], $this->excluded)) { continue; } $query .= sprintf("SELECT *, '%s' AS `board` FROM ``posts_%s`` UNION ALL ", $_board['uri'], $_board['uri']); } $query = preg_replace('/UNION ALL $/', 'ORDER BY `time` DESC LIMIT ' . (int) $settings['limit_posts'], $query); $query = query($query) or error(db_error()); while ($post = $query->fetch(PDO::FETCH_ASSOC)) { openBoard($post['board']); $post['link'] = $config['root'] . $board['dir'] . $config['dir']['res'] . link_for($post) . '#' . $post['id']; if ($post['body'] != "") { $post['snippet'] = pm_snippet($post['body'], 30); } else { $post['snippet'] = "<em>" . _("(no comment)") . "</em>"; } $post['board_name'] = $board['name']; $recent_posts[] = $post; } // Total posts $query = 'SELECT SUM(`top`) FROM ('; foreach ($boards as &$_board) { if (in_array($_board['uri'], $this->excluded)) { continue; } $query .= sprintf("SELECT MAX(`id`) AS `top` FROM ``posts_%s`` UNION ALL ", $_board['uri']); } $query = preg_replace('/UNION ALL $/', ') AS `posts_all`', $query); $query = query($query) or error(db_error()); $stats['total_posts'] = number_format($query->fetchColumn()); // Unique IPs $query = 'SELECT COUNT(DISTINCT(`ip`)) FROM ('; foreach ($boards as &$_board) { if (in_array($_board['uri'], $this->excluded)) { continue; } $query .= sprintf("SELECT `ip` FROM ``posts_%s`` UNION ALL ", $_board['uri']); } $query = preg_replace('/UNION ALL $/', ') AS `posts_all`', $query); $query = query($query) or error(db_error()); $stats['unique_posters'] = number_format($query->fetchColumn()); // Active content $query = 'SELECT DISTINCT(`files`) FROM ('; foreach ($boards as &$_board) { if (in_array($_board['uri'], $this->excluded)) { continue; } $query .= sprintf("SELECT `files` FROM ``posts_%s`` UNION ALL ", $_board['uri']); } $query = preg_replace('/UNION ALL $/', ' WHERE `num_files` > 0) AS `posts_all`', $query); $query = query($query) or error(db_error()); $files = $query->fetchAll(); $stats['active_content'] = 0; foreach ($files as &$file) { preg_match_all('/"size":([0-9]*)/', $file[0], $matches); $stats['active_content'] += array_sum($matches[1]); } return Element('themes/recent/recent.html', array('settings' => $settings, 'config' => $config, 'boardlist' => createBoardlist(), 'recent_images' => $recent_images, 'recent_posts' => $recent_posts, 'stats' => $stats)); }
$query->bindValue(':time', time() - $queries_per_minutes_all[1] * 60); $query->execute() or error(db_error($query)); if ($query->fetchColumn() > $queries_per_minutes_all[0]) { error(_('Wait a while before searching again, please.')); } $query = prepare("INSERT INTO ``search_queries`` VALUES (:ip, :time, :query)"); $query->bindValue(':ip', $_SERVER['REMOTE_ADDR']); $query->bindValue(':time', time()); $query->bindValue(':query', $phrase); $query->execute() or error(db_error($query)); _syslog(LOG_NOTICE, 'Searched /' . $_GET['board'] . '/ for "' . $phrase . '"'); // Cleanup search queries table $query = prepare("DELETE FROM ``search_queries`` WHERE `time` <= :time"); $query->bindValue(':time', time() - $queries_per_minutes_all[1] * 60); $query->execute() or error(db_error($query)); openBoard($_GET['board']); $filters = array(); function search_filters($m) { global $filters; $name = $m[2]; $value = isset($m[4]) ? $m[4] : $m[3]; if (!in_array($name, array('id', 'thread', 'subject', 'name'))) { // unknown filter return $m[0]; } $filters[$name] = $value; return $m[1]; } $phrase = trim(preg_replace_callback('/(^|\\s)(\\w+):("(.*)?"|[^\\s]*)/', 'search_filters', $phrase)); if (!preg_match('/[^*^\\s]/', $phrase) && empty($filters)) {
<?php include 'inc/functions.php'; $global = isset($_GET['global']); $post = isset($_GET['post']) ? $_GET['post'] : false; $board = isset($_GET['board']) ? $_GET['board'] : false; if (!$post || !preg_match('/^delete_\\d+$/', $post) || !$board || !openBoard($board)) { header('HTTP/1.1 400 Bad Request'); error(_('Bad request.')); } if ($config['report_captcha']) { $captcha = generate_captcha($config['captcha']['extra']); } else { $captcha = null; } $body = Element('report.html', ['global' => $global, 'post' => $post, 'board' => $board, 'captcha' => $captcha, 'config' => $config]); echo Element('page.html', ['config' => $config, 'body' => $body]);
$query = prepare('INSERT INTO ``mods`` VALUES (NULL, :username, :password, :salt, :type, :boards, :email)'); $query->bindValue(':username', $username); $query->bindValue(':password', $password); $query->bindValue(':salt', $salt); $query->bindValue(':type', 20); $query->bindValue(':boards', $uri); $query->bindValue(':email', $email); $query->execute() or error(db_error($query)); $query = prepare('INSERT INTO ``boards`` (`uri`, `title`, `subtitle`) 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)); $query = Element('posts.sql', array('board' => $uri)); query($query) or error(db_error()); if (!openBoard($_POST['uri'])) { error(_("Couldn't open board after creation.")); } if ($config['cache']['enabled']) { cache::delete('all_boards'); } // Build the board buildIndex(); rebuildThemes('boards'); $query = prepare("INSERT INTO ``board_create``(uri) VALUES(:uri)"); $query->bindValue(':uri', $uri); $query->execute() or error(db_error()); _syslog(LOG_NOTICE, "New board: {$uri}"); $body = Element("8chan/create_success.html", array("config" => $config, "password" => $_POST['password'], "uri" => $uri)); echo Element("page.html", array("config" => $config, "body" => $body, "title" => _("Success"), "subtitle" => _("This was a triumph"))); }
$query = prepare('DELETE FROM ``reports`` WHERE `board` = :id'); $query->bindValue(':id', $board['uri'], PDO::PARAM_INT); $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_INT); $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)) {