When running a Telegram bot in production, routine administrative tasks — such as switching webhooks during deployment, checking API availability, and rotating accumulated database records — should not be performed manually via Postman or a browser. For this purpose, the консольный контроллер (Yii Console Controller) in the Yii2 framework is an ideal fit.
In this guide, we will build a fully featured CLI command to automate Telegram-бот maintenance, leveraging standard Yii2 mechanisms and pure cURL for working with the Telegram Bot API.
Why You Need a CLI Tool for Bot Maintenance
Using a command-line interface for Telegram bot administrative tasks provides several key advantages:
- Security: Administrative methods (such as
setWebhook) are not accessible from the external web and are executed only by authorized server users or CI/CD pipelines. - Automation: Log rotation and health checks can easily be scheduled using the system
crontab. - Configuration management:
secret_tokenparameters, domains, and limit settings are retrieved strictly from the application configuration and environment variables (getenv).
Basic Console Controller and cURL Client
Let's create a console controller at commands/TelegramController.php. Inside, we will implement a private method to execute HTTP requests to the Telegram Bot API via cURL, including checks for HTTP status codes, JSON errors, and the ok field in the response.
<?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'];
}
}
Implementing setWebhook and deleteWebhook Methods
For a webhook to function correctly, it is essential to use the secret_token parameter (1 to 256 characters; characters A-Z, a-z, 0-9, _, and - are allowed). This token is passed in the X-Telegram-Bot-Api-Secret-Token header with every incoming request from Telegram, allowing the controller to validate the source.
Let's add actions for webhook registration and deletion to the controller:
/**
* Установка 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;
}
Bot Health Check: Verifying getMe and getWebhookInfo
To monitor the bot's health, let's create the actionHealth command. It queries the getMe method (verifying token validity and connectivity with Telegram servers) and the getWebhookInfo method (checking update delivery status, the queue of unprocessed messages, and potential delivery errors).
/**
* Проверка здоровья бота и состояния 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 Log Rotation and Deduplication Table Cleanup
To ensure webhook idempotency, incoming update_ids are saved in the database. If the webhook controller logs incoming requests into a telegram_update_log table, this table will eventually consume gigabytes of storage over time. Let's create a method to clean up records older than a specified number of days.
/**
* Ротация логов входящих апдейтов и дедупликации в БД
* Пример: 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;
}
}
Configuring the Crontab System Scheduler
To automatically keep your database clean and periodically check the webhook, add the following lines to the crontab file on your server:
# Ежедневная очистка логов 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
Common Pitfalls When Running Console Commands
- Hardcoded tokens: Never leave токен бота inside the controller file body. Use
Yii::$app->paramsor environment variables viagetenv(). - Using file_get_contents: For console commands, always use cURL with explicit timeouts (
CURLOPT_TIMEOUT,CURLOPT_CONNECTTIMEOUT) so that the CLI process does not hang during network outages. - Lack of HTTP 429 handling: If the command executes bulk requests, keep лимиты Telegram Bot API in mind and process the
retry_afterheaders/parameters.
If you need reliable Telegram bots or Mini Apps developed with a robust architecture and seamless CRM integration, contact the specialists at BotCreator.