Compare commits
2
Commits
main
...
production
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aca18b7229 | ||
|
|
07714f643c |
+20
@@ -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
@@ -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;
|
||||||
|
|||||||
@@ -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
@@ -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": "پاسخ داده شده"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
+274
-94
@@ -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 {
|
||||||
$json = file_get_contents(self::$file);
|
$envFile = __DIR__ . '/../.env';
|
||||||
return json_decode($json, true) ?: [];
|
if (file_exists($envFile)) {
|
||||||
}
|
$lines = file($envFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||||
|
foreach ($lines as $line) {
|
||||||
public static function saveData($data) {
|
$line = trim($line);
|
||||||
return file_put_contents(self::$file, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
if ($line === '' || str_starts_with($line, '#')) continue;
|
||||||
}
|
if (str_contains($line, '=')) {
|
||||||
|
[$k, $v] = explode('=', $line, 2);
|
||||||
public static function getTires() {
|
$k = trim($k);
|
||||||
$data = self::getData();
|
$v = trim($v);
|
||||||
return $data['tires'] ?? [];
|
if (!isset($_ENV[$k]) && !getenv($k)) {
|
||||||
}
|
putenv("$k=$v");
|
||||||
|
$_ENV[$k] = $v;
|
||||||
public static function getTireById($id) {
|
}
|
||||||
$tires = self::getTires();
|
}
|
||||||
foreach ($tires as $tire) {
|
|
||||||
if ($tire['id'] === $id) {
|
|
||||||
return $tire;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getBrands() {
|
/**
|
||||||
$data = self::getData();
|
* Get singleton PDO connection
|
||||||
return $data['brands'] ?? [];
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
$needsInit = !file_exists($dbPath) || filesize($dbPath) === 0;
|
||||||
|
|
||||||
|
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 getArticles() {
|
/**
|
||||||
$data = self::getData();
|
* Format tire record from DB row
|
||||||
return $data['articles'] ?? [];
|
*/
|
||||||
|
private static function formatTire(array $row): array {
|
||||||
|
return [
|
||||||
|
'id' => $row['id'],
|
||||||
|
'name' => $row['name'],
|
||||||
|
'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 getPressureGuide() {
|
public static function getTires(): array {
|
||||||
$data = self::getData();
|
$db = self::getConnection();
|
||||||
return $data['pressure_guide'] ?? [];
|
$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 getConsultations() {
|
public static function getTireById(string $id): ?array {
|
||||||
$data = self::getData();
|
$db = self::getConnection();
|
||||||
return $data['consultations'] ?? [];
|
$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 addConsultation($entry) {
|
public static function addTire(array $tire): bool {
|
||||||
$data = self::getData();
|
$db = self::getConnection();
|
||||||
$entry['id'] = 'CNS-' . (count($data['consultations'] ?? []) + 101);
|
$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 updateTire(string $id, array $updatedFields): bool {
|
||||||
|
$db = self::getConnection();
|
||||||
|
$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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($sets)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$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 ($note !== '') {
|
||||||
if ($c['id'] === $id) {
|
$stmt = $db->prepare("UPDATE consultations SET status = :status, admin_note = :note WHERE id = :id");
|
||||||
$c['status'] = $status;
|
return $stmt->execute([':id' => $id, ':status' => $status, ':note' => $note]);
|
||||||
if ($note !== '') {
|
} else {
|
||||||
$c['admin_note'] = $note;
|
$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) {
|
|
||||||
$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) {
|
$defaults = [
|
||||||
$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()
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user