Перейти к содержимому

Файлы платформы изнутри - таблица, каталоги, копии, удаление

Разбираем хранилище файлов целиком: таблица файлов, каталоги на диске, уменьшенные копии изображений, удаление и рост каталога загрузок со временем.

Механика

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

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

Файлы на диске разложены по служебным подпапкам с короткими именами. Это сделано ради файловой системы: миллион файлов в одном каталоге замедляет любые операции с ним, включая обычный просмотр списка.

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

Уменьшенные копии изображений живут отдельно от исходных файлов. Каждый новый размер создаётся при первом обращении и складывается в служебный каталог рядом с основным хранилищем.

Отсюда неожиданный для многих рост объёма. Каталог с копиями на большом магазине занимает больше, чем сами оригиналы, потому что у каждого товара несколько размеров под разные блоки витрины.

Удаление записи из таблицы файлов и удаление файла с диска - разные операции. Штатный вызов делает обе, а прямое удаление файла оставляет запись, по которой платформа будет собирать путь в никуда.

Ещё одна особенность - счётчик использования файла. Один и тот же файл может быть привязан к нескольким записям, и удалять его физически можно только тогда, когда на него больше никто не ссылается.

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

Шаги

  1. Понять, где именно лежит файл: в хранилище платформы или в своём каталоге.
  2. Проверить объём каталога загрузок и долю уменьшенных копий изображений.
  3. Удалять файлы штатным вызовом, а не командой файловой системы напрямую.
  4. Найти файлы, на которые больше не ссылается ни одна запись проекта.
  5. Настроить регулярную чистку и следить за ростом хранилища после обменов.

Код

Смотрим запись файла в таблице:

$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 -8
du -sh /home/bitrix/www/upload/resize_cache 2>/dev/null
find /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_X
FROM b_file f
LEFT JOIN b_iblock_element e ON e.DETAIL_PICTURE = f.ID OR e.PREVIEW_PICTURE = f.ID
WHERE 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']);
// путь собирается из этих двух частей и номера файла в таблице
// в облачном хранилище тот же номер даёт внешний адрес, а не локальный путь

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

Ограничения

Прямые пути к файлам в коде ломаются первыми. Настройка каталога загрузок, переезд на другой сервер и вынос файлов в облако меняют путь, а номер файла остаётся прежним.

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

Каталог загрузок доступен снаружи по прямой ссылке. Документы, которые нельзя показывать всем, хранят вне публичного каталога и отдают собственным кодом с проверкой прав.

Уменьшенные копии не удаляются вместе с оригиналом мгновенно. Часть копий остаётся на диске до чистки, и на большом каталоге это заметный объём мусора.

Одинаковые файлы платформа не объединяет автоматически. Загрузка одной картинки к сотне товаров создаёт сотню файлов, и на объёмных каталогах это стоит места.

Типичные проблемы

После переноса сайта пропали все изображения.

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

Картинка исчезла у одного элемента и у его копии.

Файл был привязан по номеру к двум записям, и удаление у одной убрало его у обеих. Копии элементов создают со своей копией файла, а не со ссылкой на общий.

Каталог загрузок вырос вдвое без новых товаров.

Растёт каталог уменьшенных копий: каждый новый размер в шаблоне создаёт новые файлы. Набор размеров согласуют на весь проект и чистят каталог копий по расписанию.

Файл удалён с диска, а страница ссылается на него.

Удаление сделано командой файловой системы, и запись в таблице файлов осталась. Файлы удаляют штатным вызовом, который убирает и запись, и сам файл.

Закрытый документ скачивается по прямой ссылке.

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

Чистка удалила нужные файлы вместе с мусором.

Список кандидатов собирался по одной таблице, а ссылки были в свойствах и в своих таблицах. Перед удалением проверяют ссылки по всем местам, где проект хранит номера файлов.

Частые вопросы

Почему в базе хранится номер, а не путь?

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

Можно ли удалить каталог уменьшенных копий?

Да, платформа создаст нужные размеры заново при первом обращении. Первые минуты после такой уборки витрина будет медленнее обычного.

Как отдать файл только по праву доступа?

Хранить его вне публичного каталога и отдавать своим кодом после проверки прав. Файл в каталоге загрузок доступен по прямой ссылке всем.

Что происходит при удалении элемента с картинкой?

Платформа удаляет привязанный файл, если на него не ссылается ничего другого. Файл, использованный в нескольких местах, остаётся до последней ссылки.

Как перенести файлы на отдельное хранилище?

Настройкой каталога загрузок или облачным хранилищем в настройках модуля. Данные при этом не меняются: в них лежат номера, а не пути.

Смежное

Первоисточник