Files
bookmarkly2/api/optimize_image.php
T
2025-09-30 22:54:32 +02:00

141 lines
4.9 KiB
PHP

<?php
// Start session if not already started
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
// Set proper content type
header('Content-Type: application/json');
// 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);
// Check if image is too large for memory (more conservative estimate)
$estimatedMemory = ($width * $height * 4) + (1920 * 1080 * 4); // Rough estimate
if ($estimatedMemory > (400 * 1024 * 1024)) { // 400MB (leave some headroom)
echo json_encode(['success' => false, 'message' => 'Image too large to process safely. Please use a smaller image or reduce the image dimensions.']);
exit;
}
// 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);
if ($source === false) {
throw new Exception('Could not load image for quality adjustment.');
}
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
$source = false;
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. The image may be corrupted or too large.');
}
// 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()]);
}