1
0
mirror of https://github.com/vichan-devel/vichan.git synced 2025-02-17 11:28:41 +01:00

large cleanup

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

View File

@ -1,5 +1,14 @@
<?php <?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 { class Cache {
private static $cache; private static $cache;
public static function init() { public static function init() {

View File

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

View File

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

View File

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

View File

@ -1,5 +1,14 @@
<?php <?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() { function event() {
global $events; global $events;

View File

@ -1,5 +1,14 @@
<?php <?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 { class Filter {
private $condition; private $condition;

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

5736
mod.php

File diff suppressed because it is too large Load Diff

1135
post.php

File diff suppressed because it is too large Load Diff