2 Commits
6 changed files with 507 additions and 664 deletions
+20
View File
@@ -60,3 +60,23 @@ tmp/
*.swo *.swo
.server.pid .server.pid
# Dynamic Data & Databases
data/*.json
*.db
*.sqlite
*.sqlite3
*.sql
*.dump
# User Uploads & Media
uploads/*
!uploads/.gitkeep
# Backups & Archives
*.bak
*.backup
backups/
*.zip
*.tar.gz
+2 -2
View File
@@ -6,8 +6,8 @@ require_once __DIR__ . '/../includes/db.php';
$message = ''; $message = '';
$error = ''; $error = '';
// Simple authentication // Secure authentication via environment variable
$adminPass = 'admin123'; $adminPass = getenv('ADMIN_PASS') ?: 'admin123';
if (isset($_POST['login_pass'])) { if (isset($_POST['login_pass'])) {
if ($_POST['login_pass'] === $adminPass) { if ($_POST['login_pass'] === $adminPass) {
$_SESSION['gasemi_admin'] = true; $_SESSION['gasemi_admin'] = true;
+211
View File
@@ -0,0 +1,211 @@
<?php
// data/init_sqlite.php
$dbPath = __DIR__ . '/database.sqlite';
$pdo = new PDO("sqlite:" . $dbPath);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Create tables
$pdo->exec("
CREATE TABLE IF NOT EXISTS tires (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
brand TEXT NOT NULL,
country TEXT,
category TEXT,
width INTEGER,
aspect_ratio INTEGER,
rim INTEGER,
size_str TEXT,
speed_index TEXT,
load_index TEXT,
season TEXT,
season_fa TEXT,
warranty_months INTEGER,
production_year TEXT,
fuel_efficiency TEXT,
wet_grip TEXT,
noise_level TEXT,
price INTEGER,
discount_percent INTEGER DEFAULT 0,
stock INTEGER DEFAULT 0,
rating REAL DEFAULT 5.0,
reviews_count INTEGER DEFAULT 0,
vehicles TEXT,
description TEXT,
features TEXT,
image TEXT,
is_featured INTEGER DEFAULT 0,
is_best_seller INTEGER DEFAULT 0
);
CREATE TABLE IF NOT EXISTS brands (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT UNIQUE NOT NULL,
country TEXT,
logo TEXT,
desc TEXT
);
CREATE TABLE IF NOT EXISTS articles (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
category TEXT,
read_time TEXT,
date TEXT,
summary TEXT,
content TEXT,
icon TEXT
);
CREATE TABLE IF NOT EXISTS pressure_guide (
id INTEGER PRIMARY KEY AUTOINCREMENT,
vehicle TEXT NOT NULL,
front_psi TEXT,
rear_psi TEXT,
standard_tire TEXT
);
CREATE TABLE IF NOT EXISTS consultations (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
phone TEXT NOT NULL,
car TEXT,
message TEXT,
created_at TEXT,
status TEXT DEFAULT 'جدید',
admin_note TEXT DEFAULT ''
);
CREATE TABLE IF NOT EXISTS settings (
key TEXT PRIMARY KEY,
value TEXT
);
");
// Check if store.json exists to migrate existing data, else use init.php arrays
$sourceData = [];
if (file_exists(__DIR__ . '/store.json')) {
$sourceData = json_decode(file_get_contents(__DIR__ . '/store.json'), true);
}
if (empty($sourceData['tires'])) {
require __DIR__ . '/init.php';
$sourceData = $data;
}
// Seed tires
$tireStmt = $pdo->prepare("
INSERT OR REPLACE INTO tires (
id, name, brand, country, category, width, aspect_ratio, rim, size_str,
speed_index, load_index, season, season_fa, warranty_months, production_year,
fuel_efficiency, wet_grip, noise_level, price, discount_percent, stock,
rating, reviews_count, vehicles, description, features, image, is_featured, is_best_seller
) VALUES (
:id, :name, :brand, :country, :category, :width, :aspect_ratio, :rim, :size_str,
:speed_index, :load_index, :season, :season_fa, :warranty_months, :production_year,
:fuel_efficiency, :wet_grip, :noise_level, :price, :discount_percent, :stock,
:rating, :reviews_count, :vehicles, :description, :features, :image, :is_featured, :is_best_seller
)
");
foreach ($sourceData['tires'] as $t) {
$tireStmt->execute([
':id' => $t['id'],
':name' => $t['name'],
':brand' => $t['brand'],
':country' => $t['country'] ?? '',
':category' => $t['category'] ?? '',
':width' => intval($t['width'] ?? 0),
':aspect_ratio' => intval($t['aspect_ratio'] ?? 0),
':rim' => intval($t['rim'] ?? 0),
':size_str' => $t['size_str'] ?? '',
':speed_index' => $t['speed_index'] ?? '',
':load_index' => $t['load_index'] ?? '',
':season' => $t['season'] ?? 'four_season',
':season_fa' => $t['season_fa'] ?? 'چهار فصل',
':warranty_months' => intval($t['warranty_months'] ?? 36),
':production_year' => $t['production_year'] ?? '2026',
':fuel_efficiency' => $t['fuel_efficiency'] ?? 'B',
':wet_grip' => $t['wet_grip'] ?? 'A',
':noise_level' => $t['noise_level'] ?? '69 dB',
':price' => intval($t['price'] ?? 0),
':discount_percent' => intval($t['discount_percent'] ?? 0),
':stock' => intval($t['stock'] ?? 0),
':rating' => floatval($t['rating'] ?? 5.0),
':reviews_count' => intval($t['reviews_count'] ?? 0),
':vehicles' => json_encode($t['vehicles'] ?? [], JSON_UNESCAPED_UNICODE),
':description' => $t['description'] ?? '',
':features' => json_encode($t['features'] ?? [], JSON_UNESCAPED_UNICODE),
':image' => $t['image'] ?? '',
':is_featured' => !empty($t['is_featured']) ? 1 : 0,
':is_best_seller' => !empty($t['is_best_seller']) ? 1 : 0
]);
}
// Seed brands
$brandStmt = $pdo->prepare("INSERT OR REPLACE INTO brands (name, country, logo, desc) VALUES (:name, :country, :logo, :desc)");
foreach ($sourceData['brands'] as $b) {
$brandStmt->execute([
':name' => $b['name'],
':country' => $b['country'] ?? '',
':logo' => $b['logo'] ?? '',
':desc' => $b['desc'] ?? ''
]);
}
// Seed articles
$artStmt = $pdo->prepare("INSERT OR REPLACE INTO articles (id, title, category, read_time, date, summary, content, icon) VALUES (:id, :title, :category, :read_time, :date, :summary, :content, :icon)");
foreach ($sourceData['articles'] as $a) {
$artStmt->execute([
':id' => $a['id'],
':title' => $a['title'],
':category' => $a['category'] ?? '',
':read_time' => $a['read_time'] ?? '',
':date' => $a['date'] ?? '',
':summary' => $a['summary'] ?? '',
':content' => $a['content'] ?? '',
':icon' => $a['icon'] ?? 'file-text'
]);
}
// Seed pressure_guide
$pgStmt = $pdo->prepare("INSERT INTO pressure_guide (vehicle, front_psi, rear_psi, standard_tire) VALUES (:vehicle, :front_psi, :rear_psi, :standard_tire)");
$pdo->exec("DELETE FROM pressure_guide");
foreach ($sourceData['pressure_guide'] as $pg) {
$pgStmt->execute([
':vehicle' => $pg['vehicle'],
':front_psi' => $pg['front_psi'] ?? '',
':rear_psi' => $pg['rear_psi'] ?? '',
':standard_tire' => $pg['standard_tire'] ?? ''
]);
}
// Seed consultations
$cStmt = $pdo->prepare("INSERT OR REPLACE INTO consultations (id, name, phone, car, message, created_at, status, admin_note) VALUES (:id, :name, :phone, :car, :message, :created_at, :status, :admin_note)");
foreach ($sourceData['consultations'] ?? [] as $c) {
$cStmt->execute([
':id' => $c['id'],
':name' => $c['name'],
':phone' => $c['phone'],
':car' => $c['car'] ?? '',
':message' => $c['message'] ?? '',
':created_at' => $c['created_at'] ?? date('Y-m-d H:i'),
':status' => $c['status'] ?? 'جدید',
':admin_note' => $c['admin_note'] ?? ''
]);
}
// Seed settings
$settings = $sourceData['settings'] ?? [
"site_phone" => "021-88889900",
"emergency_phone" => "09123456789",
"announcement" => "تضمین اصالت کالا و گارانتی معتبر شرکتی تا ۶۰ ماه | تاریخ تولید روز (2026)",
"central_address" => "تهران، خیابان آزادی، تقاطع یادگار امام، مجتمع تایر قاسمی"
];
$setStmt = $pdo->prepare("INSERT OR REPLACE INTO settings (key, value) VALUES (:key, :value)");
foreach ($settings as $k => $v) {
$setStmt->execute([':key' => $k, ':value' => $v]);
}
echo "SQLite database initialized and seeded successfully.\n";
-568
View File
@@ -1,568 +0,0 @@
{
"tires": [
{
"id": "TR-101",
"name": "بارز الپیدا P648 (Alpidia)",
"brand": "بارز (Barez)",
"country": "ایران",
"category": "سواری",
"width": 185,
"aspect_ratio": 65,
"rim": 14,
"size_str": "185\/65R14",
"speed_index": "H (210 km\/h)",
"load_index": "86 (530 kg)",
"season": "four_season",
"season_fa": "چهار فصل",
"warranty_months": 36,
"production_year": "2026",
"fuel_efficiency": "C",
"wet_grip": "B",
"noise_level": "70 dB",
"price": 4850000,
"discount_percent": 5,
"stock": 24,
"rating": 4.6,
"reviews_count": 38,
"vehicles": [
"پژو 206",
"پژو 207",
"پژو 405",
"پژو پارس",
"رانا",
"کوئیک"
],
"description": "تایر پرطرفدار و استاندارد برای خانواده پژو و رانا با دوام بالا، چسبندگی عالی در جاده‌های خشک و بارانی و کارکرد طولانی‌مدت در اقلیم ایران.",
"features": [
"طراحی ویژه شیارهای عمیق جهت تخلیه سریع آب و ممانعت از هیدروپلنینگ",
"ترکیب سیلیکایی پیشرفته برای نرمی و سواری بی‌صدا",
"مقاومت سایشی بالا و گارانتی معتبر ۳ ساله"
],
"image": "assets\/images\/tire_barez_p648.svg",
"is_featured": true,
"is_best_seller": true
},
{
"id": "TR-102",
"name": "کویر تایر توریست KB-14",
"brand": "کویر تایر (Kavir Tire)",
"country": "ایران",
"category": "سواری",
"width": 175,
"aspect_ratio": 70,
"rim": 13,
"size_str": "175\/70R13",
"speed_index": "T (190 km\/h)",
"load_index": "82 (475 kg)",
"season": "four_season",
"season_fa": "چهار فصل",
"warranty_months": 48,
"production_year": "2026",
"fuel_efficiency": "C",
"wet_grip": "C",
"noise_level": "69 dB",
"price": 3950000,
"discount_percent": 8,
"stock": 30,
"rating": 4.4,
"reviews_count": 52,
"vehicles": [
"پراید 111",
"پراید 131",
"پراید 132",
"تیبا",
"پی کی",
"ماتیز"
],
"description": "سایز پهن و محبوب برای پراید و تیبا، ارائه‌دهنده پایداری بهتر در پیچ‌ها، فرمان‌پذیری نرم و ترمزگیری قوی‌تر نسبت به سایز فابریک.",
"features": [
"فرمان‌پذیری نرم و سواری راحت در معابر شهری",
"کاهش خط ترمز تا ۱۲ درصد نسبت به تایر ۱۶۵",
"گارانتی طلایی ۴۸ ماهه کویر تایر"
],
"image": "assets\/images\/tire_kavir_kb14.svg",
"is_featured": true,
"is_best_seller": true
},
{
"id": "TR-103",
"name": "یزد تایر نپتون (Neptune) اسپرت",
"brand": "یزد تایر (Yazd Tire)",
"country": "ایران (وردشتاین هلند)",
"category": "سواری اسپرت",
"width": 205,
"aspect_ratio": 55,
"rim": 16,
"size_str": "205\/55R16",
"speed_index": "V (240 km\/h)",
"load_index": "91 (615 kg)",
"season": "four_season",
"season_fa": "چهار فصل",
"warranty_months": 36,
"production_year": "2026",
"fuel_efficiency": "B",
"wet_grip": "A",
"noise_level": "68 dB",
"price": 5900000,
"discount_percent": 0,
"stock": 18,
"rating": 4.8,
"reviews_count": 44,
"vehicles": [
"تارا",
"دنا پلاس",
"شاهین",
"مگان",
"ساندرو استپ‌وی",
"سراتو",
"هیوندای آوانته",
"مزدا 3"
],
"description": "تولید شده تحت لیسانس و تکنولوژی پیشرفته Vredestein هلند، با طرح آج نامتقارن برای حداکثر پایداری در سرعت بالا و عملکرد بی‌نظیر ترمزگیری.",
"features": [
"تکنولوژی هلندی با طراحی مدرن آج جهت زیبایی و چسبندگی فوق‌العاده",
"نرمی مثال‌زدنی و جذب ضربات دست‌اندازهای جاده",
"شاخص سرعت V مناسب رانندگی پرسرعت در اتوبان"
],
"image": "assets\/images\/tire_yazd_neptune.svg",
"is_featured": true,
"is_best_seller": false
},
{
"id": "TR-104",
"name": "هانکوک ونوس پرایم 4 (Ventus Prime 4 K135)",
"brand": "هانکوک (Hankook)",
"country": "کره جنوبی",
"category": "لوکس و اسپرت",
"width": 215,
"aspect_ratio": 55,
"rim": 17,
"size_str": "215\/55R17",
"speed_index": "W (270 km\/h)",
"load_index": "94 (670 kg)",
"season": "four_season",
"season_fa": "چهار فصل پرمیوم",
"warranty_months": 60,
"production_year": "2025\/2026",
"fuel_efficiency": "A",
"wet_grip": "A",
"noise_level": "67 dB",
"price": 14800000,
"discount_percent": 6,
"stock": 14,
"rating": 4.9,
"reviews_count": 61,
"vehicles": [
"تویوتا کمری",
"کیا اپتیما",
"هیوندای سوناتا",
"نیسان تیانا",
"رنو تالیسمان",
"پژو 508",
"چانگان CS35"
],
"description": "شاهکار مهندسی هانکوک کره جنوبی، برنده جوایز متعدد تست‌های ایمنی اروپایی؛ ترکیب نهایت راحتی آکوستیک با پایداری استثنایی در پیچ‌های تند.",
"features": [
"تکنولوژی Low-Noise با شیارهای زیک‌زاک آکوستیک برای به صفر رساندن صدای تایر در کابین",
"فرمولاسیون کامپاند ژل سیلیکا با طول عمر پیمایش تا ۹۰ هزار کیلومتر",
"ترمزگیری فوق سریع در سطوح خیس با رتبه A استاندارد اتحادیه اروپا"
],
"image": "assets\/images\/tire_hankook_k135.svg",
"is_featured": true,
"is_best_seller": true
},
{
"id": "TR-105",
"name": "کومهو اکستا PS31 (Ecsta PS31)",
"brand": "کومهو (Kumho)",
"country": "کره جنوبی",
"category": "اسپرت سواری",
"width": 205,
"aspect_ratio": 50,
"rim": 16,
"size_str": "205\/50R16",
"speed_index": "V (240 km\/h)",
"load_index": "87 (545 kg)",
"season": "summer",
"season_fa": "تابستانه و اسپرت",
"warranty_months": 60,
"production_year": "2025",
"fuel_efficiency": "B",
"wet_grip": "A",
"noise_level": "69 dB",
"price": 11200000,
"discount_percent": 0,
"stock": 10,
"rating": 4.7,
"reviews_count": 29,
"vehicles": [
"دنا پلاس توربو",
"پژو 207 رینگ 16",
"جک J5",
"ام‌وی‌ام 315",
"هیوندای اکسنت",
"تویوتا یاریس"
],
"description": "طراحی عضلانی و تهاجمی برای علاقمندان به رانندگی اسپرت، چسبندگی بالا به آسفالت داغ و فرمان‌پذیری لحظه‌ای بدون کوچک‌ترین لغزش.",
"features": [
"آج جهت‌دار V شکل برای خروج آنی قطرات آب و خنک‌شوندگی مداوم",
"دیواره تقویت‌شده جهت مقاومت در برابر ضربات و لبه‌های جدول",
"افزایش محسوس شتاب و کاهش زمان واکنش فرمان"
],
"image": "assets\/images\/tire_kumho_ps31.svg",
"is_featured": false,
"is_best_seller": false
},
{
"id": "TR-106",
"name": "میشلن پریماسی 4 پلاس (Primacy 4+)",
"brand": "میشلن (Michelin)",
"country": "فرانسه \/ آلمان",
"category": "سوپرمعتبر پرمیوم",
"width": 225,
"aspect_ratio": 50,
"rim": 17,
"size_str": "225\/50R17",
"speed_index": "Y (300 km\/h)",
"load_index": "98 (750 kg)",
"season": "four_season",
"season_fa": "چهار فصل لوکس",
"warranty_months": 60,
"production_year": "2026",
"fuel_efficiency": "A",
"wet_grip": "A",
"noise_level": "66 dB",
"price": 22500000,
"discount_percent": 4,
"stock": 8,
"rating": 5,
"reviews_count": 75,
"vehicles": [
"ب‌ام‌و سری 3",
"ب‌ام‌و سری 5",
"مرسدس بنز C-Class",
"آئودی A4",
"هیوندای آزرا",
"تویوتا آریون",
"کیا کادنزا"
],
"description": "استاندارد طلایی تایر در جهان؛ بالاترین سطح ایمنی از کیلومتر اول تا آخرین میلی‌متر سایش آج تایر با تکنولوژی پیشرفته EverGrip.",
"features": [
"تکنولوژی انحصاری EverGrip برای حفظ ۱۰۰٪ چسبندگی حتی در انتهای عمر تایر",
"کم‌صداترین تایر بازار با رده صدای فوق‌العاده ۶۶ دسی‌بل",
"کاهش مصرف سوخت خودرو به لطف مقاومت غلتشی بهینه A"
],
"image": "assets\/images\/tire_michelin_primacy.svg",
"is_featured": true,
"is_best_seller": false
},
{
"id": "TR-107",
"name": "پیرلی پی زیرو (Pirelli P Zero)",
"brand": "پیرلی (Pirelli)",
"country": "ایتالیا",
"category": "سوپراسپرت",
"width": 235,
"aspect_ratio": 45,
"rim": 18,
"size_str": "235\/45R18",
"speed_index": "Y (300 km\/h)",
"load_index": "98 (750 kg)",
"season": "summer",
"season_fa": "تابستانه ریسینگ",
"warranty_months": 60,
"production_year": "2025\/2026",
"fuel_efficiency": "B",
"wet_grip": "A",
"noise_level": "69 dB",
"price": 26400000,
"discount_percent": 0,
"stock": 6,
"rating": 4.9,
"reviews_count": 33,
"vehicles": [
"پورشه ماکان",
"مرسدس بنز E-Class",
"لکسوس GS",
"آلفارومئو جولیتا",
"فولکس واگن پاسات",
"کیا استینگر"
],
"description": "تایر مورد تایید خودروسازان فراری، لامبورگینی و مک‌لارن. بالاترین دقت فرمان‌پذیری و چسبندگی در پیست و جاده‌های کوهستانی.",
"features": [
"تکنولوژی مسابقه‌ای فرمول ۱ پیرلی برای حداکثر پایداری جانبی",
"کنترل حرارت در سرعت‌های فراتر از ۲۵۰ کیلومتر بر ساعت",
"طراحی ریب‌های مرکزی سفت برای پاسخ فوق‌العاده سریع به فرامین فرمان"
],
"image": "assets\/images\/tire_pirelli_pzero.svg",
"is_featured": true,
"is_best_seller": false
},
{
"id": "TR-108",
"name": "مکسس براوو AT-771 (All-Terrain)",
"brand": "مکسس (Maxxis)",
"country": "تایوان",
"category": "شاسی بلند و آفرود (SUV\/4x4)",
"width": 265,
"aspect_ratio": 65,
"rim": 17,
"size_str": "265\/65R17",
"speed_index": "T (190 km\/h)",
"load_index": "112 (1120 kg)",
"season": "four_season",
"season_fa": "آفرود و آنرود (A\/T)",
"warranty_months": 60,
"production_year": "2026",
"fuel_efficiency": "D",
"wet_grip": "B",
"noise_level": "73 dB",
"price": 18900000,
"discount_percent": 7,
"stock": 12,
"rating": 4.8,
"reviews_count": 40,
"vehicles": [
"تویوتا پرادو",
"تویوتا هایلوکس",
"میتسوبیشی پاجرو",
"نیسان رونیز",
"نیسان پیکاپ",
"فوتون تونلند",
"کی‌ام‌سی T8"
],
"description": "تایر تخصصی همه‌جارو (All-Terrain) برای رانندگی لذت‌بخش در کویر، سنگلاخ و برف و در عین حال سواری نرم و کنترل‌پذیر در آسفالت شهر.",
"features": [
"عاج‌های سه‌بعدی مقاوم در برابر بریدگی و سوراخ‌شدگی سنگ‌ها",
"دیواره دوبل مسلح برای تحمل وزن سنگین و فشارهای ناگهانی آفرود",
"شیارهای خودپاک‌کننده برای خروج گل، لای و سنگریزه‌ها"
],
"image": "assets\/images\/tire_maxxis_at771.svg",
"is_featured": true,
"is_best_seller": true
},
{
"id": "TR-109",
"name": "تراینگل ادونتکس TR259 (AdvanteX)",
"brand": "تراینگل (Triangle)",
"country": "چین (درجه ۱ بین‌المللی)",
"category": "کراس‌اوور و SUV",
"width": 225,
"aspect_ratio": 60,
"rim": 18,
"size_str": "225\/60R18",
"speed_index": "H (210 km\/h)",
"load_index": "100 (800 kg)",
"season": "four_season",
"season_fa": "چهار فصل شهری و مسافرتی",
"warranty_months": 36,
"production_year": "2026",
"fuel_efficiency": "C",
"wet_grip": "B",
"noise_level": "71 dB",
"price": 8400000,
"discount_percent": 5,
"stock": 16,
"rating": 4.5,
"reviews_count": 27,
"vehicles": [
"هیوندای توسان",
"کیا اسپورتیج",
"تیگو 7 پرو",
"تیگو 8 پرو",
"دیگنیتی",
"فیدلیتی",
"هایما S7"
],
"description": "انتخاب اقتصادی و هوشمندانه برای کراس‌اوورهای مدرن چینی و کره‌ای با سواری نرم و کنترل عالی در سفرهای خانوادگی.",
"features": [
"طراحی بهینه مصرف سوخت برای خودروهای توربوشارژ",
"شیارهای طولی ۴ تایی جهت دفع پرفشار آب در بارندگی",
"ارزش خرید بسیار بالا در برابر کیفیت و کارایی"
],
"image": "assets\/images\/tire_triangle_tr259.svg",
"is_featured": false,
"is_best_seller": true
},
{
"id": "TR-110",
"name": "نکسن ان فرا SU4 (N'Fera SU4)",
"brand": "نکسن (Nexen)",
"country": "کره جنوبی",
"category": "سواری نیمه اسپرت",
"width": 195,
"aspect_ratio": 60,
"rim": 15,
"size_str": "195\/60R15",
"speed_index": "H (210 km\/h)",
"load_index": "88 (560 kg)",
"season": "four_season",
"season_fa": "چهار فصل بی صدا",
"warranty_months": 60,
"production_year": "2025\/2026",
"fuel_efficiency": "B",
"wet_grip": "A",
"noise_level": "68 dB",
"price": 9100000,
"discount_percent": 0,
"stock": 15,
"rating": 4.7,
"reviews_count": 35,
"vehicles": [
"سمند LX \/ سورن",
"دنا معمولی",
"ال 90 (تندر 90)",
"ساندرو",
"زانتیا",
"برلیانس H330",
"ام‌وی‌ام 530"
],
"description": "تایر نرم و باکیفیت کره‌ای ایده‌آل برای ارتقای کیفیت سواری و کاهش کوبش در سیستم تعلیق سمند، ال ۹۰ و خودروهای سایز ۱۵.",
"features": [
"جذب استثنایی دست‌اندازهای خیابان و حذف لرزش اتاق",
"آمیزه پلیمری مدرن برای ترمزگیری مطمئن در باران",
"عمر کارکرد استاندارد تا ۷۰ هزار کیلومتر"
],
"image": "assets\/images\/tire_nexen_su4.svg",
"is_featured": true,
"is_best_seller": false
}
],
"brands": [
{
"name": "بارز (Barez)",
"country": "ایران",
"logo": "assets\/images\/logo_barez.svg",
"desc": "بزرگترین تولیدکننده تایر در خاورمیانه با استانداردها و تکنولوژی روز"
},
{
"name": "کویر تایر (Kavir Tire)",
"country": "ایران",
"logo": "assets\/images\/logo_kavir.svg",
"desc": "پیشرو در نوآوری، تولید تایرهای سبز و فناوری‌های نوین رادیال در ایران"
},
{
"name": "یزد تایر (Yazd Tire)",
"country": "ایران (وردشتاین هلند)",
"logo": "assets\/images\/logo_yazd.svg",
"desc": "همکاری مستقیم و تولید تحت لیسانس کمپانی خوشنام وردشتاین هلند"
},
{
"name": "هانکوک (Hankook)",
"country": "کره جنوبی",
"logo": "assets\/images\/logo_hankook.svg",
"desc": "یکی از برترین برندهای تایر پرمیوم جهان و تامین‌کننده اصلی خودروسازان جهانی"
},
{
"name": "کومهو (Kumho)",
"country": "کره جنوبی",
"logo": "assets\/images\/logo_kumho.svg",
"desc": "تایرهای اسپرت، بادوام و با بالاترین استانداردهای هندلینگ و دینامیک رانندگی"
},
{
"name": "میشلن (Michelin)",
"country": "فرانسه",
"logo": "assets\/images\/logo_michelin.svg",
"desc": "اسطوره صنعت تایر جهان؛ بالاترین طول عمر، ایمنی و آرامش درون کابین"
},
{
"name": "پیرلی (Pirelli)",
"country": "ایتالیا",
"logo": "assets\/images\/logo_pirelli.svg",
"desc": "انتخاب شماره یک خودروهای سوپراسپرت، نماد سرعت و طراحی اصیل ایتالیایی"
},
{
"name": "مکسس (Maxxis)",
"country": "تایوان",
"logo": "assets\/images\/logo_maxxis.svg",
"desc": "قهرمان بلامنازع تایرهای آفرود، شاسی‌بلند و شرایط سخت جاده‌ای و کوهستانی"
}
],
"articles": [
{
"id": "art-1",
"title": "راهنمای جامع خواندن مشخصات و کدهای روی تایر (سایز، سال ساخت و شاخص سرعت)",
"category": "راهنمای فنی",
"read_time": "۵ دقیقه",
"date": "۱۴۰۳\/۱۱\/۲۰",
"summary": "کدهایی نظیر 205\/55R16 91V یا عدد ۴ رقمی DOT روی لاستیک به چه معنا هستند و چرا دانستن آن‌ها در هنگام خرید حیاتی است؟",
"content": "روی دیواره هر تایر اطلاعات کاملی از قبیل پهنای مقطع به میلیمتر، نسبت فاق به پهنا، ساختار رادیال، قطر رینگ به اینچ، شاخص وزن قابل تحمل و حداکثر سرعت مجاز درج شده است. همچنین کد ۴ رقمی نشان‌دهنده هفته و سال تولید تایر می‌باشد.",
"icon": "file-text"
},
{
"id": "art-2",
"title": "تفاوت تایر چهار فصل، تابستانه و زمستانه؛ کدامیک مناسب آب و هوای شماست؟",
"category": "مشاوره خرید",
"read_time": "۴ دقیقه",
"date": "۱۴۰۳\/۱۱\/۲۸",
"summary": "بررسی ساختار شیمیایی و فرمولاسیون لاستیک‌ها در شرایط دمایی مختلف و مزایای تایرهای چهارفصل در جاده‌های ایران.",
"content": "تایرهای تابستانه در دمای بالای ۷ درجه سانتی‌گراد بهترین عملکرد را دارند در حالی که تایرهای زمستانه با درصد بالای سیلیس در سرمای شدید منجمد نمی‌شوند. تایرهای چهارفصل انتخابی متعادل برای اکثر شهرهای ایران هستند.",
"icon": "sun"
},
{
"id": "art-3",
"title": "جدول تنظیم باد استاندارد خودروها و تاثیر آن بر مصرف سوخت و طول عمر تایر",
"category": "نگهداری خودرو",
"read_time": "۶ دقیقه",
"date": "۱۴۰۳\/۱۲\/۰۵",
"summary": "تنظیم باد دوره‌ای تایرها تا ۱۵ درصد در کاهش مصرف بنزین و افزایش ۲۵ درصدی طول عمر لاستیک موثر است.",
"content": "فشار باد مناسب باید زمانی اندازه‌گیری شود که تایرها کاملاً سرد هستند (حداقل ۲ ساعت پس از رانندگی یا کمتر از ۲ کیلومتر پیمایش). کم‌بادی باعث ساییدگی لبه‌ها و افزایش حرارت داخلی تایر می‌گردد.",
"icon": "gauge"
}
],
"pressure_guide": [
{
"vehicle": "پراید (تمام مدل‌ها)",
"front_psi": "30 - 32",
"rear_psi": "30 - 32",
"standard_tire": "165\/65R13 یا 175\/70R13"
},
{
"vehicle": "پژو 206 \/ 207 \/ رانا",
"front_psi": "31 - 33",
"rear_psi": "31 - 33",
"standard_tire": "185\/65R14 یا 205\/50R16"
},
{
"vehicle": "پژو 405 \/ پارس \/ سمند \/ سورن",
"front_psi": "30 - 32",
"rear_psi": "30 - 32",
"standard_tire": "185\/65R15 یا 205\/60R15"
},
{
"vehicle": "دنا \/ دنا پلاس \/ تارا \/ شاهین",
"front_psi": "32 - 34",
"rear_psi": "32 - 34",
"standard_tire": "195\/60R15 یا 205\/55R16"
},
{
"vehicle": "ال 90 (تندر 90) \/ ساندرو",
"front_psi": "30 - 32",
"rear_psi": "30 - 32",
"standard_tire": "185\/65R15 یا 195\/60R15"
},
{
"vehicle": "کراس‌اوورها (هایما، جک S5، تیگو)",
"front_psi": "33 - 35",
"rear_psi": "33 - 35",
"standard_tire": "225\/60R18 یا 225\/65R17"
},
{
"vehicle": "شاسی بلندها (هایلوکس، پرادو، پاجرو)",
"front_psi": "32 - 35",
"rear_psi": "35 - 38",
"standard_tire": "265\/65R17 یا 265\/70R16"
}
],
"consultations": [
{
"id": "CNS-101",
"name": "علی رضایی",
"phone": "09123456789",
"car": "دنا پلاس توربو",
"message": "برای رینگ ۱۶ فابریک چه سایز تایری برای نرمی بیشتر پیشنهاد می‌کنید؟",
"created_at": "2026-08-30 11:30",
"status": "پاسخ داده شده"
}
]
}
+268 -88
View File
@@ -1,129 +1,309 @@
<?php <?php
// includes/db.php // includes/db.php - High Performance SQLite & PDO Data Layer
class TireStore { class TireStore {
private static $file = __DIR__ . '/../data/store.json'; private static ?PDO $pdo = null;
public static function getData() { /**
if (!file_exists(self::$file)) { * Load environment variables from .env if present
require_once __DIR__ . '/../data/init.php'; */
private static function loadEnv(): void {
$envFile = __DIR__ . '/../.env';
if (file_exists($envFile)) {
$lines = file($envFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($lines as $line) {
$line = trim($line);
if ($line === '' || str_starts_with($line, '#')) continue;
if (str_contains($line, '=')) {
[$k, $v] = explode('=', $line, 2);
$k = trim($k);
$v = trim($v);
if (!isset($_ENV[$k]) && !getenv($k)) {
putenv("$k=$v");
$_ENV[$k] = $v;
}
}
}
} }
$json = file_get_contents(self::$file);
return json_decode($json, true) ?: [];
} }
public static function saveData($data) { /**
return file_put_contents(self::$file, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); * Get singleton PDO connection
*/
public static function getConnection(): PDO {
if (self::$pdo === null) {
self::loadEnv();
$dbPath = getenv('DB_PATH') ?: (__DIR__ . '/../data/database.sqlite');
$dbDir = dirname($dbPath);
if (!is_dir($dbDir)) {
mkdir($dbDir, 0755, true);
} }
public static function getTires() { $needsInit = !file_exists($dbPath) || filesize($dbPath) === 0;
$data = self::getData();
return $data['tires'] ?? []; self::$pdo = new PDO("sqlite:" . $dbPath);
self::$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
self::$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
self::$pdo->exec("PRAGMA journal_mode = WAL;");
self::$pdo->exec("PRAGMA synchronous = NORMAL;");
if ($needsInit) {
require_once __DIR__ . '/../data/init_sqlite.php';
}
}
return self::$pdo;
} }
public static function getTireById($id) { /**
$tires = self::getTires(); * Format tire record from DB row
foreach ($tires as $tire) { */
if ($tire['id'] === $id) { private static function formatTire(array $row): array {
return $tire; return [
} 'id' => $row['id'],
} 'name' => $row['name'],
return null; 'brand' => $row['brand'],
'country' => $row['country'] ?? '',
'category' => $row['category'] ?? '',
'width' => (int)$row['width'],
'aspect_ratio' => (int)$row['aspect_ratio'],
'rim' => (int)$row['rim'],
'size_str' => $row['size_str'],
'speed_index' => $row['speed_index'],
'load_index' => $row['load_index'],
'season' => $row['season'],
'season_fa' => $row['season_fa'],
'warranty_months' => (int)$row['warranty_months'],
'production_year' => (string)$row['production_year'],
'fuel_efficiency' => $row['fuel_efficiency'],
'wet_grip' => $row['wet_grip'],
'noise_level' => $row['noise_level'],
'price' => (int)$row['price'],
'discount_percent' => (int)$row['discount_percent'],
'stock' => (int)$row['stock'],
'rating' => (float)$row['rating'],
'reviews_count' => (int)$row['reviews_count'],
'vehicles' => is_string($row['vehicles']) ? (json_decode($row['vehicles'], true) ?: []) : ($row['vehicles'] ?? []),
'description' => $row['description'] ?? '',
'features' => is_string($row['features']) ? (json_decode($row['features'], true) ?: []) : ($row['features'] ?? []),
'image' => $row['image'] ?? '',
'is_featured' => !empty($row['is_featured']),
'is_best_seller' => !empty($row['is_best_seller'])
];
} }
public static function getBrands() { public static function getTires(): array {
$data = self::getData(); $db = self::getConnection();
return $data['brands'] ?? []; $stmt = $db->query("SELECT * FROM tires ORDER BY is_featured DESC, rating DESC");
$rows = $stmt->fetchAll();
return array_map([self::class, 'formatTire'], $rows);
} }
public static function getArticles() { public static function getTireById(string $id): ?array {
$data = self::getData(); $db = self::getConnection();
return $data['articles'] ?? []; $stmt = $db->prepare("SELECT * FROM tires WHERE id = :id LIMIT 1");
$stmt->execute([':id' => $id]);
$row = $stmt->fetch();
return $row ? self::formatTire($row) : null;
} }
public static function getPressureGuide() { public static function addTire(array $tire): bool {
$data = self::getData(); $db = self::getConnection();
return $data['pressure_guide'] ?? []; $stmt = $db->prepare("
INSERT INTO tires (
id, name, brand, country, category, width, aspect_ratio, rim, size_str,
speed_index, load_index, season, season_fa, warranty_months, production_year,
fuel_efficiency, wet_grip, noise_level, price, discount_percent, stock,
rating, reviews_count, vehicles, description, features, image, is_featured, is_best_seller
) VALUES (
:id, :name, :brand, :country, :category, :width, :aspect_ratio, :rim, :size_str,
:speed_index, :load_index, :season, :season_fa, :warranty_months, :production_year,
:fuel_efficiency, :wet_grip, :noise_level, :price, :discount_percent, :stock,
:rating, :reviews_count, :vehicles, :description, :features, :image, :is_featured, :is_best_seller
)
");
return $stmt->execute([
':id' => $tire['id'],
':name' => $tire['name'],
':brand' => $tire['brand'],
':country' => $tire['country'] ?? '',
':category' => $tire['category'] ?? '',
':width' => (int)($tire['width'] ?? 0),
':aspect_ratio' => (int)($tire['aspect_ratio'] ?? 0),
':rim' => (int)($tire['rim'] ?? 0),
':size_str' => $tire['size_str'] ?? '',
':speed_index' => $tire['speed_index'] ?? '',
':load_index' => $tire['load_index'] ?? '',
':season' => $tire['season'] ?? 'four_season',
':season_fa' => $tire['season_fa'] ?? 'چهار فصل',
':warranty_months' => (int)($tire['warranty_months'] ?? 36),
':production_year' => $tire['production_year'] ?? '2026',
':fuel_efficiency' => $tire['fuel_efficiency'] ?? 'B',
':wet_grip' => $tire['wet_grip'] ?? 'A',
':noise_level' => $tire['noise_level'] ?? '69 dB',
':price' => (int)($tire['price'] ?? 0),
':discount_percent' => (int)($tire['discount_percent'] ?? 0),
':stock' => (int)($tire['stock'] ?? 0),
':rating' => (float)($tire['rating'] ?? 5.0),
':reviews_count' => (int)($tire['reviews_count'] ?? 0),
':vehicles' => json_encode($tire['vehicles'] ?? [], JSON_UNESCAPED_UNICODE),
':description' => $tire['description'] ?? '',
':features' => json_encode($tire['features'] ?? [], JSON_UNESCAPED_UNICODE),
':image' => $tire['image'] ?? '',
':is_featured' => !empty($tire['is_featured']) ? 1 : 0,
':is_best_seller' => !empty($tire['is_best_seller']) ? 1 : 0
]);
} }
public static function getConsultations() { public static function updateTire(string $id, array $updatedFields): bool {
$data = self::getData(); $db = self::getConnection();
return $data['consultations'] ?? []; $allowed = [
'name', 'brand', 'country', 'category', 'width', 'aspect_ratio', 'rim',
'size_str', 'speed_index', 'load_index', 'season', 'season_fa',
'warranty_months', 'production_year', 'fuel_efficiency', 'wet_grip',
'noise_level', 'price', 'discount_percent', 'stock', 'rating',
'reviews_count', 'vehicles', 'description', 'features', 'image',
'is_featured', 'is_best_seller'
];
$sets = [];
$params = [':id' => $id];
foreach ($updatedFields as $key => $value) {
if (in_array($key, $allowed, true)) {
$sets[] = "{$key} = :{$key}";
if ($key === 'vehicles' || $key === 'features') {
$params[":{$key}"] = is_array($value) ? json_encode($value, JSON_UNESCAPED_UNICODE) : $value;
} elseif ($key === 'is_featured' || $key === 'is_best_seller') {
$params[":{$key}"] = !empty($value) ? 1 : 0;
} else {
$params[":{$key}"] = $value;
}
}
} }
public static function addConsultation($entry) { if (empty($sets)) {
$data = self::getData(); return false;
$entry['id'] = 'CNS-' . (count($data['consultations'] ?? []) + 101); }
$sql = "UPDATE tires SET " . implode(', ', $sets) . " WHERE id = :id";
$stmt = $db->prepare($sql);
return $stmt->execute($params);
}
public static function deleteTire(string $id): bool {
$db = self::getConnection();
$stmt = $db->prepare("DELETE FROM tires WHERE id = :id");
return $stmt->execute([':id' => $id]);
}
public static function getBrands(): array {
$db = self::getConnection();
$stmt = $db->query("SELECT name, country, logo, desc FROM brands ORDER BY id ASC");
return $stmt->fetchAll();
}
public static function getArticles(): array {
$db = self::getConnection();
$stmt = $db->query("SELECT * FROM articles ORDER BY id ASC");
return $stmt->fetchAll();
}
public static function getPressureGuide(): array {
$db = self::getConnection();
$stmt = $db->query("SELECT vehicle, front_psi, rear_psi, standard_tire FROM pressure_guide ORDER BY id ASC");
return $stmt->fetchAll();
}
public static function getConsultations(): array {
$db = self::getConnection();
$stmt = $db->query("SELECT * FROM consultations ORDER BY created_at DESC");
return $stmt->fetchAll();
}
public static function addConsultation(array $entry): array {
$db = self::getConnection();
$countStmt = $db->query("SELECT COUNT(*) FROM consultations");
$total = (int)$countStmt->fetchColumn();
$id = 'CNS-' . ($total + 101);
$entry['id'] = $id;
$entry['created_at'] = date('Y-m-d H:i'); $entry['created_at'] = date('Y-m-d H:i');
$entry['status'] = 'جدید'; $entry['status'] = $entry['status'] ?? 'جدید';
$entry['admin_note'] = ''; $entry['admin_note'] = $entry['admin_note'] ?? '';
$data['consultations'][] = $entry;
self::saveData($data); $stmt = $db->prepare("
INSERT INTO consultations (id, name, phone, car, message, created_at, status, admin_note)
VALUES (:id, :name, :phone, :car, :message, :created_at, :status, :admin_note)
");
$stmt->execute([
':id' => $entry['id'],
':name' => $entry['name'],
':phone' => $entry['phone'],
':car' => $entry['car'] ?? '',
':message' => $entry['message'] ?? '',
':created_at' => $entry['created_at'],
':status' => $entry['status'],
':admin_note' => $entry['admin_note']
]);
return $entry; return $entry;
} }
public static function updateConsultationStatus($id, $status, $note = '') { public static function updateConsultationStatus(string $id, string $status, string $note = ''): bool {
$data = self::getData(); $db = self::getConnection();
foreach ($data['consultations'] as &$c) {
if ($c['id'] === $id) {
$c['status'] = $status;
if ($note !== '') { if ($note !== '') {
$c['admin_note'] = $note; $stmt = $db->prepare("UPDATE consultations SET status = :status, admin_note = :note WHERE id = :id");
return $stmt->execute([':id' => $id, ':status' => $status, ':note' => $note]);
} else {
$stmt = $db->prepare("UPDATE consultations SET status = :status WHERE id = :id");
return $stmt->execute([':id' => $id, ':status' => $status]);
} }
self::saveData($data);
return true;
}
}
return false;
} }
public static function deleteConsultation($id) { public static function deleteConsultation(string $id): bool {
$data = self::getData(); $db = self::getConnection();
$data['consultations'] = array_values(array_filter($data['consultations'], function($c) use ($id) { $stmt = $db->prepare("DELETE FROM consultations WHERE id = :id");
return $c['id'] !== $id; return $stmt->execute([':id' => $id]);
}));
return self::saveData($data);
} }
public static function addTire($tire) { public static function getSettings(): array {
$data = self::getData(); $db = self::getConnection();
$data['tires'][] = $tire; $stmt = $db->query("SELECT key, value FROM settings");
self::saveData($data); $rows = $stmt->fetchAll();
return true; $settings = [];
foreach ($rows as $r) {
$settings[$r['key']] = $r['value'];
} }
public static function updateTire($id, $updatedFields) { $defaults = [
$data = self::getData();
foreach ($data['tires'] as &$tire) {
if ($tire['id'] === $id) {
$tire = array_merge($tire, $updatedFields);
self::saveData($data);
return true;
}
}
return false;
}
public static function deleteTire($id) {
$data = self::getData();
$data['tires'] = array_values(array_filter($data['tires'], function($t) use ($id) {
return $t['id'] !== $id;
}));
return self::saveData($data);
}
public static function getSettings() {
$data = self::getData();
return $data['settings'] ?? [
"site_phone" => "021-88889900", "site_phone" => "021-88889900",
"emergency_phone" => "09123456789", "emergency_phone" => "09123456789",
"announcement" => "تضمین اصالت کالا و گارانتی معتبر شرکتی تا ۶۰ ماه | تاریخ تولید روز (2026)", "announcement" => "تضمین اصالت کالا و گارانتی معتبر شرکتی تا ۶۰ ماه | تاریخ تولید روز (2026)",
"central_address" => "تهران، خیابان آزادی، تقاطع یادگار امام، مجتمع تایر قاسمی" "central_address" => "تهران، خیابان آزادی، تقاطع یادگار امام، مجتمع تایر قاسمی"
]; ];
return array_merge($defaults, $settings);
} }
public static function updateSettings($settings) { public static function updateSettings(array $settings): bool {
$data = self::getData(); $db = self::getConnection();
$data['settings'] = array_merge($data['settings'] ?? [], $settings); $stmt = $db->prepare("INSERT OR REPLACE INTO settings (key, value) VALUES (:key, :value)");
return self::saveData($data); foreach ($settings as $k => $v) {
$stmt->execute([':key' => $k, ':value' => (string)$v]);
}
return true;
}
public static function getData(): array {
return [
'tires' => self::getTires(),
'brands' => self::getBrands(),
'articles' => self::getArticles(),
'pressure_guide' => self::getPressureGuide(),
'consultations' => self::getConsultations(),
'settings' => self::getSettings()
];
} }
} }
View File