
Первая часть. Общие вопросы — https://habr.com/ru/articles/1047336/
Вторая часть. Установка библиотеки и пример работы с ней — https://habr.com/ru/articles/1048882/
В сегодняшней публикации планировалось просто сделать вторую часть учебной задачи, посвящённую загрузке файлов. Но так сложилось, что в библиотеке методы загрузки были только написаны и ввиду отсутствия "боевого применения" на моих проектах не проверялись должным образом на практике. А проверки по ходу работы над учебным примером кода показали, что библиотека в части загрузки файлов требует существенной доработки, если её делать строго так, как описано в официальной документации. Соответственно библиотека была доведена до ума, учебный пример был много раз прогнан на разных типах файлов, и только сейчас я могу говорить, что код библиотеки в части функционала загрузки файлов живой и работающий. А попутно захотелось поделиться с начинающими разработчиками своих библиотек поднабитыми шишками. Это и сделаю сначала, а дальше разберём собственно загрузку файлов через библиотеку.
Скрытый текст
Лирически-теоретическое отступление про загрузку файлов
Загрузка файлов осуществляется в два этапа — получение ссылки на загрузку и собственно загрузка файла, в результате (или до) которой выдаётся строковой токен файла, передаваемый в объект вложений к сообщению. Но нормально документировано из них только получение ссылки. А по собственно загрузке файлов запросы идут на разные сервисы в зависимости от типа. И ответы на них, что называется, «кто в лес, кто по дрова». По-видимому, связано это с тем, что в зависимости от типа загружаемого файла загрузка осуществляется в файловые хранилища разных проектов группы VK, которые разрабатываются и поддерживаются разными командами — каждая как знает и как умеет. Подготовил табличку с информацией о том, что возвращается в ответ на запрос собственно загрузки файла.
Тип загрузки | Тип ответа | Содержимое ответа | Примечание |
| JSON | Объект | |
| XML-подобноэ |
| Токен выдаётся сразу в ответе первого запроса (параметр |
| JSON | Объект со свойствами |
В библиотеке, конечно, эти все ответы обрабатываются автоматически, и токен забирается из одного параметра вне зависимости от типа загружаемого файла. Полагаю, рекомендация коллегам-разработчикам библиотек поступать аналогично не будет ошибкой.
Вернёмся к учебной задаче
В прошлой части мы договорились, что приложение, с которым работает библиотека, у нас по умолчанию установлено в каталоге /var/maxbot. Здесь и в последующих частях это соглашение также будет соблюдаться; все примеры будут из этого исходить.
Прежде чем продолжать, библиотеку нужно обновить. С момента выхода прошлой части там был исправлен ряд багов.
Также, согласно документации, API-запрос GET /chats начиная с июня 2026 года поддерживаться перестал. Поэтому из библиотеки были удалены объекты запроса lubezniy\yii2max\request\GetChats
и ответа на него
lubezniy\yii2max\response\GetChatsResponse
Кроме того, для сегодняшнего примера в каталог examples/tutorial/files добавлены файлы всех видов, один из которых мы используем в сегодняшнем примере для загрузки с типом file; на других файлах вы дополнительно можете отработать загрузку самостоятельно.
Для обновления либы переходим в её каталог и гитом вытягиваем свежую ветку main:
cd /var/maxbot/vendor/lubezniy/Yii2-max git pull
Как загружать файлы через библиотеку
Для вызова соответствующих функций библиотеки нам нужны три вещи:
тип загружаемого файла согласно документации Bot API;
MIME-тип файла;
полное имя файла в файловой системе.
Конечно, тип из первого пункта списка частично можно определить по MIME-типу. Но это если бы не тип file . Хотим отправить фото или видео как файл - надо тоже указывать file , а не image или video . Возможно, в будущем для тех, кто не хочет заморачиваться, сделаю общий метод с автоприсвоением типа. А пока как есть.
Последовательность процедуры загрузки такова:
Методом модуля
createRequestсоздаём запрос классаlubezniy\yii2max\request\UploadFilePrepare. В его параметрtypeвписываем тип загружаемого файла из документации (первый пункт перечня необходимого).Как обычно, отправляем запрос методом
sendбез параметров. Метод, если не будет ошибок, вернёт в ответ объект классаlubezniy\yii2max\response\UploadFilePrepareResponse. Созданный объект нужно обязательно запомнить в какой-нибудь переменной. Это не совсем обычный тип ответа; у него есть дополнительный методprocessUpload, реализующий собственно отправку запроса на загрузку файла. И этот метод нужно вызвать для реализации второго этапа загрузки. В параметры метода передаются сначала полное имя загружаемого файла, затем его MIME-тип. Третьим необязательным параметром можно указать имя файла, под которым файл будет загружен в файлохранилище MAX. Результат выполнения этого метода нас интересует мало, его можно даже не запоминать - просто ловим исключения при ошибке.После выполнения обоих этапов загрузки осталось только получить токен загруженного файла для подстановки в сообщение. В зависимости от типа файла он появляется или после первого, или после второго этапа, но всегда находится в свойстве
tokenобъекта классаUploadFilePrepareResponse.Рекомендация — забирать его значение после выполнения второго этапа; так оно точно будет присутствовать на месте.
Примечание: Документация по API говорит нам о том, что видеофайлы после загрузки проходят ещё процесс подготовки. И, если попытаться отправить сообщение с вложением до окончания этого процесса (на больших видео он может занимать довольно значительное в масштабах исполнения веб-приложения время), то отправка сообщения вернёт ошибку. Сам пока не сталкивался с загрузкой больших видео и не могу сказать чего-либо конкретного на эту тему. Но эти моменты явно надо иметь в виду при реализации своих проектов и не торопиться отправлять сообщение с вложением сразу после загрузки большого видеофайла. Хотя бы несколько секунд стоит подождать.
Наконец, практическая реализация в учебной задаче
Надеюсь, вы ещё не потёрли с прошлой публикации файл /var/maxbot/commands/MaxLearnController.php . Идём в каталог приложения и запускаем этот файл на редактирование:
cd /var/maxbot nano commands/MaxLearnController.php
В конец файла, в строку между двумя последними закрывающими фигурными скобками (если её нет, то нужно добавить пустую), вписываем action загрузки файла (в примере загрузим docx и выведем на экран полученный токен):
/** * Шаг 2. Пример загрузки файла * @return int */ public function actionStep2(): int { // Загрузка файла /** * @var \lubezniy\yii2max\Module $module Модуль бота */ /** * @var \lubezniy\yii2max\request\UploadFilePrepare $request * Объект запроса на первый этап загрузки */ /** * @var \lubezniy\yii2max\response\UploadFilePrepareResponse $prepareResult * Объект ответа на первый этап и на всю загрузку */ $module = Yii::$app->getModule('maxbot', true); // Создаём объект запроса на первый этап $request = $module->createRequest([ 'class' => \lubezniy\yii2max\request\UploadFilePrepare::class, 'type' => 'file', ]); // Отправляем запрос, запоминаем результат $prepareResult = $request->send(); // и пробуем загрузить файл $prepareResult->processUpload( __DIR__ . '/../vendor/lubezniy/Yii2-max/examples/tutorial/files/docxfile.docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'docxfile.docx' ); // Выводим токен загруженного файла $this->stdout("Uploaded file token is " . $prepareResult->token . "\n"); return ExitCode::OK; }
Если хотите поэкспериментировать с другими типами файлов, можно поменять реквизиты при необходимости. Ещё несколько файлов на пробу лежит в репозитории библиотеки; можно прописывать даже относительный путь к ним, как описано в коде. А пока сохраняем файл, выходим из редактора и проверяем, что у нас получилось:
php yii max-learn/step2
Если всё правильно, то в результате мы увидим на экране сообщение с токеном загруженного файла. Токен просьба записать на будущее; он пригодится в следующий раз, когда мы к кнопкам отправленного сообщения добавим загруженный файл.
Подытожим
Сегодняшний материал получился узкоспециализированным и относительно небольшим, но работа по нему, надеюсь, окажется кому-то полезной. В следующем материале будем разбирать редактирование сообщений и опробуем создание сообщений с разными категориями и количеством вложений. Может быть, и библиотеку снова придётся доработать, если в этот раз чего-то не учёл. Освоение и тестирование продолжаются.
