diff --git a/admin/edit_product.php b/admin/edit_product.php index ff650f1..750facf 100644 --- a/admin/edit_product.php +++ b/admin/edit_product.php @@ -57,7 +57,7 @@ if (isset($_GET['id'])) {
-
+ @@ -81,8 +81,12 @@ if (isset($_GET['id'])) {
- - + + + +

Current image:

+ <?php echo htmlspecialchars($product['name']); ?> +
diff --git a/admin/save_product.php b/admin/save_product.php index 2ad1117..740e7ef 100644 --- a/admin/save_product.php +++ b/admin/save_product.php @@ -13,7 +13,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $description = trim($_POST['description'] ?? ''); $price = filter_var($_POST['price'], FILTER_VALIDATE_FLOAT); $stock_quantity = filter_var($_POST['stock_quantity'], FILTER_VALIDATE_INT); - $image_url = trim($_POST['image_url'] ?? ''); $id = $_POST['id'] ?? null; // Basic validation @@ -24,6 +23,46 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { } $pdo = db(); + $image_url = ''; + + if ($id) { + // Fetch existing product's image url + $stmt = $pdo->prepare("SELECT image_url FROM products WHERE id = ?"); + $stmt->execute([$id]); + $image_url = $stmt->fetchColumn(); + } + + // Handle file upload + if (isset($_FILES['image']) && $_FILES['image']['error'] === UPLOAD_ERR_OK) { + $uploadDir = __DIR__ . '/../uploads/'; + + // Sanitize the filename + $originalName = basename($_FILES['image']['name']); + $safeName = preg_replace("/[^a-zA-Z0-9-_.]+/", "", $originalName); + $fileName = uniqid('', true) . '_' . $safeName; + $uploadFile = $uploadDir . $fileName; + + // Validate file type + $imageFileType = strtolower(pathinfo($uploadFile, PATHINFO_EXTENSION)); + $allowedTypes = ['jpg', 'jpeg', 'png', 'gif']; + if (!in_array($imageFileType, $allowedTypes)) { + $_SESSION['error_message'] = 'Only JPG, JPEG, PNG & GIF files are allowed.'; + header('Location: ' . ($_SERVER['HTTP_REFERER'] ?? 'index.php')); + exit; + } + + if (move_uploaded_file($_FILES['image']['tmp_name'], $uploadFile)) { + // Delete old image if a new one is uploaded + if ($image_url && file_exists($uploadDir . $image_url)) { + unlink($uploadDir . $image_url); + } + $image_url = $fileName; + } else { + $_SESSION['error_message'] = 'Failed to upload image.'; + header('Location: ' . ($_SERVER['HTTP_REFERER'] ?? 'index.php')); + exit; + } + } try { if ($id) { @@ -40,7 +79,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $_SESSION['success_message'] = 'Product added successfully.'; } } catch (PDOException $e) { - // In a real app, you would log this error, not show it to the user $_SESSION['error_message'] = 'Database error. Could not save product.'; } @@ -49,4 +87,4 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { } header('Location: index.php'); -exit; +exit; \ No newline at end of file diff --git a/assets/pasted-20250910-210544-2d3a1682.png b/assets/pasted-20250910-210544-2d3a1682.png new file mode 100644 index 0000000..f8d83f5 Binary files /dev/null and b/assets/pasted-20250910-210544-2d3a1682.png differ diff --git a/assets/pasted-20250910-211133-18a40e8c.png b/assets/pasted-20250910-211133-18a40e8c.png new file mode 100644 index 0000000..11c22d5 Binary files /dev/null and b/assets/pasted-20250910-211133-18a40e8c.png differ diff --git a/assets/pasted-20250910-211808-2c0c6132.png b/assets/pasted-20250910-211808-2c0c6132.png new file mode 100644 index 0000000..ce7d4ed Binary files /dev/null and b/assets/pasted-20250910-211808-2c0c6132.png differ diff --git a/basket.php b/basket.php new file mode 100644 index 0000000..ca48667 --- /dev/null +++ b/basket.php @@ -0,0 +1,206 @@ +prepare('SELECT name, stock_quantity FROM products WHERE id = ?'); + $stmt->execute([$productId]); + $product = $stmt->fetch(); + + if ($product && $product['stock_quantity'] > 0) { + if (isset($_SESSION['basket'][$productId])) { + // Prevent adding more than available stock + if ($_SESSION['basket'][$productId] < $product['stock_quantity']) { + $_SESSION['basket'][$productId]++; + } else { + $_SESSION['message']['warning'] = "Cannot add more of this item. Not enough stock for " . $product['name']; + } + } else { + $_SESSION['basket'][$productId] = 1; + } + } else { + $_SESSION['message']['danger'] = "Cannot add item. Not enough stock for " . $product['name']; + } + } + break; + + case 'update': + $quantity = $_POST['quantity'] ?? 1; + if ($productId && $quantity > 0) { + // Check stock + $stmt = $pdo->prepare('SELECT name, stock_quantity FROM products WHERE id = ?'); + $stmt->execute([$productId]); + $product = $stmt->fetch(); + if ($product && $quantity <= $product['stock_quantity']) { + $_SESSION['basket'][$productId] = (int)$quantity; + } else { + $_SESSION['message']['danger'] = "Cannot update quantity. Not enough stock for " . $product['name']; + } + } else if ($productId && $quantity <= 0) { + unset($_SESSION['basket'][$productId]); + } + break; + + case 'remove': + if ($productId) { + unset($_SESSION['basket'][$productId]); + } + break; + } + // Redirect to avoid form resubmission + $redirect_url = $_POST['return_url'] ?? 'basket.php'; + header('Location: ' . $redirect_url); + exit; +} + +// Fetch product details for items in basket +$basketItems = []; +$totalPrice = 0; +if (!empty($_SESSION['basket'])) { + $productIds = array_keys($_SESSION['basket']); + $placeholders = implode(',', array_fill(0, count($productIds), '?')); + + $stmt = $pdo->prepare("SELECT id, name, price, description, stock_quantity FROM products WHERE id IN ($placeholders)"); + $stmt->execute($productIds); + $products = $stmt->fetchAll(PDO::FETCH_ASSOC | PDO::FETCH_GROUP); + + foreach ($_SESSION['basket'] as $productId => $quantity) { + if (isset($products[$productId])) { + $product = $products[$productId][0]; + $itemPrice = $product['price'] * $quantity; + $totalPrice += $itemPrice; + $basketItems[] = [ + 'id' => $productId, + 'name' => $product['name'], + 'price' => $product['price'], + 'quantity' => $quantity, + 'stock_quantity' => $product['stock_quantity'], + 'total' => $itemPrice + ]; + } + } +} +?> + + + + + + Shopping Basket - GiftShop + + + + + + + + + + +
+

Your Shopping Basket

+ + $message): + ?> + + + + +
+

Your basket is empty.

+ Start Shopping +
+ +
+
+
+
+ +
+
+
+

$

+
+
+ + + + + +
+
+
+ + + +
+
+
+ +
+
+
+
+
+
+
Order Summary
+
+ Total + $ +
+ Proceed to Checkout + Continue Shopping +
+
+
+
+ +
+ + + + + + + diff --git a/db/migrations/003_add_image_url_to_products.sql b/db/migrations/003_add_image_url_to_products.sql new file mode 100644 index 0000000..9e49e3c --- /dev/null +++ b/db/migrations/003_add_image_url_to_products.sql @@ -0,0 +1 @@ +ALTER TABLE products ADD COLUMN image_url VARCHAR(255) DEFAULT NULL; \ No newline at end of file diff --git a/index.php b/index.php index 8839fcb..c6d157b 100644 --- a/index.php +++ b/index.php @@ -1,3 +1,4 @@ + @@ -28,6 +29,11 @@ + Browse Catalog @@ -67,41 +73,63 @@ - +
-

Our Presents

-

A glimpse into our curated collection.

+

Our Products

+

Browse our curated collection of gifts.

+ $message): + ?> + +
+ query('SELECT id, name, description, price, stock_quantity, image_url FROM products ORDER BY name'); + $products = $stmt->fetchAll(PDO::FETCH_ASSOC); + + if ($products): + foreach ($products as $product): + ?>
- A vibrant bouquet of fresh flowers. -
-
Flowers
-

