Для управління інтеграцією Telegram Bot API потрібні надійні адміністративні інструменти. У той час як вебхуки обробляють вхідні користувацькі корисні навантаження у режимі реального часу, налаштування, перевірка та обслуговування цих вебхуків повинні виконуватися поза життєвим циклом запитів вебсервера HTTP. Використання інструменту CLI дозволяє надійно виконувати етапи розгортання, перевірки працездатності та завдання обслуговування без таймаутів вебсервера або публічного доступу.
\nУ цьому уроці ми створимо спеціальний консольний контролер Yii2 (commands/TelegramController.php), який безпосередньо взаємодіє з API Telegram Bot через cURL. Ми виконаємо чотири основні операції: тестування облікових даних бота з getMe, реєстрація URL-адреси загальнодоступного вебхука за допомогою setWebhook (включаючи ін'єкцію секретного токена), видалення вебхуків за допомогою deleteWebhook та очищення логів архівних сирих оновлень із локального дискового сховища.
У цьому посібнику основна увага приділяється управлінню життєвим циклом адміністратора та зберіганню журналу оновлень. Він не охоплює написання повного діалогового механизму маршрутизації, обробку демонів із тривалим опитуванням або створення користувальницького інтерфейсу повідомлень.
\n---
\nКрок 1. Налаштування параметрів API Telegram
\nЗберігайте токени API у змінних середовища або параметрах застосунку Yii2. Уникайте жорсткого кодування токенів усередині коду контролера або файлів конфігурації, які контролюються версіями.
\nДодайте конфігурацію до config/params.php:
<?php
return [
'telegram.botToken' => getenv('TELEGRAM_BOT_TOKEN') ?: '',
'telegram.secretToken' => getenv('TELEGRAM_SECRET_TOKEN') ?: '',
'telegram.webhookUrl' => getenv('TELEGRAM_WEBHOOK_URL') ?: '',
'telegram.logDir' => '@runtime/telegram-logs',
];\nПереконайтеся, що config/console.php включає простір імен команд і правильно завантажує params.php:
<?php
$params = require __DIR__ . '/params.php';
$config = [
'id' => 'basic-console',
'basePath' => dirname(__DIR__),
'bootstrap' => ['log'],
'controllerNamespace' => 'app\commands',
'components' => [
'log' => [
'targets' => [
[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
],
],
],
],
'params' => $params,
];
return $config;\n---
\nКрок 2. Реалізація консольного контролера
\nСтворіть commands/TelegramController.php. Цей клас обробляє комунікації з API з використанням стандартних функцій PHP cURL. Він перевіряє коди стану HTTP, декодує структури JSON, обробляє корисні навантаження збоїв на рівні API (ok = false;) і реєструє помилку, яка виводиться безпосередньо в Console::error.
<?php
namespace app\commands;
use Yii;
use yii\console\Controller;
use yii\console\ExitCode;
use yii\helpers\Console;
use yii\helpers\FileHelper;
class TelegramController extends Controller
{
/**
* @var string Output formatting verbosity level.
*/
public $defaultAction = 'health';
/**
* Executes getMe to verify bot token validity and connection health.
*/
public function actionHealth(): int
{
$this->stdout("Checking Telegram API connectivity...
", Console::FG_BLUE);
$response = $this->sendApiRequest('getMe');
if (!$response['ok']) {
$this->stderr("Health Check Failed: {$response['description']}
", Console::FG_RED);
return ExitCode::UNSPECIFIED_ERROR;
}
$bot = $response['result'];
$this->stdout("Bot ID: {$bot['id']}
", Console::FG_GREEN);
$this->stdout("Username: @{$bot['username']}
", Console::FG_GREEN);
$this->stdout("Can Join Groups: " . ($bot['can_join_groups'] ? 'Yes' : 'No') . "
");
$this->stdout("Can Read All Group Messages: " . ($bot['can_read_all_group_messages'] ? 'Yes' : 'No') . "
");
return ExitCode::OK;
}
/**
* Registers a webhook URL with Telegram.
*
* @param string|null $url Custom webhook URL. Defaults to params configuration.
*/
public function actionSetWebhook(?string $url = null): int
{
$targetUrl = $url ?? Yii::$app->params['telegram.webhookUrl'];
$secretToken = Yii::$app->params['telegram.secretToken'];
if (empty($targetUrl)) {
$this->stderr("Error: Webhook URL is not specified.
", Console::FG_RED);
return ExitCode::DATAERR;
}
$params = [
'url' => $targetUrl,
'max_connections' => 40,
'allowed_updates' => ['message', 'callback_query', 'my_chat_member'],
];
if (!empty($secretToken)) {
$params['secret_token'] = $secretToken;
}
$this->stdout("Setting webhook to: {$targetUrl}
");
$response = $this->sendApiRequest('setWebhook', $params);
if (!$response['ok']) {
$this->stderr("Failed to set webhook: {$response['description']}
", Console::FG_RED);
return ExitCode::UNSPECIFIED_ERROR;
}
$this->stdout("Success: {$response['result']}
", Console::FG_GREEN);
return ExitCode::OK;
}
/**
* Deletes the currently registered webhook.
*
* @param bool $dropPending Whether to drop pending updates stored on Telegram servers.
*/
public function actionDeleteWebhook(bool $dropPending = false): int
{
$this->stdout("Removing webhook configuration...
");
$params = [
'drop_pending_updates' => $dropPending,
];
$response = $this->sendApiRequest('deleteWebhook', $params);
if (!$response['ok']) {
$this->stderr("Failed to delete webhook: {$response['description']}
", Console::FG_RED);
return ExitCode::UNSPECIFIED_ERROR;
}
$this->stdout("Webhook successfully deleted.
", Console::FG_GREEN);
return ExitCode::OK;
}
/**
* Prunes update log files older than a specified number of days.
*
* @param int $days Number of days to keep logs.
*/
public function actionRotateLogs(int $days = 7): int
{
$logDir = Yii::getAlias(Yii::$app->params['telegram.logDir']);
if (!is_dir($logDir)) {
$this->stdout("Log directory does not exist: {$logDir}
", Console::FG_YELLOW);
return ExitCode::OK;
}
$cutoffTimestamp = time() - ($days * 86400);
$files = FileHelper::findFiles($logDir, ['only' => ['*.json', '*.log']]);
$deletedCount = 0;
foreach ($files as $file) {
if (filemtime($file) < $cutoffTimestamp) {
if (@unlink($file)) {
$deletedCount++;
} else {
$this->stderr("Could not delete file: {$file}
", Console::FG_RED);
}
}
}
$this->stdout("Log cleanup complete. Removed {$deletedCount} log files older than {$days} days.
", Console::FG_GREEN);
return ExitCode::OK;
}
/**
* Helper method to send HTTP Requests to Telegram Bot API via cURL.
*/
private function sendApiRequest(string $method, array $params = []): array
{
$token = Yii::$app->params['telegram.botToken'];
if (empty($token)) {
return [
'ok' => false,
'description' => 'TELEGRAM_BOT_TOKEN parameter is missing or empty.',
];
}
$url = "https://api.telegram.org/bot{$token}/{$method}";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
$rawResponse = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlError = curl_error($ch);
curl_close($ch);
if ($rawResponse === false) {
return [
'ok' => false,
'description' => "cURL network error: {$curlError}",
];
}
$decoded = json_decode($rawResponse, true);
if (json_last_error() !== JSON_ERROR_NONE) {
return [
'ok' => false,
'description' => "Failed to parse API response JSON. Raw output: " . substr($rawResponse, 0, 100),
];
}
if ($httpCode !== 200 && !isset($decoded['description'])) {
$decoded['description'] = "HTTP response status code {$httpCode}";
}
return $decoded;
}
}\n---
\nКрок 3: Використання команд та інтеграція розгортання
\nІз встановленим контролером перевірте свої команди, використовуючи стандартний виконуваний файл CLI Yii.
#### 1. Перевірка облікових даних API Запустіть команду Health (\"Здоров'я\") для перевірки того, що ваш TELEGRAM_BOT_TOKEN є правильним, і доступ до мережі api.telegram.org безперешкодний:
php yii telegram/health\nОчікувані результати
\nChecking Telegram API connectivity...
Bot ID: 123456789
Username: @MyProductionBot
Can Join Groups: Yes
Can Read All Group Messages: No\n#### 2. Реєстрація вебхуків для стейджинг- або продакшн-розгортання може викликати Установити вебхук автоматично у пайплайнах безперервної інтеграції. Ви можете передати цільову URL-адресу вебхука як явний параметр або дозволити Yii2 отримати її з вашої конфігурації Environment:
php yii telegram/set-webhook "https://example.com/telegram/webhook"\nЯкщо запит виконано успішно, Telegram повертає true, і ваш визначений секретний заголовок прив'язаний до всіх вхідних повідомлень POST, надісланих Telegram.
#### 3. Видалення вебхука в режимі обслуговування При переведенні застосунку в режим обслуговування або міграції серверних середовищ запустіть Видалити вебхук. Щоб скасувати вхідні оновлення в черзі під час вікон обслуговування, передайте прапорець --dropPending=1:
php yii telegram/delete-webhook 1\n#### 4. Автоматична ротація логів через системний Cron Якщо ваш контролер вебхука записує сирі корисні дані JSON у локальні файли логів (наприклад, усередині @runtime/telegram-logs/YYYY-MM-DD.json), необхідно очищати старі логи, щоб контролювати використання диска. Налаштуйте системне завдання cron на вашому сервері для щоденного виконання ротації логів:
# /etc/cron.d/telegram-maintenance
0 3 * * * www-data /usr/bin/php /var/www/my-app/yii telegram/rotate-logs 14 > /dev/null 2>&1\nЦей розклад виконується щоночі о 3:00 ранку, видаляючи файли оновлень, старіші за 14 днів, без ручного втручання.
\n---
\nАспекти продакшну та безпеки
\n1. Застосувати валідацію секретного токена: Завжди передавайте безпечний секретний токен — рядок, що містить від 1 до 256 буквено-цифрових символів або підкреслень при виклику setWebhook. При обробці вхідних HTTP-запитів POST у вашому вебконтролері переконайтеся, що заголовок X-Telegram-Bot-Api-Secret-Token відповідає цьому секретному значенню, використовуючи hash_equals(). 2. Обмежити типи оновлень: Використовуйте параметр масиву allowed_updates у setWebhook, щоб вказувати лише корисні дані подій, які явно обробляє ваш застосунок (наприклад, ['message', 'callback_query']). Обмеження типів не дозволяє Telegram доставляти непотрібні категорії корисного навантаження, знижуючи навантаження на мережу та накладні витрати. 3. Таймаути та повтори: Встановіть суворі таймаути (CURLOPT_TIMEOUT 10 секунд або менше) у ваших адміністративних викликах API. Якщо Telegram зазнає часткової деградації сервісу, завдання обслуговування CLI повинні швидко завершуватися, а не блокувати сценарії розгортання або черги фонових воркерів на невизначений термін. 4. Права доступу: Переконайтеся, що системний користувач, який виконує консольну команду (наприклад, www-data або deploy), має права на читання та запис у @runtime/telegram-logs для виконання rotate-logs.
Якщо вам потрібна команда для роботи з кастомною архітектурою інтеграції Telegram, вебхуками та інфраструктурою бекенду Mini App, розгляньте можливість співпраці з BotCreator.
"