Как создать Telegram-бота с помощью PHP?

Как создать Telegram-бота с помощью PHP?

Доброго времени суток! В данной статье я покажу Вам как просто можно создать Telegram-бота на PHP.

В качестве площадки для хостинга нашего бота мы будем использовать платформу Heroku, о которой я уже ранее писал статью. В качестве библиотеки для разработки бота возьмем вот эту irazasyed/telegram-bot-sdk. Но кроме нам также понадобится библиотека doctrine/annotations для удобной организации команд на которые будет реагировать бот.

Для начала нам нужно будет получить токен для бота. Для этого надо непосредственно в клиенте Telegram перейти к боту @BotFather, где набрав команду /newbot следовать инструкциям. После получения токена нам необходимо будем настроить так называемый веб-хук — URL, на который будут приходить команды, введенные пользователем в чате с ботом. Внизу ссылка в которой нужно заменить <%ТОКЕН_БОТА%> на токен Вашего бота, после чего для активации адреса нужно будет открыть его в браузере. Обратите внимание, что Telegram требует, чтобы адрес веб-хука был c настроенным SSL. К счастью, если бот размещается на Heroku, то все уже настроено и работает.

Вот сама ссылка:


https://api.bot.org/bot<%ТОКЕН_БОТА%>/setWebhook?url=https://myrusakovbot21.herokuapp.com/index.php

Все готово, теперь приступим к написанию кода — вот наш файл composer.json:


{
    "name": "myrusakov/php-bot-webhook",
    "type": "project",
    "require": {
        "irazasyed/telegram-bot-sdk": "^2.0",
        "doctrine/annotations": "^1.13"
    },
    "autoload": {
        "psr-4": {
            "": "src/"
        }
    }
}

Файлы с классами будут лежать в папке src. Вот базовая струтура директорий проекта:


.
├── vendor
├── src
│   ├── MainCommand.php
│   └── CommandsCollector.php
├── index.php
├── composer.lock
├── composer.json
└── .gitignore

Файл index.php


<?php

require __DIR__ . '/vendor/autoload.php';

use TelegramBotApi;

//  в класс передаем наш токен
$bot =  new Api('%ТОКЕН БОТА%');

function BotApp(Api $bot, array $commands = [])
{
    // получаем обновленные данные
    $result = $bot->getWebhookUpdates();
    $text = $result["message"]["text"]; //Текст сообщения
    $chat_id = $result["message"]["chat"]["id"]; //Идентификатор пользователя
    $name = $result["message"]["from"]["username"]; //Имя пользователя

    // если есть текстовая команда
    if ($text) 
    {
        // пробегаемся по массиву команд
        foreach ($commands as $commandText => $commandAction) 
        {
            // смотрим, есть ли введенная текстовая команда в списке доступных 
            if ($commandText === $text) 
            {
                // есть такая команда - получаем ее обработчики - название класса и метода
                [$class, $method] = $commandAction;

                // вызываем обработчик
                $obj = new $class();
                $obj->$method($bot, $result);
                return;
            }
        }

        // если команда не распознана срабатывает обработчик по умолчанию
        [$class, $method] = $commands['fallback'];
        $obj = new $class();
        $obj->$method($bot, $result);

    } 
    else 
    {
        $bot->sendMessage(['chat_id' => $chat_id, 'parse_mode' => 'HTML', 'text' => "Привет <b>$name!</b> Я понимаю только текст."]);
    }
}

// массив с классами команд - их может быть столько, сколько необходимо Вам
$actions = [MainCommand::class];

// проходится по классу и собирает команды, на которые срабатывает обработчик
$collector = new CommandsCollector(); 

// массива команд и соответствующих им обработчиков
$commands = [];
foreach($actions as $action)
{
    $classCommands = $collector->collect($action);
    $commands = array_merge($commands, $classCommands);
}

// запускаем бота
BotApp($bot, $commands);

