Получение ботом медиа-файлов и сохранение их на своем сервере

Как сохранить присланный боту медиа-файл? Рассмотрим на примере картинки, но принцип для остальных форматов одинаковый. Скачаем картинку на наш сервер.

В своей работе над ботом, который проводит розыгрыши, мне потребовалось сохранять у себя на сервере файлы, присылаемые пользователями.  Очень интересный и простой процесс получился.

У Telegram Bot Api для этого есть специальный метод getFile. На входе он получает file_id, на выходе объект File.

Параметров file_id у картинки может быть больше одного, потому как телеграм присылает несколько вариантов размеров картинки, последний всегда оригинал. При загрузке картинки в бот приходит информация в виде объекта Photo, в котором лежит массив объектов PhotoSize

Наш бот будет принимать только команду /start и картинку, на остальные запросы он будет "ругаться".  Чтобы определить, что нам пришло в нашем уже знакомом по предыдущим статьям методе init() будем проверять ключи массива пришедших данных. Для реализации задуманного нам нужен только объект Message

<?php
    // проверяем если пришло сообщение
    if (array_key_exists('message', $data)) {
        //если пришла команда /start
        if ($data['message']['text'] == "/start") {
            $this->sendMessage($chat_id, "Приветствую! Загрузите картинку.");
        } elseif (array_key_exists('photo', $data['message'])) {
            // если пришла картинка то сохраняем ее у себя
            $text = $this->getPhoto($data['message']['photo'])
                ? "Спасибо! Можете еще загрузить мне понравилось их сохранять."
                : "Что-то пошло не так, попробуйте еще раз";
            // отправляем сообщение о результате   
            $this->sendMessage($chat_id, $text);
        } else {
            // если пришло что-то другое
            $this->sendMessage($chat_id, "Не понимаю команду! Просто загрузите картинку.");
        }
    }
?>

Картинки мы будем сохранять в директории img, располагается она рядом с файлом index.php в котором наш код.

.
..
[ img ]
index.php

В случае если прислали картинку, то мы передаем массив объектов PhotoSize в метод getPhoto(), он вернет результат в boolean. Внутри метода происходит 2 действия:

  1. через метод getPhotoPath() получаем расположение файла на сервере Telegram
  2. через метод copyPhoto() копируем картинку к себе на сервер

Картинка располагается на сервере Telegram по стандартному пути:

https://api.telegram.org/file/bot<token>/<file_path>

Выводит картинку по этому пути где-либо в сети не рекомендую, так как будет доступен ваш токен от бота. 

Сохранять себе на сервер мы будем оригинал, поэтому нам надо узнать количество элементов в массиве, использовать будем функцию count()

Чтобы получить расширение файла, будем разбивать file_path в массив по знаку . функцией explode() и брать последний элемент используя функцию end(). Для копирования файлов пользуемся функцией copy().

<?php
    // общая функция загрузки картинки
    private function getPhoto($data)
    {
    	// берем последнюю картинку в массиве
        $file_id = $data[count($data) - 1]['file_id'];
        // получаем file_path
        $file_path = $this->getPhotoPath($file_id);
        // возвращаем результат загрузки фото
        return $this->copyPhoto($file_path);
    }

    // функция получения метонахождения файла
    private function getPhotoPath($file_id) {
    	// получаем объект File
        $array = json_decode($this->requestToTelegram(['file_id' => $file_id], "getFile"), TRUE);
        // возвращаем file_path
        return  $array['result']['file_path'];
    }

    // копируем фото к себе
    private function copyPhoto($file_path) {
    	// ссылка на файл в телеграме
        $file_from_tgrm = "https://api.telegram.org/file/bot".$this->botToken."/".$file_path;
        // достаем расширение файла
        $ext =  end(explode(".", $file_path));
        // назначаем свое имя здесь время_в_секундах.расширение_файла
        $name_our_new_file = time().".".$ext;
        return copy($file_from_tgrm, "img/".$name_our_new_file);
    }
?>

* * *

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

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

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

  • wo.rez [5 лет назад]

    А можете подсказать чтобы бот вместе с успешной загрузкой выводил ещё и линк на загруженный файл?

  • iMakeBots [5 лет назад → wo.rez]

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

  • Ильяс [4 года назад]

    Привет. Я писал код с нуля, не используя ничего. У вас тут есть функция requestToTelegram, не могу понять где ее можно взять, немного не понятно(

  • iMakeBots [4 года назад → Ильяс]

    В архиве приложенном к статье есть файл index.php - в нем есть класс Bot в этом классе последний метод

    /** Отправляем запрос в Телеграмм
     * @param $data
     * @param string $type
     * @return mixed
     */
    private function requestToTelegram($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_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
            $result = curl_exec($ch);
            curl_close($ch);
        }
        return $result;
    }
  • Winer [3 года назад]

    можно готовый билд ?

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

    В статье файл, это уже готовый билд

  • Александр Alex [3 года назад]

    Здравствуйте, а на ftp сервер загрузить можно и какой командой, чтоб успел загрузиться файл. Спасибо.

  • Шардик [3 года назад]

    А как переслать сразу файл в группу , не сохраняя на сервере, подскажите пожалуйста?

  • Шардик [3 года назад → Шардик]

    и как отправить видеофайл/GIF? подстановка video вместо photo не решает задачу

  • iMakeBots [3 года назад → Шардик]

    Попробуйте применить нужный метод отправки файла. Для video использовать sendVideo ... тд

    GIF - может быть также type = animation

  • iMakeBots [3 года назад → Шардик]

    При получении файла у вас будет в массиве данных его file_id, используя методы отправки файлов Телеграм, направьте этот файл в нужный вам чат - бот при этом должен быть участником группы с необходимым набором прав.

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

    Эххх... Этот код бы перевести в Python... Кому под силу это сделать?

  • Aleksandr Bigun [3 года назад]

    С чем может быть связано, что 

    https://api.telegram.org/file/bot<token>/<file_path>

    стал отдавать код ошибки 404 спустя неделю работы?

    Новые файлы телеграм отправляет, выдает id файлов, но их по ссылкам на api.telegram нет

  • Boris Spirin [2 года назад]

    Привет, Хороший Человек!

    Отличный сайт...

    А как можно сохранять себе не оригинал, а сжатую телеграмом картинку, или задать размеры сохраняемой картинки?

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

  • iMakeBots [2 года назад → Boris Spirin]

    Телеграм отправляет массив file_id картинок, каждый из которой имеет разные размеры, в первом элементе массива лежит файл с самым маленьким по сторонам размерам, в последнем элементе массива лежит оригинальный размер загруженной картинки.

    При сохранении картинки на сервере - вы можете указать любое название, в том числе и id пользователя.

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

    Здравствуйте!
    Я запустил этот код, изменил только токен бота, ид-р админа, внес брекпоинты для отладки.

    Почему в данном коде есть ошибка при отправке боту простого изображения с форматом png?

    А именно ошибка при получении пути файла по его ид-ру файла.

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

    может быть из-за того, что файл на латинском языке имеет название?хотя я загружал и с именем на кириллице и на латинице.