Делаем бот для обратной связи в Telegram

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

Вариант бота на Node.js описан в отдельной статье

Немаловажная часть работы администратора Телеграм канала - это конечно же работа с обратной связью. Многое приходит из общения с подписчиками, ведь они и оценивают ваш труд, и подсказывают где у вас недочеты, бывает даже подкинут новую идею. Они всегда будут вам благодарны если вы открыты для общения, и у вас налажена обратная связь, которой удобно и легко пользоваться. 

В этой статье я хочу поделиться своим ботом для взаимодействия с подписчиками, который я уже использую. Для начала нам в качестве необходимых параметров нам нужно знать наш личный ID Telegram (через бот @userinfobot) и Token API нашего бота.

* * *

Начинаем работать

Данные от Bot API приходят в формате application/json, поэтому доступа к ним через массив $_POST нет, и брать их будем в "сыром", необработанном виде через 'php://input' используя встроенную функцию PHP file_get_contents().

В работе мы будем использовать кодировку UTF-8, это требование Telegram Bot API. Определим ее в начале скрипта index.php. Создадим класс Bot, для начала добавим ему два приватных свойства и один публичный метод. Очень часто я в коде буду использовать в качестве условного оператора тернарный оператор.

<?php
    // определим кодировку UTF-8
    header('Content-type: text/html; charset=utf-8');
    // Создаем объект класса Bot
    $bot = new Bot();
    // передаем методу init() данные от BOT API
    $bot->init('php://input');

    // Класс Bot
    class Bot
        {
            // токен API 
            private $botToken = "34069ХХХХ:XXXXXXXXXXXX-XXXXXXXXXXXXKVW3qILFpY";
            // Ваш ID Telegram
            private $adminId = 123456789;

            // инициализируем объект класса
            public function init($data) {

            }
        }
?>

Создадим еще один метод, сделаем его приватным т.к. он нужен нам только внутри класса, вызываться из вне как публичный метод init() он не будет. Его задача будет преобразовывать через функцию json_decode() преданные ему данные из JSON в ассоциативный массив, назовем его getData().

<?php
    // преобразовываем входящие данные в массив
    private function getData($data) {
        return json_decode(file_get_contents($data), TRUE);
    }
?>

Для отладки можно создать метод, который будет записывать в файл все результаты работы метода getData(). Это очень удобно, ведь можно посмотреть какую информацию отправляет нам Bot API. На входе он принимает результат метода getData(). Вызывать метод можно вот так: $this->setFileLog($data);

<?php
    private function setFileLog($data) {
        $fh = fopen('log.txt', 'a') or die('can\'t open file');
        ((is_array($data)) || (is_object($data))) ? fwrite($fh, print_r($data, TRUE)."\n") : fwrite($fh, $data . "\n");
        fclose($fh);
    }
?>

Находим наш бот в Telegram и запускаем его. Бот примет нашу команду Strat/Старт, обработает и запишет результат в файл. Теперь мы можем рассмотреть содержимое файла.

Array
(
    [update_id] => 22918823
    [message] => Array
        (
            [message_id] => 1
            [from] => Array
                (
                    [id] => 123456789
                    [is_bot] => 
                    [first_name] => Name
                    [last_name] => Surname
                    [language_code] => ru
                )
            [chat] => Array
                (
                    [id] => 123456789
                    [first_name] => Name
                    [last_name] => Surname
                    [type] => private
                )
            [date] => 1512554545
            [text] => /start
            [entities] => Array
                (
                    [0] => Array
                        (
                            [offset] => 0
                            [length] => 6
                            [type] => bot_command
                        )
                )
        )
)

Как видно из содержимого, приходит много служебной информации. Сейчас нас интересует элемент массива $data['message'], который тоже является массивом и содержит в себе информацию, с которой предстоит работать. Проверяя наличие нужных нам ключей в массиве, мы можем определить какой тип данных был отправлен боту. Для данного бота важно определить кто написал, ведь от этого зависит куда направлять сообщение. 

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

* * *

Мои первые ошибки 

