Функционал из данного гайда был перенесен на messengers Business API, с помощью которого вы также сможете производить рассылки, создавать чат боты и многое другое, но без риска быть заблокированным.
В связи с изменением условий работы API, в данном гайде частично могут использоваться неактуальные сведения. Пожалуйста, посмотрите документацию перед началом работы.
Сейчас Chat API предлагает самый доступный и автоматизированный messengers Business API на рынке с Многопользовательским Чатом, Визуальным конструктором ботов, готовыми интеграциями приложений и другими полезными функциями.
Расскажем, как написать простого бота на PHP, используя API messengers.
Демонстрационный бот будет реагировать на команды, поступающие ему в виде обычных сообщений в messengers и отвечать на них. Сейчас в нашем демо чатботе присутствует следующий функционал:
- Вывод списка команд
- Вывод ID текущего чата
- Вывод текущего времени сервера, на котором работает бот.
- Вывод вашего имени
- Отправка файлов разных форматов (pdf, jpg, doc, mp3 и т.д.)
- Отправка заранее записанных голосовых сообщений
- Отправка гео-координат (локации)
- Создание конференции (группы)
Внимание: чтобы бот работал, телефон должен быть всегда подключен к интернету и не должен использоваться для messengers Web. Удобнее всего заводить отдельное устройство для этих целей.
Подготовительная работа
В самом начале, сразу свяжем messengers с нашим скриптом, чтобы по мере написания кода - проверять его работу. Для этого переходим в личный кабинет и получаем там QR-код. Далее открываем messengers на мобильном телефоне, заходим в Настройки -> messengers Web -> Сканируем QR-код.
Теперь, чтобы сервер вызывал наш скрипт при новых сообщениях, нужно указать WebHook URL. Укажите там прямую ссылку на ваш скрипт, например, https://domain.com/PHP/messengersbot.php. Нельзя указать просто IP-адрес сервера. Можно указать порт.
Получить бесплатный демо-доступ к messengers APIТеперь давайте создадим файл messengersbot.php и создадим в нем класс: class messengersBot { }
Создадим в нем переменные, в которые поместим API Url и токен. Их можно узнать в личном кабинете.
{var $APIurl = 'https://api.chat-api.com/instanceYYYYY/';
var $token = 'abcdefgh12345678';}
Теперь объявим функцию __construct(), которая будет вызываться автоматически при каждом запуске скрипта. Сервер ChatAPI будет обращаться к боту при поступлении новых сообщений (об этом подробнее ниже), присылая данные о новом сообщении в JSON-формате. Сразу ловим эти данные в начале функции и помещаем в переменные.
{public function __construct(){ $json = file_get_contents('php://input');
$decoded = json_decode($json,true);}}
Продолжаем писать код функции. Опционально мы можем сохранить пришедшие данные в файл для последующего анализа и отладки, если это потребуется. Для этого мы воспользуемся буфером вывода.
{ ob_start();
var_dump($decoded);
$input = ob_get_contents();
ob_end_clean();
file_put_contents('input_requests.log',$input.PHP_EOL,FILE_APPEND);}
Теперь напишем обработку входящих сообщений и вызов соответствующих функций. Будет много вложенного кода, но мы его разберем построчно.
{ if(isset($decoded['messages'])){
foreach($decoded['messages'] as $message){
$text = explode(' ',trim($message['body']));
if(!$message['fromMe']){
switch(mb_strtolower($text[0],'UTF-8')){
case 'hi': {$this->welcome($message['chatId'],false); break;}
case 'chatId': {$this->showchatId($message['chatId']); break;}
case 'time': {$this->time($message['chatId']); break;}
case 'me': {$this->me($message['chatId'],$message['senderName']); break;}
case 'file': {$this->file($message['chatId'],$text[1]); break;}
case 'ptt': {$this->ptt($message['chatId']); break;}
case 'geo': {$this->geo($message['chatId']); break;}
case 'group': {$this->group($message['author']); break;}
default: {$this->welcome($message['chatId'],true); break;}
}}}}}
Разбираемся:
-
if(isset($decoded['messages']))
Уведомления типа "пользователь покинул чат" тоже присылаются сервером, но в них будет отсутствовать массив сообщений. Данная проверка предотвращает ошибку "Undefined index". -
foreach($decoded['messages'] as $message)
Сообщения находятся в массиве, и их может прийти несколько сообщений одновременно. Бот должен отреагировать на каждое из них. -
$text = explode(' ',trim($message['body']));
Разбиваем тело сообщения на отдельные слова. Первое слово - команда, остальные будут параметрами команды. -
if(!$message['fromMe'])
Эта проверка нужна, чтобы бот не ушел в рекурсию. Отметка "fromMe" означает, что сообщение было послано самим ботом. Поэтому выполнение продолжаем только для входящих сообщений. -
switch(mb_strtolower($text[0],'UTF-8'))
Блок switch, который определяет, что за команда содержится в первом слове. Команду приводим в строчной регистр, чтобы бот реагировал на нее независимо от того, капсом она написана, с заглавной буквы или зАбОрЧиКоМ. -
case 'hi': {$this->welcome($message['chatId'],false)}
Собственно, выполнение соответствующей команды в зависимости от первого слова. В вызываемую функцию передаем chatId из сообщения, чтобы отправка происходила в соответствующий чат. В принципе, все следующие строки одинаковые, но обратите внимание на:case 'file': {$this->file($message['chatId'],$text[1])}
Здесь мы передаем еще один параметр, а именно второе слово сообщения, т.к. оно является параметром команды. Об этом ниже. Также обратите внимание на:case 'me': {$this->me($message['chatId'],$message['senderName'])}
Здесь в качестве второго параметра стоит имя собеседника, взятое также из данных сообщения. А в default мы вызываем функцию, выводящую список команд, но с параметром true, что означает получение неправильной команды.
Мы закончили писать функцию __construct(). Теперь перейдем к функциям, вызываемым по командам из вышеупомянутого блока switch. В части функций вызывается функция sendMessage(), в другой части - sendRequest(). В скрипте эти функции помещены внизу, но расскажем о них сразу:
Функция sendRequest() осуществляет непосредственно запрос на сервер ChatAPI для отправки сообщений и различного медиа. Она принимает 2 параметра - $method и $data.
- $method определяет, какой метод chatAPI должен быть вызван.
- $data содержит необходимые для пересылки данные.
{ public function sendRequest($method,$data){
$url = $this->APIurl.$method.'?token='.$this->token;
if(is_array($data)){ $data = json_encode($data);}
$options = stream_context_create(['http' => [
'method' => 'POST',
'header' => 'Content-type: application/json',
'content' => $data
]]);
$response = file_get_contents($url,false,$options);
file_put_contents('requests.log',$response.PHP_EOL,FILE_APPEND);}
Разберем подробнее: В $url мы формируем корректный URL-адрес, содержащий APIUrl, метод и токен. Затем проверяем входящие данные. Если это массив, преобразовываем его в JSON. Если нет - значит преобразование в JSON было уже осуществлено в вызвавшей функции. $options - задаем HTTP-заголовки. Затем через file_get_contents выполняем запрос на сформированный URL, передавая данные. Последняя строка необязательна, она просто записывает ответ сервера ChatAPI в файл для отладки и логгирования.
Функция sendMessage() - по сути просто оболочка отправки простых текстовых сообщений. Она формирует корректный массив данных и передает его в вышеупомянутую функцию sendRequest() с методом "message".
{ public function sendMessage($chatId, $text){
$data = array('chatId'=>$chatId,'body'=>$text);
$this->sendRequest('message',$data);}}
Теперь создадим управляющие функции из блока switch. Функции, посылающие простое текстовое сообщение, в большинстве своем просто вызывают sendMessage() с определенным текстом. Функции, посылающие различное медиа, формируют свои массивы данных и вызывают sendRequest() с другими методами.
Функция welcome() - вывод списка доступных команд
{ public function welcome($chatId, $noWelcome = false){
$welcomeString = ($noWelcome) ? "Incorrect command\n" : "messengers Demo Bot PHP\n";
$this->sendMessage($chatId,
$welcomeString.
"Commands:\n".
"1. chatId - show ID of the current chat\n".
"2. time - show server time\n".
"3. me - show your nickname\n".
"4. file [format] - get a file. Available formats: doc/gif/jpg/png/pdf/mp3/mp4\n".
"5. ptt - get a voice message\n".
"6. geo - get a location\n".
"7. group - create a group with the bot");}}
Если параметр $noWelcome равен false, то первая строка сообщения будет приветствием, отображаемым по команде "hi". Если true - приветствие будет заменено на сообщение неверной команде.
Функция showchatId() - вывод ID текущего чата по команде "chatId".
{ public function showchatId($chatId){
$this->sendMessage($chatId,'chatId: '.$chatId);}}
Функция time() - вывод текущего времени сервера по команде "time".
{ public function time($chatId){
$this->sendMessage($chatId,date('d.m.Y H:i:s'));}}
Функция me() - вывод имени собеседника по команде "me".
{
public function me($chatId,$name){
$this->sendMessage($chatId,$name);
}}
Функция file() - отправка файла по команде "file". Эта функция наиболее интересна, т.к. работает с параметром. В качестве параметра передается формат файла, который нужно отправить.
{ public function file($chatId,$format){
$availableFiles = array(
'doc' => 'document.doc',
'gif' => 'gifka.gif',
'jpg' => 'jpgfile.jpg',
'png' => 'pngfile.png',
'pdf' => 'presentation.pdf',
'mp4' => 'video.mp4',
'mp3' => 'mp3file.mp3'
);
if(isset($availableFiles[$format])){
$data = array(
'chatId'=>$chatId,
'body'=>'https://domain.com/PHP/'.$availableFiles[$format],
'filename'=>$availableFiles[$format],
'caption'=>'Get your file '.$availableFiles[$format]
);
$this->sendRequest('sendFile',$data);}}}
Разберем подробнее:
- $availableFiles - это массив, в котором ключами выступают параметры функции, а значениями - имена файлов. Естественно, файлы с именами из массива должны присутствовать на сервере. В данном примере они лежат там же, где и скрипт бота, но вы можете поместить их в другую папку.
- if(isset($availableFiles[$format])) - проверяем существование ключа массива с полученным параметром. Если он существует, то мы формируем массив данных, и передаем его в sendRequest() с методом "sendFile". В массиве данных должны быть следующие данные:
- chatId - как обычно, ИД чата, в который посылается ответ.
- body - прямая ссылка на файл на вашем сервере. Обратите внимание, что на сервере должен быть включен SSL!
- filename - имя файла, можно указать любое
- caption - сопровождающее этот файл сообщение.
Функция ptt() - отправка голосового сообщения по команде "ptt". Голосовое сообщение должно быть файлом формата .OGG на вашем сервере.
{ public function ptt($chatId){
$data = array(
'audio'=>'https://domain.com/PHP/ptt.ogg',
'chatId'=>$chatId
);
$this->sendRequest('sendAudio',$data);}}
Здесь, как и в предыдущей функции, формируем массив данных: chatId - ID чата audio - прямая ссылка на файл .ogg, опять же обязателен SSL И передаем его функции sendRequest с методом "sendAudio".
Функция geo() - отправка гео-координат по команде "geo"
{ public function geo($chatId){
$data = array(
'lat'=>51.51916,
'lng'=>-0.139214,
'address'=>'Ваш адрес',
'chatId'=>$chatId
);
$this->sendRequest('sendLocation',$data);
}}
Все то же самое, что и в предыдущих двух функциях. Массив должен содержать следующие данные: lat и lng - координаты; address - адрес, но можно написать любую строку; chatId - само собой разумеещееся.
Функция group() - создать конференцию, в которой будете вы и бот, по команде "group".
{ public function group($author){
$phone = str_replace('@c.us','',$author);
$data = array(
'groupName'=>'Group with the bot PHP',
'phones'=>array($phone),
'messageText'=>'It is your group. Enjoy'
);
$this->sendRequest('group',$data);}}
Здесь нам требуется указать номера телефонов пользователей, которые будут добавлены в конференцию. В первой строке извлечем номер телефона пользователя из его личного ID, который имеет вид [email protected] Затем формируем массив:
- groupName - название конференции;
- phones - массив номеров телефонов;
- messageText - текст первого сообщения в группе;
Обратите внимание, что это единственная функция, где НЕ НАДО передавать chatId. И передаем массив в sendRequest().
Теперь, когда мы закончили работать с функциями, после закрывающей класс скобки напишите строчку: new messengersBot();
Чтобы класс вызвался автоматически при обращении к скрипту.
Итоговый код будет выглядеть следующим образом
{
class messengersBot{
//specify instance URL and token
var $APIurl = 'https://api.chat-api.com/instanceYYYYY/';
var $token = '**************************';
public function __construct(){
//get the JSON body from the instance
$json = file_get_contents('php://input');
$decoded = json_decode($json,true);
//write parsed JSON-body to the file for debugging
ob_start();
var_dump($decoded);
$input = ob_get_contents();
ob_end_clean();
file_put_contents('input_requests.log',$input.PHP_EOL,FILE_APPEND);
if(isset($decoded['messages'])){
//check every new message
foreach($decoded['messages'] as $message){
//delete excess spaces and split the message on spaces. The first word in the message is a command, other words are parameters
$text = explode(' ',trim($message['body']));
//current message shouldn't be send from your bot, because it calls recursion
if(!$message['fromMe']){
//check what command contains the first word and call the function
switch(mb_strtolower($text[0],'UTF-8')){
case 'hi': {$this->welcome($message['chatId'],false); break;}
case 'chatId': {$this->showchatId($message['chatId']); break;}
case 'time': {$this->time($message['chatId']); break;}
case 'me': {$this->me($message['chatId'],$message['senderName']); break;}
case 'file': {$this->file($message['chatId'],$text[1]); break;}
case 'ptt': {$this->ptt($message['chatId']); break;}
case 'geo': {$this->geo($message['chatId']); break;}
case 'group': {$this->group($message['author']); break;}
default: {$this->welcome($message['chatId'],true); break;}
}}}}}
//this function calls function sendRequest to send a simple message
//@param $chatId [string] [required] - the ID of chat where we send a message
//@param $text [string] [required] - text of the message
public function welcome($chatId, $noWelcome = false){
$welcomeString = ($noWelcome) ? "Incorrect command\n" : "messengers Demo Bot PHP\n";
$this->sendMessage($chatId,
$welcomeString.
"Commands:\n".
"1. chatId - show ID of the current chat\n".
"2. time - show server time\n".
"3. me - show your nickname\n".
"4. file [format] - get a file. Available formats: doc/gif/jpg/png/pdf/mp3/mp4\n".
"5. ptt - get a voice message\n".
"6. geo - get a location\n".
"7. group - create a group with the bot"
);
}
//sends Id of the current chat. it is called when the bot gets the command "chatId"
//@param $chatId [string] [required] - the ID of chat where we send a message
public function showchatId($chatId){
$this->sendMessage($chatId,'chatId: '.$chatId);
}
//sends current server time. it is called when the bot gets the command "time"
//@param $chatId [string] [required] - the ID of chat where we send a message
public function time($chatId){
$this->sendMessage($chatId,date('d.m.Y H:i:s'));
}
//sends your nickname. it is called when the bot gets the command "me"
//@param $chatId [string] [required] - the ID of chat where we send a message
//@param $name [string] [required] - the "senderName" property of the message
public function me($chatId,$name){
$this->sendMessage($chatId,$name);
}
//sends a file. it is called when the bot gets the command "file"
//@param $chatId [string] [required] - the ID of chat where we send a message
//@param $format [string] [required] - file format, from the params in the message body (text[1], etc)
public function file($chatId,$format){
$availableFiles = array(
'doc' => 'document.doc',
'gif' => 'gifka.gif',
'jpg' => 'jpgfile.jpg',
'png' => 'pngfile.png',
'pdf' => 'presentation.pdf',
'mp4' => 'video.mp4',
'mp3' => 'mp3file.mp3'
);
if(isset($availableFiles[$format])){
$data = array(
'chatId'=>$chatId,
'body'=>'https://domain.com/PHP/'.$availableFiles[$format],
'filename'=>$availableFiles[$format],
'caption'=>'Get your file '.$availableFiles[$format]
);
$this->sendRequest('sendFile',$data);}}
//sends a voice message. it is called when the bot gets the command "ptt"
//@param $chatId [string] [required] - the ID of chat where we send a message
public function ptt($chatId){
$data = array(
'audio'=>'https://domain.com/PHP/ptt.ogg',
'chatId'=>$chatId
);
$this->sendRequest('sendAudio',$data);}
//sends a location. it is called when the bot gets the command "geo"
//@param $chatId [string] [required] - the ID of chat where we send a message
public function geo($chatId){
$data = array(
'lat'=>51.51916,
'lng'=>-0.139214,
'address'=>'Ваш адрес',
'chatId'=>$chatId
);
$this->sendRequest('sendLocation',$data);}
//creates a group. it is called when the bot gets the command "group"
//@param chatId [string] [required] - the ID of chat where we send a message
//@param author [string] [required] - "author" property of the message
public function group($author){
$phone = str_replace('@c.us','',$author);
$data = array(
'groupName'=>'Group with the bot PHP',
'phones'=>array($phone),
'messageText'=>'It is your group. Enjoy'
);
$this->sendRequest('group',$data);}
public function sendMessage($chatId, $text){
$data = array('chatId'=>$chatId,'body'=>$text);
$this->sendRequest('message',$data);}
public function sendRequest($method,$data){
$url = $this->APIurl.$method.'?token='.$this->token;
if(is_array($data)){ $data = json_encode($data);}
$options = stream_context_create(['http' => [
'method' => 'POST',
'header' => 'Content-type: application/json',
'content' => $data]]);
$response = file_get_contents($url,false,$options);
file_put_contents('requests.log',$response.PHP_EOL,FILE_APPEND);}}
//execute the class when this file is requested by the instance
new messengersBot();}
Вам необходимо будет только подставить свой токен из личного кабинета в переменную $token и номер инстанса
Получить ключ API