قم بإنشاء مشروع متكامل في ملف واحد فقط باسم index....

Создано: 10 сентября 2025 г.

Отвечено с использованием GPT-5 от Chat01

Вопрос

قم بإنشاء مشروع متكامل في ملف واحد فقط باسم index.php يحتوي بداخله على HTML و CSS و JavaScript و PHP لتسهيل النشر على استضافة مجانية مثل InfinityFree.
المشروع يجب أن يتضمن:

  1. الواجهة الأمامية

واجهة جذابة واحترافية بأسلوب عصري (مثل Sora أو Ideogram).

معرض صور خاص بالمستخدمين + معرض صور خاص بالأدمن.

إمكانية توليد الصور باستخدام الخادم الخارجي:

https://47zg9vbcvs.adaptive.ai/api/generate

تضمين الكود الأساسي للاستدعاء (المرفق أدناه) ضمن المشروع.

تحديث في الوقت الفعلي (نظام AJAX Polling) لكل من:

عدد النقاط.

الإشعارات الفردية والجماعية.

حالة الحساب (نشط/معلق).

سجل توليد الصور.

  1. نظام الحسابات

تسجيل مستخدمين بدون تأكيد عبر البريد.

أول حساب يتم إنشاؤه يصبح أدمن تلقائيًا.

لكل حساب جديد يتم إضافة نقاط افتراضية يحددها الأدمن.

إعادة تعيين كلمة السر تلقائيًا عند النسيان.

إظهار عنوان IP في لوحة التحكم.

  1. لوحة تحكم الأدمن

مراقبة المستخدمين (تعليق/إعادة تنشيط/تعديل النقاط في الوقت الفعلي).

عرض وحظر المستخدمين المسيئين.

إرسال إشعارات فردية أو جماعية للمستخدمين.

اختيار إشعارات جاهزة مسبقًا و إرسالها تلقائيًا.

شات دعم مباشر بين المستخدم والأدمن.

قسم خاص بالمقالات:

إضافة مقالات جديدة.

تعديل وحذف المقالات.

نشرها للعامة في صفحة مخصصة.

  1. نظام الباقات والدفع

ثلاث باقات (منها واحدة مجانية).

ربط الدفع عبر Payeer باستخدام المحفظة:

P1028352381

المستخدم يرسل رقم العملية (Transaction ID).

تأكيد الدفع يتم يدويًا من طرف الأدمن.

  1. التخزين وقاعدة البيانات

إنشاء قاعدة بيانات SQLite تلقائيًا داخل مجلد db.

تخزين الصور المولدة في مجلد generated_images.

ضبط الأذونات (CHMOD 755 أو 777 عند الحاجة).

  1. كود الاستدعاء الأساسي (مضمّن في المشروع):
