1
0
mirror of https://github.com/vichan-devel/vichan.git synced 2024-11-27 17:00:52 +01:00

large cleanup

This commit is contained in:
Michael Save 2012-04-12 02:49:22 +10:00
parent 88092e4f9e
commit c9423a2c34
15 changed files with 7150 additions and 7064 deletions

View File

@ -1,5 +1,14 @@
<?php
/*
* Copyright (c) 2010-2012 Tinyboard Development Group
*/
if(realpath($_SERVER['SCRIPT_FILENAME']) == str_replace('\\', '/', __FILE__)) {
// You cannot request this file directly.
exit;
}
class Cache {
private static $cache;
public static function init() {

View File

@ -19,6 +19,8 @@
*
* More information: http://tinyboard.org/docs/?p=Config
*
* Tinyboard documentation: http://tinyboard.org/docs/
*
*/
@ -100,8 +102,8 @@
$config['cache']['prefix'] = '';
// Memcached servers to use - http://www.php.net/manual/en/memcached.addservers.php
$config['cache']['memcached'] = Array(
Array('localhost', 11211)
$config['cache']['memcached'] = array(
array('localhost', 11211)
);
/*
@ -144,13 +146,13 @@
// DNS blacklists (DNSBL) http://tinyboard.org/docs/?p=Config/DNSBL
// http://www.sectoor.de/tor.php
$config['dnsbl'][] = Array('tor.dnsbl.sectoor.de', 1); // Tor exit servers
$config['dnsbl'][] = array('tor.dnsbl.sectoor.de', 1); // Tor exit servers
// http://www.sorbs.net/using.shtml
// $config['dnsbl'][] = Array('dnsbl.sorbs.net', Array(2, 3, 4, 5, 6, 7, 8, 9));
// $config['dnsbl'][] = array('dnsbl.sorbs.net', array(2, 3, 4, 5, 6, 7, 8, 9));
// http://www.projecthoneypot.org/httpbl.php
// $config['dnsbl'][] = Array('<your access key>.%.dnsbl.httpbl.org', function($ip) {
// $config['dnsbl'][] = array('<your access key>.%.dnsbl.httpbl.org', function($ip) {
// $octets = explode('.', $ip);
//
// // days since last activity
@ -172,7 +174,7 @@
$config['spam']['hidden_inputs_min'] = 4;
$config['spam']['hidden_inputs_max'] = 12;
// These are fields used to confuse the bots. Make sure they aren't actually used by Tinyboard, or it won't work.
$config['spam']['hidden_input_names'] = Array(
$config['spam']['hidden_input_names'] = array(
'user',
'username',
'login',
@ -185,7 +187,7 @@
'message'
);
// Always update this when adding new valid fields to the post form, or EVERYTHING WILL BE DETECTED AS SPAM!
$config['spam']['valid_inputs'] = Array(
$config['spam']['valid_inputs'] = array(
'hash',
'board',
'thread',
@ -208,10 +210,10 @@
// Custom flood filters. Detect flood attacks and reject new posts if there's a positive match.
// See http://tinyboard.org/wiki/index.php?title=Flood_filters for more information.
//$config['flood_filters'][] = Array(
// 'condition' => Array(
//$config['flood_filters'][] = array(
// 'condition' => array(
// // 100 posts in the past 5 minutes (~20 p/m)
// 'posts_in_past_x_minutes' => Array(100, 5)
// 'posts_in_past_x_minutes' => array(100, 5)
// ),
// // Don't allow the user to post
// 'action' => 'reject',
@ -220,10 +222,10 @@
//);
// Another filter
//$config['flood_filters'][] = Array(
// 'condition' => Array(
//$config['flood_filters'][] = array(
// 'condition' => array(
// // 10 new empty threads in the past 2 minutes
// 'threads_with_no_replies_in_past_x_minutes' => Array(10, 2),
// 'threads_with_no_replies_in_past_x_minutes' => array(10, 2),
// // Allow replies, but not new threads (ie. reject topics only).
// 'OP' => true
// ),
@ -300,10 +302,10 @@
// Wordfilters are used to automatically replace certain words/phrases with something else.
// For a normal string replacement:
// $config['wordfilters'][] = Array('cat', 'dog');
// $config['wordfilters'][] = array('cat', 'dog');
// Advanced raplcement (regular expressions):
// $config['wordfilters'][] = Array('/cat/', 'dog', true); // 'true' means it's a regular expression
// $config['wordfilters'][] = array('/cat/', 'dog', true); // 'true' means it's a regular expression
// Always act as if they had typed "noko" in the email field no mattter what
$config['always_noko'] = false;
@ -333,13 +335,13 @@
*/
// "Wiki" markup syntax ($config['wiki_markup'] in pervious versions):
$config['markup'][] = Array("/'''(.+?)'''/", "<strong>\$1</strong>");
$config['markup'][] = Array("/''(.+?)''/", "<em>\$1</em>");
$config['markup'][] = Array("/\*\*(.+?)\*\*/", "<span class=\"spoiler\">\$1</span>");
$config['markup'][] = Array("/^\s*==(.+?)==\s*$/m", "<span class=\"heading\">\$1</span>");
$config['markup'][] = array("/'''(.+?)'''/", "<strong>\$1</strong>");
$config['markup'][] = array("/''(.+?)''/", "<em>\$1</em>");
$config['markup'][] = array("/\*\*(.+?)\*\*/", "<span class=\"spoiler\">\$1</span>");
$config['markup'][] = array("/^\s*==(.+?)==\s*$/m", "<span class=\"heading\">\$1</span>");
// Highlight PHP code wrapped in <code> tags (PHP 5.3.0+)
// $config['markup'][] = Array(
// $config['markup'][] = array(
// '/^&lt;code&gt;(.+)&lt;\/code&gt;/ms',
// function($matches) {
// return highlight_string(html_entity_decode($matches[1]), true);
@ -507,29 +509,29 @@
// $config['uri_stylesheets'] = 'http://static.example.org/stylesheets/';
// The default stylesheet to use
$config['default_stylesheet'] = Array('Yotsuba B', $config['stylesheets']['Yotsuba B']);
$config['default_stylesheet'] = array('Yotsuba B', $config['stylesheets']['Yotsuba B']);
// Boardlinks
// You can group, order and place the boardlist at the top of every page, using the following template.
//$config['boards'] = Array(
// Array('a', 'b'),
// Array('c', 'd', 'e', 'f', 'g'),
// Array('h', 'i', 'j'),
// Array('k', Array('l', 'm')),
// Array('status' => 'http://status.example.org/')
//$config['boards'] = array(
// array('a', 'b'),
// array('c', 'd', 'e', 'f', 'g'),
// array('h', 'i', 'j'),
// array('k', array('l', 'm')),
// array('status' => 'http://status.example.org/')
//);
// Categories
// Required for the Categories theme.
//$config['categories'] = Array(
// 'Group Name' => Array('a', 'b', 'c'),
// 'Another Group' => Array('d')
//$config['categories'] = array(
// 'Group Name' => array('a', 'b', 'c'),
// 'Another Group' => array('d')
//);
// Custom_categories
// Optional for the Categories theme. Array of name => (title, url) groups for categories with non-board links.
//$config['custom_categories'] = Array(
// 'Links' => Array(
// Optional for the Categories theme. array of name => (title, url) groups for categories with non-board links.
//$config['custom_categories'] = array(
// 'Links' => array(
// 'Tinyboard' => 'http://tinyboard.org',
// 'Donate' => 'donate.html'
// )
@ -576,24 +578,24 @@
// Custom embedding (YouTube, vimeo, etc.)
// It's very important that you match the full string (with ^ and $) or things will not work correctly.
$config['embedding'] = Array(
Array(
$config['embedding'] = array(
array(
'/^https?:\/\/(\w+\.)?youtube\.com\/watch\?v=([a-zA-Z0-9\-_]{10,11})(&.+)?$/i',
'<object style="float: left;margin: 10px 20px;" width="%%tb_width%%" height="%%tb_height%%"><param name="movie" value="http://www.youtube.com/v/$2?fs=1&amp;hl=en_US"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/$2?fs=1&amp;hl=en_US" type="application/x-shockwave-flash" width="%%tb_width%%" height="%%tb_height%%" allowscriptaccess="always" allowfullscreen="true"></embed></object>'
),
Array(
array(
'/^https?:\/\/(\w+\.)?vimeo\.com\/(\d{2,10})(\?.+)?$/i',
'<object style="float: left;margin: 10px 20px;" width="%%tb_width%%" height="%%tb_height%%"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=$2&amp;server=vimeo.com&amp;show_title=0&amp;show_byline=0&amp;show_portrait=0&amp;color=00adef&amp;fullscreen=1&amp;autoplay=0&amp;loop=0" /><embed src="http://vimeo.com/moogaloop.swf?clip_id=$2&amp;server=vimeo.com&amp;show_title=0&amp;show_byline=0&amp;show_portrait=0&amp;color=00adef&amp;fullscreen=1&amp;autoplay=0&amp;loop=0" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="%%tb_width%%" height="%%tb_height%%"></embed></object>'
),
Array(
array(
'/^https?:\/\/(\w+\.)?dailymotion\.com\/video\/([a-zA-Z0-9]{2,10})(_.+)?$/i',
'<object style="float: left;margin: 10px 20px;" width="%%tb_width%%" height="%%tb_height%%"><param name="movie" value="http://www.dailymotion.com/swf/video/$2"></param><param name="allowFullScreen" value="true"></param><param name="allowScriptAccess" value="always"></param><param name="wmode" value="transparent"></param><embed type="application/x-shockwave-flash" src="http://www.dailymotion.com/swf/video/$2" width="%%tb_width%%" height="%%tb_height%%" wmode="transparent" allowfullscreen="true" allowscriptaccess="always"></embed></object>'
),
Array(
array(
'/^https?:\/\/(\w+\.)?metacafe\.com\/watch\/(\d+)\/([a-zA-Z0-9_\-.]+)\/(\?.+)?$/i',
'<div style="float:left;margin:10px 20px;width:%%tb_width%%px;height:%%tb_height%%px"><embed flashVars="playerVars=showStats=no|autoPlay=no" src="http://www.metacafe.com/fplayer/$2/$3.swf" width="%%tb_width%%" height="%%tb_height%%" wmode="transparent" allowFullScreen="true" allowScriptAccess="always" name="Metacafe_$2" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash"></embed></div>'
),
Array(
array(
'/^https?:\/\/video\.google\.com\/videoplay\?docid=(\d+)([&#](.+)?)?$/i',
'<embed src="http://video.google.com/googleplayer.swf?docid=$1&hl=en&fs=true" style="width:%%tb_width%%px;height:%%tb_height%%px;float:left;margin:10px 20px" allowFullScreen="true" allowScriptAccess="always" type="application/x-shockwave-flash"></embed>'
)
@ -767,14 +769,14 @@
//$config['custom_capcode']['Custom'] ='<a class="capcode" style="color:lightgreen;font-style:italic;font-weight:bold"> ## %s</a>';
// "## Mod" makes everything purple, including the name and tripcode
//$config['custom_capcode']['Mod'] = Array(
//$config['custom_capcode']['Mod'] = array(
// '<a class="capcode" style="color:purple"> ## %s</a>',
// 'color:purple', // Change name style; optional
// 'color:purple' // Change tripcode style; optional
//);
// "## Admin" makes everything red and bold, including the name and tripcode
//$config['custom_capcode']['Admin'] = Array(
//$config['custom_capcode']['Admin'] = array(
// '<a class="capcode" style="color:red;font-weight:bold"> ## %s</a>',
// 'color:red;font-weight:bold', // Change name style; optional
// 'color:red;font-weight:bold' // Change tripcode style; optional
@ -996,18 +998,18 @@
// If you use Varnish, Squid, or any similar caching reverse-proxy in front of Tinyboard,
// you can configure Tinyboard to PURGE files when they're written to
//$config['purge'] = Array(
// Array('127.0.0.1', 80)
// Array('127.0.0.1', 80, 'example.org')
//$config['purge'] = array(
// array('127.0.0.1', 80)
// array('127.0.0.1', 80, 'example.org')
//);
// Connection timeout, in seconds
$config['purge_timeout'] = 3;
// Remote servers
// http://tinyboard.org/wiki/index.php?title=Multiple_Servers
//$config['remote']['static'] = Array(
//$config['remote']['static'] = array(
// 'host' => 'static.example.org',
// 'auth' => Array(
// 'auth' => array(
// 'method' => 'plain',
// 'username' => 'username',
// 'password' => 'password!123'
@ -1019,11 +1021,4 @@
$config['url_regex'] = '/' . '(https?|ftp):\/\/' . '(([\w\-]+\.)+[a-zA-Z]{2,6}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' . '(:\d+)?' . '(\/([\w\-~.#\/?=&;:+%!*\[\]@$\'()+,|\^]+)?)?' . '/';
// INSANE regular expression for IPv6 addresses
$config['ipv6_regex'] = '((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?';
if($_SERVER['SCRIPT_FILENAME'] == str_replace('\\', '/', __FILE__)) {
// You cannot request this file directly.
header('Location: ../', true, 302);
exit;
}
?>

View File

@ -1,107 +1,111 @@
<?php
if($_SERVER['SCRIPT_FILENAME'] == str_replace('\\', '/', __FILE__)) {
// You cannot request this file directly.
header('Location: ../', true, 302);
exit;
}
/*
* Copyright (c) 2010-2012 Tinyboard Development Group
*/
if(realpath($_SERVER['SCRIPT_FILENAME']) == str_replace('\\', '/', __FILE__)) {
// You cannot request this file directly.
exit;
}
class PreparedQueryDebug {
protected $query;
class PreparedQueryDebug {
protected $query;
public function __construct($query) {
global $pdo;
$query = preg_replace("/[\n\t]+/", ' ', $query);
public function __construct($query) {
global $pdo;
$query = preg_replace("/[\n\t]+/", ' ', $query);
$this->query = $pdo->prepare($query);
}
public function __call($function, $args) {
global $config, $debug;
if($config['debug'] && $function == 'execute') {
$start = microtime(true);
}
$return = call_user_func_array(Array($this->query, $function), $args);
if($config['debug'] && $function == 'execute') {
$time = round((microtime(true) - $start) * 1000, 2) . 'ms';
$debug['sql'][] = Array(
'query' => $this->query->queryString,
'rows' => $this->query->rowCount(),
'time' => '~' . $time
);
}
return $return;
}
$this->query = $pdo->prepare($query);
}
function sql_open() {
global $pdo, $config;
if($pdo) return true;
public function __call($function, $args) {
global $config, $debug;
$dsn = $config['db']['type'] . ':host=' . $config['db']['server'] . ';dbname=' . $config['db']['database'];
if(!empty($config['db']['dsn']))
$dsn .= ';' . $config['db']['dsn'];
try {
$options = Array(PDO::ATTR_TIMEOUT => $config['db']['timeout']);
$options = Array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8');
if($config['db']['persistent'])
$options[PDO::ATTR_PERSISTENT] = true;
return $pdo = new PDO($dsn, $config['db']['user'], $config['db']['password'], $options);
} catch(PDOException $e) {
$message = $e->getMessage();
// Remove any sensitive information
$message = str_replace($config['db']['user'], '<em>hidden</em>', $message);
$message = str_replace($config['db']['password'], '<em>hidden</em>', $message);
// Print error
error('Database error: ' . $message);
}
}
function prepare($query) {
global $pdo, $debug, $config;
sql_open();
if($config['debug'])
return new PreparedQueryDebug($query);
return $pdo->prepare($query);
}
function query($query) {
global $pdo, $debug, $config;
sql_open();
if($config['debug']) {
if($config['debug'] && $function == 'execute') {
$start = microtime(true);
$query = $pdo->query($query);
if(!$query)
return false;
}
$return = call_user_func_array(array($this->query, $function), $args);
if($config['debug'] && $function == 'execute') {
$time = round((microtime(true) - $start) * 1000, 2) . 'ms';
$debug['sql'][] = Array(
'query' => $query->queryString,
'rows' => $query->rowCount(),
'query' => $this->query->queryString,
'rows' => $this->query->rowCount(),
'time' => '~' . $time
);
return $query;
} else {
return $pdo->query($query);
}
return $return;
}
}
function sql_open() {
global $pdo, $config;
if($pdo) return true;
function db_error($PDOStatement=null) {
global $pdo;
if(isset($PDOStatement)) {
$err = $PDOStatement->errorInfo();
return $err[2];
} else {
$err = $pdo->errorInfo();
return $err[2];
}
$dsn = $config['db']['type'] . ':host=' . $config['db']['server'] . ';dbname=' . $config['db']['database'];
if(!empty($config['db']['dsn']))
$dsn .= ';' . $config['db']['dsn'];
try {
$options = Array(PDO::ATTR_TIMEOUT => $config['db']['timeout']);
$options = Array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8');
if($config['db']['persistent'])
$options[PDO::ATTR_PERSISTENT] = true;
return $pdo = new PDO($dsn, $config['db']['user'], $config['db']['password'], $options);
} catch(PDOException $e) {
$message = $e->getMessage();
// Remove any sensitive information
$message = str_replace($config['db']['user'], '<em>hidden</em>', $message);
$message = str_replace($config['db']['password'], '<em>hidden</em>', $message);
// Print error
error('Database error: ' . $message);
}
?>
}
function prepare($query) {
global $pdo, $debug, $config;
sql_open();
if($config['debug'])
return new PreparedQueryDebug($query);
return $pdo->prepare($query);
}
function query($query) {
global $pdo, $debug, $config;
sql_open();
if($config['debug']) {
$start = microtime(true);
$query = $pdo->query($query);
if(!$query)
return false;
$time = round((microtime(true) - $start) * 1000, 2) . 'ms';
$debug['sql'][] = Array(
'query' => $query->queryString,
'rows' => $query->rowCount(),
'time' => '~' . $time
);
return $query;
} else {
return $pdo->query($query);
}
}
function db_error($PDOStatement=null) {
global $pdo;
if(isset($PDOStatement)) {
$err = $PDOStatement->errorInfo();
return $err[2];
} else {
$err = $pdo->errorInfo();
return $err[2];
}
}

View File

@ -1,445 +1,441 @@
<?php
if($_SERVER['SCRIPT_FILENAME'] == str_replace('\\', '/', __FILE__)) {
// You cannot request this file directly.
header('Location: ../', true, 302);
exit;
}
/*
* Copyright (c) 2010-2012 Tinyboard Development Group
*/
if(realpath($_SERVER['SCRIPT_FILENAME']) == str_replace('\\', '/', __FILE__)) {
// You cannot request this file directly.
exit;
}
/*
joaoptm78@gmail.com
http://www.php.net/manual/en/function.filesize.php#100097
*/
function format_bytes($size) {
$units = array(' B', ' KB', ' MB', ' GB', ' TB');
for ($i = 0; $size >= 1024 && $i < 4; $i++) $size /= 1024;
return round($size, 2).$units[$i];
}
function doBoardListPart($list, $root) {
global $config;
/*
Stuff to help with the display.
*/
/*
joaoptm78@gmail.com
http://www.php.net/manual/en/function.filesize.php#100097
*/
function format_bytes($size) {
$units = array(' B', ' KB', ' MB', ' GB', ' TB');
for ($i = 0; $size >= 1024 && $i < 4; $i++) $size /= 1024;
return round($size, 2).$units[$i];
}
function commaize($n) {
$n = strval($n);
return (intval($n) < 1000) ? $n : commaize(substr($n, 0, -3)) . ',' . substr($n, -3);
}
function doBoardListPart($list, $root) {
global $config;
$body = '';
foreach($list as $board) {
if(is_array($board))
$body .= ' [' . doBoardListPart($board, $root) . '] ';
else {
if(($key = array_search($board, $list)) && gettype($key) == 'string') {
$body .= ' <a href="' . $board . '">' . $key . '</a> /';
} else {
$body .= ' <a href="' . $root . $board . '/' . $config['file_index'] . '">' . $board . '</a> /';
}
$body = '';
foreach($list as $board) {
if(is_array($board))
$body .= ' [' . doBoardListPart($board, $root) . '] ';
else {
if(($key = array_search($board, $list)) && gettype($key) == 'string') {
$body .= ' <a href="' . $board . '">' . $key . '</a> /';
} else {
$body .= ' <a href="' . $root . $board . '/' . $config['file_index'] . '">' . $board . '</a> /';
}
}
$body = preg_replace('/\/$/', '', $body);
return $body;
}
$body = preg_replace('/\/$/', '', $body);
return $body;
}
function createBoardlist($mod=false) {
global $config;
if(!isset($config['boards'])) return Array('top'=>'','bottom'=>'');
$body = doBoardListPart($config['boards'], $mod?'?/':$config['root']);
if(!preg_match('/\] $/', $body))
$body = '[' . $body . ']';
$body = trim($body);
return Array(
'top' => '<div class="boardlist">' . $body . '</div>',
'bottom' => '<div class="boardlist bottom">' . $body . '</div>'
);
}
function error($message, $priority = true) {
global $board, $mod, $config;
if($config['syslog'] && $priority !== false) {
// Use LOG_NOTICE instead of LOG_ERR or LOG_WARNING because most error message are not significant.
_syslog($priority !== true ? $priority : LOG_NOTICE, $message);
}
function createBoardlist($mod=false) {
global $config;
if(!isset($config['boards'])) return Array('top'=>'','bottom'=>'');
$body = doBoardListPart($config['boards'], $mod?'?/':$config['root']);
if(!preg_match('/\] $/', $body))
$body = '[' . $body . ']';
$body = trim($body);
return Array(
'top' => '<div class="boardlist">' . $body . '</div>',
'bottom' => '<div class="boardlist bottom">' . $body . '</div>'
);
if(defined('STDIN')) {
// Running from CLI
die('Error: ' . $message . "\n");
}
function error($message, $priority = true) {
global $board, $mod, $config;
if($config['syslog'] && $priority !== false) {
// Use LOG_NOTICE instead of LOG_ERR or LOG_WARNING because most error message are not significant.
_syslog($priority !== true ? $priority : LOG_NOTICE, $message);
}
if(defined('STDIN')) {
// Running from CLI
die('Error: ' . $message . "\n");
}
die(Element('page.html', Array(
die(Element('page.html', Array(
'config'=>$config,
'title'=>'Error',
'subtitle'=>'An error has occured.',
'body'=>'<center>' .
'<h2>' . _($message) . '</h2>' .
(isset($board) ?
"<p><a href=\"" . $config['root'] .
($mod ? $config['file_mod'] . '?/' : '') .
$board['dir'] . $config['file_index'] . "\">Go back</a>.</p>" : '') .
'</center>'
)));
}
function loginForm($error=false, $username=false, $redirect=false) {
global $config;
die(Element('page.html', Array(
'index'=>$config['root'],
'title'=>_('Login'),
'config'=>$config,
'body'=>Element('login.html', Array(
'config'=>$config,
'title'=>'Error',
'subtitle'=>'An error has occured.',
'body'=>'<center>' .
'<h2>' . _($message) . '</h2>' .
(isset($board) ?
"<p><a href=\"" . $config['root'] .
($mod ? $config['file_mod'] . '?/' : '') .
$board['dir'] . $config['file_index'] . "\">Go back</a>.</p>" : '') .
'</center>'
)));
}
function loginForm($error=false, $username=false, $redirect=false) {
global $config;
die(Element('page.html', Array(
'index'=>$config['root'],
'title'=>_('Login'),
'config'=>$config,
'body'=>Element('login.html', Array(
'config'=>$config,
'error'=>$error,
'username'=>utf8tohtml($username),
'redirect'=>$redirect
)
'error'=>$error,
'username'=>utf8tohtml($username),
'redirect'=>$redirect
)
)));
)
)));
}
function pm_snippet($body, $len=null) {
global $config;
if(!isset($len))
$len = &$config['mod']['snippet_length'];
// Replace line breaks with some whitespace
$body = str_replace('<br/>', ' ', $body);
// Strip tags
$body = strip_tags($body);
// Unescape HTML characters, to avoid splitting them in half
$body = html_entity_decode($body, ENT_COMPAT, 'UTF-8');
// calculate strlen() so we can add "..." after if needed
$strlen = mb_strlen($body);
$body = substr($body, 0, $len);
// Re-escape the characters.
return '<em>' . utf8tohtml($body) . ($strlen > $len ? '&hellip;' : '') . '</em>';
}
function capcode($cap) {
global $config;
if(!$cap)
return false;
$capcode = Array();
if(isset($config['custom_capcode'][$cap])) {
if(is_array($config['custom_capcode'][$cap])) {
$capcode['cap'] = sprintf($config['custom_capcode'][$cap][0], $cap);
if(isset($config['custom_capcode'][$cap][1]))
$capcode['name'] = $config['custom_capcode'][$cap][1];
if(isset($config['custom_capcode'][$cap][2]))
$capcode['trip'] = $config['custom_capcode'][$cap][2];
} else {
$capcode['cap'] = sprintf($config['custom_capcode'][$cap], $cap);
}
} else {
$capcode['cap'] = sprintf($config['capcode'], $cap);
}
function pm_snippet($body, $len=null) {
global $config;
if(!isset($len))
$len = &$config['mod']['snippet_length'];
// Replace line breaks with some whitespace
$body = str_replace('<br/>', ' ', $body);
// Strip tags
$body = strip_tags($body);
// Unescape HTML characters, to avoid splitting them in half
$body = html_entity_decode($body, ENT_COMPAT, 'UTF-8');
// calculate strlen() so we can add "..." after if needed
$strlen = mb_strlen($body);
$body = substr($body, 0, $len);
// Re-escape the characters.
return '<em>' . utf8tohtml($body) . ($strlen > $len ? '&hellip;' : '') . '</em>';
return $capcode;
}
function truncate($body, $url, $max_lines = false, $max_chars = false) {
global $config;
if($max_lines === false)
$max_lines = $config['body_truncate'];
if($max_chars === false)
$max_chars = $config['body_truncate_char'];
$original_body = $body;
$lines = substr_count($body, '<br/>');
// Limit line count
if($lines > $max_lines) {
if(preg_match('/(((.*?)<br\/>){' . $max_lines . '})/', $body, $m))
$body = $m[0];
}
function capcode($cap) {
global $config;
$body = substr($body, 0, $max_chars);
if($body != $original_body) {
// Remove any corrupt tags at the end
$body = preg_replace('/<([\w]+)?([^>]*)?$/', '', $body);
if(!$cap)
return false;
$capcode = Array();
if(isset($config['custom_capcode'][$cap])) {
if(is_array($config['custom_capcode'][$cap])) {
$capcode['cap'] = sprintf($config['custom_capcode'][$cap][0], $cap);
if(isset($config['custom_capcode'][$cap][1]))
$capcode['name'] = $config['custom_capcode'][$cap][1];
if(isset($config['custom_capcode'][$cap][2]))
$capcode['trip'] = $config['custom_capcode'][$cap][2];
} else {
$capcode['cap'] = sprintf($config['custom_capcode'][$cap], $cap);
// Open tags
if(preg_match_all('/<([\w]+)[^>]*>/', $body, $open_tags)) {
$tags = Array();
for($x=0;$x<count($open_tags[0]);$x++) {
if(!preg_match('/\/(\s+)?>$/', $open_tags[0][$x]))
$tags[] = $open_tags[1][$x];
}
// List successfully closed tags
if(preg_match_all('/(<\/([\w]+))>/', $body, $closed_tags)) {
for($x=0;$x<count($closed_tags[0]);$x++) {
unset($tags[array_search($closed_tags[2][$x], $tags)]);
}
}
// remove broken HTML entity at the end (if existent)
$body = preg_replace('/&[^;]+$/', '', $body);
// Close any open tags
foreach($tags as &$tag) {
$body .= "</{$tag}>";
}
} else {
$capcode['cap'] = sprintf($config['capcode'], $cap);
// remove broken HTML entity at the end (if existent)
$body = preg_replace('/&[^;]+$/', '', $body);
}
return $capcode;
$body .= '<span class="toolong">Post too long. Click <a href="' . $url . '">here</a> to view the full text.</span>';
}
function truncate($body, $url, $max_lines = false, $max_chars = false) {
return $body;
}
function confirmLink($text, $title, $confirm, $href) {
global $config, $mod;
if($config['mod']['server-side_confirm'])
return '<a onclick="if(confirm(\'' . htmlentities(addslashes($confirm)) . '\')) document.location=\'?/' . htmlentities(addslashes($href)) . '\';return false;" title="' . htmlentities($title) . '" href="?/confirm/' . $href . '">' . $text . '</a>';
else
return '<a onclick="return confirm(\'' . htmlentities(addslashes($confirm)) . '\')" title="' . htmlentities($title) . '" href="?/' . $href . '">' . $text . '</a>';
}
class Post {
public function __construct($id, $thread, $subject, $email, $name, $trip, $capcode, $body, $time, $thumb, $thumbx, $thumby, $file, $filex, $filey, $filesize, $filename, $ip, $embed, $root=null, $mod=false) {
global $config;
if(!isset($root))
$root = &$config['root'];
if($max_lines === false)
$max_lines = $config['body_truncate'];
if($max_chars === false)
$max_chars = $config['body_truncate_char'];
$original_body = $body;
$this->id = $id;
$this->thread = $thread;
$this->subject = utf8tohtml($subject);
$this->email = $email;
$this->name = utf8tohtml($name);
$this->trip = $trip;
$this->capcode = $capcode;
$this->body = $body;
$this->time = $time;
$this->thumb = $thumb;
$this->thumbx = $thumbx;
$this->thumby = $thumby;
$this->file = $file;
$this->filex = $filex;
$this->filey = $filey;
$this->filesize = $filesize;
$this->filename = $filename;
$this->ip = $ip;
$this->embed = $embed;
$this->root = $root;
$this->mod = $mod;
$lines = substr_count($body, '<br/>');
if($this->mod)
// Fix internal links
// Very complicated regex
$this->body = preg_replace(
'/<a((([a-zA-Z]+="[^"]+")|[a-zA-Z]+=[a-zA-Z]+|\s)*)href="' . preg_quote($config['root'], '/') . '(' . sprintf(preg_quote($config['board_path'], '/'), '\w+') . ')/',
'<a $1href="?/$4',
$this->body
);
}
public function link($pre = '') {
global $config, $board;
// Limit line count
if($lines > $max_lines) {
if(preg_match('/(((.*?)<br\/>){' . $max_lines . '})/', $body, $m))
$body = $m[0];
}
return $this->root . $board['dir'] . $config['dir']['res'] . sprintf($config['file_page'], $this->thread) . '#' . $pre . $this->id;
}
public function postControls() {
global $board, $config;
$body = substr($body, 0, $max_chars);
if($body != $original_body) {
// Remove any corrupt tags at the end
$body = preg_replace('/<([\w]+)?([^>]*)?$/', '', $body);
$built = '';
if($this->mod) {
// Mod controls (on posts)
// Open tags
if(preg_match_all('/<([\w]+)[^>]*>/', $body, $open_tags)) {
$tags = Array();
for($x=0;$x<count($open_tags[0]);$x++) {
if(!preg_match('/\/(\s+)?>$/', $open_tags[0][$x]))
$tags[] = $open_tags[1][$x];
}
// List successfully closed tags
if(preg_match_all('/(<\/([\w]+))>/', $body, $closed_tags)) {
for($x=0;$x<count($closed_tags[0]);$x++) {
unset($tags[array_search($closed_tags[2][$x], $tags)]);
}
}
// remove broken HTML entity at the end (if existent)
$body = preg_replace('/&[^;]+$/', '', $body);
// Close any open tags
foreach($tags as &$tag) {
$body .= "</{$tag}>";
}
} else {
// remove broken HTML entity at the end (if existent)
$body = preg_replace('/&[^;]+$/', '', $body);
}
// Delete
if(hasPermission($config['mod']['delete'], $board['uri'], $this->mod))
$built .= ' ' . confirmLink($config['mod']['link_delete'], 'Delete', 'Are you sure you want to delete this?', $board['uri'] . '/delete/' . $this->id);
$body .= '<span class="toolong">Post too long. Click <a href="' . $url . '">here</a> to view the full text.</span>';
// Delete all posts by IP
if(hasPermission($config['mod']['deletebyip'], $board['uri'], $this->mod))
$built .= ' ' . confirmLink($config['mod']['link_deletebyip'], 'Delete all posts by IP', 'Are you sure you want to delete all posts by this IP address?', $board['uri'] . '/deletebyip/' . $this->id);
// Delete all posts by IP (global)
if(hasPermission($config['mod']['deletebyip_global'], $board['uri'], $this->mod))
$built .= ' ' . confirmLink($config['mod']['link_deletebyip_global'], 'Delete all posts by IP across all boards', 'Are you sure you want to delete all posts by this IP address, across all boards?', $board['uri'] . '/deletebyip/' . $this->id . '/global');
// Ban
if(hasPermission($config['mod']['ban'], $board['uri'], $this->mod))
$built .= ' <a title="Ban" href="?/' . $board['uri'] . '/ban/' . $this->id . '">' . $config['mod']['link_ban'] . '</a>';
// Ban & Delete
if(hasPermission($config['mod']['bandelete'], $board['uri'], $this->mod))
$built .= ' <a title="Ban & Delete" href="?/' . $board['uri'] . '/ban&amp;delete/' . $this->id . '">' . $config['mod']['link_bandelete'] . '</a>';
// Delete file (keep post)
if(!empty($this->file) && hasPermission($config['mod']['deletefile'], $board['uri'], $this->mod))
$built .= ' <a title="Remove file" href="?/' . $board['uri'] . '/deletefile/' . $this->id . '">' . $config['mod']['link_deletefile'] . '</a>';
// Edit post
if(hasPermission($config['mod']['editpost'], $board['uri'], $this->mod))
$built .= ' <a title="Edit post" href="?/' . $board['uri'] . '/edit/' . $this->id . '">' . $config['mod']['link_editpost'] . '</a>';
if(!empty($built))
$built = '<span class="controls">' . $built . '</span>';
}
return $body;
return $built;
}
function confirmLink($text, $title, $confirm, $href) {
global $config, $mod;
if($config['mod']['server-side_confirm'])
return '<a onclick="if(confirm(\'' . htmlentities(addslashes($confirm)) . '\')) document.location=\'?/' . htmlentities(addslashes($href)) . '\';return false;" title="' . htmlentities($title) . '" href="?/confirm/' . $href . '">' . $text . '</a>';
else
return '<a onclick="return confirm(\'' . htmlentities(addslashes($confirm)) . '\')" title="' . htmlentities($title) . '" href="?/' . $href . '">' . $text . '</a>';
public function build($index=false) {
global $board, $config;
return Element('post_reply.html', Array('config' => $config, 'board' => $board, 'post' => &$this, 'index' => $index));
}
};
class Thread {
public function __construct($id, $subject, $email, $name, $trip, $capcode, $body, $time, $thumb, $thumbx, $thumby, $file, $filex, $filey, $filesize, $filename, $ip, $sticky, $locked, $bumplocked, $embed, $root=null, $mod=false, $hr=true) {
global $config;
if(!isset($root))
$root = &$config['root'];
$this->id = $id;
$this->subject = utf8tohtml($subject);
$this->email = $email;
$this->name = utf8tohtml($name);
$this->trip = $trip;
$this->capcode = $capcode;
$this->body = $body;
$this->time = $time;
$this->thumb = $thumb;
$this->thumbx = $thumbx;
$this->thumby = $thumby;
$this->file = $file;
$this->filex = $filex;
$this->filey = $filey;
$this->filesize = $filesize;
$this->filename = $filename;
$this->omitted = 0;
$this->omitted_images = 0;
$this->posts = Array();
$this->ip = $ip;
$this->sticky = $sticky;
$this->locked = $locked;
$this->bumplocked = $bumplocked;
$this->embed = $embed;
$this->root = $root;
$this->mod = $mod;
$this->hr = $hr;
if($this->mod)
// Fix internal links
// Very complicated regex
$this->body = preg_replace(
'/<a(([a-zA-Z]+="[^"]+")|[a-zA-Z]+=[a-zA-Z]+|\s)*href="' . preg_quote($config['root'], '/') . '(' . sprintf(preg_quote($config['board_path'], '/'), '\w+') . ')/',
'<a href="?/$3',
$this->body
);
}
public function link($pre = '') {
global $config, $board;
return $this->root . $board['dir'] . $config['dir']['res'] . sprintf($config['file_page'], $this->id) . '#' . $pre . $this->id;
}
public function add(Post $post) {
$this->posts[] = $post;
}
public function postControls() {
global $board, $config;
$built = '';
if($this->mod) {
// Mod controls (on posts)
// Delete
if(hasPermission($config['mod']['delete'], $board['uri'], $this->mod))
$built .= ' ' . confirmLink($config['mod']['link_delete'], 'Delete', 'Are you sure you want to delete this?', $board['uri'] . '/delete/' . $this->id);
// Delete all posts by IP
if(hasPermission($config['mod']['deletebyip'], $board['uri'], $this->mod))
$built .= ' ' . confirmLink($config['mod']['link_deletebyip'], 'Delete all posts by IP', 'Are you sure you want to delete all posts by this IP address?', $board['uri'] . '/deletebyip/' . $this->id);
// Delete all posts by IP (global)
if(hasPermission($config['mod']['deletebyip_global'], $board['uri'], $this->mod))
$built .= ' ' . confirmLink($config['mod']['link_deletebyip_global'], 'Delete all posts by IP across all boards', 'Are you sure you want to delete all posts by this IP address, across all boards?', $board['uri'] . '/deletebyip/' . $this->id . '/global');
// Ban
if(hasPermission($config['mod']['ban'], $board['uri'], $this->mod))
$built .= ' <a title="Ban" href="?/' . $board['uri'] . '/ban/' . $this->id . '">' . $config['mod']['link_ban'] . '</a>';
// Ban & Delete
if(hasPermission($config['mod']['bandelete'], $board['uri'], $this->mod))
$built .= ' <a title="Ban & Delete" href="?/' . $board['uri'] . '/ban&amp;delete/' . $this->id . '">' . $config['mod']['link_bandelete'] . '</a>';
// Delete file (keep post)
if(!empty($this->file) && $this->file != 'deleted' && hasPermission($config['mod']['deletefile'], $board['uri'], $this->mod))
$built .= ' <a title="Remove file" href="?/' . $board['uri'] . '/deletefile/' . $this->id . '">' . $config['mod']['link_deletefile'] . '</a>';
// Sticky
if(hasPermission($config['mod']['sticky'], $board['uri'], $this->mod))
if($this->sticky)
$built .= ' <a title="Make thread not sticky" href="?/' . $board['uri'] . '/unsticky/' . $this->id . '">' . $config['mod']['link_desticky'] . '</a>';
else
$built .= ' <a title="Make thread sticky" href="?/' . $board['uri'] . '/sticky/' . $this->id . '">' . $config['mod']['link_sticky'] . '</a>';
if(hasPermission($config['mod']['bumplock'], $board['uri'], $this->mod))
if($this->bumplocked)
$built .= ' <a title="Allow thread to be bumped" href="?/' . $board['uri'] . '/bumpunlock/' . $this->id . '">' . $config['mod']['link_bumpunlock'] . '</a>';
else
$built .= ' <a title="Prevent thread from being bumped" href="?/' . $board['uri'] . '/bumplock/' . $this->id . '">' . $config['mod']['link_bumplock'] . '</a>';
// Lock
if(hasPermission($config['mod']['lock'], $board['uri'], $this->mod))
if($this->locked)
$built .= ' <a title="Unlock thread" href="?/' . $board['uri'] . '/unlock/' . $this->id . '">' . $config['mod']['link_unlock'] . '</a>';
else
$built .= ' <a title="Lock thread" href="?/' . $board['uri'] . '/lock/' . $this->id . '">' . $config['mod']['link_lock'] . '</a>';
if(hasPermission($config['mod']['move'], $board['uri'], $this->mod))
$built .= ' <a title="Move thread to another board" href="?/' . $board['uri'] . '/move/' . $this->id . '">' . $config['mod']['link_move'] . '</a>';
// Edit post
if(hasPermission($config['mod']['editpost'], $board['uri'], $this->mod))
$built .= ' <a title="Edit post" href="?/' . $board['uri'] . '/edit/' . $this->id . '">' . $config['mod']['link_editpost'] . '</a>';
if(!empty($built))
$built = '<span class="controls op">' . $built . '</span>';
}
return $built;
}
class Post {
public function __construct($id, $thread, $subject, $email, $name, $trip, $capcode, $body, $time, $thumb, $thumbx, $thumby, $file, $filex, $filey, $filesize, $filename, $ip, $embed, $root=null, $mod=false) {
global $config;
if(!isset($root)) $root = &$config['root'];
$this->id = $id;
$this->thread = $thread;
$this->subject = utf8tohtml($subject);
$this->email = $email;
$this->name = utf8tohtml($name);
$this->trip = $trip;
$this->capcode = $capcode;
$this->body = $body;
$this->time = $time;
$this->thumb = $thumb;
$this->thumbx = $thumbx;
$this->thumby = $thumby;
$this->file = $file;
$this->filex = $filex;
$this->filey = $filey;
$this->filesize = $filesize;
$this->filename = $filename;
$this->ip = $ip;
$this->embed = $embed;
$this->root = $root;
$this->mod = $mod;
if($this->mod)
// Fix internal links
// Very complicated regex
$this->body = preg_replace(
'/<a((([a-zA-Z]+="[^"]+")|[a-zA-Z]+=[a-zA-Z]+|\s)*)href="' . preg_quote($config['root'], '/') . '(' . sprintf(preg_quote($config['board_path'], '/'), '\w+') . ')/',
'<a $1href="?/$4',
$this->body
);
}
public function link($pre = '') {
global $config, $board;
return $this->root . $board['dir'] . $config['dir']['res'] . sprintf($config['file_page'], $this->thread) . '#' . $pre . $this->id;
}
public function postControls() {
global $board, $config;
$built = '';
if($this->mod) {
// Mod controls (on posts)
// Delete
if(hasPermission($config['mod']['delete'], $board['uri'], $this->mod))
$built .= ' ' . confirmLink($config['mod']['link_delete'], 'Delete', 'Are you sure you want to delete this?', $board['uri'] . '/delete/' . $this->id);
// Delete all posts by IP
if(hasPermission($config['mod']['deletebyip'], $board['uri'], $this->mod))
$built .= ' ' . confirmLink($config['mod']['link_deletebyip'], 'Delete all posts by IP', 'Are you sure you want to delete all posts by this IP address?', $board['uri'] . '/deletebyip/' . $this->id);
// Delete all posts by IP (global)
if(hasPermission($config['mod']['deletebyip_global'], $board['uri'], $this->mod))
$built .= ' ' . confirmLink($config['mod']['link_deletebyip_global'], 'Delete all posts by IP across all boards', 'Are you sure you want to delete all posts by this IP address, across all boards?', $board['uri'] . '/deletebyip/' . $this->id . '/global');
// Ban
if(hasPermission($config['mod']['ban'], $board['uri'], $this->mod))
$built .= ' <a title="Ban" href="?/' . $board['uri'] . '/ban/' . $this->id . '">' . $config['mod']['link_ban'] . '</a>';
// Ban & Delete
if(hasPermission($config['mod']['bandelete'], $board['uri'], $this->mod))
$built .= ' <a title="Ban & Delete" href="?/' . $board['uri'] . '/ban&amp;delete/' . $this->id . '">' . $config['mod']['link_bandelete'] . '</a>';
// Delete file (keep post)
if(!empty($this->file) && hasPermission($config['mod']['deletefile'], $board['uri'], $this->mod))
$built .= ' <a title="Remove file" href="?/' . $board['uri'] . '/deletefile/' . $this->id . '">' . $config['mod']['link_deletefile'] . '</a>';
// Edit post
if(hasPermission($config['mod']['editpost'], $board['uri'], $this->mod))
$built .= ' <a title="Edit post" href="?/' . $board['uri'] . '/edit/' . $this->id . '">' . $config['mod']['link_editpost'] . '</a>';
if(!empty($built))
$built = '<span class="controls">' . $built . '</span>';
}
return $built;
}
public function build($index=false) {
global $board, $config;
return Element('post_reply.html', Array('config' => $config, 'board' => $board, 'post' => &$this, 'index' => $index));
}
};
public function ratio() {
return fraction($this->filex, $this->filey, ':');
}
class Thread {
public function __construct($id, $subject, $email, $name, $trip, $capcode, $body, $time, $thumb, $thumbx, $thumby, $file, $filex, $filey, $filesize, $filename, $ip, $sticky, $locked, $bumplocked, $embed, $root=null, $mod=false, $hr=true) {
global $config;
if(!isset($root)) $root = &$config['root'];
$this->id = $id;
$this->subject = utf8tohtml($subject);
$this->email = $email;
$this->name = utf8tohtml($name);
$this->trip = $trip;
$this->capcode = $capcode;
$this->body = $body;
$this->time = $time;
$this->thumb = $thumb;
$this->thumbx = $thumbx;
$this->thumby = $thumby;
$this->file = $file;
$this->filex = $filex;
$this->filey = $filey;
$this->filesize = $filesize;
$this->filename = $filename;
$this->omitted = 0;
$this->omitted_images = 0;
$this->posts = Array();
$this->ip = $ip;
$this->sticky = $sticky;
$this->locked = $locked;
$this->bumplocked = $bumplocked;
$this->embed = $embed;
$this->root = $root;
$this->mod = $mod;
$this->hr = $hr;
if($this->mod)
// Fix internal links
// Very complicated regex
$this->body = preg_replace(
'/<a(([a-zA-Z]+="[^"]+")|[a-zA-Z]+=[a-zA-Z]+|\s)*href="' . preg_quote($config['root'], '/') . '(' . sprintf(preg_quote($config['board_path'], '/'), '\w+') . ')/',
'<a href="?/$3',
$this->body
);
}
public function link($pre = '') {
global $config, $board;
return $this->root . $board['dir'] . $config['dir']['res'] . sprintf($config['file_page'], $this->id) . '#' . $pre . $this->id;
}
public function add(Post $post) {
$this->posts[] = $post;
}
public function postControls() {
global $board, $config;
$built = '';
if($this->mod) {
// Mod controls (on posts)
// Delete
if(hasPermission($config['mod']['delete'], $board['uri'], $this->mod))
$built .= ' ' . confirmLink($config['mod']['link_delete'], 'Delete', 'Are you sure you want to delete this?', $board['uri'] . '/delete/' . $this->id);
// Delete all posts by IP
if(hasPermission($config['mod']['deletebyip'], $board['uri'], $this->mod))
$built .= ' ' . confirmLink($config['mod']['link_deletebyip'], 'Delete all posts by IP', 'Are you sure you want to delete all posts by this IP address?', $board['uri'] . '/deletebyip/' . $this->id);
// Delete all posts by IP (global)
if(hasPermission($config['mod']['deletebyip_global'], $board['uri'], $this->mod))
$built .= ' ' . confirmLink($config['mod']['link_deletebyip_global'], 'Delete all posts by IP across all boards', 'Are you sure you want to delete all posts by this IP address, across all boards?', $board['uri'] . '/deletebyip/' . $this->id . '/global');
// Ban
if(hasPermission($config['mod']['ban'], $board['uri'], $this->mod))
$built .= ' <a title="Ban" href="?/' . $board['uri'] . '/ban/' . $this->id . '">' . $config['mod']['link_ban'] . '</a>';
// Ban & Delete
if(hasPermission($config['mod']['bandelete'], $board['uri'], $this->mod))
$built .= ' <a title="Ban & Delete" href="?/' . $board['uri'] . '/ban&amp;delete/' . $this->id . '">' . $config['mod']['link_bandelete'] . '</a>';
// Delete file (keep post)
if(!empty($this->file) && $this->file != 'deleted' && hasPermission($config['mod']['deletefile'], $board['uri'], $this->mod))
$built .= ' <a title="Remove file" href="?/' . $board['uri'] . '/deletefile/' . $this->id . '">' . $config['mod']['link_deletefile'] . '</a>';
// Sticky
if(hasPermission($config['mod']['sticky'], $board['uri'], $this->mod))
if($this->sticky)
$built .= ' <a title="Make thread not sticky" href="?/' . $board['uri'] . '/unsticky/' . $this->id . '">' . $config['mod']['link_desticky'] . '</a>';
else
$built .= ' <a title="Make thread sticky" href="?/' . $board['uri'] . '/sticky/' . $this->id . '">' . $config['mod']['link_sticky'] . '</a>';
if(hasPermission($config['mod']['bumplock'], $board['uri'], $this->mod))
if($this->bumplocked)
$built .= ' <a title="Allow thread to be bumped" href="?/' . $board['uri'] . '/bumpunlock/' . $this->id . '">' . $config['mod']['link_bumpunlock'] . '</a>';
else
$built .= ' <a title="Prevent thread from being bumped" href="?/' . $board['uri'] . '/bumplock/' . $this->id . '">' . $config['mod']['link_bumplock'] . '</a>';
// Lock
if(hasPermission($config['mod']['lock'], $board['uri'], $this->mod))
if($this->locked)
$built .= ' <a title="Unlock thread" href="?/' . $board['uri'] . '/unlock/' . $this->id . '">' . $config['mod']['link_unlock'] . '</a>';
else
$built .= ' <a title="Lock thread" href="?/' . $board['uri'] . '/lock/' . $this->id . '">' . $config['mod']['link_lock'] . '</a>';
if(hasPermission($config['mod']['move'], $board['uri'], $this->mod))
$built .= ' <a title="Move thread to another board" href="?/' . $board['uri'] . '/move/' . $this->id . '">' . $config['mod']['link_move'] . '</a>';
// Edit post
if(hasPermission($config['mod']['editpost'], $board['uri'], $this->mod))
$built .= ' <a title="Edit post" href="?/' . $board['uri'] . '/edit/' . $this->id . '">' . $config['mod']['link_editpost'] . '</a>';
if(!empty($built))
$built = '<span class="controls op">' . $built . '</span>';
}
return $built;
public function build($index=false) {
global $board, $config, $debug;
$built = Element('post_thread.html', Array('config' => $config, 'board' => $board, 'post' => &$this, 'index' => $index));
if(!$this->mod && $index && $config['cache']['enabled']) {
cache::set($this->cache_key($index), $built);
}
public function ratio() {
return fraction($this->filex, $this->filey, ':');
}
return $built;
}
function cache_key($index) {
global $board;
public function build($index=false) {
global $board, $config, $debug;
$built = Element('post_thread.html', Array('config' => $config, 'board' => $board, 'post' => &$this, 'index' => $index));
if(!$this->mod && $index && $config['cache']['enabled']) {
cache::set($this->cache_key($index), $built);
}
return $built;
}
function cache_key($index) {
global $board;
return 'thread_' . ($index ? 'index_' : '') . $board['uri'] . '_' . $this->id;
}
};
?>
return 'thread_' . ($index ? 'index_' : '') . $board['uri'] . '_' . $this->id;
}
};

View File

@ -1,5 +1,14 @@
<?php
/*
* Copyright (c) 2010-2012 Tinyboard Development Group
*/
if(realpath($_SERVER['SCRIPT_FILENAME']) == str_replace('\\', '/', __FILE__)) {
// You cannot request this file directly.
exit;
}
function event() {
global $events;

View File

@ -1,5 +1,14 @@
<?php
/*
* Copyright (c) 2010-2012 Tinyboard Development Group
*/
if(realpath($_SERVER['SCRIPT_FILENAME']) == str_replace('\\', '/', __FILE__)) {
// You cannot request this file directly.
exit;
}
class Filter {
private $condition;

File diff suppressed because it is too large Load Diff

View File

@ -1,488 +1,491 @@
<?php
if($_SERVER['SCRIPT_FILENAME'] == str_replace('\\', '/', __FILE__)) {
// You cannot request this file directly.
header('Location: ../', true, 302);
exit;
}
class Image {
public $src, $format, $image, $size;
public function __construct($src, $format = false) {
global $config;
$this->src = $src;
$this->format = $format;
if($config['thumb_method'] == 'imagick') {
$classname = 'ImageImagick';
} elseif($config['thumb_method'] == 'convert') {
$classname = 'ImageConvert';
} else {
$classname = 'Image' . strtoupper($this->format);
if(!class_exists($classname)) {
error('Unsupported file format: ' . $this->format);
}
}
$this->image = new $classname($this);
if(!$this->image->valid()) {
$this->delete();
error($config['error']['invalidimg']);
}
$this->size = (object)Array('width' => $this->image->_width(), 'height' => $this->image->_height());
if($this->size->width < 1 || $this->size->height < 1) {
$this->delete();
error($config['error']['invalidimg']);
}
}
/*
* Copyright (c) 2010-2012 Tinyboard Development Group
*/
if(realpath($_SERVER['SCRIPT_FILENAME']) == str_replace('\\', '/', __FILE__)) {
// You cannot request this file directly.
exit;
}
class Image {
public $src, $format, $image, $size;
public function __construct($src, $format = false) {
global $config;
public function resize($extension, $max_width, $max_height) {
global $config;
if($config['thumb_method'] == 'imagick') {
$classname = 'ImageImagick';
} elseif($config['thumb_method'] == 'convert') {
$classname = 'ImageConvert';
} else {
$classname = 'Image' . strtoupper($extension);
if(!class_exists($classname)) {
error('Unsupported file format: ' . $extension);
}
}
$thumb = new $classname(false);
$thumb->src = $this->src;
$thumb->original_width = $this->size->width;
$thumb->original_height = $this->size->height;
$x_ratio = $max_width / $this->size->width;
$y_ratio = $max_height / $this->size->height;
if(($this->size->width <= $max_width) && ($this->size->height <= $max_height)) {
$width = $this->size->width;
$height = $this->size->height;
} elseif (($x_ratio * $this->size->height) < $max_height) {
$height = ceil($x_ratio * $this->size->height);
$width = $max_width;
} else {
$width = ceil($y_ratio * $this->size->width);
$height = $max_height;
}
$thumb->_resize($this->image->image, $width, $height);
return $thumb;
}
$this->src = $src;
$this->format = $format;
public function to($dst) {
$this->image->to($dst);
}
public function delete() {
file_unlink($this->src);
}
public function destroy() {
$this->image->_destroy();
}
}
class ImageGD {
public function GD_create() {
$this->image = imagecreatetruecolor($this->width, $this->height);
}
public function GD_copyresampled() {
imagecopyresampled($this->image, $this->original, 0, 0, 0, 0, $this->width, $this->height, $this->original_width, $this->original_height);
}
public function GD_resize() {
$this->GD_create();
$this->GD_copyresampled();
}
}
class ImageBase extends ImageGD {
public $image, $src, $original, $original_width, $original_height, $width, $height;
public function valid() {
return (bool)$this->image;
}
public function __construct($img) {
if(method_exists($this, 'init'))
$this->init();
if($img !== false) {
$this->src = $img->src;
$this->from();
}
}
public function _width() {
if(method_exists($this, 'width'))
return $this->width();
// use default GD functions
return imagesx($this->image);
}
public function _height() {
if(method_exists($this, 'height'))
return $this->height();
// use default GD functions
return imagesy($this->image);
}
public function _destroy() {
if(method_exists($this, 'destroy'))
return $this->destroy();
// use default GD functions
return imagedestroy($this->image);
}
public function _resize($original, $width, $height) {
$this->original = &$original;
$this->width = $width;
$this->height = $height;
if(method_exists($this, 'resize'))
$this->resize();
else
// use default GD functions
$this->GD_resize();
}
}
class ImageImagick extends ImageBase {
public function init() {
$this->image = new Imagick();
$this->image->setBackgroundColor(new ImagickPixel('transparent'));
}
public function from() {
try {
$this->image->readImage($this->src);
} catch(ImagickException $e) {
// invalid image
$this->image = false;
}
}
public function to($src) {
if(preg_match('/\.gif$/i', $src))
$this->image->writeImages($src, true);
else
$this->image->writeImage($src);
}
public function width() {
return $this->image->getImageWidth();
}
public function height() {
return $this->image->getImageHeight();
}
public function destroy() {
return $this->image->destroy();
}
public function resize() {
global $config;
if(preg_match('/\.gif$/i', $this->src) && $config['thumb_ext'] == 'gif') {
$this->image = new Imagick();
$this->image->setFormat('gif');
$keep_frames = Array();
for($i = 0; $i < $this->original->getNumberImages(); $i += floor($this->original->getNumberImages() / $config['thumb_keep_animation_frames']))
$keep_frames[] = $i;
$i = 0;
$delay = 0;
foreach($this->original as $frame) {
$delay += $frame->getImageDelay();
//if($i < $config['thumb_keep_animation_frames']) {
if(in_array($i, $keep_frames)) {
// $frame->scaleImage($this->width, $this->height, false);
$frame->sampleImage($this->width, $this->height);
$frame->setImagePage($this->width, $this->height, 0, 0);
$frame->setImageDelay($delay);
$delay = 0;
$this->image->addImage($frame->getImage());
}
$i++;
}
} else {
$this->image = clone $this->original;
$this->image->scaleImage($this->width, $this->height, false);
}
}
}
class ImageConvert extends ImageBase {
public $width, $height, $temp;
public function init() {
global $config;
$this->temp = false;
}
public function from() {
$size = trim(shell_exec('identify -format "%w %h" ' . escapeshellarg($this->src . '[0]')));
if(preg_match('/^(\d+) (\d+)$/', $size, $m)) {
$this->width = $m[1];
$this->height = $m[2];
$this->image = true;
} else {
// mark as invalid
$this->image = false;
}
}
public function to($src) {
if(!$this->temp) {
// $config['redraw_image']
shell_exec('convert ' . escapeshellarg($this->src) . ' ' . escapeshellarg($src));
} else {
rename($this->temp, $src);
chmod($src, 0664);
}
}
public function width() {
return $this->width;
}
public function height() {
return $this->height;
}
public function destroy() {
@unlink($this->temp);
$this->temp = false;
}
public function resize() {
global $config;
if($this->temp) {
// remove old
$this->destroy();
}
$this->temp = tempnam($config['tmp'], 'imagick');
$quality = $config['thumb_quality'] * 10;
if(shell_exec("convert -flatten -filter Point -scale {$this->width}x{$this->height} +antialias -quality {$quality} " . escapeshellarg($this->src . '[0]') . " " . escapeshellarg($this->temp)) || !file_exists($this->temp))
error('Failed to resize image!');
}
}
class ImagePNG extends ImageBase {
public function from() {
$this->image = @imagecreatefrompng($this->src);
}
public function to($src) {
global $config;
imagepng($this->image, $src, $config['thumb_quality']);
}
public function resize() {
$this->GD_create();
imagecolortransparent($this->image, imagecolorallocatealpha($this->image, 0, 0, 0, 0));
imagesavealpha($this->image, true);
imagealphablending($this->image, false);
$this->GD_copyresampled();
}
}
class ImageGIF extends ImageBase {
public function from() {
$this->image = @imagecreatefromgif($this->src);
}
public function to($src) {
imagegif($this->image, $src);
}
public function resize() {
$this->GD_create();
imagecolortransparent($this->image, imagecolorallocatealpha($this->image, 0, 0, 0, 0));
imagesavealpha($this->image, true);
$this->GD_copyresampled();
}
}
class ImageJPG extends ImageBase {
public function from() {
$this->image = @imagecreatefromjpeg($this->src);
}
public function to($src) {
imagejpeg($this->image, $src);
}
}
class ImageJPEG extends ImageJPG {
}
class ImageBMP extends ImageBase {
public function from() {
$this->image = @imagecreatefrombmp($this->src);
}
public function to($src) {
imagebmp($this->image, $src);
}
}
/*********************************************/
/* Fonction: imagecreatefrombmp */
/* Author: DHKold */
/* Contact: admin@dhkold.com */
/* Date: The 15th of June 2005 */
/* Version: 2.0B */
/*********************************************/
function imagecreatefrombmp($filename) {
if (! $f1 = fopen($filename,"rb")) return FALSE;
$FILE = unpack("vfile_type/Vfile_size/Vreserved/Vbitmap_offset", fread($f1,14));
if ($FILE['file_type'] != 19778) return FALSE;
$BMP = unpack('Vheader_size/Vwidth/Vheight/vplanes/vbits_per_pixel'.
'/Vcompression/Vsize_bitmap/Vhoriz_resolution'.
'/Vvert_resolution/Vcolors_used/Vcolors_important', fread($f1,40));
$BMP['colors'] = pow(2,$BMP['bits_per_pixel']);
if ($BMP['size_bitmap'] == 0) $BMP['size_bitmap'] = $FILE['file_size'] - $FILE['bitmap_offset'];
$BMP['bytes_per_pixel'] = $BMP['bits_per_pixel']/8;
$BMP['bytes_per_pixel2'] = ceil($BMP['bytes_per_pixel']);
$BMP['decal'] = ($BMP['width']*$BMP['bytes_per_pixel']/4);
$BMP['decal'] -= floor($BMP['width']*$BMP['bytes_per_pixel']/4);
$BMP['decal'] = 4-(4*$BMP['decal']);
if ($BMP['decal'] == 4) $BMP['decal'] = 0;
$PALETTE = array();
if ($BMP['colors'] < 16777216)
{
$PALETTE = unpack('V'.$BMP['colors'], fread($f1,$BMP['colors']*4));
}
$IMG = fread($f1,$BMP['size_bitmap']);
$VIDE = chr(0);
$res = imagecreatetruecolor($BMP['width'],$BMP['height']);
$P = 0;
$Y = $BMP['height']-1;
while ($Y >= 0)
{
$X=0;
while ($X < $BMP['width'])
{
if ($BMP['bits_per_pixel'] == 24)
$COLOR = unpack("V",substr($IMG,$P,3).$VIDE);
elseif ($BMP['bits_per_pixel'] == 16)
{
$COLOR = unpack("n",substr($IMG,$P,2));
$COLOR[1] = $PALETTE[$COLOR[1]+1];
}
elseif ($BMP['bits_per_pixel'] == 8)
{
$COLOR = unpack("n",$VIDE.substr($IMG,$P,1));
$COLOR[1] = $PALETTE[$COLOR[1]+1];
}
elseif ($BMP['bits_per_pixel'] == 4)
{
$COLOR = unpack("n",$VIDE.substr($IMG,floor($P),1));
if (($P*2)%2 == 0) $COLOR[1] = ($COLOR[1] >> 4) ; else $COLOR[1] = ($COLOR[1] & 0x0F);
$COLOR[1] = $PALETTE[$COLOR[1]+1];
}
elseif ($BMP['bits_per_pixel'] == 1)
{
$COLOR = unpack("n",$VIDE.substr($IMG,floor($P),1));
if (($P*8)%8 == 0) $COLOR[1] = $COLOR[1] >>7;
elseif (($P*8)%8 == 1) $COLOR[1] = ($COLOR[1] & 0x40)>>6;
elseif (($P*8)%8 == 2) $COLOR[1] = ($COLOR[1] & 0x20)>>5;
elseif (($P*8)%8 == 3) $COLOR[1] = ($COLOR[1] & 0x10)>>4;
elseif (($P*8)%8 == 4) $COLOR[1] = ($COLOR[1] & 0x8)>>3;
elseif (($P*8)%8 == 5) $COLOR[1] = ($COLOR[1] & 0x4)>>2;
elseif (($P*8)%8 == 6) $COLOR[1] = ($COLOR[1] & 0x2)>>1;
elseif (($P*8)%8 == 7) $COLOR[1] = ($COLOR[1] & 0x1);
$COLOR[1] = $PALETTE[$COLOR[1]+1];
}
else
return FALSE;
imagesetpixel($res,$X,$Y,$COLOR[1]);
$X++;
$P += $BMP['bytes_per_pixel'];
}
$Y--;
$P+=$BMP['decal'];
}
fclose($f1);
return $res;
}
function imagebmp(&$img, $filename='') {
$widthOrig = imagesx($img);
$widthFloor = ((floor($widthOrig/16))*16);
$widthCeil = ((ceil($widthOrig/16))*16);
$height = imagesy($img);
$size = ($widthCeil*$height*3)+54;
// Bitmap File Header
$result = 'BM'; // header (2b)
$result .= int_to_dword($size); // size of file (4b)
$result .= int_to_dword(0); // reserved (4b)
$result .= int_to_dword(54); // byte location in the file which is first byte of IMAGE (4b)
// Bitmap Info Header
$result .= int_to_dword(40); // Size of BITMAPINFOHEADER (4b)
$result .= int_to_dword($widthCeil); // width of bitmap (4b)
$result .= int_to_dword($height); // height of bitmap (4b)
$result .= int_to_word(1); // biPlanes = 1 (2b)
$result .= int_to_word(24); // biBitCount = {1 (mono) or 4 (16 clr ) or 8 (256 clr) or 24 (16 Mil)} (2b
$result .= int_to_dword(0); // RLE COMPRESSION (4b)
$result .= int_to_dword(0); // width x height (4b)
$result .= int_to_dword(0); // biXPelsPerMeter (4b)
$result .= int_to_dword(0); // biYPelsPerMeter (4b)
$result .= int_to_dword(0); // Number of palettes used (4b)
$result .= int_to_dword(0); // Number of important colour (4b)
// is faster than chr()
$arrChr = array();
for($i=0; $i<256; $i++){
$arrChr[$i] = chr($i);
}
// creates image data
$bgfillcolor = array('red'=>0, 'green'=>0, 'blue'=>0);
// bottom to top - left to right - attention blue green red !!!
$y=$height-1;
for ($y2=0; $y2<$height; $y2++) {
for ($x=0; $x<$widthFloor; ) {
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
}
for ($x=$widthFloor; $x<$widthCeil; $x++) {
$rgb = ($x<$widthOrig) ? imagecolorsforindex($img, imagecolorat($img, $x, $y)) : $bgfillcolor;
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
}
$y--;
}
// see imagegif
if($filename == '') {
echo $result;
if($config['thumb_method'] == 'imagick') {
$classname = 'ImageImagick';
} elseif($config['thumb_method'] == 'convert') {
$classname = 'ImageConvert';
} else {
$file = fopen($filename, 'wb');
fwrite($file, $result);
fclose($file);
$classname = 'Image' . strtoupper($this->format);
if(!class_exists($classname)) {
error('Unsupported file format: ' . $this->format);
}
}
$this->image = new $classname($this);
if(!$this->image->valid()) {
$this->delete();
error($config['error']['invalidimg']);
}
$this->size = (object)Array('width' => $this->image->_width(), 'height' => $this->image->_height());
if($this->size->width < 1 || $this->size->height < 1) {
$this->delete();
error($config['error']['invalidimg']);
}
}
// imagebmp helpers
function int_to_dword($n) {
return chr($n & 255).chr(($n >> 8) & 255).chr(($n >> 16) & 255).chr(($n >> 24) & 255);
public function resize($extension, $max_width, $max_height) {
global $config;
if($config['thumb_method'] == 'imagick') {
$classname = 'ImageImagick';
} elseif($config['thumb_method'] == 'convert') {
$classname = 'ImageConvert';
} else {
$classname = 'Image' . strtoupper($extension);
if(!class_exists($classname)) {
error('Unsupported file format: ' . $extension);
}
}
$thumb = new $classname(false);
$thumb->src = $this->src;
$thumb->original_width = $this->size->width;
$thumb->original_height = $this->size->height;
$x_ratio = $max_width / $this->size->width;
$y_ratio = $max_height / $this->size->height;
if(($this->size->width <= $max_width) && ($this->size->height <= $max_height)) {
$width = $this->size->width;
$height = $this->size->height;
} elseif (($x_ratio * $this->size->height) < $max_height) {
$height = ceil($x_ratio * $this->size->height);
$width = $max_width;
} else {
$width = ceil($y_ratio * $this->size->width);
$height = $max_height;
}
$thumb->_resize($this->image->image, $width, $height);
return $thumb;
}
function int_to_word($n) {
return chr($n & 255).chr(($n >> 8) & 255);
public function to($dst) {
$this->image->to($dst);
}
public function delete() {
file_unlink($this->src);
}
public function destroy() {
$this->image->_destroy();
}
}
class ImageGD {
public function GD_create() {
$this->image = imagecreatetruecolor($this->width, $this->height);
}
public function GD_copyresampled() {
imagecopyresampled($this->image, $this->original, 0, 0, 0, 0, $this->width, $this->height, $this->original_width, $this->original_height);
}
public function GD_resize() {
$this->GD_create();
$this->GD_copyresampled();
}
}
class ImageBase extends ImageGD {
public $image, $src, $original, $original_width, $original_height, $width, $height;
public function valid() {
return (bool)$this->image;
}
public function __construct($img) {
if(method_exists($this, 'init'))
$this->init();
if($img !== false) {
$this->src = $img->src;
$this->from();
}
}
public function _width() {
if(method_exists($this, 'width'))
return $this->width();
// use default GD functions
return imagesx($this->image);
}
public function _height() {
if(method_exists($this, 'height'))
return $this->height();
// use default GD functions
return imagesy($this->image);
}
public function _destroy() {
if(method_exists($this, 'destroy'))
return $this->destroy();
// use default GD functions
return imagedestroy($this->image);
}
public function _resize($original, $width, $height) {
$this->original = &$original;
$this->width = $width;
$this->height = $height;
if(method_exists($this, 'resize'))
$this->resize();
else
// use default GD functions
$this->GD_resize();
}
}
class ImageImagick extends ImageBase {
public function init() {
$this->image = new Imagick();
$this->image->setBackgroundColor(new ImagickPixel('transparent'));
}
public function from() {
try {
$this->image->readImage($this->src);
} catch(ImagickException $e) {
// invalid image
$this->image = false;
}
}
public function to($src) {
if(preg_match('/\.gif$/i', $src))
$this->image->writeImages($src, true);
else
$this->image->writeImage($src);
}
public function width() {
return $this->image->getImageWidth();
}
public function height() {
return $this->image->getImageHeight();
}
public function destroy() {
return $this->image->destroy();
}
public function resize() {
global $config;
if(preg_match('/\.gif$/i', $this->src) && $config['thumb_ext'] == 'gif') {
$this->image = new Imagick();
$this->image->setFormat('gif');
$keep_frames = Array();
for($i = 0; $i < $this->original->getNumberImages(); $i += floor($this->original->getNumberImages() / $config['thumb_keep_animation_frames']))
$keep_frames[] = $i;
$i = 0;
$delay = 0;
foreach($this->original as $frame) {
$delay += $frame->getImageDelay();
//if($i < $config['thumb_keep_animation_frames']) {
if(in_array($i, $keep_frames)) {
// $frame->scaleImage($this->width, $this->height, false);
$frame->sampleImage($this->width, $this->height);
$frame->setImagePage($this->width, $this->height, 0, 0);
$frame->setImageDelay($delay);
$delay = 0;
$this->image->addImage($frame->getImage());
}
$i++;
}
} else {
$this->image = clone $this->original;
$this->image->scaleImage($this->width, $this->height, false);
}
}
}
class ImageConvert extends ImageBase {
public $width, $height, $temp;
public function init() {
global $config;
$this->temp = false;
}
public function from() {
$size = trim(shell_exec('identify -format "%w %h" ' . escapeshellarg($this->src . '[0]')));
if(preg_match('/^(\d+) (\d+)$/', $size, $m)) {
$this->width = $m[1];
$this->height = $m[2];
$this->image = true;
} else {
// mark as invalid
$this->image = false;
}
}
public function to($src) {
if(!$this->temp) {
// $config['redraw_image']
shell_exec('convert ' . escapeshellarg($this->src) . ' ' . escapeshellarg($src));
} else {
rename($this->temp, $src);
chmod($src, 0664);
}
}
public function width() {
return $this->width;
}
public function height() {
return $this->height;
}
public function destroy() {
@unlink($this->temp);
$this->temp = false;
}
public function resize() {
global $config;
if($this->temp) {
// remove old
$this->destroy();
}
$this->temp = tempnam($config['tmp'], 'imagick');
$quality = $config['thumb_quality'] * 10;
if(shell_exec("convert -flatten -filter Point -scale {$this->width}x{$this->height} +antialias -quality {$quality} " . escapeshellarg($this->src . '[0]') . " " . escapeshellarg($this->temp)) || !file_exists($this->temp))
error('Failed to resize image!');
}
}
class ImagePNG extends ImageBase {
public function from() {
$this->image = @imagecreatefrompng($this->src);
}
public function to($src) {
global $config;
imagepng($this->image, $src, $config['thumb_quality']);
}
public function resize() {
$this->GD_create();
imagecolortransparent($this->image, imagecolorallocatealpha($this->image, 0, 0, 0, 0));
imagesavealpha($this->image, true);
imagealphablending($this->image, false);
$this->GD_copyresampled();
}
}
class ImageGIF extends ImageBase {
public function from() {
$this->image = @imagecreatefromgif($this->src);
}
public function to($src) {
imagegif($this->image, $src);
}
public function resize() {
$this->GD_create();
imagecolortransparent($this->image, imagecolorallocatealpha($this->image, 0, 0, 0, 0));
imagesavealpha($this->image, true);
$this->GD_copyresampled();
}
}
class ImageJPG extends ImageBase {
public function from() {
$this->image = @imagecreatefromjpeg($this->src);
}
public function to($src) {
imagejpeg($this->image, $src);
}
}
class ImageJPEG extends ImageJPG {
}
class ImageBMP extends ImageBase {
public function from() {
$this->image = @imagecreatefrombmp($this->src);
}
public function to($src) {
imagebmp($this->image, $src);
}
}
/*********************************************/
/* Fonction: imagecreatefrombmp */
/* Author: DHKold */
/* Contact: admin@dhkold.com */
/* Date: The 15th of June 2005 */
/* Version: 2.0B */
/*********************************************/
function imagecreatefrombmp($filename) {
if (! $f1 = fopen($filename,"rb")) return FALSE;
$FILE = unpack("vfile_type/Vfile_size/Vreserved/Vbitmap_offset", fread($f1,14));
if ($FILE['file_type'] != 19778) return FALSE;
$BMP = unpack('Vheader_size/Vwidth/Vheight/vplanes/vbits_per_pixel'.
'/Vcompression/Vsize_bitmap/Vhoriz_resolution'.
'/Vvert_resolution/Vcolors_used/Vcolors_important', fread($f1,40));
$BMP['colors'] = pow(2,$BMP['bits_per_pixel']);
if ($BMP['size_bitmap'] == 0) $BMP['size_bitmap'] = $FILE['file_size'] - $FILE['bitmap_offset'];
$BMP['bytes_per_pixel'] = $BMP['bits_per_pixel']/8;
$BMP['bytes_per_pixel2'] = ceil($BMP['bytes_per_pixel']);
$BMP['decal'] = ($BMP['width']*$BMP['bytes_per_pixel']/4);
$BMP['decal'] -= floor($BMP['width']*$BMP['bytes_per_pixel']/4);
$BMP['decal'] = 4-(4*$BMP['decal']);
if ($BMP['decal'] == 4) $BMP['decal'] = 0;
$PALETTE = array();
if ($BMP['colors'] < 16777216)
{
$PALETTE = unpack('V'.$BMP['colors'], fread($f1,$BMP['colors']*4));
}
$IMG = fread($f1,$BMP['size_bitmap']);
$VIDE = chr(0);
$res = imagecreatetruecolor($BMP['width'],$BMP['height']);
$P = 0;
$Y = $BMP['height']-1;
while ($Y >= 0)
{
$X=0;
while ($X < $BMP['width'])
{
if ($BMP['bits_per_pixel'] == 24)
$COLOR = unpack("V",substr($IMG,$P,3).$VIDE);
elseif ($BMP['bits_per_pixel'] == 16)
{
$COLOR = unpack("n",substr($IMG,$P,2));
$COLOR[1] = $PALETTE[$COLOR[1]+1];
}
elseif ($BMP['bits_per_pixel'] == 8)
{
$COLOR = unpack("n",$VIDE.substr($IMG,$P,1));
$COLOR[1] = $PALETTE[$COLOR[1]+1];
}
elseif ($BMP['bits_per_pixel'] == 4)
{
$COLOR = unpack("n",$VIDE.substr($IMG,floor($P),1));
if (($P*2)%2 == 0) $COLOR[1] = ($COLOR[1] >> 4) ; else $COLOR[1] = ($COLOR[1] & 0x0F);
$COLOR[1] = $PALETTE[$COLOR[1]+1];
}
elseif ($BMP['bits_per_pixel'] == 1)
{
$COLOR = unpack("n",$VIDE.substr($IMG,floor($P),1));
if (($P*8)%8 == 0) $COLOR[1] = $COLOR[1] >>7;
elseif (($P*8)%8 == 1) $COLOR[1] = ($COLOR[1] & 0x40)>>6;
elseif (($P*8)%8 == 2) $COLOR[1] = ($COLOR[1] & 0x20)>>5;
elseif (($P*8)%8 == 3) $COLOR[1] = ($COLOR[1] & 0x10)>>4;
elseif (($P*8)%8 == 4) $COLOR[1] = ($COLOR[1] & 0x8)>>3;
elseif (($P*8)%8 == 5) $COLOR[1] = ($COLOR[1] & 0x4)>>2;
elseif (($P*8)%8 == 6) $COLOR[1] = ($COLOR[1] & 0x2)>>1;
elseif (($P*8)%8 == 7) $COLOR[1] = ($COLOR[1] & 0x1);
$COLOR[1] = $PALETTE[$COLOR[1]+1];
}
else
return FALSE;
imagesetpixel($res,$X,$Y,$COLOR[1]);
$X++;
$P += $BMP['bytes_per_pixel'];
}
$Y--;
$P+=$BMP['decal'];
}
fclose($f1);
return $res;
}
function imagebmp(&$img, $filename='') {
$widthOrig = imagesx($img);
$widthFloor = ((floor($widthOrig/16))*16);
$widthCeil = ((ceil($widthOrig/16))*16);
$height = imagesy($img);
$size = ($widthCeil*$height*3)+54;
// Bitmap File Header
$result = 'BM'; // header (2b)
$result .= int_to_dword($size); // size of file (4b)
$result .= int_to_dword(0); // reserved (4b)
$result .= int_to_dword(54); // byte location in the file which is first byte of IMAGE (4b)
// Bitmap Info Header
$result .= int_to_dword(40); // Size of BITMAPINFOHEADER (4b)
$result .= int_to_dword($widthCeil); // width of bitmap (4b)
$result .= int_to_dword($height); // height of bitmap (4b)
$result .= int_to_word(1); // biPlanes = 1 (2b)
$result .= int_to_word(24); // biBitCount = {1 (mono) or 4 (16 clr ) or 8 (256 clr) or 24 (16 Mil)} (2b
$result .= int_to_dword(0); // RLE COMPRESSION (4b)
$result .= int_to_dword(0); // width x height (4b)
$result .= int_to_dword(0); // biXPelsPerMeter (4b)
$result .= int_to_dword(0); // biYPelsPerMeter (4b)
$result .= int_to_dword(0); // Number of palettes used (4b)
$result .= int_to_dword(0); // Number of important colour (4b)
// is faster than chr()
$arrChr = array();
for($i=0; $i<256; $i++){
$arrChr[$i] = chr($i);
}
?>
// creates image data
$bgfillcolor = array('red'=>0, 'green'=>0, 'blue'=>0);
// bottom to top - left to right - attention blue green red !!!
$y=$height-1;
for ($y2=0; $y2<$height; $y2++) {
for ($x=0; $x<$widthFloor; ) {
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
$rgb = imagecolorsforindex($img, imagecolorat($img, $x++, $y));
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
}
for ($x=$widthFloor; $x<$widthCeil; $x++) {
$rgb = ($x<$widthOrig) ? imagecolorsforindex($img, imagecolorat($img, $x, $y)) : $bgfillcolor;
$result .= $arrChr[$rgb['blue']].$arrChr[$rgb['green']].$arrChr[$rgb['red']];
}
$y--;
}
// see imagegif
if($filename == '') {
echo $result;
} else {
$file = fopen($filename, 'wb');
fwrite($file, $result);
fclose($file);
}
}
// imagebmp helpers
function int_to_dword($n) {
return chr($n & 255).chr(($n >> 8) & 255).chr(($n >> 16) & 255).chr(($n >> 24) & 255);
}
function int_to_word($n) {
return chr($n & 255).chr(($n >> 8) & 255);
}

View File

@ -1,283 +1,287 @@
<?php
if($_SERVER['SCRIPT_FILENAME'] == str_replace('\\', '/', __FILE__)) {
// You cannot request this file directly.
header('Location: ../', true, 302);
exit;
/*
* Copyright (c) 2010-2012 Tinyboard Development Group
*/
if(realpath($_SERVER['SCRIPT_FILENAME']) == str_replace('\\', '/', __FILE__)) {
// You cannot request this file directly.
exit;
}
// create a hash/salt pair for validate logins
function mkhash($username, $password, $salt = false) {
global $config;
if(!$salt) {
// create some sort of salt for the hash
$salt = substr(base64_encode(sha1(rand() . time(), true) . $config['cookies']['salt']), 0, 15);
$generated_salt = true;
}
// create a hash/salt pair for validate logins
function mkhash($username, $password, $salt = false) {
global $config;
if(!$salt) {
// create some sort of salt for the hash
$salt = substr(base64_encode(sha1(rand() . time(), true) . $config['cookies']['salt']), 0, 15);
$generated_salt = true;
}
// generate hash (method is not important as long as it's strong)
$hash = substr(base64_encode(md5($username . sha1($username . $password . $salt . ($config['mod']['lock_ip'] ? $_SERVER['REMOTE_ADDR'] : ''), true), true)), 0, 20);
if(isset($generated_salt))
return Array($hash, $salt);
else
return $hash;
// generate hash (method is not important as long as it's strong)
$hash = substr(base64_encode(md5($username . sha1($username . $password . $salt . ($config['mod']['lock_ip'] ? $_SERVER['REMOTE_ADDR'] : ''), true), true)), 0, 20);
if(isset($generated_salt))
return Array($hash, $salt);
else
return $hash;
}
function login($username, $password, $makehash=true) {
global $mod;
// SHA1 password
if($makehash) {
$password = sha1($password);
}
function login($username, $password, $makehash=true) {
global $mod;
// SHA1 password
if($makehash) {
$password = sha1($password);
}
$query = prepare("SELECT `id`,`type`,`boards` FROM `mods` WHERE `username` = :username AND `password` = :password LIMIT 1");
$query->bindValue(':username', $username);
$query->bindValue(':password', $password);
$query->execute() or error(db_error($query));
if($user = $query->fetch()) {
return $mod = Array(
'id' => $user['id'],
'type' => $user['type'],
'username' => $username,
'hash' => mkhash($username, $password),
'boards' => explode(',', $user['boards'])
);
} else return false;
}
$query = prepare("SELECT `id`,`type`,`boards` FROM `mods` WHERE `username` = :username AND `password` = :password LIMIT 1");
$query->bindValue(':username', $username);
$query->bindValue(':password', $password);
$query->execute() or error(db_error($query));
function setCookies() {
global $mod, $config;
if(!$mod)
error('setCookies() was called for a non-moderator!');
setcookie($config['cookies']['mod'],
$mod['username'] . // username
':' .
$mod['hash'][0] . // password
':' .
$mod['hash'][1], // salt
time() + $config['cookies']['expire'], $config['cookies']['jail'] ? $config['cookies']['path'] : '/', null, false, true);
}
function destroyCookies() {
global $config;
// Delete the cookies
setcookie($config['cookies']['mod'], 'deleted', time() - $config['cookies']['expire'], $config['cookies']['jail']?$config['cookies']['path'] : '/', null, false, true);
}
function create_pm_header() {
global $mod;
$query = prepare("SELECT `id` FROM `pms` WHERE `to` = :id AND `unread` = 1");
$query->bindValue(':id', $mod['id'], PDO::PARAM_INT);
$query->execute() or error(db_error($query));
if($pm = $query->fetch()) {
return Array('id' => $pm['id'], 'waiting' => $query->rowCount() - 1);
}
return false;
}
function modLog($action, $_board=null) {
global $mod, $board, $config;
$query = prepare("INSERT INTO `modlogs` VALUES (:id, :ip, :board, :time, :text)");
$query->bindValue(':id', $mod['id'], PDO::PARAM_INT);
$query->bindValue(':ip', $_SERVER['REMOTE_ADDR']);
$query->bindValue(':time', time(), PDO::PARAM_INT);
$query->bindValue(':text', $action);
if(isset($_board))
$query->bindValue(':board', $_board);
elseif(isset($board))
$query->bindValue(':board', $board['id']);
else
$query->bindValue(':board', null, PDO::PARAM_NULL);
$query->execute() or error(db_error($query));
if($config['syslog'])
_syslog(LOG_INFO, '[mod/' . $mod['username'] . ']: ' . $action);
}
// Generates a <ul> element with a list of linked
// boards and their subtitles. (without the <ul> opening and ending tags)
function ulBoards() {
global $mod, $config;
$body = '';
// List of boards
$boards = listBoards();
foreach($boards as &$b) {
$body .= '<li>' .
'<a href="?/' .
sprintf($config['board_path'], $b['uri']) . $config['file_index'] .
'">' .
sprintf($config['board_abbreviation'], $b['uri']) .
'</a> - ' .
$b['title'] .
(isset($b['subtitle']) ? '<span class="unimportant"> — ' . $b['subtitle'] . '</span>' : '') .
($mod['type'] >= $config['mod']['manageboards'] ?
' <a href="?/board/' . $b['uri'] . '" class="unimportant">[manage]</a>' : '') .
'</li>';
}
if($mod['type'] >= $config['mod']['newboard']) {
$body .= '<li style="margin-top:15px;"><a href="?/new"><strong>' . _('Create new board') . '</strong></a></li>';
}
return $body;
}
function form_newBan($ip=null, $reason='', $continue=false, $delete=false, $board=false, $allow_public = false) {
global $config, $mod;
$boards = listBoards();
$__boards = '<li><input type="radio" checked="checked" name="board_id" id="board_*" value="-1"/> <label style="display:inline" for="board_*"><em>' . _('all boards') . '</em></label></li>';
foreach($boards as &$_board) {
$__boards .= '<li>' .
'<input type="radio" name="board_id" id="board_' . $_board['uri'] . '" value="' . $_board['id'] . '">' .
'<label style="display:inline" for="board_' . $_board['uri'] . '"> ' .
($_board['uri'] == '*' ?
'<em>"*"</em>'
:
sprintf($config['board_abbreviation'], $_board['uri'])
) .
' - ' . $_board['title'] .
'</label>' .
'</li>';
}
return '<fieldset><legend>New ban</legend>' .
'<form action="?/ban" method="post">' .
($continue ? '<input type="hidden" name="continue" value="' . htmlentities($continue) . '" />' : '') .
($delete || $allow_public ? '<input type="hidden" name="' . (!$allow_public ? 'delete' : 'post') . '" value="' . htmlentities($delete) . '" />' : '') .
($board ? '<input type="hidden" name="board" value="' . htmlentities($board) . '" />' : '') .
'<table>' .
'<tr>' .
'<th><label for="ip">IP ' .
($config['ban_cidr'] ? '<span class="unimportant">(or subnet)' : '') .
'</span></label></th>' .
'<td><input type="text" name="ip" id="ip" size="30" maxlength="30" ' .
(isset($ip) ?
'value="' . htmlentities($ip) . '" ' : ''
) .
'/></td>' .
'</tr>' .
'<tr>' .
'<th><label for="reason">Reason</label></th>' .
'<td><textarea name="reason" id="reason" rows="5" cols="30">' .
htmlentities($reason) .
'</textarea></td>' .
'</tr>' .
($mod['type'] >= $config['mod']['public_ban'] && $allow_public ?
'<tr>' .
'<th><label for="message">Message</label></th>' .
'<td><input type="checkbox" id="public_message" name="public_message"/>' .
' <input type="text" name="message" id="message" size="35" maxlength="200" value="' . htmlentities($config['mod']['default_ban_message']) . '" />' .
' <span class="unimportant">(public; attached to post)</span></td>' .
'<script type="text/javascript">' .
'document.getElementById(\'message\').disabled = true;' .
'document.getElementById(\'public_message\').onchange = function() {' .
'document.getElementById(\'message\').disabled = !this.checked;' .
'}' .
'</script>' .
'</tr>'
: '') .
'<tr>' .
'<th><label for="length">Length</label></th>' .
'<td><input type="text" name="length" id="length" size="20" maxlength="40" />' .
' <span class="unimportant">(eg. "2d1h30m" or "2 days")</span></td>' .
'</tr>' .
'<tr>' .
'<th>Board</th>' .
'<td><ul style="list-style:none;padding:2px 5px">' . $__boards . '</tl></td>' .
'</tr>' .
'<tr>' .
'<td></td>' .
'<td><input name="new_ban" type="submit" value="New Ban" /></td>' .
'</tr>' .
'</table>' .
'</form>' .
'</fieldset>';
}
function form_newBoard() {
return '<fieldset><legend>New board</legend>' .
'<form action="?/new" method="post">' .
'<table>' .
'<tr>' .
'<th><label for="board">URI</label></th>' .
'<td><input type="text" name="uri" id="board" size="10" />' .
' <span class="unimportant">(eg. "b"; "mu")</span></td>' .
'</tr>' .
'<tr>' .
'<th><label for="title">Title</label></th>' .
'<td><input type="text" name="title" id="title" size="25" />' .
' <span class="unimportant">(eg. "Random")</span></td>' .
'</tr>' .
'<tr>' .
'<th><label for="subtitle">Subtitle</label></th>' .
'<td><input type="text" name="subtitle" id="subtitle" size="25" />' .
' <span class="unimportant">(optional)</span></td>' .
'</tr>' .
'<tr>' .
'<td></td>' .
'<td><input name="new_board" type="submit" value="New Board" /></td>' .
'</tr>' .
'</table>' .
'</form>' .
'</fieldset>';
}
function removeBan($id) {
global $config, $memcached;
$query = prepare("DELETE FROM `bans` WHERE `id` = :id");
$query->bindValue(':id', $id, PDO::PARAM_INT);
$query->execute() or error(db_error($query));
//if($config['memcached']['enabled']) {
// Remove cached ban
// TODO
// $memcached->delete("ban_{$id}");
//}
}
// Validate session
if(isset($_COOKIE[$config['cookies']['mod']])) {
// Should be username:hash:salt
$cookie = explode(':', $_COOKIE[$config['cookies']['mod']]);
if(count($cookie) != 3) {
destroyCookies();
error($config['error']['malformed']);
}
$query = prepare("SELECT `id`, `type`, `boards`, `password` FROM `mods` WHERE `username` = :username LIMIT 1");
$query->bindValue(':username', $cookie[0]);
$query->execute() or error(db_error($query));
$user = $query->fetch();
// validate password hash
if($cookie[1] != mkhash($cookie[0], $user['password'], $cookie[2])) {
// Malformed cookies
destroyCookies();
error($config['error']['malformed']);
}
$mod = Array(
if($user = $query->fetch()) {
return $mod = Array(
'id' => $user['id'],
'type' => $user['type'],
'username' => $cookie[0],
'username' => $username,
'hash' => mkhash($username, $password),
'boards' => explode(',', $user['boards'])
);
}
);
} else return false;
}
function setCookies() {
global $mod, $config;
if(!$mod)
error('setCookies() was called for a non-moderator!');
setcookie($config['cookies']['mod'],
$mod['username'] . // username
':' .
$mod['hash'][0] . // password
':' .
$mod['hash'][1], // salt
time() + $config['cookies']['expire'], $config['cookies']['jail'] ? $config['cookies']['path'] : '/', null, false, true);
}
function destroyCookies() {
global $config;
// Delete the cookies
setcookie($config['cookies']['mod'], 'deleted', time() - $config['cookies']['expire'], $config['cookies']['jail']?$config['cookies']['path'] : '/', null, false, true);
}
function create_pm_header() {
global $mod;
$query = prepare("SELECT `id` FROM `pms` WHERE `to` = :id AND `unread` = 1");
$query->bindValue(':id', $mod['id'], PDO::PARAM_INT);
$query->execute() or error(db_error($query));
if($pm = $query->fetch()) {
return Array('id' => $pm['id'], 'waiting' => $query->rowCount() - 1);
}
return false;
}
function modLog($action, $_board=null) {
global $mod, $board, $config;
$query = prepare("INSERT INTO `modlogs` VALUES (:id, :ip, :board, :time, :text)");
$query->bindValue(':id', $mod['id'], PDO::PARAM_INT);
$query->bindValue(':ip', $_SERVER['REMOTE_ADDR']);
$query->bindValue(':time', time(), PDO::PARAM_INT);
$query->bindValue(':text', $action);
if(isset($_board))
$query->bindValue(':board', $_board);
elseif(isset($board))
$query->bindValue(':board', $board['id']);
else
$query->bindValue(':board', null, PDO::PARAM_NULL);
$query->execute() or error(db_error($query));
if($config['syslog'])
_syslog(LOG_INFO, '[mod/' . $mod['username'] . ']: ' . $action);
}
// Generates a <ul> element with a list of linked
// boards and their subtitles. (without the <ul> opening and ending tags)
function ulBoards() {
global $mod, $config;
$body = '';
// List of boards
$boards = listBoards();
foreach($boards as &$b) {
$body .= '<li>' .
'<a href="?/' .
sprintf($config['board_path'], $b['uri']) . $config['file_index'] .
'">' .
sprintf($config['board_abbreviation'], $b['uri']) .
'</a> - ' .
$b['title'] .
(isset($b['subtitle']) ? '<span class="unimportant"> — ' . $b['subtitle'] . '</span>' : '') .
($mod['type'] >= $config['mod']['manageboards'] ?
' <a href="?/board/' . $b['uri'] . '" class="unimportant">[manage]</a>' : '') .
'</li>';
}
if($mod['type'] >= $config['mod']['newboard']) {
$body .= '<li style="margin-top:15px;"><a href="?/new"><strong>' . _('Create new board') . '</strong></a></li>';
}
return $body;
}
function form_newBan($ip=null, $reason='', $continue=false, $delete=false, $board=false, $allow_public = false) {
global $config, $mod;
$boards = listBoards();
$__boards = '<li><input type="radio" checked="checked" name="board_id" id="board_*" value="-1"/> <label style="display:inline" for="board_*"><em>' . _('all boards') . '</em></label></li>';
foreach($boards as &$_board) {
$__boards .= '<li>' .
'<input type="radio" name="board_id" id="board_' . $_board['uri'] . '" value="' . $_board['id'] . '">' .
'<label style="display:inline" for="board_' . $_board['uri'] . '"> ' .
($_board['uri'] == '*' ?
'<em>"*"</em>'
:
sprintf($config['board_abbreviation'], $_board['uri'])
) .
' - ' . $_board['title'] .
'</label>' .
'</li>';
}
return '<fieldset><legend>New ban</legend>' .
'<form action="?/ban" method="post">' .
($continue ? '<input type="hidden" name="continue" value="' . htmlentities($continue) . '" />' : '') .
($delete || $allow_public ? '<input type="hidden" name="' . (!$allow_public ? 'delete' : 'post') . '" value="' . htmlentities($delete) . '" />' : '') .
($board ? '<input type="hidden" name="board" value="' . htmlentities($board) . '" />' : '') .
'<table>' .
'<tr>' .
'<th><label for="ip">IP ' .
($config['ban_cidr'] ? '<span class="unimportant">(or subnet)' : '') .
'</span></label></th>' .
'<td><input type="text" name="ip" id="ip" size="30" maxlength="30" ' .
(isset($ip) ?
'value="' . htmlentities($ip) . '" ' : ''
) .
'/></td>' .
'</tr>' .
'<tr>' .
'<th><label for="reason">Reason</label></th>' .
'<td><textarea name="reason" id="reason" rows="5" cols="30">' .
htmlentities($reason) .
'</textarea></td>' .
'</tr>' .
($mod['type'] >= $config['mod']['public_ban'] && $allow_public ?
'<tr>' .
'<th><label for="message">Message</label></th>' .
'<td><input type="checkbox" id="public_message" name="public_message"/>' .
' <input type="text" name="message" id="message" size="35" maxlength="200" value="' . htmlentities($config['mod']['default_ban_message']) . '" />' .
' <span class="unimportant">(public; attached to post)</span></td>' .
'<script type="text/javascript">' .
'document.getElementById(\'message\').disabled = true;' .
'document.getElementById(\'public_message\').onchange = function() {' .
'document.getElementById(\'message\').disabled = !this.checked;' .
'}' .
'</script>' .
'</tr>'
: '') .
'<tr>' .
'<th><label for="length">Length</label></th>' .
'<td><input type="text" name="length" id="length" size="20" maxlength="40" />' .
' <span class="unimportant">(eg. "2d1h30m" or "2 days")</span></td>' .
'</tr>' .
'<tr>' .
'<th>Board</th>' .
'<td><ul style="list-style:none;padding:2px 5px">' . $__boards . '</tl></td>' .
'</tr>' .
'<tr>' .
'<td></td>' .
'<td><input name="new_ban" type="submit" value="New Ban" /></td>' .
'</tr>' .
'</table>' .
'</form>' .
'</fieldset>';
}
function form_newBoard() {
return '<fieldset><legend>New board</legend>' .
'<form action="?/new" method="post">' .
'<table>' .
'<tr>' .
'<th><label for="board">URI</label></th>' .
'<td><input type="text" name="uri" id="board" size="10" />' .
' <span class="unimportant">(eg. "b"; "mu")</span></td>' .
'</tr>' .
'<tr>' .
'<th><label for="title">Title</label></th>' .
'<td><input type="text" name="title" id="title" size="25" />' .
' <span class="unimportant">(eg. "Random")</span></td>' .
'</tr>' .
'<tr>' .
'<th><label for="subtitle">Subtitle</label></th>' .
'<td><input type="text" name="subtitle" id="subtitle" size="25" />' .
' <span class="unimportant">(optional)</span></td>' .
'</tr>' .
'<tr>' .
'<td></td>' .
'<td><input name="new_board" type="submit" value="New Board" /></td>' .
'</tr>' .
'</table>' .
'</form>' .
'</fieldset>';
}
function removeBan($id) {
global $config, $memcached;
$query = prepare("DELETE FROM `bans` WHERE `id` = :id");
$query->bindValue(':id', $id, PDO::PARAM_INT);
$query->execute() or error(db_error($query));
//if($config['memcached']['enabled']) {
// Remove cached ban
// TODO
// $memcached->delete("ban_{$id}");
//}
}
// Validate session
if(isset($_COOKIE[$config['cookies']['mod']])) {
// Should be username:hash:salt
$cookie = explode(':', $_COOKIE[$config['cookies']['mod']]);
if(count($cookie) != 3) {
destroyCookies();
error($config['error']['malformed']);
}
$query = prepare("SELECT `id`, `type`, `boards`, `password` FROM `mods` WHERE `username` = :username LIMIT 1");
$query->bindValue(':username', $cookie[0]);
$query->execute() or error(db_error($query));
$user = $query->fetch();
// validate password hash
if($cookie[1] != mkhash($cookie[0], $user['password'], $cookie[2])) {
// Malformed cookies
destroyCookies();
error($config['error']['malformed']);
}
$mod = Array(
'id' => $user['id'],
'type' => $user['type'],
'username' => $cookie[0],
'boards' => explode(',', $user['boards'])
);
}

View File

@ -1,57 +1,67 @@
<?php
class Remote {
public function __construct($config) {
foreach($config as $name => $value) {
$this->{$name} = $value;
}
$methods = Array();
if(!isset($this->auth['method']))
error('Unspecified authentication method.');
// Connect
$this->connection = ssh2_connect($this->host, isset($this->port) ? $this->port : 22, $methods);
switch($this->auth['method']) {
case 'pubkey':
if(!isset($this->auth['public']))
error('Public key filename not specified.');
if(!isset($this->auth['private']))
error('Private key filename not specified.');
if(!ssh2_auth_pubkey_file($this->connection, $this->auth['username'], $this->auth['public'], $this->auth['private'], isset($this->auth['passphrase']) ? $this->auth['passphrase']: null))
error('Public key authentication failed.');
break;
case 'plain':
if(!ssh2_auth_password($this->connection, $this->auth['username'], $this->auth['password']))
error('Plain-text authentication failed.');
break;
default:
error('Unknown authentication method: "' . $this->auth['method'] . '".');
}
/*
* Copyright (c) 2010-2012 Tinyboard Development Group
*/
if(realpath($_SERVER['SCRIPT_FILENAME']) == str_replace('\\', '/', __FILE__)) {
// You cannot request this file directly.
exit;
}
class Remote {
public function __construct($config) {
foreach($config as $name => $value) {
$this->{$name} = $value;
}
public function write($data, $remote_path) {
global $config;
switch($this->type) {
case 'sftp':
$sftp = ssh2_sftp($this->connection);
file_write('ssh2.sftp://' . $sftp . $remote_path, $data, true);
break;
case 'scp':
$file = tempnam($config['tmp'], 'tinyboard-scp');
// Write to temp file
file_write($file, $data);
ssh2_scp_send($this->connection, $file, $remote_path, 0755);
break;
default:
error('Unknown send method.');
}
$methods = Array();
if(!isset($this->auth['method']))
error('Unspecified authentication method.');
// Connect
$this->connection = ssh2_connect($this->host, isset($this->port) ? $this->port : 22, $methods);
switch($this->auth['method']) {
case 'pubkey':
if(!isset($this->auth['public']))
error('Public key filename not specified.');
if(!isset($this->auth['private']))
error('Private key filename not specified.');
if(!ssh2_auth_pubkey_file($this->connection, $this->auth['username'], $this->auth['public'], $this->auth['private'], isset($this->auth['passphrase']) ? $this->auth['passphrase']: null))
error('Public key authentication failed.');
break;
case 'plain':
if(!ssh2_auth_password($this->connection, $this->auth['username'], $this->auth['password']))
error('Plain-text authentication failed.');
break;
default:
error('Unknown authentication method: "' . $this->auth['method'] . '".');
}
};
?>
}
public function write($data, $remote_path) {
global $config;
switch($this->type) {
case 'sftp':
$sftp = ssh2_sftp($this->connection);
file_write('ssh2.sftp://' . $sftp . $remote_path, $data, true);
break;
case 'scp':
$file = tempnam($config['tmp'], 'tinyboard-scp');
// Write to temp file
file_write($file, $data);
ssh2_scp_send($this->connection, $file, $remote_path, 0755);
break;
default:
error('Unknown send method.');
}
}
};

View File

@ -1,57 +1,72 @@
<?php
if($_SERVER['SCRIPT_FILENAME'] == str_replace('\\', '/', __FILE__)) {
// You cannot request this file directly.
header('Location: ../', true, 302);
exit;
}
/*
* Copyright (c) 2010-2012 Tinyboard Development Group
*/
if(realpath($_SERVER['SCRIPT_FILENAME']) == str_replace('\\', '/', __FILE__)) {
// You cannot request this file directly.
exit;
}
$twig = false;
function load_twig() {
global $twig, $config;
require 'lib/Twig/Autoloader.php';
Twig_Autoloader::register();
Twig_Autoloader::autoload('Twig_Extensions_Node_Trans');
Twig_Autoloader::autoload('Twig_Extensions_TokenParser_Trans');
Twig_Autoloader::autoload('Twig_Extensions_Extension_I18n');
Twig_Autoloader::autoload('Twig_Extensions_Extension_Tinyboard');
$loader = new Twig_Loader_Filesystem($config['dir']['template']);
$loader->setPaths($config['dir']['template']);
$twig = new Twig_Environment($loader, Array(
'autoescape' => false,
'cache' => "{$config['dir']['template']}/cache",
'debug' => ($config['debug'] ? true : false),
));
$twig->addExtension(new Twig_Extensions_Extension_Tinyboard());
$twig->addExtension(new Twig_Extensions_Extension_I18n());
}
function Element($templateFile, array $options) {
global $config, $debug, $twig;
function Element($templateFile, array $options) {
global $config, $debug, $loader;
if(function_exists('create_pm_header') && ((isset($options['mod']) && $options['mod']) || isset($options['__mod']))) {
$options['pm'] = create_pm_header();
}
if(isset($options['body']) && $config['debug']) {
if(isset($debug['start'])) {
$debug['time'] = '~' . round((microtime(true) - $debug['start']) * 1000, 2) . 'ms';
unset($debug['start']);
}
$options['body'] .= '<h3>Debug</h3><pre style="white-space: pre-wrap;font-size: 10px;">' . str_replace("\n", '<br/>', utf8tohtml(print_r($debug, true))) . '</pre>';
}
$loader->setPaths($config['dir']['template']);
$twig = new Twig_Environment($loader, Array(
'autoescape' => false,
'cache' => "{$config['dir']['template']}/cache",
'debug' => ($config['debug'] ? true : false),
));
$twig->addExtension(new Twig_Extensions_Extension_Tinyboard());
$twig->addExtension(new Twig_Extensions_Extension_I18n());
// Read the template file
if(@file_get_contents("{$config['dir']['template']}/${templateFile}")) {
$body = $twig->render($templateFile, $options);
if($config['minify_html'] && preg_match('/\.html$/', $templateFile)) {
$body = trim(preg_replace("/[\t\r\n]/", '', $body));
}
return $body;
} else {
throw new Exception("Template file '${templateFile}' does not exist or is empty in '{$config['dir']['template']}'!");
}
if(!$twig)
load_twig();
if(function_exists('create_pm_header') && ((isset($options['mod']) && $options['mod']) || isset($options['__mod']))) {
$options['pm'] = create_pm_header();
}
?>
if(isset($options['body']) && $config['debug']) {
if(isset($debug['start'])) {
$debug['time'] = '~' . round((microtime(true) - $debug['start']) * 1000, 2) . 'ms';
unset($debug['start']);
}
$debug['included'] = get_included_files();
$debug['memory'] = round(memory_get_usage(true) / (1024 * 1024), 2) . ' MiB';
$options['body'] .=
'<h3>Debug</h3><pre style="white-space: pre-wrap;font-size: 10px;">' .
str_replace("\n", '<br/>', utf8tohtml(print_r($debug, true))) .
'</pre>';
}
// Read the template file
if(@file_get_contents("{$config['dir']['template']}/${templateFile}")) {
$body = $twig->render($templateFile, $options);
if($config['minify_html'] && preg_match('/\.html$/', $templateFile)) {
$body = trim(preg_replace("/[\t\r\n]/", '', $body));
}
return $body;
} else {
throw new Exception("Template file '${templateFile}' does not exist or is empty in '{$config['dir']['template']}'!");
}
}

View File

@ -1,10 +0,0 @@
<?php
if($_SERVER['SCRIPT_FILENAME'] == str_replace('\\', '/', __FILE__)) {
// You cannot request this file directly.
header('Location: ../', true, 302);
exit;
}
// 'false' means that the user is not logged in as a moderator
$mod = false;

File diff suppressed because it is too large Load Diff

5736
mod.php

File diff suppressed because it is too large Load Diff

1135
post.php

File diff suppressed because it is too large Load Diff