Files
SkinbaseNova/app/Services/Enhance/EnhanceValidator.php

128 lines
4.5 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Services\Enhance;
use Illuminate\Http\UploadedFile;
use Illuminate\Validation\ValidationException;
final class EnhanceValidator
{
public function validateUpload(UploadedFile $file, array $options): array
{
$path = (string) ($file->getRealPath() ?: $file->getPathname());
if ($path === '' || ! is_readable($path)) {
throw ValidationException::withMessages([
'image' => 'Unable to read the uploaded image.',
]);
}
$binary = file_get_contents($path);
if (! is_string($binary) || $binary === '') {
throw ValidationException::withMessages([
'image' => 'Unable to read the uploaded image.',
]);
}
return $this->validateBinary($binary, $options, (int) ($file->getSize() ?? strlen($binary)));
}
public function validateBinary(string $binary, array $options, ?int $filesize = null): array
{
$normalized = $this->normalizeOptions($options);
$size = $filesize ?? strlen($binary);
if ($size <= 0) {
throw ValidationException::withMessages([
'image' => 'Uploaded image is empty.',
]);
}
$maxBytes = (int) config('enhance.max_upload_mb', 20) * 1024 * 1024;
if ($maxBytes > 0 && $size > $maxBytes) {
throw ValidationException::withMessages([
'image' => sprintf('The image may not be greater than %d MB.', (int) config('enhance.max_upload_mb', 20)),
]);
}
$finfo = new \finfo(FILEINFO_MIME_TYPE);
$mime = strtolower((string) $finfo->buffer($binary));
if (! in_array($mime, (array) config('enhance.allowed_mimes', []), true)) {
throw ValidationException::withMessages([
'image' => 'Unsupported image format. Upload a JPEG, PNG, or WebP image.',
]);
}
$dimensions = @getimagesizefromstring($binary);
if (! is_array($dimensions) || (int) ($dimensions[0] ?? 0) < 1 || (int) ($dimensions[1] ?? 0) < 1) {
throw ValidationException::withMessages([
'image' => 'Uploaded file is not a valid image.',
]);
}
$width = (int) ($dimensions[0] ?? 0);
$height = (int) ($dimensions[1] ?? 0);
if ($width > (int) config('enhance.max_input_width', 4096)) {
throw ValidationException::withMessages([
'image' => sprintf('Image width may not exceed %d pixels.', (int) config('enhance.max_input_width', 4096)),
]);
}
if ($height > (int) config('enhance.max_input_height', 4096)) {
throw ValidationException::withMessages([
'image' => sprintf('Image height may not exceed %d pixels.', (int) config('enhance.max_input_height', 4096)),
]);
}
return $normalized + [
'input_width' => $width,
'input_height' => $height,
'input_filesize' => $size,
'input_mime' => $mime,
];
}
public function normalizeOptions(array $options): array
{
$allowedScales = array_map('intval', (array) config('enhance.allowed_scales', [2, 4]));
$allowedModes = array_map('strval', (array) config('enhance.allowed_modes', ['standard', 'artwork', 'photo', 'illustration']));
$allowedEngines = [
\App\Models\EnhanceJob::ENGINE_STUB,
\App\Models\EnhanceJob::ENGINE_EXTERNAL_WORKER,
];
$scale = (int) ($options['scale'] ?? config('enhance.allowed_scales.0', 2));
$mode = trim((string) ($options['mode'] ?? 'standard'));
$engine = trim((string) ($options['engine'] ?? config('enhance.default_engine', \App\Models\EnhanceJob::ENGINE_STUB)));
if (! in_array($scale, $allowedScales, true)) {
throw ValidationException::withMessages([
'scale' => 'Please select a supported scale.',
]);
}
if (! in_array($mode, $allowedModes, true)) {
throw ValidationException::withMessages([
'mode' => 'Please select a supported enhance mode.',
]);
}
if (! in_array($engine, $allowedEngines, true)) {
throw ValidationException::withMessages([
'engine' => 'Please select a supported enhance engine.',
]);
}
return [
'scale' => $scale,
'mode' => $mode,
'engine' => $engine,
];
}
}