make(Illuminate\Contracts\Console\Kernel::class)->bootstrap(); $options = getopt('', ['id::', 'limit::', 'publish']); $id = isset($options['id']) ? (int) $options['id'] : null; $limit = isset($options['limit']) ? max(1, (int) $options['limit']) : 25; $publish = array_key_exists('publish', $options); $brokenQuery = Artwork::query()->where(function ($query): void { $query->where('file_path', 'pending') ->orWhereNull('hash') ->orWhereNull('file_ext') ->orWhereNull('thumb_ext') ->orWhere('file_name', 'pending') ->orWhere('file_size', 0) ->orWhere('width', '<=', 1) ->orWhere('height', '<=', 1); }); if ($id && $id > 0) { $brokenQuery->whereKey($id); } $rows = $brokenQuery->orderBy('id')->limit($limit)->get(); if ($rows->isEmpty()) { fwrite(STDOUT, "No matching broken artworks found.\n"); exit(0); } $storageRoot = rtrim((string) config('uploads.storage_root'), DIRECTORY_SEPARATOR); $fixed = 0; $skipped = 0; $makeUniqueSlug = static function (Artwork $artwork, string $title): string { $base = Str::slug($title); if ($base === '') { $base = 'artwork-' . $artwork->id; } $slug = $base; $suffix = 2; while (Artwork::query()->where('slug', $slug)->where('id', '!=', $artwork->id)->exists()) { $slug = $base . '-' . $suffix; $suffix++; } return $slug; }; foreach ($rows as $artwork) { $files = DB::table('artwork_files') ->where('artwork_id', $artwork->id) ->get(['variant', 'path', 'mime', 'size']) ->keyBy('variant'); $orig = $files->get('orig'); if (! $orig || empty($orig->path)) { fwrite(STDOUT, "[SKIP] {$artwork->id}: no orig variant in artwork_files\n"); $skipped++; continue; } $origPath = (string) $orig->path; $absolute = $storageRoot . DIRECTORY_SEPARATOR . str_replace(['/', '\\\\'], DIRECTORY_SEPARATOR, $origPath); $hash = null; $fileSize = (int) ($orig->size ?? 0); $width = (int) $artwork->width; $height = (int) $artwork->height; if (is_file($absolute)) { $hash = hash_file('sha256', $absolute) ?: null; $actualSize = @filesize($absolute); if (is_int($actualSize) && $actualSize > 0) { $fileSize = $actualSize; } $dimensions = @getimagesize($absolute); if (is_array($dimensions) && isset($dimensions[0], $dimensions[1])) { $width = max(1, (int) $dimensions[0]); $height = max(1, (int) $dimensions[1]); } } $ext = strtolower((string) pathinfo($origPath, PATHINFO_EXTENSION)); if ($ext === '') { $ext = 'webp'; } $title = trim((string) ($artwork->title ?? '')); if ($title === '') { $title = 'Artwork ' . $artwork->id; } $slug = $makeUniqueSlug($artwork, $title); $updates = [ 'title' => $title, 'slug' => $slug, 'file_name' => basename($origPath), 'file_path' => $origPath, 'file_size' => max(1, $fileSize), 'mime_type' => (string) ($orig->mime ?: 'image/webp'), 'hash' => $hash ?: (string) ($artwork->hash ?? ''), 'file_ext' => $ext, 'thumb_ext' => $ext, 'width' => max(1, $width), 'height' => max(1, $height), ]; if ($publish) { $updates['is_public'] = true; $updates['is_approved'] = true; $updates['published_at'] = $artwork->published_at ?: now(); } if (empty($updates['hash'])) { fwrite(STDOUT, "[SKIP] {$artwork->id}: hash could not be recovered from file\n"); $skipped++; continue; } Artwork::query()->whereKey($artwork->id)->update($updates); fwrite(STDOUT, "[FIXED] {$artwork->id}: {$updates['file_path']} | hash=" . substr((string) $updates['hash'], 0, 12) . "...\n"); $fixed++; } fwrite(STDOUT, "Done. fixed={$fixed} skipped={$skipped}\n"); exit(0);