Предоставление административных операций, таких как настройка конечных точек веб-перехватчиков или очистка очередей обновлений, через общедоступные веб-маршруты создает ненужный риск для безопасности. Для раскрытия веб-маршрутов требуется сложное промежуточное программное обеспечение для аутентификации, чтобы несанкционированные третьи стороны не перенаправляли веб-перехватчик на вредоносный сервер или не наводняли конечные точки. Выполнение административных задач через консольный интерфейс Yii2 устраняет эту поверхность атаки, использует аргументы командной строки и легко интегрируется в конвейеры развертывания и системные планировщики (например, таймеры crontab или systemd).
В этом руководстве показано, как создать специальный консольный контроллер Yii2 для управления основными операциями API бота Telegram: проведение проверок работоспособности API (getMe), регистрация и отмена регистрации веб-перехватчиков (setWebhook, deleteWebhook) и выполнение ротации журналов пакетной базы данных для обработанных журналов обновлений. Этот рабочий процесс не зависит от зависимостей стороннего Telegram SDK, вместо этого используются необработанные вызовы cURL для обеспечения полного контроля над обработкой тайм-аута, проверкой статуса HTTP и разбором ошибок.
Архитектурные обязанности
Контроллер консоли обрабатывает только административные процедуры: 1. Прямая связь с конечными точками HTTPS API Telegram с использованием изолированной транспортной логики. 2. Проглатывание параметров окружающей среды (Токен бота, URL вебхуков, WEBHOOK_SECRET_TOKEN). 3. Безопасное удаление просроченных записей журнала в ограниченных транзакциях базы данных, чтобы избежать блокировки в таблицах с высокой пропускной способностью.
Он не обрабатывает анализ входящих обновлений в реальном времени или управление жизненным циклом HTTP-запросов, которые остаются в ведении веб-контроллеров или асинхронных потребителей очередей.
Реализация контроллера консоли
Создайте командный файл CLI по адресу commands/TelegramController.php. Этот класс наследуется от yii\console\Controller и предоставляет общедоступные методы, сопоставленные с подкомандами CLI.
<?php
namespace app\commands;
use Yii;
use yii\console\Controller;
use yii\console\ExitCode;
use yii\db\Query;
class TelegramController extends Controller
{
public string $token = '';
public string $webhookUrl = '';
public string $secretToken = '';
public function init(): void
{
parent::init();
// Retrieve credentials from environment or Yii params
$this->token = (string) (getenv('TELEGRAM_BOT_TOKEN') ?: Yii::$app->params['telegramBotToken'] ?? '');
$this->webhookUrl = (string) (getenv('TELEGRAM_WEBHOOK_URL') ?: Yii::$app->params['telegramWebhookUrl'] ?? '');
$this->secretToken = (string) (getenv('TELEGRAM_SECRET_TOKEN') ?: Yii::$app->params['telegramSecretToken'] ?? '');
}
/**
* Health-check: Calls getMe to verify bot token validity.
*/
public function actionHealthCheck(): int
{
$this->stdout("Checking Telegram Bot API Connectivity...\n");
$response = $this->sendApiRequest('getMe');
if (!$response['ok']) {
$this->stderr("ERROR: Failed to connect. Reason: " . ($response['description'] ?? 'Unknown error') . "\n");
return ExitCode::UNSPECIFIED_ERROR;
}
$bot = $response['result'];
$this->stdout(sprintf("SUCCESS: Connected as @%s (ID: %d)\n", $bot['username'], $bot['id']));
return ExitCode::OK;
}
/**
* Register the public HTTP webhook endpoint with Telegram API.
*/
public function actionSetWebhook(?string $url = null, bool $dropPending = false): int
{
$targetUrl = $url ?? $this->webhookUrl;
if (empty($targetUrl)) {
$this->stderr("ERROR: Webhook URL is missing. Provide it via argument or config.\n");
return ExitCode::DATAERR;
}
$payload = [
'url' => $targetUrl,
'drop_pending_updates' => $dropPending,
'allowed_updates' => ['message', 'callback_query', 'my_chat_member'],
];
if (!empty($this->secretToken)) {
$payload['secret_token'] = $this->secretToken;
}
$this->stdout("Registering Webhook URL: {$targetUrl}...\n");
$response = $this->sendApiRequest('setWebhook', $payload);
if (!$response['ok']) {
$this->stderr("ERROR: setWebhook failed: " . ($response['description'] ?? 'Unknown') . "\n");
return ExitCode::UNSPECIFIED_ERROR;
}
$this->stdout("SUCCESS: Webhook successfully registered.\n");
return ExitCode::OK;
}
/**
* Remove registered webhook from Telegram API.
*/
public function actionDeleteWebhook(bool $dropPending = false): int
{
$payload = [
'drop_pending_updates' => $dropPending,
];
$this->stdout("Deleting Webhook registration...\n");
$response = $this->sendApiRequest('deleteWebhook', $payload);
if (!$response['ok']) {
$this->stderr("ERROR: deleteWebhook failed: " . ($response['description'] ?? 'Unknown') . "\n");
return ExitCode::UNSPECIFIED_ERROR;
}
$this->stdout("SUCCESS: Webhook deleted successfully.\n");
return ExitCode::OK;
}
/**
* Purge update logs older than N days in small chunks.
*/
public function actionRotateLogs(int $days = 14, int $batchSize = 1000): int
{
if ($days < 1) {
$this->stderr("ERROR: Days must be an integer greater than 0.\n");
return ExitCode::DATAERR;
}
$cutoffDate = date('Y-m-d H:i:s', strtotime("-{$days} days"));
$this->stdout("Rotating updates logged before {$cutoffDate}...\n");
$db = Yii::$app->db;
$totalDeleted = 0;
do {
// Delete in batches to prevent long table locks
$deletedCount = $db->createCommand()
->delete('telegram_update_log', 'created_at < :cutoff', [':cutoff' => $cutoffDate])
->execute();
// Note: If using SQL databases without LIMIT support in DELETE queries,
// delete via subquery matching primary keys:
/*
$subQuery = (new Query())
->select('id')
->from('telegram_update_log')
->where(['<', 'created_at', $cutoffDate])
->limit($batchSize);
$deletedCount = $db->createCommand()
->delete('telegram_update_log', ['id' => $subQuery])
->execute();
*/
$totalDeleted += $deletedCount;
$this->stdout("Deleted chunk of {$deletedCount} logs...\n");
} while ($deletedCount >= $batchSize);
$this->stdout("Log rotation complete. Total records removed: {$totalDeleted}\n");
return ExitCode::OK;
}
/**
* Execute direct cURL request to Telegram Bot API with error handling.
*/
private function sendApiRequest(string $method, array $params = []): array
{
if (empty($this->token)) {
return [
'ok' => false,
'description' => 'Bot token is empty. Ensure TELEGRAM_BOT_TOKEN environment variable is set.',
];
}
$url = "https://api.telegram.org/bot{$this->token}/{$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,
]);
$rawResponse = curl_exec($ch);
$curlErrno = curl_errno($ch);
$curlError = curl_error($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($curlErrno !== 0) {
return [
'ok' => false,
'description' => "cURL Error ({$curlErrno}): {$curlError}",
];
}
$decoded = json_decode((string) $rawResponse, true);
if (json_last_error() !== JSON_ERROR_NONE) {
return [
'ok' => false,
'description' => 'Failed to parse JSON response. HTTP Code: ' . $httpCode,
];
}
return $decoded;
}
}
Выполнение команд через интерфейс командной строки
Чтобы выполнить эти действия на сервере, используйте двоичный код начальной загрузки Yii CLI по умолчанию Yii из корня вашего репозитория приложений.
# Verify bot account connectivity
php yii telegram/health-check
# Register public webhook endpoint
php yii telegram/set-webhook "https://example.com/telegram/webhook"
# Register webhook and drop any backlog of pending updates
php yii telegram/set-webhook "https://example.com/telegram/webhook" 1
# Remove webhook registration
php yii telegram/delete-webhook
# Purge updates logged more than 30 days ago
php yii telegram/rotate-logs 30
Конфигурация приложения
Убедитесь, что ваши файлы конфигурации безопасно передают учетные данные в консольную среду, не фиксируя конфиденциальные необработанные строки в репозитории. Измените config/params.php или config/console.php для получения параметров конфигурации во время выполнения.
// config/params.php
return [
'telegramBotToken' => getenv('TELEGRAM_BOT_TOKEN') ?: '',
'telegramWebhookUrl' => getenv('TELEGRAM_WEBHOOK_URL') ?: '',
'telegramSecretToken' => getenv('TELEGRAM_SECRET_TOKEN') ?: '',
];
Секретные токены Webhook и изоляция обновления
При установке веб-перехватчика с помощью actionSetWebhook, поставляя секретный токен string (от 1 до 256 символов с использованием (?(?=[^a-z]*[a-z])) приводит к тому, что Telegram прикрепляет X-Telegram-Bot-Api-Secret-Token заголовка для каждого входящего HTTP-запроса, отправленного на ваш URL-адрес веб-перехватчика.
В вашем веб-контроллере конечных точек (например, controllers/TelegramController.php), вы должны проверить этот заголовок перед чтением полезной нагрузки запроса:
public function actionWebhook()
{
$receivedSecret = Yii::$app->request->getHeaders()->get('X-Telegram-Bot-Api-Secret-Token');
$expectedSecret = Yii::$app->params['telegramSecretToken'];
if (empty($expectedSecret) || !hash_equals($expectedSecret, (string) $receivedSecret)) {
Yii::$app->response->statusCode = 403;
return 'Unauthorized';
}
// Parse update payload...
}
Автоматическая ротация журнала с помощью системного планировщика
При обработке обновлений боты с высоким трафиком сохраняют необработанный ввод JSON в таблицы базы данных для аудита и асинхронной обработки. Со временем такие таблицы, как telegram_update_log накапливают миллионы строк, что приводит к снижению скорости индексирования и высокому использованию хранилища.
Выполнение ротации журнала внутри системного cron предотвращает раздувание базы данных. Добавьте команду в crontab вашего сервера (crontab -e):
# Purge logs older than 14 days every night at 02:00 AM
0 2 * * * /usr/bin/php /var/www/html/yii telegram/rotate-logs 14 > /dev/null 2>&1
Использование фрагментированных пакетных удалений внутри actionRotateLogs предотвращает длительные блокировки транзакций в таблицах базы данных, позволяя одновременным запросам на запись от входящих веб-перехватчиков завершаться без тайм-аута.
Создание крупномасштабных интеграций часто требует расширения рабочих процессов управления API для обработки структурированных полезных нагрузок, проверки подлинности мини-приложений и автоматизированных конвейеров развертывания. Если вам нужна специальная поддержка разработки или пользовательские архитектурные решения для платформ Telegram, обратитесь в BotCreator — студию, которая поставляет ботов Telegram/мини-приложения. Для получения подробной информации о низкоуровневых конструкциях полезной нагрузки ознакомьтесь с официальной документацией по адресу