Blog. Just Blog

Telegram-бот на PHP

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Web-мастеру и не только | Автор: ManHunter
Telegram-бот на PHP
Telegram-бот на PHP

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

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

Для того, чтобы серверный бот мог получать все сообщения и уведомления, первым делом надо зарегистрировать так называемый webhook, то есть указать ссылку на скрипт, куда Telegram будет отправлять все данные. Формируем ссылку вида:

https://api.telegram.org/bot[token]/setWebhook?url=https://вашсайт.ру/telebot.php
где [token] - это токен, полученный при регистрации бота. Например, для описанного ранее тестового бота ссылка будет вот такой:

https://api.telegram.org/bot629705209:AAFhFqFbhR3VHHrOgOM7R4OnQT-usqJwTBk/setWebhook?url=https://вашсайт.ру/telebot.php
Если все сделано правильно, то в браузере будет получен ответ:

{"ok":true,"result":true,"description":"Webhook was set"}
Telegram отправляет данные на указанный скрипт при помощи POST-запроса, формат передаваемых данных всегда JSON. Для удобства разбора полетов, особенно на первых этапах, лучше логировать все полученные данные куда-нибудь в файл. Каркас скрипта-приемника будет иметь следующий вид:
  1. $data=file_get_contents('php://input');
  2. if ($json=json_decode($datatrue)) {
  3.     if (isset($json['update_id'])) {
  4.         // $json - отправленные данные
  5.     }
  6.     else {
  7.         // Это точно не данные от Telegram
  8.         exit;
  9.     }
  10. }
  11. else {
  12.     // Получены некорректные данные
  13.     exit;
  14. }
Тут сразу же выполняется быстрая проверка на корректность полученных данных, после чего разобранный запрос помещается в массив $json. Обычно бот может получать текстовые данные, файлы или управляющие команды. Начнем с самого простого. Когда пользователь пишет в чат сообщение, то бот получит примерно такие данные:

Array (
  [update_id] => 434540657
  [message] => Array (
    [message_id] => 1702
    [from] => Array (
      [id] => 698237240
      [is_bot] =>
      [first_name] => Dmitry
      [language_code] => ru
    )
    [chat] => Array (
      [id] => 698237240
      [first_name] => Dmitry
      [type] => private
    )
    [date] => 1679039931
    [text] => Привет
  )
)

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

Бот может принимать управляющие команды, они начинаются с косой черты "/". Если Telegram распознает такую команду, то в этом случае в уведомлении будет присутствовать дополнительный блок, хотя в остальном оно ничем не отличается от обычного текстового сообщения.

Array (
  [update_id] => 434540657
  [message] => Array (
    [message_id] => 1702
    [from] => Array (
      [id] => 698237240
      [is_bot] =>
      [first_name] => Dmitry
      [language_code] => ru
    )
    [chat] => Array (
      [id] => 698237240
      [first_name] => Dmitry
      [type] => private
    )
    [date] => 1679039931
    [text] => /dosomething
    [entities] => Array (
      [0] => Array (
        [offset] => 0
        [length] => 12
        [type] => bot_command
      )
    )
  )
)

Тут указывается, с какой позиции сообщения начинается управляющая команда и какой она длины. Реакция на ту или иную команду, естественно, остается на совести разработчика бота. Пользователь может передавать несколько команд в одном сообщении, даже перемежая их текстом. Telegram поможет их определить и для каждой команды передаст ее позицию в отправленном сообщении и длину.

Array (
  [update_id] => 434540657
  [message] => Array (
    [message_id] => 1702
    [from] => Array (
      [id] => 698237240
      [is_bot] =>
      [first_name] => Dmitry
      [language_code] => ru
    )
    [chat] => Array (
      [id] => 698237240
      [first_name] => Dmitry
      [type] => private
    )
    [date] => 1679039931
    [text] => Yo, bota! /krush /kill and /destroy
    [entities] => Array (
      [0] => Array (
        [offset] => 10
        [length] => 6
        [type] => bot_command
      )
      [1] => Array (
        [offset] => 17
        [length] => 5
        [type] => bot_command
      )
      [2] => Array (
        [offset] => 27
        [length] => 8
        [type] => bot_command
      )
    )
  )
)

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

