В сегодняшней статье пойдёт речь о том, как с помощью бота можно банить и мутить нерадивых участников беседы. Команды будут работать как по введённой ссылке на пользователя, так и по пересланному сообщению. Ко всему прочему, научим бота и просто исключать пользователей из конференции без блокировки.
Шаг 1: Подготовка
Для работы с ботами понадобится сообщество ВКонтакте. В спойлере ниже есть памятка по настройке этого самого сообщетсва:
На этом моменте подготовительную работу можно считать оконченной.
Шаг 2: Работа с БД
Информацию о банах, мутах, а также о их сроках нужно где-то хранить. Поэтому для этих целей мы будем использовать специальную таблицу, которую сейчас необходимо будет создать в базе данных:
В ней будет всего-навсего 4 поля:
id - айди записи (число);
user_id - айди пользователя (число);
type - тип записи (1 - мут, 2 - бан);
duration - срок (число).
Шаг 3: Написание бота
Для начала подключаю библиотеки и создаю несколько констант:
<?php
/* Подключение библиотек */
require_once 'simplevk-master/autoload.php';
require_once 'vendor/autoload.php';
/* Константы для работы с VK */
const VK_KEY = '********************************'; // Тот самый длинный ключ, который мы создавали
const ACCESS_KEY = '*******'; // Строка, которую должен вернуть сервер
const VERSION = '5.131'; // Версия VK API
/* Константы для работы с Mysql */
const SERVER = 'localhost';
const USERNAME = 'Имя пользователя';
const PASSWORD = 'Пароль';
const DATABASE_NAME = 'Имя БД';
const CHARSET = 'utf8mb4';
Далее подключаюсь к базе данных, авторизируюсь через токен сообщества ВК:
$vk = \DigitalStar\vk_api\vk_api::create( VK_KEY, VERSION )->setConfirm( ACCESS_KEY ); // Авторизация через токен сообщества
$db = \Krugozor\Database\Mysql::create( SERVER, USERNAME, PASSWORD )->setDatabaseName( DATABASE_NAME )->setCharset( CHARSET ); // Подключение к БД
$vk->initVars( $peer_id, $message, $payload, $vk_id, $type, $data ); // Инициализация переменных, они понадобятся для дальнейшей работы
Теперь приступаем непосредственно к написанию скрипта для бота и к обработке входящих сообщений. Начинаем с проверки на тип события. Поскольку мы поставили галочку только напротив входящих сообщений, то уведомления ни о никаких других событиях приходить к нам на сервер не будут, однако проверку всё равно пишем:
if ( $type == 'message_new' )
{
// Тут будем продолжать писать код
}
Теперь мы приступаем к обработке команд на блокировку, мут, разблокировку и размут пользователей. Чтобы этими привилегиями в беседе не пользовался кто попало - нужно убедиться, что их использует именно администратор, а не кто-либо другой. Для этого я использую метод isAdmin() класса vk_pi.
Список возвращаемых методом значений:
'owner' - создатель беседы;
'admin' - администратор;
false - пользователь;
null - пользователя нет в беседе.
Чтобы продолжить выполнение кода - нужно, чтобы была возвращена строка ('admin' или 'owner'):
if ( $type == 'message_new' )
{
if ( $vk->isAdmin( $vk_id, $peer_id ) )
{
// Тут продолжим кодить
}
}
Команды для бота будут состоять из нескольких параметров (из нескольких частей). К примеру, "/бан @id1 5 часов". Чтобы удобнее было работать с этими параметрами - разобьём строку на массив с помощью функции explode(). В итоге получится так: [ '/бан', '@id1', '5', 'часов' ]:
$message_data = explode( ' ', $message );
Теперь получившийся массив нужно немного подредачить:
Надеюсь, идею плюс минут я объяснил понятно. Так что слова теперь преобразовываю в код:
if ( isset( $data->object->reply_message ) )
{
$message_data = array_merge( array_slice( $message_data, 0, 1 ), [ $data->object->reply_message->from_id ], array_slice( $message_data, 1 ) );
}
else
{
if ( strpos( $message_data[1], '@' ) !== false )
$message_data[1] = substr( substr( $message_data[1], strpos( $message_data[1], '@' ) + 1 ), 0, -1 );
else if ( strpos( $message_data[1], '*' ) !== false )
$message_data[1] = substr( substr( $message_data[1], strpos( $message_data[1], '*' ) + 1 ), 0, -1 );
}
Теперь, когда в массив $message_data мы запихали адекватную ссылку на пользователя, можно приступать к извлечению из ВК инфы о нём (о пользователе) с помощью метода userInfo(). Нам понадобится только ID страницы, имя и фамилия:
$user_info = $vk->userInfo( $message_data[1], $scope = [ 'fields' => 'id, first_name, last_name' ] );
Пришло время сделать обработку команд. Начнём с команды /бан и команды /мут. Чтобы не делать двойную проверку - я буду использовать конструкцию try catch. Если пользователь является админом беседы или вовсе не состоит в ней, то будет присылаться соответствующее предупреждение. В ином случае мы заносим в таблицу black_list инфу о бане (или о муте) юзера, а также фиксируем срок. Ах да, тут я использую пользовательскую функцию durationCount() (для подсчёта срока наказания в секундах), о её работе напишу чуть ниже. А сейчас пишем обработку команд:
if ( $message_data[0] == '/мут' )
{
try
{
$duration = durationCount( $message_data[2], $message_data[3] );
$db->query( "INSERT INTO `black_list` SET `user_id` = ?i, `type` = ?i, `duration` = ?i", $user_info['id'], 1, $duration );
$vk->sendMessage( $peer_id, '@id' . $user_info['id'] . '(' . $user_info['first_name'] . ' ' . $user_info['last_name'] . ') замучен до ' . date( 'd.m.y H:i:s', $duration ) . ' (' . ( $message_data[4] ?? 'Без причины' ) . ')' );
}
catch ( \DigitalStar\vk_api\VkApiException $e )
{
$vk->sendMessage( $peer_id, 'Произошла ошибка. Вероятно, пользователь является администратором или отсутствует в этой беседе.' );
}
}
if ( $message_data[0] == '/бан' )
{
try
{
$duration = durationCount( $message_data[2], $message_data[3] );
$db->query( "INSERT INTO `black_list` SET `user_id` = ?i, `type` = ?i, `duration` = ?i", $user_info['id'], 2, $duration );
$vk->request( 'messages.removeChatUser', [ 'chat_id' => $peer_id - 2000000000, 'member_id' => $user_info['id'] ] );
$vk->sendMessage( $peer_id, '@id' . $user_info['id'] . '(' . $user_info['first_name'] . ' ' . $user_info['last_name'] . ') забанен до ' . date( 'd.m.y H:i:s', $duration ) . ' (' . ( $message_data[4] ?? 'Без причины' ) . ')' );
}
catch ( \DigitalStar\vk_api\VkApiException $e )
{
$vk->sendMessage( $peer_id, 'Произошла ошибка. Вероятно, пользователь является администратором или отсутствует в этой беседе.' );
}
}
Пока не ушли от темы - делаем ещё две команды (/разбан и /размут). Принцип их работы простой - после их использования из БД удаляются все записи, в которых фигурирует ID амнистируемого пользователя:
if ( $message_data[0] == '/размут' )
{
$db->query( "DELETE FROM `black_list` WHERE `user_id` = ?i AND `type` = ?i", $user_info['id'], 1 );
$vk->sendMessage( $peer_id, '@id' . $user_info['id'] . '(' . $user_info['first_name'] . ' ' . $user_info['last_name'] . ') размучен' );
}
if ( $message_data[0] == '/разбан' )
{
$db->query( "DELETE FROM `black_list` WHERE `user_id` = ?i AND `type` = ?i", $user_info['id'], 2 );
$vk->sendMessage( $peer_id, '@id' . $user_info['id'] . '(' . $user_info['first_name'] . ' ' . $user_info['last_name'] . ') разбанен' );
}
Я обещал разобрать и показать функцию durationCount(). Показываю:
function durationCount( $value, $unit )
{
if ( strpos( $unit, 'сек' ) === 0 )
$duration = time() + ( $value * 1 );
else if ( strpos( $unit, 'мин' ) === 0 )
$duration = time() + ( $value * 60 );
else if ( strpos( $unit, 'час' ) === 0 )
$duration = time() + ( $value * 3600 );
else if ( strpos( $unit, 'дн' ) === 0 )
$duration = time() + ( $value * 86400 );
return $duration;
}
На вход мы даём значение (время) и единицу измерения времени (секунды, минуты, часы или дни). Чтобы единицы измерения можно было на письме сокращать и использовать в разных падежах - прибегаю к услугам функции strpos(), которая возвращает позицию первого вхождения подстроки в строку. После определения временной единицы - умножаем полученное значение на количество секунд в неё входящее. Ну, а потом уже функция возвращает результат вычисления.
Функцию вставляем в самом низу файла.
Смотрим, как работает. В качестве последнего параметра, кстати, можно указать причину бана (мута) - "/мут @id1 10 дней Причина". Если причина не указана, то бот уведомит об её отсутствии:
Нам осталось сделать обработку сообщений ото всех пользователей беседы.
if ( isset( $data->object->action ) and $data->object->action->type == 'chat_invite_user' ) // Если кто-то кого-то пригласил
{
$result = $db->query( "SELECT * FROM `black_list` WHERE `user_id` = ?i AND `type` = ?i", $data->object->action->member_id, 2 )->fetchAssoc(); // Запрос к БД. Проверяем, нет ли приглашенного в чёрном списке?
if ( isset( $result['id'] ) and $result['id'] and $result['duration'] > time() ) // Проверяем, истёк ли срок наказания
{
$vk->request( 'messages.removeChatUser', [ 'chat_id' => $peer_id - 2000000000, 'member_id' => $data->object->action->member_id ] ); // Кикаем, если срок не истёк
$vk->sendMessage( $peer_id, 'Пользователь находится в чёрном списке беседы' ); // Уведомляем об этом участников беседы
}
}
else
{
$result = $db->query( "SELECT * FROM `black_list` WHERE `user_id` = ?i AND `type` = ?i", $vk_id, 1 )->fetchAssoc();
if ( isset( $result['id'] ) and $result['id'] and $result['duration'] > time() )
{
$vk->request( 'messages.delete', [ 'delete_for_all' => 1, 'peer_id' => $peer_id, 'cmids' => $data->object->conversation_message_id ] ); // Удаляем сообщение, если человек замучен
}
}
На этом написание бота окончено, архив с исходниками прикрепляю ниже. Бонусом, кстати, добавил команду /кик. Здесь её не разбирал, поскольку статья на эту тему уже была на сайте.
Нашли ошибку?
Вы можете сообщить об этом администрации.
Выделив текст нажмите CTRL+Enter