Telegram бот на PHP пошаговая инструкция

Разработка telegram бота на php

Предисловие

У меня появилась необходимость создать telegram бота на php, так как это один из основных языков, который я использую в своих разработках. Безусловно, для этого есть большие библиотеки, например на github, среди них есть достаточно хорошие, но часть из них либо плохо, либо вообще не документированы. Также сложности возникают, когда нужно немного поменять или добавить функционал, необходимо изучить десятки файлов, устранять возникающие ошибки, когда нужно просто добавить кнопку. Для простых действий можно вполне обойтись библиотекой Guzzle, для удобства построения запросов, вместо стандартного CURL, так как telegram API просто обрабатывает запросы в формате JSON и возвращает результат, как и многие другие API.

Скачать исходники, описанные ниже, можно в конце статьи.

Все запросы к telegram API обрабатываются следующим образом, это всего лишь запрос на адрес: https://api.telegram.org/bot/METHOD_NAME. Где после bot подставляется полученный от @BotFather токен, затем /название_метода. Ссылка на оф. сайт, с описанием всех методов telegram API https://core.telegram.org/bots/api#available-methods

Вариант описанный в данной статье подойдет для тех, кто знает как устанавливать пакеты при помощи composer, имеет хотя бы небольшой опыт использования php. А также для тех, кто желает разобраться с самого начала, как происходит процесс создания telegram ботов, от получения токена, до обработки и отправки сообщений.

Оглавление статьи:

Шаг 1 — Подготовка среды

Для работы нам потребуется:

  • Зарегистрированный telegram аккаунт;
  • Зарегистрированное доменное имя и SSL-сертификат, так как используются HTTPS-запросы к Telegram Bot API;
  • Хостинг или VPS или же свой сервер, с доступом к нему, в моем случае — это свой сервер в дата-центре.
  • Установленный на сервере PHP, Apache, NGINX, Composer. Я использую версию PHP 8.
  • Текстовый редактор, подойдет Notepad++, я использую Phpshtorm, но так было не всегда.

Шаг 2 — Получение токена

Токен бота — это как его идентификатор в системе, он необходим для формирования запросов к api. Процесс его получения достаточно простой, в строке поиска telegram вводим @BotFather и находим аккаунт.


@BotFather

Переходим в чат с @BotFather и пишем команду /newbot

В ответ получаем:

Alright, a new bot. How are we going to call it? Please choose a name for your bot. — Что означает: Хорошо, новый бот. Как мы собираемся это назвать? Пожалуйста, выберите имя для вашего бота.


шаг 1 создание telegram бота

Отправляем следующим сообщением название бота, в примере: testingbot, получаем ответ: Good. Now let’s choose a username for your bot. It must end in `bot`. Like this, for example: TetrisBot or tetris_bot. — Что означает: Хорошо. Теперь давайте выберем имя пользователя для вашего бота. Оно должно заканчиваться на `бот`. Вот так, например: Tetris Bot или tetris_bot.


Шаг 1 получение токена для telegram бота

Следующим сообщением я отправил testing99_bot, но получил ответ, что такое имя пользователя занято : Sorry, this username is already taken. Please try something different. Такое сообщение свидетельствует о том, что такое имя пользователя занято. Значит необходимо выбрать другое, в итоге вот такое было свободно botfortest99_bot. И мы получаем такое сообщение, содержащее токен токен.

Done! Congratulations on your new bot. You will find it at t.me/botfortest99_bot. You can now add a description, about section and profile picture for your bot, see /help for a list of commands. By the way, when you’ve finished creating your cool bot, ping our Bot Support if you want a better username for it. Just make sure the bot is fully operational before you do this.

Use this token to access the HTTP API:

5236473451:AAEAjVbZY0kbxOLwBFYTV4j1YXRs77HmJEI

Keep your token secure and store it safely, it can be used by anyone to control your bot.

For a description of the Bot API, see this page: https://core.telegram.org/bots/api

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


