Files
bookmarkly2/api/optimize_image.php
T
2025-09-28 16:05:53 +02:00

124 lines
4.1 KiB
PHP

<?php
session_start();
// Basic authentication check
if (!isset($_SESSION['user_id'])) {
http_response_code(403);
echo json_encode(['success' => false, 'message' => 'Authentication required.']);
exit;
}
// Check if image path is provided
if (!isset($_POST['path']) || empty($_POST['path'])) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => 'Image path not provided.']);
exit;
}
$imagePath = $_POST['path'];
// Sanitize the path: remove any query string to prevent issues with realpath()
$path_parts = parse_url($imagePath);
$imagePath = $path_parts['path'];
$baseDir = realpath(__DIR__ . '/../data/images/backgrounds');
$fullPath = realpath(__DIR__ . '/../' . $imagePath);
// Security check: ensure the file is within the backgrounds directory
if (!$fullPath || strpos($fullPath, $baseDir) !== 0 || !file_exists($fullPath)) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => 'Invalid or non-existent image path.']);
exit;
}
// --- Image Optimization Logic ---
$maxWidth = 1920;
$quality = 85;
try {
// Get image info
list($width, $height, $type) = getimagesize($fullPath);
// Don't optimize if the image is already reasonably sized
if ($width <= $maxWidth) {
// Still, re-save JPEG to apply quality setting, which might reduce size
if ($type == IMAGETYPE_JPEG) {
$source = imagecreatefromjpeg($fullPath);
imagejpeg($source, $fullPath, $quality);
imagedestroy($source);
echo json_encode(['success' => true, 'message' => 'Image quality adjusted, but no resize needed.']);
exit;
}
// For other types, if no resize is needed, there's nothing to do.
echo json_encode(['success' => true, 'message' => 'Image is already optimized (width is within limit).']);
exit;
}
// Continue with resizing for images wider than maxWidth
$newWidth = $maxWidth;
$newHeight = (int) (($newWidth / $width) * $height);
// Create image resource based on type
switch ($type) {
case IMAGETYPE_JPEG:
$source = imagecreatefromjpeg($fullPath);
break;
case IMAGETYPE_PNG:
$source = imagecreatefrompng($fullPath);
break;
case IMAGETYPE_GIF:
$source = imagecreatefromgif($fullPath);
break;
case IMAGETYPE_WEBP:
$source = imagecreatefromwebp($fullPath);
break;
default:
throw new Exception('Unsupported image type.');
}
if ($source === false) {
throw new Exception('Could not create image resource.');
}
// Create a new true color image
$thumb = imagecreatetruecolor($newWidth, $newHeight);
// Handle transparency for PNG
if ($type == IMAGETYPE_PNG) {
imagealphablending($thumb, false);
imagesavealpha($thumb, true);
$transparent = imagecolorallocatealpha($thumb, 255, 255, 255, 127);
imagefilledrectangle($thumb, 0, 0, $newWidth, $newHeight, $transparent);
}
// Resize
imagecopyresampled($thumb, $source, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);
// Save the optimized image, overwriting the original
switch ($type) {
case IMAGETYPE_JPEG:
imagejpeg($thumb, $fullPath, $quality);
break;
case IMAGETYPE_PNG:
// PNG quality is 0-9. 85 quality -> level 1-2.
imagepng($thumb, $fullPath, 1);
break;
case IMAGETYPE_GIF:
imagegif($thumb, $fullPath);
break;
case IMAGETYPE_WEBP:
imagewebp($thumb, $fullPath, $quality);
break;
}
// Free up memory
imagedestroy($source);
imagedestroy($thumb);
echo json_encode(['success' => true, 'message' => 'Image optimized successfully.']);
} catch (Exception $e) {
http_response_code(500);
echo json_encode(['success' => false, 'message' => 'Error optimizing image: ' . $e->getMessage()]);
}