<script> 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> `; } else { document.getElementById("result").innerHTML = "<p>⚠️ لم يتم العثور على بيانات صورة في الرد.</p>"; } } catch (error) { document.getElementById("result").innerHTML = "<p>❌ خطأ: " + error.message + "</p>"; } } </script>

⚡ مهم جدًا:

المشروع يجب أن يكون في ملف واحد فقط index.php يحتوي على HTML + CSS + JS + PHP.

لا تقم فقط بتحليل البرومبت، بل ابدأ بإنشاء المشروع مباشرة.

Мысль

Clarifying project requirements

I need to create a PHP project with HTML, CSS, JS, and PHP, ready for hosting on InfinityFree. I’ll implement auto-creation of an SQLite database and set up directories like generated_images. I'll ensure automatic user creation, with the first user being an admin. Also, I’ll include AJAX polling endpoints for account status, image galleries, and notifications.

Planning feature implementation

I need to integrate an external image generation API, ensuring generated images are saved to the correct folder and DB. For password reset, users can enter their username or email, and a new password will be generated and shown. Admin can manage account status (active or suspended). I'll also implement notifications, direct messaging, articles, and a plans/payment section. Everything will update in real-time via AJAX polling.

Implementing payment and user features

I need to handle transactions through a Payeer wallet, where users submit transaction IDs for admin verification. Admin can approve payments, which will upgrade user plans and add points. The points system will include a default configurable value, and updates will be real-time. I'll also implement security features, session management, and AJAX endpoints for key actions like login, register, and image generation.

Handling image saving and hosting limitations

To save images on the server, I’ll send the base64 image to PHP via a fetch request when the image is successfully generated. I’ll keep the provided JS code unchanged, as required. Also, I’ll implement AJAX polling for image histories, while ensuring proper permissions are set for storing files. Please note, server restrictions may limit some actions like CHMOD.

Outlining the structure

I’m laying out the code for a session-based app with SQLite storage. It will include user management, points system, image generation handling, real-time polls for updates like notifications and points, and a basic admin panel for management. There’ll be security measures, image handling, and dynamic front-end elements. I'll need to hide most actions behind POST and AJAX endpoints. The code will be procedural with specified helper functions and minimal comments for clarity. We’ll also need Arabic RTL UI design and careful handling of large images.

Thought for 52s

Ответ

فيما يلي مشروع متكامل “ملف واحد فقط” باسم 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 = `<div>${escapeHtml(n.message)}</div><div class="muted">${n.created_at} • ${n.is_read?'مقروء':'غير مقروء'}</div>`; 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 = `<span class="chip">${mine?'أنا':'الدعم'}</span> <span>${escapeHtml(m.message)}</span> <small class="muted">${m.created_at}</small>`; 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=>({ '&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;' }[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>

ملاحظات سريعة للتشغيل

  • ارفع index.php فقط. عند أول زيارة سيُنشئ تلقائيًا:
    • مجلد db/ وفيه قاعدة بيانات SQLite.
    • مجلد generated_images/ لحفظ الصور المولدة.
    • يحاول ضبط الأذونات إلى 777 إن لزم (قد تتجاهلها الاستضافة وهذا طبيعي).
  • أول حساب تقوم بإنشائه يصبح أدمن تلقائيًا، ويمكنه:
    • ضبط النقاط الافتراضية للمسجلين الجدد.
    • تعليق/تنشيط المستخدمين وتعديل نقاطهم في الوقت الفعلي.
    • إرسال إشعارات جماعية/فردية (مع نصوص جاهزة).
    • إدارة المقالات (إضافة/تعديل/حذف/نشر).
    • إدارة المدفوعات اليدوية للخطط (Plus/Pro) بعد أن يرسل المستخدم Transaction ID عبر Payeer (المحفظة: P1028352381).
    • اختيار صور إلى معرض الأدمن.
  • التحديث اللحظي (AJAX Polling) ينعكس على: النقاط، الإشعارات، حالة الحساب، سجل توليد الصور.
  • كود الاستدعاء الأصلي لتوليد الصور مضمن كما هو، مع إضافة خطوة حفظ تلقائي للسيرفر بعد نجاح التوليد.

جاهز؟ انسخ الملف وابدأ 👌

Вопрос

اضف ميزة تمكن الادمن من وضع اعلانات من مواقع اعلانات مختلفة تشخر في واجهة حسابات المستخدمين و في المقالات التي سيقوم الادمن بنشرها مع تحكم كامل بها و في امكانها و يستطيع اظهارها و منعها من خلال لوحة تحكم

Мысль

Planning ad feature update

The user wants to enhance their site where admins can add ads from different networks, manage them in the UI, and control visibility. I’ll prepare code for a new ads table, control settings, and ad placement options. Also, I'll implement rendering functions to display ads correctly, keeping security considerations in mind.

Planning ad code and UI update

The user wants code for CRUD operations for ads, including managing them through an admin panel. I'll also implement a system for displaying ads in specific slots on the frontend. These slots include positions like top banner, sidebar, and articles. Each ad will have a position, network, and other settings.

Implementing AJAX for ad management

The user wants AJAX functionality for creating, updating, deleting, and toggling ads. Ad code, which can contain scripts, will be stored via JSON POST. We’ll provide a drop-in "updated version" of index.php by including only necessary changes, ensuring it’s comprehensive yet manageable. I'll also ensure it’s executable.

Providing upgrade snippet

I'll provide a minimal upgrade snippet for the user, focusing on essential changes like new table creation, the render_ads function, and adding admin sections. Instead of the whole file, I’ll focus on concise instructions with clear code blocks to insert in specific spots. I'll provide sample code for the database table and admin panel section.

Thought for 23s

Ответ

تمام! أضفت لك ميزة إدارة الإعلانات (من شبكات مختلفة) مع تحكّم كامل في الظهور والمكان، وتتكامل داخل نفس ملف index.php بدون أي ملفات إضافية.
الخطوات التالية عبارة عن تحديثات موضعية (قص/لصق) على ملفك الحالي. اتبعها بالترتيب:


1) إنشاء جدول الإعلانات في قاعدة البيانات

ابحث عن دالة 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 ); ");

لا حاجة لإدخال بيانات افتراضية؛ ستضيفها من لوحة الأدمن.


2) ثوابت مواضع الإعلانات + دالة عرض

ضع هذا قبل بداية إخراج الـ 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>'; }

3) تنسيقات CSS للإعلانات

داخل وسم <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; }

4) مواضع الحقن في الواجهة

4.1 أعلى الموقع (تحت العنوان مباشرة)

بعد عنصر <header>...</header> مباشرةً أضف:

php
<?php render_ads('top_banner'); ?>

4.2 أسفل قسم التوليد

داخل تبويب التوليد (قبل إغلاق </section> لقسم توليد الصور) أضف:

php
<?php render_ads('under_generator'); ?>

4.3 أعلى المعرض

داخل قسم المعرض (بعد <h2>المعرض</h2> مباشرة):

php
<?php render_ads('gallery_top'); ?>

4.4 صفحة المقالات

  • أعلى القائمة (بعد <h2>المقالات</h2>):
php
<?php render_ads('articles_top'); ?>
  • أسفل القائمة (قبل إغلاق </section> لقسم المقالات):
php
<?php render_ads('articles_bottom'); ?>

4.5 أسفل الموقع

قبل إغلاق </main> مباشرة:

php
<?php render_ads('global_footer'); ?>

5) واجهة إدارة الإعلانات (لوحة الأدمن)

5.1 واجهة HTML

في تبويب الأدمن داخل القسم <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>

5.2 دوال واجهة الأدمن (JavaScript)

ضمن سكربت الصفحة (حيث توجد دوال الأدمن الأخرى)، أضف:

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'); }

6) نقطة API للأدمن لإدارة الإعلانات

ابحث عن كتلة الـ AJAX لديك (حيث if (isset($_GET['ajax'])) { ... }) وأضف الفرع التالي بداخلها (مع بقية فروع الأدمن):

php
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; }

7) ملاحظة أمنية مهمة

  • كود الإعلان يُعرض كما هو (HTML/JS من الشبكة)، لذا اعتمد فقط شبكات موثوقة وتأكد من أن الإعلانات لا تُدخل سكربتات ضارة.
  • إن كانت الاستضافة تفعل سياسة CSP صارمة فقد تحتاج لتعديلها للسماح لمجالات شبكات الإعلانات (غالبًا InfinityFree تسمح بذلك).

جاهزية الميزة

بعد تطبيق التعديلات:

  • افتح تبويب الأدمن ➜ قسم الإعلانات:
    • أضف إعلانًا جديدًا، اختر الموضع (Top/Under generator/…)، حدّد الأولوية، والصق كود الشبكة كما هو.
    • يمكنك إظهار/إخفاء الإعلان عبر حقل “نشط؟”.
    • يمكنك تعديل الكود أو نقل الإعلان بين المواضع.
  • سيظهر الإعلان تلقائيًا في الواجهة أو المقالات بحسب الموضع الذي اخترته.

لو رغبت لاحقًا بإضافة مواضع جديدة:

  1. أضف مفتاحًا جديدًا في المصفوفة $AD_POS.
  2. ضع render_ads('الموضع_الجديد') حيث تريد ظهوره في الصفحة.

إذا أحببت، أستطيع دمج كل التعديلات في نسخة كاملة من index.php كملف واحد جاهز للنسخ واللصق.

Вопрос

رجاءا اعطني الكود المحدث كاملا ، كما تعلم ليست لي خبرة كافية في البرمجة

Мысль

Thought for 6s

Ответ

تمام! هذا هو ملف 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 = `<div>${escapeHtml(n.message)}</div><div class="muted">${n.created_at} • ${n.is_read?'مقروء':'غير مقروء'}</div>`; 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 = `<span class="chip">${mine?'أنا':'الدعم'}</span> <span>${escapeHtml(m.message)}</span> <small class="muted">${m.created_at}</small>`; 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=>({ '&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;' }[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>

ملاحظات سريعة

  • ارفع index.php فقط. أول زيارة ستُنشئ تلقائيًا:
    • مجلد db/ مع قاعدة SQLite.
    • مجلد generated_images/ لحفظ الصور.
    • جدول ads للإعلانات.
  • من لوحة الأدمن ➜ قسم الإعلانات:
    • أضف إعلانًا جديدًا، اختر الموضع (مثل: أعلى الموقع، أسفل التوليد..)، حدِّد الأولوية، والصق كود الشبكة كما هو.
    • يمكنك إظهار/إخفاء الإعلانات وتعديلها أو حذفها.
  • تم حقن الإعلانات تلقائيًا في:
    • أعلى الموقع، أسفل مولِّد الصور، أعلى المعرض، أعلى/أسفل صفحة المقالات، وأسفل الموقع.

لو حابب أعدّل الأسماء العربية للمواضع أو أضيف مواضع جديدة داخل الصفحة، قلّي وين تفضّل أحطها وأنا أعدلها لك فورًا. ✅

Поделиться этим Q&A