шаг 3 получения токена для telegram бота

Шаг 3 — Регистрация хука

Регистрация вебхука — это явное указание, по какому https адресу должен вызываться наш php-файл обработчик. Для начала его нужно создать, например index.php или любой другой.

Для установки вебхука(скрипта), который будет обрабатывать команды и отвечать на сообщения, необходимо открыть в браузере такую строку:

https://api.telegram.org/bot5236473451:AAEAjVbZY0kbxOLwBFYTV4j1YXRs77HmJEI/setWebhook?url=https://ae-nekrasov.ru/devbot/index.php


url для установки хука telegram bot

В результате открытия этой строки в браузере и нажатии кнопки enter, мы получаем такое сообщение : {«ok»:true,»result»:true,»description»:»Webhook was set»} — это означает, что вебхук установлен и теперь отправленные боту сообщения будут приходить на этот адрес.


регистрация вебхука telegram-бот

Шаг 4 — Прием и обработка сообщений от пользователей

Чтобы принимать и обрабатывать сообщения нужно понять модель взаимодействия с telegram API и куда и в каком формате нам будут приходить сообщения.

Так как в данной статье будет рассмотрен вариант, с применением вебхука, после отправки сообщения боту, telegram API будет отправлять нам данные, которые он получил от пользователя, на указанный URL — адрес(см. Шаг 3.). Самый интересный момент в этом куда, в массив $_GET, $_POST или $_REQUEST? На самом деле не в один из них, данные будут приходить в «php://input» и получить их и просмотреть можно будет, разместив в файле index.php такой код:

<?php
$tmpdata = json_decode(file_get_contents("php://input"),true);

$arrdataapi = print_r($tmpdata, true);

file_put_contents('apidata.txt', "Данные от бота: $arrdataapi", FILE_APPEND);

В коде выше мы считываем необработанные данные из php://input и сразу же их преобразуем в ассоциативный массив, функцией json_decode, передав ей вторым параметром true. Затем в переменную $arrdataapi сохраняем распечатанный массив, функцией print_r, передав ей вторым параметром true, применение данного способа описано здесь.

Отправляем нашему боту несколько сообщений и посмотрим, что будет в файле apidata.txt.


Отправка сообщений telegram боту

Содержимое файла apidata.txt