Array (
  [update_id] => 434540657
  [message] => Array (
    [message_id] => 1702
    [from] => Array (
      [id] => 698237240
      [is_bot] =>
      [first_name] => Dmitry
      [language_code] => ru
    )
    [chat] => Array (
      [id] => 698237240
      [first_name] => Dmitry
      [type] => private
    )
    [date] => 1679039931
    [photo] => Array (
      [0] => Array (
        [file_id] => AgAAAAAA1111111222222444zF-06666667777DDDDD
        [file_unique_id] => AQ111111111111h4
        [file_size] => 1575
        [width] => 55
        [height] => 90
      )
      [1] => Array (
        [file_id] => AgAAAAAA1111111222222444zF-06666667777CCCCC
        [file_unique_id] => AQ111111111111hy
        [file_size] => 23882
        [width] => 197
        [height] => 320
      )
      [2] => Array (
        [file_id] => AgAAAAAA1111111222222444zF-06666667777BBBBB
        [file_unique_id] => AQ111111111111h9
        [file_size] => 99568
        [width] => 493
        [height] => 800
      )
      [3] => Array (
        [file_id] => AgAAAAAA1111111222222444zF-06666667777AAAAA
        [file_unique_id] => AQ111111111111h-
        [file_size] => 175335
        [width] => 789
        [height] => 1280
      )
    )
  )
)

Как видите, Telegram и тут позаботился о web-мастере, передавая не только оригинальное изображение, но и подготовив аж три превьюшки разного размера. Сам файл получается в два этапа. Сперва надо определить, какой из четырех файлов нам нужен, они отличаются по полю file_id. Допустим, превьюшки нас не интересуют, поэтому просто берем последний элемент массива и получаем информацию о загруженном файле, используя его идентификатор.
  1. // Токен бота
  2. $token='629705209:AAFhFqFbhR3VHHrOgOM7R4OnQT-usqJwTBk'
  3.  
  4. $photo=array_pop($json['message']['photo']);
  5.  
  6. $ch=curl_init();
  7. curl_setopt($chCURLOPT_URL'https://api.telegram.org/bot'.$token.'/getFile');
  8. curl_setopt($chCURLOPT_POSTTRUE);
  9. curl_setopt($chCURLOPT_POSTFIELDS'file_id='.$photo['file_id']);
  10. curl_setopt($chCURLOPT_RETURNTRANSFERTRUE);
  11. curl_setopt($chCURLOPT_HEADERFALSE);
  12. curl_setopt($chCURLOPT_SSL_VERIFYPEERFALSE);
  13. $result=curl_exec($ch);
  14. curl_close($ch);
  15.  
  16. $json=json_decode($result,true);
Если все сделано правильно, то будет получен ответ примерно такого содержания:

Array (
  [ok] => 1
  [result] => Array (
    [file_id] => AgAAAAAA1111111222222444zF-06666667777AAAAA
    [file_unique_id] => AQ111111111111h-
    [file_size] => 175335
    [file_path] => photos/file_0.jpg
  )
)

Только теперь, получив имя файла, можно загрузить его содержимое с сервера Telegram. Код будет примерно таким:
  1. $ch=curl_init();
  2. curl_setopt($chCURLOPT_URL,
  3.      'https://api.telegram.org/file/bot'.$token.'/'.$json['result']['file_path']);
  4. curl_setopt($chCURLOPT_POSTFALSE);
  5. curl_setopt($chCURLOPT_RETURNTRANSFERTRUE);
  6. curl_setopt($chCURLOPT_HEADERFALSE);
  7. curl_setopt($chCURLOPT_SSL_VERIFYPEERFALSE);
  8. $source=curl_exec($ch);
  9. curl_close($ch);
  10.  
  11. // $source - содержимое файла
Есть большой соблазн вообще пропустить предыдущий шаг, так как массив изображений формируется только для файлов в формате JPEG, а оригинальная картинка всегда хранится по пути photos/file_0.jpg. Но стопроцентной гарантии у меня нет, поэтому оставлю это на ваше усмотрение.

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

Array (
  [update_id] => 434540657
  [message] => Array (
    [message_id] => 1702
    [from] => Array (
      [id] => 698237240
      [is_bot] =>
      [first_name] => Dmitry
      [language_code] => ru
    )
    [chat] => Array (
      [id] => 698237240
      [first_name] => Dmitry
      [type] => private
    )
    [date] => 1679039931
    [document] => Array (
      [file_name] => my_image.png
      [mime_type] => image/png
      [thumbnail] => Array (
        [file_id] => AgAAAAAA1111111222222444zF-06666667777CCCCC
        [file_unique_id] => AQ111111111111hA
        [file_size] => 25093
        [width] => 320
        [height] => 282
      )
      [thumb] => Array (
        [file_id] => AgAAAAAA1111111222222444zF-06666667777BBBBB
        [file_unique_id] => AQ111111111111hB
        [file_size] => 25093
        [width] => 320
        [height] => 282
      )
      [file_id] => AgAAAAAA1111111222222444zF-06666667777AAAAA
      [file_unique_id] => AQ111111111111hC
      [file_size] => 33560
    )
  )
)

