HEX
Server: nginx/1.18.0
System: Linux test-ipsremont 5.4.0-214-generic #234-Ubuntu SMP Fri Mar 14 23:50:27 UTC 2025 x86_64
User: ips (1000)
PHP: 8.0.30
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: /var/www/ipsremont-demo/app/Console/Commands/RepairAttachmentCleaner.php
<?php

namespace App\Console\Commands;

use App\Models\Repair\Repair;
use App\Models\RepairAttachment;
use App\Repository\RepairAttachment\RepairAttachmentRepository;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage;
use Spatie\ImageOptimizer\OptimizerChainFactory;
use Spatie\ImageOptimizer\Optimizers\Jpegoptim;
use Symfony\Component\Console\Command\Command as CommandAlias;

class RepairAttachmentCleaner extends Command
{

    protected $signature = 'repair-attachment:clean';

    protected $description = 'Чистит приложения нарядов';

    private $totalSize = 0;

    private function removeDrafts()
    {
        $this->info('Удаляем старые черновики');
        $draft = RepairAttachmentRepository::getDrafts(date('Y-m-d', strtotime('-1 week')));
        $this->line('Найдено файлов: ' . count($draft));
        $size = 0;
        foreach ($draft as $item) {
            /** @var RepairAttachment $item */
            $filePath = storage_path($item->path);
            if (file_exists($filePath)) {
                $size += filesize($filePath);
                unlink($filePath);
            } else {
                $this->line('Файл не найден: ' . $item->original_name);
            }
            $item->delete();
        }

        $this->totalSize += $size;
        $this->line('Освобождено места: ' . round($size / 1024 / 1024, 2) . ' Mb');
    }

    private function removeGarbage()
    {
        $this->info('Удаляем мусор которого нет в базе');
        $repairAttachments = RepairAttachmentRepository::getAll();
        $repairAttachmentPaths = [];
        foreach ($repairAttachments as $repairAttachment) {
            $repairAttachmentPaths[] = $repairAttachment->path;
        }
        $this->line('Файлов в базе: ' . count($repairAttachments));

        $files = Storage::files(RepairAttachment::PATH);
        $this->line('Файлов на сервере: ' . count($files));

        $size = 0;
        foreach ($files as $file) {
            if (!in_array($file, $repairAttachmentPaths)) {
                $filePath = storage_path($file);
                $size += filesize($filePath);
                $this->line('Файла нет в базе: ' . $file);
                if (Storage::exists($file)) {
                    Storage::delete($file);
                }
            }
        }

        $this->totalSize += $size;
        $this->line('Освобождено места: ' . round($size / 1024 / 1024, 2) . ' Mb');
    }

    private function rotateOld()
    {
        $this->info('Ротируем старые приложение');
        $repairAttachments = RepairAttachmentRepository::getOld();
        $repairIds = $repairAttachments->pluck('repair_id')->unique()->toArray();
        $repairIds = Repair::query()->whereIn('id', $repairIds)->where('created_at', '<=', date('Y-m-d', strtotime('-1 year')))->pluck('id')->toArray();
        $this->line('Старых заявок: ' . count($repairIds));
        $toRemove = [];
        foreach ($repairAttachments as $repairAttachment) {
            if (!in_array($repairAttachment->repair_id, $repairIds)) {
                continue;
            }

            $toRemove[] = $repairAttachment;
        }
        $this->line('Файлов на удаление: ' . count($toRemove));
        $size = 0;
        foreach ($toRemove as $item) {
            /** @var RepairAttachment $item */
            $filePath = storage_path($item->path);
            if (file_exists($filePath)) {
                $size += filesize($filePath);
                unlink($filePath);
            } else {
                $this->line('Файл не найден: ' . $item->original_name);
            }
            $item->delete();
        }

        $this->totalSize += $size;
        $this->line('Освобождено места: ' . round($size / 1024 / 1024, 2) . ' Mb');
    }

    private function optimizeBigImages()
    {
        $this->info('Пережимаем большие изображения');

        $repairAttachments = RepairAttachmentRepository::getBigJpg();
        $oldSize = 0;
        $newSize = 0;
        $totalCount = count($repairAttachments);
        $this->line('Больших файлов: ' . $totalCount);
        $count = 0;
        foreach ($repairAttachments as $repairAttachment) {
            $count++;
            $this->line($count . '/' . $totalCount);
            /** @var RepairAttachment $repairAttachment */
            $filePath = storage_path($repairAttachment->path);

            $oldSize += filesize($filePath);
            if ($oldSize != $repairAttachment->size) {
                $repairAttachment->size = $oldSize;
                $repairAttachment->save();
                continue;
            }

            $optimizerChain = OptimizerChainFactory::create();
            $optimizerChain->addOptimizer(new Jpegoptim(['--m75']));
            // Это надо если мы хотим старые не удалять
            // $newFilePath = str_replace('.jpg', '_opt.jpg', $filePath);
            // $optimizerChain->optimize($filePath, $newFilePath);
            $optimizerChain->optimize($filePath);
            $repairAttachment->size = $newSize;
            $repairAttachment->is_optimized = true;
            $repairAttachment->save();
            $newSize += filesize($filePath);
        }
        $size = $oldSize - $newSize;

        $this->totalSize += $size;
        $this->line('Освобождено места: ' . round($size / 1024 / 1024, 2) . ' Mb');
    }

    public function handle(): int
    {
        $this->info($this->description);

        $this->removeDrafts();
        $this->removeGarbage();
        $this->rotateOld();
        $this->optimizeBigImages();

        $this->info('Всего освобождено места: ' . round($this->totalSize / 1024 / 1024, 2) . ' Mb');

        return CommandAlias::SUCCESS;
    }

}