В начале, когда я делал этого бота, то потратил время на написание лишней логики. Бот принимал сообщения от пользователя проверял тип и направлял его админу как новое сообщение с вложенной кнопкой "Ответить", при нажатии на которую происходила временная запись в файл id пользователя, и бот следующим действием ждал сообщение от админа для ответа пользователю. Получилось много ненужного кода, каких-то проверок и вообще пользоваться было не удобно.

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

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

Решение пришло из официальной документации

На самом деле нужно было просто внимательнее читать официальную документацию Telegram Bot API.  Есть такой метод forwardMessage - он позволяет переслать сообщение, и не важно, что в нем текст, стикер или медиа, бот просто его перенаправит в тот чат в какой укажете. Этим методом и воспользуемся. Пользователю мы будем просто отвечать на его сообщение, используя для этого доступную функцию "Ответить" в контекстном меню интерфейса приложения Телеграм, специального кода для этого не нужно. 

Плюсы от использования:

  1. Когда сообщение переслано, то в нем видно кто написал, и даже если у пользователя нет @userName мы сможем посмотреть его профиль;
  2. Когда мы отвечаем на сообщение, то видим в общем списке сообщений на что мы ответили.
Сторона пользователя
Сторона пользователя
Отвечаем на сообщение пользователя
Отвечаем на сообщение пользователя
Сторона администратора
Сторона администратора

* * *

Пишем логику бота обратной связи

В момент старта - бот отправляет нам сообщение с текстовым сообщением /start. Нам надо это сообщение поймать и обработать, например, поздороваться с пользователем, дать ему понять, что бот готов к работе. А если стартуем админ, то просто сообщить ему, что бот готов. 

Давайте напишем несколько вспомогательных методов для нашего класса Bot

<?php
    // проверим кто пишет админ или нет
    private function isAdmin($id) {
        return ($id == $this->adminId) ? true : false;
    }
    // проверим на начало диалога с ботом
    private function isStartBot($data) {
        return ($data['message']['text'] == "/start") ? true : false;
    }
?>

Настало время поговорить о том, как отправить сообщение через бот. За это отвечает целый набор методов Telegram Bot API, перечислю только те, которые мы будем использовать в рамках этой статьи:

  1. sendMessage - текстовое сообщение
  2. sendPhoto - фотография
  3. sendAudio - аудио-файл
  4. sendDocument - документ
  5. sendVideo - видео-файл
  6. sendSticker - стикер

Telegram Bot API принимает как POST так и GET HTTP-запросы. Мы напишем метод, который будет оправлять POST запрос используя возможности CURL

<?php
    // передаем массив данных, id чата, и метод передачи данных
    private function requestToTelegram($data, $chat_id, $type) {
        $result = null;
        // id чата куда отправляем
        $data['chat_id'] = $chat_id;
        if (is_array($data)) {
            // инициализируем CURL
            $ch = curl_init();
            // укажем url доставки запроса
            curl_setopt($ch, CURLOPT_URL, "https://api.telegram.org/bot".$this->botToken.'/'.$type);
            // скажем что хотим POST запрос отправить
            curl_setopt($ch, CURLOPT_POST, count($data));
            // Генерирует URL-кодированную строку запроса
            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
            // Выполняем CURL 
            $result = curl_exec($ch);
            // закрываем CURL
            curl_close($ch);
        }
        return $result;
    }
?>

Добавим еще пару свойств и изменим наш публичный метод init(), опишем в нем действия если пришло сообщение о начале диалога с ботом. В добавленных свойствах будет приветственное слово: одно для админа, другое для пользователя. И еще один метод для замены в приветственном сообщении для пользователя {username} на имя пользователя из полученных данных при помощи функции str_replace(), это придаст приветствию персонализацию. 

