Боль, которую мы все знаем

Анализируете хранилище и находите десятки копий одного файла? Пользователи загружают одинаковые документы, и вот уже:

  • ? Хранилище раздувается на десятки процентов

  • Бэкапы хранят лишнее вместо того чтобы хранить нужное

  • ? Данные теряют консистентность - разные модели ссылаются на разные копии

  • ? Деньги за место улетают впустую

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

✨Laravel Storage Dedupler

Dedupler — Laravel-пакет, который автоматически предотвращает дубликаты файлов через SHA-1 хеширование.

⚙️Как это работает изнутри

Каждый файл получает уникальный SHA-1 отпечаток

$hash = sha1_file($file->getPathname());

Хеш есть в БД → возвращаем существующий файл
Хеша нет → сохраняем и создаём запись
Все модели ссылаются на один физический файл

?Quick Start нового проекта без лишних копий

Подключаем и устанавливаем

composer require maxkhim/laravel-storage-dedupler
php artisan dedupler:install

Используем Dedupler через трейт

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

// Используем в модели
class Post extends Model
{
    use Deduplable;
}

И далее во всех точках вызова для сохранения и "прикрепления" файла к модели:

// Загружаем файлы
$uniqueFile = $post->storeUploadedFile($file); // Физически сохраняется один раз
// Загружаем ещё раз
$uniqueFile = $post->storeUploadedFile($sameFile); // Возвращает существующую запись
// Загружаем из локального хранилища
$uniqueFile = $post->storeLocalFile($absolutePathToFile); // Возвращает существующую запись
// Загружаем файл из переменных
$uniqueFile = $post->storeContentFile($content, $fileName); // Возвращает существующую запись

Или без прикрепления к моделям через фасад

$uniqueFile = Dedupler::storeFromPath($absolutePathToFile);  
$uniqueFile = Dedupler::storeFromUploadedFile($file); 
$uniqueFile = Dedupler::storeFromContent($content, $fileName);

Структура хранения

storage/
└── deduplicated/
    └── da/
		└── 39/
	         └── da39a3ee5e6b4b0d3255bfef95601890afd80709.pdf

Сборка мусора

php artisan dedupler:prune --help

Миграция структуры Legacy-проектов

Выполняем миграцию legacy структуры на хранилище без дубликатов (файлы в первоначальных местах заменяются симлинками на новое расположение в дедуплицированом хранилище)

php artisan dedupler:migrate-legacy --help

Произвольный кейс из боевого проекта

CMS для медиа-портала

Пакет был испробован для анализа архивных изображений

  • Было найдено: 35k дубликатов изображений (из 475k файлов)

  • Освобождено: 1GB (из 12GB)

  • Отдедуплено: за 32 мин

Планы по развитию

  • Дополнительные методы RestAPI

  • Расширение консольных команд для бэнчмарка оценки полезности дедупликации, миграции из структуры Legacy проектов

  • Улучшение производительности для больших файлов

Попробуйте в деле

GitHub: https://github.com/maxkhim/laravel-storage-dedupler
Packagist: https://packagist.org/packages/maxkhim/laravel-storage-dedupler
Документация: в README.md

P.S. Первые 5 качественных Issue (сообщения об ошибках или предложения функций) получат упоминания в релизных нотах! ?

P.S.S Пакет заапрувили Laravel News, это вдохновляет на дальнейшее развитие!

Комментарии (1)


  1. maxkhim Автор
    01.11.2025 09:22

    Всем привет, автор здесь. Вижу, что статью читают - уже 90 просмотров за 2 часа!
    Но пока тишина в комментариях.

    Старался сделать акцент на технической стороне, миграции legacy-проектов и потенциальной пользе. Если есть конкретные вопросы - с радостью отвечу!

    Давайте запустим дискуссию:

    • Кто уже сталкивался с проблемой дубликатов файлов?
    • Если да, какие решения пробовали до этого?
    • Есть ли опыт миграции legacy-хранилищ?