Данные от бота: Array
(
    [update_id] => 570811583
    [message] => Array
        (
            [message_id] => 6
            [from] => Array
                (
                    [id] => 816955688
                    [is_bot] => 
                    [first_name] => Александр
                    [last_name] => Некрасов
                    [username] => ANeK
                    [language_code] => ru
                )

            [chat] => Array
                (
                    [id] => 816955688
                    [first_name] => Александр
                    [last_name] => Некрасов
                    [username] => ANeK
                    [type] => private
                )

            2022 => 1649421871
            [teхt] => /start
            [entities] => Array
                (
                    [0] => Array
                        (
                            [offset] => 0
                            [length] => 6
                            [type] => bot_command
                        )

                )

        )

)
Данные от бота: Array
(
    [update_id] => 570811584
    [message] => Array
        (
            [message_id] => 7
            [from] => Array
                (
                    [id] => 816955688
                    [is_bot] => 
                    [first_name] => Александр
                    [last_name] => Некрасов
                    [username] => ANeK
                    [language_code] => ru
                )

            [chat] => Array
                (
                    [id] => 816955688
                    [first_name] => Александр
                    [last_name] => Некрасов
                    [username] => ANeK
                    [type] => private
                )

            2022 => 1649421873
            [teхt] => 123
        )

)
Данные от бота: Array
(
    [update_id] => 570811585
    [message] => Array
        (
            [message_id] => 8
            [from] => Array
                (
                    [id] => 816955688
                    [is_bot] => 
                    [first_name] => Александр
                    [last_name] => Некрасов
                    [username] => ANeK
                    [language_code] => ru
                )

            [chat] => Array
                (
                    [id] => 816955688
                    [first_name] => Александр
                    [last_name] => Некрасов
                    [username] => ANeK
                    [type] => private
                )

            2022 => 1649421877
            [teхt] => привет
        )

)
Данные от бота: Array
(
    [update_id] => 570811586
    [message] => Array
        (
            [message_id] => 9
            [from] => Array
                (
                    [id] => 816955688
                    [is_bot] => 
                    [first_name] => Александр
                    [last_name] => Некрасов
                    [username] => ANeK
                    [language_code] => ru
                )

            [chat] => Array
                (
                    [id] => 816955688
                    [first_name] => Александр
                    [last_name] => Некрасов
                    [username] => ANeK
                    [type] => private
                )

            2022 => 1649421879
            [teхt] => /help
            [entities] => Array
                (
                    [0] => Array
                        (
                            [offset] => 0
                            [length] => 5
                            [type] => bot_command
                        )

                )

        )

)
Данные от бота: Array
(
    [update_id] => 570811587
    [message] => Array
        (
            [message_id] => 10
            [from] => Array
                (
                    [id] => 816955688
                    [is_bot] => 
                    [first_name] => Александр
                    [last_name] => Некрасов
                    [username] => ANeK
                    [language_code] => ru
                )

            [chat] => Array
                (
                    [id] => 816955688
                    [first_name] => Александр
                    [last_name] => Некрасов
                    [username] => ANeK
                    [type] => private
                )

            2022 => 1649421896
            [photo] => Array
                (
                    [0] => Array
                        (
                            [file_id] => AgACAgIAAxkBAAMKYlAuSD6Q2PTZbXHAdnbUwKEcGeAAAi-8MRshN4BKa9oVsEHatVEBAAMCAANzAAMjBA
                            [file_unique_id] => AQADL7wxGyE3gEp4
                            [file_size] => 1522
                            [width] => 90
                            [height] => 64
                        )

                    [1] => Array
                        (
                            [file_id] => AgACAgIAAxkBAAMKYlAuSD6Q2PTZbXHAdnbUwKEcGeAAAi-8MRshN4BKa9oVsEHatVEBAAMCAANtAAMjBA
                            [file_unique_id] => AQADL7wxGyE3gEpy
                            [file_size] => 21642
                            [width] => 320
                            [height] => 226
                        )

                    [2] => Array
                        (
                            [file_id] => AgACAgIAAxkBAAMKYlAuSD6Q2PTZbXHAdnbUwKEcGeAAAi-8MRshN4BKa9oVsEHatVEBAAMCAAN4AAMjBA
                            [file_unique_id] => AQADL7wxGyE3gEp9
                            [file_size] => 76889
                            [width] => 800
                            [height] => 566
                        )

                )

        )

)

Просмотрев содержимое файла, мы видим, что достаточно много данных нам отправляет telegram API. Исходя из этого, можно перейти к построению обработчика. Дальнейшие действия предполагают, что подготовка среды(см. Шаг1) Вы прошли и Вам будет понятно, что происходит дальше.

В директорию, где находится файл index.php размещаем файл composer.json, со следующим содержимым :

{
 "require": {
        "guzzlehttp/guzzle": "^6.0"
    },
  "autoload": {
    "psr-4": { "": "src/" }
  }
}

И выполняем в терминале команду composer require, в результате мы увидим что-то вроде:

Search for a package: 
./composer.json has been updated
Running composer update 
Loading composer repositories with package information
Updating dependencies
Lock file operations: 8 installs, 0 updates, 0 removals
  - Locking guzzlehttp/guzzle (6.5.5)
  - Locking guzzlehttp/promises (1.5.1)
  - Locking guzzlehttp/psr7 (1.8.5)
  - Locking psr/http-message (1.0.1)
  - Locking ralouphie/getallheaders (3.0.3)
  - Locking symfony/polyfill-intl-idn (v1.25.0)
  - Locking symfony/polyfill-intl-normalizer (v1.25.0)
  - Locking symfony/polyfill-php72 (v1.25.0)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 8 installs, 0 updates, 0 removals
  - Downloading guzzlehttp/psr7 (1.8.5)
  - Installing symfony/polyfill-php72 (v1.25.0): Extracting archive
  - Installing symfony/polyfill-intl-normalizer (v1.25.0): Extracting archive
  - Installing symfony/polyfill-intl-idn (v1.25.0): Extracting archive
  - Installing ralouphie/getallheaders (3.0.3): Extracting archive
  - Installing psr/http-message (1.0.1): Extracting archive
  - Installing guzzlehttp/psr7 (1.8.5): Extracting archive
  - Installing guzzlehttp/promises (1.5.1): Extracting archive
  - Installing guzzlehttp/guzzle (6.5.5): Extracting archive
2 package suggestions were added by new dependencies, use `composer suggest` to see details.
Generating autoload files
5 packages you are using are looking for funding.
Use the `composer fund` command to find out more!

Это означает, что необходимые пакеты с зависимостями установились, появилась папка vendor. Для своих классов создаем директорию src, в корне проекта. Там разместим первый класс Api и файл соответственно называется Api.php, со следующим содержимым:

<?php

require '../vendor/autoload.php';
use GuzzleHttp\Client;

class Api extends Client
{
    /**
     *
     * @description Небольшой класс для работы с телеграмм АПИ
     * Основные функции для отправки сообщений и немного еще...
     * Данный класс описан под php версии 8+ для использования на более ранних версиях необходимо
     * убрать описание возвращаемых значений у методов, например : array
     */

    protected $conftoken;
    public $basicChatData;

    public function __construct($token)
    {
        parent::__construct();
        $this->conftoken = $token;
        $this->basicChatData = $this->getDataChat();
    }


    /**
     *
     * @return array $result - базовые данные чата
     * @throws JsonException
     *
     */

    public function getDataChat(): array
    {
        return json_decode(file_get_contents("php://input"), true, 512, JSON_THROW_ON_ERROR);
    }


    /**
     *
     * @param string $message - сообщение от бота
     * @return mixed - результат выполнения
     * @throws JsonException
     *
     */

    public function sendMessage(string $message): mixed
    {
        $params = array("chat_id" => $this->basicChatData["message"]["chat"]["id"],"text"=>$message);
        $response = $this->request('POST', "https://api.telegram.org/bot$this->conftoken/sendMessage",['json'=>$params],['http_errors' => false]);
        return json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR);
    }
}

В коде выше, был создан класс Api и внутри него метод sendMessage, на основе данных описанных в официальной документации telegram API по отправке сообщений https://core.telegram.org/bots/api#sendmessage

Чтобы класс можно было использовать, необходимо выполнить команду в терминале composer dump-autoload -o

Теперь модифицируем файл index.php, чтобы он был такого содержимого:

<?php
set_include_path(__DIR__);
require 'vendor/autoload.php';

$bot = new Api("5236473451:AAEAjVbZY0kbxOLwBFYTV4j1YXRs77HmJEI");

$bot->sendMessage("Привет");

Если Вы все сделали по инструкции описанной выше, то теперь на любые сообщения бот будет отвечать «Привет». Небольшая gif-ка с результатом работы.


Работа telegram бота первые шаги

Работает, естественно отвечать на все сообщения «Привет» — это не окончательная функциональность. Теперь нужно как-то обработать входящие сообщения и исходя из содержимого уже отправлять ответ.

Немного модифицируем класс Api, добавим новый метод, который будет возвращать отправленное сообщение боту, добавляемый код:


    /**
     *
     * @return mixed - сообщение отправленное боту
     * 
     */

    public function getMessage(): mixed
    {
        return $this->basicChatData['message']['text'];
    }

Также модифицируем файл index.php, новый код:

<?php
set_include_path(__DIR__);
require 'vendor/autoload.php';


$bot = new Api("5236473451:AAEAjVbZY0kbxOLwBFYTV4j1YXRs77HmJEI");


$message = $bot->getMessage();

$bot->sendMessage($message);

Теперь бот просто будет повторюшкой, он будет отправлять нам то, что мы ему, ниже gif-ка с примером работы:


telegram бот повторюшка

Модифицируем index.php, добавим if else ветвления, чтобы отвечать уже в зависимости от того, что нам отправит пользователь, новый код:

<?php
set_include_path(__DIR__);
require 'vendor/autoload.php';


$bot = new Api("5236473451:AAEAjVbZY0kbxOLwBFYTV4j1YXRs77HmJEI");

$message = $bot->getMessage();

if($message == "Привет" || $message == "привет"){
    
    $bot->sendMessage("Привет");
    
}elseif($message == "Как дела?" || $message == "как дела?"){
    
    $bot->sendMessage("У меня отлично, как у тебя?");
    
}elseif($message == "Кто ты?" || $message == "кто ты?"){
    
    $bot->sendMessage("Я telegram бот, созданный недавно!");
    
}

Теперь бот отвечает специальным ответом, в зависимости от вопроса, ниже gif-ка с примером работы:


пример общения с telegram ботом

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

Шаг 5 — Обработка команд

Команды можно обрабатывать как и текст сообщений, но чтобы при вводе / выпадал список команд с описанием, нужно через @BotFather их настроить, для этого:

  • 1 — в чате с @BotFather вводим /mybots
  • 2 — выбираем бота, для которого необходимо настроить команды
  • 3 — нажимаем кнопку Edit Bot
  • 4 — нажимаем кнопку Edit Commandst
  • 5 — вводим название команды пробел — пробел описание, например help — Помощь по управлению.

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


команды для telegram бота

Шаг 6 — Добавление кнопок в чат и обработка нажатий

В рамках данной статьи рассмотрим два варианта кнопок:

Вариант 1. Кнопки в зоне основной клавиатуры


встроенная клавиатура telegram bot

Вариант 2. Кнопки под сообщением


кнопки под сообщением telegram bot

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

Второй вариант обрабатывается немного иначе, я для этого использую даже другой метод отправки сообщения, после нажатия на такую клавиатуру, это обусловлено тем, что при нажатии кнопок в режиме callback query, к нам придет немного другой формат массива с данными, точнее данные([from],[message],[chat]) будут вложены в массив [‘callback_query’]

Для экспериментов с кнопками, необходимо добавить в файл Api.php несколько методов, фрагмент добавляемого кода:


    /**
     *
     * @return mixed - возвращает данные из массива ['callback_query']
     * если было нажатие, на кнопки под сообщением
     *
     */

    public function getCallBackQuery(): mixed
    {
        return $this->basicChatData['callback_query']['data'];
    }

    /**
     * Метод для ответа при обработки нажатия кнопок под сообщение
     * @param string $message - сообщение от бота
     * @return mixed - результат выполнения
     * @throws JsonException
     */

    public function sendMessageCallBackData(string $message): mixed
    {
        $params = array("chat_id" => $this->basicChatData['callback_query']["message"]["chat"]["id"],"text"=>$message);
        $response = $this->request('POST', "https://api.telegram.org/bot$this->conftoken/sendMessage",['json'=>$params],['http_errors' => false]);
        return json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR);
    }
    
   /**
     * Метод отправки кнопок вместе с сообщением
     * @param string $message - сообщение от бота
     * @param array $inlineKeyboard - клавиатура
     * @return mixed - результат выполнения
     * @throws JsonException
     */

    public function sendMessageWithInlineKeyboard(string $message, array $inlineKeyboard): mixed
    {
            $params = array("chat_id" => $this->basicChatData["message"]["chat"]["id"],"text"=>$message,"reply_markup" => array("inline_keyboard"=>$inlineKeyboard));
            $response = $this->request('POST', "https://api.telegram.org/bot$this->conftoken/sendMessage",['json'=>$params],['http_errors' => false]);
            return json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR);
    }

    /**
     * Метод вызова кнопок в зоне основной клавиатуры
     * @param string $message - сообщение от бота
     * @param array $keyboard - клавиатура
     * @return mixed $result - результат выполнения
     * @throws JsonException
     */

    public function sendMessageWithBaseKeyboard(string $message, array $keyboard): mixed
    {
            $params = array("chat_id" => $this->basicChatData["message"]["chat"]["id"],"text" => $message, "reply_markup" => array("keyboard" => $keyboard, "resize_keyboard" => true));
            $response = $this->request('POST', "https://api.telegram.org/bot$this->conftoken/sendMessage",['json'=>$params],['http_errors' => false]);
            return json_decode($response->getBody(), true, 512, JSON_THROW_ON_ERROR);
    }

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

