128 lines
4.5 KiB
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,
|
|
];
|
|
}
|
|
} |