Картинки при обмене изнутри - привязка файлов, перезапись, чужие правки
Разбираем судьбу изображений при повторном обмене: где живёт привязка файла к товару, что сеанс делает с прежними картинками и почему фотографии, залитые менеджером через админку, не переживают ночную выгрузку.
Механика
Платформа хранит не путь к изображению, а его номер в таблице файлов b_file.
Детальная картинка товара - это одно число в поле элемента, и картинка анонса
устроена ровно так же.
Дополнительные изображения живут иначе: множественным свойством типа F. Каждое
значение такого свойства - отдельная строка с номером файла и собственным
описанием, и строк у одного товара сколько угодно.
Обмен никогда не правит уже лежащий на диске файл. Приехавшая картинка сохраняется новым файлом, получает новый номер, и в поле товара записывается именно он.
Отсюда меняющийся адрес изображения на витрине. Имя файла на диске платформа задаёт сама, поэтому после полной выгрузки ссылка другая, а для поисковика и товарной площадки это новая картинка.
Прежний файл при замене никуда не девается. Отвязка от товара не удаляет ни
запись в таблице файлов, ни сам файл в каталоге загрузок, и так в /upload/
копятся сироты.
Единичное поле обмен перезаписывает, а множественное свойство ведёт себя по-другому. Запись файлового свойства по коду дополняет прежние значения, и поэтому у товара накапливаются десятки одинаковых снимков.
Обратная беда - обнуление. Полный набор значений свойств стирает всё, чего в наборе не оказалось, и вручную залитая галерея исчезает целиком вместе с описаниями своих файлов.
Описание файла - тоже отдельное поле значения, а не часть самой картинки. Обмен
кладёт туда имя файла из выгрузки, и написанный менеджером текст затирается
вместе с атрибутом alt на витрине.
Данные обмена проходят обычные события сохранения элемента инфоблока. Значит, набор полей правится до записи, и именно там снимают всё, чего учётная система касаться не должна.
Шаги
- Понять, чем занято поле: детальная картинка держит номер файла, галерея - значения свойства.
- Снять привязку товара до сеанса: номера файлов, их описания и порядок значений свойства.
- Провести обмен и сравнить номера заново, чтобы увидеть, что именно платформа заменила.
- Снять в обработчике события те поля изображений, которые ведёт сайт, а не учётная система.
- Посчитать файлы без ссылок и убирать их отдельным регулярным проходом, а не руками.
Код
Смотрим, что записано у товара:
$res = CIBlockElement::GetList([], ['IBLOCK_ID' => 5, 'ID' => $elementId], false, false, ['ID', 'DETAIL_PICTURE', 'PREVIEW_PICTURE', 'PROPERTY_MORE_PHOTO']);$row = $res->GetNext();printf("детальная=%s доп=%s\n", $row['DETAIL_PICTURE'], $row['PROPERTY_MORE_PHOTO_VALUE']);// в полях лежат номера файлов из b_file, а не пути к изображениям// PROPERTY_MORE_PHOTO_VALUE отдаёт номера значений множественного свойстваНомер файла - единственная связь товара с картинкой. Сравнение этих чисел до сеанса и после него показывает, завела платформа новый файл или оставила прежний.
Разворачиваем номер в файл:
$file = \CFile::GetFileArray($row['DETAIL_PICTURE']);printf("%s / %s / %d байт\n", $file['SRC'], $file['ORIGINAL_NAME'], $file['FILE_SIZE']);// метод вернёт false, если запись осталась, а файла на диске уже нетИсходное имя из выгрузки хранится отдельно от имени файла на диске. Поэтому одинаковые по содержимому картинки двух сеансов лежат в каталоге разными файлами и занимают место дважды.
Читаем значения галереи вместе с описаниями:
$props = CIBlockElement::GetProperty(5, $elementId, ['SORT' => 'ASC'], ['CODE' => 'MORE_PHOTO']);while ($p = $props->Fetch()) { printf("файл=%s описание=%s\n", $p['VALUE'], $p['DESCRIPTION']); }// порядок сортировки обязателен: false в третьем аргументе ломает фильтрациюОписание приходит отдельным полем рядом со значением. Именно его обмен заполняет именем файла, и текст менеджера пропадает молча, без единой записи в журнале сеанса.
Добавляем свой снимок в галерею:
use Bitrix\Iblock\ORM\PropertyValue;$photoId = \CFile::SaveFile(\CFile::MakeFileArray($path), 'iblock');\CFile::ResizeImage($photoId, ['width' => 300, 'height' => 300], BX_RESIZE_IMAGE_EXACT, true);$element->addTo('MORE_PHOTO', new PropertyValue($photoId, 'снимок менеджера'));$element->save();// файловое свойство принимает объект PropertyValue, а не номер числом// ORM не уменьшает изображение сама: ресайз вызывают сразу после сохраненияВторой аргумент объекта - то самое описание, которое перезапишет ближайший обмен. Уменьшенные копии при таком сохранении не создаются: ресайз вызывают вручную сразу после сохранения файла.
Снимаем поля картинок из набора обмена:
AddEventHandler('iblock', 'OnBeforeIBlockElementUpdate', 'protectPictures');function protectPictures(&$fields) { if (($_REQUEST['mode'] ?? '') !== 'import') { return; } // ручную правку не трогаем unset($fields['DETAIL_PICTURE'], $fields['PREVIEW_PICTURE']); unset($fields['PROPERTY_VALUES']['MORE_PHOTO']); // и галерею целиком}Снятое из набора поле обмен не переписывает, и прежний номер файла остаётся в базе нетронутым. Тот же обработчик вешают на событие добавления элемента, иначе новые товары приедут с картинками.
Очищаем галерею перед своей записью:
CIBlockElement::SetPropertyValuesEx($elementId, 5, ['MORE_PHOTO' => false]);CIBlock::clearIblockTagCache(5); // сам метод тегированный кеш не сбрасывает// пустой массив множественное свойство не очистит: только false// коды свойств здесь регистрозависимы, в отличие от выборки спискомУдаление и запись множественного файлового свойства делают одним вызовом. После любой такой операции идентификаторы значений меняются, и снятые заранее номера превращаются в мусор.
Смотрим прирост файлов по дням сеансов:
SELECT DATE(TIMESTAMP_X) d, COUNT(*) n, ROUND(SUM(FILE_SIZE)/1048576) mbFROM b_file WHERE MODULE_ID = 'iblock' GROUP BY d ORDER BY d DESC LIMIT 10;-- ровный прирост в дни обмена означает, что каждый сеанс заводит файлы зановоРовные всплески по расписанию обмена - признак повторной заливки тех же изображений. Число товаров при этом не меняется, и разница целиком складывается из отвязанных файлов.
Убираем найденных сирот:
$res = \CFile::GetList([], ['MODULE_ID' => 'iblock']); // фильтр по модулю и подкаталогуwhile ($f = $res->Fetch()) { if (isLinked($f['ID'])) { continue; } // своя проверка ссылок по всем свойствам printf("%s %s\n", $f['ID'], \CFile::FormatSize($f['FILE_SIZE'])); \CFile::Delete($f['ID']); // удаляет и запись в b_file, и файл на диске}// вызов необратим: сначала прогон со снятым удалением, только потом боевойУдаление файла командой файловой системы оставит запись в таблице, и путь соберётся в никуда. Проверку ссылок пишут по всем местам проекта, где хранятся номера файлов, а не по одной таблице элементов.
Ограничения
Защита полей действует только на стороне сайта и ни на что больше. Учётная система по-прежнему считает изображение выгруженным, и её собственный журнал сеанса проходит без единого замечания.
Обработчик выполняется на каждой позиции файла обмена без исключений. Запрос к базе внутри него превращает каталог на десять тысяч товаров в десять тысяч лишних запросов и съедает ночное окно.
Контрольные суммы элементов пропускают неизменившийся товар целиком, вместе с его картинками. Это ускоряет сеанс и заодно объясняет, почему очередная полная выгрузка изображения не перезаливает.
Сохранённый своим кодом файл платформа не удалит никогда и ни при каких условиях. Убирать его обязан тот же код, а вызов удаления необратим: он стирает запись и файл одновременно.
Договорённость о хозяине изображений важнее любого обработчика на проекте. Пока не решено, кто ведёт картинки - сайт или учётная система, защита полей остаётся спором двух правок.
Типичные проблемы
Картинки, залитые вручную, стёрлись после ночного обмена.
Поля детальной картинки и анонса приехали в наборе обмена и перезаписали прежние номера файлов. Их снимают в событии перед обновлением, отличив сеанс обмена от ручной правки менеджера.
Дополнительные изображения затираются, хотя свойства нет в выгрузке.
Обмен пишет полный набор значений свойств, и всё непереданное в нём обнуляется. Достаточно одного тега картинки у любого товара, чтобы галереи опустели у всего каталога.
После каждой выгрузки фотографии товара дублируются.
Запись файлового свойства по коду дополняет прежние значения, а не заменяет их целиком. Свой код обновления не должен передавать свойство с картинками в наборе полей элемента.
Адрес детальной картинки меняется после каждого полного обмена.
Приехавший файл сохраняется заново и получает новый номер, а имя на диске платформа задаёт сама. Постоянная ссылка достигается только отказом от повторной заливки того же изображения.
В описании картинки вместо текста менеджера имя файла.
Описание хранится отдельным полем значения, и обмен кладёт туда имя файла из выгрузки. Поле снимают вместе с самой картинкой либо переписывают своим проходом после сеанса.
Каталог загрузок растёт быстрее каталога товаров.
Отвязка картинки от товара не удаляет ни запись в таблице файлов, ни сам файл на диске. Сироты копятся каждым сеансом и убираются только отдельной регулярной чисткой.
Частые вопросы
Можно ли не выгружать картинки из 1С, а добавлять их вручную?
Да, если снять поля изображений в обработчике события перед сохранением элемента. Тогда сеанс обновит цены и остатки, а картинки останутся прежними.
Почему полная выгрузка не обновляет картинки?
Неизменившийся товар пропускается целиком вместе со своими файлами. Перезаливка происходит при принудительном обмене или после смены изображения в учётной системе.
Как запретить изменение описания детальной картинки при обмене?
Описание приезжает вместе с самой картинкой, поэтому снимают всё поле целиком. Если картинки обновлять нужно, а описания нет, текст возвращают своим проходом после сеанса.
Куда деваются старые файлы после замены картинки?
Остаются и на диске, и в таблице файлов: платформа их не удаляет. Место освобождает только чистка, сверяющая ссылки по всем свойствам проекта.
Почему у товара накопились десятки одинаковых снимков?
Множественное файловое свойство дополняется, а не перезаписывается. Каждый сеанс добавляет к галерее очередную копию того же изображения.
Смежное
- Картинки при обмене - оглавление подтемы
- Обмен с 1С и HTTP - устройство обмена целиком
- Картинки товара при обмене: детальная, дополнительные, разделы - как настроить приём изображений
- Не выгружаются картинки из 1С - когда картинок нет вовсе
- Папка загрузок растёт: дубли картинок и лишние файлы - когда сироты уже заняли диск
- Файлы платформы изнутри: таблица, каталоги, копии, удаление - устройство хранилища вообще
- Файлы из кода: сохранение, уменьшенные копии, удаление - операции с файлом из своего кода
- Своя логика при обмене: обработчики, защита правок, журнал - тем же способом защищают тексты
- Импорт каталога изнутри: файлы, сопоставление, перезапись - что обмен перезаписывает кроме файлов
- Картинки торговых предложений: смена при выборе варианта - картинки вариантов из обмена