Example #1
0
 public function __construct()
 {
     parent::__construct("Report Queue", el('h2', "Reports"), Config::getCfg('permissions')['delete']);
     $reports = Model::get()->getReports();
     $html = "<table class='reportTable'><tr><th colspan='3'>Report Queue</th></tr><tr><th style='width:3em;'>Times</th><th>Post</th><th style='width:20em;'>Options</th></tr>";
     foreach ($reports as $report) {
         $hash = bin2hex($report['md5']);
         $html .= "<tr id='report{$report['no']}'>";
         $html .= "<td>" . $report['count'] . "</td>";
         $html .= "<td><a href='{$report['threadid']}#p{$report['no']}' data-board='{$report['board']}' data-thread='{$report['threadid']}' data-post='{$report['no']}' class='quotelink noEmbed'>&gt;&gt;{$report['no']}</a></td>";
         $html .= "<td><a class='button' href='javascript:deletePost({$report['no']},\"{$report['board']}\");' >Delete&nbsp;Post</a>&nbsp;";
         $html .= "<a class='button' href='javascript:banImage(\"{$hash}\");' id='ban{$hash}'>Ban&nbsp;Image</a>&nbsp;";
         $html .= "<a class='button' href='javascript:deleteReport({$report['no']},\"{$report['board']}\");'>Delete&nbsp;Report</a>&nbsp;";
         $html .= "<a class='button' href='javascript:banReporter({$report['no']},\"{$report['board']}\");'>Ban&nbsp;Reporter</a></td>";
         $html .= "</tr>";
     }
     $html .= "</table>";
     if (Site::getUser()->getPrivilege() >= Config::getCfg('permissions')['owner']) {
         $html .= "<br><table class='reportTable'><tr><th colspan='3'>Last Few Deleted Posts</th></tr><tr><th style='width:3em;'>Board</th><th>Post</th><th style='width:7em;'>Options</th></tr>";
         foreach (Model::get()->getBoards() as $board) {
             $lastFew = OldModel::getLastNDeletedPosts($board->getName(), 5);
             foreach ($lastFew as $report) {
                 $html .= "<tr id='report{$report['no']}'>";
                 $html .= "<td>" . $board->getName() . "</td>";
                 $html .= "<td>&gt;&gt;{$report['no']} ({$report['name']}{$report['trip']})</td>";
                 $html .= "<td><a class='button' href='javascript:restorePost({$report['no']},\"{$board->getName()}\");' >Restore&nbsp;Post</a></td>";
                 $html .= "</tr>";
             }
         }
         $html .= "</table>";
     }
     $this->appendToBody($html);
 }
Example #2
0
 function __construct()
 {
     parent::__construct(Config::getCfg('site')['pagetitle'], "", 0);
     $boards = Model::get()->getBoards();
     $archiveBoards = array_filter($boards, function ($b) {
         return $b->isArchive();
     });
     $plainBoards = array_filter($boards, function ($b) {
         return !$b->isArchive();
     });
     $html = "<div class='boardlist_big'><h1>Archived Boards</h1><hr style='width:64px;'>";
     foreach ($archiveBoards as $b) {
         $html .= Site::parseHtmlFragment("indexArchiveBoard.html", ["%ago%", "%crawltime%", "%shortname%", "%longname%", "%posts%", "%threads%", "%firstcrawl%"], [ago(time() - $b->getLastCrawl()), $b->getLastCrawl(), $b->getName(), $b->getLongName(), $b->getNoPosts(), $b->getNoThreads(), date("j F Y", $b->getFirstCrawl())]);
     }
     $html .= "</div>";
     $html .= "<script type='text/javascript' src='/script/boardUpdate.js'></script>";
     if (count($plainBoards) > 0) {
         $html .= "<div class='boardlist_big'><h1>Boards</h1><hr style='width:64px;'>";
         foreach ($plainBoards as $b) {
             $html .= Site::parseHtmlFragment("indexBoard.html", ["%ago%", "%crawltime%", "%shortname%", "%longname%", "%posts%", "%threads%", "%firstcrawl%"], [ago(time() - $b->getLastCrawl()), $b->getLastCrawl(), $b->getName(), $b->getLongName(), $b->getNoPosts(), $b->getNoThreads(), date("j F Y", $b->getFirstCrawl())]);
         }
         $html .= "</div>";
     }
     $this->setBody($html);
 }