Остальные документы считаются бинарными файлами и передаются как есть.

Array (
  [update_id] => 434540657
  [message] => Array (
    [message_id] => 1702
    [from] => Array (
      [id] => 698237240
      [is_bot] =>
      [first_name] => Dmitry
      [language_code] => ru
    )
    [chat] => Array (
      [id] => 698237240
      [first_name] => Dmitry
      [type] => private
    )
    [date] => 1679039931
    [document] => Array (
      [file_name] => my_book.fb2
      [mime_type] => application/octet-stream
      [file_id] => AgAAAAAA1111111222222444zF-06666667777AAAAA
      [file_unique_id] => AQ111111111111hC
      [file_size] => 1236900
    )
  )
)

Содержимое файла получается точно так же в два захода. И вот тут от получения информации о файле уже не отвертеться.
  1. // Токен бота
  2. $token='629705209:AAFhFqFbhR3VHHrOgOM7R4OnQT-usqJwTBk'
  3.  
  4. $ch=curl_init();
  5. curl_setopt($chCURLOPT_URL'https://api.telegram.org/bot'.$token.'/getFile');
  6. curl_setopt($chCURLOPT_POSTTRUE);
  7. curl_setopt($chCURLOPT_POSTFIELDS,
  8.     'file_id='.$json['message']['document']['file_id']);
  9. curl_setopt($chCURLOPT_RETURNTRANSFERTRUE);
  10. curl_setopt($chCURLOPT_HEADERFALSE);
  11. curl_setopt($chCURLOPT_SSL_VERIFYPEERFALSE);
  12. $result=curl_exec($ch);
  13.  
  14. $json=json_decode($result,true);
  15.  
  16. curl_setopt($chCURLOPT_URL,
  17.     'https://api.telegram.org/file/bot'.$token.'/'.$json['result']['file_path']);
  18. curl_setopt($chCURLOPT_POSTFALSE);
  19. $source=curl_exec($ch);
  20. curl_close($ch);
  21.  
  22. // $source - содержимое файла
Дальше содержимое файла записывается на диск или используется по иному назначению. Хорошим тоном будет уведомить пользователя о факте успешного получения файла и о действии, которое с этим файлом было выполнено.

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

Отправка изображения
Отправка изображения
  1. // Подготовить локальный файл для отправки
  2. $file=__DIR__.'/original.jpg';
  3.  
  4. if (function_exists('curl_file_create')) {
  5.     $attachment=curl_file_create($file);
  6. }
  7. else {
  8.     $info=pathinfo($file);
  9.     $attachment='@'.realpath($file).';filename='.$info['basename'].
  10.              ';type='.mime_content_type($file);
  11. }
  12.  
  13. $query=array(
  14.     'chat_id'=>$chat_id,
  15.     'photo'=>$attachment,
  16.     'caption'=>'Тестовая картинка',
  17. );
  18.  
  19. $ch=curl_init();
  20. curl_setopt($chCURLOPT_URL,
  21.     'https://api.telegram.org/bot'.$token.'/sendPhoto');
  22. curl_setopt($chCURLOPT_RETURNTRANSFERtrue);
  23. curl_setopt($chCURLOPT_HEADERfalse);
  24. curl_setopt($chCURLOPT_SSL_VERIFYPEERfalse);
  25. curl_setopt($chCURLOPT_POSTtrue);
  26. curl_setopt($chCURLOPT_POSTFIELDS$query);
  27. $result=curl_exec($ch);
  28. curl_close($ch);
Для формирования объекта файла проверяется доступность функции cURL, так как функция curl_file_create отсутствует в старых версиях PHP. Для таких случаев создание объекта отправляемого файла выполняется в "ручном" режиме.

Отправка документа выполняется почти так же, только меняется название ключа массива и ссылка API.

Отправка документа
Отправка документа

