Files
ai-stylegallery/app/Http/Controllers/DownloadController.php
soeren f5da8ed877 - Galerien sind nun eine Entität - es kann mehrere geben
- Neues Sparkbooth-Upload-Feature: Endpoint /api/sparkbooth/upload (Token-basiert pro Galerie), Controller Api/SparkboothUploadController, Migration 2026_01_21_000001_add_upload_fields_to_galleries_table.php mit Upload-Flags/Token/Expiry;
    Galerie-Modell und Factory/Seeder entsprechend erweitert.
  - Filament: Neue Setup-Seite SparkboothSetup (mit View) zur schnellen Galerie- und Token-Erstellung inkl. QR/Endpoint/Snippet;
    Galerie-Link-Views nutzen jetzt simple-qrcode (Composer-Dependency hinzugefügt) und bieten PNG-Download.
  - Galerie-Tabelle: Slug/Pfad-Spalten entfernt, Action „Link-Details“ mit Modal; Created-at-Spalte hinzugefügt.
  - Zugriffshärtung: Galerie-IDs in API (ImageController, Download/Print) geprüft; GalleryAccess/Middleware + Gallery-Modell/Slug-UUID
    eingeführt; GalleryAccess-Inertia-Seite.
  - UI/UX: LoadingSpinner/StyledImageDisplay verbessert, Delete-Confirm, Übersetzungen ergänzt.
2025-12-04 07:52:50 +01:00

94 lines
2.9 KiB
PHP

<?php
namespace App\Http\Controllers;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
class DownloadController extends Controller
{
public function downloadImage(Request $request)
{
$request->validate([
'image_path' => 'required|string',
'gallery' => 'required|string|exists:galleries,slug',
]);
$gallery = \App\Models\Gallery::where('slug', $request->string('gallery'))->firstOrFail();
$resolvedPath = $this->resolveImagePath($request->input('image_path'));
$expectedFragment = DIRECTORY_SEPARATOR.trim($gallery->images_path, '/').DIRECTORY_SEPARATOR;
if (! $resolvedPath || ! File::exists($resolvedPath) || ! str_contains($resolvedPath, $expectedFragment)) {
Log::error("DownloadController: Image file not found at {$resolvedPath}");
return response()->json(['error' => 'Image file not found.'], 404);
}
$extension = strtolower(File::extension($resolvedPath) ?: 'jpg');
$downloadName = $this->buildDownloadName($extension);
$mimeType = File::mimeType($resolvedPath) ?: $this->getMimeType($extension);
try {
Log::info("DownloadController: Serving download for {$resolvedPath}");
return response()->download($resolvedPath, $downloadName, [
'Content-Type' => $mimeType,
'Content-Disposition' => 'attachment; filename="'.$downloadName.'"',
]);
} catch (\Exception $e) {
Log::error('DownloadController: Error serving download: '.$e->getMessage());
return response()->json(['error' => 'Failed to serve download.'], 500);
}
}
private function resolveImagePath(string $path): ?string
{
if (filter_var($path, FILTER_VALIDATE_URL)) {
$parsed = parse_url($path, PHP_URL_PATH);
return $parsed ? public_path(ltrim($parsed, '/')) : null;
}
if (Str::startsWith($path, ['storage/', 'public/'])) {
return public_path(ltrim($path, '/'));
}
if (File::exists($path)) {
return $path;
}
$candidate = public_path(ltrim($path, '/'));
return File::exists($candidate) ? $candidate : null;
}
private function buildDownloadName(string $extension): string
{
$timestamp = Carbon::now()->format('Ymd_His');
return sprintf('stylegallery_%s.%s', $timestamp, $extension);
}
private function getMimeType(string $extension): string
{
$mimeTypes = [
'jpg' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'png' => 'image/png',
'gif' => 'image/gif',
'webp' => 'image/webp',
'bmp' => 'image/bmp',
'svg' => 'image/svg+xml',
];
return $mimeTypes[strtolower($extension)] ?? 'application/octet-stream';
}
}