Для большинства случаев подойдет модуль Александра Горячкина, который лежит на маркетплейсе https://marketplace.1c-bitrix.ru/solutions/xzag.telegram/
Модуль бесплатный, за что ему говорим "Большое спасибо".
Но бывают проекты, где много нестандартных сценариев отправки уведомлений. По поводу и без. Для таких случаев создадим себе заготовку - болванку, которую потом можно будет масштабировать.
Итак, погнали.
Регистрируем бот Телеграм
Бот в Telegram делаем через @BotFather , как это сделать, в интернете найти не сложно.
На данном этапе, нам нужно получить API_KEY
Получаем ID чата
Бот может отправлять сообщения только пользователям, которые начали с ним диалог.
Чтобы получить chat_id:
-
Напишите боту любое сообщение.
-
Выполните GET-запрос:
https://api.telegram.org/bot<ВАШ_API_КЛЮЧ>/getUpdates -
В ответе найдите
idв разделеchat.Пример:
{ "ok": true, "result": [{ "update_id": 123, "message": { "chat": {"id": 123456789}, "text": "Hello" } }] }
Организовываем структуру файлов
В папке local/php_interface/lib/ создаем пространство для чатботов, их может быть несколько, сейчас создаем папку Telegram и складываем файлы:
-
Telegram/TelegramBase.php- это будет наша база -
Telegram/TelegramAlert.php- класс для уведомлений -
И сюда же в будущем будем складывать логику для сущностей (Пользователь, Заказ, другие специфичные сценарии)
TelegramBase.php
<?php
namespace Chatbot\Telegram;
use Exception;
use InvalidArgumentException;
class TelegramBase
{
private string $botToken;
private string $chatId;
private string $apiUrl;
private int $timeout;
private array $lastResponse;
public function __construct(string $botToken, string $chatId, int $timeout = 30)
{
$this->validateBotToken($botToken);
$this->validateChatId($chatId);
$this->botToken = $botToken;
$this->chatId = $chatId;
$this->timeout = $timeout;
$this->apiUrl = "https://api.telegram.org/bot{$this->botToken}/";
$this->lastResponse = [];
}
/**
* Отправляет сообщение о регистрации нового пользователя
*
* @param string $name Имя пользователя
* @param string $email Email пользователя
* @param string $phone Номер телефона пользователя
* @return array Ответ от Telegram API
* @throws Exception
*/
public function sendUserRegistrationMessage(string $name, string $email, string $phone): array
{
$message = $this->formatRegistrationMessage($name, $email, $phone);
return $this->sendMessage($message, 'HTML'); // Используем HTML вместо Markdown
}
/**
* Отправляет сообщение в Telegram
*
* @param string $message Текст сообщения
* @param string $parseMode Режим парсинга (Markdown, HTML, MarkdownV2)
* @param array $additionalParams Дополнительные параметры
* @return array Ответ от Telegram API
* @throws Exception
*/
public function sendMessage(
string $message,
string $parseMode = 'HTML',
array $additionalParams = []
): array {
$url = $this->apiUrl . 'sendMessage';
$data = array_merge([
'chat_id' => $this->chatId,
'text' => $message,
'parse_mode' => $parseMode
], $additionalParams);
$response = $this->makeRequest($url, $data);
$this->lastResponse = $response;
if (!($response['ok'] ?? false)) {
throw new Exception(
'Ошибка отправки сообщения: ' .
($response['description'] ?? 'Неизвестная ошибка')
);
}
return $response;
}
/**
* Отправляет документ в Telegram
*
* @param string $document Путь к файлу или file_id
* @param string $caption Подпись к документу
* @return array
* @throws Exception
*/
public function sendDocument(string $document, string $caption = ''): array
{
$url = $this->apiUrl . 'sendDocument';
$data = [
'chat_id' => $this->chatId,
'document' => $document
];
if (!empty($caption)) {
$data['caption'] = $caption;
}
$response = $this->makeRequest($url, $data);
$this->lastResponse = $response;
if (!($response['ok'] ?? false)) {
throw new Exception(
'Ошибка отправки документа: ' .
($response['description'] ?? 'Неизвестная ошибка')
);
}
return $response;
}
/**
* Форматирует сообщение о регистрации пользователя
*
* @param string $name
* @param string $email
* @param string $phone
* @return string
*/
private function formatRegistrationMessage(string $name, string $email, string $phone): string
{
return "🎉 <b>Новая регистрация!</b>\n\n" .
"<b>Имя:</b> " . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . "\n" .
"<b>Email:</b> " . htmlspecialchars($email, ENT_QUOTES, 'UTF-8') . "\n" .
"<b>Телефон:</b> " . htmlspecialchars($phone, ENT_QUOTES, 'UTF-8') . "\n\n" .
"<b>Время:</b> " . date('d.m.Y H:i:s');
}
/**
* Выполняет HTTP запрос к Telegram API
*
* @param string $url
* @param array $data
* @return array
* @throws Exception
*/
private function makeRequest(string $url, array $data): array
{
// Попробуем использовать cURL, если доступен
if (function_exists('curl_init')) {
return $this->makeRequestWithCurl($url, $data);
}
// Fallback на file_get_contents
return $this->makeRequestWithFileGetContents($url, $data);
}
/**
* Выполняет запрос через cURL
*
* @param string $url
* @param array $data
* @return array
* @throws Exception
*/
private function makeRequestWithCurl(string $url, array $data): array
{
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($data),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => $this->timeout,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_USERAGENT => 'TelegramBot/1.0',
CURLOPT_HTTPHEADER => [
'Content-Type: application/x-www-form-urlencoded'
]
]);
$result = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($result === false) {
throw new Exception('Ошибка cURL: ' . $error);
}
if ($httpCode !== 200) {
throw new Exception("HTTP ошибка: {$httpCode}");
}
return $this->parseResponse($result);
}
/**
* Выполняет запрос через file_get_contents
*
* @param string $url
* @param array $data
* @return array
* @throws Exception
*/
private function makeRequestWithFileGetContents(string $url, array $data): array
{
$postData = http_build_query($data);
$context = stream_context_create([
'http' => [
'method' => 'POST',
'header' => [
'Content-Type: application/x-www-form-urlencoded',
'User-Agent: TelegramBot/1.0'
],
'content' => $postData,
'timeout' => $this->timeout
]
]);
$result = @file_get_contents($url, false, $context);
if ($result === false) {
$error = error_get_last();
throw new Exception('Не удалось выполнить запрос: ' . ($error['message'] ?? 'Неизвестная ошибка'));
}
return $this->parseResponse($result);
}
/**
* Парсит ответ от Telegram API
*
* @param string $response
* @return array
* @throws Exception
*/
private function parseResponse(string $response): array
{
$decoded = json_decode($response, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new Exception('Ошибка декодирования JSON ответа: ' . json_last_error_msg());
}
return $decoded;
}
/**
* Проверяет корректность настроек бота
*
* @return array Информация о боте
* @throws Exception
*/
public function getMe(): array
{
$url = $this->apiUrl . 'getMe';
return $this->makeRequest($url, []);
}
/**
* Валидирует токен бота
*
* @param string $token
* @throws InvalidArgumentException
*/
private function validateBotToken(string $token): void
{
if (empty($token)) {
throw new InvalidArgumentException('Токен бота не может быть пустым');
}
if (!preg_match('/^\d+:[A-Za-z0-9_-]{35}$/', $token)) {
throw new InvalidArgumentException('Некорректный формат токена бота');
}
}
/**
* Валидирует chat_id
*
* @param string $chatId
* @throws InvalidArgumentException
*/
private function validateChatId(string $chatId): void
{
if (empty($chatId)) {
throw new InvalidArgumentException('Chat ID не может быть пустым');
}
}
/**
* Устанавливает новый chat_id
*
* @param string $chatId
* @throws InvalidArgumentException
*/
public function setChatId(string $chatId): void
{
$this->validateChatId($chatId);
$this->chatId = $chatId;
}
/**
* Получает текущий chat_id
*
* @return string
*/
public function getChatId(): string
{
return $this->chatId;
}
/**
* Получает последний ответ API
*
* @return array
*/
public function getLastResponse(): array
{
return $this->lastResponse;
}
/**
* Устанавливает таймаут запросов
*
* @param int $timeout
*/
public function setTimeout(int $timeout): void
{
$this->timeout = max(1, $timeout);
}
}
TelegramAlert.php
<?php
namespace Chatbot\Telegram;
use Exception;
use InvalidArgumentException;
class TelegramAlert
{
private const BOT_TOKEN = '11111111111111'; // Токен, он же api key
private const CHAT_IDS = [
'main' => 987654321, // id чата куда шлем уведомления
// 'backup' => 987654321, // Резервный чат
];
private const MESSAGE_TYPES = [
'registration' => '🎉 <b>Новая регистрация!</b>',
'order' => '🛒 <b>Новый заказ!</b>',
'error' => '⚠️ <b>Системная ошибка!</b>',
'notification' => '📢 <b>Уведомление</b>'
];
private static ?TelegramBase $telegram = null;
/**
* Отправляет уведомление о регистрации нового пользователя
*
* @param string $name Имя пользователя
* @param string $email Email пользователя
* @param string $phone Номер телефона пользователя
* @param string $chatKey Ключ чата из массива CHAT_IDS
* @return bool Успешность отправки
*/
public static function sendNewUserRegistration(
string $name,
string $email,
string $phone,
string $chatKey = 'main'
): bool {
try {
self::validateUserData($name, $email, $phone);
$telegram = self::getTelegramInstance($chatKey);
$message = self::formatRegistrationMessage($name, $email, $phone);
$response = $telegram->sendMessage($message, 'HTML');
return $response['ok'] ?? false;
} catch (Exception $e) {
self::logError('Ошибка отправки уведомления о регистрации', [
'error' => $e->getMessage(),
'name' => $name,
'email' => $email,
'phone' => $phone
]);
return false;
}
}
/**
* Отправляет уведомление о новом заказе
*
* @param array $orderData Данные заказа
* @param string $chatKey Ключ чата
* @return bool
*/
public static function sendNewOrder(array $orderData, string $chatKey = 'main'): bool
{
try {
$telegram = self::getTelegramInstance($chatKey);
$message = self::formatOrderMessage($orderData);
$response = $telegram->sendMessage($message, 'HTML');
return $response['ok'] ?? false;
} catch (Exception $e) {
self::logError('Ошибка отправки уведомления о заказе', [
'error' => $e->getMessage(),
'orderData' => $orderData
]);
return false;
}
}
/**
* Отправляет системное уведомление
*
* @param string $message Текст сообщения
* @param string $type Тип сообщения
* @param string $chatKey Ключ чата
* @return bool
*/
public static function sendSystemNotification(
string $message,
string $type = 'notification',
string $chatKey = 'main'
): bool {
try {
$telegram = self::getTelegramInstance($chatKey);
$formattedMessage = self::formatSystemMessage($message, $type);
$response = $telegram->sendMessage($formattedMessage, 'HTML');
return $response['ok'] ?? false;
} catch (Exception $e) {
self::logError('Ошибка отправки системного уведомления', [
'error' => $e->getMessage(),
'message' => $message,
'type' => $type
]);
return false;
}
}
/**
* Отправляет уведомления во все доступные чаты
*
* @param string $message Текст сообщения
* @param string $type Тип сообщения
* @return array Результаты отправки по каждому чату
*/
public static function sendToAllChats(string $message, string $type = 'notification'): array
{
$results = [];
foreach (array_keys(self::CHAT_IDS) as $chatKey) {
$results[$chatKey] = self::sendSystemNotification($message, $type, $chatKey);
}
return $results;
}
/**
* Получает экземпляр TelegramBase
*
* @param string $chatKey
* @return TelegramBase
* @throws InvalidArgumentException
*/
private static function getTelegramInstance(string $chatKey): TelegramBase
{
if (!isset(self::CHAT_IDS[$chatKey])) {
throw new InvalidArgumentException("Неизвестный ключ чата: {$chatKey}");
}
$chatId = (string) self::CHAT_IDS[$chatKey];
// Создаем новый экземпляр для каждого чата
return new TelegramBase(self::BOT_TOKEN, $chatId);
}
/**
* Валидация данных пользователя
*
* @param string $name
* @param string $email
* @param string $phone
* @throws InvalidArgumentException
*/
private static function validateUserData(string $name, string $email, string $phone): void
{
if (empty(trim($name))) {
throw new InvalidArgumentException('Имя пользователя не может быть пустым');
}
if (empty(trim($email)) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException('Некорректный email адрес');
}
if (empty(trim($phone))) {
throw new InvalidArgumentException('Номер телефона не может быть пустым');
}
}
/**
* Форматирует сообщение о регистрации
*
* @param string $name
* @param string $email
* @param string $phone
* @return string
*/
private static function formatRegistrationMessage(string $name, string $email, string $phone): string
{
return self::MESSAGE_TYPES['registration'] . "\n\n" .
"<b>Имя:</b> " . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . "\n" .
"<b>Email:</b> " . htmlspecialchars($email, ENT_QUOTES, 'UTF-8') . "\n" .
"<b>Телефон:</b> " . htmlspecialchars($phone, ENT_QUOTES, 'UTF-8') . "\n\n" .
"<b>Время:</b> " . date('d.m.Y H:i:s') . "\n" .
"<b>Сайт:</b> " . ($_SERVER['HTTP_HOST'] ?? 'Неизвестно');
}
/**
* Форматирует сообщение о заказе
*
* @param array $orderData
* @return string
*/
private static function formatOrderMessage(array $orderData): string
{
$message = self::MESSAGE_TYPES['order'] . "\n\n";
if (isset($orderData['id'])) {
$message .= "🆔 <b>Номер заказа:</b> " . htmlspecialchars($orderData['id'], ENT_QUOTES, 'UTF-8') . "\n";
}
if (isset($orderData['customer'])) {
$message .= "👤 <b>Клиент:</b> " . htmlspecialchars($orderData['customer'], ENT_QUOTES, 'UTF-8') . "\n";
}
if (isset($orderData['total'])) {
$message .= "💰 <b>Сумма:</b> " . htmlspecialchars($orderData['total'], ENT_QUOTES, 'UTF-8') . " ₽\n";
}
if (isset($orderData['items_count'])) {
$message .= "📦 <b>Товаров:</b> " . htmlspecialchars($orderData['items_count'], ENT_QUOTES, 'UTF-8') . "\n";
}
$message .= "\n⏰ <b>Время:</b> " . date('d.m.Y H:i:s');
return $message;
}
/**
* Форматирует системное сообщение
*
* @param string $message
* @param string $type
* @return string
*/
private static function formatSystemMessage(string $message, string $type): string
{
$header = self::MESSAGE_TYPES[$type] ?? self::MESSAGE_TYPES['notification'];
return $header . "\n\n" .
htmlspecialchars($message, ENT_QUOTES, 'UTF-8') . "\n\n" .
"⏰ <b>Время:</b> " . date('d.m.Y H:i:s') . "\n" .
"🌐 <b>Сервер:</b> " . ($_SERVER['HTTP_HOST'] ?? 'Неизвестно');
}
/**
* Логирует ошибки
*
* @param string $message
* @param array $context
*/
private static function logError(string $message, array $context = []): void
{
$logMessage = date('[Y-m-d H:i:s] ') . $message;
if (!empty($context)) {
$logMessage .= ' | Context: ' . json_encode($context, JSON_UNESCAPED_UNICODE);
}
$logMessage .= PHP_EOL;
// Логируем в файл или используем системный логгер
error_log($logMessage, 3, __DIR__ . '/telegram_errors.log');
}
/**
* Проверяет работоспособность бота
*
* @return bool
*/
public static function healthCheck(): bool
{
try {
$telegram = self::getTelegramInstance('main');
$response = $telegram->getMe();
return $response['ok'] ?? false;
} catch (Exception $e) {
self::logError('Ошибка проверки работоспособности бота', [
'error' => $e->getMessage()
]);
return false;
}
}
/**
* Получает информацию о боте
*
* @return array|null
*/
public static function getBotInfo(): ?array
{
try {
$telegram = self::getTelegramInstance('main');
$response = $telegram->getMe();
return $response['result'] ?? null;
} catch (Exception $e) {
self::logError('Ошибка получения информации о боте', [
'error' => $e->getMessage()
]);
return null;
}
}
}
Пример использования
Отправим уведомление о том, что зарегистрировался новый пользователь
в файл с эвентами добавляем код , перехватываем события OnAfterUserRegister и OnAfterUserSimpleRegister
$eventManager->addEventHandler(
'main',
'OnAfterUserRegister',
[Helper\UserHelper::class, 'telegramBotAlertAfterNewUserRegistration']
);
$eventManager->addEventHandler(
'main',
'OnAfterUserSimpleRegister',
[Helper\UserHelper::class, 'telegramBotAlertAfterNewUserRegistration']
);
Метод telegramBotAlertAfterNewUserRegistration()
public static function telegramBotAlertAfterNewUserRegistration(array &$arFields):void
{
TelegramAlert::sendNewUserRegistration(
$arFields['NAME'],
$arFields['EMAIL'],
$arFields['PHONE_NUMBER'],
);
}
Еще варианты до кучи
// Отправка уведомления о регистрации
TelegramAlert::sendNewUserRegistration(
'Иван Петров',
'ivan@example.com',
'+7 999 123-45-67'
);
// Отправка уведомления о заказе
TelegramAlert::sendNewOrder([
'id' => '12345',
'customer' => 'Иван Петров',
'total' => '15000',
'items_count' => '3'
]);
// Системное уведомление
TelegramAlert::sendSystemNotification(
'Произошла критическая ошибка в системе',
'error'
);
// Проверка работоспособности
if (TelegramAlert::healthCheck()) {
echo "Бот работает нормально";
}
И получаем уведомление из Битрикс в Telegram