Add moderation tools for file banning
Thank you PupperWof
This commit is contained in:
parent
d19c14a196
commit
c8821a3dec
|
@ -839,7 +839,9 @@
|
|||
// Maximum image dimensions.
|
||||
$config['max_width'] = 10000;
|
||||
$config['max_height'] = $config['max_width'];
|
||||
// Reject duplicate image uploads.
|
||||
// Reject the same image being uploaded twice in one post.
|
||||
$config['image_reject_multipost'] = true;
|
||||
// Reject duplicate image uploads on each board.
|
||||
$config['image_reject_repost'] = true;
|
||||
// Reject duplicate image uploads within the same thread. Doesn't change anything if
|
||||
// $config['image_reject_repost'] is true.
|
||||
|
@ -1173,8 +1175,11 @@
|
|||
$config['error']['invalidwebm'] = _('Invalid webm uploaded.');
|
||||
$config['error']['webmhasaudio'] = _('The uploaded webm contains an audio or another type of additional stream.');
|
||||
$config['error']['webmtoolong'] =_('The uploaded webm is longer than %d seconds.');
|
||||
$config['error']['fileduplicate'] = _('You can\'t add duplicates of same file!');
|
||||
$config['error']['filebanned'] = _('Error posting file.');
|
||||
$config['error']['fileexists'] = _('That file <a href="%s">already exists</a>!');
|
||||
$config['error']['fileexistsinthread'] = _('That file <a href="%s">already exists</a> in this thread!');
|
||||
|
||||
$config['error']['delete_too_soon'] = _('You\'ll have to wait another %s before deleting that.');
|
||||
$config['error']['mime_exploit'] = _('MIME type detection XSS exploit (IE) detected; post discarded.');
|
||||
$config['error']['invalid_embed'] = _('Couldn\'t make sense of the URL of the video you tried to embed.');
|
||||
|
@ -1371,6 +1376,7 @@
|
|||
$config['mod']['link_ban'] = '[B]';
|
||||
$config['mod']['link_bandelete'] = '[B&D]';
|
||||
$config['mod']['link_deletefile'] = '[F]';
|
||||
$config['mod']['link_deletefilepermaban'] = '[FPb]';
|
||||
$config['mod']['link_spoilerimage'] = '[S]';
|
||||
$config['mod']['link_deletebyip'] = '[D+]';
|
||||
$config['mod']['link_deletebyip_global'] = '[D++]';
|
||||
|
|
|
@ -1115,7 +1115,32 @@ function post(array $post) {
|
|||
error(db_error($query));
|
||||
}
|
||||
|
||||
return $pdo->lastInsertId();
|
||||
// Save Post ID
|
||||
$postID = $pdo->lastInsertId();
|
||||
|
||||
// Add file-hashes to database
|
||||
if($post['has_file'])
|
||||
{
|
||||
// If OP then thread ID is same as post ID
|
||||
$threadID = (!isset($post['thread']) || $post['op'])?$postID:$post['thread'];
|
||||
|
||||
// Get all filehashes for post
|
||||
$hashes = explode(":", $post['allhashes']);
|
||||
$hc = count($hashes);
|
||||
for($i=0; $i<$hc;$i++)
|
||||
{
|
||||
// Build entry for database
|
||||
$query = prepare(sprintf("INSERT INTO ``filehashes`` VALUES ( NULL, '%s', :thread, :postid, :filehash)", $board['uri']));
|
||||
$query->bindValue(':thread', $threadID, PDO::PARAM_INT);
|
||||
$query->bindValue(':postid', $postID, PDO::PARAM_INT);
|
||||
$query->bindValue(':filehash', $hashes[$i]);
|
||||
// Add entry to database
|
||||
$query->execute() or error(db_error($query));
|
||||
}
|
||||
}
|
||||
|
||||
// Return Post ID
|
||||
return $postID;
|
||||
}
|
||||
|
||||
function bumpThread($id) {
|
||||
|
@ -1151,6 +1176,76 @@ function deleteFile($id, $remove_entirely_if_already=true, $file=null) {
|
|||
if ($files[0]->file == 'deleted' && $post['num_files'] == 1 && !$post['thread'])
|
||||
return; // Can't delete OP's image completely.
|
||||
|
||||
// Delete filehash from filehashes table
|
||||
if($file == null)
|
||||
{
|
||||
$query = prepare(sprintf("DELETE FROM ``filehashes`` WHERE `thread` = :thread AND `board` = '%s' AND `post`= :id", $board['uri']));
|
||||
$query->bindValue(':thread', $post['thread'], PDO::PARAM_INT);
|
||||
$query->bindValue(':id', $id, PDO::PARAM_INT);
|
||||
$query->execute() or error(db_error($query));
|
||||
} else {
|
||||
$query = prepare(sprintf("DELETE FROM ``filehashes`` WHERE `thread` = :thread AND `board` = '%s' AND `filehash`= :hash", $board['uri']));
|
||||
$query->bindValue(':thread', $post['thread'], PDO::PARAM_INT);
|
||||
$query->bindValue(':hash', $file_to_delete->hash, PDO::PARAM_STR);
|
||||
$query->execute() or error(db_error($query));
|
||||
}
|
||||
|
||||
$query = prepare(sprintf("UPDATE ``posts_%s`` SET `files` = :file WHERE `id` = :id", $board['uri']));
|
||||
if (($file && $file_to_delete->file == 'deleted') && $remove_entirely_if_already) {
|
||||
// Already deleted; remove file fully
|
||||
$files[$file] = null;
|
||||
} else {
|
||||
foreach ($files as $i => $f) {
|
||||
if (($file !== false && $i == $file) || $file === null) {
|
||||
// Delete thumbnail
|
||||
if (isset ($f->thumb) && $f->thumb) {
|
||||
file_unlink($board['dir'] . $config['dir']['thumb'] . $f->thumb);
|
||||
unset($files[$i]->thumb);
|
||||
}
|
||||
|
||||
// Delete file
|
||||
file_unlink($board['dir'] . $config['dir']['img'] . $f->file);
|
||||
$files[$i]->file = 'deleted';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$query->bindValue(':file', json_encode($files), PDO::PARAM_STR);
|
||||
|
||||
$query->bindValue(':id', $id, PDO::PARAM_INT);
|
||||
$query->execute() or error(db_error($query));
|
||||
|
||||
if ($post['thread'])
|
||||
buildThread($post['thread']);
|
||||
else
|
||||
buildThread($id);
|
||||
}
|
||||
|
||||
// Remove file from post
|
||||
function deleteFilePermaban($id, $remove_entirely_if_already=true, $file=null) {
|
||||
global $board, $config;
|
||||
|
||||
$query = prepare(sprintf("SELECT `thread`, `files`, `num_files` FROM ``posts_%s`` WHERE `id` = :id LIMIT 1", $board['uri']));
|
||||
$query->bindValue(':id', $id, PDO::PARAM_INT);
|
||||
$query->execute() or error(db_error($query));
|
||||
if (!$post = $query->fetch(PDO::FETCH_ASSOC))
|
||||
error($config['error']['invalidpost']);
|
||||
$files = json_decode($post['files']);
|
||||
$file_to_delete = $file !== false ? $files[(int)$file] : (object)array('file' => false);
|
||||
|
||||
if (!$files[0]) error(_('That post has no files.'));
|
||||
|
||||
if ($files[0]->file == 'deleted' && $post['num_files'] == 1 && !$post['thread'])
|
||||
return; // Can't delete OP's image completely.
|
||||
|
||||
|
||||
// Delete filehash from filehashes table
|
||||
$query = prepare(sprintf("UPDATE ``filehashes`` SET `board` = '%s' WHERE `thread` = :thread AND `board` = '%s' AND `filehash`= :hash", "permaban", $board['uri']));
|
||||
$query->bindValue(':thread', $post['thread'], PDO::PARAM_INT);
|
||||
$query->bindValue(':hash', $file_to_delete->hash, PDO::PARAM_STR);
|
||||
$query->execute() or error(db_error($query));
|
||||
|
||||
|
||||
$query = prepare(sprintf("UPDATE ``posts_%s`` SET `files` = :file WHERE `id` = :id", $board['uri']));
|
||||
if (($file && $file_to_delete->file == 'deleted') && $remove_entirely_if_already) {
|
||||
// Already deleted; remove file fully
|
||||
|
@ -1262,6 +1357,11 @@ function deletePost($id, $error_if_doesnt_exist=true, $rebuild_after=true) {
|
|||
$query->bindValue(':id', $id, PDO::PARAM_INT);
|
||||
$query->execute() or error(db_error($query));
|
||||
|
||||
// Delete filehash entries for thread from filehash table
|
||||
$query = prepare(sprintf("DELETE FROM ``filehashes`` WHERE ( `thread` = :id OR `post` = :id ) AND `board` = '%s'", $board['uri']));
|
||||
$query->bindValue(':id', $id, PDO::PARAM_INT);
|
||||
$query->execute() or error(db_error($query));
|
||||
|
||||
$query = prepare("SELECT `board`, `post` FROM ``cites`` WHERE `target_board` = :board AND (`target` = " . implode(' OR `target` = ', $ids) . ") ORDER BY `board`");
|
||||
$query->bindValue(':board', $board['uri']);
|
||||
$query->execute() or error(db_error($query));
|
||||
|
@ -2618,30 +2718,78 @@ function fraction($numerator, $denominator, $sep) {
|
|||
return "{$numerator}{$sep}{$denominator}";
|
||||
}
|
||||
|
||||
function getPostByHash($hash) {
|
||||
function getHashPermabanned($hash) {
|
||||
global $board;
|
||||
$query = prepare(sprintf("SELECT `id`,`thread` FROM ``posts_%s`` WHERE `filehash` = :hash", $board['uri']));
|
||||
$query = prepare(sprintf("SELECT `id` FROM ``filehashes`` WHERE `filehash` = :hash AND `board` = '%s'", "permaban"));
|
||||
$query->bindValue(':hash', $hash, PDO::PARAM_STR);
|
||||
$query->execute() or error(db_error($query));
|
||||
|
||||
return $query->fetch(PDO::FETCH_ASSOC);
|
||||
}
|
||||
|
||||
// Function to check all posts on entire board for file hash
|
||||
function getPostByAllHash($allhashes)
|
||||
{
|
||||
global $board;
|
||||
$hashes = explode(":", $allhashes);
|
||||
foreach($hashes as $hash)
|
||||
{
|
||||
// Search for filehash
|
||||
$query = prepare("SELECT `post` AS `post`, `thread` FROM `filehashes` WHERE `filehash` = :hash AND `board` = :board");
|
||||
$query->bindValue(':hash', $hash, PDO::PARAM_STR);
|
||||
$query->bindValue(':board', $board['uri'], PDO::PARAM_STR);
|
||||
$query->execute() or error(db_error($query));
|
||||
|
||||
// Return result if found
|
||||
if ($post = $query->fetch(PDO::FETCH_ASSOC)) {
|
||||
return $post;
|
||||
}
|
||||
|
||||
}
|
||||
// Return false if no matching hash found
|
||||
return false;
|
||||
}
|
||||
|
||||
function getPostByHashInThread($hash, $thread) {
|
||||
// Function to check all posts in thread for file hash
|
||||
function getPostByAllHashInThread($allhashes, $thread)
|
||||
{
|
||||
global $board;
|
||||
$query = prepare(sprintf("SELECT `id`,`thread` FROM ``posts_%s`` WHERE `filehash` = :hash AND ( `thread` = :thread OR `id` = :thread )", $board['uri']));
|
||||
$hashes = explode(":", $allhashes);
|
||||
foreach($hashes as $hash)
|
||||
{
|
||||
$query = prepare("SELECT `post` AS `post`,`thread` FROM `filehashes` WHERE `filehash` = :hash AND `board` = :board AND `thread` = :thread");
|
||||
$query->bindValue(':hash', $hash, PDO::PARAM_STR);
|
||||
$query->bindValue(':thread', $thread, PDO::PARAM_INT);
|
||||
$query->bindValue(':board', $board['uri'], PDO::PARAM_STR);
|
||||
$query->execute() or error(db_error($query));
|
||||
|
||||
// Return result if found
|
||||
if ($post = $query->fetch(PDO::FETCH_ASSOC)) {
|
||||
return $post;
|
||||
}
|
||||
}
|
||||
// Return false if no matching hash found
|
||||
return false;
|
||||
}
|
||||
|
||||
// Function to check all OP posts in board for file hash
|
||||
function getPostByAllHashInOP($allhashes)
|
||||
{
|
||||
global $board;
|
||||
$hashes = explode(":", $allhashes);
|
||||
foreach($hashes as $hash)
|
||||
{
|
||||
// Search for filehash amongst OP images
|
||||
$query = prepare("SELECT `post` AS `post`,`thread` FROM `filehashes` WHERE `filehash` = :hash AND `board` = :board AND `thread` = `post`");
|
||||
$query->bindValue(':hash', $hash, PDO::PARAM_STR);
|
||||
$query->bindValue(':board', $board['uri'], PDO::PARAM_STR);
|
||||
$query->execute() or error(db_error($query));
|
||||
|
||||
// Return result if found
|
||||
if ($post = $query->fetch(PDO::FETCH_ASSOC)) {
|
||||
return $post;
|
||||
}
|
||||
}
|
||||
// Return false if no matching hash found
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1788,6 +1788,30 @@ function mod_deletefile($board, $post, $file) {
|
|||
header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']);
|
||||
}
|
||||
|
||||
// Delete and Permaban Image
|
||||
function mod_deletefilepermaban($board, $post, $file) {
|
||||
global $config, $mod;
|
||||
|
||||
if (!openBoard($board))
|
||||
error($config['error']['noboard']);
|
||||
|
||||
if (!hasPermission($config['mod']['deletefile'], $board))
|
||||
error($config['error']['noaccess']);
|
||||
|
||||
// Delete file
|
||||
deleteFilePermaban($post, TRUE, $file);
|
||||
// Record the action
|
||||
modLog("Deleted and Permabanned file from post #{$post}");
|
||||
|
||||
// Rebuild board
|
||||
buildIndex();
|
||||
// Rebuild themes
|
||||
rebuildThemes('post-delete', $board);
|
||||
|
||||
// Redirect
|
||||
header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']);
|
||||
}
|
||||
|
||||
function mod_spoiler_image($board, $post, $file) {
|
||||
global $config, $mod;
|
||||
|
||||
|
|
14
install.php
14
install.php
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
// Installation/upgrade file
|
||||
define('VERSION', '5.1.4');
|
||||
define('VERSION', '5.1.5');
|
||||
require 'inc/bootstrap.php';
|
||||
loadConfig();
|
||||
|
||||
|
@ -635,6 +635,18 @@ if (file_exists($config['has_installed'])) {
|
|||
`created_at` int(11),
|
||||
PRIMARY KEY (`cookie`,`extra`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;') or error(db_error());
|
||||
case '5.1.4':
|
||||
query('CREATE TABLE ``filehashes`` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`board` varchar(58) NOT NULL,
|
||||
`thread` int(11) NOT NULL,
|
||||
`post` int(11) NOT NULL,
|
||||
`filehash` text CHARACTER SET ascii NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `thread_id` (`thread`),
|
||||
KEY `post_id` (`post`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
') or error(db_error());
|
||||
case false:
|
||||
// TODO: enhance Tinyboard -> vichan upgrade path.
|
||||
query("CREATE TABLE IF NOT EXISTS ``search_queries`` ( `ip` varchar(39) NOT NULL, `time` int(11) NOT NULL, `query` text NOT NULL) ENGINE=MyISAM DEFAULT CHARSET=utf8;") or error(db_error());
|
||||
|
|
18
install.sql
18
install.sql
|
@ -260,6 +260,24 @@ CREATE TABLE IF NOT EXISTS `theme_settings` (
|
|||
KEY `theme` (`theme`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `filehashes`
|
||||
--
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `filehashes` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`board` varchar(58) NOT NULL,
|
||||
`thread` int(11) NOT NULL,
|
||||
`post` int(11) NOT NULL,
|
||||
`filehash` text CHARACTER SET ascii NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `thread_id` (`thread`),
|
||||
KEY `post_id` (`post`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
|
|
1
mod.php
1
mod.php
|
@ -79,6 +79,7 @@ $pages = array(
|
|||
'/(\%b)/edit(_raw)?/(\d+)' => 'secure_POST edit_post', // edit post
|
||||
'/(\%b)/delete/(\d+)' => 'secure delete', // delete post
|
||||
'/(\%b)/deletefile/(\d+)/(\d+)' => 'secure deletefile', // delete file from post
|
||||
'/(\%b)/deletefilepermaban/(\d+)/(\d+)' => 'secure deletefilepermaban', // delete file from post and permaban it
|
||||
'/(\%b+)/spoiler/(\d+)/(\d+)' => 'secure spoiler_image', // spoiler file
|
||||
'/(\%b)/deletebyip/(\d+)(/global)?' => 'secure deletebyip', // delete all posts by IP address
|
||||
'/(\%b)/(un)?lock/(\d+)' => 'secure lock', // lock thread
|
||||
|
|
51
post.php
51
post.php
|
@ -860,9 +860,14 @@ if (isset($_POST['delete'])) {
|
|||
}
|
||||
|
||||
$file['hash'] = $hash;
|
||||
$allhashes .= $hash;
|
||||
// Add Hashes as an imploded string
|
||||
$allhashes .= $hash . ":";
|
||||
}
|
||||
|
||||
// Remove exsessive ":" from imploded list
|
||||
$allhashes = substr_replace($allhashes, "", -1);
|
||||
$post['allhashes'] = $allhashes;
|
||||
|
||||
if (count ($post['files']) == 1) {
|
||||
$post['filehash'] = $hash;
|
||||
}
|
||||
|
@ -1063,29 +1068,61 @@ if (isset($_POST['delete'])) {
|
|||
}
|
||||
}
|
||||
|
||||
// Check if multiple images attached and if same image is added more than once
|
||||
if ($config['image_reject_multipost']) {
|
||||
$hashArray = explode(":", $post['allhashes']);
|
||||
$hashCount = count($hashArray);
|
||||
for($i=0; $i<$hashCount; $i++) {
|
||||
for($j=0; $j<$hashCount; $j++) {
|
||||
if($i != $j && $hashArray[$i] == $hashArray[$j]) {
|
||||
undoImage($post);
|
||||
error($config['error']['fileduplicate']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (getHashPermabanned($post['allhashes'])) {
|
||||
undoImage($post);
|
||||
error($config['error']['filebanned']);
|
||||
}
|
||||
|
||||
if ($config['image_reject_repost']) {
|
||||
if ($p = getPostByHash($post['filehash'])) {
|
||||
if ($p = getPostByAllHash($post['allhashes'])) {
|
||||
undoImage($post);
|
||||
error(sprintf($config['error']['fileexists'],
|
||||
($post['mod'] ? $config['root'] . $config['file_mod'] . '?/' : $config['root']) .
|
||||
($board['dir'] . $config['dir']['res'] .
|
||||
($p['thread'] ?
|
||||
$p['thread'] . '.html#' . $p['id']
|
||||
$p['thread'] . '.html#' . $p['post']
|
||||
:
|
||||
$p['id'] . '.html'
|
||||
$p['post'] . '.html'
|
||||
))
|
||||
));
|
||||
}
|
||||
} else if (!$post['op'] && $config['image_reject_repost_in_thread']) {
|
||||
if ($p = getPostByHashInThread($post['filehash'], $post['thread'])) {
|
||||
if ($p = getPostByAllHashInThread($post['allhashes'], $post['thread'])) {
|
||||
undoImage($post);
|
||||
error(sprintf($config['error']['fileexistsinthread'],
|
||||
($post['mod'] ? $config['root'] . $config['file_mod'] . '?/' : $config['root']) .
|
||||
($board['dir'] . $config['dir']['res'] .
|
||||
($p['thread'] ?
|
||||
$p['thread'] . '.html#' . $p['id']
|
||||
$p['thread'] . '.html#' . $p['post']
|
||||
:
|
||||
$p['id'] . '.html'
|
||||
$p['post'] . '.html'
|
||||
))
|
||||
));
|
||||
}
|
||||
} else if ($post['op'] && $config['image_reject_repost_in_thread']) {
|
||||
// Check all OP images and see if any have been used before
|
||||
if ($p = getPostByAllHashInOP($post['allhashes'])) {
|
||||
undoImage($post);
|
||||
error(sprintf($config['error']['fileexistsinthread'],
|
||||
($post['mod'] ? $config['root'] . $config['file_mod'] . '?/' : $config['root']) .
|
||||
($board['dir'] . $config['dir']['res'] .
|
||||
($p['thread'] ?
|
||||
$p['thread'] . '.html#' . $p['post']
|
||||
:
|
||||
$p['post'] . '.html'
|
||||
))
|
||||
));
|
||||
}
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
{% if file.file != 'deleted' and mod|hasPermission(config.mod.deletefile, board.uri) %}
|
||||
{{ secure_link_confirm(config.mod.link_deletefile, 'Delete file'|trans, 'Are you sure you want to delete this file?'|trans, board.dir ~ 'deletefile/' ~ post.id ~ '/' ~ loop.index0 ) }}
|
||||
{% endif %}
|
||||
{% if file.file != 'deleted' and mod|hasPermission(config.mod.deletefile, board.uri) %}
|
||||
{{ secure_link_confirm(config.mod.link_deletefilepermaban, 'Delete file and Permaban File'|trans, 'Are you sure you want to delete and permaban this file?'|trans, board.dir ~ 'deletefilepermaban/' ~ post.id ~ '/' ~ loop.index0 ) }}
|
||||
{% endif %}
|
||||
{% if file.file and file.file != 'deleted' and file.thumb != 'spoiler' and mod|hasPermission(config.mod.spoilerimage, board.uri) %}
|
||||
{{ secure_link_confirm(config.mod.link_spoilerimage, 'Spoiler file'|trans, 'Are you sure you want to spoiler this file?'|trans, board.dir ~ 'spoiler/' ~ post.id ~ '/' ~ loop.index0 ) }}
|
||||
{% endif %}
|
||||
|
|
Loading…
Reference in New Issue
Block a user