Отправка документа
Отправка документа
  1. // Подготовить локальный файл для отправки
  2. $file=__DIR__.'/example.xls';
  3.  
  4. if (function_exists('curl_file_create')) {
  5.     $attachment=curl_file_create($file);
  6. }
  7. else {
  8.     $info=pathinfo($file);
  9.     $attachment='@'.realpath($file).';filename='.$info['basename'].
  10.              ';type='.mime_content_type($file);
  11. }
  12.  
  13. $query=array(
  14.     'chat_id'=>$chat_id,
  15.     'document'=>$attachment,
  16.     'caption'=>'Тестовый документ',
  17. );
  18.  
  19. $ch=curl_init();
  20. curl_setopt($chCURLOPT_URL,
  21.     'https://api.telegram.org/bot'.$token.'/sendDocument');
  22. curl_setopt($chCURLOPT_RETURNTRANSFERtrue);
  23. curl_setopt($chCURLOPT_HEADERfalse);
  24. curl_setopt($chCURLOPT_SSL_VERIFYPEERfalse);
  25. curl_setopt($chCURLOPT_POSTtrue);
  26. curl_setopt($chCURLOPT_POSTFIELDS$query);
  27. $result=curl_exec($ch);
  28. curl_close($ch);
По аналогии отправляются аудиофайлы, вынесенные от документов в отдельную категорию.

Отправка аудио
Отправка аудио
  1. // Подготовить локальный файл для отправки
  2. $file=__DIR__.'/example.mp3';
  3.  
  4. if (function_exists('curl_file_create')) {
  5.     $attachment=curl_file_create($file);
  6. }
  7. else {
  8.     $info=pathinfo($file);
  9.     $attachment='@'.realpath($file).';filename='.$info['basename'].
  10.              ';type='.mime_content_type($file);
  11. }
  12.  
  13. $query=array(
  14.     'chat_id'=>$chat_id,
  15.     'audio'=>$attachment,
  16.     'caption'=>'Тестовая песенка',
  17. );
  18.  
  19. $ch=curl_init();
  20. curl_setopt($chCURLOPT_URL,
  21.     'https://api.telegram.org/bot'.$token.'/sendAudio');
  22. curl_setopt($chCURLOPT_RETURNTRANSFERtrue);
  23. curl_setopt($chCURLOPT_HEADERfalse);
  24. curl_setopt($chCURLOPT_SSL_VERIFYPEERfalse);
  25. curl_setopt($chCURLOPT_POSTtrue);
  26. curl_setopt($chCURLOPT_POSTFIELDS$query);
  27. $result=curl_exec($ch);
  28. curl_close($ch);
Отправку всяких стикеров, контактов и прочего смотрите в официальной документации, там ничего сложного.

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

Первый тип клавиатуры - inline-клавиатура, которая прикрепляется к конкретному сообщению. Как правило в ней содержится список действий, которые связаны с этим сообщением, например, переход по ссылке или открытие конкретной карточки товара. Для отправки такой клавиатуры надо сперва сформировать массив с кнопками, которые будут прикреплены к сообщению, а затем передать его в параметре reply_markup.

Пример inline-клавиатуры
Пример inline-клавиатуры
  1. $keyboard=array(
  2.     "resize_keyboard"=>true,
  3.     "inline_keyboard"=>array(
  4.         // Первая строка кнопок
  5.         array(
  6.             array(
  7.                 'text' => 'Перейти на сайт www.manhunter.ru',
  8.                 'url'=>'https://www.manhunter.ru',
  9.             ),
  10.         ),
  11.         // Вторая строка кнопок
  12.         array(
  13.             array(
  14.                 'text' => 'Привет!',
  15.                 'callback_data'=>'Нажата внопка 1'
  16.             ),
  17.             array(
  18.                 'text' => 'До свидания!',
  19.                 'callback_data'=>'Нажата внопка 2'
  20.             ),
  21.         ),
  22.     ),
  23. );
  24.  
  25. $text='Вот такие кнопки. Попробуй их все!';
  26.  
  27. $ch=curl_init();
  28. curl_setopt($chCURLOPT_URL,
  29.     'https://api.telegram.org/bot'.$token.'/sendMessage');
  30. curl_setopt($chCURLOPT_RETURNTRANSFERtrue);
  31. curl_setopt($chCURLOPT_HEADERfalse);
  32. curl_setopt($chCURLOPT_SSL_VERIFYPEERfalse);
  33. curl_setopt($chCURLOPT_POSTtrue);
  34. curl_setopt($chCURLOPT_POSTFIELDS,
  35.     'chat_id='.$chat_id.'&text='.rawurlencode($text).
  36.     '&reply_markup='.json_encode($keyboard));
  37. curl_setopt($chCURLOPT_CONNECTTIMEOUT10);
  38. $result=curl_exec($ch);
