<?php
namespace App\Services;
use App\Helpers\Ulid;
use App\Values\ImageWritingConfig;
use Illuminate\Support\Facades\File;
use RuntimeException;
class ImageStorage
{
public function __construct(
private readonly ImageWriter $imageWriter,
private readonly SvgSanitizer $svgSanitizer,
) {
}
/**
* Store an image file and return the (randomly generated) file name.
*
* @param mixed $source Any kind of image data that Intervention can read.
* @param ?string $path The path to store the image file. Randomly generated if not provided.
*
* @return string The file name.
*/
public function storeImage(mixed $source, ?ImageWritingConfig $config = null, ?string $path = null): string
{
preg_match('/^data:(image\/[A-Za-z0-9+\-.]+);base64,/', $source, $matches);
$mime = $matches[1] ?? null;
if ($mime === 'image/svg+xml') {
$svgData = preg_replace('/^data:image\/svg\+xml;base64,/', '', $source);
$raw = base64_decode($svgData, true);
if ($raw === false) {
throw new RuntimeException('Failed to decode base64 SVG data.');
}
$sanitized = $this->svgSanitizer->sanitize($raw);
if (!$sanitized) {
throw new RuntimeException('Invalid SVG file.');
}
$path ??= self::generateRandomStoragePath('svg');
File::put($path, $sanitized);
return basename($path);
}
$path ??= self::generateRandomStoragePath();
$this->imageWriter->write($path, $source, $config);
return basename($path);
}
private static function generateRandomStoragePath(string $extension = 'webp'): string
{
return image_storage_path(sprintf("%s.%s", Ulid::generate(), $extension));
}
}