Разработка Telegram бота на PHP #1: бот для технической поддержки | PROG-TIME

Разработка Telegram бота на PHP #1: бот для технической поддержки

05.10.2023
Содержание:

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

В данном уроке мы будем ссылаться на базовый курс по разработке Telegram бота.

https://prog-time.ru/course_cat/telegram-bot-basic/

Структура проекта

Бот будет иметь следующую структуру файлов:

  • bot_hook.php — файл для приёма хуков от бота.
  • BotsTime.php — класс для обработки запросов от Telegram.
  • config.php — файл с конфигурационными параметрами
  • DB.php — класс для работы с PDO
  • TelegramBot.php — класс для отправки запросов

Скрипт для приёма хуков от Telegram

Код из файла bot_hook.php.

ini_set('error_reporting', E_ALL);
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);

require_once __DIR__ . '/BotsTime.php';

$dataQuery = file_get_contents('php://input');
// file_put_contents(__DIR__ . "/message.txt", print_r($dataQuery, true));
$dataQuery = json_decode($dataQuery, true);

if(!empty($dataQuery['message'])) {
    $botTelegram = new BotsTime($dataQuery);
}

Класс для обработки запроса бота

Код из файла BotsTime.php.

<?php

require_once __DIR__ . '/config.php';
require_once __DIR__ . '/DB.php';
require_once __DIR__ . '/TelegramBot.php';

class BotsTime extends TelegramBot
{
    private $telegramUserID = 0;
    private $dataMessage = [];

    public function __construct($dataMessage)
    {
        if (!empty($dataMessage)) {
            if ($dataMessage['message']['from']['is_bot'] == false) {
                $this->dataMessage = $dataMessage;

                if (!empty($this->dataMessage['message'])) {
                    $this->telegramUserID = $this->dataMessage['message']['chat']['id'];
                    $this->botController();
                }
            }
        }
    }

    private function addNewClient() : int
    {
        /* создание топика */
        $resultQuery = $this->sendQueryTelegram(
            'createForumTopic',
            [
                'chat_id' => TG_TECH_CHAT,
                'name' => 'Клиент #' . $this->telegramUserID,
            ]
        );
        /* --------------- */

        if (!empty($resultQuery["result"])) {
            $topicID = (int)$resultQuery["result"]["message_thread_id"];

            /* запись пользователя в БД */
            $insertData = [
                'id_telegram_user' => $this->telegramUserID,
                'id_topic_telegram' => $topicID,
                'date_create_client' => time(),
            ];
            $insert_id = DB::add("INSERT INTO `clients` SET `id_telegram_user` = :id_telegram_user, `id_topic_telegram` = :id_topic_telegram, `date_create_client` = :date_create_client", $insertData);
            /* --------------- */
        } else {
            $topicID = 0;
        }

        return $topicID;
    }

    private function botController()
    {
        $clientData = DB::getRow("SELECT * FROM `clients` WHERE `id_telegram_user` = ?", $this->dataMessage["message"]["from"]["id"]);

        if ($this->dataMessage['message']['chat']['id'] === TG_TECH_CHAT) {
            if (!empty($clientData['id_telegram_user'])) {
                /* отправка сообщения в чат */
                $dataMessage = [
                    'chat_id' => $clientData['id_telegram_user'],
                    'text' => $this->dataMessage['message']['text'],
                    'parse_mode' => "html",
                ];
                $this->sendQueryTelegram('sendMessage', $dataMessage);
                /* --------------- */
            }
        } else {
            $topicID = (empty($clientData)) ? $this->addNewClient() : (int)$clientData["id_topic_telegram"];

            if (!empty($topicID)) {
                /* отправка сообщения в чат */
                $dataMessage = [
                    'chat_id' => TG_TECH_CHAT,
                    'text' => $this->dataMessage['message']['text'],
                    'parse_mode' => "html",
                    'message_thread_id' => $topicID
                ];
                $this->sendQueryTelegram('sendMessage', $dataMessage);
                /* --------------- */
            }
        }
    }
}

Конфигурационный файл

Код из файла config.php.

define('TG_TOKEN', '');
define('TG_TECH_CHAT', 0);

Класс для работы с PDO

Код из файла DB.php.

<?php

class DB
{
    public static $dsn = 'mysql:dbname=НАЗВАНИЕ_БД;host=localhost';
    public static $user = '';
    public static $pass = '';

    /**
     * Объект PDO.
    */
    public static $dbh = null;

    /**
     * Statement Handle.
    */
    public static $sth = null;

