Переименовываем картинки и прочие файлы в Битрикс

09.05.2019
2232
При добавлении нового файла в Битрикс, система его переназывает в случайный набор символов. Как правило, при разработке это не вызывает никаких проблем, но на стадии релиза оказывается, что клиенту принципиально, чтобы файлы назывались именно так, как он вам их передал.

При добавлении нового файла в Битрикс, система его переназывает в случайный набор символов. Как правило, при разработке это не вызывает никаких проблем, но на стадии релиза оказывается, что клиенту принципиально, чтобы файлы назывались именно так, как он вам их передал. Для того, чтобы избежать проблем в дальнейшем, достаточно в настройках главного модуля включить галочку "Сохранять исходные имена загружаемых файлов":

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

У нас возникла задача вернуть всем файлам первоначальные имена, либо переназвать их в соответствии с символьным кодом товара, к которому они привязаны. По ряду причин не было возможности просто сделать новый импорт каталога товаров, поэтому недолго думая мы решили написать не большую функцию, которая бы выполнила данную задачу. Сразу скажу, что код не претендует на какое-то универсальное решение, возможно какие-то моменты в нем можно улучшить, но его единственной задачей было запуститься 1 раз и поменять все файлов. 

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




$arSelect = Array("ID", "NAME", "CODE", "PROPERTY_MORE_PHOTO", "DETAIL_PICTURE");
$arFilter = Array("IBLOCK_ID"=>6);
$res = CIBlockElement::GetList(Array(), $arFilter, false, false, $arSelect);
$prods = [];
while($ob = $res->GetNextElement())
{
    $arFields = $ob->GetFields();
    $prods[] = $arFields;
}

foreach ($prods as $prod) {
    $photos = [];
    $photos[] = $prod['DETAIL_PICTURE'];
    foreach ($prod['PROPERTY_MORE_PHOTO_VALUE'] as $mphoto) {
        $photos[] = $mphoto;
    }
    $isMoreOne = count($photos) > 1 ? true : false;
    $i = 0;
    foreach ($photos as $photo) {
        $newName = $prod['CODE'];
        if ($isMoreOne && $i++ > 0)
           $newName .= "-".$i++;

        renameFileDBbyID($photo, $newName);
    }
    unset($i);
}

function renameFileDBbyID($id, $newName = null){
    $connection = Bitrix\Main\Application::getConnection();
    
    $sql = "SELECT * FROM b_file WHERE ID = $id";
    $recordset = $connection->query($sql);
    while ($record = $recordset->fetch())
    {
        if(!preg_match('/-/', $record['FILE_NAME'])) {
            if (preg_match('/.png/', $record['FILE_NAME']))
                $newName = $newName.'.png';
            else
                $newName = $newName.'.jpg';

            renameFile($id, $newName);

            $connection->queryExecute("UPDATE b_file SET FILE_NAME = '$newName' WHERE ID = $id ");
        }
    }
}

function renameFile($id, $newName = null){
    $fileArr = CFile::GetFileArray($id);
    $path = '/upload/'.$fileArr['SUBDIR'].'/'.$fileArr['FILE_NAME'];
    $newPath = '/upload/'.$fileArr['SUBDIR'].'/'.$newName;

    $file = new \Bitrix\Main\IO\File(\Bitrix\Main\Application::getDocumentRoot().$path);
    $file->rename(\Bitrix\Main\Application::getDocumentRoot().$newPath);

}


А теперь по частям.


$arSelect = Array("ID", "CODE", "PROPERTY_MORE_PHOTO", "DETAIL_PICTURE");
$arFilter = Array("IBLOCK_ID"=>6);
$res = CIBlockElement::GetList(Array(), $arFilter, false, false, $arSelect);
$prods = [];
while($ob = $res->GetNextElement())
{
    $arFields = $ob->GetFields();
    $prods[] = $arFields;
}

