diff --git a/admin/add_product.php b/admin/add_product.php new file mode 100644 index 00000000..cd330eef --- /dev/null +++ b/admin/add_product.php @@ -0,0 +1,81 @@ + + + + + + + افزودن محصول جدید + + + + + + + + +
+
+
+
+

افزودن محصول جدید

+ بازگشت +
+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
کدهای رنگ هگزادسیمال را با کاما جدا کنید.
+
+
+ + +
+ +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/admin/auth_check.php b/admin/auth_check.php new file mode 100644 index 00000000..00a8177e --- /dev/null +++ b/admin/auth_check.php @@ -0,0 +1,8 @@ +prepare("SELECT * FROM products WHERE id = ?"); + $stmt->execute([$product_id]); + $product = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$product) { + header('Location: index.php'); + exit; + } +} catch (PDOException $e) { + die("Error fetching product: " . $e->getMessage()); +} + +?> + + + + + + ویرایش محصول: <?php echo htmlspecialchars($product['name']); ?> + + + + + + + + +
+
+
+

ویرایش محصول

+
+
+
+ + + +
+ + +
+
+ + +
+
+ + +
+
+ + +
رنگ‌های موجود را با کاما از هم جدا کنید (مثال: #FFFFFF, #000000).
+
+
+ + +
تصویر فعلی:
+ Current Image +
+
+ > + +
+
+ انصراف + +
+
+
+
+
+
+
+ + + + + diff --git a/admin/handler.php b/admin/handler.php new file mode 100644 index 00000000..4e45b292 --- /dev/null +++ b/admin/handler.php @@ -0,0 +1,169 @@ +session_start(); +require_once __DIR__ . '/../db/config.php'; + +require_once __DIR__ . '/auth_check.php'; + +$action = $_REQUEST['action'] ?? ''; + +$pdo = db(); + +// Default redirect location +$redirect_to = 'index.php'; + +switch ($action) { + case 'add': + $redirect_to = 'add_product.php'; // Redirect back to form on error + if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $name = trim($_POST['name'] ?? ''); + $description = trim($_POST['description'] ?? ''); + $price = filter_var($_POST['price'], FILTER_VALIDATE_FLOAT); + $colors = trim($_POST['colors'] ?? ''); + $is_featured = isset($_POST['is_featured']) ? 1 : 0; + + $errors = []; + + // Validation + if (empty($name)) $errors[] = "Product name is required."; + if (empty($description)) $errors[] = "Description is required."; + if ($price === false) $errors[] = "Price is invalid or missing."; + + $image_path = ''; + if (isset($_FILES['image']) && $_FILES['image']['error'] === UPLOAD_ERR_OK) { + $upload_dir = __DIR__ . '/../assets/images/products/'; + if (!is_dir($upload_dir)) { + if (!mkdir($upload_dir, 0777, true)) { + $errors[] = "Image directory does not exist and could not be created."; + } + } + + if (!is_writable($upload_dir)) { + $errors[] = "Image directory is not writable. Please check server permissions."; + } else { + $filename = uniqid('product_', true) . '_' . basename($_FILES['image']['name']); + $target_file = $upload_dir . $filename; + + if (move_uploaded_file($_FILES['image']['tmp_name'], $target_file)) { + $image_path = 'assets/images/products/' . $filename; + } else { + $errors[] = "Failed to move uploaded file."; + } + } + } else { + $file_error = $_FILES['image']['error'] ?? UPLOAD_ERR_NO_FILE; + $upload_errors = [ + UPLOAD_ERR_INI_SIZE => "The uploaded file exceeds the server's maximum upload size (upload_max_filesize).", + UPLOAD_ERR_FORM_SIZE => "The uploaded file exceeds the maximum size specified in the form.", + UPLOAD_ERR_PARTIAL => "The file was only partially uploaded.", + UPLOAD_ERR_NO_FILE => "No file was selected for upload.", + UPLOAD_ERR_NO_TMP_DIR => "Server configuration error: Missing a temporary folder for uploads.", + UPLOAD_ERR_CANT_WRITE => "Server error: Failed to write the uploaded file to disk.", + UPLOAD_ERR_EXTENSION => "A PHP extension prevented the file upload.", + ]; + $error_message = $upload_errors[$file_error] ?? "An unknown upload error occurred (Code: {$file_error})."; + // Only trigger error if the action is 'add', where image is mandatory + if ($action === 'add') { + $errors[] = "Image Upload Failed: " . $error_message; + } + } + + if (empty($errors)) { + try { + $sql = "INSERT INTO products (name, description, price, image_url, colors, is_featured) VALUES (?, ?, ?, ?, ?, ?)"; + $stmt = $pdo->prepare($sql); + $stmt->execute([$name, $description, $price, $image_path, $colors, $is_featured]); + $_SESSION['flash_message'] = ['type' => 'success', 'message' => 'محصول با موفقیت اضافه شد!']; + $redirect_to = 'index.php'; + } catch (PDOException $e) { + $_SESSION['flash_message'] = ['type' => 'error', 'message' => 'خطا در افزودن محصول: ' . $e->getMessage()]; + } + } else { + $error_message = 'لطفاً تمام خطاها را برطرف کنید:

' . implode('
', $errors); + $_SESSION['flash_message'] = ['type' => 'error', 'message' => $error_message]; + } + } + break; + + case 'edit': + $id = $_POST['id'] ?? $_GET['id'] ?? null; + $redirect_to = 'edit_product.php?id=' . $id; + if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $id = filter_var($id, FILTER_VALIDATE_INT); + $name = trim($_POST['name'] ?? ''); + $description = trim($_POST['description'] ?? ''); + $price = filter_var($_POST['price'], FILTER_VALIDATE_FLOAT); + $colors = trim($_POST['colors'] ?? ''); + $is_featured = isset($_POST['is_featured']) ? 1 : 0; + + $errors = []; + + if (!$id) { + $errors[] = "شناسه محصول نامعتبر است."; + } + // Other validations... + + $image_path = $_POST['current_image'] ?? ''; + + if (isset($_FILES['image']) && $_FILES['image']['error'] === UPLOAD_ERR_OK) { + $upload_dir = __DIR__ . '/../assets/images/products/'; + $filename = uniqid('product_', true) . '_' . basename($_FILES['image']['name']); + $target_file = $upload_dir . $filename; + if (move_uploaded_file($_FILES['image']['tmp_name'], $target_file)) { + if (!empty($image_path) && file_exists(__DIR__ . '/../' . $image_path)) { + unlink(__DIR__ . '/../' . $image_path); + } + $image_path = 'assets/images/products/' . $filename; + } else { + $errors[] = "خطا در آپلود تصویر جدید."; + } + } + + if (empty($errors)) { + try { + $sql = "UPDATE products SET name = ?, description = ?, price = ?, image_url = ?, colors = ?, is_featured = ? WHERE id = ?"; + $stmt = $pdo->prepare($sql); + $stmt->execute([$name, $description, $price, $image_path, $colors, $is_featured, $id]); + $_SESSION['flash_message'] = ['type' => 'success', 'message' => 'محصول با موفقیت ویرایش شد!']; + $redirect_to = 'index.php'; + } catch (PDOException $e) { + $_SESSION['flash_message'] = ['type' => 'error', 'message' => 'خطا در ویرایش محصول: ' . $e->getMessage()]; + } + } else { + $error_message = 'فرم دارای خطا است:

' . implode('
', $errors); + $_SESSION['flash_message'] = ['type' => 'error', 'message' => $error_message]; + } + } + break; + + case 'delete': + $id = filter_var($_GET['id'], FILTER_VALIDATE_INT); + if ($id) { + try { + // First, get the image path to delete the file + $stmt = $pdo->prepare("SELECT image_url FROM products WHERE id = ?"); + $stmt->execute([$id]); + $image_to_delete = $stmt->fetchColumn(); + + // Delete the record + $sql = "DELETE FROM products WHERE id = ?"; + $stmt = $pdo->prepare($sql); + $stmt->execute([$id]); + + // If record deleted, delete the file + if ($stmt->rowCount() > 0 && $image_to_delete && file_exists(__DIR__ . '/../' . $image_to_delete)) { + unlink(__DIR__ . '/../' . $image_to_delete); + } + + $_SESSION['flash_message'] = ['type' => 'success', 'message' => 'محصول با موفقیت حذف شد.']; + } catch (PDOException $e) { + $_SESSION['flash_message'] = ['type' => 'error', 'message' => 'خطا در حذف محصول: ' . $e->getMessage()]; + } + } else { + $_SESSION['flash_message'] = ['type' => 'error', 'message' => 'شناسه محصول نامعتبر است.']; + } + $redirect_to = 'index.php'; + break; +} + +// Redirect back after the action +header('Location: ' . $redirect_to); +exit; diff --git a/admin/index.php b/admin/index.php new file mode 100644 index 00000000..8b18fbcb --- /dev/null +++ b/admin/index.php @@ -0,0 +1,117 @@ +query("SELECT id, name, price FROM products ORDER BY created_at DESC"); + $products = $stmt->fetchAll(PDO::FETCH_ASSOC); +} catch (PDOException $e) { + die("Error fetching products: " . $e->getMessage()); +} + +$flash_message = $_SESSION['flash_message'] ?? null; +if ($flash_message) { + unset($_SESSION['flash_message']); +} + +?> + + + + + + پنل مدیریت - محصولات + + + + + + + + +
+
+

مدیریت محصولات

+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
#نام محصولقیمتعملیات
هیچ محصولی یافت نشد.
تومان + ویرایش + حذف +
+
+
+ بازگشت به سایت +
+
+ + + + + \ No newline at end of file diff --git a/admin/login.php b/admin/login.php new file mode 100644 index 00000000..1853da4f --- /dev/null +++ b/admin/login.php @@ -0,0 +1,64 @@ + + + + + + + ورود به پنل مدیریت + + + + + + +
+
+
+
+
+

ورود به پنل

+

رمز عبور: admin123

+ +
+ +
+
+ + +
+
+ +
+
+
+
+
+
+
+ + + diff --git a/admin/logout.php b/admin/logout.php new file mode 100644 index 00000000..3d26eba9 --- /dev/null +++ b/admin/logout.php @@ -0,0 +1,22 @@ + tag +*/ +html.dark { + --primary-color: #C0A080; /* Lighter tan for accents in dark mode */ + --secondary-color: #8B4513; /* Darker brown */ + --accent-color: #D2B48C; + --background-color: #1A1A1A; /* Very dark grey, almost black */ + --surface-color: #2C2C2C; /* Dark grey for cards and surfaces */ + --text-color: #D5D5D5; /* Light grey for body text */ + --heading-color: #FFFFFF; /* White for headings */ + --border-color: #444444; /* Grey for borders */ + --footer-bg: #111111; /* Even darker for footer */ +} + + +body { + font-family: var(--body-font); + background-color: var(--background-color); + color: var(--text-color); + line-height: 1.7; + font-weight: 400; + overflow-x: hidden; + transition: background-color 0.3s ease, color 0.3s ease; +} + +h1, h2, h3, h4, h5, h6 { + font-weight: 700; + color: var(--heading-color); +} + +a { + color: var(--primary-color); + text-decoration: none; + transition: all 0.3s ease; +} + +a:hover { + color: var(--accent-color); + text-decoration: none; +} + +/* --- Buttons --- */ +.btn-primary { + background-color: var(--primary-color); + border-color: var(--primary-color); + color: var(--background-color); /* To have contrast in both themes */ + padding: 12px 30px; + font-weight: 600; + border-radius: 50px; + transition: all 0.3s ease-in-out; +} +html.dark .btn-primary { + color: var(--heading-color); +} + + +.btn-primary:hover, .btn-primary:focus { + background-color: var(--secondary-color); + border-color: var(--secondary-color); + box-shadow: 0 5px 15px rgba(0,0,0,0.1); + transform: translateY(-2px); +} + +.btn-outline-primary { + border-color: var(--primary-color); + color: var(--primary-color); + padding: 12px 30px; + font-weight: 600; + border-radius: 50px; +} +.btn-outline-primary:hover { + background-color: var(--primary-color); + color: var(--white-color); +} + +/* --- Header --- */ +.site-header { + background-color: var(--surface-color); + box-shadow: 0 2px 15px rgba(0,0,0,0.05); + border-bottom: 1px solid var(--border-color); + transition: background-color 0.3s ease; +} + +html.dark .site-header { + box-shadow: 0 2px 15px rgba(0,0,0,0.2); +} + +.site-header .nav-link, +.site-header a { + color: var(--text-color) !important; + font-weight: 500; + font-size: 16px; + padding: 8px 12px; + position: relative; +} + +.site-header a.active, +.site-header a:hover { + color: var(--primary-color) !important; +} + +.site-header .badge { + background-color: var(--primary-color) !important; + color: var(--background-color) !important; +} + +html.dark .site-header .badge { + color: var(--heading-color) !important; +} + + +/* --- Footer --- */ +.site-footer { + background-color: var(--footer-bg); + color: #AFAFAF; +} +.site-footer h5 { + color: var(--heading-color); +} +.site-footer a { + color: #AFAFAF !important; +} +.site-footer a:hover { + color: var(--white-color) !important; +} +.site-footer .border-top { + border-color: var(--border-color) !important; +} + +/* --- Product Card --- */ +.product-card { + background: var(--surface-color); + border: 1px solid var(--border-color); + border-radius: 15px; + overflow: hidden; + transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); + box-shadow: 0 5px 20px rgba(0,0,0,0.04); +} + +html.dark .product-card { + box-shadow: 0 5px 20px rgba(0,0,0,0.15); +} + +.product-card:hover { + transform: translateY(-8px); + box-shadow: 0 15px 30px rgba(0,0,0,0.08); +} + +html.dark .product-card:hover { + box-shadow: 0 15px 30px rgba(0,0,0,0.25); +} + + +.product-card .product-image img { + transition: transform 0.5s ease; +} + +.product-card:hover .product-image img { + transform: scale(1.05); +} + +.product-card .product-info { + padding: 20px; +} + +.product-card .product-title { + font-size: 1.1rem; + font-weight: 600; + margin-bottom: 10px; + color: var(--heading-color); +} + +.product-card .product-price { + font-size: 1.2rem; + font-weight: 700; + color: var(--primary-color); +} + +/* --- Product Page Color Swatches --- */ +.color-swatches .btn-check + .btn { + border: 2px solid var(--border-color); + border-radius: 50%; + width: 40px; + height: 40px; + display: inline-block; + padding: 0; + font-size: 0; + transition: transform 0.2s ease, box-shadow 0.2s ease; +} + +.color-swatches .btn-check:checked + .btn { + transform: scale(1.15); + box-shadow: 0 0 0 3px var(--surface-color), 0 0 0 5px var(--primary-color); +} + +/* Handle specific colors that need border in light mode */ +.color-swatches [style*="#FFFFFF"] + label, +.color-swatches [style*="#ffffff"] + label { + border-color: #dedede; +} + +html.dark .color-swatches [style*="#000000"] + label { + border-color: #555; +} + +/* --- Admin panel dark theme overrides --- */ +.bg-dark { + background-color: var(--background-color) !important; +} +.text-white { + color: var(--text-color) !important; +} +.bg-dark-2 { + background-color: var(--surface-color) !important; +} +.form-control.bg-dark { + background-color: var(--background-color) !important; + color: var(--text-color) !important; + border-color: var(--border-color); +} +.form-control.bg-dark:focus { + background-color: var(--background-color) !important; + color: var(--text-color) !important; + border-color: var(--primary-color); + box-shadow: none; +} + +/* --- Product Image Aspect Ratio --- */ +.product-image { + overflow: hidden; + position: relative; + background-color: var(--border-color); /* Placeholder bg */ + aspect-ratio: 3 / 4; /* Enforce 3:4 aspect ratio */ +} + +.product-image img { + width: 100%; + height: 100%; + object-fit: cover; /* This will crop the image to fit */ +} \ No newline at end of file diff --git a/assets/images/products/new_leather_product_1.jpg b/assets/images/products/new_leather_product_1.jpg new file mode 100644 index 00000000..a8923460 Binary files /dev/null and b/assets/images/products/new_leather_product_1.jpg differ diff --git a/assets/images/products/new_leather_product_2.jpg b/assets/images/products/new_leather_product_2.jpg new file mode 100644 index 00000000..292653fb Binary files /dev/null and b/assets/images/products/new_leather_product_2.jpg differ diff --git a/assets/images/products/new_leather_product_3.jpg b/assets/images/products/new_leather_product_3.jpg new file mode 100644 index 00000000..e41cec3f Binary files /dev/null and b/assets/images/products/new_leather_product_3.jpg differ diff --git a/assets/js/main.js b/assets/js/main.js new file mode 100644 index 00000000..6130445d --- /dev/null +++ b/assets/js/main.js @@ -0,0 +1 @@ +// Custom JavaScript will go here diff --git a/cart.php b/cart.php new file mode 100644 index 00000000..035ae582 --- /dev/null +++ b/cart.php @@ -0,0 +1,121 @@ + '1') + $product_ids = array_map(function($id) { + return (int)explode('-', $id)[0]; + }, $cart_item_ids); + + if (!empty($product_ids)) { + $placeholders = implode(',', array_fill(0, count($product_ids), '?')); + + try { + $pdo = db(); + $stmt = $pdo->prepare("SELECT id, name, price, image_url FROM products WHERE id IN ($placeholders)"); + $stmt->execute(array_unique($product_ids)); + $products_data = $stmt->fetchAll(PDO::FETCH_ASSOC | PDO::FETCH_UNIQUE); + + foreach ($_SESSION['cart'] as $cart_item_id => $item) { + $product_id = (int)explode('-', $cart_item_id)[0]; + + if (isset($products_data[$product_id])) { + $product = $products_data[$product_id]; + $quantity = $item['quantity']; + $color = $item['color']; + $subtotal = $product['price'] * $quantity; + $total_price += $subtotal; + + $cart_items_detailed[] = [ + 'cart_item_id' => $cart_item_id, + 'product_id' => $product_id, + 'name' => $product['name'], + 'price' => $product['price'], + 'image_url' => $product['image_url'], + 'quantity' => $quantity, + 'color' => $color, + 'subtotal' => $subtotal + ]; + } + } + } catch (PDOException $e) { + error_log("DB Error: " . $e->getMessage()); + $cart_items_detailed = []; + $total_price = 0; + } + } +} + +$page_title = 'سبد خرید'; +include 'includes/header.php'; +?> + +
+

سبد خرید شما

+
+ + +
+

سبد خرید شما خالی است.

+ بازگشت به فروشگاه +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + +
محصولقیمتتعدادجمع کلحذف
+ <?php echo htmlspecialchars($item['name']); ?> + +
+ + رنگ: + +
+ + + × +
+
+ +
+ +
+

جمع نهایی: تومان

+
+
+
+ +
+ ادامه جهت تسویه حساب +
+ + + diff --git a/cart_handler.php b/cart_handler.php new file mode 100644 index 00000000..6f07fcbd --- /dev/null +++ b/cart_handler.php @@ -0,0 +1,70 @@ + 0 && $quantity > 0) { + // Create a unique ID for the cart item based on product ID and color + $cart_item_id = $product_id . ($color ? '-' . preg_replace('/[^a-zA-Z0-9_]/ ', '-', $color) : ''); + + // If the exact item (product + color) is already in the cart, update the quantity + if (isset($_SESSION['cart'][$cart_item_id])) { + $_SESSION['cart'][$cart_item_id]['quantity'] += $quantity; + } else { + // Otherwise, add it as a new item + $_SESSION['cart'][$cart_item_id] = [ + 'product_id' => $product_id, + 'quantity' => $quantity, + 'color' => $color + ]; + } + } + + // Redirect to the cart page to show the updated cart + header('Location: cart.php'); + exit; +} + +// Handle removing an item from the cart +if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['action']) && $_GET['action'] === 'remove') { + $cart_item_id = isset($_GET['id']) ? $_GET['id'] : ''; + if (!empty($cart_item_id) && isset($_SESSION['cart'][$cart_item_id])) { + unset($_SESSION['cart'][$cart_item_id]); + } + // Redirect back to the cart page + header('Location: cart.php'); + exit; +} + +// Handle updating quantities +if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_cart'])){ + if(!empty($_POST['quantities'])){ + foreach($_POST['quantities'] as $cart_item_id => $quantity){ + $quantity = (int)$quantity; + if(!empty($cart_item_id) && isset($_SESSION['cart'][$cart_item_id])){ + if($quantity > 0){ + $_SESSION['cart'][$cart_item_id]['quantity'] = $quantity; + } else { + // Remove item if quantity is 0 or less + unset($_SESSION['cart'][$cart_item_id]); + } + } + } + } + header('Location: cart.php'); + exit; +} + + +// If someone accesses this file directly without a valid action, redirect them to the shop. +header('Location: shop.php'); +exit; \ No newline at end of file diff --git a/checkout.php b/checkout.php new file mode 100644 index 00000000..b9f0ab8a --- /dev/null +++ b/checkout.php @@ -0,0 +1,174 @@ +prepare("SELECT id, price FROM products WHERE id IN ($placeholders)"); + $stmt->execute($product_ids); + $products_from_db = $stmt->fetchAll(PDO::FETCH_ASSOC | PDO::FETCH_UNIQUE); + + $total_amount = 0; + foreach ($_SESSION['cart'] as $product_id => $quantity) { + if(isset($products_from_db[$product_id])){ + $total_amount += $products_from_db[$product_id]['price'] * $quantity; + } + } + + // --- Database Transaction --- + $pdo->beginTransaction(); + + // 1. Insert into orders table + $sql_order = "INSERT INTO orders (customer_name, customer_email, customer_address, total_amount) VALUES (?, ?, ?, ?)"; + $stmt_order = $pdo->prepare($sql_order); + $stmt_order->execute([$name, $email, $address, $total_amount]); + $order_id = $pdo->lastInsertId(); + + // 2. Insert into order_items table + $sql_items = "INSERT INTO order_items (order_id, product_id, quantity, price) VALUES (?, ?, ?, ?)"; + $stmt_items = $pdo->prepare($sql_items); + + foreach ($_SESSION['cart'] as $product_id => $quantity) { + if(isset($products_from_db[$product_id])){ + $price = $products_from_db[$product_id]['price']; + $stmt_items->execute([$order_id, $product_id, $quantity, $price]); + } + } + + // 3. Commit the transaction + $pdo->commit(); + + // 4. Clear the cart and set success flag + unset($_SESSION['cart']); + $order_placed_successfully = true; + $p_title = "سفارش شما ثبت شد"; + + } catch (Exception $e) { + if ($pdo->inTransaction()) { + $pdo->rollBack(); + } + error_log("Checkout Error: " . $e->getMessage()); + $error_message = 'مشکلی در ثبت سفارش شما به وجود آمد. لطفاً دوباره تلاش کنید.'; + } + } +} + +?> + + + + + + <?php echo $p_title; ?> - چرم آتیمه + + + + + + + + +
+
+ +
+
+ + +
+
+

+
+ +
+
+ +
+

از خرید شما متشکریم!

+

سفارش شما با موفقیت ثبت شد و به زودی پردازش خواهد شد. یک ایمیل تایید برای شما ارسال گردید.

+ بازگشت به فروشگاه +
+ + +
.
+ +
+
+
اطلاعات ارسال
+
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+
+
+ +
+
+
+ + + + + + + \ No newline at end of file diff --git a/contact.php b/contact.php new file mode 100644 index 00000000..cf6bbf33 --- /dev/null +++ b/contact.php @@ -0,0 +1,87 @@ + + +
+
+
+

+

+
+
+ +
+
+
+
+ + + + + + + + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+
+
+
توجه: این فرم برای اهداف آزمایشی است. برای دریافت واقعی ایمیل‌ها، باید اطلاعات سرور ایمیل (SMTP) خود را در فایل .env وارد کنید.
+
+
+
+ + + + + diff --git a/db/migrations/001_add_colors_to_products.sql b/db/migrations/001_add_colors_to_products.sql new file mode 100644 index 00000000..643dd22c --- /dev/null +++ b/db/migrations/001_add_colors_to_products.sql @@ -0,0 +1 @@ +ALTER TABLE products ADD COLUMN colors VARCHAR(255) DEFAULT NULL COMMENT 'Comma-separated list of available colors'; \ No newline at end of file diff --git a/db/migrations/002_add_is_featured_to_products.sql b/db/migrations/002_add_is_featured_to_products.sql new file mode 100644 index 00000000..e1f692b9 --- /dev/null +++ b/db/migrations/002_add_is_featured_to_products.sql @@ -0,0 +1 @@ +ALTER TABLE products ADD COLUMN is_featured BOOLEAN DEFAULT 0; \ No newline at end of file diff --git a/includes/footer.php b/includes/footer.php new file mode 100644 index 00000000..a4a48646 --- /dev/null +++ b/includes/footer.php @@ -0,0 +1,58 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/includes/header.php b/includes/header.php new file mode 100644 index 00000000..6cdcbefe --- /dev/null +++ b/includes/header.php @@ -0,0 +1,79 @@ + + + + + + + <?php echo htmlspecialchars($page_title); ?> + + + + + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/includes/pexels.php b/includes/pexels.php new file mode 100644 index 00000000..5c5aae4a --- /dev/null +++ b/includes/pexels.php @@ -0,0 +1,25 @@ + 0 ? $k : 'Vc99rnmOhHhJAbgGQoKLZtsaIVfkeownoQNbTj78VemUjKh08ZYRbf18'; +} +function pexels_get($url) { + $ch = curl_init(); + curl_setopt_array($ch, [ + CURLOPT_URL => $url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => [ 'Authorization: '. pexels_key() ], + CURLOPT_TIMEOUT => 15, + ]); + $resp = curl_exec($ch); + $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + if ($code >= 200 && $code < 300 && $resp) return json_decode($resp, true); + return null; +} +function download_to($srcUrl, $destPath) { + $data = file_get_contents($srcUrl); + if ($data === false) return false; + if (!is_dir(dirname($destPath))) mkdir(dirname($destPath), 0775, true); + return file_put_contents($destPath, $data) !== false; +} \ No newline at end of file diff --git a/index.php b/index.php index 7205f3d3..3bf84427 100644 --- a/index.php +++ b/index.php @@ -1,150 +1,88 @@ - -$phpVersion = PHP_VERSION; -$now = date('Y-m-d H:i:s'); -?> - - - - - - New Style - - - - - - - - - - - - - - - - - - - - - -
-
-

Analyzing your requirements and generating your website…

-
- Loading… -
-

AI is collecting your requirements and applying the first changes.

-

This page will update automatically as the plan is implemented.

-

Runtime: PHP — UTC

-
-
- - - + +
+
+
+ +
+
+

اصالت در هر نگاه

+

محصولات چرمی دست‌دوز، آفریده برای ماندگاری.

+ کاوش در مجموعه +
+
+ + + + + + +
+
+
+
+ درباره ما +
+
+

داستان آتیمه

+

ما در آتیمه، به تلفیق هنر سنتی و طراحی مدرن باور داریم. هر محصول، حاصل ساعت‌ها کار دست هنرمندان ماهر و استفاده از بهترین چرم‌های طبیعی است. هدف ما خلق آثاری است که نه تنها یک وسیله، بلکه بخشی از داستان و استایل شما باشند.

+ بیشتر بدانید +
+
+
+
+ + \ No newline at end of file diff --git a/migrate.php b/migrate.php new file mode 100644 index 00000000..ea3eb558 --- /dev/null +++ b/migrate.php @@ -0,0 +1,54 @@ +exec("CREATE TABLE IF NOT EXISTS migrations (migration VARCHAR(255) PRIMARY KEY, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)"); + + // Get executed migrations + $executed_migrations_stmt = $pdo->query("SELECT migration FROM migrations"); + $executed_migrations = $executed_migrations_stmt->fetchAll(PDO::FETCH_COLUMN); + + $migration_files = glob($migrations_dir . '/*.sql'); + sort($migration_files); + + foreach ($migration_files as $file) { + $migration_name = basename($file); + + if (in_array($migration_name, $executed_migrations)) { + continue; // Skip already executed migration + } + + echo "Running migration: {$migration_name}... +"; + $sql = file_get_contents($file); + + try { + $pdo->exec($sql); + + // Log the migration + $stmt = $pdo->prepare("INSERT INTO migrations (migration) VALUES (?)"); + $stmt->execute([$migration_name]); + + echo "Migration {$migration_name} executed successfully. +"; + } catch (PDOException $e) { + echo "Error running migration {$migration_name}: " . $e->getMessage() . " +"; + // Stop on error + return false; + } + } + + echo "All new migrations have been executed. +"; + return true; +} + +// Run it +run_migrations(); + diff --git a/product.php b/product.php new file mode 100644 index 00000000..99912d88 --- /dev/null +++ b/product.php @@ -0,0 +1,71 @@ +prepare("SELECT * FROM products WHERE id = ?"); + $stmt->execute([$product_id]); + $product = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$product) { + header("Location: shop.php"); + exit; + } +} catch (PDOException $e) { + error_log("DB Error: " . $e->getMessage()); + die("An error occurred. Please try again later."); +} + +$page_title = htmlspecialchars($product['name']); +$available_colors = !empty($product['colors']) ? array_map('trim', explode(',', $product['colors'])) : []; + +include 'includes/header.php'; +?> + +
+
+ <?php echo htmlspecialchars($product['name']); ?> +
+
+

+

+ +
تومان
+ +
+ + + +
+ +
+ $color): ?> +
+ > + +
+ +
+
+ + +
+ + +
+ + +
+ +
+
+ + diff --git a/shop.php b/shop.php new file mode 100644 index 00000000..73498592 --- /dev/null +++ b/shop.php @@ -0,0 +1,46 @@ +query("SELECT * FROM products ORDER BY created_at DESC"); + $products = $stmt->fetchAll(PDO::FETCH_ASSOC); +} catch (PDOException $e) { + error_log("DB Error: " . $e->getMessage()); + $products = []; +} + +$page_title = 'فروشگاه'; +include 'includes/header.php'; +?> + +
+

گالری محصولات

+

دست‌سازه‌هایی از چرم طبیعی، با عشق و دقت

+
+ +
+ + +
+
+
+ + <?php echo htmlspecialchars($product['name']); ?> + +
+
+

+

تومان

+
+
+
+ + +
+

محصولی برای نمایش یافت نشد.

+
+ +
+ +