$file->store("ticket-attachments/{$customerId}", self::DISK), $files, ); } /** * @return string[] */ public static function clientUrls(Ticket $ticket): array { return array_map( fn (int $index) => "/v1/client/tickets/{$ticket->ticket_num}/images/{$index}", array_keys(self::entries($ticket)), ); } /** * @return string[] */ public static function adminUrls(Ticket $ticket): array { return array_map( fn (int $index) => URL::temporarySignedRoute( 'admin.tickets.image', now()->addDay(), ['ticket' => $ticket->ticket_num, 'index' => $index], ), array_keys(self::entries($ticket)), ); } public static function moveLegacyToPrivate(Ticket $ticket): bool { $moved = false; $gallery = array_map(function (string $entry) use ($ticket, &$moved) { $location = self::locate($entry); if ($location === null || $location[0] !== self::LEGACY_DISK) { return $entry; } $target = "ticket-attachments/{$ticket->customer_id}/" . basename($location[1]); Storage::disk(self::DISK)->writeStream($target, Storage::disk(self::LEGACY_DISK)->readStream($location[1])); Storage::disk(self::LEGACY_DISK)->delete($location[1]); $moved = true; return $target; }, self::entries($ticket)); if ($moved) { $ticket->forceFill(['gallery' => $gallery])->saveQuietly(); } return $moved; } public static function response(Ticket $ticket, int $index): StreamedResponse { $location = self::locate(self::entries($ticket)[$index] ?? null); abort_if($location === null, 404); [$disk, $path] = $location; return Storage::disk($disk)->response($path, null, ['Cache-Control' => 'private, max-age=3600']); } /** * @return string[] */ private static function entries(Ticket $ticket): array { return array_values(array_filter( (array) ($ticket->gallery ?? []), fn ($entry) => is_string($entry) && $entry !== '', )); } /** * @return array{0: string, 1: string}|null */ private static function locate(?string $entry): ?array { if ($entry === null) { return null; } [$disk, $path] = [self::DISK, $entry]; if (preg_match('#^https?://#i', $entry)) { $urlPath = (string) parse_url($entry, PHP_URL_PATH); $offset = strpos($urlPath, self::LEGACY_URL_SEGMENT); if ($offset === false) { return null; } [$disk, $path] = [self::LEGACY_DISK, rawurldecode(substr($urlPath, $offset + strlen(self::LEGACY_URL_SEGMENT)))]; } if (str_contains($path, '..') || ! Storage::disk($disk)->exists($path)) { return null; } return [$disk, $path]; } }