diff --git a/404.php b/404.php
index 0e1b634f..cee2ece6 100644
--- a/404.php
+++ b/404.php
@@ -1,6 +1,7 @@
'.
'
'.
'';
+
+ // Use read.php?
+ // read.php is a file that dynamically displays pages to users instead of the build on demand system in use in Tinyboard since 2010.
+ //
+ // read.php is basically a watered down mod.php -- if coupled with caching, it improves performance and allows for easier replication
+ // across machines.
+ $config['use_read_php'] = false;
diff --git a/inc/display.php b/inc/display.php
index a58d92f4..9561c4b8 100644
--- a/inc/display.php
+++ b/inc/display.php
@@ -406,9 +406,13 @@ class Post {
}
public function getClean( ) {
- global $board;
+ global $board, $config;
if( !isset( $this->clean ) ) {
+ if ($config['cache']['enabled'] && $this->clean = cache::get("post_clean_{$board['uri']}_{$this->id}")) {
+ return $this->clean;
+ }
+
$query = prepare("SELECT * FROM `post_clean` WHERE `post_id` = :post AND `board_id` = :board");
$query->bindValue( ':board', $board['uri'] );
$query->bindValue( ':post', $this->id );
@@ -424,6 +428,8 @@ class Post {
'clean_local_mod_id' => null,
'clean_global_mod_id' => null,
);
+
+ cache::set("post_clean_{$board['uri']}_{$this->id}", $this->clean);
}
}
diff --git a/inc/functions.php b/inc/functions.php
index 2ffdc222..bf28009d 100755
--- a/inc/functions.php
+++ b/inc/functions.php
@@ -1099,6 +1099,11 @@ function deletePost($id, $error_if_doesnt_exist=true, $rebuild_after=true) {
$antispam_query->bindValue(':board', $board['uri']);
$antispam_query->bindValue(':thread', $post['id']);
$antispam_query->execute() or error(db_error($antispam_query));
+
+ cache::delete("thread_index_{$board['uri']}_{$post['id']}");
+ cache::delete("thread_index_display_{$board['uri']}_{$post['id']}");
+ cache::delete("thread_{$board['uri']}_{$post['id']}");
+ cache::delete("catalog_{$board['uri']}");
} elseif ($query->rowCount() == 1) {
// Rebuild thread
$rebuild = &$post['thread'];
@@ -1190,57 +1195,62 @@ function index($page, $mod=false) {
return false;
$threads = array();
-
+
while ($th = $query->fetch(PDO::FETCH_ASSOC)) {
- $thread = new Thread($th, $mod ? '?/' : $config['root'], $mod);
+ if ($config['cache']['enabled'] && !($thread = cache::get("thread_index_display_{$board['uri']}_{$th['id']}"))) {
+ $thread = new Thread($th, $mod ? '?/' : $config['root'], $mod);
- if ($config['cache']['enabled']) {
- $cached = cache::get("thread_index_{$board['uri']}_{$th['id']}");
- if (isset($cached['replies'], $cached['omitted'])) {
- $replies = $cached['replies'];
- $omitted = $cached['omitted'];
- } else {
- unset($cached);
+ if ($config['cache']['enabled']) {
+ $cached = cache::get("thread_index_{$board['uri']}_{$th['id']}");
+ if (isset($cached['replies'], $cached['omitted'])) {
+ $replies = $cached['replies'];
+ $omitted = $cached['omitted'];
+ } else {
+ unset($cached);
+ }
}
- }
- if (!isset($cached)) {
- $posts = prepare(sprintf("SELECT * FROM ``posts_%s`` WHERE `thread` = :id ORDER BY `id` DESC LIMIT :limit", $board['uri']));
- $posts->bindValue(':id', $th['id']);
- $posts->bindValue(':limit', ($th['sticky'] ? $config['threads_preview_sticky'] : $config['threads_preview']), PDO::PARAM_INT);
- $posts->execute() or error(db_error($posts));
+ if (!isset($cached)) {
+ $posts = prepare(sprintf("SELECT * FROM ``posts_%s`` WHERE `thread` = :id ORDER BY `id` DESC LIMIT :limit", $board['uri']));
+ $posts->bindValue(':id', $th['id']);
+ $posts->bindValue(':limit', ($th['sticky'] ? $config['threads_preview_sticky'] : $config['threads_preview']), PDO::PARAM_INT);
+ $posts->execute() or error(db_error($posts));
- $replies = array_reverse($posts->fetchAll(PDO::FETCH_ASSOC));
+ $replies = array_reverse($posts->fetchAll(PDO::FETCH_ASSOC));
- if (count($replies) == ($th['sticky'] ? $config['threads_preview_sticky'] : $config['threads_preview'])) {
- $count = numPosts($th['id']);
- $omitted = array('post_count' => $count['replies'], 'image_count' => $count['images']);
- } else {
- $omitted = false;
+ if (count($replies) == ($th['sticky'] ? $config['threads_preview_sticky'] : $config['threads_preview'])) {
+ $count = numPosts($th['id']);
+ $omitted = array('post_count' => $count['replies'], 'image_count' => $count['images']);
+ } else {
+ $omitted = false;
+ }
+
+ if ($config['cache']['enabled'])
+ cache::set("thread_index_{$board['uri']}_{$th['id']}", array(
+ 'replies' => $replies,
+ 'omitted' => $omitted,
+ ));
}
+ $num_images = 0;
+ foreach ($replies as $po) {
+ if ($po['num_files'])
+ $num_images+=$po['num_files'];
+
+ $thread->add(new Post($po, $mod ? '?/' : $config['root'], $mod));
+ }
+
+ $thread->images = $num_images;
+ $thread->replies = isset($omitted['post_count']) ? $omitted['post_count'] : count($replies);
+
+ if ($omitted) {
+ $thread->omitted = $omitted['post_count'] - ($th['sticky'] ? $config['threads_preview_sticky'] : $config['threads_preview']);
+ $thread->omitted_images = $omitted['image_count'] - $num_images;
+ }
+
if ($config['cache']['enabled'])
- cache::set("thread_index_{$board['uri']}_{$th['id']}", array(
- 'replies' => $replies,
- 'omitted' => $omitted,
- ));
+ cache::set("thread_index_display_{$board['uri']}_{$th['id']}", $thread);
+
}
-
- $num_images = 0;
- foreach ($replies as $po) {
- if ($po['num_files'])
- $num_images+=$po['num_files'];
-
- $thread->add(new Post($po, $mod ? '?/' : $config['root'], $mod));
- }
-
- $thread->images = $num_images;
- $thread->replies = isset($omitted['post_count']) ? $omitted['post_count'] : count($replies);
-
- if ($omitted) {
- $thread->omitted = $omitted['post_count'] - ($th['sticky'] ? $config['threads_preview_sticky'] : $config['threads_preview']);
- $thread->omitted_images = $omitted['image_count'] - $num_images;
- }
-
$threads[] = $thread;
$body .= $thread->build(true);
}
@@ -1458,6 +1468,10 @@ function checkMute() {
function buildIndex() {
global $board, $config, $build_pages;
+ if ($config['use_read_php']) {
+ cache::delete("catalog_{$board['uri']}");
+ return;
+ }
$pages = getPages();
if (!$config['try_smarter'])
@@ -1535,6 +1549,17 @@ function buildIndex() {
function buildJavascript() {
global $config;
+ if ($config['cache']['enabled']) {
+ if (false === strpos($config['file_script'], '/')) {
+ $cache_name = 'main_js';
+ } else {
+ $b = explode('/', $config['file_script'])[0];
+ $cache_name = "board_{$b}_js";
+ }
+
+ cache::delete($cache_name);
+ }
+
$script = Element('main.js', array(
'config' => $config,
));
@@ -1556,7 +1581,14 @@ function buildJavascript() {
$script = JSMin::minify($script);
}
- file_write($config['file_script'], $script);
+ if ($config['cache']['enabled'])
+ cache::set($cache_name, $script);
+
+ if (!$config['use_read_php']) {
+ file_write($config['file_script'], $script);
+ } else {
+ return $script;
+ }
}
function checkDNSBL() {
@@ -1990,27 +2022,34 @@ function strip_combining_chars($str) {
function buildThread($id, $return = false, $mod = false) {
global $board, $config, $build_pages;
+ if (!$return && $config['use_read_php']) {
+ cache::delete("thread_index_{$board['uri']}_{$id}");
+ cache::delete("thread_index_display_{$board['uri']}_{$id}");
+ cache::delete("thread_{$board['uri']}_{$id}");
+ cache::delete("catalog_{$board['uri']}");
+ return;
+ }
+
$id = round($id);
if (event('build-thread', $id))
return;
- if ($config['cache']['enabled'] && !$mod) {
- // Clear cache
- cache::delete("thread_index_{$board['uri']}_{$id}");
- cache::delete("thread_{$board['uri']}_{$id}");
- }
+ if (!($thread = cache::get("thread_{$board['uri']}_{$id}"))) {
+ unset($thread);
+ $query = prepare(sprintf("SELECT * FROM ``posts_%s`` WHERE (`thread` IS NULL AND `id` = :id) OR `thread` = :id ORDER BY `thread`,`id`", $board['uri']));
+ $query->bindValue(':id', $id, PDO::PARAM_INT);
+ $query->execute() or error(db_error($query));
- $query = prepare(sprintf("SELECT * FROM ``posts_%s`` WHERE (`thread` IS NULL AND `id` = :id) OR `thread` = :id ORDER BY `thread`,`id`", $board['uri']));
- $query->bindValue(':id', $id, PDO::PARAM_INT);
- $query->execute() or error(db_error($query));
-
- while ($post = $query->fetch(PDO::FETCH_ASSOC)) {
- if (!isset($thread)) {
- $thread = new Thread($post, $mod ? '?/' : $config['root'], $mod);
- } else {
- $thread->add(new Post($post, $mod ? '?/' : $config['root'], $mod));
+ while ($post = $query->fetch(PDO::FETCH_ASSOC)) {
+ if (!isset($thread)) {
+ $thread = new Thread($post, $mod ? '?/' : $config['root'], $mod);
+ } else {
+ $thread->add(new Post($post, $mod ? '?/' : $config['root'], $mod));
+ }
}
+
+ if (isset($thread)) cache::set("thread_{$board['uri']}_{$id}", $thread);
}
// Check if any posts were found
@@ -2038,7 +2077,7 @@ function buildThread($id, $return = false, $mod = false) {
$build_pages[] = thread_find_page($id);
// json api
- if ($config['api']['enabled']) {
+ if ($config['api']['enabled'] && !$config['use_read_php']) {
$api = new Api();
$json = json_encode($api->translateThread($thread));
$jsonFilename = $board['dir'] . $config['dir']['res'] . $id . '.json';
diff --git a/inc/mod/pages.php b/inc/mod/pages.php
index 61920b46..0f059f05 100644
--- a/inc/mod/pages.php
+++ b/inc/mod/pages.php
@@ -2995,6 +2995,9 @@ function mod_report_clean( $global_reports, $board, $unclean, $post, $global, $l
$log_action = ($unclean ? "Closed" : "Re-opened" );
$log_scope = ($local && $global ? "local and global" : ($local ? "local" : "global" ) );
modLog( "{$log_action} reports for post #{$post} in {$log_scope}.", $board);
+ if ($config['cache']['enabled']) {
+ cache::delete("post_clean_{$board}_{$post}");
+ }
rebuildPost( $post );
}
diff --git a/js/ajax.js b/js/ajax.js
index 1b2bf2c0..a80ae541 100644
--- a/js/ajax.js
+++ b/js/ajax.js
@@ -55,7 +55,7 @@ $(window).ready(function() {
}
return xhr;
},
- success: function(post_response) {
+ success: function(post_response, textStatus, xhr) {
if (post_response.error) {
if (post_response.banned) {
// You are banned. Must post the form normally so the user can see the ban message.
@@ -109,12 +109,14 @@ $(window).ready(function() {
$(form).find('input[type="submit"]').val(_('Posted...'));
$(document).trigger("ajax_after_post", post_response);
} else {
+ console.log(xhr);
alert(_('An unknown error occured when posting!'));
$(form).find('input[type="submit"]').val(submit_txt);
$(form).find('input[type="submit"]').removeAttr('disabled');
}
},
error: function(xhr, status, er) {
+ console.log(xhr);
alert(_('The server returned an error or truncated response -- your post was probably still submitted. If it wasn\'t, 8chan.co might be experiencing issues right now -- please try your post again later.'));
},
data: formData,
diff --git a/js/thread-stats.js b/js/thread-stats.js
index 7c13d66c..52176ae8 100644
--- a/js/thread-stats.js
+++ b/js/thread-stats.js
@@ -1,4 +1,4 @@
-/*
+/*
* thread-stats.js
* - Adds statistics of the thread below the posts area
* - Shows ID post count beside each postID on hover
diff --git a/post.php b/post.php
index bffc91c0..50c5c8bd 100644
--- a/post.php
+++ b/post.php
@@ -852,8 +852,10 @@ elseif (isset($_POST['post'])) {
bumpThread($post['thread']);
}
- buildThread($post['op'] ? $id : $post['thread']);
-
+ $pid = $post['op'] ? $id : $post['thread'];
+
+ buildThread($pid);
+
if ($config['try_smarter'] && $post['op'])
$build_pages = range(1, $config['max_pages']);
diff --git a/read.php b/read.php
new file mode 100644
index 00000000..f1589ee3
--- /dev/null
+++ b/read.php
@@ -0,0 +1,183 @@
+ 'view_board',
+ '/(\%b)/(\d+)\.json' => 'view_api_index',
+ '/(\%b)/catalog\.json' => 'view_api_catalog',
+ '/(\%b)/threads\.json' => 'view_api_threads',
+ '/(\%b)/main\.js' => 'view_js',
+ '/main\.js' => 'view_js',
+ '/(\%b)/catalog(\.html)?' => 'view_catalog',
+ '/(\%b)/' . preg_quote($config['file_index'], '!') => 'view_board',
+ '/(\%b)/' . str_replace('%d', '(\d+)', preg_quote($config['file_page'], '!')) => 'view_board',
+ '/(\%b)/' . preg_quote($config['dir']['res'], '!') .
+ str_replace('%d', '(\d+)', preg_quote($config['file_page50'], '!')) => 'view_thread50',
+ '/(\%b)/' . preg_quote($config['dir']['res'], '!') .
+ str_replace('%d', '(\d+)', '%d(\.html)?') => 'view_thread',
+);
+
+$new_pages = array();
+foreach ($pages as $key => $callback) {
+ if (is_string($callback) && preg_match('/^secure /', $callback))
+ $key .= '(/(?P[a-f0-9]{8}))?';
+ $key = str_replace('\%b', '?P' . sprintf(substr($config['board_path'], 0, -1), $config['board_regex']), $key);
+ $new_pages[@$key[0] == '!' ? $key : '!^' . $key . '(?:&[^&=]+=[^&]*)*$!u'] = $callback;
+}
+$pages = $new_pages;
+
+function view_thread50($boardName, $thread) {
+ global $config, $mod;
+
+ if (!openBoard($boardName)) {
+ include '404.php';
+ return;
+ }
+
+ $page = buildThread50($thread, true, false);
+ echo $page;
+}
+
+function view_thread($boardName, $thread) {
+ global $config, $mod;
+
+ if (!openBoard($boardName)) {
+ include '404.php';
+ return;
+ }
+
+ $page = buildThread($thread, true, false);
+ echo $page;
+}
+
+function view_api_index($boardName, $page) {
+ global $config, $board;
+
+ $api = new Api();
+
+ if (!openBoard($boardName)) {
+ include '404.php';
+ return;
+ }
+
+ $content = index($page+1);
+
+ if (!$content)
+ return;
+
+ if ($config['api']['enabled']) {
+ $threads = $content['threads'];
+ $json = json_encode($api->translatePage($threads));
+ header('Content-Type: text/json');
+
+ echo $json;
+ }
+}
+
+function APICatalog($boardName, $gen_threads = false) {
+ global $config;
+ if (!openBoard($boardName)) {
+ include '404.php';
+ return;
+ }
+
+ header('Content-Type: text/json');
+
+ $catalog = array();
+ $api = new Api();
+
+ for ($page = 1; $page <= $config['max_pages']; $page++) {
+ $content = index($page);
+
+ if (!$content)
+ break;
+
+ $catalog[$page-1] = $content['threads'];
+ }
+
+ echo json_encode($api->translateCatalog($catalog, $gen_threads));
+}
+
+function view_api_catalog($boardName) {
+ APICatalog($boardName, false);
+}
+
+function view_api_threads($boardName) {
+ APICatalog($boardName, true);
+}
+
+function view_board($boardName, $page_no = 1) {
+ global $config, $mod;
+
+ if (!openBoard($boardName)) {
+ include '404.php';
+ return;
+ }
+
+ if (!$page = index($page_no, $mod)) {
+ error($config['error']['404']);
+ }
+
+ $page['pages'] = getPages(false);
+ $page['pages'][$page_no-1]['selected'] = true;
+ $page['btn'] = getPageButtons($page['pages'], false);
+ $page['mod'] = false;
+ $page['config'] = $config;
+
+ echo Element('index.html', $page);
+}
+
+function view_js($boardName = false) {
+ global $config;
+
+ if ($boardName && !openBoard($boardName))
+ error($config['error']['noboard']);
+
+ if (!$boardName) {
+ $cache_name = 'main_js';
+ } else {
+ $cache_name = "board_{$boardName}_js";
+ }
+
+ if (!($script = cache::get($cache_name))) {
+ $script = buildJavascript();
+ }
+
+ echo $script;
+}
+
+function view_catalog($boardName) {
+ global $board, $config;
+ $_theme = 'catalog';
+
+ $theme = loadThemeConfig($_theme);
+
+ if (!openBoard($boardName)) {
+ include '404.php';
+ return;
+ }
+
+ require_once $config['dir']['themes'] . '/' . $_theme . '/theme.php';
+
+ $catalog = $theme['build_function']('read_php', themeSettings($_theme), $board['uri']);
+ echo $catalog;
+}
+
+$found = false;
+foreach ($pages as $uri => $handler) {
+ if (preg_match($uri, $query, $matches)) {
+ $matches = array_slice($matches, 2);
+ if (is_callable($handler)) {
+ $found = true;
+ call_user_func_array($handler, $matches);
+ }
+ }
+}
+
+if (!$found)
+ include '404.php';
diff --git a/templates/themes/catalog/theme.php b/templates/themes/catalog/theme.php
index 5b940167..72e43c14 100644
--- a/templates/themes/catalog/theme.php
+++ b/templates/themes/catalog/theme.php
@@ -25,14 +25,18 @@
} elseif ($action == 'post-thread' || ($settings['update_on_posts'] && $action == 'post') || ($settings['update_on_posts'] && $action == 'post-delete') && (in_array($board, $boards) | $settings['all'])) {
$b = new Catalog();
$b->build($settings, $board);
+ } elseif ($action == 'read_php') {
+ $b = new Catalog();
+ return $b->build($settings, $board, true);
}
}
// Wrap functions in a class so they don't interfere with normal Tinyboard operations
class Catalog {
- public function build($settings, $board_name) {
+ public function build($settings, $board_name, $return = false) {
global $config, $board;
+ if (!($config['cache']['enabled'] && $catalog_out = cache::get("catalog_{$board['uri']}"))) {;
openBoard($board_name);
$recent_images = array();
@@ -90,7 +94,7 @@
$config['additional_javascript'][] = $s;
}
- file_write($config['dir']['home'] . $board_name . '/catalog.html', Element('themes/catalog/catalog.html', Array(
+ $catalog_out = Element('themes/catalog/catalog.html', Array(
'settings' => $settings,
'config' => $config,
'boardlist' => createBoardlist(),
@@ -99,6 +103,15 @@
'stats' => $stats,
'board' => $board_name,
'link' => $config['root'] . $board['dir']
- )));
+ ));
+
+ cache::set("catalog_{$board['uri']}", $catalog_out);
+ }
+
+ if ($return) {
+ return $catalog_out;
+ } else {
+ file_write($config['dir']['home'] . $board_name . '/catalog.html', $catalog_out);
+ }
}
};