1
0
mirror of https://github.com/vichan-devel/vichan.git synced 2024-11-28 01:10:51 +01:00

- board-search.php can now act as an include as well as a direct request.

- boards.php completely rewritten to work with new board-search.php. Functions (sort-of) without JavaScript.
- inc/functions.php fetchBoardActivity() now pulls total board counts with a more reliable and faster method.
- inc/functions.php fetchBoardActivity() & fetchBoardTags() now expect db prefixes.
- stylesheets/stylesheet.css now handles title search bar.
- boards-tags.html completely thrown out for flat tag list styling.
- boards-search.html added for the new page layout.
- boards-table.html added for the <tbody> contents.


Signed-off-by: 8n-tech <8n-tech@users.noreply.github.com>
This commit is contained in:
8n-tech 2015-04-14 01:40:45 +10:00
parent 0ceb814ab3
commit 6d1eb9961d
7 changed files with 243 additions and 264 deletions

View File

@ -1,6 +1,11 @@
<?php
include "inc/functions.php";
// We want to return a value if we're included.
// Otherwise, we will be printing a JSON object-array.
$Included = defined("TINYBOARD");
if (!$Included) {
include "inc/functions.php";
}
$CanViewUnindexed = isset($mod["type"]) && $mod["type"] <= GlobalVolunteer;
@ -18,9 +23,10 @@ $languages = array(
/* Determine search parameters from $_GET */
$search = array(
'lang' => false,
'nsfw' => true,
'tags' => false,
'lang' => false,
'nsfw' => true,
'tags' => false,
'titles' => false,
);
// Include NSFW boards?
@ -96,67 +102,83 @@ foreach ($response['boards'] as $boardUri => &$board) {
/* Activity Fetching */
$boardActivity = fetchBoardActivity( array_keys( $response['boards'] ) );
$response['tags'] = array();
// Loop through each board and record activity to it.
// We will also be weighing and building a tag list.
foreach ($response['boards'] as $boardUri => &$board) {
$board['active'] = (int) $boardActivity['active'][ $boardUri ];
$board['pph'] = (int) $boardActivity['average'][ $boardUri ];
$board['posts'] = (int) $boardActivity['posts'][ $boardUri ];
$board['pph'] = (int) $boardActivity['average'][ $boardUri ];
if (isset($board['tags']) && count($board['tags']) > 0) {
foreach ($board['tags'] as $tag) {
if (isset($response['tag'][$tag])) {
$response['tag'][$tag] += $board['active'];
if (isset($response['tags'][$tag])) {
$response['tags'][$tag] += $board['active'];
}
else {
$response['tag'][$tag] = $board['active'];
$response['tags'][$tag] = $board['active'];
}
}
}
}
// Sort boards by their popularity, then by their total posts.
$boardActivityValues = array();
foreach ($response['boards'] as $boardUri => $board) {
$boardActivityValues[$boardUri] = "{$board['active']}.{$board['posts']}";
}
array_multisort($boardActivityValues, SORT_DESC, $response['boards']);
// Get the top most popular tags.
if (count($response['tag']) > 0) {
if (count($response['tags']) > 0) {
// Sort by most active tags.
arsort( $response['tag'] );
arsort( $response['tags'] );
// Get the first n most active tags.
$response['tag'] = array_splice( $response['tag'], 0, 200 );
$response['tags'] = array_splice( $response['tags'], 0, 200 );
$tagLightest = end( array_keys( $response['tag'] ) );
// $tagLightest = end( array_keys( $response['tag'] ) );
}
/* (Please) Respond */
$json = json_encode( $response );
if (!$Included) {
$json = json_encode( $response );
// Error Handling
switch (json_last_error()) {
case JSON_ERROR_NONE:
$jsonError = false;
break;
case JSON_ERROR_DEPTH:
$jsonError = 'Maximum stack depth exceeded';
break;
case JSON_ERROR_STATE_MISMATCH:
$jsonError = 'Underflow or the modes mismatch';
break;
case JSON_ERROR_CTRL_CHAR:
$jsonError = 'Unexpected control character found';
break;
case JSON_ERROR_SYNTAX:
$jsonError = 'Syntax error, malformed JSON';
break;
case JSON_ERROR_UTF8:
$jsonError = 'Malformed UTF-8 characters, possibly incorrectly encoded';
break;
default:
$jsonError = 'Unknown error';
break;
// Error Handling
switch (json_last_error()) {
case JSON_ERROR_NONE:
$jsonError = false;
break;
case JSON_ERROR_DEPTH:
$jsonError = 'Maximum stack depth exceeded';
break;
case JSON_ERROR_STATE_MISMATCH:
$jsonError = 'Underflow or the modes mismatch';
break;
case JSON_ERROR_CTRL_CHAR:
$jsonError = 'Unexpected control character found';
break;
case JSON_ERROR_SYNTAX:
$jsonError = 'Syntax error, malformed JSON';
break;
case JSON_ERROR_UTF8:
$jsonError = 'Malformed UTF-8 characters, possibly incorrectly encoded';
break;
default:
$jsonError = 'Unknown error';
break;
}
if ($jsonError) {
$json = "{\"error\":\"{$jsonError}\"}";
}
// Successful output
echo $json;
}
if ($jsonError) {
$json = "{\"error\":\"{$jsonError}\"}";
}
// Successful output
echo $json;
else {
return $response;
}

View File

@ -1,6 +1,6 @@
<?php
include "inc/functions.php";
include "inc/functions.php"; // October 23, 2013
include "inc/countries.php";
$admin = isset($mod["type"]) && $mod["type"]<=30;
@ -8,144 +8,83 @@ $admin = isset($mod["type"]) && $mod["type"]<=30;
if (php_sapi_name() == 'fpm-fcgi' && !$admin) {
error('Cannot be run directly.');
}
$boards = listBoards();
$all_tags = array();
$total_posts_hour = 0;
$total_posts = 0;
$write_maxes = false;
function to_tag($str) {
$str = trim($str);
$str = strtolower($str);
$str = str_replace(['_', ' '], '-', $str);
return $str;
/* Build parameters for page */
$searchJson = include "board-search.php";
$boards = array();
$tags = array();
if (count($searchJson)) {
if (isset($searchJson['boards'])) {
$boards = $searchJson['boards'];
}
if (isset($searchJson['tags'])) {
$tags = $searchJson['tags'];
}
}
if (!file_exists('maxes.txt') || filemtime('maxes.txt') < (time() - (60*60))) {
$fp = fopen('maxes.txt', 'w+');
$write_maxes = true;
}
foreach ($boards as $i => $board) {
$query = prepare(sprintf("
/* $query = prepare(sprintf("
SELECT IFNULL(MAX(id),0) max,
(SELECT COUNT(*) FROM ``posts_%s`` WHERE FROM_UNIXTIME(time) > DATE_SUB(NOW(), INTERVAL 1 HOUR)) pph,
(SELECT COUNT(DISTINCT ip) FROM ``posts_%s`` WHERE FROM_UNIXTIME(time) > DATE_SUB(NOW(), INTERVAL 3 DAY)) uniq_ip
FROM ``posts_%s``
", $board['uri'], $board['uri'], $board['uri'], $board['uri'], $board['uri']));
$query->execute() or error(db_error($query));
$r = $query->fetch(PDO::FETCH_ASSOC);
$r = $query->fetch(PDO::FETCH_ASSOC); */
$tquery = prepare("SELECT `tag` FROM ``board_tags`` WHERE `uri` = :uri");
$tquery->execute([":uri" => $board['uri']]) or error(db_error($tquery));
$r2 = $tquery->fetchAll(PDO::FETCH_ASSOC);
$boardQuery = prepare("SELECT COUNT(1) AS 'boards_total', COUNT(indexed) AS 'boards_public' FROM ``boards``");
$boardQuery->execute() or error(db_error($tagQuery));
$boardResult = $boardQuery->fetchAll(PDO::FETCH_ASSOC)[0];
$tags = array();
if ($r2) {
foreach ($r2 as $ii => $t) {
$tag=to_tag($t['tag']);
$tags[] = $tag;
if (!isset($all_tags[$tag])) {
$all_tags[$tag] = (int)$r['uniq_ip'];
} else {
$all_tags[$tag] += $r['uniq_ip'];
}
}
}
$boards_total = $boardResult['boards_total'];
$boards_public = $boardResult['boards_public'];
$boards_hidden = $boardResult['boards_total'] - $boardResult['boards_public'];
$pph = $r['pph'];
$posts_hour = 0;
$posts_total = 0;
$total_posts_hour += $pph;
$total_posts += $r['max'];
/* Create and distribute page */
$boardsHTML = Element("8chan/boards-table.html", array(
"config" => $config,
"boards" => $boards,
)
);
$boards[$i]['pph'] = $pph;
$boards[$i]['ppd'] = $pph*24;
$boards[$i]['max'] = $r['max'];
$boards[$i]['uniq_ip'] = $r['uniq_ip'];
$boards[$i]['tags'] = $tags;
$tagsHTML = Element("8chan/boards-tags.html", array(
"config" => $config,
"tags" => $tags,
)
);
if ($write_maxes) fwrite($fp, $board['uri'] . ':' . $boards[$i]['max'] . "\n");
}
if ($write_maxes) fclose($fp);
$searchHTML = Element("8chan/boards-search.html", array(
"config" => $config,
"boards_total" => $boards_total,
"boards_public" => $boards_public,
"boards_hidden" => $boards_hidden,
"posts_hour" => $posts_hour,
"posts_total" => $posts_total,
"page_updated" => date('r'),
"uptime" => shell_exec('uptime -p'),
"html_boards" => $boardsHTML,
"html_tags" => $tagsHTML
)
);
usort($boards,
function ($a, $b) {
$x = $b['uniq_ip'] - $a['uniq_ip'];
if ($x) { return $x;
//} else { return strcmp($a['uri'], $b['uri']); }
} else { return $b['max'] - $a['max']; }
});
$config['additional_javascript'] = array(
'js/jquery.min.js',
'js/board-directory.js'
);
$hidden_boards_total = 0;
$rows = array();
foreach ($boards as $i => &$board) {
$board_config = @file_get_contents($board['uri'].'/config.php');
$boardCONFIG = array();
if ($board_config && $board['uri'] !== 'int') {
$board_config = str_replace('$config', '$boardCONFIG', $board_config);
$board_config = str_replace('<?php', '', $board_config);
@eval($board_config);
}
$showboard = $board['indexed'];
$locale = isset($boardCONFIG['locale'])?$boardCONFIG['locale']:'en';
$pageHTML = Element("page.html", array(
"config" => $config,
"body" => $searchHTML,
"title" => "Boards on &infin;chan"
)
);
$board['title'] = utf8tohtml($board['title']);
$locale_arr = explode('_', $locale);
$locale_short = isset($locale_arr[1]) ? strtolower($locale_arr[1]) : strtolower($locale_arr[0]);
$locale_short = str_replace('.utf-8', '', $locale_short);
$country = get_country($locale_short);
if ($board['uri'] === 'int') {$locale_short = 'eo'; $locale = 'eo'; $country = 'Esperanto';}
$board['img'] = "<img class=\"flag flag-$locale_short\" src=\"/static/blank.gif\" style=\"width:16px;height:11px;\" alt=\"$country\" title=\"$country\">";
if ($showboard || $admin) {
if (!$showboard) {
$lock = ' <i class="fa fa-lock" title="No index"></i>';
} else {
$lock = '';
}
$board['ago'] = human_time_diff(strtotime($board['time']));
} else {
unset($boards[$i]);
$hidden_boards_total += 1;
}
}
$n_boards = sizeof($boards);
$t_boards = $hidden_boards_total + $n_boards;
$boards = array_values($boards);
arsort($all_tags);
$config['additional_javascript'] = array('js/jquery.min.js', 'js/jquery.tablesorter.min.js');
$body = Element("8chan/boards-tags.html", array("config" => $config, "n_boards" => $n_boards, "t_boards" => $t_boards, "hidden_boards_total" => $hidden_boards_total, "total_posts" => $total_posts, "total_posts_hour" => $total_posts_hour, "boards" => $boards, "last_update" => date('r'), "uptime_p" => shell_exec('uptime -p'), 'tags' => $all_tags, 'top2k' => false));
$html = Element("page.html", array("config" => $config, "body" => $body, "title" => "Boards on &infin;chan"));
$boards_top2k = $boards;
array_splice($boards_top2k, 100);
$boards_top2k = array_values($boards_top2k);
$body = Element("8chan/boards-tags.html", array("config" => $config, "n_boards" => $n_boards, "t_boards" => $t_boards, "hidden_boards_total" => $hidden_boards_total, "total_posts" => $total_posts, "total_posts_hour" => $total_posts_hour, "boards" => $boards_top2k, "last_update" => date('r'), "uptime_p" => shell_exec('uptime -p'), 'tags' => $all_tags, 'top2k' => true));
$html_top2k = Element("page.html", array("config" => $config, "body" => $body, "title" => "Boards on &infin;chan"));
if ($admin) {
echo $html;
} else {
foreach ($boards as $i => &$b) { unset($b['img']); }
file_write("boards.json", json_encode($boards));
file_write("tags.json", json_encode($all_tags));
foreach ($boards as $i => $b) {/*
if (in_array($b['uri'], $config['no_top_bar_boards'])) {
unset($boards[$i]);
}*/
unset($boards[$i]['img']);
}
array_splice($boards, 48);
$boards = array_values($boards);
file_write("boards-top20.json", json_encode($boards));
file_write("boards.html", $html_top2k);
file_write("boards_full.html", $html);
echo $html;
}
file_write("boards.html", $pageHTML);
echo $pageHTML;

View File

@ -820,11 +820,14 @@ function loadBoardConfig( $uri ) {
}
function fetchBoardActivity( $uris ) {
global $config;
$boardActivity = array();
/*
$uris = "\"" . implode( (array) $uris, "\",\"" ) . "\"";
$tablePrefix = "{$config['db']['prefix']}posts_";
$uris = "\"{$tablePrefix}" . implode( (array) $uris, "\",\"{$tablePrefix}" ) . "\"";
/*
$tagQuery = prepare("SELECT * FROM ``board_tags`` WHERE `uri` IN ({$uris})");
$tagQuery->execute() or error(db_error($tagQuery));
$tagResult = $tagQuery->fetchAll(PDO::FETCH_ASSOC);
@ -845,20 +848,30 @@ function fetchBoardActivity( $uris ) {
}
*/
foreach( (array) $uris as $uri ) {
$aiQuery = prepare("SELECT `TABLE_NAME`, `AUTO_INCREMENT` FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = \"{$config['db']['database']}\" AND TABLE_NAME IN ({$uris})");
$aiQuery->execute() or error(db_error($aiQuery));
$aiResult = $aiQuery->fetchAll(PDO::FETCH_ASSOC);
foreach ($aiResult as $aiRow) {
$uri = str_replace( $tablePrefix, "", $aiRow['TABLE_NAME'] );
$posts = $aiRow['AUTO_INCREMENT'] - 1;
$random = rand( -1000, 1000 );
if( $random < 0 ) $random = 0;
$boardActivity['active'][ $uri ] = $random;
$boardActivity['average'][ $uri ] = $random * 72;
$boardActivity['active'][ $uri ] = $random;
$boardActivity['average'][ $uri ] = ($random * 72) / 72;
$boardActivity['posts'][ $uri ] = $posts;
}
return $boardActivity;
}
function fetchBoardTags( $uris ) {
global $config;
$boardTags = array();
$uris = "\"" . implode( (array) $uris, "\",\"" ) . "\"";
$uris = "\"{$config['db']['prefix']}" . implode( (array) $uris, "\",\"" ) . "\"";
$tagQuery = prepare("SELECT * FROM ``board_tags`` WHERE `uri` IN ({$uris})");
$tagQuery->execute() or error(db_error($tagQuery));

View File

@ -1394,10 +1394,10 @@ aside.search-container .box {
margin: 8px 0;
}
.search-sfw {
display: block;
cursor: pointer;
font-size: 110%;
line-height: 120%;
vertical-align: bottom;
}
#search-sfw-input {
margin: 0;
@ -1405,6 +1405,7 @@ aside.search-container .box {
transform: scale(1.20);
}
#search-lang-input,
#search-title-input,
#search-tag-input {
box-sizing: border-box;
font-size: 110%;

View File

@ -0,0 +1,78 @@
<main id="boardlist">
<section class="description box col col-12">
<h2 class="box-title">Global Statistics</h2>
<p class="box-content">{% trans %}There are currently <strong>{{boards_public}}</strong> public boards, <strong>{{boards_total}}</strong> total. Site-wide, {{posts_hour}} posts have been made in the last hour, with {{posts_total}} being made on all active boards since {{founding_date}}.{% endtrans %}</p>
{% if uptime %}<p class="box-content">{{uptime}} without interruption</p>{% endif %}
<p class="box-content">This page last updated {{page_updated}}.</p>
</section>
<div class="board-list">
<aside class="search-container col col-2">
<form id="search-form" class="box" method="post" target="/board-search.php">
<h2 class="box-title">Search</h2>
<div class="board-search box-content">
<label class="search-item search-sfw">
<input type="checkbox" id="search-sfw-input" name="sfw" checked="checked" />&nbsp;NSFW boards
</label>
<div class="search-item search-title">
<input type="text" id="search-title-input" name="title" placeholder="Search titles..." />
</div>
<div class="search-item search-lang">
<select id="search-lang-input" name="lang">
<optgroup label="Popular">
<option>All languages</option>
<option>English</option>
<option>Spanish</option>
</optgroup>
<optgroup label="All">
<option>Chinese</option>
</optgroup>
</select>
</div>
<div class="search-item search-tag">
<input type="text" id="search-tag-input" name="tag" placeholder="Search tags..." />
</div>
<div class="search-item search-submit">
<button id="search-submit">Search</button>
</div>
</div>
<ul class="tag-list box-content">
{{html_tags}}
</ul>
</form>
</aside>
<section class="board-list col col-10">
<table class="board-list-table">
<colgroup>
<col class="board-meta" />
<col class="board-uri" />
<col class="board-title" />
<col class="board-pph" />
<col class="board-max" />
<col class="board-unique" />
<col class="board-tags" />
</colgroup>
<thead>
<tr>
<th class="board-meta" data-column="meta"></th>
<th class="board-uri" data-column="uri">{% trans %}Board{% endtrans %}</th>
<th class="board-title" data-column="title">{% trans %}Title{% endtrans %}</th>
<th class="board-pph" data-column="pph" title="Posts per hour">{% trans %}PPH{% endtrans %}</th>
<th class="board-max" data-column="max">{% trans %}Total posts{% endtrans %}</th>
<th class="board-unique" data-column="unique" title="Unique IPs to post in the last 72 hours">{% trans %}Active users{% endtrans %}</th>
<th class="board-tags" data-column="tags">{% trans %}Tags{% endtrans %}</th>
</tr>
</thead>
<tbody class="board-list-tbody">{{html_boards}}</tbody>
</table>
</section>
</div>
</main>

View File

@ -0,0 +1,11 @@
{% for board in boards %}
<tr>
<td class="board-meta">{{ board.img|raw }} {% if board['sfw'] %}<img src="/static/sfw.png" title="Safe for work">{% else %}<img src="/static/nsfw.png" title="Not safe for work">{% endif %}</td>
<td class="board-uri"><div class="board-list-wrapper uri"><a href='/{{board['uri']}}/'>/{{board['uri']}}/</a>{{lock|raw}}</div></td>
<td class="board-title"><div class="board-cell" title="Created {{board['time']}} ({{board['ago']}} ago)">{{ board['title'] }}</div></td>
<td class="board-pph"><div class="board-cell">{{board['pph']}}</td>
<td class="board-max"><div class="board-cell">{{board['posts']}}</td>
<td class="board-unique"><div class="board-cell">{{board['active']}}</td>
<td class="board-tags"><div class="board-cell">{% for tag in board.tags %}<span class="board-tag">{{ tag }}</span>&nbsp;{% endfor %}</div></td>
</tr>
{% endfor %}

View File

@ -1,90 +1,5 @@
<main id="boardlist">
<section class="description box col col-12">
<h2 class="box-title">Global Statistics</h2>
<p class="box-content">{% trans %}There are currently <strong>{{t_boards}}</strong> total boards, <strong>{{hidden_boards_total}}</strong> of which are unindexed. Site-wide, {{total_posts_hour}} posts have been made in the last hour, with {{total_posts}} being made on all active boards since October 23, 2013.{% endtrans %}</p>
{% if uptime %}<p class="box-content">{{uptime_p}} without interruption</p>{% endif %}
<p class="box-content">This page last updated <time>{{last_update}}</time>.</p>
</section>
<div class="board-list">
<aside class="search-container col col-2">
<form id="search-form" class="box" method="post" target="/board-search.php">
<h2 class="box-title">Search</h2>
<div class="board-search box-content">
<label class="search-item search-sfw">
<input type="checkbox" id="search-sfw-input" checked="checked" />&nbsp;NSFW boards
</label>
<div class="search-item search-lang">
<select id="search-lang-input">
<optgroup label="Popular">
<option>All languages</option>
<option>English</option>
<option>Spanish</option>
</optgroup>
<optgroup label="All">
<option>Chinese</option>
</optgroup>
</select>
</div>
<div class="search-item search-tag">
<input type="text" id="search-tag-input" placeholder="Search tags..." />
</div>
<div class="search-item search-submit">
<button id="search-submit">Search</button>
</div>
</div>
<ul class="tag-list box-content">
{% for tag, pop in tags %}
<li class="tag-item">
<a class="tag-link" href="#">{{ tag }}</a>
</li>
{% endfor %}
</ul>
</form>
</aside>
<section class="board-list col col-10">
<table class="board-list-table">
<colgroup>
<col class="board-meta" />
<col class="board-uri" />
<col class="board-title" />
<col class="board-pph" />
<col class="board-max" />
<col class="board-unique" />
<col class="board-tags" />
</colgroup>
<thead>
<tr>
<th class="board-meta"></th>
<th class="board-uri">{% trans %}Board{% endtrans %}</th>
<th class="board-title">{% trans %}Title{% endtrans %}</th>
<th class="board-pph" title="Posts per hour">{% trans %}PPH{% endtrans %}</th>
<th class="board-max">{% trans %}Total posts{% endtrans %}</th>
<th class="board-unique" title="Unique IPs to post in the last 72 hours">{% trans %}Active users{% endtrans %}</th>
<th class="board-tags">{% trans %}Tags{% endtrans %}</th>
</tr>
</thead>
<tbody>
{% for board in boards %}
<tr>
<td class="board-meta">{{ board.img|raw }} {% if board['sfw'] %}<img src="/static/sfw.png" title="Safe for work">{% else %}<img src="/static/nsfw.png" title="Not safe for work">{% endif %}</td>
<td class="board-uri"><div class="board-list-wrapper uri"><a href='/{{board['uri']}}/'>/{{board['uri']}}/</a>{{lock|raw}}</div></td>
<td class="board-title"><div class="board-cell" title="Created {{board['time']}} ({{board['ago']}} ago)">{{ board['title'] }}</div></td>
<td class="board-pph"><div class="board-cell">{{board['pph']}}</td>
<td class="board-max"><div class="board-cell">{{board['max']}}</td>
<td class="board-unique"><div class="board-cell">{{board['uniq_ip']}}</td>
<td class="board-tags"><div class="board-cell">{% for tag in board.tags %}<span class="board-tag">{{ tag }}</span>&nbsp;{% endfor %}</div></td>
</tr>
{% endfor %}
</tbody>
</table>
</section>
</div>
</main>
{% for tag, weight in tags %}
<li class="tag-item">
<a class="tag-link" href="#">{{tag}}</a>
</li>
{% endfor %}