Файлы платформы изнутри - таблица, каталоги, копии, удаление
Разбираем хранилище файлов целиком: таблица файлов, каталоги на диске, уменьшенные копии изображений, удаление и рост каталога загрузок со временем.
Механика
Платформа хранит не путь к файлу, а его номер в собственной таблице файлов. Поля элементов, свойства и пользовательские поля держат именно этот номер, а путь собирается по нему в момент вывода на страницу.
Такой подход позволяет менять расположение файлов без правки данных. Каталог хранения задаётся настройкой, и переезд на другой диск не требует обновления ни одного элемента инфоблока.
Файлы на диске разложены по служебным подпапкам с короткими именами. Это сделано ради файловой системы: миллион файлов в одном каталоге замедляет любые операции с ним, включая обычный просмотр списка.
Имя файла на диске платформа задаёт сама, сохраняя исходное имя отдельным полем таблицы. Поэтому два посетителя могут загрузить файлы с одинаковыми именами, не затирая работу друг друга.
Уменьшенные копии изображений живут отдельно от исходных файлов. Каждый новый размер создаётся при первом обращении и складывается в служебный каталог рядом с основным хранилищем.
Отсюда неожиданный для многих рост объёма. Каталог с копиями на большом магазине занимает больше, чем сами оригиналы, потому что у каждого товара несколько размеров под разные блоки витрины.
Удаление записи из таблицы файлов и удаление файла с диска - разные операции. Штатный вызов делает обе, а прямое удаление файла оставляет запись, по которой платформа будет собирать путь в никуда.
Ещё одна особенность - счётчик использования файла. Один и тот же файл может быть привязан к нескольким записям, и удалять его физически можно только тогда, когда на него больше никто не ссылается.
Отдельная история - файлы, загруженные посетителями сайта. Они попадают в тот же каталог загрузок, доступны по прямой ссылке и требуют проверки содержимого до сохранения на диск.
Шаги
- Понять, где именно лежит файл: в хранилище платформы или в своём каталоге.
- Проверить объём каталога загрузок и долю уменьшенных копий изображений.
- Удалять файлы штатным вызовом, а не командой файловой системы напрямую.
- Найти файлы, на которые больше не ссылается ни одна запись проекта.
- Настроить регулярную чистку и следить за ростом хранилища после обменов.
Код
Смотрим запись файла в таблице:
$file = \CFile::GetFileArray($fileId);printf("путь=%s имя=%s размер=%d байт\n", $file['SRC'], $file['ORIGINAL_NAME'], $file['FILE_SIZE']);// исходное имя хранится отдельно от имени файла на диске// путь в поле SRC уже учитывает облачное хранилище, если оно подключеноОтвет показывает и путь для витрины, и исходное имя загруженного файла. Именно исходное имя отдают посетителю при скачивании, а на диске файл лежит под другим, служебным именем.
Смотрим объём хранилища по подкаталогам:
du -sh /home/bitrix/www/upload/* 2>/dev/null | sort -h | tail -8du -sh /home/bitrix/www/upload/resize_cache 2>/dev/nullfind /home/bitrix/www/upload -type f | wc -l# каталог уменьшенных копий часто оказывается крупнее каталога оригиналовКаталог копий можно удалить целиком без потери данных. Платформа соберёт нужные размеры заново при первом обращении, но первые минуты после такой уборки витрина будет заметно медленнее обычного.
Создаём уменьшенную копию из кода:
$thumb = \CFile::ResizeImageGet($fileId, ['width' => 400, 'height' => 400], BX_RESIZE_IMAGE_PROPORTIONAL, true);printf("копия: %s (%dx%d)\n", $thumb['src'], $thumb['width'], $thumb['height']);// четвёртый аргумент включает сохранение копии для повторных обращений// каждый новый набор размеров создаёт ещё один файл в каталоге копийРазные размеры в разных шаблонах множат копии. Один согласованный набор размеров на весь проект экономит и место на диске, и время первой отрисовки страницы для посетителя.
Удаляем файл правильно:
\CFile::Delete($fileId); // удаляет и запись в таблице, и файл на диске\CFile::ResizeImageDelete($fileId); // заодно убирает уменьшенные копии// прямое удаление файла с диска оставит запись, и путь соберётся в никудаИщем файлы без ссылок:
SELECT f.ID, f.FILE_NAME, f.FILE_SIZE, f.TIMESTAMP_XFROM b_file fLEFT JOIN b_iblock_element e ON e.DETAIL_PICTURE = f.ID OR e.PREVIEW_PICTURE = f.IDWHERE e.ID IS NULL AND f.MODULE_ID = 'iblock'ORDER BY f.FILE_SIZE DESC LIMIT 50;-- запрос показывает кандидатов, но проверять ссылки нужно по всем таблицам проектаФайл может быть привязан к свойству, к разделу или к своей таблице проекта. Поэтому список кандидатов на удаление всегда проверяют вручную, прежде чем запускать чистку на боевом сайте.
Проверяем настройку каталога хранения:
printf("каталог загрузок: %s\n", \Bitrix\Main\Config\Option::get('main', 'upload_dir', 'upload'));printf("путь к сайту: %s\n", \Bitrix\Main\Application::getDocumentRoot());printf("файл на диске: %s\n", \Bitrix\Main\Application::getDocumentRoot() . $file['SRC']);// путь собирается из этих двух частей и номера файла в таблице// в облачном хранилище тот же номер даёт внешний адрес, а не локальный путьПолезная привычка - держать список размеров изображений в одном месте проекта. Тогда новый блок витрины берёт готовый размер, а не заводит очередной набор копий на диске.
Ограничения
Прямые пути к файлам в коде ломаются первыми. Настройка каталога загрузок, переезд на другой сервер и вынос файлов в облако меняют путь, а номер файла остаётся прежним.
Файлы не переносятся вместе со структурой при выкладке. Миграции переносят инфоблоки и настройки, а изображения товаров приезжают отдельным шагом или обменом с учётной системой.
Каталог загрузок доступен снаружи по прямой ссылке. Документы, которые нельзя показывать всем, хранят вне публичного каталога и отдают собственным кодом с проверкой прав.
Уменьшенные копии не удаляются вместе с оригиналом мгновенно. Часть копий остаётся на диске до чистки, и на большом каталоге это заметный объём мусора.
Одинаковые файлы платформа не объединяет автоматически. Загрузка одной картинки к сотне товаров создаёт сотню файлов, и на объёмных каталогах это стоит места.
Типичные проблемы
После переноса сайта пропали все изображения.
В коде или в данных записаны прямые пути вместо номеров файлов платформы. Хранить нужно номер файла, а путь собирать штатным вызовом в момент вывода.
Картинка исчезла у одного элемента и у его копии.
Файл был привязан по номеру к двум записям, и удаление у одной убрало его у обеих. Копии элементов создают со своей копией файла, а не со ссылкой на общий.
Каталог загрузок вырос вдвое без новых товаров.
Растёт каталог уменьшенных копий: каждый новый размер в шаблоне создаёт новые файлы. Набор размеров согласуют на весь проект и чистят каталог копий по расписанию.
Файл удалён с диска, а страница ссылается на него.
Удаление сделано командой файловой системы, и запись в таблице файлов осталась. Файлы удаляют штатным вызовом, который убирает и запись, и сам файл.
Закрытый документ скачивается по прямой ссылке.
Файл лежит в каталоге загрузок, доступном всем по прямому адресу. Такие файлы хранят вне публичного каталога и отдают кодом с проверкой прав.
Чистка удалила нужные файлы вместе с мусором.
Список кандидатов собирался по одной таблице, а ссылки были в свойствах и в своих таблицах. Перед удалением проверяют ссылки по всем местам, где проект хранит номера файлов.
Частые вопросы
Почему в базе хранится номер, а не путь?
Номер не зависит от расположения файлов и переживает переезд, смену каталога и вынос хранилища. Путь собирается по номеру в момент вывода страницы.
Можно ли удалить каталог уменьшенных копий?
Да, платформа создаст нужные размеры заново при первом обращении. Первые минуты после такой уборки витрина будет медленнее обычного.
Как отдать файл только по праву доступа?
Хранить его вне публичного каталога и отдавать своим кодом после проверки прав. Файл в каталоге загрузок доступен по прямой ссылке всем.
Что происходит при удалении элемента с картинкой?
Платформа удаляет привязанный файл, если на него не ссылается ничего другого. Файл, использованный в нескольких местах, остаётся до последней ссылки.
Как перенести файлы на отдельное хранилище?
Настройкой каталога загрузок или облачным хранилищем в настройках модуля. Данные при этом не меняются: в них лежат номера, а не пути.
Смежное
- Файлы в коде - оглавление подтемы
- Файлы из кода: сохранение, уменьшенные копии, удаление - основные операции с файлами
- Отдача файла с проверкой прав: закрытые каталоги, заголовки, ссылки - файлы вне публичного каталога
- Файл не загружается: пределы, права, типы, веб-сервер - разбор проблем загрузки
- Загрузка файла с формы: приём, проверки, прогресс, хранение - приём файла от посетителя
- Быстрые картинки на витрине: размеры, ленивая загрузка, WebP - согласованный набор размеров
- Папка загрузок растёт: дубли картинок и лишние файлы - рост хранилища после обменов
- Ядро D7 - устройство ядра целиком
- Картинки не отображаются: разбор причин - разбор пропавших картинок по этому устройству
- Облачное хранилище и CDN: подключение, перенос, копии - когда файлы уезжают за пределы диска
- Картинки при обмене изнутри - что делает с этим хранилищем ночной обмен с 1С