Налаштування автоматичного накладення водяних знаків 1С-Bitrix
Менеджер завантажує нове зображення товара через адміністративну частину — і воно повинно автоматично отримати водяний знак без жодних додаткових дій. Ручна обробка після завантаження — це зламаний процес: хто-то забуде, хто-то зробить неправильно. Потрібен перехват на рівні події завантаження файлу.
Точки перехвату при завантаженні зображень
У Bitrix файли завантажуються через CFile::SaveFile() та CFile::Add(). Подія OnBeforeFileAdd дозволяє перехопити завантаження до збереження на диск:
AddEventHandler('main', 'OnBeforeFileAdd', function(&$fileFields, $moduleId) {
// $moduleId: 'iblock', 'sale', 'catalog' тощо
if ($moduleId !== 'iblock') {
return; // Обробляємо тільки зображення каталогу
}
$mimeType = $fileFields['type'] ?? '';
if (!str_starts_with($mimeType, 'image/')) {
return;
}
$tmpFile = $fileFields['tmp_name'];
applyWatermarkInPlace($tmpFile);
});
Функція applyWatermarkInPlace модифікує тимчасовий файл до його збереження в /upload/. Це означає: в базі та на диску опиниться уже оброблений файл, без необхідності зберігати оригінал та кеш окремо.
Різниця між оновленням та новим завантаженням
Подія OnBeforeFileAdd спрацьовує тільки при нових завантаженнях. При оновленні елемента каталогу, якщо зображення не змінювалось, файл не перезаписується — подія не спрацює. Це коректна поведінка.
Проблема: якщо адміністратор завантажує зображення через масовий імпорт CSV або через REST API (iblock.element.update), подія OnBeforeFileAdd також повинна спрацювати — і спрацює, оскільки імпорт в кінцевому рахунку викликає CFile::SaveFile().
Виключення з автоматичного накладення
Не всі зображення потрібно маркувати. Логотип компанії в шапці, значки категорій, системні зображення — все це проходить через CFile. Фільтрація за $moduleId вирішує тільки частину завдання.
Для більш точного управління додаємо перевірку контексту через сесійну змінну:
AddEventHandler('main', 'OnBeforeFileAdd', function(&$fileFields, $moduleId) {
if ($moduleId !== 'iblock') return;
if (!isset($_SESSION['WATERMARK_ENABLED'])) return;
$iblockId = $_SESSION['CURRENT_IBLOCK_ID'] ?? null;
$noWatermarkIblocks = \Bitrix\Main\Config\Option::get('catalog', 'no_watermark_iblocks', '');
$excluded = array_map('intval', explode(',', $noWatermarkIblocks));
if ($iblockId && in_array($iblockId, $excluded)) return;
applyWatermarkInPlace($fileFields['tmp_name']);
});
Змінна CURRENT_IBLOCK_ID встановлюється в обробнику події OnBeforeIBlockElementAdd / OnBeforeIBlockElementUpdate. Список виключених інфоблоків зберігається в b_option.
Обробка помилок при накладенні
Якщо GD-обробка завершиться з помилкою (битий файл, непідтримуваний формат), завантаження не повинно блокуватися. Обгортка applyWatermarkInPlace у блоці try/catch — при помилці файл зберігається без водяного знака, помилка пишеться в лог:
function applyWatermarkInPlace(string $tmpFile): void
{
try {
// Обробка через GD
$result = processWatermark($tmpFile);
if ($result) {
file_put_contents($tmpFile, $result);
}
} catch (\Throwable $e) {
\Bitrix\Main\Diag\Debug::writeToFile(
$e->getMessage(), 'watermark_error', '/bitrix/watermark.log'
);
// Не переривємо завантаження — файл збереться оригінальним
}
}
Продуктивність при масовому завантаженні
При імпорті каталогу 5 000 товарів з 3 зображеннями кожного — 15 000 операцій GD. На середньому сервері обробка одного зображення займає 50–150 мс. Всього: 12–37 хвилин додається до часу імпорту. Якщо це неприйнятно — переключаємось на асинхронну схему: зберігаємо оригінал, ставимо завдання в чергу b_agent, агент обробляє пакетами по 100 зображень.
Що налаштовуємо
- Обробник події
OnBeforeFileAddз фільтрацією за$moduleId - Список інфоблоків-виключень в
b_option - Обробку помилок GD без блокування завантаження
- Для масового імпорту: асинхронну обробку через агент
- Моніторинг логу
/bitrix/watermark.logна предмет битих зображень







