Upload beautify
This commit is contained in:
112
app/Services/Uploads/UploadValidationService.php
Normal file
112
app/Services/Uploads/UploadValidationService.php
Normal file
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Uploads;
|
||||
|
||||
use App\DTOs\Uploads\UploadValidationResult;
|
||||
|
||||
final class UploadValidationService
|
||||
{
|
||||
public function validate(string $path): UploadValidationResult
|
||||
{
|
||||
if (! is_file($path) || ! is_readable($path)) {
|
||||
return UploadValidationResult::fail('file_unreadable');
|
||||
}
|
||||
|
||||
$size = (int) filesize($path);
|
||||
$maxBytes = $this->maxSizeBytes();
|
||||
if ($maxBytes > 0 && $size > $maxBytes) {
|
||||
return UploadValidationResult::fail('file_too_large', null, null, null, $size);
|
||||
}
|
||||
|
||||
$mime = $this->detectMime($path);
|
||||
if ($mime === '' || ! in_array($mime, $this->allowedMimes(), true)) {
|
||||
return UploadValidationResult::fail('mime_not_allowed', null, null, $mime, $size);
|
||||
}
|
||||
|
||||
$info = @getimagesize($path);
|
||||
if (! $info || empty($info[0]) || empty($info[1])) {
|
||||
return UploadValidationResult::fail('invalid_image', null, null, $mime, $size);
|
||||
}
|
||||
|
||||
$width = (int) $info[0];
|
||||
$height = (int) $info[1];
|
||||
$maxPixels = $this->maxPixels();
|
||||
if ($maxPixels > 0 && ($width > $maxPixels || $height > $maxPixels)) {
|
||||
return UploadValidationResult::fail('image_too_large', $width, $height, $mime, $size);
|
||||
}
|
||||
|
||||
$data = @file_get_contents($path);
|
||||
if ($data === false) {
|
||||
return UploadValidationResult::fail('file_unreadable', $width, $height, $mime, $size);
|
||||
}
|
||||
|
||||
$image = @imagecreatefromstring($data);
|
||||
if ($image === false) {
|
||||
return UploadValidationResult::fail('decode_failed', $width, $height, $mime, $size);
|
||||
}
|
||||
|
||||
$reencodeOk = $this->reencodeTest($image, $mime);
|
||||
imagedestroy($image);
|
||||
|
||||
if (! $reencodeOk) {
|
||||
return UploadValidationResult::fail('reencode_failed', $width, $height, $mime, $size);
|
||||
}
|
||||
|
||||
return UploadValidationResult::ok($width, $height, $mime, $size);
|
||||
}
|
||||
|
||||
private function maxSizeBytes(): int
|
||||
{
|
||||
return (int) config('uploads.max_size_mb', 0) * 1024 * 1024;
|
||||
}
|
||||
|
||||
private function maxPixels(): int
|
||||
{
|
||||
return (int) config('uploads.max_pixels', 0);
|
||||
}
|
||||
|
||||
private function allowedMimes(): array
|
||||
{
|
||||
$allowed = (array) config('uploads.allowed_mimes', []);
|
||||
if ((bool) config('uploads.allow_gif', false)) {
|
||||
$allowed[] = 'image/gif';
|
||||
}
|
||||
|
||||
return array_values(array_unique($allowed));
|
||||
}
|
||||
|
||||
private function detectMime(string $path): string
|
||||
{
|
||||
$finfo = new \finfo(FILEINFO_MIME_TYPE);
|
||||
$mime = $finfo->file($path);
|
||||
|
||||
return $mime ? (string) $mime : '';
|
||||
}
|
||||
|
||||
private function reencodeTest($image, string $mime): bool
|
||||
{
|
||||
ob_start();
|
||||
$result = false;
|
||||
|
||||
switch ($mime) {
|
||||
case 'image/jpeg':
|
||||
$result = function_exists('imagejpeg') ? imagejpeg($image, null, 80) : false;
|
||||
break;
|
||||
case 'image/png':
|
||||
$result = function_exists('imagepng') ? imagepng($image, null, 6) : false;
|
||||
break;
|
||||
case 'image/webp':
|
||||
$result = function_exists('imagewebp') ? imagewebp($image, null, 80) : false;
|
||||
break;
|
||||
case 'image/gif':
|
||||
$result = function_exists('imagegif') ? imagegif($image) : false;
|
||||
break;
|
||||
}
|
||||
|
||||
$data = ob_get_clean();
|
||||
|
||||
return (bool) $result && is_string($data) && $data !== '';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user