Example #3
0
 public static function post(array $path) : array
 {
     $model = Model::get();
     $board = $model->getBoard(get('board'));
     $num = (int) get('num');
     $post = $model->getPost($board, $num);
     return self::fuukaFormat($post);
 }
Example #4
0
 /**
  * Logs in the session user. Throws exception if username
  * and password don't match any users.
  *
  * @param string $username
  * @param string $password
  * @throws NotFoundException
  */
 static function logIn(string $username, string $password)
 {
     $user = Model::get()->getUser($username, $password);
     $_SESSION['user'] = $user;
     $uid = $user->getUID();
     $time = time();
     $ip = $_SERVER['REMOTE_ADDR'];
     Config::getPDOConnectionRW()->query("INSERT INTO `logins` (`uid`,`time`,`ip`) VALUES ({$uid},{$time},'{$ip}')");
 }
Example #5
0
 function __construct()
 {
     parent::__construct("b-stats news", "", 0);
     $this->appendToBody("<h2>News</h2>");
     $articles = Model::get()->getAllNewsArticles();
     foreach ($articles as $article) {
         $date = date("Y-m-d g:i a", $article['time']);
         $content = nl2br($article['content']);
         $this->appendToBody(Site::parseHtmlFragment("article.html", ['_author_', '_id_', '_title_', '_content_', '_date_'], [$article['username'], $article['article_id'], $article['title'], $content, $date]));
     }
 }
Example #6
0
 /**
  * Naiive attempt at making an imageboard.
  *
  * @todo: Make this not as spaghetti
  *
  * @return string
  * @throws Exception
  * @throws \NotFoundException
  */
 static function post() : string
 {
     srand((int) (microtime(true) * 1000));
     if (post('captcha') != $_SESSION['captcha']) {
         $_SESSION['captcha'] = rand(100000, 999999);
         throw new Exception("Invalid Captcha");
     }
     $_SESSION['captcha'] = rand(100000, 999999);
     $model = Model::get();
     if (post('mode') != 'regist') {
         throw new Exception("invalid mode");
     }
     $board = $model->getBoard(post('board'));
     if ($board->isArchive()) {
         throw new Exception("Board is an archive");
     }
     $name = post('name', 'Anonymous');
     if ($name == '') {
         $name = 'Anonymous';
     }
     $trip = Yotsuba::parseTripcode($name);
     if ($trip == false) {
         $trip = null;
     } else {
         $trip = '!' . $trip;
     }
     $name = strtok($name, '#');
     $com = post('com');
     if ($com == '') {
         $com = null;
     }
     $file = self::checkUploadedFile();
     if ($com == null && $file == null) {
         throw new Exception("Post must contain image");
     }
     $post = $model->addPost($board, post('resto', 0), htmlspecialchars($name), $trip, htmlspecialchars(post('email')), htmlspecialchars(post('sub')), $com, $file);
     // auto-noko
     return "/{$board->getName()}/thread/{$post->getThreadId()}";
 }
Example #7
0
 /**
  * Loads the last (n) posts from the DB
  * @param type $n
  * @return \Thread reference to self
  */
 function loadLastN($n)
 {
     try {
         $posts = Model::get()->getLastNReplies($this, $n);
         foreach ($posts as $p) {
             $this->addPost($p);
         }
     } catch (Exception $e) {
     }
     return $this;
 }
Example #8
0
if (!$db->query(file_get_contents("../sql/init.sql"))) {
    echo "Could not set up all the tables for some reason! Start over!" . PHP_EOL;
    echo "Error(s): " . PHP_EOL;
    foreach ($db->error_list as $error) {
        print_r($error);
        echo PHP_EOL;
    }
    exit;
}
echo PHP_EOL . PHP_EOL . PHP_EOL . "[  SITE CUSTOMIZATION  ]" . PHP_EOL . PHP_EOL;
$site = [];
$site['name'] = readline("Enter a site name to show up on all pages (e.g., 'b-stats archive'): ");
$date = date('j F Y');
$site['subtitle'] = readline("Enter a subtitle to show up below the name (e.g. 'since {$date}'): ");
$site['pagetitle'] = readline("Enter a default HTML page title (e.g., 'archive'): ");
$site['ga_id'] = readline("If you have a Google Analytics ID, enter it, otherwise press enter: ");
if ($site['ga_id'] == '') {
    unset($site['ga_id']);
}
echo "Writing site configuration to ../cfg/site.json ... ";
$json = json_encode($site, JSON_PRETTY_PRINT);
file_put_contents("../cfg/site.json", json_encode($site, JSON_PRETTY_PRINT));
echo "Done!" . PHP_EOL . PHP_EOL;
echo "One last thing, before your site is ready. You must create" . PHP_EOL;
echo "an admin user account." . PHP_EOL;
$username = readline("Enter admin username: "******"Enter admin password: "******"yotsuba");
echo "That's it! Your site is ready to go (hopefully)!" . PHP_EOL;
echo "Thank you for choosing my shitty PHP scripts!" . PHP_EOL;
echo PHP_EOL . "~terrance" . PHP_EOL;
Example #9
0
 * @param array $arr
 * @param array ...$key Keys to ensure the existence
 */
