Бот для telegram на php. Отложенный постинг, кнопки, инлайн-запросы.
В общем-то, эта статья является дополнением этой — Пишем бота для Telegram на php, так-что если вы попали сюда впервые — советую, для начала, прочитать ее.
Здесь я отвечу читателям на ряд вопросов, которые мне были заданы тут на блоге, см комментарии в указанном выше посте. В общем и целом, все варианты тут будут приведены на php, однако ничто не мешает вам использовать так-же и C# тоже, да и любой другой язык.
Как, используя бота, публиковать новости в свой канал
Поясню для читателя, что такое канал. Канал, это что-то вроде паблика вк, на нем нельзя общаться, но можно читать, что пишет автор этого самого канала. Как пример — Красные Котлеты — это мой личный канал, подписывайтесь, к стати. Ну, если мои взгляды (анархо-коммунист) разделяете, разумеется.
Для решения этой, с виду не такой уж простой, задачи надо добавить нашего бота в канал, как администратора. Чтобы сделать это, я, на своей текущей версии телеграма, перехожу в админку канала и добавляю туда своего бота из вышеуказанной статьи. Переходим в управление группой -> administrators
Тыкаем туда, после чего указываем ник нашего бота и добавляем.
Отлично!
Код
А тут, на самом деле, ничего сложно нет. Фича именно что не очевидная, для многих. Сейчас поясню. По идее нам надо отправлять в канал сообщения через метод $bot->sendMessage(), однако, первый аргумент этого метода требует наличия некоего ID чата, в который отсылается сообщение. В случае с чатами, конфами и прочей фигней эти самые ID — цифровые, как у групп в VK, а вот в случае с каналами такие ID соответствуют названию самих каналов. Поэтому чтобы отослать в канал «Красные котлеты» сообщение «Тест» сгодится такой код:
$bot->sendMessage("@burgercaputt", "Тест");
Куда прописывать этот код? Да прямо между $bot = new \TelegramBot\Api\Client($token,null); и $bot->run(); впишите. В смысле примерно так, как на картинке.
Как запустить? Да легко, переходим на страничку с вашим ботом и руками нажимаем там F5(обновить).
Ну и, собственно, вот результат работы данной команды —
Теперь ничего не стоит добавить вызов данной страницы в, например, CURL и получить отложенный постинг. Разберетесь. Так-же был вопрос — как сделать, чтобы бот публиковал в канал по команде, или публиковал в несколько каналов. — Запросто — используйте банальные GET параметры, вот как примерно в этом наброске кода:
if($_GET["bname"] == "revcombot"){
$bot->sendMessage("@burgercaputt", "Тест");
}
if($_GET["bname"] == "someoother"){
$bot->sendMessage("@someoother", "Тест");
}
Теперь достаточно обратиться к файлу index.php с get параметрами вида index.php?bname=revcombot. Дальше, думаю, сами разберетесь.
Как вывести кнопки после сообщения и обработать их
Для начала о каких кнопках идет речь. Вот на картинке вы видите их:
Как вывести такие кнопки используя telegram-bot/api? Вообще это весьма обширная тема, я чуть ли не два часа потратил на эти гребаные кнопки и попытки их осилить. Выводятся они следующим кодом:
// Кнопки у сообщений
$bot->command("ibutton", function ($message) use ($bot) {
$keyboard = new \TelegramBot\Api\Types\Inline\InlineKeyboardMarkup(
[
[
['callback_data' => 'data_test', 'text' => 'Answer'],
['callback_data' => 'data_test2', 'text' => 'ОтветЪ']
]
]
);
$bot->sendMessage($message->getChat()->getId(), "тест", false, null,null,$keyboard);
});
То есть по команде /ibutton вылезут к нам две кнопки Answer и ОтветЪ. С выводом разобрались, теперь нам надо их обработать. Это очень сложная часть всей свистопляски, которая отняла у меня изрядно времени. Делается все так:
// Обработка кнопок у сообщений
$bot->on(function($update) use ($bot, $callback_loc, $find_command){
$callback = $update->getCallbackQuery();
$message = $callback->getMessage();
$chatId = $message->getChat()->getId();
$data = $callback->getData();
if($data == "data_test"){
$bot->answerCallbackQuery( $callback->getId(), "This is Ansver!",true);
}
if($data == "data_test2"){
$bot->sendMessage($chatId, "Это ответ!");
$bot->answerCallbackQuery($callback->getId()); // можно отослать пустое, чтобы просто убрать "часики" на кнопке
}
}, function($update){
$callback = $update->getCallbackQuery();
if (is_null($callback) || !strlen($callback->getData()))
return false;
return true;
});
Вот и все. Собственно, вот результат работы этой функции:
Как вы видите — все отлично работает. Ну и вторая кнопка для большей… полноты материала.
Как вы видите так — тоже можно.
Обработка reply-кнопок
Если вы работали с botfater’ом то видели там такую панельку из кнопок, примерно:
То есть этот вид кнопок появляется не под сообщением, а под вашим текстовым полем. Как вывести эти кнопки? Вот код —
// Reply-Кнопки
$bot->command("buttons", function ($message) use ($bot) {
$keyboard = new \TelegramBot\Api\Types\ReplyKeyboardMarkup([[["text" => "Власть советам!"], ["text" => "Сиськи!"]]], true, true);
$bot->sendMessage($message->getChat()->getId(), "тест", false, null,null, $keyboard);
});
Тут задается команда /buttons после которой и появляются эти команды. Как обработать? На самом деле никакой особой обработки эти кнопки не требуют, в смысле их надо обрабатывать как обычные текстовые сообщения. В данном случае, я сделал это через метод on() —
// Отлов любых сообщений + обрабтка reply-кнопок
$bot->on(function($Update) use ($bot){
$message = $Update->getMessage();
$mtext = $message->getText();
$cid = $message->getChat()->getId();
if(mb_stripos($mtext,"Сиськи") !== false){
$pic = "http://aftamat4ik.ru/wp-content/uploads/2017/05/14277366494961.jpg";
$bot->sendPhoto($message->getChat()->getId(), $pic);
}
if(mb_stripos($mtext,"власть советам") !== false){
$bot->sendMessage($message->getChat()->getId(), "Смерть богатым!");
}
}, function($message) use ($name){
return true; // когда тут true - команда проходит
});
Ну и, собственно, если на любую из этих кнопок ткнуть, получим результат.
Обработка inline-запросов
Что такое inline запрос у telegram? Хм, на словах будет сложно объяснить, лучше покажу. Есть у нас бот, очень популярный — @vkmusic_bot, он выполняет поиск музыки по вконтакте. И его можно вызывать в любом месте телеграма. Просто прописываем его название и следом — название трека, который надо найти. Это и есть inline запрос.
Как сделать в своем боте такую-же фичу?
На самом деле эта задачка заставила меня попотеть изрядно. Я перелопатил половину буржунета и весь код долбаной библиотеки telebram-bot/api, отдебажил там все ключевые функции и только потом смог найти нормальный ответ. И знаете что? Вам, таки, повезло что я его нашел!
Подготовка бота
Не только лишь все боты могут обрабатывать inline запросы, а только те, в которых автор включил эту фичу. Идем на botfather’а и выполняем там команду /setinline, и выбираем бота. Вылезет что-то типа того:
Думаете все, режим включился? А вот фиг там было! Нам надо передать в botfather’а форму инлайн команды, примерно так: @revcom_bot тестовый inline ответ
Вот ТЕПЕРЬ можно начинать написание кода.
Код
Собственно в библиотеке бота есть метод $bot->inlineQuery(), именно он отвечает за обработку контекстных запросов. Но как заставить его работать? Оказывается у каждого поля, отправляемого в результат запроса свой формат + для некоторых полей надо данные готовить заранее. Однако я все прокомментировал, так что разобраться с этим функционалом вы сможете в два счета. А вот мне пришлось чуть ли не в слепую угадывать что и куда ставить из-за отсутствия вменяемой документации к библиотеке.
// обработка инлайнов
$bot->inlineQuery(function ($inlineQuery) use ($bot) {
mb_internal_encoding("UTF-8");
$qid = $inlineQuery->getId();
$text = $inlineQuery->getQuery();
// Это - базовое содержимое сообщения, оно выводится, когда тыкаем на выбранный нами инлайн
$str = "Что другие?
Свора голодных нищих.
Им все равно...
В этом мире немытом
Душу человеческую
Ухорашивают рублем,
И если преступно здесь быть бандитом,
То не более преступно,
Чем быть королем...
Я слышал, как этот прохвост
Говорил тебе о Гамлете.
Что он в нем смыслит?
Гамлет восстал против лжи,
В которой варился королевский двор.
Но если б теперь он жил,
То был бы бандит и вор.";
$base = new \TelegramBot\Api\Types\Inline\InputMessageContent\Text($str,"Html");
// Это список инлайнов
// инлайн для стихотворения
$msg = new \TelegramBot\Api\Types\Inline\QueryResult\Article("1","С. Есенин","Отрывок из поэмы `Страна негодяев`");
$msg->setInputMessageContent($base); // указываем, что в ответ к этому сообщению надо показать стихотворение
// инлайн для картинки
$full = "http://aftamat4ik.ru/wp-content/uploads/2017/05/14277366494961.jpg"; // собственно урл на картинку
$thumb = "http://aftamat4ik.ru/wp-content/uploads/2017/05/14277366494961-150x150.jpg"; // и миниятюра
$photo = new \TelegramBot\Api\Types\Inline\QueryResult\Photo("2",$full,$thumb);
// инлайн для музыки
$url = "http://aftamat4ik.ru/wp-content/uploads/2017/05/mongol-shuudan_-_kozyr-nash-mandat.mp3";
$mp3 = new \TelegramBot\Api\Types\Inline\QueryResult\Audio("3",$url,"Монгол Шуудан - Козырь наш Мандат!");
// инлайн для видео
$vurl = "http://aftamat4ik.ru/wp-content/uploads/2017/05/bb.mp4";
$thumb = "http://aftamat4ik.ru/wp-content/uploads/2017/05/joker_5-150x150.jpg";
$video = new \TelegramBot\Api\Types\Inline\QueryResult\Video("4",$vurl,$thumb, "video/mp4","коммунальные службы","тут тоже может быть описание");
// отправка
try{
$result = $bot->answerInlineQuery( $qid, [$msg,$photo,$mp3,$video],100,false);
}catch(Exception $e){
file_put_contents("rdata",print_r($e,true));
}
});
Как это работает в боте? Смотрим.
Проверить как это работает во всех трех случаях вы сможете прямо в telegram’е, ну а тут выведу вам результат теста только одного варианта с отрывком поэмы Сергея Есенина.
Надеюсь я смог решить вашу проблему.
Исходники
Разумеется, важно выложить исходники бота. Если не хотите все перечитывать, просто скачайте их и тестируйте.

