netgescon-day0/app/Services/Support/TicketAttachmentUploadService.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,
};
}
}