Как подключить форму на одностраничнике к Telegram-чату: пошагово

Заявки с сайтов чат телеграм Полезное

Внимание, этот мануал для тех, кто немного разбирается в коде и у кого уже есть готовый сайт, к которому нужно наладить отправку форм в телеграм чатах.

Зачем вообще Telegram для заявок

  • Мгновенные уведомления: видишь заявки сразу, не ждёшь почту.
  • Удобно обрабатывать с телефона: ответил — закрепил — поставил реакцию.
  • Низкий процент потерь: даже если на хостинге “падает” SMTP, Telegram доставит.

Что понадобится

  1. Аккаунт в Telegram.
  2. Бот (создаётся за 1 минуту через @BotFather).
  3. Токен бота (его даёт BotFather).
  4. chat_id — куда слать сообщения (это может быть личка, группа или канал).
  5. Обработчик формы на сервере (PHP-скрипт), который:
    • принимает поля из формы,
    • валидирует,
    • формирует красивое сообщение,
    • стучится в Telegram API sendMessage,
    • отдаёт пользователю понятный ответ.

Шаг 1. Создать бота и получить токен

Открой https://telegram.me/botfather @BotFather → пропиши /newbot или нажми Open и в открывшимся окне нажми Create New Bot.

Придумай имя бота и @username. Username обязательно должен заканчиваться на _bot

Сохраним токен формата 123456789:AA.... Это “ключ” бота для отправки. Вскоре он нам понадобится.

Токен можно получить в любой момент достаточно зайти в чат @BotFather и написать команду /start и потом /token — далее выбрать из меню имя бота от которого нам нужен токен.

Шаг 2. Получить свой chat_id

После того, как мы создали Бота, зайдём с ним в переписку нажав на его имя в переписке с @BotFather и нажмём кнопку Start — либо же пропишем команду /start
дополнительно, напишите любой текст в чате со своим новым ботом, например: привет

Далее добавляем бота в чат. Чтобы это сделать, нужно добавить нашего бота в уже имеющийся чат/канал, либо создать новый чат/канал с нуля и добавить туда нашего бота. В чате Бота нужно назначить администратором.

Далее, напишите пару сообщений в свой чат/канал куда добавили бота — без разницы что. Их можно будет удалить.

Когда вы предоставите права администратора боту в канале/чате, у него появится надпись, что он имеет доступ к сообщениям.

Затем, копируем следующую ссылку и подготовляем ваш токен бота, который мы сохранили до этого.

https://api.telegram.org/bot<Токен вашего бота>/getUpdates

<Токен вашего бота> — вместо этого подставляем ваш токен. Если вы видите только надпись {«ok»:true,»result»:[]} — ничего страшного, просто подождите. Можете написать ещё что-нибудь в свой чат или канал, куда мы добавили нового бота.

Нас интересует значение рядом с ID которая начинается с минуса и содержит 13 символов. Копируем его.

Теперь у нас есть наш token и чат id.

Шаг 3. HTML-форма на лендинге

В нашей форме есть несколько полей и прикрепление фотографии или файла.

Пример формы с картинки выше
<form class="form_upload2" action="mail.php" method="post" enctype="multipart/form-data"> 
		  <input type="hidden" name="ajax" value="1">

            <div class="prilouder">
              <svg viewBox="0 0 417 325" xmlns="http://www.w3.org/2000/svg">
                <path d="M159.677 318.278C155.696 322.282 150.266 324.516 144.624 324.516C138.983 324.516 133.552 322.282 129.571 318.278L9.35675 198.044C-3.11892 185.568 -3.11892 165.338 9.35675 152.886L24.4094 137.829C36.889 125.354 57.0957 125.354 69.5713 137.829L144.624 212.886L347.428 10.0784C359.907 -2.39724 380.134 -2.39724 392.59 10.0784L407.642 25.135C420.118 37.6107 420.118 57.8368 407.642 70.293L159.677 318.278Z"></path>
              </svg>
            </div>
            <div class="input_container">     
              <h3>закажите новую мебель у нас по цене на 15% ниже рыночной</h3>
              <div class="input_box"> 
                <label for="vid2">Вид мебели </label>
                <select id="vid2" name="Вид мебели"> 
                  <option>Угловой диван (сложной формы)</option>
                  <option>Угловой диван (еврокнига)</option>
                  <option>Кухонный уголок или диван</option>
                  <option>Диван-аккордеон</option>
                  <option>Диван-аккордеон (цельный чехол)</option>
                  <option>Кресло</option>
                  <option>Кресло-кровать</option>
                  <option>Диван-двойка, широкое кресло</option>
                  <option>Стул (со спинкой, кухонный, офисный)</option>
                  <option>Пуфик</option>
                  <option>Тахта</option>
                </select>
              </div>
              <div class="input_box"> 
                <label for="material2">ВЫБЕРИТЕ материал</label>
                <select id="material2" name="Материал">   
                  <option>Искусственная кожа</option>
                  <option>Экокожа</option>
                  <option>Велюр</option>
                  <option>Флор</option>
                  <option>Жаккард</option>
                  <option>Шенилл</option>
                  <option>Рогожка</option>
                  <option>Не определился</option>
                </select>
              </div>
              <div class="input_box"> 
                <label for="phone2">Ваш номер телефона         </label>
                <input id="phone2" name="phone" placeholder="Ваш телефон" type="text" onkeyup="var yratext=/['a-zA-Zа-яА-Я',':;*&lt;&gt;!?']/; if(yratext.test(this.value)) this.value=''" required="">
              </div>
              <div class="input_box" style="margin-top: 0px;"> 
                <label for="file_v2">загрузите фото</label>
                <div class="file-upload2">
                  <label>
                    <input id="file_v2" type="file" name="file"><span id="file2">Выбрать файл </span>
                  </label>
                </div>
              </div>
              <div class="input_box textarea">            
                <label for="textarea">Описание</label>
                <textarea id="textarea" rows="4" name="Описание" type="text" placeholder="Описание" onkeyup="var yratext=/[':;*&lt;&gt;!?']/; if(yratext.test(this.value)) this.value=''" required></textarea>
              </div>
              <button class="button" type="submit">Рассчитать</button>
            </div>
          </form>

