Глибоке зв'язання в Telegram-боті: LIMIT, MAPPING і БЕЗОПАСНОСТЬ

Deep linking в Telegram — сильний інструмент для вказування користувачів на конкретні дії (реєстрація послуги, відкриття картки, бронювання). Однак використання t.me/Bot?start=payload вимагає суворого дотримання обмежень API та захисту від підміни даних.

\n\n

ЛІМИТИ payload і обмеження API

\n

Telegram дозволяє передавати в callback_data не більше 64 байт. Це критично для безпеки та продуктивності. Якщо payload занадто великий, сервер відхиляє запит або він просто не проходить валидацію. Також врахуйте, що payload має бути кодуванням UTF-8 рядковим значенням.

\n\n

МАППИНГ start → сущність у БД

\n

При отриманні t.me/Bot?start=payload ви повинні поєднати цей payload з існуючим об'єктом у базі даних. Стандартна практика — генерувати унікальний lead_id (bin2hex(random_bytes(7))) і зберігати його разом із payload. Для ідемпотентності використовуйте update_id з webhook-відповіді як ключ для перевірки дублікатів.

\n\n

БЕЗОПАСНОСТЬ: захист від підміни payload

\n

Підміна callback_data — класична атака, яка може призвести до несанкціованої дії бота. Щоб захиститися:

\n
    \n
  • Зawsal валідувати update_id з webhook перед обробкою payload.
  • \n
  • Храніть мапу в БД з timestamp і перевірте, що current_update_id не збігається з збереженим.
  • \n
  • Використовуйте HMAC‑SHA256 для підписання важливих параметрів, якщо бізнес-логіка потребує додаткової перевірки.
  • \n
\n\n

ПРАКТІЧНА РЕАЛЬИЗАЦІЯ

\n

Нижче наведені приклади коду на PHP (Yii2/Laravel) для надсилки глибокого зв'язку та його обробки з ідемпотентністю.

\n\n
// Отправка deep link через webhook с валидацией
$url = 'https://api.telegram.org/bot/sendMessage';
$data = [
'text' => 'Запись на услугу',
'callback_data' => 'deep_link_abc123def456', // ≤ 64 байтов
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer '
]);
$response = curl_exec($ch);
$body = json_decode($response, true);
if (!isset($body['ok']) || $body['ok'] !== true) {
throw new RuntimeException('Telegram API rejected request');
}
curl_close($ch);

// Обработка deep link после получения
function handleDeepLink($updateId, $callbackData) {
// Генерация lead_id для идемпотентности
$leadId = bin2hex(random_bytes(7));

// Проверка, что payload соответствует ожидаемому формату
if (strpos($callbackData, 'deep_link_') !== false) {
// Извлекаем сущность
$entityType = substr(str_replace(['deep_link_', ''], '', $callbackData), 0, strlen($callbackData) - 16);
$payload = explode('|', $callbackData)[1] ?? null;

// Сохраняем в БД (пример)
$record = new DeepLinkRecord($leadId, $entityType, 1, ['name' => $payload]);
$db->save($record);

// Сохраняем update_id для идемпотентности
$updatedUpdateId = $updateId;
} else {
throw new RuntimeException('Invalid deep link payload');
}
}
\n\n

Приклад зберігання в БД (псевдокод для чіткості):

\n
// Таблица deep_link_entities
// columns: id, lead_id (PK), entity_type, record_id, created_at

// Создание записи при first time
$leadId = bin2hex(random_bytes(7));
$entity = 'service'; // или 'appointment', 'product'
$record = new EntityRecord($leadId, $entity, 1, ['name' => 'Услуга А']);
$db->insert('deep_link_entities', [
'lead_id' => $leadId,
'entity_type' => $entity,
'record_id' => $record->id,
'created_at' => date('c')
]);

// Проверка дубликатов при повторном запросе
$existing = $db->find('deep_link_entities', ['lead_id' => $leadId'])
->where('entity_type', $entity)
->first();
if ($existing) {
// Payload уже обработан — возвращаем результат предыдущей операции
return $existing->processedPayload;
}
\n\n

Запам'ятайте: завжди перевіряйте HTTP статус (200 OK), використовуйте json_last_error() для діагностики, і зберігайте update_id разом із payload для гарантії ідемпотентності. Це мінімізує ризик підміни та забезпечує стабільну роботу вашого бота.

"}

Нові статті — у Telegram

Розбираємо, що автоматизувати в бізнесі та як це працює на практиці. Без спаму.