Telegram API и PHP: разработка ботов от простого к сложному
Основные подходы к разработке Telegram ботов на PHP
Библиотека longman/telegram-bot (webhook)
Наиболее эффективным речением можно считать использование официальной библиотеки longman/telegram-bot, которая предоставляет удобный интерфейс для работы с Bot API через webhook. Этот метод обеспечивает мгновенную реакцию на сообщения пользователей без необходимости постоянного опроса сервера.
Установка и настройка
composer require longman/telegram-botПосле установки создайте файл bot.php:
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Longman\TelegramBot\Telegram;
use Longman\TelegramBot\Exception\TelegramException;
try {
$telegram = new Telegram('YOUR_BOT_TOKEN', 'bot_username');
$telegram->handle();
} catch (TelegramException $e) {
error_log($e->getMessage());
}Установите webhook, указав публичный URL вашего скрипта (обязательно HTTPS):
$telegram->setWebhook('https://example.com/bot.php');Теперь все входящие сообщения будут автоматически передаваться на PHP-скрипт.
Типичные ошибки
- Ошибка 404 при запросе к webhook – проверьте правильность URL и наличие SSL-сертификата (самоподписанный не подойдёт).
- Неверный токен – убедитесь, что YOUR_BOT_TOKEN получен у @BotFather и скопирован без лишних символов.
- Проблемы с правами на запись – лог файлы могут не создаваться; настройте права папки /tmp или укажите свою директорию.
Обработка команд
Создайте класс команды, например StartCommand.php:
namespace App\Commands;
use Longman\TelegramBot\Commands\UserCommands\StartCommand;
class StartCommand extends StartCommand
{
public function execute()
{
$message = $this->getMessage();
$chatId = $message->getChat()->getId();
$data = [
'chat_id' => $chatId,
'text' => 'Привет! Я бот на PHP.',
];
return Request::sendMessage($data);
}
}Зарегистрируйте команду в основном скрипте:
$telegram->addCommandClass(StartCommand::class);Как реализовать бота без библиотек, используя чистые HTTP-запросы?
Можно напрямую вызывать методы API через curl или Guzzle. Этот вариант подходит для простых задач или когда нет возможности использовать внешние зависимости.
$token = 'YOUR_BOT_TOKEN';
$url = "https://api.telegram.org/bot{$token}/sendMessage";
$data = [
'chat_id' => 123456789,
'text' => 'Привет!',
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo $response;Для получения обновлений используется метод getUpdates с циклом опроса. Однако такой подход требует постоянного выполнения скрипта и может привести к дублированию сообщений (ошибка с подтверждением offset).
Возможные проблемы
- Без подтверждения offset одно и то же обновление будет обрабатываться многократно.
- Длительное выполнение скрипта может превысить лимит времени PHP (установите set_time_limit(0)).
- При использовании длинного опроса (long polling) важно задавать таймаут (например, 30 секунд).
Как использовать long polling с библиотекой danog/telegram-bot-api?
Библиотека danog/telegram-bot-api предоставляет реализацию Bot API на PHP с поддержкой long polling. Установка:
composer require danog/telegram-bot-apiПример скрипта:
<?php
require 'vendor/autoload.php';
use danog\TelegramBotApi\BotApi;
$bot = new BotApi('YOUR_BOT_TOKEN');
$updates = $bot->getUpdates(['timeout' => 30]);
foreach ($updates as $update) {
$message = $update->getMessage();
$chatId = $message->getChat()->getId();
$bot->sendMessage($chatId, 'Привет из long polling!');
$bot->markUpdate($update->getUpdateId());
}Этот вариант не требует настройки webhook и подходит для локальной разработки.
Расширенные примеры кода с пояснениями
Отправка фото с подписью
$url = "https://api.telegram.org/bot{$token}/sendPhoto";
$data = [
'chat_id' => $chatId,
'photo' => 'https://example.com/image.jpg', // или file_id
'caption' => 'Пример изображения',
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data); // для multipart/form-data
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo $response;{"ok":true,"result":{"message_id":123,"from":{...},"chat":{...},"date":...,"photo":[...],"caption":"Пример изображения"}}Если используется file_id (уже загруженного ранее фото), передавайте его как строку. Для отправки файла с диска используйте конструкцию new CURLFile().
Инлайн клавиатура с кнопками
use Longman\TelegramBot\Entities\InlineKeyboard;
$keyboard = new InlineKeyboard([
[
['text' => 'Кнопка 1', 'callback_data' => 'btn1'],
['text' => 'Кнопка 2', 'callback_data' => 'btn2'],
],
[
['text' => 'Ссылка', 'url' => 'https://example.com'],
],
]);
$data = [
'chat_id' => $chatId,
'text' => 'Выберите действие:',
'reply_markup' => $keyboard,
];
$result = Request::sendMessage($data);Для обработки callback запроса создайте класс команды CallbackqueryCommand:
class CallbackqueryCommand extends Command
{
public function execute()
{
$callback = $this->getUpdate()->getCallbackQuery();
$data = $callback->getData();
$message = $callback->getMessage();
$chatId = $message->getChat()->getId();
if ($data === 'btn1') {
$text = 'Вы нажали кнопку 1';
} else {
$text = 'Нажата кнопка 2';
}
Request::sendMessage([
'chat_id' => $chatId,
'text' => $text,
]);
// Подтверждаем callback
Request::answerCallbackQuery($callback->getId(), 'Готово');
}
}Отправка документа (файла)
$url = "https://api.telegram.org/bot{$token}/sendDocument";
$file = new CURLFile('/path/to/file.pdf', 'application/pdf', 'document.pdf');
$data = [
'chat_id' => $chatId,
'document' => $file,
'caption' => 'Отчёт',
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo $response;{"ok":true,"result":{"message_id":456,"document":{"file_id":"...","file_name":"document.pdf","file_size":12345}}}Обратите внимание: при отправке файлов размером более 50 МБ используйте серверы Telegram с поддержкой загрузки больших файлов (не все методы).
Работа с чатами (получение информации, установка действий)
$chatInfo = Request::getChat(['chat_id' => $chatId]);
echo $chatInfo->getChat()->getTitle(); // для групп/супергрупп
// Установка статуса набора текста
Request::sendChatAction([
'chat_id' => $chatId,
'action' => 'typing',
]);
// Удаление кнопок после выбора
Request::editMessageReplyMarkup([
'chat_id' => $chatId,
'message_id' => $messageId,
'reply_markup' => null,
]);Пример вывода при успешном запросе getChat:
{"ok":true,"result":{"id":-100123456789,"title":"Моя группа","type":"supergroup","members_count":150}}