Как привязать чат-бота в Telegram к текущему пользователю в Laravel
В большинстве инструкций по работе с телеграм-ботом не сказано про то, как получить тот самый RECIPIENT_CHAT_ID
, в который надо слать сообщения из PHP.
Вот типичный пример отправки сообщения из Laravel-приложения в Телеграм:
Route::post('bot/sendmessage', function() {
Telegram::sendMessage([
'chat_id' => 'RECIPIENT_CHAT_ID',
'text' => 'Привет, мир!'
]);
return;
});
Предположим, что наша задача — слать уведомления пользователю в телеграм, если на сайте ему ответили на комментарий. Такое уведомление нужно отправлять только конкретному пользователю, а не всем сразу.
Простой способ для привязки пользователя на сайте и чата с ботом в телеграме — использование ссылки-инвайта для добавления чат-бота. Вы даёте пользователю специальную ссылку с параметром, и когда он на неё кликает — открывается чат с ботом, бот получает инструкцию «начать работу» и отправляет информацию на сервер вместе с тем самым параметром из ссылки, а также CHAT_ID
. По этому параметру вы находите в своей базе пользователя и назначаете ему CHAT_ID
.
Показываем пользователю на сайте ссылку:
https://telegram.me/arutyunov_bot?start=asd123
Когда пользователь перейдёт по ссылке, у него откроется чат 1-на-1 с ботом. Как только пользователь нажмёт кнопку Start, бот получит сообщение вида:
/start PAYLOAD
Вместо PAYLOAD
и будет тот самый токен. В нашем примере это asd123
. Теперь вам нужно обработать это сообщение на своём сервере.
Вот пример для обработчика, который привязан к Webhook:
if ($message->getText()) {
if (strpos('/start', $message->getText()) !== false) {
$textStrings = explode(' ', $message->getText());
if (isset($textStrings[1])) {
$token = $textStrings[1];
$chatId = $message->getChat()->getId();
if ($token) {
$user = User::find(['telegram_token' => $token]);
if ($user !== null) {
$user->telegram_chat_id = $chatId;
return response()->json(['status' => $user->save()]);
}
}
}
}
}
В официальной документации Телеграм есть описание этого механизма, который называется Deep linking
.
В телеграме каждый чат имеет свой уникальный CHAT_ID
. Обратите внимание, что чат с ботом будет иметь числовой CHAT_ID
больше 0, а если вы добавили бота в группу, то CHAT_ID
будет отрицательный.
Здравствуйте, Кирилл.
Спасибо, Вы мне очень помогли.
Рад, что материал оказался полезным 🙂
Кирилл, подскажите пожалуйста, в какой части кода, необходимо прописывать ответ серверу Telegram?
Мне нужно после каждого обновления возвращать header («HTTP/1.1 200 OK»);
Сейчас на мой сайт, с телеграмма ежесекундно приходят десятки запросов типа:
«POST /токен-моего-бота/webhook HTTP/1.1» 500
Спасибо.
Лучше в адресе вебхука не указывать токен бота, это не безопасно. Вы можете указать вебхук так:
https://api.telegram.org/bot{my_bot_token}/setWebhook?url=https://mysite.ru/bot/telegram_webhook
. В таком случае телеграм будет слать вам POST-запросы на адресhttps://mysite.ru/bot/telegram_webhook
. Собственно если у вас Laravel, то настраиваете роуты, контроллер и обрабатываете ответ от телеграма. Если не Laravel, то обрабатываете по-своему. Но суть везде одна и та же — у вас входящий ПОСТ-запрос, который надо разобрать и в ответ что-то отдать. В случае успеха не забыть код 200, иначе телеграм будет засыпать сервер запросами.Кирилл, спасибо Вам за ответ.
У меня Laravel 5.8
Использую компонент irazasyed/telegram-bot-sdk
Бот рабочий, на мои сообщения — отвечает.
Проблема как раз в ответе 200 ОК, телеграм сервер уже засыпает мой сайт запросами.
Прочитал, что нужно вернуть ему header («HTTP/1.1 200 OK»);
Но где это прописывать? После sendMessage?
Не могли бы Вы привести часть своего кода, где вы возвращаете серверу код 200.
Спасибо.
У меня это примерно так происходит:
$this→sendMessage ($chatId, $text, $replyMarkup);
return 'OK';
Можно и так:
return response ('OK', 200)→header ('Content-Type', 'text/plain');
Сначала отправляете сообщение, потом посылаете response с нужными заголовками. SendMessage, по сути, это же curl-запрос к телеграму.
Единственное, могут быть тонкости при использовании Async-настроек в этом пакете — тут ничего не смогу подсказать, потому что не работал с этим пакетом.
Кирилл, благодарю Вас!
Последний вопрос, если позволите.
Если отключить webHook, и потом заново его включить setWebHook, от бота приходят старые сообщения.
Читал, что в случае с getUpdates, нужно отправить update_id последнего обновления api.telegram.org/bot/getUpdates?offset=
и тогда, бот не будет присылать старые сообщения.
А как это реализовать с webHook?
Спасибо.
Не сталкивался с такой задачей. Я бы в крайнем случае дописал какой-нибудь обработчик, в котором по timestamp’у отсёк бы старые сообщения и в ответ на такие запросы просто возвращал бы 200 ОК и ничего больше не делал бы. Ещё для исключения ддоса со стороны серверов телеграма, если что-то идёт не так, мы писали middleware, который кидал в кеш md5 всех полей запроса и каждый входящий запрос проверял, и если такой md5 уже был в кеше, то вебхук ничего не делал и отдавал 200 ОК. Костыль, но позволял фильтровать запросы от Телеграма, чтобы сервак не перегружался :-).
Спасибо, Кирилл. Костыли у меня как раз хорошо получаются в последнее время:)