View file delta_framework-main/core/lib/Core/ExternalServices/Telegram.class.php

File size: 14.56Kb
<?php
    /**
     * Copyright (c) 2022 Roman Grinko <[email protected]>
     * Permission is hereby granted, free of charge, to any person obtaining
     * a copy of this software and associated documentation files (the
     * "Software"), to deal in the Software without restriction, including
     * without limitation the rights to use, copy, modify, merge, publish,
     * distribute, sublicense, and/or sell copies of the Software, and to
     * permit persons to whom the Software is furnished to do so, subject to
     * the following conditions:
     * The above copyright notice and this permission notice shall be included
     * in all copies or substantial portions of the Software.
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
     * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     */

    /**
     * Класс для работы с API телеграмм
     * Поддерживает:
     * - отправка сообщений с разметкой html
     * - редактирование отправленных сообщений
     * - работу с inline класиатурами (в сообщении)
     * - работу с быстрыми клавиатурами (меню бота)
     * - отправка сообщений с изображением с разметкой html
     * - отправка файлов
     * - получение информации о группе или канале
     * - получение файлов по идентификатору
     * - имитация действий (набирает сообщение, записывает голосовое и т.д.)
     * - отправка местоположений
     * - обработка callback запросов
     * - обработка inline событий
     *
     * @version 2.5.1
     * @author  Roman Grinko <[email protected]>
     */

    namespace Core\ExternalServices;

    class Telegram
    {
        /**
         * @var string $token Токен бота
         */
        private static string $token;

        /**
         * @var string $url Адрес API запроса
         */
        private static string $url;

        const BASE_URL = 'api.telegram.org';

        /**
         * @var string $uploadDir Директория для загрузки и хранения файлов
         */
        private static string $uploadDir;

        /**
         * Инициализация
         *
         * @param string $token     Токен бота
         * @param string $uploadDir Директория для загрузки и хранения файлов
         */
        public static function init(string $token, string $uploadDir): void
        {
            self::$token     = $token;
            self::$url       = 'https://' . self::BASE_URL . '/bot' . $token . '/';
            self::$uploadDir = $uploadDir;
        }

        /**
         * Отправка запроса на API Telegram
         *
         * @param string $method   Используемый метод
         * @param array  $response Параметры
         *
         * @return array
         */
        private static function sendRequest(string $method, array $response): array
        {
            $ch = curl_init(self::$url . $method);
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $response);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_HEADER, false);
            $res      = curl_exec($ch);
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);
            return json_decode($res, true);
        }

        /**
         * Получение информации о канале или группе
         *
         * @param string $channel Канал
         *
         * @return array
         */
        public static function getChat(string $channel): array
        {
            $channel  = str_replace('https://t.me/', '', str_replace('@', '', $channel));
            $response = [
                'chat_id' => '@' . $channel,
            ];
            return self::sendRequest('getChat', $response);
        }

        /**
         * Отправка изображения
         *
         * @param int    $chatId    Идентификатор чата
         * @param string $imagePath Путь до изображения
         *
         * @return array
         */
        public static function sendPhoto(int $chatId, string $imagePath): array
        {
            $response = [
                'chat_id' => $chatId,
                'photo'   => curl_file_create($imagePath),
            ];
            return self::sendRequest('sendPhoto', $response);
        }

        /**
         * Отправка файла
         *
         * @param int    $chatId   Идентификатор чата
         * @param string $filePath Путь до файла
         *
         * @return array
         */
        public static function sendDocument(int $chatId, string $filePath): array
        {
            $response = [
                'chat_id'  => $chatId,
                'document' => curl_file_create($filePath),
            ];
            return self::sendRequest('sendDocument', $response);
        }

        /**
         * Получить присланный файл
         *
         * @param string $fileId Идентификатор файла
         *
         * @return string|null
         */
        public static function getFile(string $fileId): ?string
        {
            $response = [
                'file_id' => $fileId,
            ];
            $res      = self::sendRequest('getFile', $response);
            if ($res['ok']) {
                $src  = 'https://' . self::BASE_URL . '/file/bot' . self::$token . '/' . $res['result']['file_path'];
                $dest = self::$uploadDir . '/' . time() . '-' . basename($src);

                if (copy($src, $dest)) {
                    return $dest;
                } else {
                    return null;
                }
            }
        }

        /**
         * Изменяет уже отправленное сообщение на указанное
         *
         * @param int    $chatId
         * @param int    $messageId
         * @param string $text
         *
         * @return array
         */
        public static function updateMessage(int $chatId, int $messageId, string $text): array
        {
            $response = [
                'chat_id'    => $chatId,
                'message_id' => $messageId,
                'text'       => $text,
            ];
            return self::sendRequest('editMessageText', $response);
        }

        /**
         * Отправка в чат имитаций событий
         * <pre>
         * typing для набора текста
         * upload_photo для загрузки фото
         * record_video или upload_video для видео
         * record_voice или upload_voice для голосовых
         * upload_document здля загрузки документов
         * choose_sticker для выбора стикера
         * find_location для местоположения
         * record_video_note или upload_video_note для видеосообщений
         * </pre>
         *
         * @param int    $chatId ID чата
         * @param string $action Событие
         *
         * @return array
         */

        public static function sendChatAction(int $chatId, string $action = 'typing'): array
        {
            $response = [
                'chat_id' => $chatId,
                'action'  => $action,
            ];
            return self::sendRequest('sendChatAction', $response);
        }

        /**
         * Отправляет координаты с картой
         *
         * @param int   $chatId    ID чата
         * @param float $latitude  Широта
         * @param float $longitude Долгота
         *
         * @return array
         */
        public static function sendLocation(int $chatId, float $latitude, float $longitude): array
        {
            $response = [
                'chat_id'   => $chatId,
                'latitude'  => $latitude,
                'longitude' => $longitude,
            ];
            return self::sendRequest('sendLocation', $response);
        }

        /**
         * Метод для обработки событий callback'ов
         *
         * @param int|null    $callbackId Идентификатор callback
         * @param string|null $text       Текст
         * @param bool        $showAlert  Показывать ли уведомление
         * @param string|null $url        Адрес
         *
         * @return array
         */
        public static function answerCallbackQuery(?int $callbackId, ?string $text = null, bool $showAlert = false, ?string $url = null): array
        {
            $response = [
                'callback_query_id' => $callbackId,
                'text'              => $text,
                'show_alert'        => $showAlert,
                'url'               => $url,
            ];
            return self::sendRequest('answerCallbackQuery', $response);
        }

        /**
         * Метод для обработки событий Inline режима
         *
         * @param int|null $inline_query_id ID запроса
         * @param string   $results         Массив результатов запроса
         * @param int      $cache_time      Время кэширования
         * @param bool     $is_personal     Персонально для каждого пользователя
         *
         * @return array
         */
        public static function answerInlineQuery(?int $inline_query_id, string $results, int $cache_time = 300, bool $is_personal = true): array
        {
            $response = [
                'inline_query_id' => $inline_query_id,
                'results'         => $results,
                'cache_time'      => $cache_time,
                'is_personal'     => $is_personal,
            ];
            return self::sendRequest('answerInlineQuery', $response);
        }

        /**
         * Создание json с результатами для отдачи в inline
         * <pre>
         * $arData = [
         *              [
         *                'title' => 'Title1',
         *                'description' => 'description1',
         *                'message_text' => 'Message1',
         *                'thumb_url' => 'http://example.com/1.jpg'
         *              ],
         *           ]
         * </pre>
         *
         * @param string $inlineType Тип результата
         * @param array  $arData     Массив элементов+
         *
         * @return string
         */
        public static function createInlineQueryResult(string $inlineType, array $arData): string
        {
            $result = [];
            foreach ($arData as $key => $element) {
                $tmpResult = [
                    'type' => $inlineType,
                    'id'   => 'id_' . $key,
                ];
                $result[]  = array_merge($tmpResult, $element);
            }
            $result = json_encode($result);
            return $result;
        }

        /**
         * Отправка сообщение пользователю в телеграм
         *
         * @param int         $chatId          Идентификатор чата
         * @param string|null $text            Текст сообщения
         * @param string      $image           Путь к картинке
         * @param array       $inline_keyboard Массив встроенной клавиатуры
         * @param array       $keyboard        Массив клавиатуры
         * @param array       $keyboard_opt    Массив клавиатуры
         *
         * @return array
         */
        public static function execute(
            int $chatId,
            ?string $text,
            string $image = '',
            array $inline_keyboard = [],
            array $keyboard = [],
            array $keyboard_opt = []
        ): array {
            $params            = [];
            $params['chat_id'] = $chatId;
            $text              = substr(trim($text), 0, 4096);
            $text              = strip_tags($text, '<b><a><strong><i><em><u><ins><s><strike><del><s><code><pre>');
            $text              = mb_convert_encoding($text, 'UTF-8', 'UTF-8');

            if (!empty($image)) { //text + image
                $params['photo']   = curl_file_create($image);
                $params['caption'] = $text;
                $method            = 'sendPhoto';
            } else { //only text
                $params['parse_mode'] = 'html';
                $params['text']       = $text;
                $method               = 'sendMessage';
            }

            /* клавиатура */
            if (!empty($inline_keyboard)) { // инлайн клавиатура если есть
                $inlineKeyboardMarkup   = ['inline_keyboard' => $inline_keyboard];
                $params['reply_markup'] = json_encode($inlineKeyboardMarkup);
            } else { // ставим обычную клавиатуру если есть
                if (empty($keyboard_opt)) {
                    $keyboard_opt[0] = 'keyboard';
                    $keyboard_opt[1] = false;
                    $keyboard_opt[2] = true;
                }
                $options      = [
                    $keyboard_opt[0]    => $keyboard,
                    'one_time_keyboard' => $keyboard_opt[1],
                    'resize_keyboard'   => $keyboard_opt[2],
                ];
                $replyMarkups = json_encode($options);

                $removeMarkups = json_encode(['remove_keyboard' => true]);
                if ($keyboard == [0]) {
                    $params['reply_markup'] = $removeMarkups;
                } else {
                    $params['reply_markup'] = $replyMarkups;
                }
            }

            return self::sendRequest($method, $params);
        }
    }