resolvePath($file); $extension = $this->resolveExtension($file, $sourcePath); $this->assertSupported($extension); if (! in_array($extension, self::IMAGE_EXTENSIONS, true)) { throw new InvalidArgumentException('Nur Bilddateien koennen mit convertImage verarbeitet werden.'); } $this->assertSize($file, $sourcePath); $filename = Str::uuid()->toString() . '.jpg'; $relativePath = 'slides/' . $filename; $targetPath = Storage::disk('public')->path($relativePath); Storage::disk('public')->makeDirectory('slides'); $this->ensureDirectory(dirname($targetPath)); $manager = $this->createImageManager(); $canvas = $manager->create(1920, 1080)->fill('000000'); $image = $manager->read($sourcePath); $image->scaleDown(width: 1920, height: 1080); $canvas->place($image, 'center'); $canvas->save($targetPath, quality: 90); $thumbnailPath = $this->generateThumbnail($relativePath); return [ 'filename' => $relativePath, 'thumbnail' => $thumbnailPath, ]; } public function convertPowerPoint(UploadedFile|string|SplFileInfo $file): string { $sourcePath = $this->resolvePath($file); $extension = $this->resolveExtension($file, $sourcePath); $this->assertSupported($extension); if (! in_array($extension, self::POWERPOINT_EXTENSIONS, true)) { throw new InvalidArgumentException('Nur PPT/PPTX-Dateien sind hier erlaubt.'); } $this->assertSize($file, $sourcePath); $jobId = Str::uuid()->toString(); ConvertPowerPointJob::dispatch($sourcePath, $jobId); return $jobId; } public function processZip(UploadedFile|string|SplFileInfo $file): array { $sourcePath = $this->resolvePath($file); $extension = $this->resolveExtension($file, $sourcePath); $this->assertSupported($extension); if ($extension !== 'zip') { throw new InvalidArgumentException('processZip erwartet eine ZIP-Datei.'); } $this->assertSize($file, $sourcePath); $zip = new ZipArchive(); if ($zip->open($sourcePath) !== true) { throw new InvalidArgumentException('ZIP-Datei konnte nicht geoeffnet werden.'); } $extractDir = storage_path('app/temp/zip-' . Str::uuid()->toString()); if (! is_dir($extractDir) && ! mkdir($extractDir, 0775, true) && ! is_dir($extractDir)) { throw new InvalidArgumentException('Temporaires ZIP-Verzeichnis konnte nicht erstellt werden.'); } $zip->extractTo($extractDir); $zip->close(); $results = []; $iterator = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($extractDir, RecursiveDirectoryIterator::SKIP_DOTS) ); foreach ($iterator as $entry) { if (! $entry instanceof SplFileInfo || ! $entry->isFile()) { continue; } $entryPath = $entry->getRealPath(); if ($entryPath === false) { continue; } $entryExtension = $this->extensionFromPath($entryPath); if (! in_array($entryExtension, self::SUPPORTED_EXTENSIONS, true)) { continue; } if (in_array($entryExtension, self::IMAGE_EXTENSIONS, true)) { $results[] = $this->convertImage($entryPath); continue; } if (in_array($entryExtension, self::POWERPOINT_EXTENSIONS, true)) { $results[] = ['job_id' => $this->convertPowerPoint($entryPath)]; continue; } $results = [...$results, ...$this->processZip($entryPath)]; } $this->deleteDirectory($extractDir); return $results; } public function generateThumbnail(string $path): string { $absolutePath = str_starts_with($path, DIRECTORY_SEPARATOR) ? $path : Storage::disk('public')->path($path); if (! is_file($absolutePath)) { throw new InvalidArgumentException('Datei fuer Thumbnail nicht gefunden.'); } $filename = pathinfo($absolutePath, PATHINFO_FILENAME) . '.jpg'; $thumbnailRelativePath = 'slides/thumbnails/' . $filename; $thumbnailAbsolutePath = Storage::disk('public')->path($thumbnailRelativePath); Storage::disk('public')->makeDirectory('slides/thumbnails'); $this->ensureDirectory(dirname($thumbnailAbsolutePath)); $manager = $this->createImageManager(); $canvas = $manager->create(320, 180)->fill('000000'); $image = $manager->read($absolutePath); $image->scaleDown(width: 320, height: 180); $canvas->place($image, 'center'); $canvas->save($thumbnailAbsolutePath, quality: 85); return $thumbnailRelativePath; } private function resolvePath(UploadedFile|string|SplFileInfo $file): string { if ($file instanceof UploadedFile) { $path = $file->getRealPath(); if ($path === false || ! is_file($path)) { throw new InvalidArgumentException('Upload-Datei ist ungueltig.'); } return $path; } if ($file instanceof SplFileInfo) { $path = $file->getRealPath(); if ($path === false) { throw new InvalidArgumentException('Dateipfad ist ungueltig.'); } return $path; } if (! is_file($file)) { throw new InvalidArgumentException('Datei wurde nicht gefunden.'); } return $file; } private function assertSupported(string $extension): void { if (! in_array($extension, self::SUPPORTED_EXTENSIONS, true)) { throw new InvalidArgumentException('Dateityp wird nicht unterstuetzt.'); } } private function extensionFromPath(string $path): string { return strtolower((string) pathinfo($path, PATHINFO_EXTENSION)); } private function resolveExtension(UploadedFile|string|SplFileInfo $file, string $sourcePath): string { if ($file instanceof UploadedFile) { return strtolower($file->getClientOriginalExtension()); } return $this->extensionFromPath($sourcePath); } private function assertSize(UploadedFile|string|SplFileInfo $file, string $resolvedPath): void { $size = $file instanceof UploadedFile ? ($file->getSize() ?? 0) : (filesize($resolvedPath) ?: 0); if ($size > self::MAX_FILE_SIZE_BYTES) { throw new InvalidArgumentException('Datei ist groesser als 50MB.'); } } private function deleteDirectory(string $directory): void { if (! is_dir($directory)) { return; } $iterator = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST ); foreach ($iterator as $item) { if (! $item instanceof SplFileInfo) { continue; } if ($item->isDir()) { @rmdir($item->getPathname()); continue; } @unlink($item->getPathname()); } @rmdir($directory); } private function ensureDirectory(string $directory): void { if (is_dir($directory)) { return; } if (! mkdir($directory, 0775, true) && ! is_dir($directory)) { throw new InvalidArgumentException('Zielverzeichnis konnte nicht erstellt werden.'); } } private function createImageManager(): mixed { $managerClass = implode('\\', ['Intervention', 'Image', 'ImageManager']); $driverClass = implode('\\', ['Intervention', 'Image', 'Drivers', 'Gd', 'Driver']); return new $managerClass(new $driverClass()); } }