Что подготовить перед установкой
- Создайте бота через официальный BotFather и добавьте его Telegram-токен в кабинет BotGate.
- Получите API-ключ BotGate и публичный ID бота вида
bot_…. Telegram-токен, API-ключ и публичный ID — разные значения. - Подготовьте PHP 8.2 или новее, Composer и исходящее HTTPS-соединение с BotGate.
- Откройте личный чат с ботом и отправьте ему
/start. Для первого сообщения используйте собственный тестовый чат.
chat_id — идентификатор чата-получателя, а не ID бота. Его можно получить из message.chat.id входящего обновления после настройки webhook. В BotGate getUpdates не поддерживается; пример разбора обновления есть ниже. Если бот должен писать в группу или канал, отдельно проверьте его участие и права.
Не публикуйте ключи в HTML, JavaScript, Git или скриншотах. PHP выполняет запрос на сервере; браузеру достаточно обратиться к вашему собственному авторизованному обработчику.
1. Установите пакет и создайте клиент
В каталоге вашего PHP-приложения:
composer require botgate/sdk
Composer установит зависимости HTTP-клиента. Сохраните composer.lock, чтобы окружения использовали согласованные версии. Эти команды предназначены для вашего проекта, а не для каталога сервера BotGate.
Передайте процессу PHP переменные BOTGATE_API_KEY и BOTGATE_BOT_ID; для отправки понадобится TELEGRAM_CHAT_ID. Используйте настройки хостинга, контейнера или менеджера секретов. Обычный PHP не загружает файл .env автоматически. Если проект использует dotenv, его загрузку нужно выполнить до этого кода.
Создайте bootstrap.php рядом с vendor. PHP-файлы в примерах должны начинаться с <?php; открывающий тег в блоках опущен.
declare(strict_types=1);
use BotGate\Client;
use BotGate\Config;
require __DIR__.'/vendor/autoload.php';
$requiredEnv = static function (string $name): string {
$value = getenv($name);
if ($value === false || trim($value) === '') {
throw new RuntimeException('Не задана переменная '.$name);
}
return $value;
};
$client = Client::fromConfig(new Config(
apiKey: $requiredEnv('BOTGATE_API_KEY'),
timeout: 20.0,
maxRetries: 0,
));
$bot = $client->bot($requiredEnv('BOTGATE_BOT_ID'));
maxRetries: 0 выбран намеренно: решение о повторе будет принимать приложение. Стандартный транспорт SDK повторяет HTTP 429, 502, 503 и 504. При ошибке после отправки неизвестно, успел ли Telegram выполнить действие; повтор может создать второе сообщение.
Сначала выполните безопасный запрос, который ничего не отправляет:
declare(strict_types=1);
require __DIR__.'/bootstrap.php';
$response = $bot->call('getMe');
echo $response->ok ? "Бот доступен\n" : "Проверка не пройдена\n";
Запустите php check.php в среде проекта. Успех означает доступность этого метода через шлюз; отправка в чат и входящий webhook проверяются отдельно.
2. Отправьте сообщение в тестовый чат
Создайте CLI-скрипт send.php. Он выполняет одну попытку и не повторяет сообщение автоматически:
declare(strict_types=1);
use BotGate\Exception\BotGateException;
use BotGate\Exception\RateLimitException;
use BotGate\Exception\TelegramException;
use BotGate\Exception\TransportException;
require __DIR__.'/bootstrap.php';
try {
$response = $bot->call('sendMessage', [
'chat_id' => $requiredEnv('TELEGRAM_CHAT_ID'),
'text' => 'Проверка уведомлений из PHP',
]);
$result = is_array($response->result) ? $response->result : [];
echo 'Отправлено. message_id: '.($result['message_id'] ?? 'не указан')."\n";
} catch (RateLimitException $error) {
$wait = $error->retryAfter();
fwrite(STDERR, 'Лимит BotGate. Ожидание: '.($wait ?? 'не указано')." секунд\n");
exit(1);
} catch (TelegramException $error) {
if ($error->telegramErrorCode() === 429) {
$wait = $error->retryAfter();
fwrite(STDERR, 'Лимит Telegram. Ожидание: '.($wait ?? 'не указано')." секунд\n");
} else {
fwrite(STDERR, 'Telegram отклонил запрос, код '.($error->telegramErrorCode() ?? 'не указан').". Проверьте параметры и права бота.\n");
}
exit(1);
} catch (TransportException $error) {
fwrite(STDERR, "Сбой соединения. Результат отправки неизвестен; проверьте чат и журнал.\n");
exit(1);
} catch (BotGateException $error) {
fwrite(STDERR, 'Запрос остановлен, HTTP '.$error->httpStatusCode().". Проверьте настройки и ответ API.\n");
exit(1);
}
После php send.php проверьте сообщение в чате. Повторный запуск скрипта отправит ещё одно сообщение. Не привязывайте такой вызов к обычной загрузке публичной страницы: обновление страницы или повтор HTTP-запроса тогда тоже может вызвать отправку.
Для динамического текста начните без parse_mode. Если нужен HTML или Markdown, экранируйте пользовательские значения по правилам выбранного формата. Ошибка разметки — это ошибка параметров сообщения, а не признак недоступности Telegram.
В веб-приложении результат удобнее сохранять в журнале уведомлений: идентификатор бизнес-события, попытка, время и полученный message_id. Пользовательскую страницу не следует удерживать до завершения долгой сетевой операции; для регулярных уведомлений используйте очередь.
3. Отправьте небольшой файл
Для multipart-загрузки SDK принимает части запроса. MultipartField::file() не открывает путь сам. Передайте ресурс fopen, иначе строка пути станет содержимым загружаемого файла.
Создайте рядом со скриптом небольшой example.txt с тестовым текстом:
declare(strict_types=1);
use BotGate\Http\MultipartField;
require __DIR__.'/bootstrap.php';
$stream = fopen(__DIR__.'/example.txt', 'rb');
if ($stream === false) {
throw new RuntimeException('Не удалось открыть тестовый файл.');
}
try {
$bot->callMultipart('sendDocument', [
MultipartField::field('chat_id', $requiredEnv('TELEGRAM_CHAT_ID')),
MultipartField::file('document', $stream, 'example.txt', 'text/plain'),
MultipartField::field('caption', 'Тестовый документ из PHP'),
]);
} finally {
if (is_resource($stream)) {
fclose($stream);
}
}
Обработку исключений добавьте по схеме предыдущего примера. Не берите путь к локальному файлу напрямую из параметра пользователя. Для повторной попытки поток понадобится открыть заново; в этом примере повторы отключены.
Скачивание устроено отдельно: сначала вызовите getFile с полученным file_id, затем передайте file_path в $bot->downloadFile(...). Метод возвращает PSR-поток. Сохраняйте его в разрешённое место по частям и закрывайте после чтения; не считайте публичный URL с токеном безопасным способом отдать файл браузеру. Формат маршрута описан в документации файлов.
4. Принимайте события через webhook
Чтобы бот реагировал на команды, нужен HTTPS POST-обработчик. Его адрес указывается в карточке бота BotGate. Сервис доставляет JSON и заголовок X-BotGate-Signature; Webhook Secret берётся из той же карточки.
Следующая функция проверяет подпись по исходному телу и разбирает событие. Это часть обработчика, а не готовая система хранения и доставки:
declare(strict_types=1);
use BotGate\DTO\Update;
use BotGate\Webhook\SignatureValidator;
function decodeBotGateUpdate(string $body, string $signature, string $secret): Update
{
if ($secret === '') {
throw new RuntimeException('Webhook Secret не настроен.');
}
(new SignatureValidator($secret))->validate($body, $signature);
$update = Update::fromJson($body);
if (!is_int($update->payload['update_id'] ?? null)) {
throw new UnexpectedValueException('Отсутствует корректный update_id.');
}
return $update;
}
Загрузите Composer autoload и эту функцию в вашем POST-маршруте. Тело читайте из php://input, подпись — из $_SERVER['HTTP_X_BOTGATE_SIGNATURE'], секрет — из защищённой конфигурации. Не декодируйте и не пересобирайте JSON до проверки подписи.
При неверной подписи возвращайте 403, при некорректном JSON — 400. Ошибка конфигурации или сохранения события требует ответа об ошибке сервера. После проверки надёжно сохраните событие или поставьте задание в очередь и только затем отвечайте HTTP 2xx. BotGate ожидает подтверждение в течение 10 секунд.
Из $update->message() можно получить массив сообщения и message.chat.id; для кнопки используется $update->callbackQuery(). Сохраняйте уникальность пары «бот + update_id», чтобы повтор доставки не выполнил одну команду дважды. Полное тело события не нужно выводить в публичный ответ или обычные диагностические логи.
Подробная последовательность проверки адреса, TLS, очереди и обработчика есть в руководстве по webhook. Если проект использует Laravel, готовый маршрут и событие пакета разобраны в статье для Laravel.
Какие ошибки нужно различать
| Ситуация | Действие |
|---|---|
| 401 / 403 / 404 | Проверьте API-ключ, публичный ID, владельца, статус бота и разрешённый метод. Повтор без исправления настроек не поможет. |
| HTTP 429 BotGate | SDK бросает RateLimitException. Метод retryAfter() возвращает ожидание из числового заголовка Retry-After, если он передан. |
| Ошибка Telegram в JSON, HTTP 400 | SDK бросает TelegramException. telegramErrorCode() содержит код Telegram, parameters() — параметры ошибки. При коде 429 используйте retryAfter(); null означает, что корректное время ожидания не передано. |
| Таймаут / 502 / обрыв соединения | Результат операции может быть неизвестен. Не повторяйте отправку автоматически только на основании этой ошибки. |
Не стройте обработку ошибок только на проверке $response->ok: неуспешный ответ приводит к исключению ещё до получения DTO. У TelegramException метод httpStatusCode() возвращает HTTP-статус BotGate (400), а telegramErrorCode() — код Telegram (например, 429). Планирование отложенной попытки через SDK разобрано в статье о лимитах.
В журнале сохраняйте этап, метод, идентификатор уведомления и безопасный код ошибки. Не записывайте API-ключ и полный дамп исключения вместе с запросом: транспортное исключение может содержать сетевые подробности.
Что проверить до подключения реальных уведомлений
- getMe проходит из той же среды, где работает приложение.
- Однократный запуск отправляет одно сообщение нужному получателю.
- Тестовый документ содержит байты файла, а не строку пути к нему.
- Неверная подпись webhook отклоняется; правильная проверяется по исходному телу.
- Ошибки лимита, параметров и соединения обрабатываются по-разному.
- Повтор одного бизнес-события не приводит к бесконтрольной повторной отправке.
SDK решает сетевую часть интеграции. Хранение состояния диалога, правила команд, очередь уведомлений и защита от дублей остаются задачами приложения.
Источники
Подключение, настройка клиента и обработка ошибок описаны в README BotGate PHP SDK. Форматы запросов и ответов сервиса — в документации BotGate.
Это учебная интеграция для собственного тестового бота. Отправляющие скрипты меняют состояние чата.