Кнопки могут быть расположены в несколько строчек, а в качестве параметров указывается ссылка или строка с описанием действия, которое будет передано на ваш обработчик. При нажатии на кнопку-ссылку Telegram спросит подтверждение на переход, а при нажатии на кнопку-действие ваш обработчик получит примерно такие уведомление:

Array (
  [update_id] => 434540657
  [callback_query] => Array (
    [id] => 1111222223333344444
    [from] => Array (
      [id] => 698237240
      [is_bot] =>
      [first_name] => Dmitry
      [language_code] => ru
    )
    [message] => Array (
      [message_id] => 74
      [from] => Array (
        [id] => 1112223445
        [is_bot] => 1
        [first_name] => MySupaTestBot
        [username] => MySupaTestBot_bot
      )
      [chat] => Array (
        [id] => 698237240
        [first_name] => Dmitry
        [type] => private
      )
      [date] => 1679227556
      [text] => Вот такие кнопки. Попробуй их все!
      [reply_markup] => Array (
        [inline_keyboard] => Array (
          [0] => Array (
            [0] => Array (
              [text] => Перейти на сайт
              [url] => https://www.manhunter.ru/
            )
          )
          [1] => Array (
            [0] => Array (
              [text] => Привет
              [callback_data] => Нажата внопка 1
            )
            [1] => Array (
              [text] => До свидания
              [callback_data] => Нажата внопка 2
            )
          )
        )
      )
    )
    [chat_instance] => -123456789081123230
    [data] => Нажата внопка 1
  )
)

После отправки callback-сообщения клиент Telegram переходит в режим ожидания ответа, при этом на нажатой кнопке появляется значок часиков. Если в течение определенного времени ответ от серверного обработчика не получен, то значок часиков пропадает. Но хорошей практикой будет отправлять из обработчика ответ на callback-сообщения с помощью метода answerCallbackQuery. В этом случае для идентификации получателя используется поле ['callback_query']['id'].
  1. $callback_id=$json['callback_query']['id'];
  2.  
  3. $text='';
  4.  
  5. $ch=curl_init();
  6. curl_setopt($chCURLOPT_URL,
  7.     'https://api.telegram.org/bot'.$token.'/answerCallbackQuery');
  8. curl_setopt($chCURLOPT_RETURNTRANSFERtrue);
  9. curl_setopt($chCURLOPT_HEADERfalse);
  10. curl_setopt($chCURLOPT_SSL_VERIFYPEERfalse);
  11. curl_setopt($chCURLOPT_POSTtrue);
  12. curl_setopt($chCURLOPT_POSTFIELDS,
  13.     'callback_query_id='.$callback_id.'&text='.rawurlencode($text));
  14. curl_setopt($chCURLOPT_CONNECTTIMEOUT10);
  15. $result=curl_exec($ch);
Текст ответа появится в виде всплывающего сообщения, если текст пустой, то клиент просто вернется из режима ожидания ответа в обычный режим работы. Показ сообщения также регулируется параметром show_alert. В зависимости от задачи, вместо показа сообщения можно передать параметр url, в этом случае клиент выполнит команду "открыть сылку".

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

Пример обычной клавиатуры
Пример обычной клавиатуры
  1. $keyboard=array(
  2.     "resize_keyboard"=>true,
  3.     "keyboard"=>array(
  4.         array(
  5.             array(
  6.                 'text' => 'Всем привет!',
  7.             ),
  8.             array(
  9.                 'text' => 'До свидания!',
  10.             ),
  11.         ),
  12.     ),
  13. );
  14.  
  15. $text='Вот такие кнопки. Попробуй их все!';
  16.  
  17. $ch=curl_init();
  18. curl_setopt($chCURLOPT_URL,
  19.     'https://api.telegram.org/bot'.$token.'/sendMessage');
  20. curl_setopt($chCURLOPT_RETURNTRANSFERtrue);
  21. curl_setopt($chCURLOPT_HEADERfalse);
  22. curl_setopt($chCURLOPT_SSL_VERIFYPEERfalse);
  23. curl_setopt($chCURLOPT_POSTtrue);
  24. curl_setopt($chCURLOPT_POSTFIELDS,
  25.     'chat_id='.$chat_id.'&text='.rawurlencode($text).
  26.     '&reply_markup='.json_encode($keyboard));
  27. curl_setopt($chCURLOPT_CONNECTTIMEOUT10);
  28. $result=curl_exec($ch);
При нажатиии таких кнопок серверному обработчику, соответственно, приходят самые обычные уведомления, как будто пользователь набрал их на клавиатуре.

