119 lines
3.8 KiB
PHP
119 lines
3.8 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Support;
|
|
|
|
use App\Models\TicketAttachment;
|
|
use Illuminate\Http\UploadedFile;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Livewire\Features\SupportFileUploads\TemporaryUploadedFile;
|
|
|
|
class TicketAttachmentUploadService
|
|
{
|
|
/**
|
|
* @param UploadedFile|TemporaryUploadedFile $file
|
|
* @return array{path:string,mime:string,size:int,original_name:string}
|
|
*/
|
|
public function store(object $file, string $directory): array
|
|
{
|
|
$path = $file->store($directory, 'public');
|
|
|
|
$originalName = method_exists($file, 'getClientOriginalName')
|
|
? (string) $file->getClientOriginalName()
|
|
: basename($path);
|
|
|
|
$mime = TicketAttachment::normalizeMimeType(
|
|
method_exists($file, 'getClientMimeType') ? (string) $file->getClientMimeType() : '',
|
|
$originalName,
|
|
$path,
|
|
);
|
|
|
|
if (str_starts_with($mime, 'image/')) {
|
|
$this->optimizeImage($path, $mime);
|
|
$mime = TicketAttachment::normalizeMimeType($mime, $originalName, $path);
|
|
}
|
|
|
|
$size = 0;
|
|
try {
|
|
$size = (int) Storage::disk('public')->size($path);
|
|
} catch (\Throwable) {
|
|
$size = (int) (method_exists($file, 'getSize') ? $file->getSize() : 0);
|
|
}
|
|
|
|
return [
|
|
'path' => $path,
|
|
'mime' => $mime,
|
|
'size' => $size,
|
|
'original_name' => $originalName,
|
|
];
|
|
}
|
|
|
|
private function optimizeImage(string $path, string $mime): void
|
|
{
|
|
$absolutePath = Storage::disk('public')->path($path);
|
|
if (! is_file($absolutePath) || ! function_exists('getimagesize')) {
|
|
return;
|
|
}
|
|
|
|
$size = @getimagesize($absolutePath);
|
|
if (! is_array($size)) {
|
|
return;
|
|
}
|
|
|
|
[$width, $height] = $size;
|
|
if ($width <= 0 || $height <= 0) {
|
|
return;
|
|
}
|
|
|
|
$maxWidth = 1600;
|
|
$maxHeight = 1600;
|
|
$ratio = min($maxWidth / $width, $maxHeight / $height, 1);
|
|
$targetW = (int) max(1, round($width * $ratio));
|
|
$targetH = (int) max(1, round($height * $ratio));
|
|
|
|
$source = $this->createImageResource($absolutePath, $mime);
|
|
if (! $source) {
|
|
return;
|
|
}
|
|
|
|
$target = imagecreatetruecolor($targetW, $targetH);
|
|
if ($target === false) {
|
|
imagedestroy($source);
|
|
return;
|
|
}
|
|
|
|
if (in_array($mime, ['image/png', 'image/webp'], true)) {
|
|
imagealphablending($target, false);
|
|
imagesavealpha($target, true);
|
|
$transparent = imagecolorallocatealpha($target, 255, 255, 255, 127);
|
|
imagefilledrectangle($target, 0, 0, $targetW, $targetH, $transparent);
|
|
}
|
|
|
|
imagecopyresampled($target, $source, 0, 0, 0, 0, $targetW, $targetH, $width, $height);
|
|
|
|
switch ($mime) {
|
|
case 'image/png':
|
|
imagepng($target, $absolutePath, 6);
|
|
break;
|
|
case 'image/webp':
|
|
if (function_exists('imagewebp')) {
|
|
imagewebp($target, $absolutePath, 82);
|
|
}
|
|
break;
|
|
default:
|
|
imagejpeg($target, $absolutePath, 82);
|
|
break;
|
|
}
|
|
|
|
imagedestroy($target);
|
|
imagedestroy($source);
|
|
}
|
|
|
|
private function createImageResource(string $absolutePath, string $mime)
|
|
{
|
|
return match ($mime) {
|
|
'image/png' => function_exists('imagecreatefrompng') ? @imagecreatefrompng($absolutePath) : false,
|
|
'image/webp' => function_exists('imagecreatefromwebp') ? @imagecreatefromwebp($absolutePath) : false,
|
|
default => function_exists('imagecreatefromjpeg') ? @imagecreatefromjpeg($absolutePath) : false,
|
|
};
|
|
}
|
|
} |