Создаём Telegram-бота на PHP 8: webhook, меню и inline-кнопки
Что получится
Соберём небольшого, но настоящего бота:
/startи/menuпоказывают приветствие и меню;/helpобъясняет команды;- inline-кнопки отправляют callback-запрос;
- сервер проверяет секретный заголовок webhook;
- токен хранится в переменной окружения, а не в PHP-коде;
- автоматические тесты проверяют обработчик без реального Telegram.
Бот будет написан на PHP 8.1+ и работать через официальный HTTP Bot API. Сторонние библиотеки не нужны. Для приёма обновлений понадобится публичный адрес с HTTPS.
1. Создаём бота в BotFather
Откройте Telegram и найдите официальный аккаунт @BotFather. Выполните /newbot, задайте отображаемое имя и username, который заканчивается на bot. BotFather выдаст токен.
Токен даёт возможность управлять ботом. Не публикуйте его, не добавляйте в исходники, скриншоты, открытые логи и Git. Если токен случайно оказался публичным, отзовите его в BotFather и используйте новый.
Для разработки достаточно своего тестового бота. Не проверяйте примеры на рабочем сообществе, пока не убедились, что понимаете каждую отправляемую команду.
2. Требования и структура проекта
Понадобятся:
- PHP 8.1 или новее;
- включённое расширение cURL;
- хостинг, на котором PHP-скрипт доступен по HTTPS;
- возможность задать переменные окружения.
Структура скачиваемого проекта:
telegram-webhook-bot/
├── bin/
│ └── set-webhook.php
├── public/
│ └── webhook.php
├── src/
│ ├── Bot.php
│ ├── TelegramApi.php
│ └── TelegramClient.php
└── tests/
└── run.php
Настройте document root сайта на каталог public/. Папки src/, bin/ и tests/ не должны раздаваться веб-сервером как публичные файлы. Если хостинг не позволяет менять корень сайта, разместите проект вне публичной директории и выведите наружу только endpoint webhook.
Проверьте PHP и cURL:
php -v
php -m
В списке модулей должно быть curl.
3. Разделяем обработку команд и HTTP API
Вместо того чтобы смешивать бизнес-логику с отправкой HTTP-запроса, проект использует интерфейс TelegramClient. Это упрощает тестирование: в тестах вместо Telegram подставляется фальшивый клиент.
interface TelegramClient
{
public function sendMessage(
int|string $chatId,
string $text,
?array $replyMarkup = null
): void;
public function answerCallbackQuery(
string $callbackQueryId,
string $text = ''
): void;
}
Реализация TelegramApi отправляет JSON через cURL, задаёт тайм-ауты и проверяет сразу три результата: сетевую ошибку, HTTP-статус и поле ok в JSON-ответе Telegram. Если запрос не удался, программа выдаёт исключение; она не делает вид, будто сообщение отправлено.
Бот понимает /start, /menu и /help. Нажатие inline-кнопки приходит отдельным объектом callback_query, поэтому обработчик отвечает на callback и отправляет выбранный раздел обычным сообщением.
Полные исходники классов TelegramApi и Bot находятся в архиве проекта. Важная деталь: callback_data — это только значение кнопки, а не секрет и не доказательство полномочий пользователя. В боте, который меняет данные или выполняет действия, права нужно проверять отдельно.
4. Принимаем обновления через webhook
Webhook — это HTTPS-адрес вашего приложения, на который Telegram отправляет POST-запросы с JSON-обновлениями. Для защиты задаётся secret_token; затем сервер сверяет его с заголовком X-Telegram-Bot-Api-Secret-Token.
Упрощённая логика проверки в public/webhook.php:
$providedSecret = $_SERVER['HTTP_X_TELEGRAM_BOT_API_SECRET_TOKEN'] ?? '';
if (!is_string($providedSecret) || !hash_equals($secret, $providedSecret)) {
http_response_code(403);
exit('Forbidden');
}
hash_equals() выполняет безопасное сравнение строк. Endpoint также ограничивает размер тела запроса и отвечает 405 на любой метод, кроме POST. Текст исключения и токен не отправляются посетителю или в журнал: наружу уходит нейтральное сообщение, а в серверный лог — класс ошибки.
В этом демонстрационном боте обрабатываются только текстовые команды и callback-кнопки. Фото, документы и неизвестные типы обновлений игнорируются. Это явное поведение: новые функции добавляйте отдельными обработчиками и тестами.
5. Задаём настройки безопасно
Нужны три переменные окружения:
TELEGRAM_BOT_TOKEN— токен от BotFather;TELEGRAM_WEBHOOK_SECRET— случайная строка для заголовка webhook;TELEGRAM_WEBHOOK_URL— полный HTTPS-адресwebhook.php.
Сгенерировать случайный секрет локально можно командой:
php -r "echo bin2hex(random_bytes(32)), PHP_EOL;"
Укажите переменные в панели хостинга. Для локального запуска CLI в PowerShell:
$env:TELEGRAM_BOT_TOKEN = 'токен-из-BotFather'
$env:TELEGRAM_WEBHOOK_SECRET = 'случайная-строка'
$env:TELEGRAM_WEBHOOK_URL = 'https://example.ru/telegram/webhook.php'
Не делайте скриншот с реальными значениями. Настройки PowerShell относятся только к текущему окну терминала и не заменяют конфигурацию на сервере.
6. Регистрируем webhook
Убедитесь, что endpoint уже загружен, домен открывается по HTTPS и сертификат действителен. Затем из корня проекта запустите:
php bin/set-webhook.php
Скрипт проверит HTTPS-схему и допустимые символы секрета, затем вызовет метод setWebhook. В ответ он выводит только результат операции — токен не показывается.
Для одного бота выбирают один способ получения обновлений: webhook или long polling через getUpdates. Если webhook уже установлен, polling не используется. Проверить состояние можно через Bot API getWebhookInfo; не публикуйте вывод, если в нём виден адрес endpoint.
7. Проверяем код до подключения Telegram
Тесты работают без токена и не отправляют запросы в сеть:
php tests/run.php
Они проверяют, что:
/startотвечает в нужный чат;- главное меню содержит inline-кнопки;
- callback получает ответ;
- неподдерживаемый тип обновления безопасно игнорируется.
Перед размещением проверьте синтаксис всех PHP-файлов:
Get-ChildItem -Recurse -Filter *.php | ForEach-Object {
php -l $_.FullName
}
После регистрации webhook откройте бота, отправьте /start, нажмите «О боте», затем попробуйте /help. Для каждого шага сделайте скриншот без персональных данных и секретов.
8. Как расширять проект
Добавляйте одну функцию за раз:
- обработчик текстового сообщения;
- новую кнопку с отдельным значением
callback_data; - хранение состояния в MySQL/SQLite;
- очередь для долгих задач;
- логирование и мониторинг.
Перед созданием платежей, заказов или других действий, которые нельзя выполнить дважды, добавьте устойчивую обработку update_id, транзакционное хранилище и очередь/outbox. Telegram может повторить webhook-доставку при сетевой ошибке; простой демонстрационный обработчик не обеспечивает «ровно один раз» для внешнего побочного эффекта.
Частые проблемы
Webhook возвращает 403. Проверьте, что хостинг передаёт X-Telegram-Bot-Api-Secret-Token в PHP и что секрет точно совпадает.
setWebhook сообщает об ошибке. Убедитесь, что URL начинается с https://, доступен извне и сертификат действителен.
Бот молчит. Проверьте PHP error log, переменную токена и состояние через getWebhookInfo. Не передавайте токен в публичный чат поддержки.
Запрос отклоняется из-за cURL. Проверьте, что расширение PHP cURL включено именно для той версии PHP, которая обслуживает сайт.
Итог
Мы получили минимальный проект, который можно запустить на PHP-хостинге: команды, inline-меню, защищённый webhook, тесты и сценарий регистрации endpoint. Это не готовая коммерческая платформа — в ней намеренно нет базы данных, ролей и очереди. Но структура уже позволяет развивать учебный пример по шагам и проверять каждое изменение.
Скачать исходный код: архив проекта
KOTOFF.NET