Кейс: 318 ГБ фото в OpenCart остановили загрузку товаров

30.10.2026 • 5 просмотров • Категория: Обслуживание сайтов

Кейс: 318 ГБ фото в OpenCart остановили загрузку товаров

Интернет-магазин одежды на OpenCart перестал принимать новые фото товаров: менеджер загружала папки по FTP, а Total Commander останавливался на 1% с ошибками 550 No such file or directory и «Не удаётся создать удалённый каталог». Причина была не в FTP: фото товаров занимали 318 ГБ на диске в 394 ГБ, и серверу не хватило места для записи. Мы освободили место, собственным скриптом удалили фото товаров, которых уже нет в каталоге, и перевели изображения в WebP. Всё — в рамках обслуживания сайта.

Что видел клиент

Каталог магазина наполняется так: для каждого товара менеджер создаёт на FTP папку с артикулом и загружает туда фото. Одна партия — несколько десятков товаров и сотни мегабайт: отдельный снимок весил 6,2 МБ. В какой-то момент загрузка начала обрываться:

  • 451 Append/Restart not permitted — сервер не дал докачать файл после обрыва;
  • 550 No such file or directory и «Не удаётся создать удалённый каталог» — сервер не создаёт папку для нового товара.

После пяти попыток загрузка не шла дальше 1%, а потом перестала стартовать вообще. На стороне клиента ничего не менялось, поэтому первым подозрением были FTP-клиент или сеть.

Диагностика: куда делось место

Вместо настроек Total Commander мы проверили сам сервер. Картину дали три команды:

  • df -i — inodes (лимит количества файлов) заняты всего на 2%, значит, дело не в количестве файлов;
  • df -h — основной раздел 394 ГБ, из них занято 316 ГБ;
  • du -ahx / | sort -rh | head -n 20 — почти всё это место занимает папка image магазина.
ПапкаРазмерЧто в ней
image/catalog282 ГБоригиналы фото товаров в том виде, в каком их загрузили
image/cache36 ГБуменьшенные копии, которые OpenCart генерирует сам
Всего image318 ГБ81% всего диска сервера

Почему OpenCart так разрастается

Это не сбой, а три особенности OpenCart, которые проявляются на больших каталогах:

  1. Оригинал хранится как есть. OpenCart не уменьшает загруженное фото. Типичный снимок в этом магазине — 2235×3365 пикселей и 2,3 МБ, хотя на сайте он нигде не показывается в таком размере.
  2. На каждое фото — набор копий. Для карточки товара, списка, корзины, сравнения и других блоков OpenCart создаёт отдельные миниатюры в image/cache. Здесь это около 8 размеров на каждое фото.
  3. Удалённый товар не забирает с собой фото. Когда товар удаляют в админке, исчезает только запись в базе, а файлы остаются на диске. Ассортимент за годы сменился, а фото старых коллекций никуда не делись.

Каталог растёт с каждой поставкой, так что диск закончится рано или поздно. Вопрос только в том, когда.

Что мы сделали

1. Освободили место, чтобы восстановить загрузку

Сначала убрали то, что можно удалить без риска, — кеш миниатюр image/cache. OpenCart создаёт его заново при первом открытии страницы. После этого FTP снова начал создавать папки, и менеджер продолжила наполнение.

2. Написали скрипт поиска «осиротевших» фото

Готовые модули очистки для OpenCart мы отбросили: они не знают о нестандартном импорте товаров в этом магазине и могут принять живые фото за мусор. Поэтому написали свой скрипт с простой логикой:

  1. собрать из базы все пути к фото товаров: главные (oc_product) и из галереи (oc_product_image);
  2. пройти папку с оригиналами и сверить каждый файл со списком;
  3. файл, которого нет в базе, удалить; папку товара, ставшую пустой, — тоже.

Ядро проверки занимает несколько строк:

$used = [];
foreach (['product', 'product_image'] as $table) {
    $res = $db->query("SELECT image FROM " . DB_PREFIX . $table . " WHERE image <> ''");
    while ($row = $res->fetch_assoc()) {
        $used[$row['image']] = true;   // catalog/nobrand/038939/2.jpg
    }
}

// path on disk -> path as stored in the database
$relative = str_replace(DIR_IMAGE, '', $fullPath);

if (!isset($used[$relative])) {
    unlink($fullPath);   // dry run: echo $relative;
}

Главный риск такого скрипта — стереть живые фото. Поэтому работали так:

  • Сначала — режим имитации. Скрипт ничего не удалял, а показывал первые 100 файлов-кандидатов и примеры путей из базы. Так мы убедились, что пути на диске и в базе записаны одинаково (catalog/..., без слеша в начале). Если бы они отличались хоть на один символ, скрипт посчитал бы мусором вообще всё.
  • Только папка с фото товаров. Картинки категорий, баннеров и производителей лежат отдельно, и скрипт их не трогает.
  • Запуск из консоли, а не из браузера. Обход сотен гигабайт длится дольше, чем позволяет таймаут веб-сервера. Запуск, оборванный посередине, оставил бы непонятным, что уже удалено. Через PHP CLI скрипт работает до конца и выводит прогресс каждые 5000 файлов.
  • После работы скрипт удалили с сервера. Оставленный в корне сайта, он позволил бы любому стереть фото, просто открыв ссылку.

3. Оптимизировали фото и перевели в WebP

Сначала попробовали сжать оригиналы без потерь утилитой jpegoptim. На реальных фото магазина это почти ничего не дало: 2 274 925 → 2 273 571 байт, то есть 0,06%. Снимки из фотостудии уже сохранены с хорошим сжатием, и без потери качества из них ничего не выжать.

Поэтому мы написали собственный скрипт, который проходит каждое изображение, оптимизирует его и конвертирует в WebP. Здесь есть нюанс OpenCart: пути к фото хранятся в базе с расширением .jpg. Если просто заменить файлы на диске на WebP, картинки на сайте пропадут. Поэтому смена формата должна идти вместе с заменой путей в базе.

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

Результат

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

Как не довести свой магазин до такого

  • Настройте уведомление о заполнении диска, например на 80%. Ошибка FTP — это уже поздний симптом.
  • Уменьшайте фото до загрузки. Оригинал на 3000+ пикселей лежит на диске навсегда, хотя сайту нужен гораздо меньший.
  • Раз в квартал проверяйте размер папки image и чистите фото удалённых товаров.
  • Перед массовым удалением — бэкап и режим имитации. Восстановить стёртые фото без копии невозможно.

Такие задачи мы решаем в рамках обслуживания сайтов: следим за состоянием сервера и сайта, чтобы проблема не дошла до покупателей. Если ваш магазин на OpenCart замедлился или сервер «съедает» место, напишите нам — посмотрим.

Интересуют наши услуги?
Оставьте заявку!
Отправляя форму, Вы даете согласие на обработку персональных данных. Мы гарантируем что ваши данные никогда не будут переданы третьим лицам.
Отправляем...

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

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

Стандартный OpenCart при удалении товара убирает только записи в базе данных, а файлы изображений остаются на диске. Их приходится чистить отдельно — вручную или скриптом, который сверяет файлы с базой.

Выполните на сервере df -h (свободное место) и df -i (лимит количества файлов), а также проверьте дисковую квоту FTP-пользователя в панели хостинга. Типичные симптомы — ошибка 550 при создании папки и отказ докачивать файлы.

Только вместе с заменой путей в базе данных: OpenCart хранит их с расширением .jpg, и без этого фото на сайте пропадут.

Telegram
Написать в Telegram Ответим за 5 минут