@@ -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() { | |||
@@ -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( | |||
// '/^<code>(.+)<\/code>/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&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&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&server=vimeo.com&show_title=0&show_byline=0&show_portrait=0&color=00adef&fullscreen=1&autoplay=0&loop=0" /><embed src="http://vimeo.com/moogaloop.swf?clip_id=$2&server=vimeo.com&show_title=0&show_byline=0&show_portrait=0&color=00adef&fullscreen=1&autoplay=0&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; | |||
} | |||
?> | |||
@@ -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); | |||
if($config['debug'] && $function == 'execute') { | |||
$start = microtime(true); | |||
} | |||
} | |||
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; | |||
$return = call_user_func_array(array($this->query, $function), $args); | |||
sql_open(); | |||
if($config['debug']) { | |||
$start = microtime(true); | |||
$query = $pdo->query($query); | |||
if(!$query) | |||
return false; | |||
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]; | |||
} | |||
?> | |||
} | |||
@@ -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; | |||
$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); | |||
/* | |||
Stuff to help with the display. | |||
*/ | |||
return $body; | |||
} | |||
function createBoardlist($mod=false) { | |||
global $config; | |||
if(!isset($config['boards'])) return Array('top'=>'','bottom'=>''); | |||
/* | |||
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]; | |||
} | |||
$body = doBoardListPart($config['boards'], $mod?'?/':$config['root']); | |||
if(!preg_match('/\] $/', $body)) | |||
$body = '[' . $body . ']'; | |||
function commaize($n) { | |||
$n = strval($n); | |||
return (intval($n) < 1000) ? $n : commaize(substr($n, 0, -3)) . ',' . substr($n, -3); | |||
} | |||
$body = trim($body); | |||
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 = preg_replace('/\/$/', '', $body); | |||
return $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; | |||
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($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 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( | |||
'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>' | |||
))); | |||
if(defined('STDIN')) { | |||
// Running from CLI | |||
die('Error: ' . $message . "\n"); | |||
} | |||
function loginForm($error=false, $username=false, $redirect=false) { | |||
global $config; | |||
die(Element('page.html', Array( | |||
'index'=>$config['root'], | |||
'title'=>_('Login'), | |||
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, | |||
'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 ? '…' : '') . '</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 ? '…' : '') . '</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; | |||
if(!$cap) | |||
return false; | |||
$body = substr($body, 0, $max_chars); | |||
if($body != $original_body) { | |||
// Remove any corrupt tags at the end | |||
$body = preg_replace('/<([\w]+)?([^>]*)?$/', '', $body); | |||
$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/>'); | |||
// Limit line count | |||
if($lines > $max_lines) { | |||
if(preg_match('/(((.*?)<br\/>){' . $max_lines . '})/', $body, $m)) | |||
$body = $m[0]; | |||
} | |||
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; | |||
$body = substr($body, 0, $max_chars); | |||
return $this->root . $board['dir'] . $config['dir']['res'] . sprintf($config['file_page'], $this->thread) . '#' . $pre . $this->id; | |||
} | |||
public function postControls() { | |||
global $board, $config; | |||
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); | |||
// 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&delete/' . $this->id . '">' . $config['mod']['link_bandelete'] . '</a>'; | |||
$body .= '<span class="toolong">Post too long. Click <a href="' . $url . '">here</a> to view the full text.</span>'; | |||
// 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 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']; | |||
}; | |||
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); | |||
$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; | |||
// 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); | |||
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; | |||
// 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'); | |||
return $this->root . $board['dir'] . $config['dir']['res'] . sprintf($config['file_page'], $this->thread) . '#' . $pre . $this->id; | |||
} | |||
public function postControls() { | |||
global $board, $config; | |||
// 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>'; | |||
$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&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; | |||
// Ban & Delete | |||
if(hasPermission($config['mod']['bandelete'], $board['uri'], $this->mod)) | |||
$built .= ' <a title="Ban & Delete" href="?/' . $board['uri'] . '/ban&delete/' . $this->id . '">' . $config['mod']['link_bandelete'] . '</a>'; | |||
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']; | |||
// 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>'; | |||
$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; | |||
// 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($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; | |||
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>'; | |||
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; | |||
// 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>'; | |||
$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&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 ratio() { | |||
return fraction($this->filex, $this->filey, ':'); | |||
} | |||
public function build($index=false) { | |||
global $board, $config, $debug; | |||
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>'; | |||
$built = Element('post_thread.html', Array('config' => $config, 'board' => $board, 'post' => &$this, 'index' => $index)); | |||
// 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(!$this->mod && $index && $config['cache']['enabled']) { | |||
cache::set($this->cache_key($index), $built); | |||
} | |||
return $built; | |||
if(!empty($built)) | |||
$built = '<span class="controls op">' . $built . '</span>'; | |||
} | |||
function cache_key($index) { | |||
global $board; | |||
return 'thread_' . ($index ? 'index_' : '') . $board['uri'] . '_' . $this->id; | |||
return $built; | |||
} | |||
public function ratio() { | |||
return fraction($this->filex, $this->filey, ':'); | |||
} | |||
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; | |||
} | |||
}; | |||
@@ -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; | |||
@@ -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; | |||
@@ -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; | |||
$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); | |||
} | |||
$thumb->_resize($this->image->image, $width, $height); | |||
return $thumb; | |||
} | |||
public function to($dst) { | |||
$this->image->to($dst); | |||
$this->image = new $classname($this); | |||
if(!$this->image->valid()) { | |||
$this->delete(); | |||
error($config['error']['invalidimg']); | |||
} | |||
public function delete() { | |||
file_unlink($this->src); | |||
} | |||
public function destroy() { | |||
$this->image->_destroy(); | |||
$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']); | |||
} | |||
} | |||
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 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); | |||
} | |||
} | |||
public function GD_resize() { | |||
$this->GD_create(); | |||
$this->GD_copyresampled(); | |||
$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; | |||
} | |||
class ImageBase extends ImageGD { | |||
public $image, $src, $original, $original_width, $original_height, $width, $height; | |||
public function valid() { | |||
return (bool)$this->image; | |||
} | |||
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(); | |||
public function __construct($img) { | |||
if(method_exists($this, 'init')) | |||
$this->init(); | |||
if($img !== false) { | |||
$this->src = $img->src; | |||
$this->from(); | |||
} | |||
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; | |||
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(); | |||
if(method_exists($this, 'resize')) | |||
$this->resize(); | |||
else | |||
// 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(); | |||
$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; | |||
} | |||
} | |||
class ImageImagick extends ImageBase { | |||
public function init() { | |||
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->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; | |||
$this->image->setFormat('gif'); | |||
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; | |||
$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(); | |||
$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; | |||
//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); | |||
} | |||
$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; | |||
class ImageConvert extends ImageBase { | |||
public $width, $height, $temp; | |||
public function init() { | |||
global $config; | |||
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; | |||
$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]; | |||
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!'); | |||
$this->image = true; | |||
} else { | |||
// mark as invalid | |||
$this->image = false; | |||
} | |||
} | |||
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(); | |||
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); | |||
} | |||
} | |||
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(); | |||
} | |||
public function width() { | |||
return $this->width; | |||
} | |||
class ImageJPG extends ImageBase { | |||
public function from() { | |||
$this->image = @imagecreatefromjpeg($this->src); | |||
} | |||
public function to($src) { | |||
imagejpeg($this->image, $src); | |||
} | |||
public function height() { | |||
return $this->height; | |||
} | |||
class ImageJPEG extends ImageJPG { | |||
public function destroy() { | |||
@unlink($this->temp); | |||
$this->temp = false; | |||
} | |||
class ImageBMP extends ImageBase { | |||
public function from() { | |||
$this->image = @imagecreatefrombmp($this->src); | |||
} | |||
public function to($src) { | |||
imagebmp($this->image, $src); | |||
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!'); | |||
} | |||
/*********************************************/ | |||
/* 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)); | |||
} | |||
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(); | |||
} | |||
} | |||
$IMG = fread($f1,$BMP['size_bitmap']); | |||
$VIDE = chr(0); | |||
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(); | |||
} | |||
} | |||
$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); | |||
class ImageJPG extends ImageBase { | |||
public function from() { | |||
$this->image = @imagecreatefromjpeg($this->src); | |||
} | |||
public function to($src) { | |||
imagejpeg($this->image, $src); | |||
} | |||
} | |||
class ImageJPEG extends ImageJPG { | |||
} | |||
return $res; | |||
class ImageBMP extends ImageBase { | |||
public function from() { | |||
$this->image = @imagecreatefrombmp($this->src); | |||
} | |||
function imagebmp(&$img, $filename='') { | |||
$widthOrig = imagesx($img); | |||
$widthFloor = ((floor($widthOrig/16))*16); | |||
$widthCeil = ((ceil($widthOrig/16))*16); | |||
$height = imagesy($img); | |||
public function to($src) { | |||
imagebmp($this->image, $src); | |||
} | |||
} | |||
$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) | |||
/*********************************************/ | |||
/* Fonction: imagecreatefrombmp */ | |||
/* Author: DHKold */ | |||
/* Contact: admin@dhkold.com */ | |||
/* Date: The 15th of June 2005 */ | |||
/* Version: 2.0B */ | |||
/*********************************************/ | |||
// is faster than chr() | |||
$arrChr = array(); | |||
for($i=0; $i<256; $i++){ | |||
$arrChr[$i] = chr($i); | |||
} | |||
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; | |||
// creates image data | |||
$bgfillcolor = array('red'=>0, 'green'=>0, 'blue'=>0); | |||
$PALETTE = array(); | |||
if ($BMP['colors'] < 16777216) | |||
{ | |||
$PALETTE = unpack('V'.$BMP['colors'], fread($f1,$BMP['colors']*4)); | |||
} | |||
// 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--; | |||
} | |||
$IMG = fread($f1,$BMP['size_bitmap']); | |||
$VIDE = chr(0); | |||
// see imagegif | |||
if($filename == '') { | |||
echo $result; | |||
} else { | |||
$file = fopen($filename, 'wb'); | |||
fwrite($file, $result); | |||
fclose($file); | |||
} | |||
$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']; | |||
} | |||
// imagebmp helpers | |||
function int_to_dword($n) { | |||
return chr($n & 255).chr(($n >> 8) & 255).chr(($n >> 16) & 255).chr(($n >> 24) & 255); | |||
$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); | |||
} | |||
function int_to_word($n) { | |||
return chr($n & 255).chr(($n >> 8) & 255); | |||
// 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); | |||
} | |||
?> |
@@ -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; | |||
// 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; | |||
} | |||
if(!$salt) { | |||
// create some sort of salt for the hash | |||
$salt = substr(base64_encode(sha1(rand() . time(), true) . $config['cookies']['salt']), 0, 15); | |||
// 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; | |||
$generated_salt = true; | |||
} | |||
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; | |||
} | |||
// 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); | |||
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); | |||
} | |||
if(isset($generated_salt)) | |||
return Array($hash, $salt); | |||
else | |||
return $hash; | |||
} | |||
function login($username, $password, $makehash=true) { | |||
global $mod; | |||
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); | |||
// SHA1 password | |||
if($makehash) { | |||
$password = sha1($password); | |||
} | |||
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; | |||
$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; | |||
} | |||
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); | |||
} | |||
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); | |||
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>'; | |||
} | |||
// 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; | |||
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; | |||
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>'; | |||
$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>'; | |||
} | |||
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>' . | |||
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>' . | |||
'<td></td>' . | |||
'<td><input name="new_board" type="submit" value="New Board" /></td>' . | |||
'</tr>' . | |||
'</table>' . | |||
'</form>' . | |||
'</fieldset>'; | |||
} | |||
'<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)); | |||
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}"); | |||
//} | |||
//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 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']) | |||
); | |||
// 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']) | |||
); | |||
} | |||
@@ -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.'); | |||
} | |||
}; | |||
?> | |||
} | |||
}; | |||
@@ -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(!$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(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>'; | |||
if($config['minify_html'] && preg_match('/\.html$/', $templateFile)) { | |||
$body = trim(preg_replace("/[\t\r\n]/", '', $body)); | |||
} | |||
$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']}'!"); | |||
} | |||
return $body; | |||
} else { | |||
throw new Exception("Template file '${templateFile}' does not exist or is empty in '{$config['dir']['template']}'!"); | |||
} | |||
?> | |||
} | |||
@@ -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; | |||