Під час експлуатації Telegram-бота в продакшені регулярні адміністративні завдання — такі як перемикання вебхуків при деплої, перевірка доступності API та ротація накопичених записів у базі даних — не повинні виконуватися вручну через Postman або браузер. Для цього у фреймворку Yii2 ідеально підходить консольный контроллер (Yii Console Controller).
У цьому посібнику ми розробимо повноцінну CLI-команду для автоматизації обслуговування Telegram-бот а, задіявши штатні механізми Yii2 та чистий cURL для роботи з Telegram Bot API.
Навіщо потрібен CLI-інструмент обслуговування бота
Використання консольного інтерфейсу для вирішення завдань адміністрування Telegram-бота дає кілька ключових переваг:
- Безпека: адміністративні методи (наприклад,
setWebhook) не доступні з зовнішнього вебу та запускаються лише авторизованими користувачами сервера або CI/CD пайплайнами. - Автоматизація: ротацію логів та перевірки здоров'я (health-check) можна легко повісити на системний
crontab. - Управління конфігурацією: параметри
secret_token, домени та налаштування лімітів беруться строго з конфігурації застосунку та змінних оточення (getenv).
Базовий консольний контролер та cURL-клієнт
Створимо консольний контролер commands/TelegramController.php. У ньому передбачимо приватний метод для виконання HTTP-запитів до Telegram Bot API за допомогою cURL з перевіркою HTTP-кодів статусу, помилок JSON та поля ok у відповіді.
<?php
namespace app\commands;
use Yii;
use yii\console\Controller;
use yii\console\ExitCode;
use yii\helpers\Console;
class TelegramController extends Controller
{
private string $botToken;
private string $secretToken;
public function init()
{
parent::init();
$this->botToken = (string) (Yii::$app->params['telegram_bot_token'] ?? getenv('TELEGRAM_BOT_TOKEN'));
$this->secretToken = (string) (Yii::$app->params['telegram_secret_token'] ?? getenv('TELEGRAM_SECRET_TOKEN'));
if (empty($this->botToken)) {
$this->stderr("Ошибка: TELEGRAM_BOT_TOKEN не задан в конфигурации.\n", Console::FG_RED);
exit(ExitCode::CONFIG);
}
}
/**
* Прямой HTTP-запрос к Telegram Bot API через cURL
*/
private function sendApiRequest(string $method, array $params = []): ?array
{
$url = "https://api.telegram.org/bot{$this->botToken}/{$method}";
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($params),
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_CONNECTTIMEOUT => 5]);
$response = curl_exec($ch);
$curlError = curl_error($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($response === false) {
$this->stderr("cURL Error [{$method}]: {$curlError}\n", Console::FG_RED);
return null;
}
$decoded = json_decode($response, true);
if (json_last_error() !== JSON_ERROR_NONE) {
$this->stderr("JSON Decode Error [{$method}]: " . json_last_error_msg() . "\n", Console::FG_RED);
return null;
}
if ($httpCode !== 200 || empty($decoded['ok'])) {
$description = $decoded['description'] ?? 'Unknown error';
$this->stderr("Telegram API Error [{$method}] (HTTP {$httpCode}): {$description}\n", Console::FG_RED);
return null;
}
return $decoded['result'];
}
}
Реалізація методів setWebhook та deleteWebhook
Для коректної роботи вебхука необхідно обов'язково використовувати параметр secret_token (від 1 до 256 символів, допускаються символи A-Z, a-z, 0-9, _ та -). Цей токен передається в заголовку X-Telegram-Bot-Api-Secret-Token при кожному вхідному запиті від Telegram, що дозволяє контролеру валідувати джерело.
Додамо в контролер дії для реєстрації та видалення вебхука:
/**
* Установка Webhook для бота
* Пример: php yii telegram/set-webhook https://example.com/telegram/webhook
*/
public function actionSetWebhook(string $url): int
{
if (!filter_var($url, FILTER_VALIDATE_URL)) {
$this->stderr("Ошибка: Некорректный URL '{$url}'\n", Console::FG_RED);
return ExitCode::DATAERR;
}
$params = [
'url' => $url,
'max_connections' => 40,
'allowed_updates' => ['message', 'callback_query', 'my_chat_member']];
if (!empty($this->secretToken)) {
$params['secret_token'] = $this->secretToken;
}
$this->stdout("Отправка запроса setWebhook на {$url}...\n");
$result = $this->sendApiRequest('setWebhook', $params);
if ($result === true) {
$this->stdout("Webhook успешно установлен!\n", Console::FG_GREEN);
return ExitCode::OK;
}
return ExitCode::UNSPECIFIED_ERROR;
}
/**
* Удаление Webhook с опциональной очисткой зависших апдейтов
* Пример: php yii telegram/delete-webhook 1
*/
public function actionDeleteWebhook(bool $dropPendingUpdates = false): int
{
$params = [
'drop_pending_updates' => $dropPendingUpdates];
$this->stdout("Удаление Webhook...\n");
$result = $this->sendApiRequest('deleteWebhook', $params);
if ($result === true) {
$this->stdout("Webhook успешно удален.\n", Console::FG_GREEN);
return ExitCode::OK;
}
return ExitCode::UNSPECIFIED_ERROR;
}
Health-check бота: перевірка getMe та getWebhookInfo
Для моніторингу стану бота створимо команду actionHealth. Вона опитує метод getMe (перевірка валідності токена та зв'язку з серверами Telegram) та метод getWebhookInfo (перевірка статусу доставки апдейтів, черги необроблених повідомлень та можливих помилок доставки).
/**
* Проверка здоровья бота и состояния Webhook
* Пример: php yii telegram/health
*/
public function actionHealth(): int
{
$this->stdout("=== Проверка Health-check Telegram API ===\n", Console::BOLD);
// 1. Проверка getMe
$botInfo = $this->sendApiRequest('getMe');
if (!$botInfo) {
$this->stderr("[FAIL] Не удалось получить данные бота через getMe\n", Console::FG_RED);
return ExitCode::UNSPECIFIED_ERROR;
}
$this->stdout("[OK] Бот авторизован: @{$botInfo['username']} (ID: {$botInfo['id']})\n", Console::FG_GREEN);
// 2. Проверка getWebhookInfo
$webhookInfo = $this->sendApiRequest('getWebhookInfo');
if (!$webhookInfo) {
$this->stderr("[FAIL] Не удалось запросить getWebhookInfo\n", Console::FG_RED);
return ExitCode::UNSPECIFIED_ERROR;
}
$url = $webhookInfo['url'] ?: 'не установлен';
$pendingCount = $webhookInfo['pending_update_count'] ?? 0;
$lastErrorDate = $webhookInfo['last_error_date'] ?? null;
$lastErrorMessage = $webhookInfo['last_error_message'] ?? null;
$this->stdout("Текущий URL: {$url}\n");
$this->stdout("Зависших апдейтов (Pending updates): {$pendingCount}\n");
if ($lastErrorDate) {
$dateStr = date('Y-m-d H:i:s', $lastErrorDate);
$this->stderr("[WARNING] Последняя ошибка отправки ({$dateStr}): {$lastErrorMessage}\n", Console::FG_YELLOW);
} else {
$this->stdout("[OK] Ошибок доставки вебхука не зафиксировано\n", Console::FG_GREEN);
}
return ExitCode::OK;
}
Ротація логів апдейтів та очищення таблиці дедуплікації
Для забезпечення ідемпотентності вебхуків вхідні update_id зберігаються в базі даних. Якщо вебхук-контролер зберігає лог вхідних запитів у таблицю telegram_update_log, ця база з часом починає займати гігабайти пам'яті. Створимо метод для очищення записів, старіших за задану кількість днів.
/**
* Ротация логов входящих апдейтов и дедупликации в БД
* Пример: php yii telegram/rotate-logs 14
*/
public function actionRotateLogs(int $days = 14): int
{
if ($days < 1) {
$this->stderr("Количество дней должно быть не менее 1.\n", Console::FG_RED);
return ExitCode::DATAERR;
}
$thresholdDate = date('Y-m-d H:i:s', strtotime("-{$days} days"));
$this->stdout("Удаление логов Telegram старше {$thresholdDate}...\n");
try {
$deletedRows = Yii::$app->db->createCommand()
->delete('telegram_update_log', ['<', 'created_at', $thresholdDate])
->execute();
$this->stdout("Успешно удалено записей: {$deletedRows}\n", Console::FG_GREEN);
return ExitCode::OK;
} catch (\Exception $e) {
$this->stderr("Ошибка при очистке БД: " . $e->getMessage() . "\n", Console::FG_RED);
return ExitCode::UNSPECIFIED_ERROR;
}
}
Налаштування системного планувальника Crontab
Для автоматичного підтримки чистоти БД та періодичної перевірки вебхука додайте наступні рядки до файлу crontab на вашому сервері:
# Ежедневная очистка логов Telegram старше 14 дней в 03:00 ночи
0 3 * * * /usr/bin/php /path/to/your/project/yii telegram/rotate-logs 14 >> /dev/null 2>&1
# Каждые 15 минут проверка работоспособности (Health-check)
*/15 * * * * /usr/bin/php /path/to/your/project/yii telegram/health >> /var/log/telegram_health.log 2>&1
Типові помилки при експлуатації консольних команд
- Захардкоджені токени: Ніколи не залишайте токен бота у тілі файлу контролера. Використовуйте
Yii::$app->paramsабо змінні оточенняgetenv(). - Використання file_get_contents: Для консольних команд завжди застосовуйте cURL з явними таймаутами (
CURLOPT_TIMEOUT,CURLOPT_CONNECTTIMEOUT), щоб CLI-процес не зависав при збоях мережі. - Відсутність обробки HTTP 429: Якщо команда здійснює масові запити, враховуйте лимиты Telegram Bot API та обробляйте заголовки/параметри
retry_after.
Якщо вам потрібна розробка надійних Telegram-ботів або Mini Apps з продуманою архітектурою та інтеграцією в CRM, зверніться до фахівців BotCreator.