|
@@ -22,9 +22,13 @@ header('Content-Type: application/json');
|
|
|
|
|
|
|
|
// Create uploads directory if it doesn't exist
|
|
// Create uploads directory if it doesn't exist
|
|
|
$uploadsDir = '../uploads/images';
|
|
$uploadsDir = '../uploads/images';
|
|
|
|
|
+$thumbsDir = '../uploads/images/thumbs';
|
|
|
if (!file_exists($uploadsDir)) {
|
|
if (!file_exists($uploadsDir)) {
|
|
|
mkdir($uploadsDir, 0755, true);
|
|
mkdir($uploadsDir, 0755, true);
|
|
|
}
|
|
}
|
|
|
|
|
+if (!file_exists($thumbsDir)) {
|
|
|
|
|
+ mkdir($thumbsDir, 0755, true);
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
// Handle file upload
|
|
// Handle file upload
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['images'])) {
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['images'])) {
|
|
@@ -52,11 +56,16 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['images'])) {
|
|
|
$extension = pathinfo($file['name'], PATHINFO_EXTENSION);
|
|
$extension = pathinfo($file['name'], PATHINFO_EXTENSION);
|
|
|
$filename = uniqid() . '.' . $extension;
|
|
$filename = uniqid() . '.' . $extension;
|
|
|
$filepath = $uploadsDir . '/' . $filename;
|
|
$filepath = $uploadsDir . '/' . $filename;
|
|
|
|
|
+ $thumbFilename = 'thumb_' . $filename;
|
|
|
|
|
+ $thumbPath = $thumbsDir . '/' . $thumbFilename;
|
|
|
|
|
|
|
|
// Move file to uploads directory
|
|
// Move file to uploads directory
|
|
|
if (move_uploaded_file($file['tmp_name'], $filepath)) {
|
|
if (move_uploaded_file($file['tmp_name'], $filepath)) {
|
|
|
|
|
+ // Generate thumbnail
|
|
|
|
|
+ $thumbnailGenerated = generateThumbnail($filepath, $thumbPath);
|
|
|
|
|
+
|
|
|
// Save to database
|
|
// Save to database
|
|
|
- $imageId = saveImageToDatabase($filename, $file['name'], $file['size']);
|
|
|
|
|
|
|
+ $imageId = saveImageToDatabase($filename, $file['name'], $file['size'], $thumbFilename);
|
|
|
|
|
|
|
|
if ($imageId) {
|
|
if ($imageId) {
|
|
|
$uploadedFiles[] = [
|
|
$uploadedFiles[] = [
|
|
@@ -65,11 +74,14 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['images'])) {
|
|
|
'original_name' => $file['name'],
|
|
'original_name' => $file['name'],
|
|
|
'size' => $file['size'],
|
|
'size' => $file['size'],
|
|
|
'url' => '/uploads/images/' . $filename,
|
|
'url' => '/uploads/images/' . $filename,
|
|
|
- 'thumbnail_url' => '/uploads/images/' . $filename
|
|
|
|
|
|
|
+ 'thumbnail_url' => '/uploads/images/thumbs/' . $thumbFilename
|
|
|
];
|
|
];
|
|
|
} else {
|
|
} else {
|
|
|
$errors[] = 'Failed to save ' . $file['name'] . ' to database';
|
|
$errors[] = 'Failed to save ' . $file['name'] . ' to database';
|
|
|
unlink($filepath); // Remove uploaded file
|
|
unlink($filepath); // Remove uploaded file
|
|
|
|
|
+ if ($thumbnailGenerated) {
|
|
|
|
|
+ unlink($thumbPath); // Remove thumbnail if generated
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|
|
|
$errors[] = 'Failed to upload ' . $file['name'];
|
|
$errors[] = 'Failed to upload ' . $file['name'];
|
|
@@ -138,15 +150,101 @@ function validateImageFile($file) {
|
|
|
return ['valid' => true];
|
|
return ['valid' => true];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * Generate thumbnail for uploaded image
|
|
|
|
|
+ */
|
|
|
|
|
+function generateThumbnail($sourcePath, $destPath, $maxWidth = 300, $maxHeight = 200) {
|
|
|
|
|
+ // Check if GD extension is available
|
|
|
|
|
+ if (!extension_loaded('gd')) {
|
|
|
|
|
+ error_log('GD extension not available for thumbnail generation');
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ // Get image info
|
|
|
|
|
+ $imageInfo = getimagesize($sourcePath);
|
|
|
|
|
+ if (!$imageInfo) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $width = $imageInfo[0];
|
|
|
|
|
+ $height = $imageInfo[1];
|
|
|
|
|
+ $type = $imageInfo[2];
|
|
|
|
|
+
|
|
|
|
|
+ // Calculate new dimensions
|
|
|
|
|
+ $ratio = min($maxWidth / $width, $maxHeight / $height);
|
|
|
|
|
+ $newWidth = (int)($width * $ratio);
|
|
|
|
|
+ $newHeight = (int)($height * $ratio);
|
|
|
|
|
+
|
|
|
|
|
+ // Create image resource based on type
|
|
|
|
|
+ switch ($type) {
|
|
|
|
|
+ case IMAGETYPE_JPEG:
|
|
|
|
|
+ $source = imagecreatefromjpeg($sourcePath);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case IMAGETYPE_PNG:
|
|
|
|
|
+ $source = imagecreatefrompng($sourcePath);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case IMAGETYPE_GIF:
|
|
|
|
|
+ $source = imagecreatefromgif($sourcePath);
|
|
|
|
|
+ break;
|
|
|
|
|
+ default:
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!$source) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Create new image
|
|
|
|
|
+ $thumb = imagecreatetruecolor($newWidth, $newHeight);
|
|
|
|
|
+
|
|
|
|
|
+ // Preserve transparency for PNG and GIF
|
|
|
|
|
+ if ($type == IMAGETYPE_PNG || $type == IMAGETYPE_GIF) {
|
|
|
|
|
+ imagealphablending($thumb, false);
|
|
|
|
|
+ imagesavealpha($thumb, true);
|
|
|
|
|
+ $transparent = imagecolorallocatealpha($thumb, 255, 255, 255, 127);
|
|
|
|
|
+ imagefilledrectangle($thumb, 0, 0, $newWidth, $newHeight, $transparent);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Resize image
|
|
|
|
|
+ imagecopyresampled($thumb, $source, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);
|
|
|
|
|
+
|
|
|
|
|
+ // Save thumbnail
|
|
|
|
|
+ $result = false;
|
|
|
|
|
+ switch ($type) {
|
|
|
|
|
+ case IMAGETYPE_JPEG:
|
|
|
|
|
+ $result = imagejpeg($thumb, $destPath, 85);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case IMAGETYPE_PNG:
|
|
|
|
|
+ $result = imagepng($thumb, $destPath, 8);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case IMAGETYPE_GIF:
|
|
|
|
|
+ $result = imagegif($thumb, $destPath);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Clean up
|
|
|
|
|
+ imagedestroy($source);
|
|
|
|
|
+ imagedestroy($thumb);
|
|
|
|
|
+
|
|
|
|
|
+ return $result;
|
|
|
|
|
+
|
|
|
|
|
+ } catch (Exception $e) {
|
|
|
|
|
+ error_log('Error generating thumbnail: ' . $e->getMessage());
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* Save image information to database
|
|
* Save image information to database
|
|
|
*/
|
|
*/
|
|
|
-function saveImageToDatabase($filename, $originalName, $size) {
|
|
|
|
|
|
|
+function saveImageToDatabase($filename, $originalName, $size, $thumbnailFilename = null) {
|
|
|
$db = Database::getInstance();
|
|
$db = Database::getInstance();
|
|
|
|
|
|
|
|
try {
|
|
try {
|
|
|
$db->insert('images', [
|
|
$db->insert('images', [
|
|
|
'filename' => $filename,
|
|
'filename' => $filename,
|
|
|
|
|
+ 'thumbnail_filename' => $thumbnailFilename,
|
|
|
'original_name' => $originalName,
|
|
'original_name' => $originalName,
|
|
|
'file_size' => $size,
|
|
'file_size' => $size,
|
|
|
'uploaded_at' => date('Y-m-d H:i:s'),
|
|
'uploaded_at' => date('Y-m-d H:i:s'),
|
|
@@ -171,13 +269,19 @@ function getExistingImages() {
|
|
|
|
|
|
|
|
$result = [];
|
|
$result = [];
|
|
|
foreach ($images as $image) {
|
|
foreach ($images as $image) {
|
|
|
|
|
+ // Use thumbnail if available, otherwise use original image
|
|
|
|
|
+ $thumbnailUrl = $image['thumbnail_filename']
|
|
|
|
|
+ ? '/uploads/images/thumbs/' . $image['thumbnail_filename']
|
|
|
|
|
+ : '/uploads/images/' . $image['filename'];
|
|
|
|
|
+
|
|
|
$result[] = [
|
|
$result[] = [
|
|
|
'id' => $image['id'],
|
|
'id' => $image['id'],
|
|
|
'filename' => $image['filename'],
|
|
'filename' => $image['filename'],
|
|
|
|
|
+ 'thumbnail_filename' => $image['thumbnail_filename'],
|
|
|
'original_name' => $image['original_name'],
|
|
'original_name' => $image['original_name'],
|
|
|
'size' => $image['file_size'],
|
|
'size' => $image['file_size'],
|
|
|
'url' => '/uploads/images/' . $image['filename'],
|
|
'url' => '/uploads/images/' . $image['filename'],
|
|
|
- 'thumbnail_url' => '/uploads/images/' . $image['filename'],
|
|
|
|
|
|
|
+ 'thumbnail_url' => $thumbnailUrl,
|
|
|
'uploaded_at' => $image['uploaded_at']
|
|
'uploaded_at' => $image['uploaded_at']
|
|
|
];
|
|
];
|
|
|
}
|
|
}
|