Files
cresta31/app/Http/Controllers/LodgePhotoController.php
T
Mark Gregory 1e06af2105
tests / ci (push) Canceled after 0s
Initial Commit
2026-10-15 16:51:54 +01:00

90 lines
3.6 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\LodgePhoto;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
class LodgePhotoController extends Controller
{
private function authorizeAdmin(Request $request): void
{
abort_unless(filled(config('lodge.admin_email')) && $request->user()?->email === config('lodge.admin_email'), 403);
}
public function store(Request $request)
{
$this->authorizeAdmin($request);
$request->validate([
'photos' => ['required','array','min:1','max:10'],
'photos.*' => ['required','image','mimes:jpeg,png,webp','max:15360'],
]);
if (!extension_loaded('gd') || !function_exists('imagewebp')) {
throw ValidationException::withMessages(['photos' => 'PHP GD with WebP support is required. Install php8.5-gd.']);
}
foreach ($request->file('photos') as $file) {
$raw = file_get_contents($file->getRealPath());
$source = @imagecreatefromstring($raw);
unset($raw);
if (!$source) {
throw ValidationException::withMessages(['photos' => 'One image could not be decoded.']);
}
$width = imagesx($source); $height = imagesy($source);
if ($width < 1 || $height < 1 || $width * $height > 45000000) {
imagedestroy($source);
throw ValidationException::withMessages(['photos' => 'Image dimensions are not supported (maximum 45 megapixels).']);
}
$id = (string) Str::uuid();
$gallery = "lodge/gallery/{$id}.webp";
$thumbnail = "lodge/thumb/{$id}.webp";
try {
$this->saveWebp($source, $width, $height, 1600, 82, $gallery);
$this->saveWebp($source, $width, $height, 480, 77, $thumbnail);
LodgePhoto::create(['gallery_path'=>$gallery,'thumbnail_path'=>$thumbnail,'alt_text'=>'Cresta 31 lodge photograph']);
} catch (\Throwable $e) {
Storage::disk('public')->delete([$gallery,$thumbnail]);
throw $e;
} finally {
imagedestroy($source);
}
}
return back()->with('success', 'Photographs uploaded and optimised.');
}
private function saveWebp($source, int $width, int $height, int $maxWidth, int $quality, string $path): void
{
$scale = min(1, $maxWidth / $width);
$w = max(1, (int) round($width * $scale));
$h = max(1, (int) round($height * $scale));
$target = imagecreatetruecolor($w, $h);
imagefill($target, 0, 0, imagecolorallocate($target, 255, 255, 255));
imagecopyresampled($target, $source, 0, 0, 0, 0, $w, $h, $width, $height);
ob_start();
try {
if (!imagewebp($target, null, $quality)) {
throw new \RuntimeException('WebP conversion failed.');
}
$bytes = ob_get_clean();
} catch (\Throwable $e) {
ob_end_clean();
imagedestroy($target);
throw $e;
}
imagedestroy($target);
if (!Storage::disk('public')->put($path, $bytes)) {
throw new \RuntimeException('Unable to save the optimised image.');
}
}
public function destroy(Request $request, LodgePhoto $photo)
{
$this->authorizeAdmin($request);
$paths = [$photo->gallery_path, $photo->thumbnail_path];
$photo->delete();
Storage::disk('public')->delete($paths);
return back()->with('success', 'Photograph deleted.');
}
}