النظام مبني على إطار عمل PHP مخصص يُسمى "aw framework" (تطوير داخلي يعود لحوالي عام 2015)، بدون أي إطار عمل قياسي معروف. يتكون من أربعة تطبيقات فرعية تتشارك قاعدة بيانات MySQL واحدة (312 جدولًا) ومكتبات مشتركة في مجلد _library. طبقة العرض تعتمد على قوالب Smarty، وطبقة البيانات على RedBeanPHP، والتوجيه يتم بالوصول المباشر لملفات الكنترولر دون نقطة دخول موحدة. هذا القسم يشرح البنية وطريقة العمل والوضع الأمني والديون التقنية بصراحة مهنية لدعم قرار الترحيل إلى منظومة Laravel + Angular.
/obgy/core/controllers/patients.php?ac=search..htaccess الرئيسي يضبط فقط DirectoryIndex وصفحات الأخطاء ويمنع تصفح المجلدات (Options -Indexes)، بينما RewriteEngine off._library/: مكتبة قاعدة البيانات (RedBeanPHP)، نظام تسجيل الدخول (login_system)، مكتبة JWT (غير مستخدمة فعليًا)، قوالب Smarty، وإضافات (Breadcrumbs، رفع ملفات، PHPMailer)._public/aw_config.php (نموذج عام) مع نسخة مكررة داخل كل تطبيق فرعي (core/public/aw_config.php وما يقابلها) — جميعها تحمل نفس بيانات اتصال قاعدة البيانات مكتوبة نصًا صريحًا.upload/ (نحو 3.2 جيجابايت، منها 3.1 جيجابايت سونار) داخل مجلد الويب العام.http://api.gt4it.com (بدون تشفير HTTPS).| التطبيق | المسار | الغرض | الحجم التقريبي |
|---|---|---|---|
| العيادة الرئيسية (core) | obgy/core/ | قلب النظام: المرضى، الزيارات، الشيتات الإكلينيكية (حمل/نساء/عقم/حقن مجهري)، التقارير المالية، الإعدادات، النسخ الاحتياطي، وخدمات الموبايل mobileservices.php | 70 كنترولر / ~37,900 سطر |
| الصيدلية (pharmacy) | obgy/pharmacy/ | الأدوية، المشتريات، المخزن، الفواتير (receipt)، الموظفون | 6 كنترولرات |
| البورد التعليمي (board) | obgy/board/ | جلسات وطلبات البورد والموظفون | 4 كنترولرات |
| شاشة الانتظار (screen) | obgy/screen/ | شاشة عرض دور المرضى في الاستقبال — يعيد استخدام ملفات core مباشرة (require core/controllers/imp/) | كنترولر واحد |
amrtechogate_obgy) ونفس جداول المستخدمين والصلاحيات (awusers/awrole...) ونفس المكتبات.core/controllers/imp/_imp.php (23 سطرًا) هو "الموجّه" بالكامل: يقرأ ?ac= من الرابط، ينشئ كائنًا من كلاس Controllers، ويستدعي الدالة المطابقة لاسم ac إن وُجدت وإلا index(). لا يوجد تحقق من نوع الطلب (GET/POST) ولا قائمة سماح بالأكشنات — أي دالة public في الكلاس قابلة للاستدعاء من الرابط مباشرة.Controllers (تعارض تسمية مقصود لأن كل ملف يعمل منفصلًا). الـ constructor يكرر في كل ملف نفس الكود التمهيدي (~60 سطرًا): تحميل الإعدادات والاتصال بقاعدة البيانات وتهيئة Smarty وBreadcrumbs وتضمين كلاسات _header/_sidebar/_leftsidebar/_footer.views/؛ كل أكشن يعرض الصفحة على أجزاء متتالية: header::headershow() ثم sidebar::sidebarshow() ثم القالب الخاص بالشاشة ($smarty->display('xxx.html')) ثم القائمة اليسرى والفوتر. تمرير البيانات عبر $smarty->assign().awcontroll (الشاشات) وawcontrollprop (الأكشنات داخل كل شاشة) وawrole (الأدوار) وawrolecontrollprop (صلاحية كل دور على كل أكشن) إضافة إلى awmenu/awrolemenu (القوائم لكل دور) وawrolebtn (أزرار الواجهة). الدالة autho::checkauthoize() تتحقق عند كل أكشن من صلاحية دور المستخدم الحالي ($_SESSION['role_id']) وتعيد التوجيه لصفحة خطأ عند الرفض.awmenu هرميًا حسب دور المستخدم وإعداد "النموذج المبسط/الكامل" في programesetting.| العنصر | التفاصيل | الملاحظات |
|---|---|---|
| المكتبة (ORM) | RedBeanPHP إصدار 4.3 — ملف واحد _library/db_main/rb.php (12,380 سطرًا) | إصدار قديم (~2016)؛ الإصدار الحالي 5.x |
| قاعدة البيانات | MySQL — قاعدة amrtechogate_obgy بـ312 جدولًا (307 InnoDB، 5 MyISAM منها جدول المستخدمين awusers) | جدول المستخدمين MyISAM لا يدعم المعاملات |
| الترميز (Charset) | الاتصال يفرض SET NAMES latin1 بينما الجداول utf8 وتحوي بيانات عربية | اعتماد على "ازدواج ترميز" هش — أي ترحيل بيانات يتطلب معالجة ترميز دقيقة |
| وضع التشغيل | R::freeze(FALSE) — الوضع "السائل" (Fluid Mode) مفعّل في الإنتاج | المكتبة قادرة على تعديل بنية الجداول تلقائيًا أثناء التشغيل — مخاطرة على سلامة المخطط |
| أسلوب الاستعلام | خليط: ORM (R::find/load/store/trash) باستعلامات مُعاملة آمنة، بجانب SQL خام عبر R::getAll/getRow/exec كثير منه مبني بدمج نصوص مباشر | الجزء الخام هو مصدر ثغرات حقن SQL (انظر الأمان) |
| المعاملات (Transactions) | R::begin/commit/rollback تُستخدم في عمليات الإدخال المركبة | ممارسة جيدة، لكنها بلا أثر على الجداول الـMyISAM |
_library/login_system/classes/Login.php) تستخدم PDO باستعلامات مُعاملة (Prepared Statements) وجلسات PHP و"تذكرني" بكوكي، مع عدّاد محاولات فاشلة (user_failed_logins) للحد من التخمين.password_hash() بخوارزمية bcrypt بتكلفة 10 (مؤكد من عمود user_password_hash بصيغة $2y$10$... في جدول awusers)، وكذلك كلمات مرور المرضى للموبايل.core/controllers/mobileservices.php (671 سطرًا) يوفر تسجيل/تحديث بيانات المرضى وإرجاع JSON — لكن كل فحوصات الدخول والصلاحيات فيه معلّقة، ومفتوح للجميع مع Access-Control-Allow-Origin: *.php-jwt-master موجودة في _library لكن لا يوجد أي استدعاء لها في كود التطبيقات — تبعية ميتة، أي لا توجد مصادقة Token حقيقية للـ API._public/api_config.php يضع مفاتيح api_key/api_user/api_password كمتغيرات بيئة بقيم مكتوبة نصًا في الملف، ويفعّل display_errors = on — ولا يوجد ملف داخل النظام يستدعيه (يُرجح استخدامه من خدمات خارجية مثل SMS/التحاليل)./ERP/controllers/clientControllerAjax.php لمزامنة العملاء والفواتير دون أي توقيع أو مفتاح مصادقة ظاهر.password_hash/password_verify مع إعادة تجزئة تلقائية عند الحاجة.awcontroll/awrole*) مطبق في معظم شاشات النظام الداخلية.filter_input() لقراءة المدخلات، واستعلامات مُعاملة في مكتبة الدخول وفي جزء كبير من استدعاءات ORM.display_errors = off في الإعدادات الرئيسية، ومنع تصفح المجلدات في .htaccess، وحد لمحاولات الدخول الفاشلة.| الثغرة | الدليل (مسار الملف) | الخطورة |
|---|---|---|
| حقن SQL — مدخلات المستخدم تُدمج نصيًا في الاستعلامات (شاشة بحث المرضى: الاسم/العنوان/الهاتف...، التقارير المالية، الزيارات، السونار) | core/controllers/patients.php (بناء $q1..$q8 بصيغة LIKE '%$input%')، financialreport.php (executeSql)، visits.php، sonar.php (R::exec('... WHERE id = ' . $id)) | حرجة — قاعدة البيانات تحوي بيانات طبية حساسة |
| API الموبايل بلا أي مصادقة + CORS مفتوح للجميع، يتيح إنشاء/تعديل سجلات مرضى وقراءة بياناتهم | core/controllers/mobileservices.php (فحوصات autho معلّقة، Access-Control-Allow-Origin: *) | حرجة |
| بيانات اعتماد مكتوبة نصًا داخل الكود: كلمة مرور قاعدة البيانات مكررة في 5 ملفات إعدادات، مفاتيح API خارجية، ومفتاح سري للكوكيز ثابت | _public/aw_config.php، _public/api_config.php، ونسخ core/pharmacy/board/screen/public/aw_config.php | عالية |
| النسخ الاحتياطية لقاعدة البيانات (ببيانات المرضى كاملة) مخزنة داخل مجلد الويب العام، وتُنشأ بأمر نظام يمرر كلمة المرور في سطر الأوامر | core/db_backups/ (1.6 جيجابايت، 39 نسخة)، _db/*.sql، الكود في core/controllers/index.php (دالة takeackup عبر system()) | عالية |
| لا توجد حماية CSRF في أي نموذج، ولا قائمة سماح للأكشنات القابلة للاستدعاء من الرابط | نمط imp/_imp.php العام في كل الكنترولرات | عالية |
أكشنات إدارية خطرة قابلة للاستدعاء بمجرد تسجيل الدخول دون فحص صلاحيات (مثل onesetup الذي يحذف قوائم وأدوارًا) | core/controllers/index.php (دالة onesetup — فحص الدخول فقط دون فحص الدور) | متوسطة إلى عالية |
display_errors = on في إعدادات الـ API (تسريب تفاصيل تقنية)، واتصال خارجي بخدمة SMS عبر HTTP غير مشفر | _public/api_config.php، $hosturlApi = 'http://api.gt4it.com' في aw_config.php | متوسطة |
| وضع ORM "السائل" مفعّل في الإنتاج (يسمح بتعديل بنية الجداول تلقائيًا) | R::freeze(FALSE) في _public/aw_config.php | متوسطة |
| البند | الوضع الحالي | الأثر |
|---|---|---|
| إصدار PHP | الخادم يعمل بـ PHP 5.6.40 — انتهى دعمه الأمني نهائيًا في ديسمبر 2018 | لا تصلح أمنية منذ 7+ سنوات؛ عائق أمام أي مكتبات حديثة |
| Smarty | الإصدار 3.1.11 (صدر 2012) | ثغرات معروفة في إصدارات Smarty القديمة، ولا هروب تلقائي للمخرجات افتراضيًا |
| RedBeanPHP | الإصدار 4.3 (~2016) كملف وحيد منسوخ يدويًا | لا إدارة تبعيات (لا Composer إطلاقًا في المشروع) |
| تكرار الكود | ~60 سطرًا من كود التهيئة منسوخة في كل كنترولر من الـ81؛ ملفات إعدادات مكررة بنفس كلمة المرور في كل تطبيق فرعي؛ كنترولرات عملاقة (patients.php = 2,259 سطرًا، visits.php = 1,946) | أي تعديل عرضي مكلف وعرضة للأخطاء؛ صعوبة الصيانة هي المحرك الأساسي لقرار الترحيل |
| ملفات الرفع | مجلد upload/ بحجم ~3.2 جيجابايت (السونار وحده 3.1) داخل مجلد الويب، يُقرأ من نظام الملفات مباشرة دون فهرسة كاملة في قاعدة البيانات | صعوبة النسخ الاحتياطي والترحيل؛ مخاطر وصول مباشر للملفات |
| استراتيجية النسخ الاحتياطي | تُنفذ داخل طلب الصفحة الرئيسية: أول زيارة يومية للصفحة الرئيسية تشغّل mysqldump بشكل متزامن وتكتب في core/db_backups/ (39 نسخة متراكمة، 1.6 جيجابايت) دون تدوير أو نقل خارج الخادم؛ نسخ Excel في core/excel_backups/ | بطء عشوائي للمستخدم الأول صباحًا؛ النسخ على نفس القرص = لا حماية من فقد الخادم |
| اتساق البيئة | توقيتان مختلفان في الإعدادات (لوس أنجلوس في aw_config مقابل القاهرة في الكود والـ API)؛ ترميز latin1/utf8 مزدوج؛ كود ميت (php-jwt، جداول مهجورة، كتل معلّقة كثيرة) | أخطاء تواريخ محتملة؛ تعقيد إضافي عند ترحيل البيانات |
| الاختبارات والتحكم بالإصدارات | لا توجد أي اختبارات آلية، ولا مستودع Git، وملفات error_log وملفات تجريبية متناثرة داخل مجلدات الكنترولرات | أي تعديل = مخاطرة غير مقيسة؛ يصعّب التطوير المتوازي |