Stunning bouquets for any celebration.

+ <?= htmlspecialchars($product['name']) ?> +
+
+

+
+

$

+
+ + + + +
+
-
-
- An assortment of colorful, artisanal candies. -
-
Candies & Sweets
-

Delicious treats to sweeten their day.

-
-
-
-
-
- A stack of books tied with a ribbon. -
-
Books & Stationery
-

Inspiring reads and beautiful paper goods.

-
-
+ +
+

No products found. Please check back later!

+
diff --git a/update_user_role.php b/update_user_role.php new file mode 100644 index 0000000..ef77cf7 --- /dev/null +++ b/update_user_role.php @@ -0,0 +1,16 @@ +prepare("UPDATE users SET role = 'super_admin' WHERE username = 'admin'"); + $stmt->execute(); + + if ($stmt->rowCount() > 0) { + echo "User role updated successfully. You can now log in to the admin panel. Please delete this file immediately."; + } else { + echo "Could not find the 'admin' user or the role is already 'super_admin'. Please check your database. You can delete this file."; + } +} catch (PDOException $e) { + echo "Database error: " . $e->getMessage(); +} diff --git a/uploads/68c1e8788f2356.53020190_Screenshot2025-09-10at23.03.50.png b/uploads/68c1e8788f2356.53020190_Screenshot2025-09-10at23.03.50.png new file mode 100644 index 0000000..4e88517 Binary files /dev/null and b/uploads/68c1e8788f2356.53020190_Screenshot2025-09-10at23.03.50.png differ