149 lines
4.3 KiB
PHP
149 lines
4.3 KiB
PHP
<?php
|
|
require_once '../include/init.php';
|
|
require_once '../include/auth.php';
|
|
|
|
// Set proper headers
|
|
header('Content-Type: application/json');
|
|
|
|
// Check if URL parameter is provided
|
|
if (!isset($_GET['url']) || empty($_GET['url'])) {
|
|
http_response_code(400);
|
|
echo json_encode(['error' => 'URL parameter is required']);
|
|
exit;
|
|
}
|
|
|
|
$imageUrl = $_GET['url'];
|
|
$width = isset($_GET['w']) ? intval($_GET['w']) : null;
|
|
$height = isset($_GET['h']) ? intval($_GET['h']) : null;
|
|
$quality = isset($_GET['q']) ? intval($_GET['q']) : 85;
|
|
|
|
// Validate URL
|
|
if (!filter_var($imageUrl, FILTER_VALIDATE_URL)) {
|
|
http_response_code(400);
|
|
echo json_encode(['error' => 'Invalid URL']);
|
|
exit;
|
|
}
|
|
|
|
// Allowed domains (add your CDN domains here)
|
|
$allowedDomains = [
|
|
'cdn.jsdelivr.net',
|
|
'favicon.hibbit.net',
|
|
'favicon.hibbit.cloud',
|
|
'localhost',
|
|
'127.0.0.1'
|
|
];
|
|
|
|
$parsedUrl = parse_url($imageUrl);
|
|
$domain = $parsedUrl['host'] ?? '';
|
|
|
|
if (!in_array($domain, $allowedDomains)) {
|
|
http_response_code(403);
|
|
echo json_encode(['error' => 'Domain not allowed']);
|
|
exit;
|
|
}
|
|
|
|
// Create cache directory
|
|
$cacheDir = '../data/images/cache/';
|
|
if (!is_dir($cacheDir)) {
|
|
mkdir($cacheDir, 0755, true);
|
|
}
|
|
|
|
// Generate cache key
|
|
$cacheKey = md5($imageUrl . $width . $height . $quality);
|
|
$cacheFile = $cacheDir . $cacheKey;
|
|
|
|
// Check if cached version exists and is fresh (1 day)
|
|
if (file_exists($cacheFile) && (time() - filemtime($cacheFile)) < 86400) {
|
|
// Serve cached file
|
|
$imageInfo = getimagesize($cacheFile);
|
|
if ($imageInfo) {
|
|
header('Content-Type: ' . $imageInfo['mime']);
|
|
header('Content-Length: ' . filesize($cacheFile));
|
|
header('Cache-Control: public, max-age=86400');
|
|
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 86400) . ' GMT');
|
|
header('ETag: "' . $cacheKey . '"');
|
|
readfile($cacheFile);
|
|
exit;
|
|
}
|
|
}
|
|
|
|
// Fetch the image
|
|
$context = stream_context_create([
|
|
'http' => [
|
|
'timeout' => 30,
|
|
'user_agent' => 'Bookmarkly Image Proxy/1.0',
|
|
'follow_location' => true,
|
|
'max_redirects' => 5
|
|
]
|
|
]);
|
|
|
|
$imageData = @file_get_contents($imageUrl, false, $context);
|
|
|
|
if ($imageData === false) {
|
|
http_response_code(404);
|
|
echo json_encode(['error' => 'Failed to fetch image']);
|
|
exit;
|
|
}
|
|
|
|
// Check if ImageMagick is available for processing
|
|
if (extension_loaded('imagick') && ($width || $height || $quality < 100)) {
|
|
try {
|
|
$imagick = new Imagick();
|
|
$imagick->readImageBlob($imageData);
|
|
|
|
// Resize if dimensions are specified
|
|
if ($width || $height) {
|
|
$imagick->resizeImage(
|
|
$width ?: 0,
|
|
$height ?: 0,
|
|
Imagick::FILTER_LANCZOS,
|
|
1
|
|
);
|
|
}
|
|
|
|
// Set quality for JPEG
|
|
if ($imagick->getImageFormat() === 'JPEG') {
|
|
$imagick->setImageCompressionQuality($quality);
|
|
}
|
|
|
|
$processedData = $imagick->getImageBlob();
|
|
$imagick->destroy();
|
|
|
|
// Save to cache
|
|
file_put_contents($cacheFile, $processedData);
|
|
|
|
// Set headers
|
|
$imageInfo = getimagesize($cacheFile);
|
|
header('Content-Type: ' . $imageInfo['mime']);
|
|
header('Content-Length: ' . strlen($processedData));
|
|
header('Cache-Control: public, max-age=86400');
|
|
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 86400) . ' GMT');
|
|
header('ETag: "' . $cacheKey . '"');
|
|
|
|
echo $processedData;
|
|
exit;
|
|
|
|
} catch (Exception $e) {
|
|
// Fallback to original image if processing fails
|
|
error_log('Image processing failed: ' . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
// Serve original image and cache it
|
|
file_put_contents($cacheFile, $imageData);
|
|
|
|
$imageInfo = @getimagesize($cacheFile);
|
|
if ($imageInfo) {
|
|
header('Content-Type: ' . $imageInfo['mime']);
|
|
} else {
|
|
header('Content-Type: image/jpeg'); // fallback
|
|
}
|
|
|
|
header('Content-Length: ' . strlen($imageData));
|
|
header('Cache-Control: public, max-age=86400');
|
|
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 86400) . ' GMT');
|
|
header('ETag: "' . $cacheKey . '"');
|
|
|
|
echo $imageData;
|
|
?>
|