foreach ($prods as $prod) {
    $photos = [];
    $photos[] = $prod['DETAIL_PICTURE'];
    foreach ($prod['PROPERTY_MORE_PHOTO_VALUE'] as $mphoto) {
        $photos[] = $mphoto;
    }
    $isMoreOne = count($photos) > 1 ? true : false;
    $i = 0;
    foreach ($photos as $photo) {
        $newName = $prod['CODE'];
        if ($isMoreOne && $i++ > 0)
           $newName .= "-".$i++;

        renameFileDBbyID($photo, $newName);
    }
    unset($i);
}


Сначала получаем список товаров с информацией о детальном изображении и дополнительных фотографиях (свойство "PROPERTY_MORE_PHOTO"). Если у Вас есть опыт работы с Битрикс, то Вы знаете, что информация о любых привязанных файлах, в т.ч. и изображениях, приходят в виде ID этого самого файла. После получения списка товаров, мы проходим по нему циклом, в котором сначала собираем в массив все id изображений, а потом сразу же запускаем еще один цикл, который по очереди берет id`шники, формирует новое имя файла и запускает наши функции "renameFileDBbyID" и "renameFile" (внизу в листинге кода).

Теперь пробежимся по самим функциям. Т.к. в базе данных хранится только информация о файлах, а сами файлы хранятся просто в папке на хостинге, то и изменения нам нужно вносить в двух местах: изменить запись в БД, изменить имя файла. Сначала пробежимся по функции, которая будет переназывать сам файл:

function renameFile($id, $newName = null){
    $fileArr = CFile::GetFileArray($id);
    $path = '/upload/'.$fileArr['SUBDIR'].'/'.$fileArr['FILE_NAME'];
    $newPath = '/upload/'.$fileArr['SUBDIR'].'/'.$newName;

    $file = new \Bitrix\Main\IO\File(\Bitrix\Main\Application::getDocumentRoot().$path);
    $file->rename(\Bitrix\Main\Application::getDocumentRoot().$newPath);

}
На вход мы передаем id и новое имя. Первым делом, используя функцию Битрикса CFile::GetFileArray($id), получаем информацию по файлу, в первую очередь нас интересует текущее имя файла и подпапка, той папки в которой сохраняются файлы, обычно это папка "upload". Далее строим текущий путь к файлу и новый, переменные $path и $newPath. Для получения и переименования файла используем класс Битрикс \Bitrix\Main\IO\File.С файлом разобрались.

Теперь переходим к работе с БД. Информация о файлах хранится в таблице b_file. В Битрикс есть стандартные функции, которых полностью хватает для решения нашей задачи. Создаем подключение, находим нужную запись по ID. В принципе, можно сразу обновлять строку в БД по ID файла, но в нашем случае был нюанс, по которому нужно было изменять не все записи, а только те, у которых в названии нету символа "-", но тут уже каждый сам напишет, что нужно в его случае. Другими словами минимальные необходимые строки для внесения изменений: Создание подключения $connection = Bitrix\Main\Application::getConnection(); , внесение изменений в БД $connection->queryExecute("UPDATE b_file SET FILE_NAME = '$newName' WHERE ID = $id ");



function renameFileDBbyID($id, $newName = null){
    $connection = Bitrix\Main\Application::getConnection();
    
    $sql = "SELECT * FROM b_file WHERE ID = $id";
    $recordset = $connection->query($sql);
    while ($record = $recordset->fetch())
    {
        if(!preg_match('/-/', $record['FILE_NAME'])) {
            if (preg_match('/.png/', $record['FILE_NAME']))
                $newName = $newName.'.png';
            else
                $newName = $newName.'.jpg';

            renameFile($id, $newName);

            $connection->queryExecute("UPDATE b_file SET FILE_NAME = '$newName' WHERE ID = $id ");
        }
    }
}


Интересно такое решение?

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

Вячеслав Дудоров
Сооснователь OFF GROUP
Директор по производству

похожие материалы

Есть вопросы?

Заполните форму и мы свяжемся с вами в теление одного рабочего дня.

Нажимая на кнопку «Отправить», я даю согласие на обработку персональных данных и соглашаюсь c политикой конфиденциальности