Взаимодействие пользователя с ботом должно быть интуитивным. Пользователь должен понимать, как общаться с ботом чтобы получить необходимый результат. Давайте рассмотрим какие есть способы взаимодействия с ботом.
При открытии бота по умолчанию сразу доступна кнопка Старт, при нажатии, на которую будет начат диалог и в бот будет отправлена команда
. Уже здесь мы можем поймать эту команду, обработать и выполнить какие-то действия. Вместе с этой командой в бот отправляется минимальная информация о пользователе:/start
- id - уникальный идентификатор пользователя в Telegram
- last_name - значение поля фамилия, может быть пустым
- first_name - значение поля имя, может быть пустым
- username - уникальное значение текстовый идентификатор, может быть пустым
- language_code - кодовое обозначение выбранного языка интерфейса приложения (en, ru ...)
- is_bot - флаг, определяющий пользователя как бота, в случае с ботом равен 1, в случае с пользователем пустое значение
* * *
Полезный инструмент
У каждого бота есть ссылка, которая открывает диалог с ним в Telegram — https://telegram.me/ИМЯ_БОТА
. К этой ссылке можно добавить параметры start
или startgroup
со значениями. Значение может быть длиной от 1 до 64 символов и состоять из букв латинского алфавита (больших - A-Z и маленьких - a-z), цифр - 0-9, нижнего подчеркивания _ и тире -.
https://telegram.me/ИМЯ_БОТА?start=ВАШЕ_ЗНАЧЕНИЕ
Telegram Bot API рекомендует использовать base64url для кодирования параметров с двоичным и другими типами контента.
По ссылке с параметром start будет открыт диалог с ботом, с кнопкой Старт в месте поля ввода. Если используется параметр startgroup, пользователю будет предложено выбрать группу для добавления бота.
Как только пользователь подтвердит действие (нажмет кнопку Пуск в своем приложении или выберет группу для добавления бота), ваш бот получит сообщение от этого пользователя в таком формате:
/start ВАШЕ_ЗНАЧЕНИЕ
Для удобства пользователя, можно через настройки
вашего бота у @BotFather, задать список поддерживаемых ботом команд. Тогда при вводе знака слеш Commands
, пользователь увидит все команды и сможет сразу их отправить, просто нажав на одну из них. Каждая команда состоит из собственно командного слова, начинающегося со слеша и короткого описания:/
/invoice Выписать счет
* * *
Клавиатуры и их возможности
Для управления ботом вы как создатель бота предполагаете какой-то сценарий. Пользователю чтобы получить от бота желаемый результат нужно отправить команду. Бот, когда получит команду обработает ее и отреагирует по установленному вами сценарию. Но представьте, что пользователь написал команду с ошибкой, бот в этом случае должен предупредить что команда не распознана и попросить попробовать еще раз. Это не совсем удобно пользователю, и он может пойти искать другого бота с аналогичными возможностями. Вы можете потерять потенциального клиента, это не совсем хорошо.
В этом случае нам помогут клавиатуры. Ее нужно просто после старта диалога с ботом вывести на экран пользователю, и когда тот нажмет на нужную ему кнопку, боту отправиться заложенная вами правильная команда. В этом случае уходим от возможных ошибок, интерфейс бота выглядит более приветливо и профессионально. Качество бота повышается.
С каждым сообщением бот может отправлять разный набор кнопок как по количеству, так и по назначению. Кнопки можно расположить непосредственно под сообщением (InlineKeyboardButton), или зафиксировать под тестовым полем для ввода сообщения (KeyboardButton). Различия в них очень существенные на мой взгляд. Давайте рассмотрим некоторые их возможности.
KeyboardButton
Этот объект представляет одну кнопку клавиатуры, располагающуюся под текстовым полем для отправки сообщения. Поставляется она в интерфейс приложения в наборе с другими аналогичными кнопками через объект ReplyKeyboardMarkup. В качестве параметров с ним можно передать:
- text - текст который будет на отображен на кнопке, обязательный параметр, поддерживает текст и смайлики (эмодзи)
- request_contact - если параметр установлен в true, пользователь отправит в бот свой номер телефона на который зарегистрирован аккаунт
- request_location - если параметр установлен в true, пользователь отправит в бот свое текущее местоположение
Если будет заполнен только обязательный параметр text
, то при нажатии на кнопку будет отправлено текстовое сообщение с содержанием из этого параметра. Если будет включено дополнительно одно из необязательных параметров или локация, или контакт, то будет отправлен или контакт, или локация соответственно. Необязательные параметры взаимоисключающие.
Помимо набора кнопок в объект ReplyKeyboardMarkup
можно передать еще ряд параметров:
- keyboard - массив кнопок (объекты KeyboardButton)
- resize_keyboard - если предать true, то клавиатура подгонится по высоте до возможного минимума.
- one_time_keyboard - возможность скрывать клавиатуру после ее использования
- selective - если надо показать клавиатуру только определенным пользователям
При необходимости удалить клавиатуру используйте объект ReplyKeyboardRemove.
InlineKeyboardButton
Это объект одной кнопки встроенной клавиатуры. Располагается набор таких кнопок сразу под сообщением. С помощью этого объекта можно передать кнопке url
, или использовать его для голосования как одним из вариантов. В любом случае можно сделать много интересного и полезного. Рассмотрим его возможности на практике чуть ниже. Передается в наборе с другими аналогичными кнопками через объект InlineKeyboardMarkup. Принимает параметры:
- text - текст который будет на отображен на кнопке, обязательный параметр, поддерживает текст и смайлики (эмодзи)
- url - адрес на который будет направлен пользователь
- callback_data - строка 1-64 символа будет передан боту через объект CallbackQuery
- switch_inline_query - после нажатия будет предложен выбор чата где будет использован бот во встроенном режиме, пример @gif dog
- switch_inline_query_current_chat - после нажатия вставит команду для использования бота во встроенном режиме в текущем чате
- callback_game - описание игры, которая будет запущена при нажатии пользователем кнопки.
* * *
Теперь немного практики
Предлагаю рассмотреть поближе возможности клавиатур. Для примера я сделаю 4 кнопки: 2 KeyboardButton и 2 InlineKeyboardButton. Для этого будем работать с теми же инструментами, которые были в предыдущей статье. Добавим только несколько новых методов.
Логика скрипта будет простая, при старте бот будет выводить сообщение о готовности и 2 кнопки Голосовать и Помощь. При нажатии на кнопку Помощь - выведется сообщение с небольшой инструкцией, а при нажатии на кнопку Голосовать на экране появиться сообщение и под ним 2 кнопки, при нажатии на которые произойдет увеличения счетчика.
Чтобы обрабатывать команды от всех типов кнопок нам надо составить условия проверки. В моем примере от кнопки KeyboardButton команда приходит в виде обычного текстового сообщения вместе с объектом Message под ключом text, а от кнопки InlineKeyboardButton в объекте CallbackQuery под ключом data.
<?php
// если это просто объект message
if (array_key_exists('message', $arrData)) {
// получаем id чата
$chat_id = $arrData['message']['chat']['id'];
// текстовое значение
$message = $arrData['message']['text'];
// если это объект callback_query
} elseif (array_key_exists('callback_query', $arrData)) {
$chat_id = $arrData['callback_query']['message']['chat']['id'];
$message = $arrData['callback_query']['data'];
}
?>
Кнопки будем отправлять в параметре reply_markup в методе sendMessage. Набор кнопок идет в таком формате:
Массив данных (
'Тип клавиатуры' =>
Массив строк кнопок (
Массив кнопок строки (
Массив параметров кнопки (
)
)
),
// если предусмотрено
'Дополнительный параметр',
)
Создадим два метода для разных клавиатур, на входе принимают массив строк кнопок, на выходе строку в формате JSON.
<?php
private function getInlineKeyBoard($data)
{
$inlineKeyboard = array(
"inline_keyboard" => $data,
);
return json_encode($inlineKeyboard);
}
private function getKeyBoard($data)
{
$keyboard = array(
"keyboard" => $data,
"one_time_keyboard" => false,
"resize_keyboard" => true
);
return json_encode($keyboard);
}
?>
Сам набор кнопок будет выглядеть вот так.
<?php
$justKeyboard = $this->getKeyBoard([[["text" => "Голосовать"], ["text" => "Помощь"]]]);
$inlineKeyboard = $this->getInlineKeyBoard([[
['text' => hex2bin('F09F918D') . ' 0', 'callback_data' => 'vote_1_0_0'],
['text' => hex2bin('F09F918E') . ' 0', 'callback_data' => 'vote_0_0_0']
]]);
?>
Во встроенных кнопках (inlineKeyboardButton) в качестве значения параметра callback_data будем передавать служебную информацию в виде
, где action_type_count1_count2
- action - действие, в нашем случае это vote
- type - тип кнопки: 1 - левая, 0 - правая
- count1 - текущее значение левой кнопки
- count2 - текущее состояние правой кнопки
В значении параметра text передаем бинарный код эмодзи в кодировке UTF-8 (список эмодзи), которые преобразуются из шестнадцатеричных данных в двоичные данные функцией hex2bin, и еще выведем текущее числовое значение счетчика кнопки.
Теперь нам остается только описать механизм определения команды и механизм ее обработки. Поэтому в методе init() создадим конструкцию оператора switch
<?php
switch ($message) {
// если начало диалога
case '/start':
$dataSend = array(
'text' => "Приветствую, давайте начнем нашу практику. Нажмите на кнопку Голосовать.",
'chat_id' => $chat_id,
// отправляем клавиатуру
'reply_markup' => $justKeyboard,
);
$this->requestToTelegram($dataSend, "sendMessage");
break;
// если пришла команда Голосовать
case 'Голосовать':
$dataSend = array(
'text' => "Выберите один из вариантов",
'chat_id' => $chat_id,
// отправляем встроенную клавиатуру
'reply_markup' => $inlineKeyboard,
);
$this->requestToTelegram($dataSend, "sendMessage");
break;
// если запросили Помощь
case 'Помощь':
$dataSend = array(
'text' => "Просто нажмите на кнопку Голосовать.",
'chat_id' => $chat_id,
);
$this->requestToTelegram($dataSend, "sendMessage");
break;
// если вызвана встроенная кнопка
case (preg_match('/^vote/', $message) ? true : false):
// получаем новую клавиатуру
$params = $this->setParams($message);
$dataSend = array(
'reply_markup' => $params[0],
'message_id' => $arrData['callback_query']['message']['message_id'],
'chat_id' => $chat_id,
);
// изменяем клавиатуру под выбранным сообщением
$this->changeVote($dataSend, $params[1], $arrData['callback_query']['id']);
break;
// незапланированное действие обрабатываем как поумолчанию
default:
$dataSend = array(
'text' => "Не запланированная реакция, может просто нажмете на кнопку Голосовать.",
'chat_id' => $chat_id,
);
$this->requestToTelegram($dataSend, "sendMessage");
break;
}
?>
Давайте разберемся, что в этом коде происходит. Оператор switch
принимает значение $message
, которое может быть, как просто текст сообщения (в том числе команды), так и значение объекта callbackQuery
.
- При получении команды /start - мы выводим приветственное слово и набор кнопок: Голосовать, Помощь.
- При получении команды Помощь, выводим простое текстовое сообщение.
- При получении команды Голосовать, выводим текстовое сообщение и набор встроенных кнопок с параметром
callback_data
. - При получении не запланированного значения, выводим текстовое сообщение.
- И самое интересное это когда принимаем значение в начале которого стоит
, в нашем случае этоaction
vote
. Мы формируем новую клавиатуру изменяем в ней текстовое значение, увеличиваем счетчик у нажатой кнопки и подставляем новую служебную информацию в параметрахcallback_data
.
Для создания новой клавиатуры мы используем метод setParams()
, а для отправки изменений мы используем метод changeVote(). Здесь остановим внимание на методах Bot API
- editMessageReplyMarkup - меняем клавиатуру у заданного сообщения
- answerCallbackQuery - позволяет выводить уведомление о проделанной работе CallbackQuery, мы его используем, уведомляя пользователя что он удачно проголосовал.
<?php
private function changeVote($data, $emoji, $callback_query_id)
{
// готовим текст уведомления взависимости от результата
// обновления клавиатуры у сообщения
$text = $this->requestToTelegram($data, "editMessageReplyMarkup")
? "Вы проголосовали " . hex2bin($emoji)
: "Непредвиденная ошибка, попробуйте позже.";
// отправляем уведомление при любом результате
$this->requestToTelegram([
'callback_query_id' => $callback_query_id,
'text' => $text,
'cache_time' => 3,
], "answerCallbackQuery");
}
private function setParams($data)
{
// разбиваем в массив по знаку _
$params = explode("_", $data);
// увеличиваем значение или левой или правой кнопки
$params[1] ? $params[2]++ : $params[3]++;
// готови клавиатуру с новыми значениями callback_data
$arr[] = $this->getInlineKeyBoard([[
[
'text' => hex2bin('F09F918D') . ' ' . $params[2],
'callback_data' => 'vote_1_' . $params[2] . '_' . $params[3]
],
[
'text' => hex2bin('F09F918E') . ' ' . $params[3],
'callback_data' => 'vote_0_' . $params[2] . '_' . $params[3]
]
]]);
// готовим эмодзи для уведомления
$arr[] = $params[1] ? 'F09F918D' : 'F09F918E';
return $arr;
}
?>
* * *
Подводим итоги
Мы рассмотрели некоторые способы взаимодействия между пользователем и ботом, в основном это элементы интерфейса бота.
Откройте по ссылке или QR бот @iMakeBot, нажмите кнопку Старт/Start.
Следуйте инструкциям бота.
Ты не подскажешь как в цикле вывести инлайн-кнопки, мне нужно 30 шт вывести из базы
30 шт лучше выводить с постраничной навигацией по 10 шт например, у Телеграм если не ошибаюсь установлено ограничение.
У меня была ситуация, когда на 32 строке кнопок был косяк, но постраничка решила проблему.
А вывести не сложно если из базы получить массив то стандартными функциями (foreach, for, do while ...) php можно спокойно это сделать.
что нужно дописать этому боту сюда:
чтобы он вел лог отдельно для каждого чат_айди в папке log?
Здравствуйте а как кнопкам меню задать стиль ширину и длину?
К сожалению Телеграм это не позволяет регулировать.
жалко что вам скрин нельзя прислать, может я не правильно спросил, а как их перенести по принципу <br> что б они в столбик были?
Если я правильно понял ваш вопрос, то это можно сделать просто - разбить массив на вложенность кратное необходимому кол-во строк.
можно еще подробней узнать о
хочу реализовать реф систему
Откройте ветку на форуме, там удобнее. Только вопрос по больше разверните, что именно вам нужно узнать.
Как доставать это значение? ВАШЕ_ЗНАЧЕНИЕ
Например если вы переходите по ссылке https://t.me/your_bot/start=123456789
Значение будет лежать:
1. Если приводить к объекту json_decode(file_get_contents('php://input'))->message->text
2. Если приводить к ассоциативному массиву json_decode(file_get_contents('php://input'), true)['message']['text']
Это значение будет /start 123456789
ТАК я формирую ссылку
но когда я перехожу по ссылке мне выдает ошибку
Старт выглядит также как у вас
1. Просьба оформить топик на форуме все еще актуальна.
2. У вас нет необходимого case поэтому условие проваливается в default, обратите внимание я вам выше писал, какое значение вам будет прилетать /start 123456789, где 123456789 в вашем случае это подставленный $chat_id
/start 123456789 и /start - разные case
Спасибо, очень полезная статья)
Автор, спасибо тебе огромное! Благодаря тебе я сделал кнопки, а то неделю с ними провозился! Просто я копировал этого бота из вк (у меня там уже работает бот на РНР) и поставил не думая $message = $text. Спасибо!!!
Подскажите, а можно inline кнопкой просто отправить текст, как делает это KeyboardButton
На кнопку навесить обработчик, который направит текст по событию
Если не сложно, можете написать пример как это реализовать?)
В статье выше есть как раз этот пример с голосованием.