function require_keys(array $arr, ...$key)
{
    foreach ($key as $k) {
        if (!array_key_exists($k, $arr)) {
            throw new RuntimeException("`{$k}` not set");
        }
    }
}
error_reporting(E_ALL);
define("MAX_TIME", 200);
//Board config is stored in the database.
try {
    $boardObj = Model::get()->getBoard($board);
    define("EXEC_TIME", $boardObj->getArchiveTime());
} catch (Exception $ex) {
    log_error("Board has not been configured. Add it to the boards table.");
    log_exception($ex);
    die;
}
file_put_contents("{$board}.pid", getmypid());
if (file_exists("{$board}.kill")) {
    unlink("{$board}.kill");
}
$startTime = time();
function o($msg, $newline = true)
{
    global $startTime, $logToFile, $board;
    $line = time() - $startTime . ' : ' . $msg . ($newline ? PHP_EOL : '');
Example #10
0
<?php

require_once '../inc/config.php';
use Site\Archivers;
use Model\Model;
$boards = Model::get()->getBoards(true);
$log = function ($msg) {
    echo $msg . PHP_EOL;
    file_put_contents("check.log", $msg . PHP_EOL, FILE_APPEND);
};
$log("Checking at " . date('c'));
foreach ($boards as $board) {
    if (!$board->isArchive()) {
        continue;
    }
    $status = Archivers::getStatus($board->getName());
    switch ($status) {
        case Archivers::STOPPED_UNCLEAN:
            Archivers::run($board->getName());
            $log("Restarted uncleanly stopped archiver for " . $board->getName() . ".");
            break;
        case Archivers::RUNNING:
            $log("Archiver for {$board->getName()} is running normally.");
            break;
        case Archivers::STOPPING:
            $log("Archiver for {$board->getName()} is stopping normally.");
            break;
        case Archivers::STOPPED:
            $log("Archiver for {$board->getName()} is stopped normally.");
            break;
    }
Example #11
0
 public static function requests(array $path) : array
 {
     self::ensureGET();
     Site::requirePrivilege(Config::getCfg('permissions')['owner']);
     return Model::get()->getRequests();
 }
Example #12
0
 public static function post(array $path) : array
 {
     if (count($path) < 5) {
         throw new InvalidRequestURIException();
     }
     $board = strtolower(alphanum($path[3]));
     $id = $path[4];
     $model = Model::get();
     $post = $model->getPost($model->getBoard($board), $id);
     if (count($path) === 6 && $path[5] == 'html') {
         $content = PostRenderer::renderPost($post);
         return ["html" => $content];
     }
     return $post->asArray();
 }
Example #13
0
 /**
  * Formats a plain-text post with HTML.
  *
  * Notes:
  * - cross-board or cross-thread links are not fixed, but instead left as
  *   deadlinks.
  * - <code>&lt;wbr&gt;</code> tags are not replaced.
  *
  * @param Post $post
  * @return string HTML-formatted comment
  */
 public static function toHtml(Post $post)
 {
     $comment = $post->getComment();
     $posts = $post->hasThread() ? $post->getThread()->getPostIds() : [];
     $search[0] = '~&gt;&gt;([0-9]{1,9})~';
     // >>123 type post links
     $search[1] = "~^&gt;(.*)\$~m";
     // >greentext
     $search[2] = "~&gt;&gt;&gt;/([a-z]{1,4})/~";
     // >>>/board/ links
     $search[3] = "~&gt;&gt;&gt;/([a-z]{1,4})/([0-9]{1,9})~";
     // >>>/board/123 type post links
     $replace[0] = '<a href="" class="quotelink">&gt;&gt;$1</a>';
     $replace[1] = '<span class="quote">&gt;$1</span>';
     $replace[2] = '<a href="/$1/" class="quotelink">&gt;&gt;&gt;/$1/</a>';
     $replace[3] = '<span class="deadlink">&gt;&gt;&gt;/$1/$2</span>';
     $srch = array('&', "'", '<', '>', '"');
     $rpl = array("&amp;", '&#039;', '&lt;', '&gt;', "&quot;");
     $htmlSpecialCharComment = str_replace($srch, $rpl, $comment);
     $initialTagComment = preg_replace($search, $replace, $htmlSpecialCharComment);
     $formattedComment = preg_replace_callback('~<a href="" class="quotelink">&gt;&gt;([0-9]{1,9})</a>~', function ($matches) use($posts, $post) {
         if (in_array($matches[1], $posts)) {
             return '<a href="#p' . $matches[1] . '" class="quotelink" ' . 'data-board="' . $post->getBoard()->getName() . '"' . 'data-thread="' . $post->getThreadId() . '"' . 'data-post="' . $matches[1] . '"' . '>&gt;&gt;' . $matches[1] . '</a>';
         } else {
             try {
                 $threadId = Model::get()->getThreadId($post->getBoard(), $matches[1]);
                 return '<a href="' . $threadId . '#p' . $matches[1] . '" class="quotelink" ' . 'data-board="' . $post->getBoard()->getName() . '"' . 'data-thread="' . $threadId . '"' . 'data-post="' . $matches[1] . '"' . '>&gt;&gt;' . $matches[1] . '</a>';
             } catch (\NotFoundException $ex) {
                 return '<span class="deadlink">&gt;&gt;' . $matches[1] . '</span>';
             }
         }
     }, $initialTagComment);
     $formattedComment = str_replace("\r", "", $formattedComment);
     $finalComment = str_replace("\n", "<br>", $formattedComment);
     return $finalComment;
 }
Example #14
0
 /**
  * Routes to the proper view given a path relative to the site root.
  * @param string $path
  * @throws Exception
  * @throws NotFoundException if the path can't be routed
  */
 public static function route(string $path)
 {
     $exploded = explode('/', $path);
     $base = strtolower($exploded[1]);
     switch ($base) {
         case "do":
             // Action pages begin with do
             Action::run($exploded);
             break;
         case "api":
             // API endpoints begin with api
             $page = PublicApi::run($exploded);
             break;
         case "admin":
             $page = AdminApi::run($exploded);
             break;
         case "_":
             // Fuuka API support
             $page = FuukaApiAdaptor::run($exploded);
             break;
         default:
             $pages = Config::getCfg('pages');
             $boards = Model::get()->getBoards(true);
             if (array_key_exists($base, $boards)) {
                 $board = $boards[$base];
                 if (isset($exploded[2])) {
                     switch ($exploded[2]) {
                         case "catalog":
                             $page = new Catalog($board);
                             break;
                         case "thread":
                         case "res":
                             $num = $exploded[3] ?? "";
                             if (is_numeric($num)) {
                                 $page = new ThreadView(Model::get()->getThread($board, $num));
                             } else {
                                 throw new Exception("Invalid thread id provided");
                             }
                             break;
                         case "post":
                             $post = Model::get()->getPost($board, $exploded[3] ?? 0);
                             try {
                                 $thread = Model::get()->getThread($board, $post->threadid);
                                 header("Location: /{$board->getName()}/thread/{$post->getThreadId()}#{$post->getNo()}");
                                 exit;
                             } catch (NotFoundException $ex) {
                                 $page = new OrphanPost($post);
                             }
                             break;
                         case "search":
                             $page = new Search($board, $exploded);
                             break;
                         case "":
                             $page = new BoardIndexPage($boards[$base], 1);
                             break;
                         default:
                             if (is_numeric($exploded[2])) {
                                 $page = new BoardIndexPage($boards[$base], $exploded[2]);
                             } else {
                                 throw new Exception("Unknown board page requested");
                             }
                             break;
                     }
                 } else {
                     if (!array_key_exists($base, $pages)) {
                         header("Location: {$path}/");
                         exit;
                     } else {
                         $class = '\\View\\Pages\\' . $pages[$base];
                         $page = new $class();
                     }
                 }
             } else {
                 if (array_key_exists($base, $pages)) {
                     $class = '\\View\\Pages\\' . $pages[$base];
                     $page = new $class();
                 }
             }
             break;
     }
     if (isset($page)) {
         echo $page->display();
     } else {
         throw new NotFoundException('Unrecognized URL: ' . $path);
     }
 }
Example #15
0
 static function run(string $board) : bool
 {
     if (file_exists(Site::getPath() . "/backend/{$board}-archiver.php") && !file_exists(Site::getPath() . "/backend/no_custom_archivers")) {
         if (self::getStatus($board) == self::STOPPED || self::getStatus($board) == self::STOPPED_UNCLEAN) {
             if (PHP_OS == "Linux") {
                 exec("cd " . Site::getPath() . "/backend/ && php {$board}-archiver.php -f >> /dev/null &");
             } else {
                 $path = Site::getPath() . "/backend/{$board}-archiver.php";
                 $cmd = "c:/php/php.exe \"{$path}\" -f";
                 pclose(popen('cd ' . Site::getPath() . "/backend/" . ' && start /b ' . $cmd, 'r'));
             }
             return true;
         }
     } else {
         $b = Model::get()->getBoard($board);
         if (!$b->isArchive()) {
             return false;
         }
         if (self::getStatus($board) == self::STOPPED || self::getStatus($board) == self::STOPPED_UNCLEAN) {
             if (PHP_OS == "Linux") {
                 exec("cd " . Site::getPath() . "/backend/ && " . "php archiver.php -b {$board} -f >> /dev/null &");
             } else {
                 $path = Site::getPath() . "/backend/archiver.php";
                 $cmd = "c:/php/php.exe \"{$path}\" -b {$board} -f";
                 pclose(popen('cd ' . Site::getPath() . "/backend/" . ' && start /b ' . $cmd, 'r'));
             }
             return true;
         }
     }
     return false;
 }
Example #16
0
 public static function getBoardList() : string
 {
     $ret = "";
     $boards = Model::get()->getBoards();
     $types = [];
     $types['Archives'] = array_filter($boards, function ($b) {
         /* @var Board $b */
         return $b->isArchive();
     });
     $types['Boards'] = array_filter($boards, function ($b) {
         /* @var Board $b */
         return !$b->isArchive();
     });
     foreach ($types as $n => $t) {
         if (count($t) == 0) {
             continue;
         }
         $ret .= $n . ": ";
         $groups = array();
         foreach ($t as $board) {
             $groups[$board['group']][] = $board;
         }
         foreach ($groups as $group) {
             $ret .= "[";
             $i = 0;
             foreach ($group as $board) {
                 if ($i++ > 0) {
                     $ret .= " / ";
                 }
                 $ret .= '<a href="/' . $board['shortname'] . '/" title="' . $board['longname'] . '">' . $board['shortname'] . '</a>';
             }
             $ret .= "] ";
         }
     }
     return $ret;
 }
Example #17
0
 private function id($id)
 {
     if ($id == null) {
         throw new Exception('Invalid ID');
     }
     if ($id == 'Heaven') {
         throw new Exception('ID Heaven posted so much that searching for his posts would slow the server down.');
     }
     $id = str_replace('-', '/', $id);
     return Model::get()->getPostsByID($this->board, $id, $this->perPage, $this->start);
 }
Example #18
0
 private function renderExtraButtons()
 {
     $extraButtons = "";
     if ($this->user->getPrivilege() >= Site::LEVEL_ADMIN) {
         $no = Model::get()->getNumberOfReports();
         $reports = $no ? " ({$no})" : "";
         $extraButtons .= span('[' . a('Reports' . $reports, '/reports') . ']', 'navelement') . PHP_EOL;
     }
     if ($this->user->getPrivilege() > Site::LEVEL_ADMIN) {
         $extraButtons .= span('[' . a('SCP', '/scp') . ']', 'navelement') . PHP_EOL;
     }
     if ($this->user->canSearch()) {
         $extraButtons .= span('[' . a('Search', '/search') . ']', 'navelement') . PHP_EOL;
     }
     return $extraButtons;
 }