Example #1
0
 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'])));
 }
Example #2
0
 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'])));
 }
Example #3
0
 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 .= '&lt;empty&gt;';
         } 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>') . ' &mdash; 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;
 }
Example #4
0
 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'])));
 }
Example #5
0
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']);
        }
    }
}
Example #6
0
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|<|>|"|\\.||\\]|!|\\?|,|&#44;|&quot;)*(?:[\\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('  ', ' &nbsp;', $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)&gt;&gt;(\\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 . '">' . '&gt;&gt;' . $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)&gt;&gt;&gt;\\/(' . $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 . '">' . '&gt;&gt;&gt;/' . $_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] . '">' . '&gt;&gt;&gt;/' . $_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*&gt;.*\$/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("&#10;", "&#9;"), htmlspecialchars($code)) . "</pre>";
            $body = str_replace("<code {$id}>", $code, $body);
        }
    }
    if ($config['markup_repair_tidy']) {
        $tidy = new tidy();
        $body = str_replace("\t", '&#09;', $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;
}
Example #7
0
    $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'])) {
Example #8
0
function sb_catalog($b)
{
    if (!openBoard($b)) {
        return false;
    }
    rebuildTheme("catalog", "post-thread", $b);
    return true;
}
Example #9
0
<?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);
Example #10
0
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", '&#010;', 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", '&#010;', $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 : ''))));
}
Example #11
0
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)&gt;&gt;(\\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 . '">' . '&gt;&gt;' . $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)&gt;&gt;&gt;\\/(\\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 . '">' . '&gt;&gt;&gt;/' . $_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'] . '">' . '&gt;&gt;&gt;/' . $_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]+)?(&gt;)([^\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;
}
Example #12
0
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']));
}
Example #13
0
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;
    }
Example #14
0
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|<|>|"|\\.||\\]|!|\\?|,|&#44;|&quot;)*(?:[\\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('  ', ' &nbsp;', $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)&gt;&gt;(\\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 . '">' . '&gt;&gt;' . $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)&gt;&gt;&gt;\\/(' . $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 . '">' . '&gt;&gt;&gt;/' . $_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] . '">' . '&gt;&gt;&gt;/' . $_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, "&gt;") === 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*&gt;.*\$/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", '&#09;', $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", '&#09;', $body);
    return $tracked_cites;
}
Example #15
0
     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>';
Example #16
0
 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));
 }
Example #17
0
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));
}
Example #18
0
 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)));
 }
Example #19
0
 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;
 }
Example #20
0
 /**
  * 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;
 }
Example #21
0
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|<|>|"|\\.||\\]|!|\\?|,|&#44;|&quot;)*(?:[\\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)&gt;&gt;(\\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 . '">' . '&gt;&gt;' . $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)&gt;&gt;&gt;\\/(\\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 . '">' . '&gt;&gt;&gt;/' . $_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'] . '">' . '&gt;&gt;&gt;/' . $_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*&gt;.*\$/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;
}
Example #22
0
 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;
 }
Example #23
0
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));
}
Example #24
0
 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));
 }
Example #25
0
 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));
 }
Example #26
0
 $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)) {
Example #27
0
<?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]);
Example #28
0
    $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")));
}
Example #29
0
 $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)) {