Всем привет! Недавно на одном проекте мне пришлось столкнуться с ботом вк, который "живёт" в сообщениях группы. До этого я имел самый разный опыт создания ботов из личных страничек. Для того, чтобы бот мог нормально отвечать на сообщения приходилось делать самые разные извращения с кроном, таймерами, "запоминанием" сообщений и другими разными ужасами.
Как же я удивился, когда начав курить VK API групп касаемо сообщений, я увидел это чудо - Callback API.
Для нетерпеливых или любящих разбираться со всем самостоятельно в конце есть готовый пример.
Статья рассчитана не для совсем новичков и я не стал её сильно затягивать, специально опустив разжёвывание совсем очевидных вещей, иначе бы это была бы очень огромная статья. Тема написания ботов в целом так-то не очень новичковая тема.
Для тех кто не знает, что это, расскажу кратко.
При помощи этой фишки вк сам, автоматически, отправляет запросы в формате JSON куда мы укажем сами.
О формате JSON я писал немного инфы в статье про создание авторизации через вк
Так вот, в этом callback запросе вк может уведомлять обо всём: новых сообщениях группы, исходящих от группы сообщениях, видео, аудио, комментариях, новых подписчиках и так далее. И мы, прочитав этот запрос, можем решить, как на этот запрос реагировать.
Прямо как платёжные системы. Магия.
Давайте по порядку. Для того, чтобы воспользоваться callback api для создания бота или ещё чего-бы то ни было, нужно:
Сначала, конечно же, создать группу.
Открыть раздел "Управление сообществом", в котором справа будет вот такое меню:
Выбираем работу с API, где и имеем все настройки.
В первую очередь нужно создать API ключ, который сразу желательно где-то записать, потому что для его повторного отображения нужно будет получать смску на телефон.
Наверху водится вкладка с Callback API.
Откройте её и посмотрите, что там есть. Сразу можете указать в типах событий "Входящее сообщение", остальные пока не трогаем, иначе они будут без нужды напрягать сервер как вк, так и Ваш.
Предлагаю сделать вот что:
Пусть бот будет отвечать на сообщения этим же сообщением, которое ему прислали, только задом-наперёд, ахах
Для начала давайте слепим два файла. callback.php и vk.class.php. Класс нужен чисто для удобства, чтобы не громоздить большую кучу кода в одном файлике. Сделаем всё аккуратно :D
Забегая наперёд скажу, что локалхосты указывать нельзя, сервер вк их попросту не увидит, для тестов или даже полноценного бота вам в любом случае придётся завести какой-нибудь худо-бедный сервачок.
Перед использованием самого каллбек апи придётся так же для начала подтвердить свой каллбек-скрипт, отдав вк нужную строку. Все запросы от каллбека будут лететь в формате JSON (уже говорил) и вк как бы сам показывает, как они будут выглядеть. Первый из них, это confirmation, который будет смотреться примерно так:
{"type":"confirmation","group_id":ИДГРУППЫ}
Идём теперь в наш callback.php, в котором для начала нужно получить запрос от вк и проверить, что же там пришло и сразу это обработать. О структуре запроса отправляемого от вк можно узнать из официальной документации вк
Ниже приведён сразу полный код файла callback.php, который будет укомплектован тонной комментариев )
Весь код будет максимально упрощен, во многих местах на каком-то большом и серьёзном проекте так лучше не делать ) Нужны будут как минимум обработчики ошибок и так далее, которые вк может вполне себе вернуть. Так же желательно будет использовать секретный ключ и всякое-разное
<?php $body = file_get_contents('php://input'); //Получаем в $body json строку $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; //Отправляем ответ в виде массива } }
Рабочий пример, так сказать, демо, можно посмотреть вот здесь. )