Через @BotFather можно задавать список команд бота. Он появится в меню команд при нажатии кнопки рядом с полем ввода. Но можно сделать это и программно, например, сразу после старта бота.

Меню команд бота
Меню команд бота
  1. $commands=array(
  2.     array(
  3.         'command'=>'start',
  4.         'description'=>'Запуск бота'
  5.     ),
  6.     array(
  7.         'command'=>'monster',
  8.         'description'=>'Монстр дня'
  9.     ),
  10.     array(
  11.         'command'=>'crossword',
  12.         'description'=>'Кроссворд'
  13.     ),
  14.     array(
  15.         'command'=>'coupon',
  16.         'description'=>'Купон'
  17.     ),
  18. );
  19.  
  20. $query=array(
  21.     'commands'=>json_encode($commands),
  22. );
  23.  
  24. $ch=curl_init();
  25. curl_setopt($chCURLOPT_URL,
  26.     'https://api.telegram.org/bot'.$token.'/setMyCommands');
  27. curl_setopt($chCURLOPT_RETURNTRANSFERtrue);
  28. curl_setopt($chCURLOPT_HEADERfalse);
  29. curl_setopt($chCURLOPT_SSL_VERIFYPEERfalse);
  30. curl_setopt($chCURLOPT_POSTtrue);
  31. curl_setopt($chCURLOPT_POSTFIELDS$query);
  32. curl_setopt($chCURLOPT_CONNECTTIMEOUT10);
  33. $result=curl_exec($ch);
  34. curl_close($ch);
Как и в предыдущем случае, на сервер отправится управляющая команда, как будто ее набрали с клавиатуры. Количество команд в списке не должно быть больше 100.

И напоследок буквально пару слов об оформлении сообщений, которые бот отправляет пользователю. Чтобы определенный фрагмент текста можно было скопировать одним нажатием, его надо оформить тегами <code> и дополнить список полей отправки параметром parse_mode=HTML.
  1. $text='Длинный текст, <code>а этот фрагмент можно копировать</code>, и еще текст';
  2. $ch=curl_init();
  3. curl_setopt($chCURLOPT_URL,
  4.     'https://api.telegram.org/bot'.$token.'/sendMessage');
  5. curl_setopt($chCURLOPT_RETURNTRANSFERtrue);
  6. curl_setopt($chCURLOPT_HEADERfalse);
  7. curl_setopt($chCURLOPT_SSL_VERIFYPEERfalse);
  8. curl_setopt($chCURLOPT_POSTtrue);
  9. curl_setopt($chCURLOPT_POSTFIELDS,
  10.     'chat_id='.$chat_id.'&text='.rawurlencode($text).'&parse_mode=HTML');
  11. curl_setopt($chCURLOPT_CONNECTTIMEOUT10);
  12. $result=curl_exec($ch);
  13. curl_close($ch);
По умолчанию Telegram не позволяет вставлять изображения в текст сообщений. Это частично можно обойти, сформировав сообщение особым образом, указав ссылку на картинку с пустым текстом ссылки и добавив еще один параметр disable_web_page_preview=false в отправляемые данные.

Изображение в сообщении
Изображение в сообщении

В этом случае превью изображения будет расположено сразу под текстом, независимо, где оно находилось в оригинале. И такая превьюшка в сообщении может быть только одна. Что ж, это лучше, чем ничего.
  1. $text='Посмотрите, какая картинка есть у нас ';
  2. $text.='<a href="https://вашсайт.ру/image.jpg">&#8205;</a>';
  3. $text.='Вам нравится?';
  4.  
  5. $ch=curl_init();
  6. curl_setopt($chCURLOPT_URL,
  7.     'https://api.telegram.org/bot'.$token.'/sendMessage');
  8. curl_setopt($chCURLOPT_RETURNTRANSFERtrue);
  9. curl_setopt($chCURLOPT_HEADERfalse);
  10. curl_setopt($chCURLOPT_SSL_VERIFYPEERfalse);
  11. curl_setopt($chCURLOPT_POSTtrue);
  12. curl_setopt($chCURLOPT_POSTFIELDS,
  13.     'chat_id='.$chat_id.'&text='.rawurlencode($text).
  14.     '&disable_web_page_preview=false&parse_mode=HTML');
  15. curl_setopt($chCURLOPT_CONNECTTIMEOUT10);
  16. $result=curl_exec($ch);
  17. curl_close($ch);
Еще один часто используемый вариант оформления постов - большой текст в качестве подписи к изображению. В этом случае картинка будет сверху, а под ней, например, рекламный текст. Длина подписи к картинке, а, следовательно, и текста поста, не должна превышать 1024 символа. Обычный текст сообщения к фото добавлять нельзя.