Желающие могут поиграться с демонстрационным ботом тут — revcom_bot
Запись Бот для telegram на php. Отложенный постинг, кнопки, инлайн-запросы. впервые появилась Личный блог Гарри.
Комментарии (28):
ну дык, Дуров постоянно улучшает telegram, то кнопки добавит, то короткие войс-сообщения, то еще что-то. А люди хотят в своих ботах всю эту хрень видеть, ну и… приходится искать способы реализации, как говорится.
Спасибо огромное! Реально круто! тоже вчера на эти кнопки полдня убила, но так и не дошла до логичного завершения, а сегодня с вашей помощью все ок! Сейчас пробую методы editMessageCaption и editMessageReplyMarkup, чтоб не новые сообщения отправлялись, а перезатирались старые (особенно полезно для клавиатур). Еще раз спасибо
пожалуйста) очень рад, что смог помочь
Ебааааать! Ты Штокман? Троцкач, которого еще когда соцсети были молодыми и рулили форумы, банили повсюду. Чур, меня, чур. Форум РКСМ(б) помнишь, форум ревфронта загорска? Какие срачи были, эх….
нет, я немного не тот Штокман. Тот Андрей, вроде, а я Саша.
Привет, было бы здорово если бы написал статью про интернет магазинов или доставка еды. Щас такие боты актуальная тема помоэму!
я не занимаюсь доставкой еды и интернет магазинами, но если статья поможет кому-то из кодеров написать бота для магазина или чего-то еще я буду только рад. А сам я про магазины не пишу.
Здарова, а как подключиться к БД?
я попробовал так, но не сработал..
$mysqli = new mysqli(«localhost», «*****», «***********», «*****_db»);
if ($mysqli->connect_errno) {
echo «Не удалось подключиться к MySQL: (» . $mysqli->connect_errno . «) » . $mysqli->connect_error;
}
$bot->command(‘pip’, function ($message) use ($bot) {
$res = $mysqli->query(«SELECT name FROM stopwatch Where id=1»);
$row = $res->fetch_assoc();
$bot->sendMessage($message->getChat()->getId(), $row);
});
насчет бд это вам не ко мне, а к документации php
советую сделать так, как написано тут — http://www.softtime.ru/bookphp/gl12_10.php
К слову, не используйте mysqli, если не уверены в том, что это расширение есть на сервере.
Добрый вечер aftamat4ik!
как можно обработать InlineKeyboard и ReplyKeyboard в методе on()??
я же показал пример как обрабатывать, вот тут обработка reply-keyboard — http://aftamat4ik.ru/bot-dlya-telegram-na-php-knopki-posting-inline-queryes/#reply-buttons с методом on,
а вот — http://aftamat4ik.ru/bot-dlya-telegram-na-php-knopki-posting-inline-queryes/#buttons — обработка InlineKeyboard в методе on.
Объедините их. Или просто используйте 2 метода on, как я делаю в примере(там их даже три!). Скачайте файлы исходников и посмотрите.
не получается объединить их(
Вот код:
________________________________________________________________
$bot->command(«ibutton», function ($message) use ($bot) {
$keyboard = new \TelegramBot\Api\Types\ReplyKeyboardMarkup([[[«text» => «button1»], [«text» => «button1»]]], true, true);
$bot->sendMessage($message->getChat()->getId(), «тест», false, null,null,$keyboard);
});
// Обработка кнопок у сообщений
$bot->on(function($update) use ($bot,$callback_loc, $find_command){
$message = $update->getMessage();
$mtext = $message->getText();
switch ($mtext) {
case ‘button1’:
$keyboard = new \TelegramBot\Api\Types\Inline\InlineKeyboardMarkup(
[
[
[‘callback_data’ => ‘data_test1’, ‘text’ => ‘Answer’],
[‘callback_data’ => ‘data_test2’, ‘text’ => ‘ОтветЪ’]
]
]
);
$bot->sendMessage($message->getChat()->getId(), «тест», false, null,null,$keyboard);
break;
case ‘button1’:
$keyboard = new \TelegramBot\Api\Types\Inline\InlineKeyboardMarkup(
[
[
[‘callback_data’ => ‘data_test3’, ‘text’ => ‘Answer’],
[‘callback_data’ => ‘data_test4’, ‘text’ => ‘ОтветЪ’]
]
]
);
$bot->sendMessage($message->getChat()->getId(), «тест», false, null,null,$keyboard);
break;
}
$callback = $update->getCallbackQuery();
$message = $callback->getMessage();
$chatId = $message->getChat()->getId();
$data = $callback->getData();
switch ($data) {
case ‘data_test1’:
$bot->sendMessage($message->getChat()->getId(), «тест1», false, null,null,$keyboard);
break;
case ‘data_test2’:
$bot->sendMessage($message->getChat()->getId(), «тест2», false, null,null,$keyboard);
break;
}
}, function($message) use ($name){
return true; // когда тут true — команда проходит
});
_______________________________________
если не получается — используйте по рознь оба сразу. Это удобнее т.к. код проще читать будет.
т.е. использовать два раза метода on()??
так тоже попробовал но не получилось, так как они связаны между собой(
да два раза использовать. Попробуйте из одного к другому обращаться через глобальные(global) переменные или триггеры файловые.
Скажите, а можно как то отправлять в канал в бдном сообщении и текст, и изображение, да так, чтобы урл изображения не отображался. Пробовал в режиме HTML. но там тег <img не поддерживается
нет, никак нельзя, этого телеграм сам по себе не позволяет сделать. Можно отправить картинку + небольшой текст-описание под нее, не более этого.
Привет. Пытаюсь по крону запустить файл, чтоб каждые 10 мин слал сообщение в чат, приходят ошибки, хотя если вручную запускать все работает:
PHP Fatal error: Uncaught exception ‘TelegramBot\Api\HttpException’ with message ‘Bad Request’ in /telegramMonitor/vendor/telegram-bot/api/src/BotApi.php:261
Подскажите, из-за чего может быть такое?
вероятно из-за версии php, но это не точно, пишите разрабам библиотеки telegram/BotApi прямо на гитхаб вот сюда — https://github.com/TelegramBot/Api/issues
полностью вашу проблему. я же не могу ответить в чем может быть ошибка внутри библиотеки бота т.к. сам ее я не писал и даже не форкал.
Доброго времени суток. Подскажите пожалуйста. Как получить id пользователя, отправившего запрос боту?
Например:
$bot->command(‘start’, function ($message) use ($bot) {
…
});
Я не силён в ооп. Поэтому задаю этот, может глупый, вопрос.
примерно так:
$bot->command('start', function ($message) use ($bot) {
$user = $message->getFrom();
$id = $user->getId();
}
);
вот, я так делаю — http://take.ms/GExUV (скрин)
Здравствуйте! а можете скинуть пример какова нибудь бота! с использованием этой библиотеки! т.е где используются большинства
функций и как правильно реализовывать функционал этой библиотеки! если есть уже у вас готовые боты с данной библиотекой!
тут УЖЕ выложен пример бота
А как сделать чтобы бот мог читать html теги? при отправке сообщения!
Всё сам разобрался!
$bot->sendMessage($message->getChat()->getId(), ‘Раздел продукция!’, ‘HTML’);
А как сделать запрос телефона или локации?
$keyboard = new \TelegramBot\Api\Types\ReplyKeyboardMarkup([[["text" => "Отправить номер телефона", 'request_contact' => true], ["text" => "Отмена"]]], true, true);
Войдите или зарегистрируйтесь чтобы оставить комментарий
Коммуникабельный бот-)