|
|
@@ -0,0 +1,244 @@
|
|
|
+<?php
|
|
|
+/**
|
|
|
+ * Image Upload Handler
|
|
|
+ * Handles image uploads for the WYSIWYG editor
|
|
|
+ */
|
|
|
+
|
|
|
+// Start session
|
|
|
+if (session_status() === PHP_SESSION_NONE) {
|
|
|
+ session_start();
|
|
|
+}
|
|
|
+
|
|
|
+require_once '../includes/config.php';
|
|
|
+require_once '../includes/database.php';
|
|
|
+require_once '../includes/auth.php';
|
|
|
+
|
|
|
+// Require authentication
|
|
|
+$auth = new Auth();
|
|
|
+$auth->requireAuth();
|
|
|
+
|
|
|
+// Set headers for JSON response
|
|
|
+header('Content-Type: application/json');
|
|
|
+
|
|
|
+// Create uploads directory if it doesn't exist
|
|
|
+$uploadsDir = '../uploads/images';
|
|
|
+if (!file_exists($uploadsDir)) {
|
|
|
+ mkdir($uploadsDir, 0755, true);
|
|
|
+}
|
|
|
+
|
|
|
+// Handle file upload
|
|
|
+if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['images'])) {
|
|
|
+ $uploadedFiles = [];
|
|
|
+ $errors = [];
|
|
|
+
|
|
|
+ // Handle multiple files
|
|
|
+ $files = $_FILES['images'];
|
|
|
+ $fileCount = count($files['name']);
|
|
|
+
|
|
|
+ for ($i = 0; $i < $fileCount; $i++) {
|
|
|
+ if ($files['error'][$i] === UPLOAD_ERR_OK) {
|
|
|
+ $file = [
|
|
|
+ 'name' => $files['name'][$i],
|
|
|
+ 'type' => $files['type'][$i],
|
|
|
+ 'tmp_name' => $files['tmp_name'][$i],
|
|
|
+ 'error' => $files['error'][$i],
|
|
|
+ 'size' => $files['size'][$i]
|
|
|
+ ];
|
|
|
+
|
|
|
+ // Validate file
|
|
|
+ $validation = validateImageFile($file);
|
|
|
+ if ($validation['valid']) {
|
|
|
+ // Generate unique filename
|
|
|
+ $extension = pathinfo($file['name'], PATHINFO_EXTENSION);
|
|
|
+ $filename = uniqid() . '.' . $extension;
|
|
|
+ $filepath = $uploadsDir . '/' . $filename;
|
|
|
+
|
|
|
+ // Move file to uploads directory
|
|
|
+ if (move_uploaded_file($file['tmp_name'], $filepath)) {
|
|
|
+ // Save to database
|
|
|
+ $imageId = saveImageToDatabase($filename, $file['name'], $file['size']);
|
|
|
+
|
|
|
+ if ($imageId) {
|
|
|
+ $uploadedFiles[] = [
|
|
|
+ 'id' => $imageId,
|
|
|
+ 'filename' => $filename,
|
|
|
+ 'original_name' => $file['name'],
|
|
|
+ 'size' => $file['size'],
|
|
|
+ 'url' => '/uploads/images/' . $filename,
|
|
|
+ 'thumbnail_url' => '/uploads/images/' . $filename
|
|
|
+ ];
|
|
|
+ } else {
|
|
|
+ $errors[] = 'Failed to save ' . $file['name'] . ' to database';
|
|
|
+ unlink($filepath); // Remove uploaded file
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ $errors[] = 'Failed to upload ' . $file['name'];
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ $errors[] = $validation['error'];
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ $errors[] = 'Error uploading file: ' . getUploadErrorMessage($files['error'][$i]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ echo json_encode([
|
|
|
+ 'success' => empty($errors),
|
|
|
+ 'files' => $uploadedFiles,
|
|
|
+ 'errors' => $errors
|
|
|
+ ]);
|
|
|
+ exit;
|
|
|
+}
|
|
|
+
|
|
|
+// Handle GET request to fetch existing images
|
|
|
+if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
|
|
+ $images = getExistingImages();
|
|
|
+ echo json_encode([
|
|
|
+ 'success' => true,
|
|
|
+ 'images' => $images
|
|
|
+ ]);
|
|
|
+ exit;
|
|
|
+}
|
|
|
+
|
|
|
+// Handle DELETE request to remove image
|
|
|
+if ($_SERVER['REQUEST_METHOD'] === 'DELETE' && isset($_GET['id'])) {
|
|
|
+ $imageId = (int)$_GET['id'];
|
|
|
+ $success = deleteImage($imageId);
|
|
|
+ echo json_encode([
|
|
|
+ 'success' => $success
|
|
|
+ ]);
|
|
|
+ exit;
|
|
|
+}
|
|
|
+
|
|
|
+echo json_encode(['success' => false, 'error' => 'Invalid request']);
|
|
|
+
|
|
|
+/**
|
|
|
+ * Validate uploaded image file
|
|
|
+ */
|
|
|
+function validateImageFile($file) {
|
|
|
+ // Check file size (5MB max)
|
|
|
+ $maxSize = 5 * 1024 * 1024; // 5MB
|
|
|
+ if ($file['size'] > $maxSize) {
|
|
|
+ return ['valid' => false, 'error' => 'File too large. Maximum size is 5MB'];
|
|
|
+ }
|
|
|
+
|
|
|
+ // Check file type
|
|
|
+ $allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
|
|
|
+ if (!in_array($file['type'], $allowedTypes)) {
|
|
|
+ return ['valid' => false, 'error' => 'Invalid file type. Only JPG, PNG, GIF, and WebP are allowed'];
|
|
|
+ }
|
|
|
+
|
|
|
+ // Check file extension
|
|
|
+ $allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
|
|
|
+ $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
|
|
|
+ if (!in_array($extension, $allowedExtensions)) {
|
|
|
+ return ['valid' => false, 'error' => 'Invalid file extension'];
|
|
|
+ }
|
|
|
+
|
|
|
+ return ['valid' => true];
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Save image information to database
|
|
|
+ */
|
|
|
+function saveImageToDatabase($filename, $originalName, $size) {
|
|
|
+ $db = Database::getInstance();
|
|
|
+
|
|
|
+ try {
|
|
|
+ $db->insert('images', [
|
|
|
+ 'filename' => $filename,
|
|
|
+ 'original_name' => $originalName,
|
|
|
+ 'file_size' => $size,
|
|
|
+ 'uploaded_at' => date('Y-m-d H:i:s'),
|
|
|
+ 'uploaded_by' => $_SESSION['user_id'] ?? 1
|
|
|
+ ]);
|
|
|
+
|
|
|
+ return $db->lastInsertId();
|
|
|
+ } catch (Exception $e) {
|
|
|
+ error_log('Failed to save image to database: ' . $e->getMessage());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Get existing images from database
|
|
|
+ */
|
|
|
+function getExistingImages() {
|
|
|
+ $db = Database::getInstance();
|
|
|
+
|
|
|
+ try {
|
|
|
+ $images = $db->fetchAll("SELECT * FROM images ORDER BY uploaded_at DESC");
|
|
|
+
|
|
|
+ $result = [];
|
|
|
+ foreach ($images as $image) {
|
|
|
+ $result[] = [
|
|
|
+ 'id' => $image['id'],
|
|
|
+ 'filename' => $image['filename'],
|
|
|
+ 'original_name' => $image['original_name'],
|
|
|
+ 'size' => $image['file_size'],
|
|
|
+ 'url' => '/uploads/images/' . $image['filename'],
|
|
|
+ 'thumbnail_url' => '/uploads/images/' . $image['filename'],
|
|
|
+ 'uploaded_at' => $image['uploaded_at']
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ return $result;
|
|
|
+ } catch (Exception $e) {
|
|
|
+ error_log('Failed to fetch images: ' . $e->getMessage());
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Delete image from database and filesystem
|
|
|
+ */
|
|
|
+function deleteImage($imageId) {
|
|
|
+ $db = Database::getInstance();
|
|
|
+
|
|
|
+ try {
|
|
|
+ // Get image info
|
|
|
+ $image = $db->fetch("SELECT * FROM images WHERE id = ?", [$imageId]);
|
|
|
+ if (!$image) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Delete from database
|
|
|
+ $db->delete('images', 'id = ?', [$imageId]);
|
|
|
+
|
|
|
+ // Delete file from filesystem
|
|
|
+ $filepath = '../uploads/images/' . $image['filename'];
|
|
|
+ if (file_exists($filepath)) {
|
|
|
+ unlink($filepath);
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+ } catch (Exception $e) {
|
|
|
+ error_log('Failed to delete image: ' . $e->getMessage());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Get upload error message
|
|
|
+ */
|
|
|
+function getUploadErrorMessage($errorCode) {
|
|
|
+ switch ($errorCode) {
|
|
|
+ case UPLOAD_ERR_INI_SIZE:
|
|
|
+ return 'The uploaded file exceeds the upload_max_filesize directive in php.ini';
|
|
|
+ case UPLOAD_ERR_FORM_SIZE:
|
|
|
+ return 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form';
|
|
|
+ case UPLOAD_ERR_PARTIAL:
|
|
|
+ return 'The uploaded file was only partially uploaded';
|
|
|
+ case UPLOAD_ERR_NO_FILE:
|
|
|
+ return 'No file was uploaded';
|
|
|
+ case UPLOAD_ERR_NO_TMP_DIR:
|
|
|
+ return 'Missing a temporary folder';
|
|
|
+ case UPLOAD_ERR_CANT_WRITE:
|
|
|
+ return 'Failed to write file to disk';
|
|
|
+ case UPLOAD_ERR_EXTENSION:
|
|
|
+ return 'A PHP extension stopped the file upload';
|
|
|
+ default:
|
|
|
+ return 'Unknown upload error';
|
|
|
+ }
|
|
|
+}
|
|
|
+?>
|