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()]); }