Сопоставление команд с обработчиком происходит с помощью аннотаций. Для этого как раз и нужен пакет doctrine/annotations

Класс, который содержит обработчики команд


<?php

use TelegramBotApi;
use TelegramBotObjectsUpdate as ObjectsUpdate;

class MainCommand
{
    /**
     * @Command(text="привет")
     */
    public function welcome(Api $bot, ObjectsUpdate $result)
    {
        $chat_id = $result["message"]["chat"]["id"];
        $reply = "Информация с помощью.";
        $bot->sendMessage(['chat_id' => $chat_id, 'text' => $reply]);
    }

    /**
     * @Command(text="вакансии")
     */
    public function vacanciesFeed(Api $bot, ObjectsUpdate $result)
    {
        $reply = '';
        $url = 'https://career.habr.com/vacancies/rss?currency=RUR&sort=relevance&type=all';
        $chat_id = $result["message"]["chat"]["id"];

        $rss = simplexml_load_file($url);

        foreach ($rss->channel->item as $item) {
            $reply .= "xE2x9ExA1 " . $item->title . " (<a href='" . $item->link . "'>читать</a>)n";
        }

        $bot->sendMessage(['chat_id' => $chat_id, 'parse_mode' => 'HTML', 'disable_web_page_preview' => false, 'text' => $reply]);

    }

    /**
     * @Command(text="fallback")
     */
    public function fallback(Api $bot, ObjectsUpdate $result)
    {
        $text = $result["message"]["text"];
        $chat_id = $result["message"]["chat"]["id"];

        $reply = "По запросу "<b>$text</b>" ничего не найдено.";
        $bot->sendMessage(['chat_id' => $chat_id, 'parse_mode' => 'HTML', 'text' => $reply]);
    }
}

Формированием команд и их обработчиков занимается класс CommandsCollector:


<?php

use DoctrineCommonAnnotationsAnnotationReader;

/**
 * @Annotation
 * @Target({"CLASS","METHOD"})
 */
final class Command
{
    public $text;
}

class CommandsCollector
{
    /**
     * Выбирает из класса все публичные методы, затем вытаскивает 
     * из них текст команд, на которые они должны срабатывать и формирует 
     * массив вида:
     * 
     * [
     *      'привет' => ['MainCommand', 'welcome']      * ]      * 
     * Т.е. на введенную пользователем команду будет срабатывать метод welcome класса MainCommand 
     */
    public function collect($class)
    {
        $reader    = new AnnotationReader();
        $refClass  = new ReflectionClass($class);

        $refMethods = $refClass -> getMethods(ReflectionMethod::IS_PUBLIC);

        $commands = [];
        foreach($refMethods as $method)
        {
            $command = $reader->getMethodAnnotation($method, Command::class);

            if($command) {
                $commands[$command->text] = [$method->class, $method->name];
            }
        }

        return $commands;
    }
}

После того, как код написан — нужно его разместить на платформе Heroku. Для этого нужно выполнить следующие команды в папке проекта (предполагается, что консольная утилита heroku уже установлена в системе и доступна в консоли как команда heroku):


$ cd myrusakov-telegram-bot # переходим в папку проекта - в моем случае она называется так

$ heroku login # вы должны быть зарегистрированы на Heroku и приложение myrusakovbot21 (в моем случае оно так называется) должно создано

$ heroku git:remote -a myrusakovbot21 # связываем наше приложение на компьютере с удаленным приложением на сервере

$ git add .
$ git commit -am "Initial commit"
$ git push heroku main

Таким образом, если не возникнет ошибок в ходе размещения бота на Heroku, то Ваш бот успешно размещен на сервере и готов принимать команды. Если же, после всего сделанного бот не запускается, то в папке приложения можно выполнить команду heroku logs -a myrusakovbot21, которая выведет ошибки, возникшие при обработке команд.

Источник

Статьи по теме

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.

Back to top button