В новой записи мы с вами разработаем 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 — дата создания клиента
