قم بإنشاء مشروع متكامل في ملف واحد فقط باسم index....
作成日: 2025年9月10日
作成日: 2025年9月10日
قم بإنشاء مشروع متكامل في ملف واحد فقط باسم index.php يحتوي بداخله على HTML و CSS و JavaScript و PHP لتسهيل النشر على استضافة مجانية مثل InfinityFree.
المشروع يجب أن يتضمن:
واجهة جذابة واحترافية بأسلوب عصري (مثل Sora أو Ideogram).
معرض صور خاص بالمستخدمين + معرض صور خاص بالأدمن.
إمكانية توليد الصور باستخدام الخادم الخارجي:
https://47zg9vbcvs.adaptive.ai/api/generate
تضمين الكود الأساسي للاستدعاء (المرفق أدناه) ضمن المشروع.
تحديث في الوقت الفعلي (نظام AJAX Polling) لكل من:
عدد النقاط.
الإشعارات الفردية والجماعية.
حالة الحساب (نشط/معلق).
سجل توليد الصور.
تسجيل مستخدمين بدون تأكيد عبر البريد.
أول حساب يتم إنشاؤه يصبح أدمن تلقائيًا.
لكل حساب جديد يتم إضافة نقاط افتراضية يحددها الأدمن.
إعادة تعيين كلمة السر تلقائيًا عند النسيان.
إظهار عنوان IP في لوحة التحكم.
مراقبة المستخدمين (تعليق/إعادة تنشيط/تعديل النقاط في الوقت الفعلي).
عرض وحظر المستخدمين المسيئين.
إرسال إشعارات فردية أو جماعية للمستخدمين.
اختيار إشعارات جاهزة مسبقًا و إرسالها تلقائيًا.
شات دعم مباشر بين المستخدم والأدمن.
قسم خاص بالمقالات:
إضافة مقالات جديدة.
تعديل وحذف المقالات.
نشرها للعامة في صفحة مخصصة.
ثلاث باقات (منها واحدة مجانية).
ربط الدفع عبر Payeer باستخدام المحفظة:
P1028352381
المستخدم يرسل رقم العملية (Transaction ID).
تأكيد الدفع يتم يدويًا من طرف الأدمن.
إنشاء قاعدة بيانات SQLite تلقائيًا داخل مجلد db.
تخزين الصور المولدة في مجلد generated_images.
ضبط الأذونات (CHMOD 755 أو 777 عند الحاجة).
⚡ مهم جدًا:
المشروع يجب أن يكون في ملف واحد فقط index.php يحتوي على HTML + CSS + JS + PHP.
لا تقم فقط بتحليل البرومبت، بل ابدأ بإنشاء المشروع مباشرة.
فيما يلي مشروع متكامل “ملف واحد فقط” باسم index.php (HTML + CSS + JS + PHP + SQLite) جاهز للرفع مباشرةً على استضافة مجانية مثل InfinityFree.
يوفّر: نظام حسابات، أول مستخدم أدمن تلقائيًا، نقاط افتراضية قابلة للتعديل، توليد صور عبر الخادم الخارجي (مع تضمين كود الاستدعاء المطلوب)، حفظ الصور محليًا، تحديث لحظي عبر AJAX للنقاط/الإشعارات/حالة الحساب/سجل التوليد، معرض المستخدم + معرض الأدمن، لوحة تحكم أدمن كاملة (تعليق/تنشيط/تعديل نقاط، إشعارات فردية/جماعية، شات دعم، مقالات)، نظام باقات مع تأكيد يدوي للمدفوعات عبر Payeer، إنشاء قاعدة بيانات SQLite تلقائيًا داخل مجلد db، وتخزين الصور في generated_images مع ضبط أذونات المجلدات.
مهم: احفظ الملف التالي باسم
index.phpوارفعه وحده. أول تشغيل سيُنشئ المجلدات وقاعدة البيانات تلقائيًا.
php<?php /****************************************************** * Single-file App: index.php * Author: ChatGPT (for Larry Cruz) * Encoding: UTF-8 * Requirements: PHP 7.4+ with SQLite3/PDO_SQLite ******************************************************/ mb_internal_encoding("UTF-8"); session_start(); date_default_timezone_set('UTC'); define('DB_DIR', __DIR__ . '/db'); define('DB_FILE', DB_DIR . '/app.sqlite'); define('IMG_DIR', __DIR__ . '/generated_images'); define('BASE_URL', rtrim(dirname($_SERVER['SCRIPT_NAME']), '/\\')); function ensure_dirs() { if (!is_dir(DB_DIR)) @mkdir(DB_DIR, 0777, true); if (!is_dir(IMG_DIR)) @mkdir(IMG_DIR, 0777, true); @chmod(DB_DIR, 0777); @chmod(IMG_DIR, 0777); } ensure_dirs(); function db() { static $pdo = null; if ($pdo === null) { $pdo = new PDO('sqlite:' . DB_FILE); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->exec("PRAGMA journal_mode=WAL;"); $pdo->exec("PRAGMA foreign_keys=ON;"); } return $pdo; } function init_db() { $pdo = db(); // users $pdo->exec(" CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE NOT NULL, email TEXT, password_hash TEXT NOT NULL, is_admin INTEGER DEFAULT 0, points INTEGER DEFAULT 0, status TEXT DEFAULT 'active', -- active/suspended ip TEXT, plan TEXT DEFAULT 'free', created_at TEXT, last_login_at TEXT ); "); // settings $pdo->exec(" CREATE TABLE IF NOT EXISTS settings ( key TEXT PRIMARY KEY, value TEXT ); "); // notifications + recipients (تتبّع قراءة المستخدمين للبث/الفردي) $pdo->exec(" CREATE TABLE IF NOT EXISTS notifications ( id INTEGER PRIMARY KEY AUTOINCREMENT, message TEXT NOT NULL, created_at TEXT NOT NULL ); "); $pdo->exec(" CREATE TABLE IF NOT EXISTS notification_recipients ( id INTEGER PRIMARY KEY AUTOINCREMENT, notification_id INTEGER NOT NULL REFERENCES notifications(id) ON DELETE CASCADE, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, is_read INTEGER DEFAULT 0 ); "); // images $pdo->exec(" CREATE TABLE IF NOT EXISTS images ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, path TEXT NOT NULL, prompt TEXT, width INTEGER, height INTEGER, is_admin_gallery INTEGER DEFAULT 0, is_public INTEGER DEFAULT 1, created_at TEXT NOT NULL ); "); // support chat $pdo->exec(" CREATE TABLE IF NOT EXISTS support_messages ( id INTEGER PRIMARY KEY AUTOINCREMENT, from_user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, to_user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, message TEXT NOT NULL, created_at TEXT NOT NULL ); "); // articles $pdo->exec(" CREATE TABLE IF NOT EXISTS articles ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, content TEXT NOT NULL, is_published INTEGER DEFAULT 0, created_at TEXT NOT NULL, updated_at TEXT ); "); // payments $pdo->exec(" CREATE TABLE IF NOT EXISTS payments ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, plan TEXT NOT NULL, -- free/plus/pro tx_id TEXT NOT NULL, status TEXT DEFAULT 'pending', -- pending/approved/rejected created_at TEXT NOT NULL ); "); // default settings $stmt = $pdo->prepare("INSERT OR IGNORE INTO settings(key,value) VALUES ('default_points','50')"); $stmt->execute(); $stmt = $pdo->prepare("INSERT OR IGNORE INTO settings(key,value) VALUES ('ready_notifications', 'مرحبا بك!|تمت إضافة نقاط إلى رصيدك|تذكير: استخدم الوصف بدقة|هام: التزم بسياسات الاستخدام|خبر: ميزات جديدة قادمة')"); $stmt->execute(); } init_db(); function h($s){ return htmlspecialchars($s ?? '', ENT_QUOTES|ENT_SUBSTITUTE, 'UTF-8'); } function now(){ return gmdate('Y-m-d H:i:s'); } function ip_address(){ return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0'; } function rand_string($len=10){ $a='ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789'; $o=''; for($i=0;$i<$len;$i++){$o.=$a[random_int(0,strlen($a)-1)];} return $o; } function setting($key, $default=null){ $stmt = db()->prepare("SELECT value FROM settings WHERE key=?"); $stmt->execute([$key]); $v = $stmt->fetchColumn(); return $v !== false ? $v : $default; } function set_setting($key,$value){ $stmt = db()->prepare("INSERT INTO settings(key,value) VALUES(?,?) ON CONFLICT(key) DO UPDATE SET value=excluded.value"); $stmt->execute([$key,$value]); } function current_user(){ if (!empty($_SESSION['user_id'])) { $stmt = db()->prepare("SELECT * FROM users WHERE id=?"); $stmt->execute([$_SESSION['user_id']]); $u = $stmt->fetch(PDO::FETCH_ASSOC); if ($u) return $u; } return null; } function require_login_json(){ if (!current_user()){ http_response_code(401); echo json_encode(['ok'=>false,'error'=>'auth_required']); exit; } } function first_admin_id(){ $stmt = db()->query("SELECT id FROM users WHERE is_admin=1 ORDER BY id ASC LIMIT 1"); $id = $stmt->fetchColumn(); return $id ?: null; } function is_username_taken($username){ $stmt = db()->prepare("SELECT 1 FROM users WHERE username=?"); $stmt->execute([$username]); return (bool)$stmt->fetchColumn(); } /* ====================== AUTH HANDLERS ====================== */ if (isset($_POST['action']) && $_POST['action']==='register') { $username = trim($_POST['username'] ?? ''); $email = trim($_POST['email'] ?? ''); $password = $_POST['password'] ?? ''; if ($username==='' || $password==='') $error = "الرجاء إدخال اسم المستخدم وكلمة المرور."; elseif (is_username_taken($username)) $error = "اسم المستخدم مستخدم مسبقًا."; else { $pdo = db(); $count = (int)$pdo->query("SELECT COUNT(*) FROM users")->fetchColumn(); $is_admin = ($count===0) ? 1 : 0; // أول حساب = أدمن $default_points = (int)setting('default_points', '50'); $stmt = $pdo->prepare("INSERT INTO users (username,email,password_hash,is_admin,points,status,ip,plan,created_at) VALUES (?,?,?,?,?,?,?,?,?)"); $stmt->execute([ $username, $email, password_hash($password, PASSWORD_DEFAULT), $is_admin, $default_points, 'active', ip_address(), 'free', now() ]); $_SESSION['user_id'] = (int)$pdo->lastInsertId(); header("Location: ".($_SERVER['PHP_SELF'])); exit; } } if (isset($_POST['action']) && $_POST['action']==='login') { $username = trim($_POST['username'] ?? ''); $password = $_POST['password'] ?? ''; $stmt = db()->prepare("SELECT * FROM users WHERE username=?"); $stmt->execute([$username]); $u = $stmt->fetch(PDO::FETCH_ASSOC); if (!$u || !password_verify($password, $u['password_hash'])) { $error = "بيانات الدخول غير صحيحة."; } else { $_SESSION['user_id'] = (int)$u['id']; $stmt2 = db()->prepare("UPDATE users SET last_login_at=?, ip=? WHERE id=?"); $stmt2->execute([now(), ip_address(), $u['id']]); header("Location: ".($_SERVER['PHP_SELF'])); exit; } } if (isset($_POST['action']) && $_POST['action']==='reset_password') { $username = trim($_POST['username'] ?? ''); $stmt = db()->prepare("SELECT * FROM users WHERE username=? OR email=?"); $stmt->execute([$username,$username]); $u = $stmt->fetch(PDO::FETCH_ASSOC); if (!$u) { $error = "لم يتم العثور على حساب بهذا المعرف."; } else { $new = rand_string(10); $stmt2 = db()->prepare("UPDATE users SET password_hash=? WHERE id=?"); $stmt2->execute([password_hash($new, PASSWORD_DEFAULT), $u['id']]); $reset_success = "تمت إعادة تعيين كلمة السر. كلمة السر الجديدة: <code>".h($new)."</code>"; // إضافة إشعار $notif_id = add_notification("تمت إعادة تعيين كلمة المرور لحسابك."); add_notification_recipient($notif_id, $u['id']); } } if (isset($_POST['action']) && $_POST['action']==='logout') { session_destroy(); header("Location: ".($_SERVER['PHP_SELF'])); exit; } /* =============== UTIL: Notifications & Chat helpers =============== */ function add_notification($message){ $stmt = db()->prepare("INSERT INTO notifications (message,created_at) VALUES(?,?)"); $stmt->execute([$message, now()]); return (int)db()->lastInsertId(); } function add_notification_recipient($notification_id, $user_id){ $stmt = db()->prepare("INSERT INTO notification_recipients (notification_id,user_id,is_read) VALUES (?,?,0)"); $stmt->execute([$notification_id,$user_id]); } function broadcast_notification($message){ $pdo = db(); $pdo->beginTransaction(); try { $nid = add_notification($message); $user_ids = $pdo->query("SELECT id FROM users")->fetchAll(PDO::FETCH_COLUMN); $ins = $pdo->prepare("INSERT INTO notification_recipients (notification_id,user_id,is_read) VALUES (?,?,0)"); foreach ($user_ids as $uid) $ins->execute([$nid,$uid]); $pdo->commit(); return $nid; } catch (Exception $e) { $pdo->rollBack(); return null; } } /* ====================== AJAX API ====================== */ if (isset($_GET['ajax'])) { header('Content-Type: application/json; charset=utf-8'); $action = $_GET['ajax']; if ($action==='poll') { require_login_json(); $u = current_user(); // unread notifications $stmt = db()->prepare("SELECT COUNT(*) FROM notification_recipients WHERE user_id=? AND is_read=0"); $stmt->execute([$u['id']]); $unread = (int)$stmt->fetchColumn(); $stmt = db()->prepare(" SELECT n.id, n.message, n.created_at, nr.is_read FROM notifications n JOIN notification_recipients nr ON nr.notification_id=n.id WHERE nr.user_id=? ORDER BY n.id DESC LIMIT 10 "); $stmt->execute([$u['id']]); $notifs = $stmt->fetchAll(PDO::FETCH_ASSOC); // recent images (user history) $stmt = db()->prepare("SELECT id,path,created_at,prompt,width,height FROM images WHERE user_id=? ORDER BY id DESC LIMIT 10"); $stmt->execute([$u['id']]); $history = $stmt->fetchAll(PDO::FETCH_ASSOC); echo json_encode([ 'ok'=>true, 'points'=>(int)$u['points'], 'status'=>$u['status'], 'plan'=>$u['plan'], 'unread_notifications'=>$unread, 'notifications'=>$notifs, 'history'=>$history ]); exit; } if ($action==='mark_notifs_read') { require_login_json(); $u = current_user(); $stmt = db()->prepare("UPDATE notification_recipients SET is_read=1 WHERE user_id=?"); $stmt->execute([$u['id']]); echo json_encode(['ok'=>true]); exit; } if ($action==='save_image') { require_login_json(); $u = current_user(); $data = json_decode(file_get_contents('php://input'), true); if (!$data || empty($data['b64'])) { echo json_encode(['ok'=>false,'error'=>'no_data']); exit; } $b64 = $data['b64']; // raw base64 (بدون data:image) $prompt = trim($data['prompt'] ?? ''); $w = (int)($data['width'] ?? 0); $h = (int)($data['height'] ?? 0); $bin = base64_decode($b64); if ($bin===false) { echo json_encode(['ok'=>false,'error'=>'decode_failed']); exit; } $fname = 'img_'.time().'_'.bin2hex(random_bytes(4)).'.png'; $fpath = IMG_DIR . '/' . $fname; if (file_put_contents($fpath, $bin) === false) { echo json_encode(['ok'=>false,'error'=>'write_failed']); exit; } @chmod($fpath, 0777); $rel = 'generated_images/'.$fname; $stmt = db()->prepare("INSERT INTO images (user_id,path,prompt,width,height,is_admin_gallery,is_public,created_at) VALUES (?,?,?,?,?,?,?,?)"); $stmt->execute([$u['id'],$rel,$prompt,$w,$h,0,1,now()]); echo json_encode(['ok'=>true,'path'=>$rel]); exit; } if ($action==='get_chat') { require_login_json(); $u = current_user(); $admin_id = first_admin_id(); $peer = ($u['is_admin'] ? (int)($_GET['user_id'] ?? 0) : $admin_id); if (!$peer) $peer = $admin_id; $stmt = db()->prepare(" SELECT * FROM support_messages WHERE (from_user_id=? AND to_user_id=?) OR (from_user_id=? AND to_user_id=?) ORDER BY id ASC LIMIT 200 "); $stmt->execute([$u['id'],$peer,$peer,$u['id']]); echo json_encode(['ok'=>true,'peer'=>$peer,'messages'=>$stmt->fetchAll(PDO::FETCH_ASSOC)]); exit; } if ($action==='send_chat') { require_login_json(); $u = current_user(); $data = json_decode(file_get_contents('php://input'), true); $to = (int)($data['to'] ?? 0); if (!$to) $to = first_admin_id(); $msg = trim($data['message'] ?? ''); if ($msg===''){ echo json_encode(['ok'=>false,'error'=>'empty']); exit; } $stmt = db()->prepare("INSERT INTO support_messages (from_user_id,to_user_id,message,created_at) VALUES (?,?,?,?)"); $stmt->execute([$u['id'],$to,$msg,now()]); echo json_encode(['ok'=>true]); exit; } // Admin endpoints (simple JSON forms) if ($action==='admin_user_action') { require_login_json(); $u=current_user(); if(!$u['is_admin']){ http_response_code(403); echo json_encode(['ok'=>false]); exit; } $data = json_decode(file_get_contents('php://input'), true); $user_id = (int)$data['user_id']; $op = $data['op'] ?? ''; if ($op==='suspend') { $stmt = db()->prepare("UPDATE users SET status='suspended' WHERE id=?"); $stmt->execute([$user_id]); } elseif ($op==='activate') { $stmt = db()->prepare("UPDATE users SET status='active' WHERE id=?"); $stmt->execute([$user_id]); } elseif ($op==='set_points') { $pts = (int)($data['points'] ?? 0); $stmt = db()->prepare("UPDATE users SET points=? WHERE id=?"); $stmt->execute([$pts,$user_id]); } echo json_encode(['ok'=>true]); exit; } if ($action==='admin_send_notification') { require_login_json(); $u=current_user(); if(!$u['is_admin']){ http_response_code(403); echo json_encode(['ok'=>false]); exit; } $data = json_decode(file_get_contents('php://input'), true); $msg = trim($data['message'] ?? ''); $target = $data['target'] ?? 'all'; // 'all' أو user_id if ($msg===''){ echo json_encode(['ok'=>false,'error'=>'empty']); exit; } if ($target==='all') broadcast_notification($msg); else { $nid = add_notification($msg); add_notification_recipient($nid, (int)$target); } echo json_encode(['ok'=>true]); exit; } if ($action==='admin_article') { require_login_json(); $u=current_user(); if(!$u['is_admin']){ http_response_code(403); echo json_encode(['ok'=>false]); exit; } $data = json_decode(file_get_contents('php://input'), true); $op = $data['op'] ?? ''; if ($op==='create') { $t = trim($data['title'] ?? 'بدون عنوان'); $c = trim($data['content'] ?? ''); $stmt = db()->prepare("INSERT INTO articles (title,content,is_published,created_at,updated_at) VALUES (?,?,?,?,?)"); $stmt->execute([$t,$c,0,now(),now()]); echo json_encode(['ok'=>true]); exit; } elseif ($op==='update') { $id=(int)$data['id']; $t=trim($data['title']??''); $c=trim($data['content']??''); $p=(int)($data['is_published']??0); $stmt = db()->prepare("UPDATE articles SET title=?, content=?, is_published=?, updated_at=? WHERE id=?"); $stmt->execute([$t,$c,$p,now(),$id]); echo json_encode(['ok'=>true]); exit; } elseif ($op==='delete') { $id=(int)$data['id']; $stmt=db()->prepare("DELETE FROM articles WHERE id=?"); $stmt->execute([$id]); echo json_encode(['ok'=>true]); exit; } } if ($action==='admin_payment') { require_login_json(); $u=current_user(); if(!$u['is_admin']){ http_response_code(403); echo json_encode(['ok'=>false]); exit; } $data=json_decode(file_get_contents('php://input'), true); $id=(int)$data['id']; $status=$data['status'] ?? 'approved'; $stmt = db()->prepare("UPDATE payments SET status=? WHERE id=?"); $stmt->execute([$status,$id]); // ترقية الخطة عند الموافقة if ($status==='approved') { $row = db()->prepare("SELECT user_id,plan FROM payments WHERE id=?"); $row->execute([$id]); $p = $row->fetch(PDO::FETCH_ASSOC); if ($p) { db()->prepare("UPDATE users SET plan=? WHERE id=?")->execute([$p['plan'],$p['user_id']]); $nid = add_notification("تمت الموافقة على دفعتك وترقية خطتك إلى: ".$p['plan']); add_notification_recipient($nid, $p['user_id']); } } echo json_encode(['ok'=>true]); exit; } if ($action==='admin_toggle_admin_gallery') { require_login_json(); $u=current_user(); if(!$u['is_admin']){ http_response_code(403); echo json_encode(['ok'=>false]); exit; } $img=(int)($_GET['id']??0); $flag=(int)($_GET['flag']??0); db()->prepare("UPDATE images SET is_admin_gallery=? WHERE id=?")->execute([$flag,$img]); echo json_encode(['ok'=>true]); exit; } if ($action==='admin_update_defaults') { require_login_json(); $u=current_user(); if(!$u['is_admin']){ http_response_code(403); echo json_encode(['ok'=>false]); exit; } $data=json_decode(file_get_contents('php://input'),true); $def=intval($data['default_points']??50); set_setting('default_points', (string)$def); echo json_encode(['ok'=>true]); exit; } echo json_encode(['ok'=>false,'error'=>'unknown_action']); exit; } /* ====================== PAGE (HTML) ====================== */ $me = current_user(); ?> <!DOCTYPE html> <html lang="ar" dir="rtl"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>مولّد الصور - لوحة شاملة (ملف واحد)</title> <style> :root{ --bg:#0b0f1a; --card:#121827cc; --muted:#9aa4b2; --accent:#8b5cf6; /* violet-like */ --accent2:#06b6d4; /* cyan-like */ --good:#22c55e; --bad:#ef4444; } *{box-sizing:border-box} body{ margin:0; font-family:system-ui,-apple-system,Segoe UI,Roboto; color:#e5e7eb; background: radial-gradient(1000px 500px at 10% -10%, #1b2555 0%, transparent 60%), radial-gradient(1000px 500px at 90% 0%, #0f766e55 0%, transparent 60%), var(--bg); min-height:100vh; } header{ position:sticky; top:0; z-index:100; backdrop-filter: saturate(150%) blur(10px); background:linear-gradient(90deg,#0b0f1acc,#0b0f1a99); border-bottom:1px solid #1f2937; padding:12px 16px; display:flex; gap:12px; align-items:center; justify-content:space-between; } .brand{display:flex; align-items:center; gap:10px; font-weight:700; letter-spacing:.3px} .brand .dot{width:10px;height:10px;border-radius:50%;background:linear-gradient(45deg,var(--accent),var(--accent2)); box-shadow:0 0 12px var(--accent)} .pill{padding:6px 10px; border:1px solid #243041; border-radius:999px; background:#0b1220; color:#cbd5e1; font-size:13px} .btn{ border:0; background:linear-gradient(135deg,var(--accent),var(--accent2)); color:#fff; padding:10px 14px; border-radius:10px; cursor:pointer; font-weight:600; transition:transform .15s ease, opacity .15s ease; } .btn:disabled{opacity:.6; cursor:default} .btn.ghost{background:transparent; border:1px solid #334155; color:#e2e8f0} .btn.warn{background:linear-gradient(135deg,#ef4444,#f97316)} .grid{display:grid; gap:16px} .two{grid-template-columns:repeat(2,minmax(0,1fr))} .three{grid-template-columns:repeat(3,minmax(0,1fr))} @media(max-width:1000px){ .two,.three{grid-template-columns:1fr} } .card{background:var(--card); border:1px solid #1f2937; border-radius:16px; padding:16px; box-shadow:0 10px 30px #0005} h1,h2,h3{margin:6px 0 12px} small, .muted{color:var(--muted)} input,select,textarea{ width:100%; padding:10px 12px; background:#0b1220; border:1px solid #22304a; color:#e5e7eb; border-radius:10px; outline:none; font-size:14px } label{font-size:13px; color:#9fb0c3} .row{display:flex; gap:10px; align-items:center} .row.wrap{flex-wrap:wrap} .tabs{display:flex; gap:8px; flex-wrap:wrap} .tab{padding:8px 12px; border:1px solid #22304a; border-radius:999px; cursor:pointer; background:#0b1220} .tab.active{background:linear-gradient(135deg,#111827,#0b1220); border-color:#31415f} .gallery{display:grid; grid-template-columns:repeat(auto-fill,minmax(160px,1fr)); gap:10px} .gallery img{width:100%; border-radius:12px; display:block; border:1px solid #1f2937} .chip{display:inline-block; padding:2px 8px; border-radius:999px; border:1px solid #233147; font-size:12px; color:#a9b8cc} .table{width:100%; border-collapse:collapse; font-size:14px} .table th,.table td{border-bottom:1px solid #223047; padding:8px} .status.active{color:var(--good)} .status.suspended{color:var(--bad)} .kbd{background:#111827; border:1px solid #223047; padding:2px 6px; border-radius:6px; font-family:ui-monospace, SFMono-Regular, Menlo, monospace; font-size:12px} .note{background:#0b1220; border:1px dashed #233147; padding:10px; border-radius:10px} a{color:#93c5fd; text-decoration:none} </style> </head> <body> <header> <div class="brand"> <div class="dot"></div> <div>مولّد الصور</div> <span class="pill">ملف واحد</span> </div> <div class="row wrap"> <?php if ($me): ?> <span class="pill">الحساب: <b><?=h($me['username'])?></b> <span class="muted">[IP: <?=h($me['ip'])?>]</span></span> <span class="pill">الخطة: <b id="planLabel"><?=h($me['plan'])?></b></span> <span class="pill">نقاطك: <b id="pointsLabel"><?= (int)$me['points'] ?></b></span> <span class="pill">الحالة: <b id="statusLabel" class="status <?=h($me['status'])?>"><?=h($me['status'])?></b></span> <form method="post" style="margin:0"> <input type="hidden" name="action" value="logout"> <button class="btn ghost">تسجيل الخروج</button> </form> <?php else: ?> <span class="pill">غير مسجل دخول</span> <?php endif; ?> </div> </header> <main style="padding:20px; max-width:1200px; margin:0 auto"> <?php if (!$me): ?> <div class="grid two"> <div class="card"> <h2>تسجيل الدخول</h2> <?php if (!empty($error)) echo '<div class="note" style="color:#fecaca">'. $error .'</div>'; ?> <?php if (!empty($reset_success)) echo '<div class="note" style="color:#bbf7d0">'. $reset_success .'</div>'; ?> <form method="post" class="grid"> <input type="hidden" name="action" value="login"> <div> <label>اسم المستخدم</label> <input name="username" required> </div> <div> <label>كلمة المرور</label> <input name="password" type="password" required> </div> <button class="btn">دخول</button> </form> <details style="margin-top:10px"> <summary class="muted">نسيت كلمة السر؟</summary> <form method="post" class="grid" style="margin-top:10px"> <input type="hidden" name="action" value="reset_password"> <label>اكتب اسم المستخدم أو البريد لحسابك</label> <input name="username" required> <button class="btn">إعادة تعيين تلقائي</button> </form> </details> <div class="muted" style="margin-top:10px">أول حساب يتم إنشاؤه يصبح <b>أدمن</b> تلقائيًا.</div> </div> <div class="card"> <h2>إنشاء حساب</h2> <form method="post" class="grid"> <input type="hidden" name="action" value="register"> <div class="row"> <div style="flex:1"> <label>اسم المستخدم</label> <input name="username" required> </div> <div style="flex:1"> <label>البريد (اختياري)</label> <input name="email" type="email"> </div> </div> <div> <label>كلمة المرور</label> <input name="password" type="password" required> </div> <button class="btn">تسجيل</button> </form> <div class="note" style="margin-top:10px"> سيتم إضافة نقاط افتراضية لكل حساب جديد (القيمة يحددها الأدمن). لا حاجة لتأكيد البريد. </div> </div> </div> <?php else: ?> <!-- Tabs --> <div class="tabs" id="tabs"> <div class="tab active" data-tab="gen">توليد الصور</div> <div class="tab" data-tab="gallery">المعرض</div> <div class="tab" data-tab="articles">المقالات</div> <div class="tab" data-tab="support">الدعم المباشر</div> <div class="tab" data-tab="notifications">الإشعارات</div> <div class="tab" data-tab="plans">الباقات والدفع</div> <?php if ($me['is_admin']): ?> <div class="tab" data-tab="admin">لوحة الأدمن</div> <?php endif; ?> </div> <!-- Generator --> <section id="tab-gen" class="card" style="margin-top:12px"> <h2>توليد الصور</h2> <div class="grid two"> <div> <label>الوصف (Prompt)</label> <textarea id="prompt" rows="4" placeholder="صف الصورة بدقة..."></textarea> </div> <div> <label>الحجم</label> <select id="size" onchange="toggleCustomSize(this.value)"> <option value="512x512">512x512</option> <option value="768x768">768x768</option> <option value="1024x1024">1024x1024</option> <option value="custom">مخصص</option> </select> <div id="customSizeInputs" style="display:none; margin-top:8px" class="row"> <input id="customWidth" type="number" placeholder="العرض px" value="512" style="flex:1"> <input id="customHeight" type="number" placeholder="الارتفاع px" value="512" style="flex:1"> </div> <div class="row" style="margin-top:10px"> <button class="btn" onclick="generateImage()">توليد الآن</button> <span id="genInfo" class="muted"></span> </div> </div> </div> <div id="result" style="margin-top:12px" class="note"></div> <details style="margin-top:16px"> <summary class="muted">🧠 ملاحظة</summary> <div class="muted">بعد التوليد، يتم حفظ الصورة تلقائيًا في <span class="kbd">generated_images/</span> وتظهر في سجلّك وفي معرض المستخدم.</div> </details> </section> <!-- Gallery --> <section id="tab-gallery" class="card" style="display:none; margin-top:12px"> <h2>المعرض</h2> <div class="grid two"> <div> <h3>معرض المستخدم</h3> <div id="userGallery" class="gallery"></div> </div> <div> <h3>معرض الأدمن</h3> <div class="muted">صور مختارة من قبل فريق الإدارة.</div> <div class="gallery"> <?php $imgs = db()->query("SELECT path FROM images WHERE is_admin_gallery=1 ORDER BY id DESC LIMIT 60")->fetchAll(PDO::FETCH_COLUMN); if ($imgs) foreach ($imgs as $p) echo '<a href="'.h($p).'" target="_blank"><img src="'.h($p).'" alt=""></a>'; else echo '<div class="muted">لا توجد صور في معرض الأدمن بعد.</div>'; ?> </div> </div> </div> </section> <!-- Articles --> <section id="tab-articles" class="card" style="display:none; margin-top:12px"> <h2>المقالات</h2> <div class="grid"> <?php $arts = db()->query("SELECT * FROM articles WHERE is_published=1 ORDER BY id DESC")->fetchAll(PDO::FETCH_ASSOC); if (!$arts) echo '<div class="muted">لا توجد مقالات منشورة بعد.</div>'; foreach ($arts as $a){ echo '<div class="note"><h3>'.h($a['title']).'</h3><div>'.nl2br(h($a['content'])).'</div><div class="muted" style="margin-top:6px">نُشرت: '.h($a['created_at']).'</div></div>'; } ?> </div> </section> <!-- Support Chat --> <section id="tab-support" class="card" style="display:none; margin-top:12px"> <h2>الدعم المباشر</h2> <div id="chatBox" style="height:260px; overflow:auto; border:1px solid #223047; border-radius:12px; padding:10px; background:#0b1220"></div> <div class="row" style="margin-top:8px"> <input id="chatInput" placeholder="اكتب رسالتك..."> <button class="btn" onclick="sendChat()">إرسال</button> </div> </section> <!-- Notifications --> <section id="tab-notifications" class="card" style="display:none; margin-top:12px"> <h2>الإشعارات</h2> <div class="row"> <button class="btn ghost" onclick="markAllRead()">اعتبار الكل مقروءًا</button> <span class="chip">غير المقروء: <b id="unreadCount">0</b></span> </div> <div id="notifList" class="grid" style="margin-top:10px"></div> </section> <!-- Plans & Payment --> <section id="tab-plans" class="card" style="display:none; margin-top:12px"> <h2>الباقات والدفع</h2> <div class="grid three"> <div class="note"> <h3>مجانية</h3> <div>خطة البداية - مناسبة للتجربة.</div> <div class="chip">free</div> </div> <div class="note"> <h3>Plus</h3> <div>سرعات وأولوية أعلى.</div> <div class="chip">plus</div> </div> <div class="note"> <h3>Pro</h3> <div>للاستخدام المكثف والفرق.</div> <div class="chip">pro</div> </div> </div> <div style="margin-top:10px"> <h3>الدفع عبر Payeer</h3> <div class="muted">المحفظة: <span class="kbd">P1028352381</span></div> <div class="note" style="margin-top:6px"> بعد التحويل، أرسل رقم العملية (Transaction ID) ليتم التأكيد يدويًا من قبل الأدمن. </div> <form method="post" onsubmit="submitTX(event)" class="grid two" style="margin-top:8px"> <div> <label>اختر الباقة</label> <select id="planSel"> <option value="plus">Plus</option> <option value="pro">Pro</option> </select> </div> <div> <label>Transaction ID</label> <input id="txId" required> </div> <button class="btn">إرسال للتأكيد</button> </form> <div id="txStatus" class="muted" style="margin-top:8px"></div> <h3 style="margin-top:20px">طلباتك</h3> <table class="table"> <thead><tr><th>التاريخ</th><th>الباقة</th><th>TX</th><th>الحالة</th></tr></thead> <tbody> <?php $rows = db()->prepare("SELECT * FROM payments WHERE user_id=? ORDER BY id DESC"); $rows->execute([$me['id']]); $rows=$rows->fetchAll(PDO::FETCH_ASSOC); if (!$rows) echo '<tr><td colspan="4" class="muted">لا توجد طلبات.</td></tr>'; foreach ($rows as $r) echo '<tr><td>'.h($r['created_at']).'</td><td>'.h($r['plan']).'</td><td>'.h($r['tx_id']).'</td><td>'.h($r['status']).'</td></tr>'; ?> </tbody> </table> </div> </section> <!-- Admin Panel --> <?php if ($me['is_admin']): ?> <section id="tab-admin" class="card" style="display:none; margin-top:12px"> <h2>لوحة تحكم الأدمن</h2> <div class="grid two"> <div class="note"> <h3>إعدادات عامة</h3> <label>النقاط الافتراضية لكل مستخدم جديد</label> <div class="row"> <input id="defaultPoints" type="number" value="<?= (int)setting('default_points','50') ?>" style="max-width:150px"> <button class="btn" onclick="updateDefaults()">حفظ</button> </div> <details style="margin-top:10px"> <summary>إشعارات جاهزة</summary> <div class="muted">قم باختيار نص جاهز للإرسال السريع.</div> <div class="grid" id="readyNotifs" style="margin-top:6px"></div> </details> </div> <div class="note"> <h3>إرسال إشعار</h3> <label>الرسالة</label> <textarea id="admNotif" rows="3"></textarea> <div class="row" style="margin-top:8px"> <button class="btn" onclick="sendAdminNotif('all')">إرسال للجميع</button> <input id="toUserId" type="number" placeholder="User ID (اختياري)"> <button class="btn ghost" onclick="sendAdminNotif('one')">إرسال لمستخدم</button> </div> </div> </div> <div class="grid two" style="margin-top:12px"> <div class="note"> <h3>مراقبة المستخدمين</h3> <table class="table"> <thead><tr><th>ID</th><th>اسم</th><th>IP</th><th>نقاط</th><th>حالة</th><th>خطة</th><th>تحكم</th></tr></thead> <tbody> <?php $users = db()->query("SELECT id,username,ip,points,status,plan FROM users ORDER BY id DESC")->fetchAll(PDO::FETCH_ASSOC); foreach ($users as $u) { echo '<tr> <td>'.$u['id'].'</td> <td>'.h($u['username']).'</td> <td class="muted">'.h($u['ip']).'</td> <td><input type="number" id="pts'.$u['id'].'" value="'.(int)$u['points'].'" style="width:90px"></td> <td><span class="status '.$u['status'].'">'.h($u['status']).'</span></td> <td>'.h($u['plan']).'</td> <td class="row"> <button class="btn ghost" onclick="setPoints('.$u['id'].')">تعديل النقاط</button> <button class="btn '.($u['status']=='active'?'warn':'').'" onclick="toggleSuspend('.$u['id'].',\''.($u['status']=='active'?'suspend':'activate').'\')">'.($u['status']=='active'?'تعليق':'تنشيط').'</button> </td> </tr>'; } ?> </tbody> </table> </div> <div class="note"> <h3>إدارة المدفوعات</h3> <table class="table"> <thead><tr><th>ID</th><th>User</th><th>Plan</th><th>TX</th><th>تاريخ</th><th>حالة</th><th>إجراء</th></tr></thead> <tbody> <?php $pay = db()->query("SELECT p.*, u.username FROM payments p JOIN users u ON u.id=p.user_id ORDER BY p.id DESC")->fetchAll(PDO::FETCH_ASSOC); if (!$pay) echo '<tr><td colspan="7" class="muted">لا توجد طلبات.</td></tr>'; foreach ($pay as $p) { echo '<tr> <td>'.$p['id'].'</td> <td>'.h($p['username']).'</td> <td>'.h($p['plan']).'</td> <td>'.h($p['tx_id']).'</td> <td>'.h($p['created_at']).'</td> <td>'.h($p['status']).'</td> <td class="row"> <button class="btn" onclick="approvePay('.$p['id'].')">موافقة</button> <button class="btn warn" onclick="rejectPay('.$p['id'].')">رفض</button> </td> </tr>'; } ?> </tbody> </table> </div> </div> <div class="grid two" style="margin-top:12px"> <div class="note"> <h3>المقالات</h3> <div class="row"> <input id="artTitle" placeholder="العنوان"> <button class="btn" onclick="createArticle()">إضافة</button> </div> <textarea id="artContent" rows="6" placeholder="المحتوى..."></textarea> </div> <div class="note"> <h3>تحرير/نشر المقالات</h3> <table class="table"> <thead><tr><th>ID</th><th>العنوان</th><th>منشور؟</th><th>تحكم</th></tr></thead> <tbody> <?php $arts = db()->query("SELECT * FROM articles ORDER BY id DESC")->fetchAll(PDO::FETCH_ASSOC); if (!$arts) echo '<tr><td colspan="4" class="muted">لا توجد مقالات بعد.</td></tr>'; foreach ($arts as $a){ echo '<tr> <td>'.$a['id'].'</td> <td><input id="t'.$a['id'].'" value="'.h($a['title']).'" style="width:100%"></td> <td><select id="p'.$a['id'].'"><option value="0" '.(!$a['is_published']?'selected':'').'>لا</option><option value="1" '.($a['is_published']?'selected':'').'>نعم</option></select></td> <td class="row"> <button class="btn" onclick="updateArticle('.$a['id'].')">حفظ</button> <button class="btn warn" onclick="deleteArticle('.$a['id'].')">حذف</button> </td> </tr> <tr><td colspan="4"><textarea id="c'.$a['id'].'" rows="4" style="width:100%;">'.h($a['content']).'</textarea></td></tr>'; } ?> </tbody> </table> </div> </div> <div class="note" style="margin-top:12px"> <h3>اختيار صور إلى معرض الأدمن</h3> <div class="gallery"> <?php $all = db()->query("SELECT id,path,is_admin_gallery FROM images ORDER BY id DESC LIMIT 80")->fetchAll(PDO::FETCH_ASSOC); foreach ($all as $im){ echo '<div><a href="'.h($im['path']).'" target="_blank"><img src="'.h($im['path']).'"></a> <div class="row" style="margin-top:6px"><span class="chip">#'.$im['id'].'</span> <button class="btn ghost" onclick="toggleAdminGallery('.$im['id'].','.($im['is_admin_gallery']?0:1).')">'.($im['is_admin_gallery']?'إزالة':'إضافة').'</button> </div></div>'; } ?> </div> </div> </section> <?php endif; ?> <?php endif; // logged in ?> </main> <script> // ====== تبويب بسيط document.querySelectorAll('.tab').forEach(t=>{ t.addEventListener('click', ()=>{ document.querySelectorAll('.tab').forEach(x=>x.classList.remove('active')); t.classList.add('active'); const id = t.dataset.tab; document.querySelectorAll('section[id^="tab-"]').forEach(s=>s.style.display='none'); document.getElementById('tab-'+id).style.display='block'; }); }); // ====== تحديث لحظي (AJAX Polling) let pollTimer=null; <?php if ($me): ?> function startPolling(){ if (pollTimer) clearInterval(pollTimer); const run = ()=>{ fetch('index.php?ajax=poll').then(r=>r.json()).then(j=>{ if(!j.ok) return; // points, status, plan document.getElementById('pointsLabel').textContent = j.points; document.getElementById('statusLabel').textContent = j.status; document.getElementById('statusLabel').className = 'status '+j.status; document.getElementById('planLabel').textContent = j.plan; // notifications const unread = document.getElementById('unreadCount'); if (unread) unread.textContent = j.unread_notifications; const box = document.getElementById('notifList'); if (box) { box.innerHTML = ''; j.notifications.forEach(n=>{ const div = document.createElement('div'); div.className='note'; div.innerHTML = ``; box.appendChild(div); }); } // user gallery/history const g=document.getElementById('userGallery'); if (g){ g.innerHTML=''; if (j.history.length===0) g.innerHTML='<div class="muted">لا يوجد سجل توليد بعد.</div>'; j.history.forEach(im=>{ const a=document.createElement('a'); a.href = im.path; a.target='_blank'; const img=new Image(); img.src=im.path; img.alt=im.prompt||''; a.appendChild(img); g.appendChild(a); }); } }).catch(()=>{}); }; run(); pollTimer = setInterval(run, 5000); } startPolling(); <?php endif; ?> // ====== إشعارات: تحديد كمقروء function markAllRead(){ fetch('index.php?ajax=mark_notifs_read').then(r=>r.json()).then(_=>startPolling()); } // ====== دعم مباشر let chatPeer = null; // للمستخدم: الأدمن تلقائيًا function scrollChat(){ const box=document.getElementById('chatBox'); box.scrollTop=box.scrollHeight; } function loadChat(){ fetch('index.php?ajax=get_chat'+(chatPeer?('&user_id='+chatPeer):'')).then(r=>r.json()).then(j=>{ if(!j.ok) return; chatPeer = j.peer; const box=document.getElementById('chatBox'); if(!box) return; box.innerHTML=''; j.messages.forEach(m=>{ const meId = <?= $me ? (int)$me['id'] : 0 ?>; const mine = (m.from_user_id==meId); const item = document.createElement('div'); item.style.margin='6px 0'; item.style.textAlign= mine ? 'left' : 'right'; item.innerHTML = ``; box.appendChild(item); }); scrollChat(); }); } function sendChat(){ const inp=document.getElementById('chatInput'); const msg=inp.value.trim(); if(!msg) return; fetch('index.php?ajax=send_chat',{method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({to:chatPeer,message:msg})}) .then(r=>r.json()).then(j=>{ if(j.ok){ inp.value=''; loadChat(); } }); } <?php if ($me): ?> setInterval(loadChat, 6000); loadChat(); <?php endif; ?> // ====== نظام الدفع: إرسال TX function submitTX(e){ e.preventDefault(); const plan=document.getElementById('planSel').value; const tx=document.getElementById('txId').value.trim(); if(!tx){ alert('أدخل رقم العملية'); return; } // بسيط عبر POST عادي: سنستخدم fetch إلى self عبر INSERT server-side fetch('', {method:'POST', headers:{'Content-Type':'application/x-www-form-urlencoded'}, body:new URLSearchParams({ '__tx':'1','plan':plan,'tx':tx })}).then(()=>{ location.reload(); }); } // ====== Admin JS function toggleSuspend(uid,op){ fetch('index.php?ajax=admin_user_action',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({user_id:uid,op:op})}) .then(r=>r.json()).then(j=>{ if(j.ok){ startPolling(); location.reload(); }}); } function setPoints(uid){ const val = document.getElementById('pts'+uid).value; fetch('index.php?ajax=admin_user_action',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({user_id:uid,op:'set_points',points:val})}) .then(r=>r.json()).then(j=>{ if(j.ok){ startPolling(); }}); } function sendAdminNotif(mode){ const msg=document.getElementById('admNotif').value.trim(); if(!msg) return; const payload={message:msg, target:(mode==='all'?'all':(document.getElementById('toUserId').value||'all'))}; fetch('index.php?ajax=admin_send_notification',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(payload)}) .then(r=>r.json()).then(j=>{ if(j.ok){ alert('تم الإرسال'); document.getElementById('admNotif').value=''; } }); } function createArticle(){ const t=document.getElementById('artTitle').value.trim(); const c=document.getElementById('artContent').value.trim(); if(!t||!c) return alert('أدخل العنوان والمحتوى'); fetch('index.php?ajax=admin_article',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({op:'create',title:t,content:c})}) .then(()=>location.reload()); } function updateArticle(id){ const t=document.getElementById('t'+id).value; const c=document.getElementById('c'+id).value; const p=document.getElementById('p'+id).value; fetch('index.php?ajax=admin_article',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({op:'update',id:id,title:t,content:c,is_published:p})}) .then(()=>alert('تم الحفظ')); } function deleteArticle(id){ if(!confirm('حذف المقال؟')) return; fetch('index.php?ajax=admin_article',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({op:'delete',id:id})}) .then(()=>location.reload()); } function approvePay(id){ fetch('index.php?ajax=admin_payment',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({id:id,status:'approved'})}) .then(()=>location.reload()); } function rejectPay(id){ fetch('index.php?ajax=admin_payment',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({id:id,status:'rejected'})}) .then(()=>location.reload()); } function toggleAdminGallery(id,flag){ fetch('index.php?ajax=admin_toggle_admin_gallery&id='+id+'&flag='+flag) .then(()=>location.reload()); } function updateDefaults(){ const v=parseInt(document.getElementById('defaultPoints').value||'50',10); fetch('index.php?ajax=admin_update_defaults',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({default_points:v})}) .then(()=>alert('تم التحديث')); } (function initReadyNotifs(){ const wrap=document.getElementById('readyNotifs'); if(!wrap) return; const list="<?=h(setting('ready_notifications','مرحبا بك!|اختبار|نص جاهز'))?>".split('|'); list.forEach(txt=>{ const b=document.createElement('button'); b.className='btn ghost'; b.style.margin='4px'; b.textContent=txt; b.onclick=()=>{ document.getElementById('admNotif').value = txt; }; wrap.appendChild(b); }); })(); // ====== تضمين كود الاستدعاء الأساسي كما طلبت (مع حفظ تلقائي للسيرفر) function toggleCustomSize(value) { const customDiv = document.getElementById("customSizeInputs"); customDiv.style.display = value === "custom" ? "block" : "none"; } async function generateImage() { const prompt = document.getElementById("prompt").value; const size = document.getElementById("size").value; let width, height; if (size === "custom") { width = parseInt(document.getElementById("customWidth").value) || 512; height = parseInt(document.getElementById("customHeight").value) || 512; } else { const parts = size.split("x"); width = parseInt(parts[0]); height = parseInt(parts[1]); } document.getElementById("result").innerHTML = "<p>⏳ جاري التوليد...</p>"; try { const response = await fetch("https://47zg9vbcvs.adaptive.ai/api/generate", { method: "POST", headers: { "Content-Type": "application/json", "Accept": "*/*" }, body: JSON.stringify({ model: "black-forest-labs/flux-schnell", prompt: prompt, response_format: "b64_json", response_extension: "png", width: width, height: height, num_inference_steps: 4, negative_prompt: "", seed: -1 }) }); const data = await response.json(); console.log("API Response:", data); if (data && data.data && data.data[0] && data.data[0].b64_json) { const base64 = data.data[0].b64_json; const imgUrl = "data:image/png;base64," + base64; document.getElementById("result").innerHTML = ` <h3>✅ النتيجة:</h3> <img src="${imgUrl}" alt="Generated Image"> <br><a href="${imgUrl}" download="generated.png">⬇️ تحميل الصورة</a> `; // --- إضافة: حفظ تلقائي في السيرفر لتحديث سجلّ التوليد والمعرض --- saveImageToServer(base64, prompt, width, height).then(()=>startPolling()); } else { document.getElementById("result").innerHTML = "<p>⚠️ لم يتم العثور على بيانات صورة في الرد.</p>"; } } catch (error) { document.getElementById("result").innerHTML = "<p>❌ خطأ: " + error.message + "</p>"; } } // حفظ الصورة المولدة في مجلد generated_images عبر AJAX async function saveImageToServer(base64, prompt, width, height){ try{ const r = await fetch('index.php?ajax=save_image', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({b64: base64, prompt: prompt, width: width, height: height}) }); const j = await r.json(); if(!j.ok){ console.warn('لم يتم الحفظ:', j); } }catch(e){ console.warn('حفظ فشل', e); } } // ====== أدوات مساعدة function escapeHtml(str){ return (str||'').replace(/[&<>"']/g, m=>({ '&':'&','<':'<','>':'>','"':'"',"'":''' }[m])); } // ====== إدراج دفع (POST عادي لعدم تعقيد CORS) <?php if ($me && isset($_POST['__tx'])): $plan = $_POST['plan'] ?? 'plus'; $tx = trim($_POST['tx'] ?? ''); if ($tx !== '') { $stmt = db()->prepare("INSERT INTO payments (user_id,plan,tx_id,status,created_at) VALUES (?,?,?,?,?)"); $stmt->execute([$me['id'],$plan,$tx,'pending',now()]); $nid = add_notification("تم استلام طلب الدفع الخاص بك. سيتم المراجعة يدويًا قريبًا."); add_notification_recipient($nid, $me['id']); } endif; ?> </script> </body> </html>
P1028352381).جاهز؟ انسخ الملف وابدأ 👌
اضف ميزة تمكن الادمن من وضع اعلانات من مواقع اعلانات مختلفة تشخر في واجهة حسابات المستخدمين و في المقالات التي سيقوم الادمن بنشرها مع تحكم كامل بها و في امكانها و يستطيع اظهارها و منعها من خلال لوحة تحكم
تمام! أضفت لك ميزة إدارة الإعلانات (من شبكات مختلفة) مع تحكّم كامل في الظهور والمكان، وتتكامل داخل نفس ملف index.php بدون أي ملفات إضافية.
الخطوات التالية عبارة عن تحديثات موضعية (قص/لصق) على ملفك الحالي. اتبعها بالترتيب:
ابحث عن دالة init_db() وأضف الأجزاء التالية بداخلها (بعد جداولك الحالية مباشرة):
php// ads $pdo->exec(" CREATE TABLE IF NOT EXISTS ads ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, network TEXT, code TEXT NOT NULL, -- كود الإعلان (HTML/JS) كما هو position TEXT NOT NULL, -- موضع الظهور is_active INTEGER DEFAULT 1, -- 1 يظهر / 0 مخفي priority INTEGER DEFAULT 0, -- أولوية الظهور (أصغر = قبل) created_at TEXT NOT NULL ); ");
لا حاجة لإدخال بيانات افتراضية؛ ستضيفها من لوحة الأدمن.
ضع هذا قبل بداية إخراج الـ HTML (بعد تعريف الدوال المساعدة وقبل /* ====================== PAGE (HTML) ====================== */):
php// ====== مواضع الإعلانات المعتمدة $AD_POS = [ 'top_banner' => 'بنر أعلى الموقع', 'under_generator' => 'أسفل قسم التوليد', 'gallery_top' => 'أعلى المعرض', 'articles_top' => 'أعلى صفحة المقالات', 'articles_bottom' => 'أسفل صفحة المقالات', 'global_footer' => 'أسفل الموقع' ]; // ====== دالة عرض الإعلانات لموضع محدد function render_ads($slot){ $stmt = db()->prepare("SELECT title, code FROM ads WHERE is_active=1 AND position=? ORDER BY priority ASC, id ASC"); $stmt->execute([$slot]); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); if (!$rows) return; echo '<div class="ad-stack">'; foreach ($rows as $r){ // ملاحظة: الكود يُعرض كما هو (قد يحتوي سكربت من شبكة الإعلانات) echo '<div class="ad-box" data-slot="'.h($slot).'" title="'.h($r['title']).'">'.$r['code'].'</div>'; } echo '</div>'; }
داخل وسم <style> في رأس الصفحة، أضف:
css.ad-stack{ display:grid; gap:10px; margin:8px 0 } .ad-box{ background:#0b1220; border:1px dashed #334155; border-radius:12px; padding:8px; overflow:hidden; } .ad-box:has(iframe), .ad-box:has(script){ border-style:solid; }
بعد عنصر <header>...</header> مباشرةً أضف:
php<?php render_ads('top_banner'); ?>
داخل تبويب التوليد (قبل إغلاق </section> لقسم توليد الصور) أضف:
php<?php render_ads('under_generator'); ?>
داخل قسم المعرض (بعد <h2>المعرض</h2> مباشرة):
php<?php render_ads('gallery_top'); ?>
<h2>المقالات</h2>):php<?php render_ads('articles_top'); ?>
</section> لقسم المقالات):php<?php render_ads('articles_bottom'); ?>
قبل إغلاق </main> مباشرة:
php<?php render_ads('global_footer'); ?>
في تبويب الأدمن داخل القسم <section id="tab-admin"...> ضع هذا بلوك جديد مثلاً أسفل “تحرير/نشر المقالات”:
php<div class="note" style="margin-top:12px"> <h3>الإعلانات</h3> <h4>إضافة إعلان جديد</h4> <div class="grid two"> <div> <label>العنوان التعريفي</label> <input id="adTitle" placeholder="مثال: بنر جوجل - أعلى"> </div> <div> <label>الشبكة الإعلانية</label> <input id="adNetwork" placeholder="Google, Propeller, ..."> </div> </div> <div class="grid two" style="margin-top:8px"> <div> <label>الموضع</label> <select id="adPosition"> <?php foreach($AD_POS as $k=>$v) echo '<option value="'.h($k).'">'.h($v).'</option>'; ?> </select> </div> <div> <label>الأولوية (0 أولاً)</label> <input id="adPriority" type="number" value="0"> </div> </div> <div style="margin-top:8px"> <label>كود الإعلان (HTML/JS كما هو من الشبكة)</label> <textarea id="adCode" rows="5" placeholder="ألصق كود الإعلان من الشبكة هنا"></textarea> </div> <div class="row" style="margin-top:8px"> <button class="btn" onclick="createAd()">إضافة إعلان</button> </div> <h4 style="margin-top:16px">كل الإعلانات</h4> <table class="table"> <thead> <tr><th>ID</th><th>العنوان</th><th>الشبكة</th><th>الموضع</th><th>أولوية</th><th>نشط؟</th><th>تحكم</th></tr> </thead> <tbody> <?php $ads = db()->query("SELECT * FROM ads ORDER BY position ASC, priority ASC, id DESC")->fetchAll(PDO::FETCH_ASSOC); if (!$ads) echo '<tr><td colspan="7" class="muted">لا توجد إعلانات بعد.</td></tr>'; foreach ($ads as $a){ echo '<tr> <td>'.$a['id'].'</td> <td><input id="adt'.$a['id'].'" value="'.h($a['title']).'" style="width:140px"></td> <td><input id="adn'.$a['id'].'" value="'.h($a['network']).'" style="width:120px"></td> <td> <select id="adp'.$a['id'].'">'; foreach($AD_POS as $k=>$v){ $sel = ($a['position']===$k)?'selected':''; echo '<option value="'.h($k).'" '.$sel.'>'.h($v).'</option>'; } echo '</select> </td> <td><input id="adr'.$a['id'].'" type="number" value="'.(int)$a['priority'].'" style="width:80px"></td> <td> <select id="ada'.$a['id'].'"> <option value="1" '.($a['is_active']?'selected':'').'>نعم</option> <option value="0" '.(!$a['is_active']?'selected':'').'>لا</option> </select> </td> <td class="row"> <button class="btn" onclick="updateAd('.$a['id'].')">حفظ</button> <button class="btn ghost" onclick="editAdCode('.$a['id'].')">تحرير الكود</button> <button class="btn warn" onclick="deleteAd('.$a['id'].')">حذف</button> </td> </tr> <tr><td colspan="7"> <textarea id="adc'.$a['id'].'" rows="4" style="width:100%; display:none;">'.h($a['code']).'</textarea> </td></tr>'; } ?> </tbody> </table> <div class="muted" style="margin-top:6px"> ⚠️ تأكد أنك تثق في كود الإعلانات (قد يحتوي سكربت). يوصى بإضافة شبكات موثوقة فقط. </div> </div>
ضمن سكربت الصفحة (حيث توجد دوال الأدمن الأخرى)، أضف:
javascript// ===== الإعلانات: CRUD function createAd(){ const title = document.getElementById('adTitle').value.trim(); const network = document.getElementById('adNetwork').value.trim(); const position = document.getElementById('adPosition').value; const priority = parseInt(document.getElementById('adPriority').value||'0',10); const code = document.getElementById('adCode').value; if(!title || !code){ alert('أدخل العنوان والكود'); return; } fetch('index.php?ajax=admin_ads', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({op:'create', title, network, position, priority, code}) }).then(r=>r.json()).then(j=>{ if(j.ok){ location.reload(); } else { alert('فشل الإضافة'); } }); } function updateAd(id){ const title = document.getElementById('adt'+id).value.trim(); const network = document.getElementById('adn'+id).value.trim(); const position = document.getElementById('adp'+id).value; const priority = parseInt(document.getElementById('adr'+id).value||'0',10); const is_active = parseInt(document.getElementById('ada'+id).value||'1',10); const code = document.getElementById('adc'+id).style.display==='none' ? null : document.getElementById('adc'+id).value; fetch('index.php?ajax=admin_ads', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({op:'update', id, title, network, position, priority, is_active, code}) }).then(r=>r.json()).then(j=>{ if(j.ok){ alert('تم الحفظ'); if(j.reload) location.reload(); } else { alert('فشل التحديث'); } }); } function deleteAd(id){ if(!confirm('حذف الإعلان نهائيًا؟')) return; fetch('index.php?ajax=admin_ads', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({op:'delete', id}) }).then(r=>r.json()).then(j=>{ if(j.ok){ location.reload(); } else { alert('فشل الحذف'); } }); } function editAdCode(id){ const ta = document.getElementById('adc'+id); ta.style.display = (ta.style.display==='none' ? 'block' : 'none'); }
ابحث عن كتلة الـ AJAX لديك (حيث if (isset($_GET['ajax'])) { ... }) وأضف الفرع التالي بداخلها (مع بقية فروع الأدمن):
phpif ($action==='admin_ads') { require_login_json(); $u=current_user(); if(!$u['is_admin']){ http_response_code(403); echo json_encode(['ok'=>false]); exit; } $data = json_decode(file_get_contents('php://input'), true); $op = $data['op'] ?? ''; if ($op==='create') { $title = trim($data['title'] ?? ''); $network = trim($data['network'] ?? ''); $position = trim($data['position'] ?? 'top_banner'); $priority = (int)($data['priority'] ?? 0); $code = $data['code'] ?? ''; if ($title==='' || $code===''){ echo json_encode(['ok'=>false,'error'=>'missing']); exit; } $stmt = db()->prepare("INSERT INTO ads (title,network,code,position,is_active,priority,created_at) VALUES (?,?,?,?,1,?,?)"); $stmt->execute([$title,$network,$code,$position,$priority,now()]); echo json_encode(['ok'=>true]); exit; } elseif ($op==='update') { $id=(int)($data['id'] ?? 0); if(!$id){ echo json_encode(['ok'=>false]); exit; } $title = trim($data['title'] ?? ''); $network = trim($data['network'] ?? ''); $position = trim($data['position'] ?? 'top_banner'); $priority = (int)($data['priority'] ?? 0); $is_active = (int)($data['is_active'] ?? 1); // إن تم فتح حقل الكود وإرساله نحدّثه، وإلا نتركه كما هو if (array_key_exists('code',$data) && $data['code']!==null) { $code = $data['code']; $stmt = db()->prepare("UPDATE ads SET title=?, network=?, code=?, position=?, is_active=?, priority=? WHERE id=?"); $stmt->execute([$title,$network,$code,$position,$is_active,$priority,$id]); echo json_encode(['ok'=>true,'reload'=>false]); exit; } else { $stmt = db()->prepare("UPDATE ads SET title=?, network=?, position=?, is_active=?, priority=? WHERE id=?"); $stmt->execute([$title,$network,$position,$is_active,$priority,$id]); echo json_encode(['ok'=>true,'reload'=>false]); exit; } } elseif ($op==='delete') { $id=(int)($data['id'] ?? 0); if(!$id){ echo json_encode(['ok'=>false]); exit; } db()->prepare("DELETE FROM ads WHERE id=?")->execute([$id]); echo json_encode(['ok'=>true]); exit; } echo json_encode(['ok'=>false,'error'=>'unknown_op']); exit; }
بعد تطبيق التعديلات:
لو رغبت لاحقًا بإضافة مواضع جديدة:
$AD_POS.render_ads('الموضع_الجديد') حيث تريد ظهوره في الصفحة.إذا أحببت، أستطيع دمج كل التعديلات في نسخة كاملة من index.php كملف واحد جاهز للنسخ واللصق.
رجاءا اعطني الكود المحدث كاملا ، كما تعلم ليست لي خبرة كافية في البرمجة
تمام! هذا هو ملف index.php المُحدَّث كاملًا (ملف واحد فقط) مع ميزة إدارة الإعلانات مدموجة وجاهزة للرفع كما هو على استضافة مجانية (مثل InfinityFree).
انسخه كما هو واحفظه باسم index.php.
يتضمن: نظام الحسابات، لوحة الأدمن، توليد الصور عبر واجهة API الخارجية (مع كود الاستدعاء المطلوب)، حفظ الصور، تحديث لحظي عبر AJAX، مقالات، باقات مع الدفع عبر Payeer (تأكيد يدوي)، وإدارة الإعلانات بمواقع متعددة مع تحكم كامل بالظهور والموضع.
php<?php /****************************************************** * Single-file App: index.php * Author: ChatGPT * Encoding: UTF-8 * Requirements: PHP 7.4+ with SQLite3/PDO_SQLite ******************************************************/ mb_internal_encoding("UTF-8"); session_start(); date_default_timezone_set('UTC'); define('DB_DIR', __DIR__ . '/db'); define('DB_FILE', DB_DIR . '/app.sqlite'); define('IMG_DIR', __DIR__ . '/generated_images'); define('BASE_URL', rtrim(dirname($_SERVER['SCRIPT_NAME']), '/\\')); function ensure_dirs() { if (!is_dir(DB_DIR)) @mkdir(DB_DIR, 0777, true); if (!is_dir(IMG_DIR)) @mkdir(IMG_DIR, 0777, true); @chmod(DB_DIR, 0777); @chmod(IMG_DIR, 0777); } ensure_dirs(); function db() { static $pdo = null; if ($pdo === null) { $pdo = new PDO('sqlite:' . DB_FILE); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->exec("PRAGMA journal_mode=WAL;"); $pdo->exec("PRAGMA foreign_keys=ON;"); } return $pdo; } function init_db() { $pdo = db(); // users $pdo->exec(" CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE NOT NULL, email TEXT, password_hash TEXT NOT NULL, is_admin INTEGER DEFAULT 0, points INTEGER DEFAULT 0, status TEXT DEFAULT 'active', -- active/suspended ip TEXT, plan TEXT DEFAULT 'free', created_at TEXT, last_login_at TEXT ); "); // settings $pdo->exec(" CREATE TABLE IF NOT EXISTS settings ( key TEXT PRIMARY KEY, value TEXT ); "); // notifications $pdo->exec(" CREATE TABLE IF NOT EXISTS notifications ( id INTEGER PRIMARY KEY AUTOINCREMENT, message TEXT NOT NULL, created_at TEXT NOT NULL ); "); $pdo->exec(" CREATE TABLE IF NOT EXISTS notification_recipients ( id INTEGER PRIMARY KEY AUTOINCREMENT, notification_id INTEGER NOT NULL REFERENCES notifications(id) ON DELETE CASCADE, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, is_read INTEGER DEFAULT 0 ); "); // images $pdo->exec(" CREATE TABLE IF NOT EXISTS images ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, path TEXT NOT NULL, prompt TEXT, width INTEGER, height INTEGER, is_admin_gallery INTEGER DEFAULT 0, is_public INTEGER DEFAULT 1, created_at TEXT NOT NULL ); "); // support chat $pdo->exec(" CREATE TABLE IF NOT EXISTS support_messages ( id INTEGER PRIMARY KEY AUTOINCREMENT, from_user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, to_user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, message TEXT NOT NULL, created_at TEXT NOT NULL ); "); // articles $pdo->exec(" CREATE TABLE IF NOT EXISTS articles ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, content TEXT NOT NULL, is_published INTEGER DEFAULT 0, created_at TEXT NOT NULL, updated_at TEXT ); "); // payments $pdo->exec(" CREATE TABLE IF NOT EXISTS payments ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, plan TEXT NOT NULL, -- free/plus/pro tx_id TEXT NOT NULL, status TEXT DEFAULT 'pending', -- pending/approved/rejected created_at TEXT NOT NULL ); "); // ads (NEW) $pdo->exec(" CREATE TABLE IF NOT EXISTS ads ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, network TEXT, code TEXT NOT NULL, -- raw ad HTML/JS code position TEXT NOT NULL, -- slot key is_active INTEGER DEFAULT 1, -- 1 show / 0 hide priority INTEGER DEFAULT 0, -- lower first created_at TEXT NOT NULL ); "); // default settings $stmt = $pdo->prepare("INSERT OR IGNORE INTO settings(key,value) VALUES ('default_points','50')"); $stmt->execute(); $stmt = $pdo->prepare("INSERT OR IGNORE INTO settings(key,value) VALUES ('ready_notifications', 'مرحبا بك!|تمت إضافة نقاط إلى رصيدك|تذكير: استخدم الوصف بدقة|هام: التزم بسياسات الاستخدام|خبر: ميزات جديدة قادمة')"); $stmt->execute(); } init_db(); function h($s){ return htmlspecialchars($s ?? '', ENT_QUOTES|ENT_SUBSTITUTE, 'UTF-8'); } function now(){ return gmdate('Y-m-d H:i:s'); } function ip_address(){ return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0'; } function rand_string($len=10){ $a='ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789'; $o=''; for($i=0;$i<$len;$i++){$o.=$a[random_int(0,strlen($a)-1)];} return $o; } function setting($key, $default=null){ $stmt = db()->prepare("SELECT value FROM settings WHERE key=?"); $stmt->execute([$key]); $v = $stmt->fetchColumn(); return $v !== false ? $v : $default; } function set_setting($key,$value){ $stmt = db()->prepare("INSERT INTO settings(key,value) VALUES(?,?) ON CONFLICT(key) DO UPDATE SET value=excluded.value"); $stmt->execute([$key,$value]); } function current_user(){ if (!empty($_SESSION['user_id'])) { $stmt = db()->prepare("SELECT * FROM users WHERE id=?"); $stmt->execute([$_SESSION['user_id']]); $u = $stmt->fetch(PDO::FETCH_ASSOC); if ($u) return $u; } return null; } function require_login_json(){ if (!current_user()){ http_response_code(401); echo json_encode(['ok'=>false,'error'=>'auth_required']); exit; } } function first_admin_id(){ $stmt = db()->query("SELECT id FROM users WHERE is_admin=1 ORDER BY id ASC LIMIT 1"); $id = $stmt->fetchColumn(); return $id ?: null; } function is_username_taken($username){ $stmt = db()->prepare("SELECT 1 FROM users WHERE username=?"); $stmt->execute([$username]); return (bool)$stmt->fetchColumn(); } /* ====================== AUTH HANDLERS ====================== */ if (isset($_POST['action']) && $_POST['action']==='register') { $username = trim($_POST['username'] ?? ''); $email = trim($_POST['email'] ?? ''); $password = $_POST['password'] ?? ''; if ($username==='' || $password==='') $error = "الرجاء إدخال اسم المستخدم وكلمة المرور."; elseif (is_username_taken($username)) $error = "اسم المستخدم مستخدم مسبقًا."; else { $pdo = db(); $count = (int)$pdo->query("SELECT COUNT(*) FROM users")->fetchColumn(); $is_admin = ($count===0) ? 1 : 0; // أول حساب = أدمن $default_points = (int)setting('default_points', '50'); $stmt = $pdo->prepare("INSERT INTO users (username,email,password_hash,is_admin,points,status,ip,plan,created_at) VALUES (?,?,?,?,?,?,?,?,?)"); $stmt->execute([ $username, $email, password_hash($password, PASSWORD_DEFAULT), $is_admin, $default_points, 'active', ip_address(), 'free', now() ]); $_SESSION['user_id'] = (int)$pdo->lastInsertId(); header("Location: ".($_SERVER['PHP_SELF'])); exit; } } if (isset($_POST['action']) && $_POST['action']==='login') { $username = trim($_POST['username'] ?? ''); $password = $_POST['password'] ?? ''; $stmt = db()->prepare("SELECT * FROM users WHERE username=?"); $stmt->execute([$username]); $u = $stmt->fetch(PDO::FETCH_ASSOC); if (!$u || !password_verify($password, $u['password_hash'])) { $error = "بيانات الدخول غير صحيحة."; } else { $_SESSION['user_id'] = (int)$u['id']; $stmt2 = db()->prepare("UPDATE users SET last_login_at=?, ip=? WHERE id=?"); $stmt2->execute([now(), ip_address(), $u['id']]); header("Location: ".($_SERVER['PHP_SELF'])); exit; } } if (isset($_POST['action']) && $_POST['action']==='reset_password') { $username = trim($_POST['username'] ?? ''); $stmt = db()->prepare("SELECT * FROM users WHERE username=? OR email=?"); $stmt->execute([$username,$username]); $u = $stmt->fetch(PDO::FETCH_ASSOC); if (!$u) { $error = "لم يتم العثور على حساب بهذا المعرف."; } else { $new = rand_string(10); $stmt2 = db()->prepare("UPDATE users SET password_hash=? WHERE id=?"); $stmt2->execute([password_hash($new, PASSWORD_DEFAULT), $u['id']]); $reset_success = "تمت إعادة تعيين كلمة السر. كلمة السر الجديدة: <code>".h($new)."</code>"; // إشعار $nid = add_notification("تمت إعادة تعيين كلمة المرور لحسابك."); add_notification_recipient($nid, $u['id']); } } if (isset($_POST['action']) && $_POST['action']==='logout') { session_destroy(); header("Location: ".($_SERVER['PHP_SELF'])); exit; } /* =============== UTIL: Notifications & Chat helpers =============== */ function add_notification($message){ $stmt = db()->prepare("INSERT INTO notifications (message,created_at) VALUES(?,?)"); $stmt->execute([$message, now()]); return (int)db()->lastInsertId(); } function add_notification_recipient($notification_id, $user_id){ $stmt = db()->prepare("INSERT INTO notification_recipients (notification_id,user_id,is_read) VALUES (?,?,0)"); $stmt->execute([$notification_id,$user_id]); } function broadcast_notification($message){ $pdo = db(); $pdo->beginTransaction(); try { $nid = add_notification($message); $user_ids = $pdo->query("SELECT id FROM users")->fetchAll(PDO::FETCH_COLUMN); $ins = $pdo->prepare("INSERT INTO notification_recipients (notification_id,user_id,is_read) VALUES (?,?,0)"); foreach ($user_ids as $uid) $ins->execute([$nid,$uid]); $pdo->commit(); return $nid; } catch (Exception $e) { $pdo->rollBack(); return null; } } /* =============== ADS: positions + render (NEW) =============== */ // مواضع الإعلانات المعتمدة $AD_POS = [ 'top_banner' => 'بنر أعلى الموقع', 'under_generator' => 'أسفل قسم التوليد', 'gallery_top' => 'أعلى المعرض', 'articles_top' => 'أعلى صفحة المقالات', 'articles_bottom' => 'أسفل صفحة المقالات', 'global_footer' => 'أسفل الموقع' ]; // دالة عرض الإعلانات لموضع محدد function render_ads($slot){ $stmt = db()->prepare("SELECT title, code FROM ads WHERE is_active=1 AND position=? ORDER BY priority ASC, id ASC"); $stmt->execute([$slot]); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); if (!$rows) return; echo '<div class="ad-stack">'; foreach ($rows as $r){ // عرض الكود كما هو (قد يحتوي سكربت/iframe) echo '<div class="ad-box" data-slot="'.h($slot).'" title="'.h($r['title']).'">'.$r['code'].'</div>'; } echo '</div>'; } /* ====================== AJAX API ====================== */ if (isset($_GET['ajax'])) { header('Content-Type: application/json; charset=utf-8'); $action = $_GET['ajax']; if ($action==='poll') { require_login_json(); $u = current_user(); // unread notifications $stmt = db()->prepare("SELECT COUNT(*) FROM notification_recipients WHERE user_id=? AND is_read=0"); $stmt->execute([$u['id']]); $unread = (int)$stmt->fetchColumn(); $stmt = db()->prepare(" SELECT n.id, n.message, n.created_at, nr.is_read FROM notifications n JOIN notification_recipients nr ON nr.notification_id=n.id WHERE nr.user_id=? ORDER BY n.id DESC LIMIT 10 "); $stmt->execute([$u['id']]); $notifs = $stmt->fetchAll(PDO::FETCH_ASSOC); // recent images $stmt = db()->prepare("SELECT id,path,created_at,prompt,width,height FROM images WHERE user_id=? ORDER BY id DESC LIMIT 10"); $stmt->execute([$u['id']]); $history = $stmt->fetchAll(PDO::FETCH_ASSOC); echo json_encode([ 'ok'=>true, 'points'=>(int)$u['points'], 'status'=>$u['status'], 'plan'=>$u['plan'], 'unread_notifications'=>$unread, 'notifications'=>$notifs, 'history'=>$history ]); exit; } if ($action==='mark_notifs_read') { require_login_json(); $u = current_user(); $stmt = db()->prepare("UPDATE notification_recipients SET is_read=1 WHERE user_id=?"); $stmt->execute([$u['id']]); echo json_encode(['ok'=>true]); exit; } if ($action==='save_image') { require_login_json(); $u = current_user(); $data = json_decode(file_get_contents('php://input'), true); if (!$data || empty($data['b64'])) { echo json_encode(['ok'=>false,'error'=>'no_data']); exit; } $b64 = $data['b64']; $prompt = trim($data['prompt'] ?? ''); $w = (int)($data['width'] ?? 0); $h = (int)($data['height'] ?? 0); $bin = base64_decode($b64); if ($bin===false) { echo json_encode(['ok'=>false,'error'=>'decode_failed']); exit; } $fname = 'img_'.time().'_'.bin2hex(random_bytes(4)).'.png'; $fpath = IMG_DIR . '/' . $fname; if (file_put_contents($fpath, $bin) === false) { echo json_encode(['ok'=>false,'error'=>'write_failed']); exit; } @chmod($fpath, 0777); $rel = 'generated_images/'.$fname; $stmt = db()->prepare("INSERT INTO images (user_id,path,prompt,width,height,is_admin_gallery,is_public,created_at) VALUES (?,?,?,?,?,?,?,?)"); $stmt->execute([$u['id'],$rel,$prompt,$w,$h,0,1,now()]); echo json_encode(['ok'=>true,'path'=>$rel]); exit; } if ($action==='get_chat') { require_login_json(); $u = current_user(); $admin_id = first_admin_id(); $peer = ($u['is_admin'] ? (int)($_GET['user_id'] ?? 0) : $admin_id); if (!$peer) $peer = $admin_id; $stmt = db()->prepare(" SELECT * FROM support_messages WHERE (from_user_id=? AND to_user_id=?) OR (from_user_id=? AND to_user_id=?) ORDER BY id ASC LIMIT 200 "); $stmt->execute([$u['id'],$peer,$peer,$u['id']]); echo json_encode(['ok'=>true,'peer'=>$peer,'messages'=>$stmt->fetchAll(PDO::FETCH_ASSOC)]); exit; } if ($action==='send_chat') { require_login_json(); $u = current_user(); $data = json_decode(file_get_contents('php://input'), true); $to = (int)($data['to'] ?? 0); if (!$to) $to = first_admin_id(); $msg = trim($data['message'] ?? ''); if ($msg===''){ echo json_encode(['ok'=>false,'error'=>'empty']); exit; } $stmt = db()->prepare("INSERT INTO support_messages (from_user_id,to_user_id,message,created_at) VALUES (?,?,?,?)"); $stmt->execute([$u['id'],$to,$msg,now()]); echo json_encode(['ok'=>true]); exit; } // Admin: users if ($action==='admin_user_action') { require_login_json(); $u=current_user(); if(!$u['is_admin']){ http_response_code(403); echo json_encode(['ok'=>false]); exit; } $data = json_decode(file_get_contents('php://input'), true); $user_id = (int)$data['user_id']; $op = $data['op'] ?? ''; if ($op==='suspend') { $stmt = db()->prepare("UPDATE users SET status='suspended' WHERE id=?"); $stmt->execute([$user_id]); } elseif ($op==='activate') { $stmt = db()->prepare("UPDATE users SET status='active' WHERE id=?"); $stmt->execute([$user_id]); } elseif ($op==='set_points') { $pts = (int)($data['points'] ?? 0); $stmt = db()->prepare("UPDATE users SET points=? WHERE id=?"); $stmt->execute([$pts,$user_id]); } echo json_encode(['ok'=>true]); exit; } if ($action==='admin_send_notification') { require_login_json(); $u=current_user(); if(!$u['is_admin']){ http_response_code(403); echo json_encode(['ok'=>false]); exit; } $data = json_decode(file_get_contents('php://input'), true); $msg = trim($data['message'] ?? ''); $target = $data['target'] ?? 'all'; // 'all' أو user_id if ($msg===''){ echo json_encode(['ok'=>false,'error'=>'empty']); exit; } if ($target==='all') broadcast_notification($msg); else { $nid = add_notification($msg); add_notification_recipient($nid, (int)$target); } echo json_encode(['ok'=>true]); exit; } if ($action==='admin_article') { require_login_json(); $u=current_user(); if(!$u['is_admin']){ http_response_code(403); echo json_encode(['ok'=>false]); exit; } $data = json_decode(file_get_contents('php://input'), true); $op = $data['op'] ?? ''; if ($op==='create') { $t = trim($data['title'] ?? 'بدون عنوان'); $c = trim($data['content'] ?? ''); $stmt = db()->prepare("INSERT INTO articles (title,content,is_published,created_at,updated_at) VALUES (?,?,?,?,?)"); $stmt->execute([$t,$c,0,now(),now()]); echo json_encode(['ok'=>true]); exit; } elseif ($op==='update') { $id=(int)$data['id']; $t=trim($data['title']??''); $c=trim($data['content']??''); $p=(int)($data['is_published']??0); $stmt = db()->prepare("UPDATE articles SET title=?, content=?, is_published=?, updated_at=? WHERE id=?"); $stmt->execute([$t,$c,$p,now(),$id]); echo json_encode(['ok'=>true]); exit; } elseif ($op==='delete') { $id=(int)$data['id']; $stmt=db()->prepare("DELETE FROM articles WHERE id=?"); $stmt->execute([$id]); echo json_encode(['ok'=>true]); exit; } } if ($action==='admin_payment') { require_login_json(); $u=current_user(); if(!$u['is_admin']){ http_response_code(403); echo json_encode(['ok'=>false]); exit; } $data=json_decode(file_get_contents('php://input'), true); $id=(int)$data['id']; $status=$data['status'] ?? 'approved'; $stmt = db()->prepare("UPDATE payments SET status=? WHERE id=?"); $stmt->execute([$status,$id]); if ($status==='approved') { $row = db()->prepare("SELECT user_id,plan FROM payments WHERE id=?"); $row->execute([$id]); $p = $row->fetch(PDO::FETCH_ASSOC); if ($p) { db()->prepare("UPDATE users SET plan=? WHERE id=?")->execute([$p['plan'],$p['user_id']]); $nid = add_notification("تمت الموافقة على دفعتك وترقية خطتك إلى: ".$p['plan']); add_notification_recipient($nid, $p['user_id']); } } echo json_encode(['ok'=>true]); exit; } if ($action==='admin_toggle_admin_gallery') { require_login_json(); $u=current_user(); if(!$u['is_admin']){ http_response_code(403); echo json_encode(['ok'=>false]); exit; } $img=(int)($_GET['id']??0); $flag=(int)($_GET['flag']??0); db()->prepare("UPDATE images SET is_admin_gallery=? WHERE id=?")->execute([$flag,$img]); echo json_encode(['ok'=>true]); exit; } if ($action==='admin_update_defaults') { require_login_json(); $u=current_user(); if(!$u['is_admin']){ http_response_code(403); echo json_encode(['ok'=>false]); exit; } $data=json_decode(file_get_contents('php://input'),true); $def=intval($data['default_points']??50); set_setting('default_points', (string)$def); echo json_encode(['ok'=>true]); exit; } // ====== Admin Ads CRUD (NEW) if ($action==='admin_ads') { require_login_json(); $u=current_user(); if(!$u['is_admin']){ http_response_code(403); echo json_encode(['ok'=>false]); exit; } $data = json_decode(file_get_contents('php://input'), true); $op = $data['op'] ?? ''; if ($op==='create') { $title = trim($data['title'] ?? ''); $network = trim($data['network'] ?? ''); $position = trim($data['position'] ?? 'top_banner'); $priority = (int)($data['priority'] ?? 0); $code = $data['code'] ?? ''; if ($title==='' || $code===''){ echo json_encode(['ok'=>false,'error'=>'missing']); exit; } $stmt = db()->prepare("INSERT INTO ads (title,network,code,position,is_active,priority,created_at) VALUES (?,?,?,?,1,?,?)"); $stmt->execute([$title,$network,$code,$position,$priority,now()]); echo json_encode(['ok'=>true]); exit; } elseif ($op==='update') { $id=(int)($data['id'] ?? 0); if(!$id){ echo json_encode(['ok'=>false]); exit; } $title = trim($data['title'] ?? ''); $network = trim($data['network'] ?? ''); $position = trim($data['position'] ?? 'top_banner'); $priority = (int)($data['priority'] ?? 0); $is_active = (int)($data['is_active'] ?? 1); if (array_key_exists('code',$data) && $data['code']!==null) { $code = $data['code']; $stmt = db()->prepare("UPDATE ads SET title=?, network=?, code=?, position=?, is_active=?, priority=? WHERE id=?"); $stmt->execute([$title,$network,$code,$position,$is_active,$priority,$id]); echo json_encode(['ok'=>true,'reload'=>false]); exit; } else { $stmt = db()->prepare("UPDATE ads SET title=?, network=?, position=?, is_active=?, priority=? WHERE id=?"); $stmt->execute([$title,$network,$position,$is_active,$priority,$id]); echo json_encode(['ok'=>true,'reload'=>false]); exit; } } elseif ($op==='delete') { $id=(int)($data['id'] ?? 0); if(!$id){ echo json_encode(['ok'=>false]); exit; } db()->prepare("DELETE FROM ads WHERE id=?")->execute([$id]); echo json_encode(['ok'=>true]); exit; } echo json_encode(['ok'=>false,'error'=>'unknown_op']); exit; } echo json_encode(['ok'=>false,'error'=>'unknown_action']); exit; } /* ====================== PAGE (HTML) ====================== */ $me = current_user(); ?> <!DOCTYPE html> <html lang="ar" dir="rtl"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>مولّد الصور - لوحة شاملة (ملف واحد)</title> <style> :root{ --bg:#0b0f1a; --card:#121827cc; --muted:#9aa4b2; --accent:#8b5cf6; --accent2:#06b6d4; --good:#22c55e; --bad:#ef4444; } *{box-sizing:border-box} body{ margin:0; font-family:system-ui,-apple-system,Segoe UI,Roboto; color:#e5e7eb; background: radial-gradient(1000px 500px at 10% -10%, #1b2555 0%, transparent 60%), radial-gradient(1000px 500px at 90% 0%, #0f766e55 0%, transparent 60%), var(--bg); min-height:100vh; } header{ position:sticky; top:0; z-index:100; backdrop-filter: saturate(150%) blur(10px); background:linear-gradient(90deg,#0b0f1acc,#0b0f1a99); border-bottom:1px solid #1f2937; padding:12px 16px; display:flex; gap:12px; align-items:center; justify-content:space-between; } .brand{display:flex; align-items:center; gap:10px; font-weight:700; letter-spacing:.3px} .brand .dot{width:10px;height:10px;border-radius:50%;background:linear-gradient(45deg,var(--accent),var(--accent2)); box-shadow:0 0 12px var(--accent)} .pill{padding:6px 10px; border:1px solid #243041; border-radius:999px; background:#0b1220; color:#cbd5e1; font-size:13px} .btn{ border:0; background:linear-gradient(135deg,var(--accent),var(--accent2)); color:#fff; padding:10px 14px; border-radius:10px; cursor:pointer; font-weight:600; transition:transform .15s ease, opacity .15s ease; } .btn:disabled{opacity:.6; cursor:default} .btn.ghost{background:transparent; border:1px solid #334155; color:#e2e8f0} .btn.warn{background:linear-gradient(135deg,#ef4444,#f97316)} .grid{display:grid; gap:16px} .two{grid-template-columns:repeat(2,minmax(0,1fr))} .three{grid-template-columns:repeat(3,minmax(0,1fr))} @media(max-width:1000px){ .two,.three{grid-template-columns:1fr} } .card{background:var(--card); border:1px solid #1f2937; border-radius:16px; padding:16px; box-shadow:0 10px 30px #0005} h1,h2,h3{margin:6px 0 12px} small, .muted{color:var(--muted)} input,select,textarea{ width:100%; padding:10px 12px; background:#0b1220; border:1px solid #22304a; color:#e5e7eb; border-radius:10px; outline:none; font-size:14px } label{font-size:13px; color:#9fb0c3} .row{display:flex; gap:10px; align-items:center} .row.wrap{flex-wrap:wrap} .tabs{display:flex; gap:8px; flex-wrap:wrap} .tab{padding:8px 12px; border:1px solid #22304a; border-radius:999px; cursor:pointer; background:#0b1220} .tab.active{background:linear-gradient(135deg,#111827,#0b1220); border-color:#31415f} .gallery{display:grid; grid-template-columns:repeat(auto-fill,minmax(160px,1fr)); gap:10px} .gallery img{width:100%; border-radius:12px; display:block; border:1px solid #1f2937} .chip{display:inline-block; padding:2px 8px; border-radius:999px; border:1px solid #233147; font-size:12px; color:#a9b8cc} .table{width:100%; border-collapse:collapse; font-size:14px} .table th,.table td{border-bottom:1px solid #223047; padding:8px} .status.active{color:var(--good)} .status.suspended{color:var(--bad)} .kbd{background:#111827; border:1px solid #223047; padding:2px 6px; border-radius:6px; font-family:ui-monospace, SFMono-Regular, Menlo, monospace; font-size:12px} .note{background:#0b1220; border:1px dashed #233147; padding:10px; border-radius:10px} a{color:#93c5fd; text-decoration:none} /* NEW: Ads */ .ad-stack{ display:grid; gap:10px; margin:8px 0 } .ad-box{ background:#0b1220; border:1px dashed #334155; border-radius:12px; padding:8px; overflow:hidden; } .ad-box:has(iframe), .ad-box:has(script){ border-style:solid; } </style> </head> <body> <header> <div class="brand"> <div class="dot"></div> <div>مولّد الصور</div> <span class="pill">ملف واحد</span> </div> <div class="row wrap"> <?php if ($me): ?> <span class="pill">الحساب: <b><?=h($me['username'])?></b> <span class="muted">[IP: <?=h($me['ip'])?>]</span></span> <span class="pill">الخطة: <b id="planLabel"><?=h($me['plan'])?></b></span> <span class="pill">نقاطك: <b id="pointsLabel"><?= (int)$me['points'] ?></b></span> <span class="pill">الحالة: <b id="statusLabel" class="status <?=h($me['status'])?>"><?=h($me['status'])?></b></span> <form method="post" style="margin:0"> <input type="hidden" name="action" value="logout"> <button class="btn ghost">تسجيل الخروج</button> </form> <?php else: ?> <span class="pill">غير مسجل دخول</span> <?php endif; ?> </div> </header> <!-- NEW: Ad slot right under header --> <?php render_ads('top_banner'); ?> <main style="padding:20px; max-width:1200px; margin:0 auto"> <?php if (!$me): ?> <div class="grid two"> <div class="card"> <h2>تسجيل الدخول</h2> <?php if (!empty($error)) echo '<div class="note" style="color:#fecaca">'. $error .'</div>'; ?> <?php if (!empty($reset_success)) echo '<div class="note" style="color:#bbf7d0">'. $reset_success .'</div>'; ?> <form method="post" class="grid"> <input type="hidden" name="action" value="login"> <div> <label>اسم المستخدم</label> <input name="username" required> </div> <div> <label>كلمة المرور</label> <input name="password" type="password" required> </div> <button class="btn">دخول</button> </form> <details style="margin-top:10px"> <summary class="muted">نسيت كلمة السر؟</summary> <form method="post" class="grid" style="margin-top:10px"> <input type="hidden" name="action" value="reset_password"> <label>اكتب اسم المستخدم أو البريد لحسابك</label> <input name="username" required> <button class="btn">إعادة تعيين تلقائي</button> </form> </details> <div class="muted" style="margin-top:10px">أول حساب يتم إنشاؤه يصبح <b>أدمن</b> تلقائيًا.</div> </div> <div class="card"> <h2>إنشاء حساب</h2> <form method="post" class="grid"> <input type="hidden" name="action" value="register"> <div class="row"> <div style="flex:1"> <label>اسم المستخدم</label> <input name="username" required> </div> <div style="flex:1"> <label>البريد (اختياري)</label> <input name="email" type="email"> </div> </div> <div> <label>كلمة المرور</label> <input name="password" type="password" required> </div> <button class="btn">تسجيل</button> </form> <div class="note" style="margin-top:10px"> سيتم إضافة نقاط افتراضية لكل حساب جديد (القيمة يحددها الأدمن). لا حاجة لتأكيد البريد. </div> </div> </div> <?php else: ?> <!-- Tabs --> <div class="tabs" id="tabs"> <div class="tab active" data-tab="gen">توليد الصور</div> <div class="tab" data-tab="gallery">المعرض</div> <div class="tab" data-tab="articles">المقالات</div> <div class="tab" data-tab="support">الدعم المباشر</div> <div class="tab" data-tab="notifications">الإشعارات</div> <div class="tab" data-tab="plans">الباقات والدفع</div> <?php if ($me['is_admin']): ?> <div class="tab" data-tab="admin">لوحة الأدمن</div> <?php endif; ?> </div> <!-- Generator --> <section id="tab-gen" class="card" style="margin-top:12px"> <h2>توليد الصور</h2> <div class="grid two"> <div> <label>الوصف (Prompt)</label> <textarea id="prompt" rows="4" placeholder="صف الصورة بدقة..."></textarea> </div> <div> <label>الحجم</label> <select id="size" onchange="toggleCustomSize(this.value)"> <option value="512x512">512x512</option> <option value="768x768">768x768</option> <option value="1024x1024">1024x1024</option> <option value="custom">مخصص</option> </select> <div id="customSizeInputs" style="display:none; margin-top:8px" class="row"> <input id="customWidth" type="number" placeholder="العرض px" value="512" style="flex:1"> <input id="customHeight" type="number" placeholder="الارتفاع px" value="512" style="flex:1"> </div> <div class="row" style="margin-top:10px"> <button class="btn" onclick="generateImage()">توليد الآن</button> <span id="genInfo" class="muted"></span> </div> </div> </div> <div id="result" style="margin-top:12px" class="note"></div> <details style="margin-top:16px"> <summary class="muted">🧠 ملاحظة</summary> <div class="muted">بعد التوليد، يتم حفظ الصورة تلقائيًا في <span class="kbd">generated_images/</span> وتظهر في سجلّك وفي معرض المستخدم.</div> </details> <!-- NEW: Ad slot under generator --> <?php render_ads('under_generator'); ?> </section> <!-- Gallery --> <section id="tab-gallery" class="card" style="display:none; margin-top:12px"> <h2>المعرض</h2> <?php render_ads('gallery_top'); ?> <div class="grid two"> <div> <h3>معرض المستخدم</h3> <div id="userGallery" class="gallery"></div> </div> <div> <h3>معرض الأدمن</h3> <div class="muted">صور مختارة من قبل فريق الإدارة.</div> <div class="gallery"> <?php $imgs = db()->query("SELECT path FROM images WHERE is_admin_gallery=1 ORDER BY id DESC LIMIT 60")->fetchAll(PDO::FETCH_COLUMN); if ($imgs) foreach ($imgs as $p) echo '<a href="'.h($p).'" target="_blank"><img src="'.h($p).'" alt=""></a>'; else echo '<div class="muted">لا توجد صور في معرض الأدمن بعد.</div>'; ?> </div> </div> </div> </section> <!-- Articles --> <section id="tab-articles" class="card" style="display:none; margin-top:12px"> <h2>المقالات</h2> <?php render_ads('articles_top'); ?> <div class="grid"> <?php $arts = db()->query("SELECT * FROM articles WHERE is_published=1 ORDER BY id DESC")->fetchAll(PDO::FETCH_ASSOC); if (!$arts) echo '<div class="muted">لا توجد مقالات منشورة بعد.</div>'; foreach ($arts as $a){ echo '<div class="note"><h3>'.h($a['title']).'</h3><div>'.nl2br(h($a['content'])).'</div><div class="muted" style="margin-top:6px">نُشرت: '.h($a['created_at']).'</div></div>'; } ?> </div> <?php render_ads('articles_bottom'); ?> </section> <!-- Support Chat --> <section id="tab-support" class="card" style="display:none; margin-top:12px"> <h2>الدعم المباشر</h2> <div id="chatBox" style="height:260px; overflow:auto; border:1px solid #223047; border-radius:12px; padding:10px; background:#0b1220"></div> <div class="row" style="margin-top:8px"> <input id="chatInput" placeholder="اكتب رسالتك..."> <button class="btn" onclick="sendChat()">إرسال</button> </div> </section> <!-- Notifications --> <section id="tab-notifications" class="card" style="display:none; margin-top:12px"> <h2>الإشعارات</h2> <div class="row"> <button class="btn ghost" onclick="markAllRead()">اعتبار الكل مقروءًا</button> <span class="chip">غير المقروء: <b id="unreadCount">0</b></span> </div> <div id="notifList" class="grid" style="margin-top:10px"></div> </section> <!-- Plans & Payment --> <section id="tab-plans" class="card" style="display:none; margin-top:12px"> <h2>الباقات والدفع</h2> <div class="grid three"> <div class="note"> <h3>مجانية</h3> <div>خطة البداية - مناسبة للتجربة.</div> <div class="chip">free</div> </div> <div class="note"> <h3>Plus</h3> <div>سرعات وأولوية أعلى.</div> <div class="chip">plus</div> </div> <div class="note"> <h3>Pro</h3> <div>للاستخدام المكثف والفرق.</div> <div class="chip">pro</div> </div> </div> <div style="margin-top:10px"> <h3>الدفع عبر Payeer</h3> <div class="muted">المحفظة: <span class="kbd">P1028352381</span></div> <div class="note" style="margin-top:6px"> بعد التحويل، أرسل رقم العملية (Transaction ID) ليتم التأكيد يدويًا من قبل الأدمن. </div> <form method="post" onsubmit="submitTX(event)" class="grid two" style="margin-top:8px"> <div> <label>اختر الباقة</label> <select id="planSel"> <option value="plus">Plus</option> <option value="pro">Pro</option> </select> </div> <div> <label>Transaction ID</label> <input id="txId" required> </div> <button class="btn">إرسال للتأكيد</button> </form> <div id="txStatus" class="muted" style="margin-top:8px"></div> <h3 style="margin-top:20px">طلباتك</h3> <table class="table"> <thead><tr><th>التاريخ</th><th>الباقة</th><th>TX</th><th>الحالة</th></tr></thead> <tbody> <?php $rows = db()->prepare("SELECT * FROM payments WHERE user_id=? ORDER BY id DESC"); $rows->execute([$me['id']]); $rows=$rows->fetchAll(PDO::FETCH_ASSOC); if (!$rows) echo '<tr><td colspan="4" class="muted">لا توجد طلبات.</td></tr>'; foreach ($rows as $r) echo '<tr><td>'.h($r['created_at']).'</td><td>'.h($r['plan']).'</td><td>'.h($r['tx_id']).'</td><td>'.h($r['status']).'</td></tr>'; ?> </tbody> </table> </div> </section> <!-- Admin Panel --> <?php if ($me['is_admin']): ?> <section id="tab-admin" class="card" style="display:none; margin-top:12px"> <h2>لوحة تحكم الأدمن</h2> <div class="grid two"> <div class="note"> <h3>إعدادات عامة</h3> <label>النقاط الافتراضية لكل مستخدم جديد</label> <div class="row"> <input id="defaultPoints" type="number" value="<?= (int)setting('default_points','50') ?>" style="max-width:150px"> <button class="btn" onclick="updateDefaults()">حفظ</button> </div> <details style="margin-top:10px"> <summary>إشعارات جاهزة</summary> <div class="muted">قم باختيار نص جاهز للإرسال السريع.</div> <div class="grid" id="readyNotifs" style="margin-top:6px"></div> </details> </div> <div class="note"> <h3>إرسال إشعار</h3> <label>الرسالة</label> <textarea id="admNotif" rows="3"></textarea> <div class="row" style="margin-top:8px"> <button class="btn" onclick="sendAdminNotif('all')">إرسال للجميع</button> <input id="toUserId" type="number" placeholder="User ID (اختياري)"> <button class="btn ghost" onclick="sendAdminNotif('one')">إرسال لمستخدم</button> </div> </div> </div> <div class="grid two" style="margin-top:12px"> <div class="note"> <h3>مراقبة المستخدمين</h3> <table class="table"> <thead><tr><th>ID</th><th>اسم</th><th>IP</th><th>نقاط</th><th>حالة</th><th>خطة</th><th>تحكم</th></tr></thead> <tbody> <?php $users = db()->query("SELECT id,username,ip,points,status,plan FROM users ORDER BY id DESC")->fetchAll(PDO::FETCH_ASSOC); foreach ($users as $u) { echo '<tr> <td>'.$u['id'].'</td> <td>'.h($u['username']).'</td> <td class="muted">'.h($u['ip']).'</td> <td><input type="number" id="pts'.$u['id'].'" value="'.(int)$u['points'].'" style="width:90px"></td> <td><span class="status '.$u['status'].'">'.h($u['status']).'</span></td> <td>'.h($u['plan']).'</td> <td class="row"> <button class="btn ghost" onclick="setPoints('.$u['id'].')">تعديل النقاط</button> <button class="btn '.($u['status']=='active'?'warn':'').'" onclick="toggleSuspend('.$u['id'].',\''.($u['status']=='active'?'suspend':'activate').'\')">'.($u['status']=='active'?'تعليق':'تنشيط').'</button> </td> </tr>'; } ?> </tbody> </table> </div> <div class="note"> <h3>إدارة المدفوعات</h3> <table class="table"> <thead><tr><th>ID</th><th>User</th><th>Plan</th><th>TX</th><th>تاريخ</th><th>حالة</th><th>إجراء</th></tr></thead> <tbody> <?php $pay = db()->query("SELECT p.*, u.username FROM payments p JOIN users u ON u.id=p.user_id ORDER BY p.id DESC")->fetchAll(PDO::FETCH_ASSOC); if (!$pay) echo '<tr><td colspan="7" class="muted">لا توجد طلبات.</td></tr>'; foreach ($pay as $p) { echo '<tr> <td>'.$p['id'].'</td> <td>'.h($p['username']).'</td> <td>'.h($p['plan']).'</td> <td>'.h($p['tx_id']).'</td> <td>'.h($p['created_at']).'</td> <td>'.h($p['status']).'</td> <td class="row"> <button class="btn" onclick="approvePay('.$p['id'].')">موافقة</button> <button class="btn warn" onclick="rejectPay('.$p['id'].')">رفض</button> </td> </tr>'; } ?> </tbody> </table> </div> </div> <div class="grid two" style="margin-top:12px"> <div class="note"> <h3>المقالات</h3> <div class="row"> <input id="artTitle" placeholder="العنوان"> <button class="btn" onclick="createArticle()">إضافة</button> </div> <textarea id="artContent" rows="6" placeholder="المحتوى..."></textarea> </div> <div class="note"> <h3>تحرير/نشر المقالات</h3> <table class="table"> <thead><tr><th>ID</th><th>العنوان</th><th>منشور؟</th><th>تحكم</th></tr></thead> <tbody> <?php $arts = db()->query("SELECT * FROM articles ORDER BY id DESC")->fetchAll(PDO::FETCH_ASSOC); if (!$arts) echo '<tr><td colspan="4" class="muted">لا توجد مقالات بعد.</td></tr>'; foreach ($arts as $a){ echo '<tr> <td>'.$a['id'].'</td> <td><input id="t'.$a['id'].'" value="'.h($a['title']).'" style="width:100%"></td> <td><select id="p'.$a['id'].'"><option value="0" '.(!$a['is_published']?'selected':'').'>لا</option><option value="1" '.($a['is_published']?'selected':'').'>نعم</option></select></td> <td class="row"> <button class="btn" onclick="updateArticle('.$a['id'].')">حفظ</button> <button class="btn warn" onclick="deleteArticle('.$a['id'].')">حذف</button> </td> </tr> <tr><td colspan="4"><textarea id="c'.$a['id'].'" rows="4" style="width:100%;">'.h($a['content']).'</textarea></td></tr>'; } ?> </tbody> </table> </div> </div> <!-- NEW: Ads Management --> <div class="note" style="margin-top:12px"> <h3>الإعلانات</h3> <h4>إضافة إعلان جديد</h4> <div class="grid two"> <div> <label>العنوان التعريفي</label> <input id="adTitle" placeholder="مثال: بنر جوجل - أعلى"> </div> <div> <label>الشبكة الإعلانية</label> <input id="adNetwork" placeholder="Google, Propeller, ..."> </div> </div> <div class="grid two" style="margin-top:8px"> <div> <label>الموضع</label> <select id="adPosition"> <?php foreach($AD_POS as $k=>$v) echo '<option value="'.h($k).'">'.h($v).'</option>'; ?> </select> </div> <div> <label>الأولوية (0 أولاً)</label> <input id="adPriority" type="number" value="0"> </div> </div> <div style="margin-top:8px"> <label>كود الإعلان (HTML/JS كما هو من الشبكة)</label> <textarea id="adCode" rows="5" placeholder="ألصق كود الإعلان من الشبكة هنا"></textarea> </div> <div class="row" style="margin-top:8px"> <button class="btn" onclick="createAd()">إضافة إعلان</button> </div> <h4 style="margin-top:16px">كل الإعلانات</h4> <table class="table"> <thead> <tr><th>ID</th><th>العنوان</th><th>الشبكة</th><th>الموضع</th><th>أولوية</th><th>نشط؟</th><th>تحكم</th></tr> </thead> <tbody> <?php $ads = db()->query("SELECT * FROM ads ORDER BY position ASC, priority ASC, id DESC")->fetchAll(PDO::FETCH_ASSOC); if (!$ads) echo '<tr><td colspan="7" class="muted">لا توجد إعلانات بعد.</td></tr>'; foreach ($ads as $a){ echo '<tr> <td>'.$a['id'].'</td> <td><input id="adt'.$a['id'].'" value="'.h($a['title']).'" style="width:140px"></td> <td><input id="adn'.$a['id'].'" value="'.h($a['network']).'" style="width:120px"></td> <td> <select id="adp'.$a['id'].'">'; foreach($AD_POS as $k=>$v){ $sel = ($a['position']===$k)?'selected':''; echo '<option value="'.h($k).'" '.$sel.'>'.h($v).'</option>'; } echo '</select> </td> <td><input id="adr'.$a['id'].'" type="number" value="'.(int)$a['priority'].'" style="width:80px"></td> <td> <select id="ada'.$a['id'].'"> <option value="1" '.($a['is_active']?'selected':'').'>نعم</option> <option value="0" '.(!$a['is_active']?'selected':'').'>لا</option> </select> </td> <td class="row"> <button class="btn" onclick="updateAd('.$a['id'].')">حفظ</button> <button class="btn ghost" onclick="editAdCode('.$a['id'].')">تحرير الكود</button> <button class="btn warn" onclick="deleteAd('.$a['id'].')">حذف</button> </td> </tr> <tr><td colspan="7"> <textarea id="adc'.$a['id'].'" rows="4" style="width:100%; display:none;">'.h($a['code']).'</textarea> </td></tr>'; } ?> </tbody> </table> <div class="muted" style="margin-top:6px"> ⚠️ تأكد من الثقة في أكواد الإعلانات (قد تحتوي سكربت). استخدم شبكات موثوقة فقط. </div> </div> </section> <?php endif; ?> <?php endif; // logged in ?> <!-- NEW: Global footer ad --> <?php render_ads('global_footer'); ?> </main> <script> // ====== تبويب بسيط document.querySelectorAll('.tab').forEach(t=>{ t.addEventListener('click', ()=>{ document.querySelectorAll('.tab').forEach(x=>x.classList.remove('active')); t.classList.add('active'); const id = t.dataset.tab; document.querySelectorAll('section[id^="tab-"]').forEach(s=>s.style.display='none'); document.getElementById('tab-'+id).style.display='block'; }); }); // ====== تحديث لحظي (AJAX Polling) let pollTimer=null; <?php if ($me): ?> function startPolling(){ if (pollTimer) clearInterval(pollTimer); const run = ()=>{ fetch('index.php?ajax=poll').then(r=>r.json()).then(j=>{ if(!j.ok) return; document.getElementById('pointsLabel').textContent = j.points; document.getElementById('statusLabel').textContent = j.status; document.getElementById('statusLabel').className = 'status '+j.status; document.getElementById('planLabel').textContent = j.plan; const unread = document.getElementById('unreadCount'); if (unread) unread.textContent = j.unread_notifications; const box = document.getElementById('notifList'); if (box) { box.innerHTML = ''; j.notifications.forEach(n=>{ const div = document.createElement('div'); div.className='note'; div.innerHTML = ``; box.appendChild(div); }); } const g=document.getElementById('userGallery'); if (g){ g.innerHTML=''; if (j.history.length===0) g.innerHTML='<div class="muted">لا يوجد سجل توليد بعد.</div>'; j.history.forEach(im=>{ const a=document.createElement('a'); a.href = im.path; a.target='_blank'; const img=new Image(); img.src=im.path; img.alt=im.prompt||''; a.appendChild(img); g.appendChild(a); }); } }).catch(()=>{}); }; run(); pollTimer = setInterval(run, 5000); } startPolling(); <?php endif; ?> // ====== إشعارات: تحديد كمقروء function markAllRead(){ fetch('index.php?ajax=mark_notifs_read').then(r=>r.json()).then(_=>startPolling()); } // ====== دعم مباشر let chatPeer = null; function scrollChat(){ const box=document.getElementById('chatBox'); box.scrollTop=box.scrollHeight; } function loadChat(){ fetch('index.php?ajax=get_chat'+(chatPeer?('&user_id='+chatPeer):'')).then(r=>r.json()).then(j=>{ if(!j.ok) return; chatPeer = j.peer; const box=document.getElementById('chatBox'); if(!box) return; box.innerHTML=''; j.messages.forEach(m=>{ const meId = <?= $me ? (int)$me['id'] : 0 ?>; const mine = (m.from_user_id==meId); const item = document.createElement('div'); item.style.margin='6px 0'; item.style.textAlign= mine ? 'left' : 'right'; item.innerHTML = ``; box.appendChild(item); }); scrollChat(); }); } function sendChat(){ const inp=document.getElementById('chatInput'); const msg=inp.value.trim(); if(!msg) return; fetch('index.php?ajax=send_chat',{method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({to:chatPeer,message:msg})}) .then(r=>r.json()).then(j=>{ if(j.ok){ inp.value=''; loadChat(); } }); } <?php if ($me): ?> setInterval(loadChat, 6000); loadChat(); <?php endif; ?> // ====== نظام الدفع: إرسال TX function submitTX(e){ e.preventDefault(); const plan=document.getElementById('planSel').value; const tx=document.getElementById('txId').value.trim(); if(!tx){ alert('أدخل رقم العملية'); return; } fetch('', {method:'POST', headers:{'Content-Type':'application/x-www-form-urlencoded'}, body:new URLSearchParams({ '__tx':'1','plan':plan,'tx':tx })}).then(()=>{ location.reload(); }); } // ====== Admin JS function toggleSuspend(uid,op){ fetch('index.php?ajax=admin_user_action',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({user_id:uid,op:op})}) .then(r=>r.json()).then(j=>{ if(j.ok){ startPolling(); location.reload(); }}); } function setPoints(uid){ const val = document.getElementById('pts'+uid).value; fetch('index.php?ajax=admin_user_action',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({user_id:uid,op:'set_points',points:val})}) .then(r=>r.json()).then(j=>{ if(j.ok){ startPolling(); }}); } function sendAdminNotif(mode){ const msg=document.getElementById('admNotif').value.trim(); if(!msg) return; const payload={message:msg, target:(mode==='all'?'all':(document.getElementById('toUserId').value||'all'))}; fetch('index.php?ajax=admin_send_notification',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(payload)}) .then(r=>r.json()).then(j=>{ if(j.ok){ alert('تم الإرسال'); document.getElementById('admNotif').value=''; } }); } function createArticle(){ const t=document.getElementById('artTitle').value.trim(); const c=document.getElementById('artContent').value.trim(); if(!t||!c) return alert('أدخل العنوان والمحتوى'); fetch('index.php?ajax=admin_article',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({op:'create',title:t,content:c})}) .then(()=>location.reload()); } function updateArticle(id){ const t=document.getElementById('t'+id).value; const c=document.getElementById('c'+id).value; const p=document.getElementById('p'+id).value; fetch('index.php?ajax=admin_article',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({op:'update',id:id,title:t,content:c,is_published:p})}) .then(()=>alert('تم الحفظ')); } function deleteArticle(id){ if(!confirm('حذف المقال؟')) return; fetch('index.php?ajax=admin_article',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({op:'delete',id:id})}) .then(()=>location.reload()); } function approvePay(id){ fetch('index.php?ajax=admin_payment',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({id:id,status:'approved'})}) .then(()=>location.reload()); } function rejectPay(id){ fetch('index.php?ajax=admin_payment',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({id:id,status:'rejected'})}) .then(()=>location.reload()); } function toggleAdminGallery(id,flag){ fetch('index.php?ajax=admin_toggle_admin_gallery&id='+id+'&flag='+flag) .then(()=>location.reload()); } function updateDefaults(){ const v=parseInt(document.getElementById('defaultPoints').value||'50',10); fetch('index.php?ajax=admin_update_defaults',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({default_points:v})}) .then(()=>alert('تم التحديث')); } (function initReadyNotifs(){ const wrap=document.getElementById('readyNotifs'); if(!wrap) return; const list="<?=h(setting('ready_notifications','مرحبا بك!|اختبار|نص جاهز'))?>".split('|'); list.forEach(txt=>{ const b=document.createElement('button'); b.className='btn ghost'; b.style.margin='4px'; b.textContent=txt; b.onclick=()=>{ document.getElementById('admNotif').value = txt; }; wrap.appendChild(b); }); })(); // ====== الإعلانات: CRUD (NEW) function createAd(){ const title = document.getElementById('adTitle').value.trim(); const network = document.getElementById('adNetwork').value.trim(); const position = document.getElementById('adPosition').value; const priority = parseInt(document.getElementById('adPriority').value||'0',10); const code = document.getElementById('adCode').value; if(!title || !code){ alert('أدخل العنوان والكود'); return; } fetch('index.php?ajax=admin_ads', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({op:'create', title, network, position, priority, code}) }).then(r=>r.json()).then(j=>{ if(j.ok){ location.reload(); } else { alert('فشل الإضافة'); } }); } function updateAd(id){ const title = document.getElementById('adt'+id).value.trim(); const network = document.getElementById('adn'+id).value.trim(); const position = document.getElementById('adp'+id).value; const priority = parseInt(document.getElementById('adr'+id).value||'0',10); const is_active = parseInt(document.getElementById('ada'+id).value||'1',10); const codeT = document.getElementById('adc'+id); const code = (codeT.style.display==='none') ? null : codeT.value; fetch('index.php?ajax=admin_ads', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({op:'update', id, title, network, position, priority, is_active, code}) }).then(r=>r.json()).then(j=>{ if(j.ok){ alert('تم الحفظ'); if(j.reload) location.reload(); } else { alert('فشل التحديث'); } }); } function deleteAd(id){ if(!confirm('حذف الإعلان نهائيًا؟')) return; fetch('index.php?ajax=admin_ads', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({op:'delete', id}) }).then(r=>r.json()).then(j=>{ if(j.ok){ location.reload(); } else { alert('فشل الحذف'); } }); } function editAdCode(id){ const ta = document.getElementById('adc'+id); ta.style.display = (ta.style.display==='none' ? 'block' : 'none'); } // ====== تضمين كود الاستدعاء الأساسي (مع حفظ تلقائي) function toggleCustomSize(value) { const customDiv = document.getElementById("customSizeInputs"); customDiv.style.display = value === "custom" ? "block" : "none"; } async function generateImage() { const prompt = document.getElementById("prompt").value; const size = document.getElementById("size").value; let width, height; if (size === "custom") { width = parseInt(document.getElementById("customWidth").value) || 512; height = parseInt(document.getElementById("customHeight").value) || 512; } else { const parts = size.split("x"); width = parseInt(parts[0]); height = parseInt(parts[1]); } document.getElementById("result").innerHTML = "<p>⏳ جاري التوليد...</p>"; try { const response = await fetch("https://47zg9vbcvs.adaptive.ai/api/generate", { method: "POST", headers: { "Content-Type": "application/json", "Accept": "*/*" }, body: JSON.stringify({ model: "black-forest-labs/flux-schnell", prompt: prompt, response_format: "b64_json", response_extension: "png", width: width, height: height, num_inference_steps: 4, negative_prompt: "", seed: -1 }) }); const data = await response.json(); console.log("API Response:", data); if (data && data.data && data.data[0] && data.data[0].b64_json) { const base64 = data.data[0].b64_json; const imgUrl = "data:image/png;base64," + base64; document.getElementById("result").innerHTML = ` <h3>✅ النتيجة:</h3> <img src="${imgUrl}" alt="Generated Image"> <br><a href="${imgUrl}" download="generated.png">⬇️ تحميل الصورة</a> `; // حفظ تلقائي في السيرفر saveImageToServer(base64, prompt, width, height).then(()=>startPolling()); } else { document.getElementById("result").innerHTML = "<p>⚠️ لم يتم العثور على بيانات صورة في الرد.</p>"; } } catch (error) { document.getElementById("result").innerHTML = "<p>❌ خطأ: " + error.message + "</p>"; } } async function saveImageToServer(base64, prompt, width, height){ try{ const r = await fetch('index.php?ajax=save_image', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({b64: base64, prompt: prompt, width: width, height: height}) }); const j = await r.json(); if(!j.ok){ console.warn('لم يتم الحفظ:', j); } }catch(e){ console.warn('حفظ فشل', e); } } // ====== أدوات مساعدة function escapeHtml(str){ return (str||'').replace(/[&<>"']/g, m=>({ '&':'&','<':'<','>':'>','"':'"',"'":''' }[m])); } // ====== إدراج دفع (POST عادي) <?php if ($me && isset($_POST['__tx'])): $plan = $_POST['plan'] ?? 'plus'; $tx = trim($_POST['tx'] ?? ''); if ($tx !== '') { $stmt = db()->prepare("INSERT INTO payments (user_id,plan,tx_id,status,created_at) VALUES (?,?,?,?,?)"); $stmt->execute([$me['id'],$plan,$tx,'pending',now()]); $nid = add_notification("تم استلام طلب الدفع الخاص بك. سيتم المراجعة يدويًا قريبًا."); add_notification_recipient($nid, $me['id']); } endif; ?> </script> </body> </html>
لو حابب أعدّل الأسماء العربية للمواضع أو أضيف مواضع جديدة داخل الصفحة، قلّي وين تفضّل أحطها وأنا أعدلها لك فورًا. ✅