<?php
    // Приветствие для админа при старте
    private $helloAdmin = "Начинаем ждать сообщений от пользователей.";
    // Приветствие для пользователя при старте
    private $helloUser = "Приветствую Вас {username}.\nЯ очень жду вашего сообщения.\n------\nСпасибо.";

    public function init($data) {
        // создаем массив из пришедших данных от API Telegram
        $arrData = $this->getData($data);
        // Определяем id отправителя
        $chat_id = $arrData['message']['chat']['id'];
        // если это Старт
        if($this->isStartBot($arrData)) {
            // Определяем id чата куда будем отправлять админу или пользователю
            $chat_id = $this->isAdmin($chat_id) ? $this->adminId : $chat_id;
            // Выводим приветственное слово
            $hello = $is_admin ? $this->helloAdmin : $this->setTextHello($this->helloUser, $arrData);
            // Отправляем приветственное сообщение
            $this->requestToTelegram(array("text" => $hello), $chat_id, "sendMessage");
        } else {
            // Если это не старт
        }
    }

    private function setTextHello($text, $data) {
        // узнаем имя и фамилию отправителя
        $username = $this->getNameUser($data);
        // подменяем {username} на Имя и Фамилию
        return str_replace("{username}", $username, $text);
    }

    // получаем name и surname пользователя
    private function getNameUser($data) {
        return $data['message']['chat']['first_name'] . " " . $data['message']['chat']['last_name'];
    }
?>

Теперь давайте опишем действия если это уже очередное сообщение, а не начало диалога с ботом, оно может быть, как от пользователя, так и от админа. Следующий код - это обработка сообщения от пользователя - перенаправление сообщения администратору - здесь все просто: создаем массив с обязательными параметрами для метода forwardMessage и передадим в наш метод для отправки запроса в API. 

<?php
    // Если это не старт
    if($this->isAdmin($chat_id))  {
        // Здесь далее будет код если сообщение отправляет админ

    } else {
        // Если это написал пользователь то перенаправляем админу
        $dataSend = array('from_chat_id' => $chat_id, 'message_id' => $arrData['message']['message_id']);
        $this->requestToTelegram($dataSend, $this->adminId, "forwardMessage");
    }
?>

Чтобы пользователь получил от бота сообщение, боту нужно сказать в какой чат отправлять, узнаем id чата пользователя из специального параметра

​$data['message']['reply_to_message']['forward_from']['id']

Добавим несколько проверок

Исключим ситуацию когда админ может забыть использовать в контекстном меню команду "Ответить", для этого нужно сделать проверку, и в таком случае вывести предупреждение, добавим еще одно свойство в котором будет текст предупреждения, и метод в котором будем проверять наличие ключа reply_to_message с помощью функции array_key_exists(), это ключ скажет нам, что это ответ на чье-то сообщение

<?php
    private function isReply($data) {
        return array_key_exists('reply_to_message', $data['message']) ? true : false;
    }
?>

Обработаем еще одну ситуацию, когда админ по ошибке может начать отвечать на сообщение бота. Согласитесь такое ведь тоже может быть, у меня было )) поэтому и родилась эта проверка. Когда сообщение прислал бот (это может быть предупреждение или приветствие для админа) то это можно определить проверив значение ['from']['is_bot'] оно будет равно единице. Вторым условием в проверке исключим ситуацию, когда бот пересылает сообщение пользователя, потому что при ответе на сообщение пользователя, в служебных данных будет присутствовать флаг, определяющий отправителя как бота.

<?php
    private function isBot($data) {
        return ($data['message']['reply_to_message']['from']['is_bot'] == 1
            && !array_key_exists('forward_from',$data['message']['reply_to_message']));
    }
?>

Опишем обработку отправки сообщения пользователю от админа, здесь нам нужно сначала определить, что мы будем отправлять: текст, документ, картинку, стикер, аудио или видео. Для администратора это сделает интерфейс Телеграма, боту же нужно использовать методы Telegram Bot API. У каждого метода API есть свои обязательные параметры. Создадим свой метод, который будет понимать, что отправил админ, заполнит необходимые параметры и предаст их в метод для отправки запроса в Telegram с соответствующей командой.

