close(); http_response_code(400); echo json_encode(['error' => 'Album ID is required']); exit; } // Verify ownership $ownerCheck = $conn->prepare("SELECT user_id FROM photo_albums WHERE album_id = ?"); $ownerCheck->bind_param("i", $album_id); $ownerCheck->execute(); $ownerResult = $ownerCheck->get_result(); if ($ownerResult->num_rows === 0) { $conn->close(); http_response_code(404); echo json_encode(['error' => 'Album not found']); exit; } $owner = $ownerResult->fetch_assoc(); if ($owner['user_id'] !== $user_id) { $conn->close(); http_response_code(403); echo json_encode(['error' => 'You do not have permission to edit this album']); exit; } $ownerCheck->close(); // Validate inputs if (empty($title) || !validateName($title)) { $conn->close(); http_response_code(400); echo json_encode(['error' => 'Album title is required and must be valid']); exit; } if (!empty($description) && strlen($description) > 500) { $conn->close(); http_response_code(400); echo json_encode(['error' => 'Description must be 500 characters or less']); exit; } try { // Start transaction $conn->begin_transaction(); // Update album $updateStmt = $conn->prepare("UPDATE photo_albums SET title = ?, description = ?, updated_at = NOW() WHERE album_id = ?"); $updateStmt->bind_param("ssi", $title, $description, $album_id); $updateStmt->execute(); $updateStmt->close(); // Handle cover image upload if provided if (isset($_FILES['cover_image']) && $_FILES['cover_image']['error'] === UPLOAD_ERR_OK) { $fileName = $_FILES['cover_image']['name']; $fileTmpName = $_FILES['cover_image']['tmp_name']; $fileSize = $_FILES['cover_image']['size']; // Validate file extension $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); $allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp']; if (!in_array($ext, $allowedExtensions)) { throw new Exception('Invalid cover image file type. Allowed: jpg, jpeg, png, gif, webp'); } if ($fileSize > 5 * 1024 * 1024) { throw new Exception('Cover image file too large (max 5MB)'); } $albumDir = $rootPath . '/assets/uploads/gallery/' . $album_id; // Create directory if it doesn't exist (match working pattern) if (!file_exists($albumDir)) { mkdir($albumDir, 0777, true); } // Delete old cover if it exists $oldCoverStmt = $conn->prepare("SELECT cover_image FROM photo_albums WHERE album_id = ?"); $oldCoverStmt->bind_param("i", $album_id); $oldCoverStmt->execute(); $oldCoverResult = $oldCoverStmt->get_result(); if ($oldCoverResult->num_rows > 0) { $oldCover = $oldCoverResult->fetch_assoc(); if ($oldCover['cover_image']) { $oldCoverPath = $rootPath . $oldCover['cover_image']; if (file_exists($oldCoverPath)) { @unlink($oldCoverPath); } } } $oldCoverStmt->close(); // Generate unique filename $newFileName = 'cover_' . uniqid() . '.' . $ext; $filePath = $albumDir . '/' . $newFileName; $coverImagePath = '/assets/uploads/gallery/' . $album_id . '/' . $newFileName; if (!move_uploaded_file($fileTmpName, $filePath)) { throw new Exception('Failed to upload cover image'); } // Update cover image in album record $updateCover = $conn->prepare("UPDATE photo_albums SET cover_image = ? WHERE album_id = ?"); $updateCover->bind_param("si", $coverImagePath, $album_id); $updateCover->execute(); $updateCover->close(); } // Handle photo uploads if any if (isset($_FILES['photos']) && $_FILES['photos']['error'][0] === UPLOAD_ERR_OK) { $maxSize = 5 * 1024 * 1024; // 5MB $albumDir = $rootPath . '/assets/uploads/gallery/' . $album_id; // Create directory if it doesn't exist (match working pattern) if (!file_exists($albumDir)) { mkdir($albumDir, 0777, true); } // Get current max display order $orderStmt = $conn->prepare("SELECT MAX(display_order) as max_order FROM photos WHERE album_id = ?"); $orderStmt->bind_param("i", $album_id); $orderStmt->execute(); $orderResult = $orderStmt->get_result(); $orderRow = $orderResult->fetch_assoc(); $displayOrder = ($orderRow['max_order'] ?? 0) + 1; $orderStmt->close(); for ($i = 0; $i < count($_FILES['photos']['name']); $i++) { if ($_FILES['photos']['error'][$i] !== UPLOAD_ERR_OK) { continue; } $fileName = $_FILES['photos']['name'][$i]; $fileTmpName = $_FILES['photos']['tmp_name'][$i]; $fileSize = $_FILES['photos']['size'][$i]; // Validate file extension $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION)); $allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp']; if (!in_array($ext, $allowedExtensions)) { throw new Exception('Invalid file type: ' . $fileName . '. Allowed: jpg, jpeg, png, gif, webp'); } if ($fileSize > $maxSize) { throw new Exception('File too large: ' . $fileName . ' (max 5MB)'); } // Generate unique filename $ext = pathinfo($fileName, PATHINFO_EXTENSION); $newFileName = uniqid('photo_') . '.' . $ext; $filePath = $albumDir . '/' . $newFileName; $relativePath = '/assets/uploads/gallery/' . $album_id . '/' . $newFileName; if (!move_uploaded_file($fileTmpName, $filePath)) { throw new Exception('Failed to upload: ' . $fileName); } // Insert photo record $caption = $fileName; // Default caption is filename $photoStmt = $conn->prepare("INSERT INTO photos (album_id, file_path, caption, display_order, created_at) VALUES (?, ?, ?, ?, NOW())"); $photoStmt->bind_param("issi", $album_id, $relativePath, $caption, $displayOrder); $photoStmt->execute(); $photoStmt->close(); $displayOrder++; } } // Commit transaction $conn->commit(); $conn->close(); // Redirect back to album view header('Location: view_album?id=' . $album_id); exit; } catch (Exception $e) { // Rollback on error $conn->rollback(); $conn->close(); http_response_code(400); echo json_encode(['error' => $e->getMessage()]); exit; } ?>