Недавно на одном проекте мне пришлось столкнуться с ботом вк, который «живёт» в сообщениях группы. До этого я имел самый разный опыт создания ботов из личных страничек. Для того, чтобы бот мог нормально отвечать на сообщения приходилось делать самые разные извращения с кроном, таймерами, «запоминанием» сообщений и другими разными ужасами.
Как же я удивился, когда начав курить VK API групп касаемо сообщений, я увидел это чудо — Callback API.
Для нетерпеливых или любящих разбираться со всем самостоятельно в конце есть готовый пример.
Статья рассчитана не для совсем новичков и я не стал её сильно затягивать, специально опустив разжёвывание совсем очевидных вещей, иначе бы это была бы очень огромная статья. Тема написания ботов в целом так-то не очень новичковая тема.
Для тех кто не знает, что это, расскажу кратко.
При помощи этой фишки вк сам, автоматически, отправляет запросы в формате JSON куда мы укажем сами.
О формате JSON я писал немного инфы в статье про создание авторизации через вк
Так вот, в этом callback запросе вк может уведомлять обо всём: новых сообщениях группы, исходящих от группы сообщениях, видео, аудио, комментариях, новых подписчиках и так далее. И мы, прочитав этот запрос, можем решить, как на этот запрос реагировать.
Прямо как платёжные системы. Магия.
Давайте по порядку. Для того, чтобы воспользоваться callback api для создания бота или ещё чего-бы то ни было, нужно:
Сначала, конечно же, создать группу.
Открыть раздел «Управление сообществом», в котором справа будет вот такое меню:
Выбираем работу с API, где и имеем все настройки.
В первую очередь нужно создать API ключ, который сразу желательно где-то записать, потому что для его повторного отображения нужно будет получать смску на телефон.
Наверху водится вкладка с Callback API.
Откройте её и посмотрите, что там есть. Сразу можете указать в типах событий «Входящее сообщение», остальные пока не трогаем, иначе они будут без нужды напрягать сервер как вк, так и Ваш.
Предлагаю сделать вот что:
Пусть бот будет отвечать на сообщения этим же сообщением, которое ему прислали, только задом-наперёд, ахах
Для начала давайте слепим два файла. callback.php и vk.class.php. Класс нужен чисто для удобства, чтобы не громоздить большую кучу кода в одном файлике. Сделаем всё аккуратно
Забегая наперёд скажу, что локалхосты указывать нельзя, сервер вк их попросту не увидит, для тестов или даже полноценного бота вам в любом случае придётся завести какой-нибудь худо-бедный сервачок.
Перед использованием самого каллбек апи придётся так же для начала подтвердить свой каллбек-скрипт, отдав вк нужную строку. Все запросы от каллбека будут лететь в формате JSON (уже говорил) и вк как бы сам показывает, как они будут выглядеть. Первый из них, это confirmation, который будет смотреться примерно так:
{ "type" : "confirmation" , "group_id" :ИДГРУППЫ} |
Идём теперь в наш callback.php, в котором для начала нужно получить запрос от вк и проверить, что же там пришло и сразу это обработать. О структуре запроса отправляемого от вк можно узнать из официальной документации вк
Ниже приведён сразу полный код файла callback.php, который будет укомплектован тонной комментариев )
Весь код будет максимально упрощен, во многих местах на каком-то большом и серьёзном проекте так лучше не делать ) Нужны будут как минимум обработчики ошибок и так далее, которые вк может вполне себе вернуть. Так же желательно будет использовать секретный ключ и всякое-разное
<?php $arr = json_decode( $body , true); //Разбираем json запрос на массив в переменную $arr if ( $arr [ 'type' ] == 'confirmation' ) { //Если нам пришел запрос на подтверждение callback скрипта, то exit ( "xxxxxxxx" ); //отдаём в ответ свой код подтверждения выданный вк и останавливаем скрипт, дальше ему ничего не требуется } //Если скрипт выполняется дальше, значит это не confirmation, а одно из уведомлений. //Т.к. на данном этапе мы обрабатываем только входящее письмо, значит это входящее письмо if ( $arr [ 'type' ] == 'message_new' ) { //Проверим на всякий случай, точно ли это входящее письмо function cir_strrev( $stroka ){ //Так как функция strrev не умеет нормально переворачивать кириллицу, нужен костыль через массив. Создадим функцию preg_match_all( '/./us' , $stroka , $array ); return implode( '' , array_reverse ( $array [0])); } //Значит точно входящее. Можно уже и наш класс подключить include_once ( 'vk.class.php' ); //Меж дела подключаем наш vk.class.php //Сразу и создадим этот класс, который будет написан чуть позже //Сюда пишем ключ апи, который создавали в самом начале $vk = new vk( 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' ); $sms = $arr [ 'object' ][ 'body' ]; //Получаем текст сообщения, которое нам пришло. //О структуре этого массива который прилетел нам от вк можно узнать из официальной документации. Ссылка выше, до кода //Сразу и user_id получим, которому нужно отправлять всё это назад $vk_id = $arr [ 'object' ][ 'user_id' ]; //Перевернём строку задом-наперёд используя php функцию strrev $sms_rev = cir_strrev( $sms ); //Используем наш ещё не написанный класс, для отправки сообщения в ответ $vk ->send( $vk_id , $sms_rev ); } exit ( 'ok' ); //Обязательно возвращаем "ok", иначе вк отправит уведомление несколько раз |
Теперь, собственно, сам vk.class.php:
<?php //Задаём класс class VK { public $token = '' ; //Создаём публичную переменную для токена, который нужно отправлять каждый раз при использовании апи вк public function __construct( $token ) { $this ->token = $token ; //Забиваем в переменную токен при конструкте класса } public function send( $id , $message ) { //Задаём публичную функцию send для отправки сообщений //Заполняем массив $data инфой, которую мы через api отправим до вк. О функции api "messages.send" можно почитать в официальной документации вк $data = array ( 'peer_id' => $id , 'message' => $message , 'v' => '5.46' , //Версия для функции. Её передавать нужно обязательно. Узнать нужную можно через официальную документацию вк ); //Получаем ответ через функцию отправки до апи, которую создадим ниже $out = $this ->request( 'messages.send' , $data ); //И пусть функция вернёт ответ. Правда в данном примере мы это никак не будем использовать, пусть будет задаток на будущее return $out ; } public function request( $method , $data = array ()) { $curl = curl_init(); //мутим курл-мурл в переменную. Для отправки предпочтительнее использовать курл, но можно и через file_get_contents если сервер не поддерживает $data [ 'access_token' ] = $this ->token; //токен, который нужно отправить вместе с запросом тоже нужно добавить в дату curl_setopt( $curl , CURLOPT_URL, 'https://api.vk.com/method/' . $method ); //Ссылки до разных методов апи вк выглядят так: https://api.vk.com/method/И_ТУТ_САМ_МЕТОД, поэтому метод вполне можно забивать в эту функцию и без всяких ссылок curl_setopt( $curl , CURLOPT_RETURNTRANSFER, true); curl_setopt( $curl , CURLOPT_CUSTOMREQUEST, 'POST' ); //Отправляем через POST curl_setopt( $curl , CURLOPT_POST, true); curl_setopt( $curl , CURLOPT_POSTFIELDS, $data ); //Сами данные отправляемые $out = json_decode(curl_exec( $curl ), true); //Получаем результат выполнения, который сразу расшифровываем из JSON'a в массив для удобства curl_close( $curl ); //Закрываем курл return $out ; //Отправляем ответ в виде массива } } |