<?php
    private function getTypeCommand($data)
    {
        // определяем id пользователя для уведомления
        $chat_id = $data['message']['reply_to_message']['forward_from']['id'];
        // если текст
        if (array_key_exists('text', $data['message'])) {
            // готовим данные
            $dataSend = array(
                'text' => $data['message']['text'],
            );
            // отправляем - передаем нужный метод
            $this->requestToTelegram($dataSend, $chat_id, "sendMessage");
        } elseif (array_key_exists('sticker', $data['message'])) {
            $dataSend = array(
                'sticker' => $data['message']['sticker']['file_id'],
            );
            $this->requestToTelegram($dataSend, $chat_id, "sendSticker");
        } elseif (array_key_exists('document', $data['message'])) {
            $dataSend = array(
                'document' => $data['message']['document']['file_id'],
                'caption' => $data['message']['caption'],
            );
            $this->requestToTelegram($dataSend, $chat_id, "sendDocument");
        } elseif (array_key_exists('photo', $data['message'])) {
            // картинки Телеграм ресайзит и предлагает разные размеры, 
            // мы берем самый последний вариант
            // так как он самый большой - то есть оригинал
            $img_num = count($data['message']['photo']) - 1;
            $dataSend = array(
                'photo' => $data['message']['photo'][$img_num]['file_id'],
                'caption' => $data['message']['caption'],
            );
            $this->requestToTelegram($dataSend, $chat_id, "sendPhoto");
        } elseif (array_key_exists('video', $data['message'])) {
            $dataSend = array(
                'video' => $data['message']['video']['file_id'],
                'caption' => $data['message']['caption'],
            );
            $this->requestToTelegram($dataSend, $chat_id, "sendVideo");
        } else {
            // другие тип не поддерживаем
            $this->requestToTelegram(array("text" => "Тип передаваемого сообщения не поддерживается"), $chat_id,"sendMessage");
        }
    }
?>

И заключительная часть - это отправка и реализация проверок сообщений от администратора к пользователю

<?php
    if($this->isReply($arrData)) {
        // если ответ самому себе
        if($this->isAdmin($arrData['message']['reply_to_message']['from']['id'])) {
            $this->requestToTelegram(array("text" => "Вы ответили на свое сообщение."), $this->adminId, "sendMessage");
        } elseif ($this->isBot($arrData)) {
            // если ответ боту
            $this->requestToTelegram(array("text" => "Вы ответили на сообщение Бота."), $this->adminId, "sendMessage");
        } else {
            // все нормально отправляем на обработку
            $this->getTypeCommand($arrData);
        }
    } else {
        // нажать кнопку ответить
        $this->requestToTelegram(array("text" => $this->answerAdmin), $this->adminId, "sendMessage");
    }
?>

* * *

Подводим итоги

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

botFeedBack.php.zip
2.6
54 комментария
Авторизуйтесь через Telegram, чтобы оставить комментарий.
Откройте по ссылке или QR бот @iMakeBot, нажмите кнопку Старт/Start.
Следуйте инструкциям бота.

  • Vyacheslav Koval [5 лет назад]

    Спасибо большое за статью!

  • nun [4 года назад]

    А как php привязать к боту?

  • iMakeBots [4 года назад → nun]

    Не совсем правильный вопрос. Бот по сути это приложение - его можно написать с использованием разных языков программирования, в том числе и на php.

  • Arteater ✏️ [4 года назад]

    Большое спасибо за статью и бота. Подскажите, а как запустить? Я очень слаб во всем этом. Есть опыт работы с ботами через веб хук. фа как тут быть. При обращении к телу бота напрямую из хостинга выдало:

    {"ok":false,"error_code":400,"description":"Bad Request: chat_id is empty"}

    Я что-то пропустил?

  • iMakeBots [4 года назад → Arteater ✏️]

    Вы как вызываете бота через браузер? Ошибка простая - в теле запроса отсутствует chat_id - то есть Телеграм ругается потому что не знает куда направлять сообщение - в какой чат.

  • Arteater ✏️ [4 года назад → iMakeBots]

    Бота вызвал через прямой путь к нему)

  • iMakeBots [4 года назад → Arteater ✏️]

    )))) так не получиться.Приложение получает необходимые параметры из направленных ему Телеграмом набором данных через webHook или getUpdates

  • Arteater ✏️ [4 года назад → iMakeBots]

    Фух, запустил, спасибо огромное! Проблемы с вебхук были.

  • iMakeBots [4 года назад → Arteater ✏️]

    Отлично))

  • Vladimir Belyaev [3 года назад → iMakeBots]

    Не могу понять как связывается именно конкретный файл php с конкретным ботом. Откуда Телеграм понимает что если пришло сообщение боту, нужно дернуть именно конкретный файл php?

  • Vladimir Belyaev [3 года назад → Vladimir Belyaev]

    Нашел

    https://api.telegram.org/botYOUR-TOKEN/setWebhook?url=https://<YOURWEBSITE>/<YOUR_PHP_URL>
  • Arteater ✏️ [4 года назад → iMakeBots]

    А бот в телеграм просто молчит. Хотя токен вроде верный.

  • iMakeBots [4 года назад → Arteater ✏️]

    Нужно искать ошибки в логах. Возможно неправильно настроены webHook или SSL сертификат отсутствует.

  • Arteater ✏️ [4 года назад → iMakeBots]

    SSl сертификат есть. На этом сервере уже один бот работает.

  • iMakeBots [4 года назад → Arteater ✏️]

    Версия php?

  • Arteater ✏️ [4 года назад → iMakeBots]

    7.2

  • iMakeBots [4 года назад → Arteater ✏️]

    Нужно тогда смотреть логи - какая там информация.

  • Arteater ✏️ [4 года назад → iMakeBots]

    Я бы с радостью посмотрел. Но они не появились. Что странно.

  • iMakeBots [4 года назад → Arteater ✏️]

    Сложно диагностировать к сожалению не имея возможности дебажить. Попробуйте оставить в точке входа (index.php) прием данных ('php://input') от Телеграм и запишите их в файл.

    Если запись идет - значит webHook настроен правильно, тогда продолжайте искать причину дальше - шаг за шагом. например отправьте тестовое сообщение в ответ.

  • Arteater ✏️ [4 года назад → iMakeBots]

    Хорошо спасибо. буду искать

  • Arteater ✏️ [4 года назад → iMakeBots]

    И последний вопрос. Я правильно понимаю, что в боте нужно только 2 строчки отредактировать с user id и бот токен? Я ничего не пропустил?

  • iMakeBots [4 года назад → Arteater ✏️]

    Да: токен и admin_id

  • Dilshod Abdujalilov [4 года назад]

    определяем id пользователя для уведомления - не работает

  • iMakeBots [4 года назад → Dilshod Abdujalilov]

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

  • Psycho [3 года назад]

    Бот работает, но почему то не создается никакой лог файл

  • Freddy Krueger [3 года назад → Psycho]

    Так он и не должен создавать лог файл

  • Админ [3 года назад]

    Ответ пользователю не работает если у него в настройках безопасности стоит 

    Пересылка сообщений: Никто

    Можно это как то исправить?

  • iMakeBots [3 года назад → Админ]

    Исправить можно.

    Переписать логику перенаправления и ответа на сообщение.

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

    И при ответе на сообщение админом считывать необходимую информацию - в том числе и id пользователя.

  • Абдукарим Худайберганов [1 год назад → iMakeBots]
    $dataSend2 = array(
        'chat_id' => $data['message']['reply_to_message']['forward_from']['id'],
        'message_id' => $data['message']['message_id'],
        'from_chat_id' => $data['message']['from']['id'],
    );
    
    // отправляем - передаем нужный метод
    $this->requestToTelegram2($dataSend2, "copyMessage");
    
    // а в функции убрал строку $data['chat_id'] = $chat_id;
    
    private function requestToTelegram2($data, $type) {
        $result = null;
        if (is_array($data)) {
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $this->apiUrl . $this->botToken . '/' . $type);
            curl_setopt($ch, CURLOPT_POST, count($data));
            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
            $result = curl_exec($ch);
            curl_close($ch);
        }
        return $result;
    }
    

    Работает. только появился сомнение

  • k k [3 месяца назад → iMakeBots]

    Сделал пересылку копию сообщения, в тело сообщения вставляется ID пользователя. Если ID пользователя скопировать и отправить боту. то он поймет куда переслать то, что ему отправил админ. Но если нажать именно "ответить" то бот не может считать ID пользователя в тексте сообщения на которое отвечаю. То есть бот не может добраться до цитаты и взять оттуда текст. Может у Вас есть мысли как сделать чтобы нажав на кнопку "ответить" бот смог добраться до содержимого сообщения на которое получает ответ.

  • iMakeBots [3 месяца назад → k k]

    https://imakebots.ru/article/bot-obratnoy-svyazi-bez-hostinga-google-apps-script-telegram-bot-api

    Посмотрите там есть пример обход блокировки пересылки. Может развернуть бота и на примере посмотреть.

  • k k [3 месяца назад → iMakeBots]

    спасибо

  • k k [3 месяца назад → k k]

    Нашел по ссылке ответ - $data['message']['reply_to_message']['text'] это текст сообщения на которое отвечаешь. Бот к нему имеет доступ и там можно забрать ID.  у Вас по ссылке это this.bot.data.message.reply_to_message.text

  • Roman [3 года назад]

    Заменил admin_id и токен, начал выдавать ошибку

    {"ok":false,"error_code":400,"description":"Bad Request: parameter "from_chat_id" is required"}

    Если там вписать id админа, что куда направлять сообщение, то ругается и выплевывает ошибку

    {"ok":false,"error_code":400,"description":"Bad Request: message to forward not found"}

    И как с этим быть? Заранее благодарю

  • Дмитрий [3 года назад]

    если в настройках безопасности стоит 

    Пересылка сообщений: Никто

    то бот отвечает сам себе

  • iMakeBots [3 года назад → Дмитрий]

    Комментарием выше есть решение.

  • Дмитрий [3 года назад → iMakeBots]
  • iMakeBots [3 года назад → Дмитрий]

    Да

  • Дмитрий [3 года назад → iMakeBots]

    Я не силен в том чтобы переписывать логику. Спасибо

  • Вадим [2 года назад → iMakeBots]

    Пожалуйста исправьте в примере, не работает с закрытым профилем.

  • Jay Gatsby [2 года назад]

    Отличный бот, спасибо!

    Можно ли сюда добавить автоответ на определенные слова или добавить кнопки в меню, типа Адреса и Часто задаваемые вопросы, а в ответ соответственно заготовка, что не было нужды каждый раз отвечать на одно и тоже.

    Если это возможно, будьте добры написать пример кода, спасибо

  • iMakeBots [2 года назад → Jay Gatsby]

    Спасибо. В этот пример бота можно добавить все, что необходимо - Телеграм АПИ в этом плане гибкий. К сожалению времени на дополнения сейчас нет.

  • Vano Kako [2 года назад]

    Что-то туплю :(

    Что нужно послать в канал, чтобы бот ответил картинкой?

  • Sergey Michaylovich [2 года назад]

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

  • Sergey Michaylovich [2 года назад]

    Каким образом осуществляется взаимодействие между сайтом, ботом, телеграмом?
    То есть каким образом движется запрос и ответ?
    Пользователь отправил текст/нажал кнопку в телеграм боте запрос ушел куда, что и каким образом происходит дальше?
    Предполагаю, что через вебхук на адрес апи телеграмма пошел зарпос, правильно?
    Для этого чтобы этот сервер апи телеграмма понимал что это запрос от такого юота мы его регистрируем с помощью вебхука?
    Как и где посмотреть состояние текущего запроса?
    Через лог файл, но он не создается даже при запуске кода из архива к этой статье(токен и админ ид-р разумеется указал).
    Или через браузер?
    Тогда по какому адресу?

    Хостинг использую также timeweb, сертифтикат установил бесплатный.

  • Sergey Michaylovich [2 года назад]

    В предлагаемом архиве для скачивания нет метода для записи в лог файл.

    Скопировал из статьи соответвующий метод.

    Получал при каждом запросе строку php://input в лог файле

    Переделал метод

    Вроде заработало, но в лог фал пока добавляется в конец новый запрос, а не перезаписывается, это правильно?!

    Правильно ли я внес следующие изменения в скачанный архив.

    /**
    * Парсим что приходит преобразуем в массив
    * @param $data
    * @return mixed
    */
    private function getData($data)
    {
        $this->setFileLog($data);
        return json_decode(file_get_contents($data), TRUE);
    }
    
    private function setFileLog($data) {
        $data = json_decode(file_get_contents($data), TRUE);
        $fh = fopen('log.txt', 'a') or die('can't open file');
        ((is_array($data)) || (is_object($data))) ? fwrite($fh, print_r($data, TRUE)."n") : fwrite($fh, $data . "n");
        fclose($fh);
    }

    Заранее спасибо!

  • iMakeBots [2 года назад → Sergey Michaylovich]

    Совершенно правильно сделали, что взяли метод логирования из статьи, он в статье как раз для этого и был описан.

  • Gigalit [7 месяцев назад]

    При авторизации с помощью iMakeBot в Google Chrome увидел на странице вашего сайта свое имя, а вот в FireFox это не работает. В чем может быть проблема?  

  • iMakeBots [7 месяцев назад → Gigalit]

    Протестил в FF только что - все норм. Не подскажу, так как надо смотреть на вашей стороне. Но там нет ничего, что могло бы конфликтовать. После авторизации идет перезагрузка страницы, и если в браузере есть авторизация то имя выводится из бд в шаблон страницы.

  • Gigalit [7 месяцев назад → iMakeBots]

    1. Провел эксперимент с FF второй раз - результат положительный ;)

    Вижу, что у вас ссылка/кнопка на iMakeBot передает секретный код типа "0d98...57d8", по которому потом происходит в базе идентификация с кукой выставленной на сайте. Если не секрет, какое время жизни этого кода? Оно совпадает с временем куки?

    2. В статьях такого рода хотелось бы слышать и несколько слов о безопасности. Например, вебхук вашего бота имеет простой вид, типа https://imakebots.ru/bots/index.php

    Эту ссылку могут дёргать не только сервера Telegram, но в принципе кто угодно, при этом отправляя JSON-код с подставными данными (с вытекающими негативными результатами). Ставите защиту от такого?

  • iMakeBots [7 месяцев назад → Gigalit]

    1. Отлично

    Передает не секретный код, а просто сгенерированную одноразовую строку, для индентификации в бд, эта строка не хранится в бд или перегенерируется

    2. Про какую статью вы имеете в виду и с чего вы взяли что вебхук моего бота имеет такой вид?

  • Gigalit [7 месяцев назад → iMakeBots]

    1. Пока посетитель не зашел в бот страница циклически посылает запросы к серверу (проверяя, пришел ли код от бота). Пока этот код (параметр start в "сгенерированной одноразовой строке") не пришел, он должен где-то храниться, например, в БД, в файле или буквально в PHP-сессии.

    Я хочу сделать аналогичный механизм, интересует практическое время хранения кода.

    2. Я сказал слово НАПРИМЕР. Кстати, в вашей статье "Регистрируем бот у @BotFather, устанавливаем WebHook" так и написано: ...setwebhook?url=https://ВАШ_ДОМЕН/bots/index.php

    Многие ведь так и сделают ;)

    Сейчас вопрос о вариантах защиты при вызовах данного URL.

  • iMakeBots [7 месяцев назад → Gigalit]

    Обсуждение не про данную статью, есть на сайте по теме статья и не совсем место это здесь обсуждать. Просьба, откройте ветку на форуме.

    1. Код не храниться в бд, алгоритм простой:

    Генерируется код, идет запрос AJAX на проверку наличия этого кода в бд. Если его нет значит пользователь не авторизовался.

    Пользователь когда проходит по ссылке для авторизации - этот код передается в бот, бот передает на сервер мета данные пользователя с кодом, идет запись в бд

    Далее запрос AJAX находит запись с этим кодом в бд, идет 3 процедуры - удаляется проверочный код из бд (null или новое значение тут на выбор), идет авторизация пользователя в системе и перезагружается страница откуда вызов. При загрузке страницы если пользователь авторизован то ему доступны доп возможности.

    2. Этой статье уже более 5 лет )) на тот момент я совсем по-другому работал - сам так делал.

    Для проверки вы можете использовать один из предложенных вариантов самого Телеграм:

    If you'd like to make sure that the webhook was set by you, you can specify secret data in the parameter secret_token. If specified, the request will contain a header “X-Telegram-Bot-Api-Secret-Token” with the secret token as content.

    https://core.telegram.org/bots/api#setwebhook

  • Gigalit [7 месяцев назад → iMakeBots]

    “X-Telegram-Bot-Api-Secret-Token” - классная штука. Я недавно начал писать боты и как-то не заметил этого параметра в документации. Проверил, работает. Спасибо за совет, теперь я спокоен! ;)