Текст в подписи и inline-клавиатура
Текст в подписи и inline-клавиатура

Пост можно дополнить инлайновыми кнопками-ссылками, украсить иконками эмодзи, главное во всем знать меру. Код для отправки будет следующим:
  1. $keyboard=array(
  2.     "resize_keyboard"=>true,
  3.     "inline_keyboard"=>array(
  4.         array(
  5.             array(
  6.                 'text' => 'Перейти на сайт www.manhunter.ru',
  7.                 'url'=>'https://www.manhunter.ru',
  8.             ),
  9.         ),
  10.     ),
  11. );
  12.  
  13. // Подготовить локальный файл для отправки
  14. $file=__DIR__.'/example.jpg';
  15.  
  16. if (function_exists('curl_file_create')) {
  17.     $attachment=curl_file_create($file);
  18. }
  19. else {
  20.     $info=pathinfo($file);
  21.     $attachment='@'.realpath($file).';filename='.$info['basename'].
  22.              ';type='.mime_content_type($file);
  23. }
  24.  
  25. $query=array(
  26.     'chat_id'=>$chat_id,
  27.     'photo'=>$attachment,
  28.     'caption'=>'Новинка! Распродажа!'."\n".
  29.                'Только сейчас и только у нас!'."\n".
  30.                'Налетай, торопись, покупай живопись!',
  31.     'reply_markup'=>json_encode($keyboard),
  32. );
  33.  
  34. $ch=curl_init();
  35. curl_setopt($chCURLOPT_URL,
  36.     'https://api.telegram.org/bot'.$token.'/sendPhoto');
  37. curl_setopt($chCURLOPT_RETURNTRANSFERtrue);
  38. curl_setopt($chCURLOPT_HEADERfalse);
  39. curl_setopt($chCURLOPT_SSL_VERIFYPEERfalse);
  40. curl_setopt($chCURLOPT_POSTtrue);
  41. curl_setopt($chCURLOPT_POSTFIELDS$query);
  42. $result=curl_exec($ch);
  43. curl_close($ch);
Также очень эффектно смотрится группа картинок и/или видео, отправленные одним сообщением. Максимальное количество медиафайлов в одном сообщении не должно превышать 10 штук. Для отправки группы картинок используется метод sendMediaGroup.

Отправка группы картинок
Отправка группы картинок

Локальные файлы для отправки готовятся следующим образом. Обратите внимание, что если требуется общий сопроводительный текст для группы, то он прописывается в описании первого элемента. В противном случае текст описания будет виден только при открытии на просмотр каждой отдельной картинки или видео.
  1. // Подготовить локальные файлы для отправки
  2. $file1=__DIR__.'/original_3.jpg';
  3. $file2=__DIR__.'/original_2.jpg';
  4. $file3=__DIR__.'/original_1.jpg';
  5.  
  6. if (function_exists('curl_file_create')) {
  7.     $attachment1=curl_file_create($file1);
  8.     $attachment2=curl_file_create($file2);
  9.     $attachment3=curl_file_create($file3);
  10. }
  11. else {
  12.     $info=pathinfo($file1);
  13.     $attachment1='@'.realpath($file1).';filename='.$info['basename'].
  14.                 ';type='.mime_content_type($file1);
  15.     $info=pathinfo($file2);
  16.     $attachment2='@'.realpath($file2).';filename='.$info['basename'].
  17.                 ';type='.mime_content_type($file2);
  18.     $info=pathinfo($file3);
  19.     $attachment3='@'.realpath($file3).';filename='.$info['basename'].
  20.                 ';type='.mime_content_type($file3);
  21. }
  22.  
  23. $query=array(
  24.     'chat_id'=>$chat_id,
  25.     'media'=>json_encode(array(
  26.         array(
  27.             'type'=>'photo',
  28.             'media'=>'attach://attach_1',
  29.             'caption'=>'Группа картинок',
  30.         ),
  31.         array(
  32.             'type'=>'photo',
  33.             'media'=>'attach://attach_2',
  34.         ),
  35.         array(
  36.             'type'=>'photo',
  37.             'media'=>'attach://attach_3',
  38.         ),
  39.     )),
  40.     'attach_1'=>$attachment1,
  41.     'attach_2'=>$attachment2,
  42.     'attach_3'=>$attachment3,
  43. );
  44.  
  45. $ch=curl_init();
  46. curl_setopt($chCURLOPT_URL,
  47.         'https://api.telegram.org/bot'.$token.'/sendMediaGroup');
  48. curl_setopt($chCURLOPT_RETURNTRANSFERtrue);
  49. curl_setopt($chCURLOPT_HEADERfalse);
  50. curl_setopt($chCURLOPT_SSL_VERIFYPEERfalse);
  51. curl_setopt($chCURLOPT_POSTtrue);
  52. curl_setopt($chCURLOPT_POSTFIELDS$query);
  53. $result=curl_exec($ch);
  54. curl_close($ch);