Реальность такова: нам нужны имена атрибутов инпутов, которые обработчик действительно ждёт. Часто это что-то вроде:

  • name — имя
  • phone — телефон
  • whatever — что угодно (опционально)

Главное: поля формы и ожидания в PHP должны совпадать по именам. Если на вашем сайте форма содержит поле name=»name» или name=»phone» — значит в нашем php-обработчике поля должны соответствовать.

Шаг 4. Что делает обработчик (смысловой алгоритм)

  1. Проверяет метод запроса (только POST).
  2. Забирает и чистит поля (trim, фильтры, базовая валидация).
  3. Проверяет “обязательные” поля (телефон).
  4. Склеивает сообщение для Telegram. Здесь важно:
    • Лаконичный, читаемый шаблон.
    • Выделяем жирным важное.
    • Каждое поле — с новой строки.
  5. Шлёт запрос в Telegram API:
    • sendMessage (текст), опционально — sendPhoto/sendDocument.
    • Передаёт chat_id, text, parse_mode=HTML.
  6. Разруливает ответ (успех/ошибка) и возвращает пользователю понятный фидбек:
    • Для классической формы — редирект на “спасибо-страницу”.
<?php
// ====== CONFIG ======
$BOT_TOKEN = 'СЮДА ВСТАВИТЬ ВАШ ТОКЕН';
$CHAT_ID   = 'СЮДА ВСТАВИТЬ ВАШ CHAT ID с - '; // пример: -1001234567990 для канала/группы
$THANK_URL = '/thank.html'; // перевод на страницу спасибо
$LOG_FILE  = __DIR__ . '/error.log';

// ====== УТИЛИТЫ ======
function log_error($msg){
  global $LOG_FILE;
  $line = '['.date('Y-m-d H:i:s')."] ".$msg."\n";
  @file_put_contents($LOG_FILE, $line, FILE_APPEND);
}
function is_ajax(){
  // фронт всегда шлёт ajax=1 и ждёт JSON
  return (isset($_POST['ajax']) && $_POST['ajax']=='1');
}
function resp_json($arr){
  header('Content-Type: application/json; charset=UTF-8');
  echo json_encode($arr, JSON_UNESCAPED_UNICODE);
  exit;
}
function tg_api($method, $data, $isMultipart=false){
  global $BOT_TOKEN;
  $url = "https://api.telegram.org/bot{$BOT_TOKEN}/{$method}";
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_POST, true);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_TIMEOUT, 20);
  if ($isMultipart){
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: multipart/form-data'));
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
  } else {
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
  }
  $res = curl_exec($ch);
  if ($res === false){
    $err = curl_error($ch);
    curl_close($ch);
    log_error("cURL error: ".$err);
    return array('ok'=>false, 'error'=>$err);
  }
  curl_close($ch);
  $j = json_decode($res, true);
  if (!$j || !isset($j['ok'])){
    log_error("Telegram bad response: ".$res);
    return array('ok'=>false, 'error'=>'bad_telegram_response');
  }
  return $j;
}

// ====== ТЕХНИЧЕСКИЕ ПРОВЕРКИ ======
if (isset($_GET['health'])) {
  // Простой ответ для проверки 200 ОК из браузера
  header('Content-Type: application/json; charset=UTF-8');
  echo json_encode(array('ok'=>true,'php'=>PHP_VERSION,'time'=>date('c')));
  exit;
}
if (isset($_GET['selftest'])) {
  // Лёгкий self-test: не шлём ничего в чат, просто показываем что скрипт жив
  header('Content-Type: application/json; charset=UTF-8');
  echo json_encode(array('ok'=>true,'curl'=>function_exists('curl_init'),'php'=>PHP_VERSION));
  exit;
}

// ====== СБОР ДАННЫХ ФОРМЫ ======
$name    = isset($_POST['name'])    ? trim($_POST['name'])    : '';
$phone   = isset($_POST['phone'])   ? trim($_POST['phone'])   : '';
$message = isset($_POST['message']) ? trim($_POST['message']) : ''; // если где-то есть

// Склеим ВСЕ поля (в т.ч. русские name вроде "Вид мебели", "Материал", чекбоксы и т.д.)
$lines = array();
foreach ($_POST as $k=>$v){
  if ($k==='ajax') continue;
  // Нормализуем массивы (на всякий случай)
  if (is_array($v)) { $v = implode(', ', $v); }
  $lines[] = $k.': '.$v;
}
if (!empty($_FILES['file']) && isset($_FILES['file']['name']) && $_FILES['file']['error']===UPLOAD_ERR_OK){
  $lines[] = 'Файл: '.$_FILES['file']['name'].' ('.$_FILES['file']['type'].', '.$_FILES['file']['size'].' байт)';
}

if ($phone===''){
  $msg = 'Ошибка: укажите телефон';
  if (is_ajax()) resp_json(array('success'=>false, 'message'=>$msg));
  header("HTTP/1.1 400 Bad Request"); echo $msg; exit;
}

// ====== ОТПРАВКА В TELEGRAM ======
$txt  = "🛠 <b>Новая заявка с сайта </b>\n";
$txt .= "📅 <b>Время:</b> " . date('d.m.Y H:i') . "\n\n";

// Сначала выведем телефон и имя отдельно, потом всё остальное
$phone_line = '';
$name_line  = '';
$other_lines = '';

foreach ($_POST as $k => $v) {
    if ($k === 'ajax') continue;
    if (is_array($v)) $v = implode(', ', $v);
    $v = trim($v);
    if ($v === '') continue;

    if (preg_match('/phone|тел/i', $k)) {
        $phone_line = "☎️ <b>Телефон:</b> " . htmlspecialchars($v, ENT_QUOTES, 'UTF-8') . "\n";
    } elseif (preg_match('/name|имя/i', $k)) {
        $name_line = "👤 <b>Имя:</b> " . htmlspecialchars($v, ENT_QUOTES, 'UTF-8') . "\n";
    } elseif (preg_match('/mail|почт/i', $k)) {
        $other_lines .= "📧 <b>Email:</b> " . htmlspecialchars($v, ENT_QUOTES, 'UTF-8') . "\n";
    } else {
        $other_lines .= "▫️ <b>" . htmlspecialchars($k, ENT_QUOTES, 'UTF-8') . ":</b> " . htmlspecialchars($v, ENT_QUOTES, 'UTF-8') . "\n";
    }
}

$txt .= $phone_line;
$txt .= $name_line;
$txt .= $other_lines;

if (!empty($_FILES['file']) && $_FILES['file']['error'] === UPLOAD_ERR_OK) {
    $txt .= "\n📎 <b>Файл прикреплён:</b> " . htmlspecialchars($_FILES['file']['name'], ENT_QUOTES, 'UTF-8');
}



$r1 = tg_api('sendMessage', array(
  'chat_id' => $CHAT_ID,
  'text'    => $txt,
  'parse_mode' => 'HTML'
));

if (empty($r1['ok'])){
  $msg = 'Не удалось отправить сообщение. Попробуйте позже.';
  log_error('sendMessage failed: '.json_encode($r1));
  if (is_ajax()) resp_json(array('success'=>false, 'message'=>$msg));
  header("HTTP/1.1 500 Internal Server Error"); echo $msg; exit;
}

// 2) Если есть файл — шлём как документ (универсально)
if (!empty($_FILES['file']) && $_FILES['file']['error']===UPLOAD_ERR_OK){
  $tmp  = $_FILES['file']['tmp_name'];
  $nameFile = $_FILES['file']['name'];
  $mime = !empty($_FILES['file']['type']) ? $_FILES['file']['type'] : 'application/octet-stream';

  // В PHP 5.6 используем CURLFile
  if (class_exists('CURLFile')) {
    $fileObj = new CURLFile($tmp, $mime, $nameFile);
  } else {
    // legacy формат — на очень старых сборках PHP/cURL
    $fileObj = '@'.$tmp.';filename='.$nameFile.';type='.$mime;
  }

  $cap = "Файл от: ".($name?:'—')."; Телефон: ".$phone;
  $r2 = tg_api('sendDocument', array(
    'chat_id'  => $CHAT_ID,
    'caption'  => $cap,
    'document' => $fileObj
  ), true);

  if (empty($r2['ok'])){
    log_error('sendDocument failed: '.json_encode($r2));
    // Не валим заявку — текст уже ушёл. Просто сообщим фронту «ок, но файл не приложился».
  }
}

// ====== ОТВЕТ ФРОНТУ ======
if (is_ajax()){
  resp_json(array('success'=>true, 'redirect'=>$THANK_URL));
} else {
  header('Location: '.$THANK_URL);
  exit;
}

Главное, чтобы у вас был создан файл mail.php и он же задан как обработчик формы через action=»mail.php» method=»post»

Cкопируйте и поставьте код выше в свой mail.php.
Ваши поля должны соответствовать заданным в этом файле.

Итог:

Специалист о контекстной рекламе и интернет-маркетинге | Яндекс Директ и Google Ads
Telegram Viber WhatsApp