Всем привет! Недавно на одном проекте мне пришлось столкнуться с ботом вк, который "живёт" в сообщениях группы. До этого я имел самый разный опыт создания ботов из личных страничек. Для того, чтобы бот мог нормально отвечать на сообщения приходилось делать самые разные извращения с кроном, таймерами, "запоминанием" сообщений и другими разными ужасами.
Как же я удивился, когда начав курить 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; //Отправляем ответ в виде массива
}
}
Рабочий пример, так сказать, демо, можно посмотреть вот здесь. )
