Better and faster basic flood prevention, while merging it into $config['filters'].
This commit is contained in:
parent
14ff0fbeb3
commit
f309e4037c
177
inc/config.php
177
inc/config.php
|
@ -168,13 +168,6 @@
|
||||||
* ====================
|
* ====================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Minimum time between between each post by the same IP address.
|
|
||||||
$config['flood_time'] = 10;
|
|
||||||
// Minimum time between between each post with the exact same content AND same IP address.
|
|
||||||
$config['flood_time_ip'] = 120;
|
|
||||||
// Same as above but by a different IP address. (Same content, not necessarily same IP address.)
|
|
||||||
$config['flood_time_same'] = 30;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* To further prevent spam and abuse, you can use DNS blacklists (DNSBL). A DNSBL is a list of IP
|
* To further prevent spam and abuse, you can use DNS blacklists (DNSBL). A DNSBL is a list of IP
|
||||||
* addresses published through the Internet Domain Name Service (DNS) either as a zone file that can be
|
* addresses published through the Internet Domain Name Service (DNS) either as a zone file that can be
|
||||||
|
@ -283,6 +276,118 @@
|
||||||
$config['recaptcha_public'] = '6LcXTcUSAAAAAKBxyFWIt2SO8jwx4W7wcSMRoN3f';
|
$config['recaptcha_public'] = '6LcXTcUSAAAAAKBxyFWIt2SO8jwx4W7wcSMRoN3f';
|
||||||
$config['recaptcha_private'] = '6LcXTcUSAAAAAOGVbVdhmEM1_SyRF4xTKe8jbzf_';
|
$config['recaptcha_private'] = '6LcXTcUSAAAAAOGVbVdhmEM1_SyRF4xTKe8jbzf_';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Custom filters detect certain posts and reject/ban accordingly. They are made up of a condition and an
|
||||||
|
* action (for when ALL conditions are met). As every single post has to be put through each filter,
|
||||||
|
* having hundreds probably isn't ideal as it could slow things down.
|
||||||
|
*
|
||||||
|
* By default, the custom filters array is populated with basic flood prevention conditions. This
|
||||||
|
* includes forcing users to wait at least 5 seconds between posts. To disable (or amend) these flood
|
||||||
|
* prevention settings, you will need to empty the $config['filters'] array first. You can do so by
|
||||||
|
* adding "$config['filters'] = array();" to inc/instance-config.php. Basic flood prevention used to be
|
||||||
|
* controlled solely by config variables such as $config['flood_time'] and $config['flood_time_ip'], and
|
||||||
|
* it still is, as long as you leave the relevant $config['filters'] intact. These old config variables
|
||||||
|
* still exist for backwards-compatability and general convenience.
|
||||||
|
*
|
||||||
|
* Read more: http://tinyboard.org/docs/index.php?p=Config/Filters
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Minimum time between between each post by the same IP address.
|
||||||
|
$config['flood_time'] = 10;
|
||||||
|
// Minimum time between between each post with the exact same content AND same IP address.
|
||||||
|
$config['flood_time_ip'] = 120;
|
||||||
|
// Same as above but by a different IP address. (Same content, not necessarily same IP address.)
|
||||||
|
$config['flood_time_same'] = 30;
|
||||||
|
|
||||||
|
// Minimum time between posts by the same IP address (all boards).
|
||||||
|
$config['filters'][] = array(
|
||||||
|
'condition' => array(
|
||||||
|
'flood-match' => array('ip'), // Only match IP address
|
||||||
|
'flood-time' => &$config['flood_time'] // 10 seconds minimum
|
||||||
|
),
|
||||||
|
'action' => 'reject',
|
||||||
|
'message' => &$config['error']['flood']
|
||||||
|
);
|
||||||
|
|
||||||
|
// Minimum time between posts by the same IP address with the same text.
|
||||||
|
$config['filters'][] = array(
|
||||||
|
'condition' => array(
|
||||||
|
'flood-match' => array('ip', 'body'), // Match IP address and post body
|
||||||
|
'flood-time' => &$config['flood_time_ip'] // 2 minutes minimum
|
||||||
|
),
|
||||||
|
'action' => 'reject',
|
||||||
|
'message' => &$config['error']['flood']
|
||||||
|
);
|
||||||
|
|
||||||
|
// Minimum time between posts with the same text. (Same content, but not always the same IP address.)
|
||||||
|
$config['filters'][] = array(
|
||||||
|
'condition' => array(
|
||||||
|
'flood-match' => array('body'), // Match IP address and post body
|
||||||
|
'flood-time' => &$config['flood_time_same'] // 30 seconds minimum
|
||||||
|
),
|
||||||
|
'action' => 'reject',
|
||||||
|
'message' => &$config['error']['flood']
|
||||||
|
);
|
||||||
|
|
||||||
|
// Example: Minimum time between posts with the same file hash.
|
||||||
|
// $config['filters'][] = array(
|
||||||
|
// 'condition' => array(
|
||||||
|
// 'flood-match' => array('file'), // Match file hash
|
||||||
|
// 'flood-time' => 60 * 2 // 2 minutes minimum
|
||||||
|
// ),
|
||||||
|
// 'action' => 'reject',
|
||||||
|
// 'message' => &$config['error']['flood']
|
||||||
|
// );
|
||||||
|
|
||||||
|
// An example of blocking an imaginary known spammer, who keeps posting a reply with the name "surgeon",
|
||||||
|
// ending his posts with "regards, the surgeon" or similar.
|
||||||
|
// $config['filters'][] = array(
|
||||||
|
// 'condition' => array(
|
||||||
|
// 'name' => '/^surgeon$/',
|
||||||
|
// 'body' => '/regards,\s+(the )?surgeon$/i',
|
||||||
|
// 'OP' => false
|
||||||
|
// ),
|
||||||
|
// 'action' => 'reject',
|
||||||
|
// 'message' => 'Go away, spammer.'
|
||||||
|
// );
|
||||||
|
|
||||||
|
// Same as above, but issuing a 3-hour ban instead of just reject the post.
|
||||||
|
// $config['filters'][] = array(
|
||||||
|
// 'condition' => array(
|
||||||
|
// 'name' => '/^surgeon$/',
|
||||||
|
// 'body' => '/regards,\s+(the )?surgeon$/i',
|
||||||
|
// 'OP' => false
|
||||||
|
// ),
|
||||||
|
// 'action' => 'ban',
|
||||||
|
// 'expires' => 60 * 60 * 3, // 3 hours
|
||||||
|
// 'reason' => 'Go away, spammer.'
|
||||||
|
// );
|
||||||
|
|
||||||
|
// PHP 5.3+ (anonymous functions)
|
||||||
|
// There is also a "custom" condition, making the possibilities of this feature pretty much endless.
|
||||||
|
// This is a bad example, because there is already a "name" condition built-in.
|
||||||
|
// $config['filters'][] = array(
|
||||||
|
// 'condition' => array(
|
||||||
|
// 'body' => '/h$/i',
|
||||||
|
// 'OP' => false,
|
||||||
|
// 'custom' => function($post) {
|
||||||
|
// if($post['name'] == 'Anonymous')
|
||||||
|
// return true;
|
||||||
|
// else
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// ),
|
||||||
|
// 'action' => 'reject'
|
||||||
|
// );
|
||||||
|
|
||||||
|
// Filter flood prevention conditions ("flood-match") depend on a table which contains a cache of recent
|
||||||
|
// posts across all boards. This table is automatically purged of older posts, determining the maximum
|
||||||
|
// "age" by looking at each filter. However, when determining the maximum age, Tinyboard does not look
|
||||||
|
// outside the current board. This means that if you have a special flood condition for a specific board
|
||||||
|
// (contained in a board configuration file) which has a flood-time greater than any of those in the
|
||||||
|
// global configuration, you need to set the following variable to the maximum flood-time condition value.
|
||||||
|
// $config['flood_cache'] = 60 * 60 * 24; // 24 hours
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ====================
|
* ====================
|
||||||
* Post settings
|
* Post settings
|
||||||
|
@ -401,57 +506,6 @@
|
||||||
// Require users to see the ban page at least once for a ban even if it has since expired.
|
// Require users to see the ban page at least once for a ban even if it has since expired.
|
||||||
$config['require_ban_view'] = true;
|
$config['require_ban_view'] = true;
|
||||||
|
|
||||||
/*
|
|
||||||
* Custom filters detect certain posts and reject/ban accordingly. They are made up of a
|
|
||||||
* condition and an action (for when ALL conditions are met). As every single post has to
|
|
||||||
* be put through each filter, having hundreds probably isn’t ideal as it could slow things down.
|
|
||||||
*
|
|
||||||
* Read more: http://tinyboard.org/docs/index.php?p=Config/Filters
|
|
||||||
*
|
|
||||||
* This used to be named $config['flood_filters'] (still exists as an alias).
|
|
||||||
*/
|
|
||||||
|
|
||||||
// An example of blocking an imaginary known spammer, who keeps posting a reply with the name "surgeon",
|
|
||||||
// ending his posts with "regards, the surgeon" or similar.
|
|
||||||
// $config['filters'][] = array(
|
|
||||||
// 'condition' => array(
|
|
||||||
// 'name' => '/^surgeon$/',
|
|
||||||
// 'body' => '/regards,\s+(the )?surgeon$/i',
|
|
||||||
// 'OP' => false
|
|
||||||
// ),
|
|
||||||
// 'action' => 'reject',
|
|
||||||
// 'message' => 'Go away, spammer.'
|
|
||||||
// );
|
|
||||||
|
|
||||||
// Same as above, but issuing a 3-hour ban instead of just reject the post.
|
|
||||||
// $config['filters'][] = array(
|
|
||||||
// 'condition' => array(
|
|
||||||
// 'name' => '/^surgeon$/',
|
|
||||||
// 'body' => '/regards,\s+(the )?surgeon$/i',
|
|
||||||
// 'OP' => false
|
|
||||||
// ),
|
|
||||||
// 'action' => 'ban',
|
|
||||||
// 'expires' => 60 * 60 * 3, // 3 hours
|
|
||||||
// 'reason' => 'Go away, spammer.'
|
|
||||||
// );
|
|
||||||
|
|
||||||
// PHP 5.3+ (anonymous functions)
|
|
||||||
// There is also a "custom" condition, making the possibilities of this feature pretty much endless.
|
|
||||||
// This is a bad example, because there is already a "name" condition built-in.
|
|
||||||
// $config['filters'][] = array(
|
|
||||||
// 'condition' => array(
|
|
||||||
// 'body' => '/h$/i',
|
|
||||||
// 'OP' => false,
|
|
||||||
// 'custom' => function($post) {
|
|
||||||
// if($post['name'] == 'Anonymous')
|
|
||||||
// return true;
|
|
||||||
// else
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
// ),
|
|
||||||
// 'action' => 'reject'
|
|
||||||
// );
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ====================
|
* ====================
|
||||||
* Markup settings
|
* Markup settings
|
||||||
|
@ -593,10 +647,6 @@
|
||||||
// that as a thumbnail instead of resizing/redrawing.
|
// that as a thumbnail instead of resizing/redrawing.
|
||||||
$config['minimum_copy_resize'] = false;
|
$config['minimum_copy_resize'] = false;
|
||||||
|
|
||||||
// Image hashing function. There's really no reason to change this.
|
|
||||||
// sha1_file, md5_file, etc. You can also define your own similar function.
|
|
||||||
$config['file_hash'] = 'sha1_file';
|
|
||||||
|
|
||||||
// Maximum image upload size in bytes.
|
// Maximum image upload size in bytes.
|
||||||
$config['max_filesize'] = 10 * 1024 * 1024; // 10MB
|
$config['max_filesize'] = 10 * 1024 * 1024; // 10MB
|
||||||
// Maximum image dimensions.
|
// Maximum image dimensions.
|
||||||
|
@ -1156,7 +1206,8 @@
|
||||||
// Post bypass unoriginal content check on robot-enabled boards
|
// Post bypass unoriginal content check on robot-enabled boards
|
||||||
$config['mod']['postunoriginal'] = ADMIN;
|
$config['mod']['postunoriginal'] = ADMIN;
|
||||||
// Bypass flood check
|
// Bypass flood check
|
||||||
$config['mod']['flood'] = ADMIN;
|
$config['mod']['bypass_filters'] = ADMIN;
|
||||||
|
$config['mod']['flood'] = &$config['mod']['bypass_filters'];
|
||||||
// Raw HTML posting
|
// Raw HTML posting
|
||||||
$config['mod']['rawhtml'] = ADMIN;
|
$config['mod']['rawhtml'] = ADMIN;
|
||||||
|
|
||||||
|
|
109
inc/filters.php
109
inc/filters.php
|
@ -7,6 +7,7 @@
|
||||||
defined('TINYBOARD') or exit;
|
defined('TINYBOARD') or exit;
|
||||||
|
|
||||||
class Filter {
|
class Filter {
|
||||||
|
public $flood_check;
|
||||||
private $condition;
|
private $condition;
|
||||||
|
|
||||||
public function __construct(array $arr) {
|
public function __construct(array $arr) {
|
||||||
|
@ -22,6 +23,56 @@ class Filter {
|
||||||
if (!is_callable($match))
|
if (!is_callable($match))
|
||||||
error('Custom condition for filter is not callable!');
|
error('Custom condition for filter is not callable!');
|
||||||
return $match($post);
|
return $match($post);
|
||||||
|
case 'flood-match':
|
||||||
|
if (!is_array($match))
|
||||||
|
error('Filter condition "flood-match" must be an array.');
|
||||||
|
|
||||||
|
// Filter out "flood" table entries which do not match this filter.
|
||||||
|
|
||||||
|
$flood_check_matched = array();
|
||||||
|
|
||||||
|
foreach ($this->flood_check as $flood_post) {
|
||||||
|
foreach ($match as $flood_match_arg) {
|
||||||
|
switch ($flood_match_arg) {
|
||||||
|
case 'ip':
|
||||||
|
if ($flood_post['ip'] != $_SERVER['REMOTE_ADDR'])
|
||||||
|
continue 3;
|
||||||
|
break;
|
||||||
|
case 'body':
|
||||||
|
if ($flood_post['posthash'] != md5($post['body_nomarkup']))
|
||||||
|
continue 3;
|
||||||
|
break;
|
||||||
|
case 'file':
|
||||||
|
if (!isset($post['filehash']))
|
||||||
|
return false;
|
||||||
|
if ($flood_post['filehash'] != $post['filehash'])
|
||||||
|
continue 3;
|
||||||
|
break;
|
||||||
|
case 'board':
|
||||||
|
if ($flood_post['board'] != $post['board'])
|
||||||
|
continue 3;
|
||||||
|
break;
|
||||||
|
case 'isreply':
|
||||||
|
if ($flood_post['isreply'] == $post['op'])
|
||||||
|
continue 3;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error('Invalid filter flood condition: ' . $flood_match_arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$flood_check_matched[] = $flood_post;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->flood_check = $flood_check_matched;
|
||||||
|
|
||||||
|
return !empty($this->flood_check);
|
||||||
|
case 'flood-time':
|
||||||
|
foreach ($this->flood_check as $flood_post) {
|
||||||
|
if (time() - $flood_post['time'] <= $match) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
case 'name':
|
case 'name':
|
||||||
return preg_match($match, $post['name']);
|
return preg_match($match, $post['name']);
|
||||||
case 'trip':
|
case 'trip':
|
||||||
|
@ -31,7 +82,7 @@ class Filter {
|
||||||
case 'subject':
|
case 'subject':
|
||||||
return preg_match($match, $post['subject']);
|
return preg_match($match, $post['subject']);
|
||||||
case 'body':
|
case 'body':
|
||||||
return preg_match($match, $post['body']);
|
return preg_match($match, $post['body_nomarkup']);
|
||||||
case 'filename':
|
case 'filename':
|
||||||
if (!$post['has_file'])
|
if (!$post['has_file'])
|
||||||
return false;
|
return false;
|
||||||
|
@ -126,14 +177,64 @@ class Filter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function purge_flood_table() {
|
||||||
|
global $config;
|
||||||
|
|
||||||
|
// Determine how long we need to keep a cache of posts for flood prevention. Unfortunately, it is not
|
||||||
|
// aware of flood filters in other board configurations. You can solve this problem by settings the
|
||||||
|
// config variable $config['flood_cache'] (seconds).
|
||||||
|
|
||||||
|
if (isset($config['flood_cache'])) {
|
||||||
|
$max_time = &$config['flood_cache'];
|
||||||
|
} else {
|
||||||
|
$max_time = 0;
|
||||||
|
foreach ($config['filters'] as $filter) {
|
||||||
|
if (isset($filter['condition']['flood-time']))
|
||||||
|
$max_time = max($max_time, $filter['condition']['flood-time']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$time = time() - $max_time;
|
||||||
|
|
||||||
|
query("DELETE FROM ``flood`` WHERE ``time`` < $time") or error(db_error());
|
||||||
|
}
|
||||||
|
|
||||||
function do_filters(array $post) {
|
function do_filters(array $post) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
if (!isset($config['filters']))
|
if (!isset($config['filters']) || empty($config['filters']))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach ($config['filters'] as $arr) {
|
foreach ($config['filters'] as $filter) {
|
||||||
$filter = new Filter($arr);
|
if (isset($filter['condition']['flood-match'])) {
|
||||||
|
$has_flood = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
purge_flood_table();
|
||||||
|
|
||||||
|
if (isset($has_flood)) {
|
||||||
|
if ($post['has_file']) {
|
||||||
|
$query = prepare("SELECT * FROM ``flood`` WHERE `ip` = :ip OR `posthash` = :posthash OR `filehash` = :filehash");
|
||||||
|
$query->bindValue(':ip', $_SERVER['REMOTE_ADDR']);
|
||||||
|
$query->bindValue(':posthash', md5($post['body_nomarkup']));
|
||||||
|
$query->bindValue(':filehash', $post['filehash']);
|
||||||
|
} else {
|
||||||
|
$query = prepare("SELECT * FROM ``flood`` WHERE `ip` = :ip OR `posthash` = :posthash");
|
||||||
|
$query->bindValue(':ip', $_SERVER['REMOTE_ADDR']);
|
||||||
|
$query->bindValue(':posthash', md5($post['body_nomarkup']));
|
||||||
|
|
||||||
|
}
|
||||||
|
$query->execute() or error(db_error($query));
|
||||||
|
$flood_check = $query->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
} else {
|
||||||
|
$flood_check = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($config['filters'] as $filter_array) {
|
||||||
|
$filter = new Filter($filter_array);
|
||||||
|
$filter->flood_check = $flood_check;
|
||||||
if ($filter->check($post))
|
if ($filter->check($post))
|
||||||
$filter->action();
|
$filter->action();
|
||||||
}
|
}
|
||||||
|
|
|
@ -572,30 +572,6 @@ function listBoards() {
|
||||||
return $boards;
|
return $boards;
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkFlood($post) {
|
|
||||||
global $board, $config;
|
|
||||||
|
|
||||||
$query = prepare(sprintf("SELECT COUNT(*) FROM ``posts_%s`` WHERE
|
|
||||||
(`ip` = :ip AND `time` >= :floodtime)
|
|
||||||
OR
|
|
||||||
(`ip` = :ip AND :body != '' AND `body_nomarkup` = :body AND `time` >= :floodsameiptime)
|
|
||||||
OR
|
|
||||||
(:body != '' AND `body_nomarkup` = :body AND `time` >= :floodsametime) LIMIT 1", $board['uri']));
|
|
||||||
$query->bindValue(':ip', $_SERVER['REMOTE_ADDR']);
|
|
||||||
$query->bindValue(':body', $post['body']);
|
|
||||||
$query->bindValue(':floodtime', time()-$config['flood_time'], PDO::PARAM_INT);
|
|
||||||
$query->bindValue(':floodsameiptime', time()-$config['flood_time_ip'], PDO::PARAM_INT);
|
|
||||||
$query->bindValue(':floodsametime', time()-$config['flood_time_same'], PDO::PARAM_INT);
|
|
||||||
$query->execute() or error(db_error($query));
|
|
||||||
|
|
||||||
$flood = (bool) $query->fetchColumn();
|
|
||||||
|
|
||||||
if (event('check-flood', $post))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return $flood;
|
|
||||||
}
|
|
||||||
|
|
||||||
function until($timestamp) {
|
function until($timestamp) {
|
||||||
$difference = $timestamp - time();
|
$difference = $timestamp - time();
|
||||||
if ($difference < 60) {
|
if ($difference < 60) {
|
||||||
|
@ -780,6 +756,22 @@ function threadExists($id) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function insertFloodPost(array $post) {
|
||||||
|
global $board;
|
||||||
|
|
||||||
|
$query = prepare("INSERT INTO ``flood`` VALUES (NULL, :ip, :board, :time, :posthash, :filehash, :isreply)");
|
||||||
|
$query->bindValue(':ip', $_SERVER['REMOTE_ADDR']);
|
||||||
|
$query->bindValue(':board', $board['uri']);
|
||||||
|
$query->bindValue(':time', time());
|
||||||
|
$query->bindValue(':posthash', md5($post['body_nomarkup']));
|
||||||
|
if ($post['has_file'])
|
||||||
|
$query->bindValue(':filehash', $post['filehash']);
|
||||||
|
else
|
||||||
|
$query->bindValue(':filehash', null, PDO::PARAM_NULL);
|
||||||
|
$query->bindValue(':isreply', !$post['op']);
|
||||||
|
$query->execute() or error(db_error($query));
|
||||||
|
}
|
||||||
|
|
||||||
function post(array $post) {
|
function post(array $post) {
|
||||||
global $pdo, $board;
|
global $pdo, $board;
|
||||||
$query = prepare(sprintf("INSERT INTO ``posts_%s`` VALUES ( NULL, :thread, :subject, :email, :name, :trip, :capcode, :body, :body_nomarkup, :time, :time, :thumb, :thumbwidth, :thumbheight, :file, :width, :height, :filesize, :filename, :filehash, :password, :ip, :sticky, :locked, 0, :embed)", $board['uri']));
|
$query = prepare(sprintf("INSERT INTO ``posts_%s`` VALUES ( NULL, :thread, :subject, :email, :name, :trip, :capcode, :body, :body_nomarkup, :time, :time, :thumb, :thumbwidth, :thumbheight, :file, :width, :height, :filesize, :filename, :filehash, :password, :ip, :sticky, :locked, 0, :embed)", $board['uri']));
|
||||||
|
@ -788,19 +780,19 @@ function post(array $post) {
|
||||||
if (!empty($post['subject'])) {
|
if (!empty($post['subject'])) {
|
||||||
$query->bindValue(':subject', $post['subject']);
|
$query->bindValue(':subject', $post['subject']);
|
||||||
} else {
|
} else {
|
||||||
$query->bindValue(':subject', NULL, PDO::PARAM_NULL);
|
$query->bindValue(':subject', null, PDO::PARAM_NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($post['email'])) {
|
if (!empty($post['email'])) {
|
||||||
$query->bindValue(':email', $post['email']);
|
$query->bindValue(':email', $post['email']);
|
||||||
} else {
|
} else {
|
||||||
$query->bindValue(':email', NULL, PDO::PARAM_NULL);
|
$query->bindValue(':email', null, PDO::PARAM_NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($post['trip'])) {
|
if (!empty($post['trip'])) {
|
||||||
$query->bindValue(':trip', $post['trip']);
|
$query->bindValue(':trip', $post['trip']);
|
||||||
} else {
|
} else {
|
||||||
$query->bindValue(':trip', NULL, PDO::PARAM_NULL);
|
$query->bindValue(':trip', null, PDO::PARAM_NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
$query->bindValue(':name', $post['name']);
|
$query->bindValue(':name', $post['name']);
|
||||||
|
@ -811,27 +803,27 @@ function post(array $post) {
|
||||||
$query->bindValue(':ip', isset($post['ip']) ? $post['ip'] : $_SERVER['REMOTE_ADDR']);
|
$query->bindValue(':ip', isset($post['ip']) ? $post['ip'] : $_SERVER['REMOTE_ADDR']);
|
||||||
|
|
||||||
if ($post['op'] && $post['mod'] && isset($post['sticky']) && $post['sticky']) {
|
if ($post['op'] && $post['mod'] && isset($post['sticky']) && $post['sticky']) {
|
||||||
$query->bindValue(':sticky', 1, PDO::PARAM_INT);
|
$query->bindValue(':sticky', true, PDO::PARAM_INT);
|
||||||
} else {
|
} else {
|
||||||
$query->bindValue(':sticky', 0, PDO::PARAM_INT);
|
$query->bindValue(':sticky', false, PDO::PARAM_INT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($post['op'] && $post['mod'] && isset($post['locked']) && $post['locked']) {
|
if ($post['op'] && $post['mod'] && isset($post['locked']) && $post['locked']) {
|
||||||
$query->bindValue(':locked', 1, PDO::PARAM_INT);
|
$query->bindValue(':locked', true, PDO::PARAM_INT);
|
||||||
} else {
|
} else {
|
||||||
$query->bindValue(':locked', 0, PDO::PARAM_INT);
|
$query->bindValue(':locked', false, PDO::PARAM_INT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($post['mod'] && isset($post['capcode']) && $post['capcode']) {
|
if ($post['mod'] && isset($post['capcode']) && $post['capcode']) {
|
||||||
$query->bindValue(':capcode', $post['capcode'], PDO::PARAM_INT);
|
$query->bindValue(':capcode', $post['capcode'], PDO::PARAM_INT);
|
||||||
} else {
|
} else {
|
||||||
$query->bindValue(':capcode', NULL, PDO::PARAM_NULL);
|
$query->bindValue(':capcode', null, PDO::PARAM_NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($post['embed'])) {
|
if (!empty($post['embed'])) {
|
||||||
$query->bindValue(':embed', $post['embed']);
|
$query->bindValue(':embed', $post['embed']);
|
||||||
} else {
|
} else {
|
||||||
$query->bindValue(':embed', NULL, PDO::PARAM_NULL);
|
$query->bindValue(':embed', null, PDO::PARAM_NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($post['op']) {
|
if ($post['op']) {
|
||||||
|
|
17
install.php
17
install.php
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
// Installation/upgrade file
|
// Installation/upgrade file
|
||||||
define('VERSION', 'v0.9.6-dev-18');
|
define('VERSION', 'v0.9.6-dev-19');
|
||||||
|
|
||||||
require 'inc/functions.php';
|
require 'inc/functions.php';
|
||||||
|
|
||||||
|
@ -392,6 +392,21 @@ if (file_exists($config['has_installed'])) {
|
||||||
query("ALTER TABLE ``ip_notes``
|
query("ALTER TABLE ``ip_notes``
|
||||||
DROP INDEX `ip`,
|
DROP INDEX `ip`,
|
||||||
ADD INDEX `ip_lookup` (`ip`, `time`)") or error(db_error());
|
ADD INDEX `ip_lookup` (`ip`, `time`)") or error(db_error());
|
||||||
|
case 'v0.9.6-dev-18':
|
||||||
|
query("CREATE TABLE IF NOT EXISTS ``flood`` (
|
||||||
|
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`ip` varchar(39) CHARACTER SET ascii NOT NULL,
|
||||||
|
`board` varchar(58) CHARACTER SET utf8 NOT NULL,
|
||||||
|
`time` int(11) NOT NULL,
|
||||||
|
`posthash` char(32) NOT NULL,
|
||||||
|
`filehash` char(32) DEFAULT NULL,
|
||||||
|
`isreply` tinyint(1) NOT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `ip` (`ip`),
|
||||||
|
KEY `posthash` (`posthash`),
|
||||||
|
KEY `filehash` (`filehash`),
|
||||||
|
KEY `time` (`time`)
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=ascii COLLATE=ascii_bin AUTO_INCREMENT=1 ;") or error(db_error());
|
||||||
case false:
|
case false:
|
||||||
// Update version number
|
// Update version number
|
||||||
file_write($config['has_installed'], VERSION);
|
file_write($config['has_installed'], VERSION);
|
||||||
|
|
21
install.sql
21
install.sql
|
@ -245,6 +245,27 @@ CREATE TABLE IF NOT EXISTS `theme_settings` (
|
||||||
KEY `theme` (`theme`)
|
KEY `theme` (`theme`)
|
||||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `flood`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `flood` (
|
||||||
|
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`ip` varchar(39) CHARACTER SET ascii NOT NULL,
|
||||||
|
`board` varchar(58) CHARACTER SET utf8 NOT NULL,
|
||||||
|
`time` int(11) NOT NULL,
|
||||||
|
`posthash` char(32) NOT NULL,
|
||||||
|
`filehash` char(32) DEFAULT NULL,
|
||||||
|
`isreply` tinyint(1) NOT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `ip` (`ip`),
|
||||||
|
KEY `posthash` (`posthash`),
|
||||||
|
KEY `filehash` (`filehash`),
|
||||||
|
KEY `time` (`time`)
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=ascii COLLATE=ascii_bin AUTO_INCREMENT=1 ;
|
||||||
|
|
||||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||||
|
|
21
post.php
21
post.php
|
@ -198,7 +198,7 @@ if (isset($_POST['delete'])) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($post['mod'] = isset($_POST['mod']) && $_POST['mod']) {
|
if ($post['mod'] = isset($_POST['mod']) && $_POST['mod']) {
|
||||||
require 'inc/mod.php';
|
require 'inc/mod/auth.php';
|
||||||
if (!$mod) {
|
if (!$mod) {
|
||||||
// Liar. You're not a mod.
|
// Liar. You're not a mod.
|
||||||
error($config['error']['notamod']);
|
error($config['error']['notamod']);
|
||||||
|
@ -428,11 +428,6 @@ if (isset($_POST['delete'])) {
|
||||||
|
|
||||||
wordfilters($post['body']);
|
wordfilters($post['body']);
|
||||||
|
|
||||||
// Check for a flood
|
|
||||||
if (!hasPermission($config['mod']['flood'], $board['uri']) && checkFlood($post)) {
|
|
||||||
error($config['error']['flood']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$post['body'] = escape_markup_modifiers($post['body']);
|
$post['body'] = escape_markup_modifiers($post['body']);
|
||||||
|
|
||||||
if ($mod && isset($post['raw']) && $post['raw']) {
|
if ($mod && isset($post['raw']) && $post['raw']) {
|
||||||
|
@ -469,9 +464,7 @@ if (isset($_POST['delete'])) {
|
||||||
|
|
||||||
$post['tracked_cites'] = markup($post['body'], true);
|
$post['tracked_cites'] = markup($post['body'], true);
|
||||||
|
|
||||||
require_once 'inc/filters.php';
|
|
||||||
|
|
||||||
do_filters($post);
|
|
||||||
|
|
||||||
if ($post['has_file']) {
|
if ($post['has_file']) {
|
||||||
if (!in_array($post['extension'], $config['allowed_ext']) && !in_array($post['extension'], $config['allowed_ext_files']))
|
if (!in_array($post['extension'], $config['allowed_ext']) && !in_array($post['extension'], $config['allowed_ext_files']))
|
||||||
|
@ -487,9 +480,17 @@ if (isset($_POST['delete'])) {
|
||||||
if (!is_readable($upload))
|
if (!is_readable($upload))
|
||||||
error($config['error']['nomove']);
|
error($config['error']['nomove']);
|
||||||
|
|
||||||
$post['filehash'] = $config['file_hash']($upload);
|
$post['filehash'] = md5_file($upload);
|
||||||
$post['filesize'] = filesize($upload);
|
$post['filesize'] = filesize($upload);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasPermission($config['mod']['bypass_filters'], $board['uri'])) {
|
||||||
|
require_once 'inc/filters.php';
|
||||||
|
|
||||||
|
do_filters($post);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($post['has_file']) {
|
||||||
if ($is_an_image && $config['ie_mime_type_detection'] !== false) {
|
if ($is_an_image && $config['ie_mime_type_detection'] !== false) {
|
||||||
// Check IE MIME type detection XSS exploit
|
// Check IE MIME type detection XSS exploit
|
||||||
$buffer = file_get_contents($upload, null, null, null, 255);
|
$buffer = file_get_contents($upload, null, null, null, 255);
|
||||||
|
@ -679,6 +680,8 @@ if (isset($_POST['delete'])) {
|
||||||
|
|
||||||
$post['id'] = $id = post($post);
|
$post['id'] = $id = post($post);
|
||||||
|
|
||||||
|
insertFloodPost($post);
|
||||||
|
|
||||||
if (isset($post['antispam_hash'])) {
|
if (isset($post['antispam_hash'])) {
|
||||||
incrementSpamHash($post['antispam_hash']);
|
incrementSpamHash($post['antispam_hash']);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue