В этой статье я расскажу как уменьшить размер картинки в Живой ленте Битрикс24 при загрузке пользователем.
Вся история с ресайзом картинок в живой ленте началась с шутки. Однажды, зимним холодным утром, подошел ко мне тимлид и говорит:
«Почему главная страница нашего корп портала так долго грузится, несмотря что она находится в локальной сети?».
«Ну так пользователи грузят картинки по 6 мб. Вот …., только в этом посте 20 картинок размером с 1-6 мб.» — отвечаю я.
«Ну так отресайз картинки при загрузке. В чем проблема?»
«Ресайз?! В Живой ленте? Чтобы сделать это понадобиться месяц» — пошутил я.
«Месяц?!… Даю два дня, не больше.» — грозно сказал он.
Про месяц я, конечно же, пошутил. Но, как говорится, в каждой шутке…
Проблема с большим размером картинок в живой ленте в компании существовало давно, но были более приоритетные задачи и эти «картинки» все отодвигались и отодвигались. Сам я пытался в свободное время покопаться в компоненте живой ленты. Но объем кода ужасал, кто смотрел, тот поймет. Несколько десятков или сотня файлов с over 2000 строк недокументированного PHP кода вперемешку с JS + HTML. OMG! 🙂 Наверное, компонент живой ленты самый большой в Битрикс24… (Upd: в 16,5 версии дела улучшились)
Ну что ж, задание дано — нужно делать.
Я буду описывать действия для версии 16.5, хотя изначально задача была поставлена для версии 15.х.
Открываем инструменты разработчика в Хроме, заливаем картинку в живой ленте, смотрим куда обращается скрипт. Обращение идет к файлу \bitrix\tools\disk\uf.php?action=uploadFile. Следуем за хлебными крошками и видим в конце файла такой код
1 2 3 4 5 6 |
$ufController = new Bitrix\Disk\Uf\Controller(); $ufController ->setActionName($_GET['action']) ->exec(); |
Исследуем контроллер Bitrix\Disk\Uf\Controller(). В нем как раз есть необходимый метод processActionUploadFile. Какой экшен использовать зависит от $_GET[‘action’].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
protected function processActionUploadFile() { static $uploader = null; if ($uploader === null) $uploader = new \CFileUploader(array("events" => array("onFileIsUploaded" => array($this, "processActionHandleFile"))), "get"); if (!$uploader->checkPost() && check_bitrix_sessid() && $this->request->getFile("disk_file")) { $file = $this->request->getFile("disk_file") + array("files" => array("default" => $this->request->getFile("disk_file"))); if ($this->processActionHandleFile( $hash = "", $file, $package = array(), $upload = array(), $error = array() ) ) { unset($file["files"]); unset($file["tmp_name"]); $this->sendJsonResponse(array( 'status' => self::STATUS_SUCCESS, 'data' => $file )); } else { $this->sendJsonResponse(array( 'status' => self::STATUS_ERROR, 'message' => $error )); } } } |
Читаем чужой код. Долго ли, мало ли, приходим к понимаю что за обработку файла отвечает метод processActionHandleFile. Можно было бы вставить код туда, но изменять внутренние методы битрикса нежелательно. Но, к счастью, для нас оставили лазейку. Сам метод привязывается к событию вот так:
1 2 3 |
$uploader = new \CFileUploader(array("events" => array("onFileIsUploaded" => array($this, "processActionHandleFile"))), "get") |
Что ж, используем событие «onFileIsUploaded». Идем в init.php, он у меня находится в \local\php_interface\init.php, привязываемся к событию:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
AddEventHandler('main_bxu', 'onFileIsUploaded', 'resizeImage'); function resizeImage($hash, &$file, &$package, &$upload, &$error){ try{ foreach ($file['files'] as &$arFile){ $filePath = $arFile['tmp_name']; $fileSize = &$arFile['size']; $fileType = &$arFile['type']; $type = exif_imagetype($filePath); $isImage = in_array($type, [IMAGETYPE_PNG, IMAGETYPE_BMP, IMAGETYPE_JPEG, IMAGETYPE_JPEG2000]); if($isImage && ($fileSize > 1024 * 800)) { $destinationFile = $filePath . '_copy'; $source = $filePath; CFile::ResizeImageFile($source, $destinationFile, ['width' => 1366, 'height' => 768], BX_RESIZE_IMAGE_EXACT); $arImageSize = CFile::GetImageSize($destinationFile); copy($destinationFile, $source); $fileType = $arImageSize["mime"]; $fileSize = filesize($destinationFile); unlink($destinationFile); } } }catch (Exception $e){ $error = $e->getMessage(); } return (empty($error)); } |
- main_bxu — взято из класса \bitrix\modules\main\lib\ui\uploader\uploader.php.
123const EVENT_NAME = "main_bxu"; - Возможность загрузить несколько файлов. Так что нужно пройтись по массиву
123foreach ($file['files'] as &$arFile) - Дальше создаем уменьшенную копию картинки, заменяем ей оригинал, удаляем копию. Записываем в переменную новые данные о размере картинки.
Тестируем:
Задача выполнена 🙂
UPD: Изначальна задача была выполнена в версии 15.х .К сожалению, я уже не помню весь путь поиска нужного блока кода.
Это, наверное, главное причина почему я открыл блог. Записывать нужные блоки кода, чтобы при выполнении похожей или такой же задачи не тратить заново время на поиск пути или туториала. Ведь запомнить все что делал несколько лет или даже месяцев назад очень трудно. (Конечно, если вы не мальчик из сериала «The Middle», который помнит все).
Остались только обрывочные записи. Ищите в компоненте bitrix\components\webdav.element.upload\action_iblock.php. Так как это компонент, то его можно скопировать в свое пространство имен.
Найдите там метод saveFile и вставьте этот код
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
$ob = $this->ob; $arResult = $this->arResult; $arParams = $this->arParams; // Ресайз картинок в живой ленте $type = exif_imagetype($arFile['tmp_name']); $isImage = in_array($type, [IMAGETYPE_PNG, IMAGETYPE_BMP, IMAGETYPE_JPEG, IMAGETYPE_JPEG2000]); if( $arParams['IBLOCK_ID'] == 16 && $isImage && ($arFile["size"] > 1024 * 800)) { $source = $destinationFile = $arFile['tmp_name']; $y = CFile::ResizeImageFile($source, $destinationFile, ['width' => 1366, 'height' => 768], BX_RESIZE_IMAGE_EXACT); $arImageSize = CFile::GetImageSize($destinationFile); $arFile["type"] = $arImageSize["mime"]; $arFile["size"] = filesize($destinationFile); } |
Возможно, это даст кому то толчок в правильном направлении.