قبل أي شيء: احتفظ بالموقع الحالي وبياناته، وجرّب النسخة في مجلد وقاعدة منفصلين. لا ترفع عدة المطور أو المفتاح الخاص إلى الاستضافة. هذه النسخة ليست Laravel.
تثبيت منصة الودادية 1.0.0
طبيعة النسخة
هذه إعادة بناء مستقلة بلغة PHP، مع فصل المسارات ووحدات المعالجة والخدمات والقوالب (MVC). ليست Laravel، ولا تحتاج Composer أو Node أو SSH على الاستضافة. تحتاج قاعدة MySQL ينشئها صاحب الاستضافة؛ المعالج ينشئ جداول التطبيق وحساب المسؤول وملف الإعدادات تلقائياً. لا توجد كلمات مرور دخول افتراضية.
الأرشيف يحتوي مجلد widadya-modern-1.0.0. ارفع محتويات هذا المجلد إلى المجلد الذي سيستضيف الموقع، وليس عدة المطور. تأكد من رفع ملفات .htaccess المخفية ومجلدات storage الفارغة.
المتطلبات
PHP 8.3 أو أحدث، مع PDO MySQL وOpenSSL وFileinfo وzlib والجلسات. اتصال MySQL مع InnoDB وutf8mb4 وصلاحيات SELECT وINSERT وUPDATE وDELETE وCREATE وALTER وINDEX. صُمم المخطط لـMySQL 8؛ لم يُنفذ اختبار MySQL فعلي في بيئة إعداد هذا التسليم.
Apache 2.4 أو خادم متوافق يطبق قواعد .htaccess وmod_rewrite. على Nginx لا تعمل .htaccess؛ يلزم إعداد منع المجلدات الداخلية بواسطة مدير الخادم قبل التثبيت. لا تترك config أوstorage أوapp أوdatabase أوdocs أوtests أوtools متاحة عبر HTTP، ولا تسمح بقراءة الملفات المخفية أوملفات السجل والمفاتيح.
يجب أن تكون config وstorage قابلة للكتابة بواسطة مستخدم PHP. لتحديث الكود من اللوحة، يجب أن تكون الملفات المستهدفة قابلة للكتابة أيضاً؛ لا تستعمل chmod 777. يلزم HTTPS عند التشغيل العام؛ الأداء بالبطاقة معطل دون HTTPS وامتداد cURL والمفاتيح اللازمة.
إعدادات أولية مقترحة لحزم التحديث: memory_limit لا يقل عن 256M، وupload_max_filesize=64M، وpost_max_size=96M، وmax_execution_time=120. قد تحتاج قواعد البيانات الكبيرة إلى مساحة وذاكرة ووقت أكبر، أو إلى تحديث يدوي مخطط. رفع وصل أو صورة داخل المحتوى محدود بـ6 MiB. لا يعني توفر مساحة 100 MiB أن النسخة الاحتياطية الكبيرة ستكفيها هذه المساحة.
التثبيت خطوة بخطوة
1. احفظ نسخة كاملة من موقعك الحالي وقاعدة بياناته خارج مسار الموقع. أنشئ مجلداً أو نطاقاً فرعياً تجريبياً وقاعدة MySQL جديدة ومستخدماً مخولاً بها؛ لا تستبدل الموقع العامل.
2. فك أرشيف التطبيق وارفع محتويات المجلد، بما فيها .htaccess. فعّل PHP والامتدادات المطلوبة من لوحة الاستضافة. افتح https://example.test/widadya/storage/access-test.txt بعد استبدال النطاق والمسار: يجب أن يرجع 403 أو404، وألا يظهر محتواه. توقف وأصلح الحماية إن ظهر النص. راجع أيضاً منع /config/update-public.pem و/docs/.
3. افتح https://example.test/widadya/index.php?page=install. من File Manager افتح config/install-key.php وانسخ قيمة المفتاح المكتوبة بين علامتي التنصيص بعد return، دون نشرها. أدخلها في خانة مفتاح التثبيت.
4. أدخل خادم MySQL واسم القاعدة ومستخدمها وكلمة مروره، ورابط التطبيق الكامل دون الشرطة الأخيرة، والبادئة wd_، واسم المسؤول وبريده وكلمة مرور قوية من 12 محرفاً/بايتاً على الأقل. لا تضع index.php في رابط التطبيق الأساسي. ينشئ المعالج الجداول وconfig/local.php وstorage/installed.lock ثم ينقلك إلى الدخول.
5. سجّل الدخول بحساب المسؤول. راجع الإعدادات والحسابات البنكية وأضف المحتوى الحقيقي. اختبر رسالة البريد من اللوحة، والتسجيل والتفعيل واستعادة كلمة المرور، قبل فتح التسجيل للعموم. النسخة المنشورة لا تتضمن المستخدمين أو الطلبات التجريبية التي استُخدمت للاختبار.
إن كنت ستشارك أرشيف التثبيت علناً، أنشئ مفتاح تثبيت عشوائياً خاصاً بنسختك قبل النشر بدلاً من نشر المفتاح الموجود. لا تضع كلمات مرور الاستضافة في مستند عام. احتفظ بنسخة سرية من config/local.php بعد نجاح التثبيت؛ فهو يتضمن مفتاح تشفير أسرار البريد وStripe.
التحقق قبل التشغيل العام
راجع صفحات الهاتف والحاسوب، وصلاحيات عضو وغير عضو في المكتبة، ومستخدم عادي ومسؤول، وطلب دفع بنكي تجريبي مع مراجعة الوصل، وتتبع الطلب برمزه الخاص. تحقق من عدم عرض تفاصيل الطلب بمجرد تخمين رقمه الداخلي. انشر المحتوى الحقيقي بعد مراجعته وألغِ حسابات التجربة في نسختك الاختبارية.
إذا ظهرت صفحة 500 قبل المعالج، راجع سجل PHP في الاستضافة وإعداد .htaccess وصلاحيات المجلدات. إذا أعلن المعالج غياب امتداد، فعّله بدلاً من تجاوز الفحص. إذا انقطع التثبيت بعد إنشاء حساب المسؤول وقبل حفظ config/local.php، لا تحذف الجداول القديمة عشوائياً؛ راجع النسخة الاحتياطية وسجل الأخطاء أو أعد التجربة في قاعدة جديدة. ملف إعداد ناقص لا يعني أن عملية SQL كلها تراجعت تلقائياً.
البريد وStripe
البريد يدعم PHP mail أو SMTP مع TLS/SSL. نجاح طلب الإرسال في البرنامج لا يثبت وصول الرسالة؛ افحص صندوق الوارد والبريد غير المرغوب فيه وإعدادات SPF/DKIM مع المستضيف. لا توجد بيانات SMTP جاهزة في هذه الحزمة.
الأداء بالبطاقة اختياري؛ يلزم حساب Stripe قادر على الخدمة والعملة المستخدمة (MAD)، ومفاتيح وضع اختبار أو إنتاج متطابقة، وWebhook صحيح. اللوحة تعرض عنوان Webhook والأحداث المطلوبة. لا تعتبر العودة من صفحة الأداء إثباتاً للدفع. اختبر السيناريوهات في وضع الاختبار أولاً. لا يتضمن التطبيق إرجاع أموال آلياً؛ معالجة استرداد أداء حقيقي تحتاج إجراءً منفصلاً في بوابة الدفع ومراجعة السجل.
نقل بيانات النسخة السابقة
حدود الأرشيف المتاح
widadya.zip يضم 55 ملفاً، منها 50 ملف PHP و13 ملفاً فارغاً. ملف SQL الموجود يعرّف جدول orders فقط، وليس قاعدة الموقع الكاملة. لذلك لا تكفي هذه الملفات لاستعادة المستخدمين والمقالات والاتفاقيات والمكتبة والمخزون والوسائط الفعلية. لا تُحمّل سجلات الطلبات النموذجية الموجودة في الأرشيف تلقائياً عند التثبيت الجديد.
تجهيز نسخة تجريبية
احصل من استضافتك على تصدير كامل لقاعدة البيانات القديمة ونسخة الوسائط. اعمل على نسخة منفصلة، لا على الأصل. يمكن وضع الجداول الأصلية بأسمائها القديمة غير المسبوقة داخل قاعدة التجربة، ثم تثبيت التطبيق الجديد ببادئة wd_، أو استيراد الجداول الأصلية بعد التثبيت مع مراجعة أسماء الجداول وعبارات SQL حتى لا تمس wd_. لا يرفع معالج النقل SQL من المتصفح ولا ينفّذه.
قبل تشغيل النقل، انسخ مجلدات الوسائط القديمة إلى storage/legacy-media/ مع الحفاظ على المسار النسبي؛ مثلاً الملف القديم uploads/photo.jpg يوضع في storage/legacy-media/uploads/photo.jpg. ينقل المعالج الملفات الموجودة محلياً فقط، ويتحقق من نوعها وحجمها؛ لا يجلب روابط خارجية مجهولة ولا يقبل روابط رمزية خارجة عن هذا المجلد.
من لوحة المسؤول افتح «نقل البيانات القديمة». يعرض المعالج الجداول المعروفة التي وجدها وعدد سجلاتها. انقل المستخدمين والحسابات البنكية والمحتويات والهيكلة أولاً، ثم خيارات المنتجات، ثم الطلبات وعناصر الطلبات والتسجيلات والتعليقات والصور. تعالج كل دفعة حتى 100 سجل؛ تابع من آخر معرف معروض، ثم أعد مراجعة السجلات الفاشلة.
تحتفظ المنصة بخريطة معرفات قديم→جديد، فلا يتطلب النقل تطابق المعرفات. إعادة دفعة لا تنشئ نسخة أخرى من سجل سبق ربطه. تحفظ أيضاً كل صف أصلي بصيغة JSON محمية قبل تحويله، بما في ذلك الحقول التي لا يوجد لها مقابل في الواجهة الجديدة. هذه الأرشفة ليست وعداً بظهور كل حقل غير معروف في واجهة التطبيق.
نقاط يجب مراجعتها يدوياً
الحسابات تُنقل بصلاحية مستخدم، ولا تُمنح الإدارة تلقائياً. كلمات المرور المشفرة المدعومة تُحفظ؛ الحساب الذي لا يملك صيغة صالحة يحتاج إعادة تفعيل/استعادة كلمة مرور. إذا كان البريد موجوداً أصلاً في النسخة الجديدة، يربطه المعالج دون تغيير كلمة المرور أو الصلاحية الحالية.
تُراجع حالات الأداء البنكي والبطاقة والانخراط والتسجيل قبل اعتمادها. الكود السابق كان يستطيع تسجيل «مؤدى» دون تحقق حقيقي من Stripe؛ لذلك لا يثق النقل بهذا التأكيد. الطلبات المنقولة لا تُفتح لها جلسة أداء جديدة بالبطاقة كي لا يُحصّل ثمنها مرتين. الطلب القديم لا يُفترض أن مخزونه حُجز في النسخة الجديدة، لذلك لا تُزاد كمياته آلياً عند إلغائه؛ راجع المخزون فعلياً عند الانتقال.
قد يحتوي الموقع القديم library وlibrary_items معاً؛ راجع احتمالات التكرار. الوسائط المفقودة أو غير المدعومة تظهر في التنبيهات. ضع الوسائط قبل النقل: إعادة سجل مرتبط تتخطاه ولا تعيد إرفاق صورة ظهرت لاحقاً؛ أضف الملف الناقص من تحرير المحتوى في اللوحة. المعالج يتعرف على أسماء الجداول والحقول المعروفة في الكود المرسل فقط؛ أي اختلاف إضافي في القاعدة الحقيقية يحتاج مطابقة من المطور.
قبل تحويل النطاق إلى النسخة الجديدة
قارن أعداد المستخدمين والمحتويات والطلبات وعناصرها، وافحص عينات من النصوص والصور والملفات والمدفوعات والصلاحيات. احتفظ بالموقع القديم للرجوع إليه. نقل الجداول الفعلية الكبيرة والوسائط الكاملة لم يُختبر هنا لأن النسخة الكاملة لم تكن موجودة في الأرشيف؛ الاختبارات المنفذة استخدمت جداول قديمة مصطنعة للتحقق من الربط والحماية وعدم تغيير المصدر.
تحديث المنصة والاسترجاع
تشغيل التحديث من لوحة المسؤول
من القائمة الإدارية افتح «التحديثات»، وارفع حزمة ZIP موقعة مخصصة لهذه النسخة من المطور. الحزمة العادية التي تضم موقعاً كاملاً ليست حزمة تحديث. يفحص التطبيق التوقيع والمنتج ورقم الإصدار ومتطلبات PHP وSHA256 لكل ملف والمسارات المسموح بها قبل عرض المعاينة.
احفظ نسخة مستقلة كاملة من الملفات والبيانات من لوحة الاستضافة أولاً. راجع الإصدار والملفات والملاحظات، وأكد النسخ الاحتياطي، وأدخل كلمة مرور المسؤول ثم اختر تطبيق التحديث. يوقف التطبيق الطلبات المتزامنة أثناء استبدال الملفات، وينشئ لقطة ما قبل التحديث، ويضيف الجداول/الأعمدة المسموح بها، ثم يكتب VERSION ويسجل النجاح. حافظ على الملف الذي تسلمته من المطور ولا تعدّل داخله بعد التوقيع.
لا يوجد خادم خارجي لنشر التحديثات أو تنزيلها تلقائياً. الرفع والتحقق والتطبيق يتم من اللوحة بعد توفير حزمة من المطور. إنشاء تلك الحزمة يتم بأداة عدة المطور على حاسوبه، لا على استضافة الموقع.
ما الذي تحتويه اللقطة؟
تحفظ اللقطة في storage/backups، ويمكن تنزيل لقطة التحديث الناجح من سجله. تتضمن:
- ملفات الكود القديمة التي ستُستبدل، وقائمة absent.json للملفات الجديدة التي لم تكن موجودة.
- بيانات جداول المنصة بصيغة JSON، والمخطط السابق، ونسخة سرية من config/local.php والمفتاح العام.
- ملف database/restore.sql عند التشغيل على MySQL، منشأ من بنية الجداول الفعلية وبياناتها، دون DROP، للاستيراد في قاعدة فارغة فقط. هذا الفرع الخاص بـMySQL لم يُنفذ هنا لغياب MySQL في بيئة الاختبار.
ليست هذه نسخة كاملة من الموقع: لا تشمل كل الوسائط ولا الجداول الأصلية غير التابعة للمنصة. النسخة من الاستضافة تبقى ضرورية. اللقطة تحتوي بيانات شخصية وأسرار إعداد؛ احتفظ بها خارج المسار العام ولا تشاركها علناً.
حدود ترحيل المخطط
الترحيل المدمج إضافي فقط: ينشئ جدولاً جديداً أو يضيف عموداً، ويمنع العمود الإلزامي بلا قيمة افتراضية داخل جدول موجود. لا يحذف الجداول ولا يغير أنواع الأعمدة الموجودة ولا يطبق سكربت SQL عشوائياً. لا ينشئ فهارس جديدة لجدول موجود تلقائياً؛ تحتاج إعادة هيكلة أوسع إلى خطة مطور منفصلة. تغيير الأعمدة أو البيانات ليس عملية يمكن ضمان التراجع التلقائي عنها بمجرد استرجاع ملفات PHP.
عند الفشل
عند خطأ يُلتقط أثناء التطبيق، يحاول النظام استعادة ملفات الكود السابقة وحذف الملفات الجديدة التي أدخلتها العملية. لا يعيد قاعدة البيانات تلقائياً إلى حالة قديمة؛ قد تبقى إضافات للمخطط ويجب مراجعتها. إذا فشل الاسترجاع الكامل تبقى علامة الصيانة. انقطاع عملية PHP أو الخادم فجأة قد يتطلب استرجاعاً يدوياً.
قبل أي استرجاع يدوي، احتفظ بنسخة من الحالة الحالية ومن اللقطة. عبر File Manager، اعثر على اللقطة المحددة في storage/maintenance.json أو سجل النسخ. فكها خارج المسار العام. أعد محتويات code/ إلى مساراتها المقابلة في جذر التطبيق، واحذف فقط المسارات الجديدة المعلنة في absent.json بعد التحقق منها، وأعد VERSION السابق. لا تنسخ مجلدات اللقطة نفسها مباشرة إلى جذر الموقع.
لاستعادة البيانات، الأفضل استرجاع النسخة الكاملة المستقلة بواسطة الاستضافة. بديل يدوي على MySQL: أنشئ قاعدة جديدة فارغة، ثم استورد database/restore.sql، وأعد إعداد config/local.php ليشير إلى القاعدة الجديدة مع الاحتفاظ بمفتاح app_key الصحيح. استرجع ملفات الوسائط من النسخة الكاملة عند الحاجة. لا تستورد SQL اللقطة فوق قاعدة حية؛ قد يُنشئ تعارضات أو يفقد تغييرات أحدث إذا أُسيء التعامل معه.
بعد اكتمال إصلاح الكود والقاعدة والتحقق منهما فقط، احذف storage/maintenance.json، واطلب من المستضيف تفريغ OPcache/إعادة تشغيل PHP عند الحاجة، ثم اختبر الدخول والصلاحيات والطلبات. لا تحذف علامة الصيانة لمجرد إعادة فتح الموقع قبل إصلاح السبب.
المفتاح الخاص
ملف widadya-developer-kit.zip يحتوي مفتاح التوقيع الخاص وأداة إنشاء الحزم. لا ترفعه إلى الموقع، ولا إلى لوحة التحديثات. تحفظ الاستضافة المفتاح العام فقط في config/update-public.pem. توقيع موثوق يثبت هوية مصدر الحزمة وسلامتها، لا سلامة منطق الكود؛ يجب مراجعة التحديث واختباره قبل التطبيق.
خريطة الوظائف
| القسم | الوظائف في النسخة المعاد بناؤها |
| الهوية والصفحة الرئيسية | الشعار الأصلي، واجهة عربية RTL داكنة، عرض الأقسام، الإعلانات، وإمكانية تفعيل الفيديو المرفق من الإعدادات |
| الأخبار | قائمة وبحث وترقيم صفحات، تفاصيل، صور ومرفق PDF، تعليقات مع تعديل تعليق صاحبه |
| الاتفاقيات | البحث والتصفية بالمدينة والصنف، نسبة الخصم، خريطة برابط، معرض صور، تقييمات |
| الأنشطة | تمييز القادمة والسابقة، التفاصيل، التسجيل، الموعد النهائي والسعة، إثبات بنكي أو بطاقة اختيارية |
| المكتبة | بحث واقتراحات، تصنيف، ملفات عامة أو مخصصة لعضوية فعالة، معاينة وتنزيل محميان |
| المتجر | بحث واقتراحات وأفضل مبيعات، تفاصيل وصور وخيارات لون/نوع، مخزون وتقييمات ومنتجات مرتبطة |
| السلة والطلب | إضافة وتعديل وحذف، تجميع الكمية لكل منتج عبر خياراته، حساب السعر على الخادم؛ التوصيل مرة لكل سطر خيار مميز وليس لكل وحدة |
| الأداء والتتبع | بنكي، عند التسليم وفق السماح، وStripe اختياري؛ وصل خاص، حالة إدارية، رقم شحن، رمز تتبع، QR محلي، ملخص قابل للطباعة |
| الحساب | تسجيل وتفعيل بالبريد واستعادة كلمة المرور، ملف شخصي وصورة وكلمة مرور؛ لا يتضمن حسابات افتراضية |
| الانخراط | استمارة مهنية، وصل اختياري، قرار المسؤول ومدة العضوية وصلاحية الوصول للمكتبة |
| الهيكلة | مكاتب وطنية وجهوية ومحلية مع المدينة والجهة والمحكمة بحسب البيانات |
| التواصل | مراسلات العضو ورد المسؤول وإشعارات داخلية |
| الإدارة | لوحة مؤشرات، CRUD للمحتويات، حسابات بنكية وإعلانات، المستخدمون والأدوار، التعليقات، الطلبات والتسجيلات والانخراط والمراسلات والسجل |
| التشغيل | معالج تثبيت من المتصفح، إعداد البريد والدفع، نقل الجداول القديمة المعروفة، فحص وتطبيق تحديثات موقعة |
لم تُضمّن بيانات العملاء أو الطلبات المصطنعة أو مفاتيح Stripe/SMTP أو سجلات الاختبار داخل نسخة النشر. الصور التجريبية في المعاينة لا تعني أن قاعدة الموقع الحقيقية نُقلت.
تقرير الاختبارات — النسخة 1.0.0
نجح 337 من 337 فحصاً محلياً مسجلاً في TEST-RESULTS.json. هذه فحوص جزئية ومتكررة لسيناريوهات محددة، وليست 337 اختبارات مستقلة تغطي كل حالات النظام. نتائج الفحوص لا تُعد اعتماد تشغيل إنتاجي.
| المجموعة | النتيجة |
| HTTP workflows | 144/144 |
| Responsive rendering | 59/59 |
| Core, migration, signed update and rollback | 66/66 |
| HTTP Stripe callback validation | 15/15 |
| Developer signing tool and unsafe archives | 13/13 |
| Email activation and administrative blocking | 16/16 |
| Installer preflight safeguards | 8/8 |
| Bundled CLI smoke test | 16/16 |
ماذا نُفذ فعلياً؟
شغلت نسخة منفصلة من التطبيق على PHP 8.4.24. اختُبرت الطلبات HTTP والصلاحيات والملفات الخاصة والمحتويات والسلة والطلبات والحجز والإلغاء والمراجعة البنكية عبر خادم PHP محلي. لم تتوفر إضافتا PDO MySQL وPDO SQLite أو خادم MySQL في البيئة؛ لذلك استُخدمت قاعدة SQLite فعلية عبر موائم FFI خاص بالاختبار يحقق واجهة الاتصال نفسها. هذا الموائم وقاعدة التجارب غير مضمنين في تطبيق النشر ولا يحتاجهما على الاستضافة.
اختُبر العرض على Chromium 144 بعروض 1440 و820 و390 و320 بكسل. منع إعداد المتصفح في البيئة التنقل المحلي المباشر؛ لذلك رُسم HTML الفعلي الصادر من التطبيق مع تضمين ملفاته محلياً في صفحة دون اتصال. فُحص تجاوز العرض الأفقي والقوائم وأخطاء JavaScript. لا تمثل هذه الفحوص اختبار تنقل حي أو AJAX متكامل داخل المتصفح؛ طُلبت نقاط HTTP بصورة مستقلة.
نجح تطبيق تحديث موقّع على نسخة اختبار، وإضافة عمود، والحفاظ على الطلبات والإعدادات، وإنشاء لقطة سابقة. ثم حُفز خطأ بعد استبدال الملفات أثناء ترحيل غير مسموح، وتحققت استعادة الكود وحذف الملف الجديد. اختُبرت أداة توقيع المطور مع محلل الحزم الفعلي، ورفض العبث بالتوقيع أو بالمحتوى ومسارات الخروج والروابط الرمزية والتكرار وCRC التالف.
تحققت المطابقة الكاملة لمصفوفة QR المحلية (Version 10-L / mask 0) مع مرجع Python qrcode لبيانات معلومة. جرى أيضاً التحقق من أحداث Stripe مصطنعة موقعة عبر HTTP: رفض التوقيع القديم أو الخاطئ والمبلغ والعملة والجلسة غير المطابقة، وقبول الإشعار الصحيح وعدم تكرار التأكيد والإشعار الداخلي.
ما لم يُتحقق منه
التثبيت الفعلي مع MySQL، وفرع إنتاج/استيراد restore.sql الخاص بـMySQL، وضبط .htaccess على استضافتك، وتسليم بريد حقيقي، وإنشاء جلسة Stripe خارجية أو تحصيل مال، ونقل قاعدة الموقع الحقيقية كاملة، وتحمل الأحمال الكبيرة، والتعافي من انقطاع قسري للخادم أثناء التحديث. يجب اختبار هذه الأمور على نسخة تجريبية من الاستضافة قبل الانتقال. ولا يوجد تقرير اختبار اختراق مستقل.
لتشغيل فحص الخدمات الخفيف على حاسوب مطور أو خادم يملك PHP CLI:
php tests/smoke.php
لا يحتاج هذا الفحص إلى تثبيت التطبيق أو الاتصال بقاعدة بيانات. النجاح فيه لا يستبدل اختبار MySQL أو البريد أو الأداء الحقيقي.