أصدقائي، سنتحدث اليوم عن شيء يدفع أي شخص قام بالبحث في كود PHP لشخص آخر إلى الجنون. تفتح موقعاً إلكترونياً، ولا تجد شيئاً. شاشة بيضاء. لا يوجد خطأ، ولا تلميح عما حدث بشكل خاطئ.
هل يبدو هذا مألوفاً؟
هذه هي الحالة الكلاسيكية للخطأ الفادح في PHP الذي يقتل السكربت فوراً ويختفي دون أن يودع. اليوم، سوف نتعلم كيف نجعل PHP تتحدث، وكيف نفعّل السجلات (logs)، ونجد تلك الأخطاء الفادحة المختبئة خلف "الشاشة البيضاء للموت".
لماذا تظل PHP صامتة: القليل من النظرية
أولاً، دعونا نفهم كيف يتعامل PHP مع الأخطاء بشكل عام. الأمر ليس مجرد "خطأ -> سجل". هناك تسلسل هرمي كامل.
في PHP 7+، كل ما يمكن أن يسوء ينفذ واجهة Throwable. لها فرعان رئيسيان: - Error — أخطاء PHP الداخلية (الفادحة، التحليل اللغوي، الأخطاء النوعية) - Exception — الاستثناءات التي يمكن التقاطها باستخدام try-catch
الأخطاء الفادحة (E_ERROR, E_PARSE, E_CORE_ERROR) هي أسوأ كابوس لأي مطور. إنها تقتل السكربت فوراً، والمعالجات القياسية عبر set_error_handler() لا تلتقطها . الطريقة الوحيدة لاعتراض خطأ فادح هي استخدام register_shutdown_function().
لكن دعنا ننتقل خطوة بخطوة. أولاً، نحتاج إلى تفعيل التسجيل لكي تُكتب الأخطاء بالفعل في مكان ما.
الخطوة 1: تفعيل التسجيل عبر php.ini
الطريقة الأصح لتكوين السجلات هي تحرير ملف تكوين PHP. يعتمد مكان وجوده على نظامك :
| النظام | المسار إلى php.ini |
|---------|--------------------|
| Ubuntu/Debian (Apache) | /etc/php/7.x/apache2/php.ini |
| Ubuntu/Debian (CLI) | /etc/php/7.x/cli/php.ini |
| Ubuntu/Debian (PHP-FPM) | /etc/php/7.x/fpm/php.ini |
| CentOS/RHEL | /etc/php.ini أو /etc/php.d/ |
| Windows (XAMPP) | C:\xampp\php\php.ini |
| Windows (WAMP) | C:\wamp\bin\php\phpX.X.X\php.ini |
في هذا الملف، نهتم بالتوجيهات التالية :
```ini ; تفعيل كتابة الأخطاء في ملف سجل (إلزامي!) log_errors = On
; تحديد المسار إلى ملف السجل error_log = /var/log/php_errors.log
; تعطيل عرض الأخطاء على الشاشة (للإنتاج!) display_errors = Off
; للتطوير، يمكنك تفعيل هذا، ولكن قم بتعطيله لاحقاً display_startup_errors = Off
; مستوى الإبلاغ عن الأخطاء — جميع الأخطاء error_reporting = E_ALL ```
مهم: واجهة سطر الأوامر (CLI) تستخدم ملف php.ini الخاص بها، وقد تُكتب السجلات في مكان مختلف . إذا كنت تختبر سكربتاً في وحدة التحكم، تحقق بشكل منفصل.
بعد إجراء التغييرات، تحتاج إلى إعادة تشغيل خادم الويب :
bash
sudo systemctl restart apache2 # لأباتشي
sudo systemctl restart php7.4-fpm # لـ PHP-FPM
ماذا تعني هذه الإعدادات
- log_errors = On — يفعل كتابة الأخطاء في ملف. بدون هذا، سيظل PHP صامتاً كالقبر .
- error_log — المسار إلى الملف حيث سيتم كتابة كل شيء. من الضروري أن يكون لمستخدم خادم الويب (عادة
www-dataأوapache) أذونات الكتابة لهذا الملف والدليل الخاص به . - display_errors = Off — قم بتعطيل هذا في الإنتاج بالتأكيد لتجنب كشف التفاصيل للمستخدمين .
- error_reporting = E_ALL — تسجيل جميع أنواع الأخطاء. للإنتاج، يمكنك تقييد هذا، ولكن لتصحيح الأخطاء من الأفضل رؤية كل شيء.
الخطوة 2: بديل: تفعيل التسجيل مباشرة في الكود
إذا لم يكن لديك وصول إلى php.ini (على سبيل المثال، في استضافة مشتركة)، يمكنك محاولة تفعيل التسجيل مباشرة في السكربت الخاص بك باستخدام الدالة ini_set().
أدخل هذا في بداية الملف المشكل:
```php
/dev/null ``` أو قم بإنشاء ملف PHP يحتوي على `phpinfo();` وابحث عن قسم **error_log**. ## الخطوة 4: قراءة السجلات: الأدوات والتقنيات بمجرد كتابة السجلات، تحتاج إلى معرفة كيفية عرضها وتصفيتها بسرعة. ### tail — عرض الأحداث الأخيرة ```bash # آخر 50 سطراً tail -n 50 /var/log/php_errors.log # المتابعة في الوقت الفعلي (مثل docker logs -f) tail -f /var/log/php_errors.log ``` ### grep — البحث عن أخطاء محددة ```bash # فقط الأخطاء الفادحة grep "Fatal error" /var/log/php_errors.log # أخطاء التحليل اللغوي (أخطاء بناء الجملة) grep "Parse error" /var/log/php_errors.log # تجاهل حالة الأحرف grep -i "warning" /var/log/php_errors.log ``` ### less — عرض مريح مع التنقل ```bash less /var/log/php_errors.log ``` داخل less، يمكنك الضغط على `/` وكتابة كلمة للبحث، `n` للنتيجة التالية، `N` للنتيجة السابقة. ### المجموعات — خط أنابيب قوي ```bash # عرض آخر 100 سطر والبحث عن أخطاء tail -n 100 /var/log/php_errors.log | grep -i fatal # المتابعة والتصفية في الوقت الفعلي tail -f /var/log/php_errors.log | grep --line-buffered "error" # عد الأخطاء حسب النوع grep -o "PHP [A-Za-z]* error" /var/log/php_errors.log | sort | uniq -c ``` ## الخطوة 5: فك رموز الأخطاء: ما هو ما يبدو إدخال السجل النموذجي كما يلي : ``` [2026-03-04 14:35:22 UTC] PHP Fatal error: Uncaught Error: Call to undefined function foo() in /var/www/html/index.php on line 10 ``` دعنا نحلله: - **التاريخ والوقت** — متى حدث - **PHP Fatal error** — مستوى الخطأ - **Uncaught Error: Call to undefined function foo()** — الرسالة - **/var/www/html/index.php:10** — الملف ورقم السطر مستويات الأخطاء الرئيسية : | المستوى | المعنى | مثال | |---------|--------|------| | **E_ERROR** / **Fatal error** | خطأ فادح، السكربت يموت | استدعاء دالة غير موجودة، ذاكرة غير كافية | | **E_WARNING** / **Warning** | تحذير، لكن السكربت يستمر | `include` لملف غير موجود | | **E_PARSE** / **Parse error** | خطأ في بناء الجملة، السكربت لن يعمل | فاصلة منقوطة مفقودة | | **E_NOTICE** / **Notice** | إشعار، عادة غير خطير | الوصول إلى متغير غير معرف | | **E_DEPRECATED** | بناء قديم | استخدام `mysql_connect()` | ## الخطوة 6: التقاط الأخطاء الفادحة (الجزء المثير للاهتمام) الأخطاء الفادحة هي تلك التي لا يمكن التقاطها بواسطة `set_error_handler()` القياسي. إنها تقتل السكربت على الفور، والمعالج الافتراضي ببساطة لا يملك الوقت الكافي للتنفيذ . لكن هناك طريقة! استخدم `register_shutdown_function()` — يتم استدعاء هذه الدالة في جميع الأحوال، حتى في حالة حدوث خطأ فادح . ### معالج بسيط للأخطاء الفادحة ```php getMessage()." | ".$e->getFile().":".$e->getLine()." | $url\n"; file_put_contents($logFile, $msg, FILE_APPEND); }); // معالج للأخطاء الفادحة register_shutdown_function(function() use ($logFile) { $error = error_get_last(); if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) { $url = ($_SERVER['HTTP_HOST'] ?? 'CLI') . ($_SERVER['REQUEST_URI'] ?? ''); $msg = "[".date('Y-m-d H:i:s')."] [FATAL] ".$error['message']." | ".$error['file'].":".$error['line']." | $url\n"; file_put_contents($logFile, $msg, FILE_APPEND); } }); ``` يمكنك إدراج هذا الكود في بداية ملفك الرئيسي (على سبيل المثال، `index.php` أو `header.php`)، وسيلتقط كل شيء على الإطلاق . ## الخطوة 7: السجلات في الأطر الشائعة إذا كنت تستخدم إطار عمل حديثاً، فالتسجيل مضبوط مسبقاً، لكن مسارات السجلات مختلفة. ### Laravel يتم تخزين السجلات في `storage/logs/laravel.log`. بشكل افتراضي، يستخدم Monolog؛ يمكن أن يكون التنسيق نصاً أو JSON. لرؤية الأخطاء: ```bash tail -f storage/logs/laravel.log ``` ### Symfony السجلات الافتراضية: `var/log/dev.log` و `var/log/prod.log`. يستخدم أيضاً Monolog، قابل للتكوين بدرجة كبيرة. ### WordPress بشكل افتراضي، لا يكتب WordPress سجلات، ولكن يمكنك تفعيلها بإضافة هذا إلى `wp-config.php`: ```php define('WP_DEBUG', true); define('WP_DEBUG_LOG', true); define('WP_DEBUG_DISPLAY', false); ``` ستكون السجلات في `/wp-content/debug.log`. ## الخطوة 8: المشاكل الشائعة وحلولها ### المشكلة: السجلات لا تُكتب على الإطلاق ما يجب التحقق منه: 1. هل `log_errors = On` مضبوط بالتأكيد؟ 2. هل هناك أذونات كتابة للملف والدليل الخاص به؟ 3. هل قمت بتحرير ملف php.ini الصحيح (تحقق باستخدام `phpinfo()`)؟ 4. هل أعدت تشغيل خادم الويب بعد إجراء التغييرات؟ ### المشكلة: الأخطاء الفادحة لا تُلتقط حتى مع تفعيل التسجيل، في بعض الأحيان لا تُكتب الأخطاء الفادحة إذا حدثت مبكراً جداً (على سبيل المثال، خطأ في تحليل بناء الجملة في نفس الملف حيث تقوم بتفعيل التسجيل). الحل الوحيد هو الموضع الصحيح — في البداية، قبل أي شيء آخر . ### المشكلة: سجلات كثيرة جداً إذا تم تفعيل `E_ALL` في الإنتاج، فستنمو السجلات بسرعة. قم بتكوين `error_reporting` بشكل معقول : ```ini error_reporting = E_ALL & ~E_DEPRECATED & ~E_NOTICE ``` ### المشكلة: السجلات تملأ القرص قم بإعداد تدوير السجلات باستخدام `logrotate`. تكوين لسجلات PHP: ``` /var/log/php_errors.log { daily rotate 30 compress delaycompress missingok notifempty create 644 www-data www-data } ``` ## الخطوة 9: مثال عملي: التحقيق في صفحة بيضاء تخيل موقفاً: تفتح موقعاً إلكترونياً وهو أبيض بالكامل. ماذا تفعل خطوة بخطوة؟ 1. **تحقق من سجلات خادم الويب** (Apache/Nginx) — غالباً ما تحتوي على تلميح 2. **تحقق من سجلات PHP** — ابحث عن إدخالات الدقائق القليلة الماضية ```bash tail -n 50 /var/log/php_errors.log | grep -A5 -B5 "$(date +%Y-%m-%d)" ``` 3. **اعثر على الخطأ** : ``` [2026-03-04 15:30:22] PHP Fatal error: Uncaught Error: Class 'DB' not found in /var/www/site/index.php on line 12 ``` 4. **افتح الملف**، تحقق من السطر 12 — بالفعل، لقد نسيت تضمين الكلاس. 5. **صححه**، اختبره — الموقع يعمل! سحر! ## مرجع سريع: ورقة الغش | الإجراء | الأمر / الكود | |---------|---------------| | تفعيل التسجيل في php.ini | `log_errors = On` + `error_log = /مسار/إلى/ملف` | | تفعيل في الكود | `ini_set('log_errors', 'On');` | | عرض آخر سطور | `tail -f /var/log/php_errors.log` | | البحث عن أخطاء فادحة | `grep "Fatal error" /var/log/php_errors.log` | | التقاط أخطاء فادحة | `register_shutdown_function()` + `error_get_last()` | | أين توجد سجلات Laravel؟ | `storage/logs/laravel.log` | | أين توجد سجلات Symfony؟ | `var/log/dev.log` و `var/log/prod.log` | ## بدلاً من الخاتمة PHP ليس مخيفاً كما يُصوَّر غالباً. نعم، الشاشة البيضاء للموت مرعبة، لكن خلفها دائماً خطأ محدد لا يريد التحدث فقط. تعلم تفعيل السجلات، وسيبدأ PHP في الكلام. القواعد الرئيسية: - في الإنتاج، **دائماً** فعّل `log_errors` وعطّل `display_errors` - اكتب السجلات في ملف مخصص، وليس في syslog — البحث أسهل - استخدم `register_shutdown_function` لالتقاط الأخطاء الفادحة - تحقق من سجلاتك بانتظام — مرة واحدة على الأقل يومياً وتذكر: الكود المثالي لا يكتب أخطاء. ولكن إذا حدث خطأ، فليترك على الأقل ملاحظة. ?>