Pull to refresh

Диалоговый телеграм бот на PHP

Reading time 5 min
Views 156K
На данную тему написано много статей на Хабре и просто в интернете. И я расскажу о своем опыте работы с телеграм ботом и моментами, которые «в лоб» не удалось решить.

Создание бота


Первое, с чего нужно начать, так это с создания бота. Есть официальная документация и там подробно расписаны шаги.

Если в описанной инструкции ничего не понятно, то вот пошаговая инструкция
  1. находим в телеграм бота BotFather и добавляем себе в контакт лист
  2. смотрим доступные команды бота с помощью команды /help


  3. выбираем /newbot и далее, следуя инструкции, выполняем необходимые действия (следующая картинка взята из google)




После создания бота вы получите токен, которые нужно будет использовать в коде вашего бота, поэтому сообщение с токеном необходимо сохранить.

Связываем бота с приложением\сайтом


Начинается самое интересное, а также именно тут я столкнулся с первой проблемой.
Первым делом выбираем библиотеку на php по созданию бота. Я свой выбор остановил на этой библиотеке, так как мне она показалась самой удобной.

После подключения библиотеки нужно организовать взаимодействие бота с вашим сайтом\приложением. Организовать это взаимодействие можно с помощью вебхуков.

Вебхук — это своего рода ретранслятор, который все запросы от бота будет передавать на адрес, указанный при регистрации вебхука. Зарегистрировать вебхук очень просто, нужно просто отправить запрос вида https: //api.telegram.org/bot~token~/setWebhook?url=https: //example.ru/path, где
https: //example.ru/ — это ссылка на ваш сайт, куда будет перенаправлять бот запросы.
~token~ — это токен, который вы получили при регистрации своего бота.
path — это часть url, на которую будут приходить обращения.

И вот именно тут возникает проблема. Оказывается вебхук можно зарегистрировать только в случае, если сайт находится на https. Если же ваш сайт на http, то зарегистрировать вебхук вам не получится.

Но выход есть, если вы не хотите покупать сертификат
Вы можете воспользоваться сервисом Let’s Encrypt
Переходим в раздел getting startted и следуем инструкции.

Написание кода бота


Теперь же приступаем к программированию. После того, как взаимосвязь организована, можно начинать писать логику нашего бота.

Разработчики telegram, для того чтобы пользователям было проще работать с ботами, просят всех разработчиков реализовывать поддержку следующих команд:

/start — начинает общение с пользователем (например, отправляет приветственное сообщение). В эту команду также можно передавать дополнительные аргументы.
/help — отображает сообщение с помощью по командам. Оно может представлять собой короткое сообщение о вашем боте и список доступных команд.

Все что нам нужно сделать, это в контроллере вашего приложения\сайта написать следующий код:

$token = "токен";
$bot = new \TelegramBot\Api\Client($token);
// команда для start
$bot->command('start', function ($message) use ($bot) {
    $answer = 'Добро пожаловать!';
    $bot->sendMessage($message->getChat()->getId(), $answer);
});

// команда для помощи
$bot->command('help', function ($message) use ($bot) {
    $answer = 'Команды:
/help - вывод справки';
    $bot->sendMessage($message->getChat()->getId(), $answer);
});

$bot->run();

Теперь если в окне телеграм бота написать /help, то будет выведен текст:

Команды:
/help — вывод справки


Что ж, мы написали список рекомендуемых команд. Далее мы можем реализовывать необходимые нам команды.

Так как команды могут принимать аргументы, то мы эту возможность используем. Например, мы сделаем так, чтобы наш бот, на команду hello Вася, отвечал сообщением: Привет, Вася.

Для этого следует написать следующий код:

$bot->command('hello', function ($message) use ($bot) {
    $text = $message->getText();
    $param = str_replace('/hello ', '', $text);
    $answer = 'Неизвестная команда';
    if (!empty($param))
    {
    	$answer = 'Привет, ' . $param;
    }
    $bot->sendMessage($message->getChat()->getId(), $answer);
});

Получается все очень просто и быстро.

Заносим список команд бота


Для того, чтобы бот мог выдавать интерактивную справку



необходимо боту BotFather сообщить список команд.
Сделать это можно с помощью его команды /setcommands

Велосипедство


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

Значит нужно сделать так, чтобы бот запоминал команду, которую вы вводите. Это можно сделать с помощью любого хранилища (MySQL, memcached, redis, tarantool, Postgres, etc)
Все что нужно, это запоминать предыдущий ввод пользователя.

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

Вот на этом этапе у меня снова возникла трудность, так как я не нашел в библиотеке возможности получить команду до вызова метода command. Также мне не понравилось то, что вся логика будет заперта в рамках одного контроллера приложения.

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

Для начала мы описываем точку входа в контроллер

function main()
{
	$telegram = new Telegram();
	// подключаем хранилище
	$storage = new Storage();
	// получаем объект сообщения
	$message = $telegram->getMessage();
	// получаем команду, если ее передали
	$command = $message->getCommand();
	// получаем текст, если его передали (тут лежит все, что не является командой)
	$text = $message->getParams($command);
	// если команда пустая, то мы проверяем, есть ли у пользователя на предыдущем шаге вызов команды и восстановливаем ее
	if (empty($command))
	{
	  $command = $storage->restoreCommand($message->getChat()->getId());
	}
	// запоминаем команду, котрую ввел пользователь
	$storage->storeCommand(
	    $message->getChat()->getId(),
	    $command
	);
	// логика подключения нашего метода для котроллера
	$this->chooseMethod($command, $message, $text);
}

Теперь рассмотрим один из методов.

function getnewtext(Message $telegram, $text)
{
	// если не передали текст, то выведем сообщение с разъяснением
	if (empty($text))
	{
	  $answer = "Введите слово или несколько слов для поиска. Именно по ним будет происходить поиск 5 свежих новостей.";
	  $telegram->sendMessage($telegram->getChat()->getId(), $answer);
	}
	else
	{
		// основаня логика
		$tgNews = new TelegramNews();
		$arData = $tgNews->getByWord($text, 'new');
		if (empty($arData))
		{
			$answer = 'Ничего не найдено';
		}
		else
		{
			$answer = common_setViewGetContent('telegram/get', [
			    'data' => $arData
			]);
		}
		$telegram->sendMessage($telegram->getChat()->getId(), $answer);
	}
}

Так стало все в разы приятнее, интерактивнее и удобнее.



Спасибо, что дочитали статью до конца. Поиграть с живым ботом, который работает в режиме диалога можно тут.

UPD: боту добавлена возможность отдавать фото на некоторые виды запросов. Например на
/gettable — возвращает результирующую таблицу спортивных событий
/getevents — возвращает события спортивных мероприятий
Tags:
Hubs:
+11
Comments 13
Comments Comments 13

Articles