Telegram API и PHP: разработка ботов от простого к сложному

Раздел: Работа с API -> Telegram API

Основные подходы к разработке 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}}

Telegram боты на PHP - comments

En
Telegram php (php)