معرفات الأقسام: 1, 3, 7
أخطاء شائعة في كتابة الـ Regular Expressions (Regex) في PHP وكيف تتجنبها
يا هلا بيك يا صديقي المبرمج. أكيد في يوم من الأيام، وأنت شغال على مشروع بي إتش بي (PHP)، وقفك سياق معين محتاج validate لإيميل، أو استخراج أرقام تليفونات، أو تنضيف نص معين (Text Sanitization). أول حاجة جت في بالك إيه؟ بالضبط كده، التعبيرات النمطية أو الـ (Regular Expressions - Regex).
الـ (Regex) ده عامل زي السكينة الحادة؛ يا إما هيسهل عليك حياتك ويحللك مشاكل معقدة في سطر واحد، يا إما هيقلب بكارثة أمنية ويخلي السيرفر بتاعك (Server Performance) يضرب ويجيب آخرة بسبب البطء والـ (CPU Usage) العالي. تعال ناخد جولة سريعة وعميقة في نفس الوقت، ونشوف إيه هي أبرز الأخطاء اللي بنوقع فيها وإزiej نكتب (Regex) صح وآمن وسريع.
Table of contents [Show]
الخطأ الأول: الوقوع في فخ الـ (Catastrophic Backtracking)
المشكلة دي تعتبر كابوس لأي مبرمج بيستخدم (Regex). بتحصل لما بنكتب نمط (Pattern) يخلي المحرك (Regex Engine) يجرب عدد لا نهائي من الاحتمالات عشان يطابق النص، وده بيحصل غالباً لما بنستخدم تكرار متداخل زي (a+)+ أو (a|a)+.
تخيل معايا إنك بتعمل مطابقة لنص مش مطابق للاستركشر اللي طالبه الـ (Regex)، المحرك هيفضل يعمل (Backtracking) رايح جاي ملايين المرات، وده هيؤدي لبطء شديد في السيرفر أو تهنيج التطبيق بالكامل (Denial of Service). عشان نتجنب ده، لازم نبعد عن التكرارات المتداخلة ونستخدم حدود واضحة للنصوص زي الـ (Anchors).
مثال على كود غلط:
// كود كارثي ممكن يوقع السيرفر مع النصوص الطويلة
$pattern = '/^(a+)+$/';
preg_match($pattern, 'aaaaaaaaaaaaaaaaX');
الخطأ الثاني: إهمال استخدام الـ Delimiters والمعدلات (Modifiers) الصح
في لغة (PHP)، لما بنشتغل مع دوال الـ (PCRE) زي preg_match، لازم نحط النمط جوه (Delimiters)، والمشكلة إن ناس كتير بتستسهل وتختار أي رمز زي السلاش / من غير ما تاخد بالها إن النص لو فيه نفس الرمز، هيحصل خطأ (Error) أو سلوك غير متوقع، ده غير إننا بننسى أحياناً نستخدم المعدلات المهمة.
مثلاً، لو مش محدد حالة الأحرف (Case-Insensitive)، هتبص تجد نفسك كاتب أنماط معقدة عشان تغطي الحروف الكبيرة والصغيرة، في حين إن حرف الـ i كمعدل كان هيحل الموضوع في ثانية.
مثال كود صحيح لاستخدام المعدلات:
// استخدام الـ Delimiter المناسب والمعدل i لتجاهل حالة الأحرف
$pattern = '#^php[0-9]+$#i';
if (preg_match($pattern, 'PHP8')) {
echo "مطابق بنجاح!";
}
الخطأ الثالث: الاعتماد الكلي على الـ Regex في التحقق الأمني (Security Validation)
غلطة شائعة جداً، وهي إننا نعتبر الـ (Regex) هو خط الدفاع الوحيد ضد الـ (SQL Injection) أو الـ (XSS). الـ (Regex) أداة عظيمة للتحقق من شكل البيانات (Pattern Matching)، لكنه مش بديل للـ (Data Sanitization) ولا الـ (Prepared Statements).
لو بتتحقق من إيميل مثلاً، الـ (Regex) هيديك مؤشر إن الشكل العام صح، لكنه مش هيمنع هجمات تانية لو ما استخدمتش الدوال المخصصة زي filter_var($email, FILTER_VALIDATE_EMAIL) في (PHP) اللي بتعتبر أسهل وأضمن بكتير من كتابة (Regex) معقد للإيميلات.
الخطأ الرابع: نسيان الـ Anchors (بداية ونهاية النص)
لما تكتب نمط زي /cat/ من غير ما تحط علامات البداية ^ والنهاية $، الـ (Regex) هي بدور جوه النص وهيلاقي المطابقة لو كلمة (cat) موجودة في أي حتة جوه جملة طويلة زي (Concatenation). ده بيعمل ثغرات أحياناً لو أنت عايز تتأكد إن النص كله عبارة عن النمط ده بس مش مجرد جزء منه.
مثال للتوضيح:
// بدون Anchors، الكود ده هيقبل أي جملة فيها كلمة admin حتى لو في النص
$pattern = '/admin/';
// الصح لو عاوز تتأكد إن النص كله عبارة عن admin فقط:
$strictPattern = '/^admin$/';
الخاتمة ونصيحة من أخ
يا صديقي، الـ (Regex) ده فن وعلم، وكل ما مارسته كل ما بقيت أسرع وأدق فيه. نصيحتي ليك: متكتبش (Regex) معقد من دماغك كده وخلاص؛ استعين بأدوات أونلاين زي (Regex101) عشان تختبر الأنماط بتاعتك وتشوف هي بتستهلك كم خطوة (Steps)، ودايماً اسأل نفسك: هل أنا فعلاً محتاج (Regex) هنا ولا فيه دالة جاهزة في (PHP) هتعملي ده بطريقة أسرع وأكثر أماناً؟
خليك دايمًا مهتم بالأداء (Performance) وأمان السيرفر، وعاش يا مبرمج يا جامد!