Также необходимо обновить файл index.php, его новый код:

<?php
set_include_path(__DIR__);
require 'vendor/autoload.php';


$bot = new Api("5236473451:AAEAjVbZY0kbxOLwBFYTV4j1YXRs77HmJEI");

$message = $bot->getMessage();

$callBackQuery = $bot->getCallBackQuery();




if($callBackQuery){



if($callBackQuery == "444"){

    $bot->sendMessageCallBackData("Нажата кнопка 1");

}elseif($callBackQuery == "555"){

    $bot->sendMessageCallBackData("Нажата кнопка 2");

}elseif($callBackQuery == "777"){

    $bot->sendMessageCallBackData("Нажата кнопка 3");

}


}

// формат клавиатуры снизу в зоне вывода стандартной

$keyboard2 = array(
    array(
        array(
            "text" => "888"
        ),
        array(
            "text" => "999"
        ),
    )
);


// формат клавиатуры для вывода под сообщением

$arrInlineKey =  array(
    array(
        array('text'=>'Кнопка 1','callback_data'=>'444'),
        array('text'=>'Кнопка 2','callback_data'=>'555'),
        array('text'=>'Кнопка 3','callback_data'=>'777'),
    )
);


if($message == "Привет" || $message == "привет"){

    $bot->sendMessage("Привет");

}elseif($message == "Как дела?" || $message == "как дела?"){

    $bot->sendMessage("У меня отлично, как у тебя?");

}elseif($message == "Кто ты?" || $message == "кто ты?"){

    $bot->sendMessage("Я telegram бот, созданный недавно!");

}elseif($message == "/help"){

    $bot->sendMessage("Вызвана команда /help");

}elseif($message == "клавиатура"){

    $bot->sendMessageWithInlineKeyboard("Кнопки под сообщением \n тут могут быть любые кнопки \n еще строка текста \n еще строка текста", $arrInlineKey);

}elseif($message == "клавиатура2"){

    $bot->sendMessageWithBaseKeyboard("Вызвана клавиатура", $keyboard2);

}elseif($message == "888"){

    $bot->sendMessage("Нажата кнопка 888");

}elseif($message == "999"){

    $bot->sendMessage("Нажата кнопка 999");

}

Если Вы все делали по инструкции, то должен быть такой результат, как на gif-ке ниже:

пример работы telegram бота

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

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

Также выкладываю архив с исходниками, данный токен будет удален, для использования, Вам будет необходимо передать свой, $bot = new Api(«ВАШ_ТОКЕН»);

Для установки, распакуйте архив в папку проекта, куда будет настроен Ваш вебхук, запустите команду composer require и команду composer dump-autoload -o

Добавляйте свои методы, или модифицируйте написанные мной. Ссылка на оф. сайт, с описанием всех методов telegram API https://core.telegram.org/bots/api#available-methods Всем успехов в разработке!


Скачать исходники

Рекламный блок, для развития проекта


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

Ваш адрес email не будет опубликован.