Переклад цього гайду зʼявиться незабаром. Поки що текст доступний російською — перемкніться на RU або читайте нижче. Відкрити російську версію

Оновлення

З polling на webhook

Переход с режима Long Polling на Webhook — это стандартный шаг при переносе Telegram-бота из локальной среды разработки (development) на боевой сервер (production). При работе через getUpdates ваш PHP-скрипт сам непрерывно запрашивает обновления у серверов Telegram. В режиме Webhook инициатива переходит к Telegram: как только пользователь отправляет сообщение, сервер платформы мгновенно пересылает его POST-запросом на ваш HTTPS-эндпоинт.

Почему необходим переход

Long Polling тратит ресурсы процессора и сети на бесконечные пустые запросы, даже когда ботом никто не пользуется. Webhook работает по событию (event-driven), что позволяет экономить ресурсы сервера и мгновенно реагировать на действия пользователей. Однако одновременная работа двух режимов невозможна. Если запустить polling при активном webhook, Telegram вернет ошибку, а сообщения начнут теряться или дублироваться.

Шаг 1: Полная остановка Long Polling

Перед тем как переключить режим, обязательно остановите все запущенные демоны, cron-задачи или бесконечные CLI-скрипты, которые вызывают getUpdates. Если этого не сделать, старый процесс продолжит забирать обновления из очереди Telegram, и они просто не дойдут до вашего нового вебхук-обработчика.

Шаг 2: Регистрация вебхука через setWebhook

Для переключения режима используется метод setWebhook. При его вызове Telegram автоматически отключает режим polling для вашего бота. Нам также понадобится передать секретный токен безопасности (secret_token), чтобы защитить наш эндпоинт от сторонних запросов.

Используем функцию telegramApi(), которую мы сделали в главе Первый запрос: getMe. Здесь только вызываем её — реализацию не копируем.

<?php

// set_webhook.php

$token = getenv('TELEGRAM_BOT_TOKEN');
if (!$token) {
die("Ошибка: TELEGRAM_BOT_TOKEN не задан в окружении.\n");
}

// Генерируем криптографически безопасный ключ для проверки подлинности запросов от Telegram
$secretToken = bin2hex(random_bytes(16));

// В реальном проекте сохраните этот токен в .env файл или базу данных
file_put_contents(__DIR__ . '/.webhook_secret', $secretToken);

$params = [
'url' => 'https://example.com/telegram/webhook.php',
'secret_token' => $secretToken,
'drop_pending_updates' => true, // Очищает очередь старых необработанных сообщений
'allowed_updates' => json_encode(['message', 'callback_query'])
];

$response = telegramApi($token, 'setWebhook', $params);

echo "Результат выполнения setWebhook:\n";
print_r($response);

Запустите этот скрипт в консоли: php set_webhook.php. Вы увидите структурированный массив, возвращенный функцией print_r(). Пример успешного JSON-ответа от API, который наша функция декодировала в массив:

{
"ok": true,
"result": true,
"description": "Webhook was set"
}

Разбор ключевых полей ответа:

  • ok: логическое значение true указывает на успешное выполнение HTTP-запроса к API.
  • result: возвращает true, если вебхук успешно зарегистрирован в системе Telegram.
  • description: текстовое пояснение от сервера («Webhook was set»).

Если поле ok вернуло false, обратите внимание на описание ошибки в description. Типичные проблемы: использование незащищенного протокола HTTP вместо HTTPS, использование нестандартного порта (Telegram поддерживает только 80, 88, 443 и 8443) или проблемы с SSL-сертификатом (самоподписанные сертификаты без явной загрузки их открытого ключа в параметре certificate не принимаются).

Параметр drop_pending_updates => true критически важен при миграции. Он удаляет все накопившиеся в очереди сообщения, которые бот не успел обработать в режиме polling. Если его не передать, Telegram попытается лавинообразно доставить все старые сообщения на ваш новый вебхук, что может привести к перегрузке сервера или повторной обработке старых команд.

Шаг 3: Проверка статуса вебхука через getWebhookInfo

После успешной установки вебхука рекомендуется проверить его текущее состояние и убедиться, что Telegram видит ваш сервер и не фиксирует ошибок доставки.

Используем функцию telegramApi(), которую мы сделали в главе Первый запрос: getMe. Здесь только вызываем её — реализацию не копируем.

<?php

// get_webhook_info.php

$token = getenv('TELEGRAM_BOT_TOKEN');
if (!$token) {
die("Ошибка: TELEGRAM_BOT_TOKEN не задан в окружении.\n");
}

$response = telegramApi($token, 'getWebhookInfo');

echo "Информация о вебхуке:\n";
print_r($response);

Запустите скрипт: php get_webhook_info.php. В терминале отобразится текущий статус интеграции. Пример JSON-ответа:

{
"ok": true,
"result": {
"url": "https://example.com/telegram/webhook.php",
"has_custom_certificate": false,
"pending_update_count": 0,
"max_connections": 40,
"allowed_updates": [
"message",
"callback_query"
]
}
}

Важные поля для диагностики:

  • pending_update_count: количество обновлений, ожидающих отправки в очереди Telegram. В идеальном состоянии здесь должен быть 0. Если число растет — ваш вебхук-скрипт работает слишком медленно или возвращает ошибки, отличные от HTTP-кода 200 OK.
  • last_error_date и last_error_message: если при доставке запросов возникали сетевые сбои или ошибки сервера, здесь будут указаны Unix-время ошибки и ее текстовое описание (например, «Connection timed out» или «HTTP status code 500»).
  • max_connections: максимальное количество одновременных HTTPS-соединений, которые Telegram может открыть к вашему серверу (по умолчанию 40).

Шаг 4: Сброс очереди обновлений (при необходимости)

Если вы хотите временно отключить вебхук и вернуться к тестированию через polling, вам потребуется удалить вебхук. При этом полезно сбросить накопленный offset на стороне Telegram, чтобы при следующем запуске polling не получить гору старых сообщений. Для этого отправьте один запрос к getUpdates с параметром offset = -1.

Используем функцию telegramApi(), которую мы сделали в главе Первый запрос: getMe. Здесь только вызываем её — реализацию не копируем.

<?php

// clear_queue.php

$token = getenv('TELEGRAM_BOT_TOKEN');
if (!$token) {
die("Ошибка: TELEGRAM_BOT_TOKEN не задан в окружении.\n");
}

// Сначала удаляем вебхук
telegramApi($token, 'deleteWebhook', ['drop_pending_updates' => true]);

// Подтверждаем все оставшиеся обновления в очереди
$response = telegramApi($token, 'getUpdates', [
'offset' => -1,
'limit' => 1,
'timeout'=> 0
]);

echo "Очередь очищена. Ответ API:\n";
print_r($response);

Пример JSON-ответа при успешном сбросе очереди:

{
"ok": true,
"result": []
}

Пустой массив в поле result подтверждает, что все старые обновления успешно помечены сервером Telegram как прочитанные, и очередь пуста.

Чек-лист успешного перехода

  • Скрипт Long Polling полностью остановлен и убран из автозапуска.
  • Ваш вебхук-скрипт доступен по публичному HTTPS-адресу с валидным SSL-сертификатом.
  • Сгенерирован надежный secret_token, который проверяется внутри вебхука.
  • Метод setWebhook вызван с флагом drop_pending_updates => true.
  • Запрос getWebhookInfo подтверждает отсутствие ошибок доставки (pending_update_count равен 0, ошибок в last_error_message нет).

Дальше: sendMessage — отправляем первое текстовое сообщение пользователю.