Важное замечание. На любой запрос вашему боту от API Telegram нужно возвращать ответ с кодом 200. В противном случае сообщение будет считаться не принятым и Telegram будет раз в минуту слать повторы на адрес вашего webhook'a.

Комбинируя описанные тут методы приема и отправки сообщений разного типа, вы можете написать собственного Telegram-бота с нужным функционалом. В очередной раз скажу, что перечисленными функциями возможности Telegram-ботов не ограничиваются. Изучайте документацию, смотрите примеры, пробуйте и у вас все получится.

Поделиться ссылкой ВКонтакте
Просмотров: 5135 | Комментариев: 11

Метки: PHP, Telegram
Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
morgot (08.10.2023 в 17:57):
ManHunter, это все сложная тема, по работе и т.д. За статью спасибо еще раз.
Единственное - мне пришлось добавить mb_convert_encoding("тут сообщение на русском",'UTF-8')); - т.к. почему-то телеграм ругался на "Bad Request: strings must be encoded in UTF-8"". Хотя сам файл скрипта был в кодировке утф-8, ну да ладно, не суть.
ManHunter (07.10.2023 в 23:31):
Цитатане знаю, сидишь ли где-то, видел только на кряклабе

Нигде больше не сижу, на свой сайт с трудом времени хватает
morgot (04.10.2023 в 23:51):
ManHunter, да сейчас везде такой подход. Взять любой форум по кодингу или тот же хабр (не знаю, сидишь ли где-то, видел только на кряклабе). Нельзя самому делать гуи, есть QT/Electron. Нельзя самому закодить простейшую анимацию или там ajax - бери Vue/React. И с РНР аналогично - везде composer, фреймворки. Кодить никто с нуля не умеет, все ищут либы чтобы сделать то или это. А потом еще случаются истории, как с node-ipc.
ManHunter (04.10.2023 в 23:36):
Ха, а мне тут совсем недавно выкатили, что так ботов писать нельзя, надо взять готовую библиотеку и все.
morgot (04.10.2023 в 23:15):
Спасибо. Единственное, наверное, на весь инет нормальное руководство - чистый процедурный код.  А то везде ООП, композер, симфони и подобный гуан. Вообще, РНР последние годы стал какой-то монструозной джавой, где для хелловорлда надо написать 20 строк и вызвать 120 зависимостей.
ManHunter (04.05.2023 в 13:08):
Добавил в статью информацию про answerCallbackQuery, про список команд, подкорректировал код создания объектов отправляемых файлов.
ManHunter (22.03.2023 в 21:35):
С чего вдруг такая забота?
Petya (22.03.2023 в 19:24):
Я надеюсь, токены бота в статье липовые приведены?
ManHunter (20.03.2023 в 09:53):
ЦитатаЕсли не секрет, какую мобилу юзаете?

У меня их две: Huawei P30 и Huawei P30 Pro

master-ufa, разместить скрипт-приемник можно на любом ресурсе, который доступен извне по https. Оптимально это свой сайт или сервер, зависит от задачи. У меня скрипт залит на этот сайт, по уведомлениям о разных событиях я одним нажатием нужной кнопки мгновенно выполняю нужное действие. И не важно, где я нахожусь, не надо лезть в комп, открывать браузер, заходить в админку и все такое.
Скрипт для отправки может работать вообще хоть откуда, лишь бы был исходящий интернет.
nordpoint (20.03.2023 в 09:46):
Спасибо за труды! Если не секрет, какую мобилу юзаете?
master-ufa (20.03.2023 в 08:56):
Вчера только решил изучить телеграм-бота, а тут уже все расписано. СПАСИБО. Один только вопрос: где можно разместить Скрипт?
1. На домашнем компьютере который постоянно включен?
2. Если на "мойсайт.ру", то в каком месте?
3. В самом Телеграмм есть возможность?
4. Какие надежные сторонние сервисы для размещения Вы используете?

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2024
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.13 сек. / MySQL: 2 (0.038 сек.) / Память: 4.5 Mb
Наверх