    /**
     * Выполняемый SQL запрос.
    */
    public static $query = '';

    /**
     * Подключение к БД.
    */
    public static function getDbh()
    {
        if (!self::$dbh) {
            try {
                self::$dbh = new PDO(
                    self::$dsn,
                    self::$user,
                    self::$pass,
                    array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'")
                );
                self::$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
            } catch (PDOException $e) {
                exit('Error connecting to database: ' . $e->getMessage());
            }
        }

        return self::$dbh;
    }

    /**
      * Закрытие соединения.
    */
    public static function destroy()
    {
        self::$dbh = null;
        return self::$dbh;
    }

    /**
     * Получение ошибки запроса.
    */
    public static function getError()
    {
        $info = self::$sth->errorInfo();
        return (isset($info[2])) ? 'SQL: ' . $info[2] : null;
    }

    /**
     * Возвращает структуру таблицы в виде ассоциативного массива.
    */
    public static function getStructure($table)
    {
        $res = array();
        foreach (self::getAll("SHOW COLUMNS FROM {$table}") as $row) {
            $res[$row['Field']] = (is_null($row['Default'])) ? '' : $row['Default'];
        }

        return $res;
    }

    /**
     * Добавление в таблицу, в случаи успеха вернет вставленный ID, иначе 0.
    */
    public static function add($query, $param = array())
    {
        self::$sth = self::getDbh()->prepare($query);
        return (self::$sth->execute((array)$param)) ? self::getDbh()->lastInsertId() : 0;
    }

    /**
     * Выполнение запроса.
    */
    public static function set($query, $param = array())
    {
        self::$sth = self::getDbh()->prepare($query);
        return self::$sth->execute((array)$param);
    }

    /**
     * Получение строки из таблицы.
    */
    public static function getRow($query, $param = array())
    {
        self::$sth = self::getDbh()->prepare($query);
        self::$sth->execute((array)$param);
        return self::$sth->fetch(PDO::FETCH_ASSOC);
    }

    /**
     * Получение всех строк из таблицы.
    */
    public static function getAll($query, $param = array())
    {
        self::$sth = self::getDbh()->prepare($query);
        self::$sth->execute((array)$param);
        return self::$sth->fetchAll(PDO::FETCH_ASSOC);
    }

    /**
     * Получение значения.
    */
    public static function getValue($query, $param = array(), $default = null)
    {
        $result = self::getRow($query, $param);
        if (!empty($result)) {
            $result = array_shift($result);
        }

        return (empty($result)) ? $default : $result;
    }

    /**
     * Получение столбца таблицы.
    */
    public static function getColumn($query, $param = array())
    {
        self::$sth = self::getDbh()->prepare($query);
        self::$sth->execute((array)$param);
        return self::$sth->fetchAll(PDO::FETCH_COLUMN);
    }
}

Класс для отправки запросов для Telegram

Код из файла TelegramBot.php.

<?php

require_once __DIR__ . '/config.php';

class TelegramBot
{
    private $token = TG_TOKEN;

    /**
     * Отправка запроса в Telegram
     *
     * @param  mixed $method
     * @param  mixed $arrayQuery
     * @return void
     */
    public function sendQueryTelegram(string $method, array $arrayQuery = [])
    {
        $ch = curl_init("https://api.telegram.org/bot" . $this->token . "/" . $method . "");
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $arrayQuery);
        curl_setopt($ch, CURLOPT_HTTPHEADER, ["Content-Type:multipart/form-data"]);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_HEADER, false);
        $result = curl_exec($ch);
        curl_close($ch);

        return json_decode($result, true);
    }
}

Структура БД

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

Поля для таблицы clients:

  • id_client — уникальный идентификатор пользователя
  • id_telegram_user — id telegram пользователя
  • id_topic_telegram — id темы в группе с менеджерами
  • date_create_client — дата создания клиента
На этом всё!
Больше интересных статей в нашей группе - https://vk.com/progtime
Вы так же можете разместить свой вопрос на нашем форуме, где другие программисты смогут вам помочь в решение вашей задачи - https://vk.com/prog_time
Так же прокачивайте свои навыки на нашем канале - https://www.youtube.com/c/ProgTime
Наши планы
  • Написание материала для курса по разработке ботов на Telegram
  • Разработка универсального парсера на PHP

Поддержите мой сайт!

Каждый переведённый донат, мотивирует на создание новых записей и уроков на YouTube

Материалы курса

Ссылка на мой KWORK