Бот для 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’е, ну а тут выведу вам результат теста только одного варианта с отрывком поэмы Сергея Есенина.

Надеюсь я смог решить вашу проблему.

Исходники

Разумеется, важно выложить исходники бота. Если не хотите все перечитывать, просто скачайте их и тестируйте.

RevcomBot исходники
Скачано: 0, размер: 578.6 KB, дата: 24.Май.2017

Желающие могут поиграться с демонстрационным ботом тут — revcom_bot

 

Запись Бот для telegram на php. Отложенный постинг, кнопки, инлайн-запросы. впервые появилась Личный блог Гарри.

Источник

Комментарии (28):

seoonly.ru25.05.2017 02:09

Коммуникабельный бот-)

aftamat4ik25.05.2017 02:09

ну дык, Дуров постоянно улучшает telegram, то кнопки добавит, то короткие войс-сообщения, то еще что-то. А люди хотят в своих ботах всю эту хрень видеть, ну и… приходится искать способы реализации, как говорится.

Александра25.05.2017 17:12

Спасибо огромное! Реально круто! тоже вчера на эти кнопки полдня убила, но так и не дошла до логичного завершения, а сегодня с вашей помощью все ок! Сейчас пробую методы editMessageCaption и editMessageReplyMarkup, чтоб не новые сообщения отправлялись, а перезатирались старые (особенно полезно для клавиатур). Еще раз спасибо

aftamat4ik25.05.2017 17:43

пожалуйста) очень рад, что смог помочь

Ваше слово, товарищ Браузер26.05.2017 23:02

Ебааааать! Ты Штокман? Троцкач, которого еще когда соцсети были молодыми и рулили форумы, банили повсюду. Чур, меня, чур. Форум РКСМ(б) помнишь, форум ревфронта загорска? Какие срачи были, эх….

aftamat4ik26.05.2017 23:02

нет, я немного не тот Штокман. Тот Андрей, вроде, а я Саша.

Хасан26.05.2017 23:02

Привет, было бы здорово если бы написал статью про интернет магазинов или доставка еды. Щас такие боты актуальная тема помоэму!

aftamat4ik26.05.2017 23:02

я не занимаюсь доставкой еды и интернет магазинами, но если статья поможет кому-то из кодеров написать бота для магазина или чего-то еще я буду только рад. А сам я про магазины не пишу.

Виктор28.05.2017 16:26

Здарова, а как подключиться к БД?
я попробовал так, но не сработал..

$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);
});

aftamat4ik28.05.2017 16:26

насчет бд это вам не ко мне, а к документации php
советую сделать так, как написано тут — http://www.softtime.ru/bookphp/gl12_10.php
К слову, не используйте mysqli, если не уверены в том, что это расширение есть на сервере.

Али26.06.2017 02:27

Добрый вечер aftamat4ik!
как можно обработать InlineKeyboard и ReplyKeyboard в методе on()??

aftamat4ik26.06.2017 02:27

я же показал пример как обрабатывать, вот тут обработка 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, как я делаю в примере(там их даже три!). Скачайте файлы исходников и посмотрите.

Али26.06.2017 02:27

не получается объединить их(
Вот код:
________________________________________________________________
$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 — команда проходит
});
_______________________________________

aftamat4ik26.06.2017 02:27

если не получается — используйте по рознь оба сразу. Это удобнее т.к. код проще читать будет.

Али26.06.2017 02:27

т.е. использовать два раза метода on()??
так тоже попробовал но не получилось, так как они связаны между собой(

aftamat4ik26.06.2017 02:27

да два раза использовать. Попробуйте из одного к другому обращаться через глобальные(global) переменные или триггеры файловые.

Mixa23.08.2017 04:29

Скажите, а можно как то отправлять в канал в бдном сообщении и текст, и изображение, да так, чтобы урл изображения не отображался. Пробовал в режиме HTML. но там тег <img не поддерживается

aftamat4ik23.08.2017 04:29

нет, никак нельзя, этого телеграм сам по себе не позволяет сделать. Можно отправить картинку + небольшой текст-описание под нее, не более этого.

Роман23.08.2017 04:29

Привет. Пытаюсь по крону запустить файл, чтоб каждые 10 мин слал сообщение в чат, приходят ошибки, хотя если вручную запускать все работает:
PHP Fatal error: Uncaught exception ‘TelegramBot\Api\HttpException’ with message ‘Bad Request’ in /telegramMonitor/vendor/telegram-bot/api/src/BotApi.php:261

Подскажите, из-за чего может быть такое?

aftamat4ik23.08.2017 04:29

вероятно из-за версии php, но это не точно, пишите разрабам библиотеки telegram/BotApi прямо на гитхаб вот сюда — https://github.com/TelegramBot/Api/issues
полностью вашу проблему. я же не могу ответить в чем может быть ошибка внутри библиотеки бота т.к. сам ее я не писал и даже не форкал.

Balumba23.08.2017 04:29

Доброго времени суток. Подскажите пожалуйста. Как получить id пользователя, отправившего запрос боту?
Например:
$bot->command(‘start’, function ($message) use ($bot) {

});
Я не силён в ооп. Поэтому задаю этот, может глупый, вопрос.

aftamat4ik23.08.2017 04:29

примерно так:

$bot->command('start', function ($message) use ($bot) {
$user = $message->getFrom();
$id = $user->getId();
}
);

вот, я так делаю — http://take.ms/GExUV (скрин)

DLC23.08.2017 04:29

Здравствуйте! а можете скинуть пример какова нибудь бота! с использованием этой библиотеки! т.е где используются большинства
функций и как правильно реализовывать функционал этой библиотеки! если есть уже у вас готовые боты с данной библиотекой!

aftamat4ik23.08.2017 04:29

тут УЖЕ выложен пример бота

DLC23.08.2017 04:29

А как сделать чтобы бот мог читать html теги? при отправке сообщения!

DLC23.08.2017 04:29

Всё сам разобрался!
$bot->sendMessage($message->getChat()->getId(), ‘Раздел продукция!’, ‘HTML’);

#131.01.2018 19:30
А как сделать запрос телефона или локации?
#207.03.2018 14:02
$keyboard = new \TelegramBot\Api\Types\ReplyKeyboardMarkup([[["text" => "Отправить номер телефона", 'request_contact' => true], ["text" => "Отмена"]]], true, true);

Войдите или зарегистрируйтесь чтобы оставить комментарий