مولد السلاسل العشوائية في PHP: ما تحت الغطاء

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مولد السلاسل العشوائية في PHP: كيف يعمل تحت الغطاء

\n\n

كل مطور واجه مرة على الأقل مهمة توليد سلسلة عشوائية. سواء للتوكنات، كلمات المرور المؤقتة، معرفات الجلسات، أو ببساطة لبيانات الاختبار. في PHP هناك عشرات الطرق لفعل ذلك، لكن أيها الصحيح؟ والأهم — لماذا؟

\n\n

سؤال «مولد السلاسل العشوائية في PHP» على Stack Overflow حصد آلاف المشاهدات ومئات الإجابات. لكن معظمها مجرد مقتطفات جاهزة بدون شرح. اليوم سننظر تحت غطاء PHP ونتعرف على كيفية عمل مولدات السلاسل العشوائية فعليًا، وما الفرق بين rand() و random_int()، ولماذا قد لا تكون كلمة المرور «العشوائية» الخاصة بك عشوائية على الإطلاق.

\n\n

ما هي «العشوائية» في PHP؟

\n\n

في البرمجة، هناك نوعان من العشوائية: العشوائية الزائفة و العشوائية المشفرة. الفرق بينهما كالفرق بين حجر النرد وآلة حاسبة قابلة للتنبؤ.

\n\n

الأرقام العشوائية الزائفة (PRNG) يتم توليدها بواسطة خوارزمية تعتمد على بذرة أولية (seed). إذا كنت تعرف البذرة — فأنت تعرف التسلسل بأكمله. للمهام البسيطة (عشوائية الألوان في التصميم، بيانات الاختبار) هذا كافٍ. لكن لتوكنات المصادقة وكلمات المرور — هذه كارثة.

\n\n

تقدم PHP عدة دوال، وكل منها يمثل مستوى مختلفًا من «العشوائية»:

\n\n
    \n
  • rand() — PRNG كلاسيكي، سريع لكن قابل للتنبؤ
  • \n
  • mt_rand() — خوارزمية Mersenne Twister المحسّنة، أسرع وبفترة أطول
  • \n
  • random_int() و random_bytes() — مولدات مشفرة (PHP 7+)
  • \n
  • openssl_random_pseudo_bytes() — خيار مشفر آخر
  • \n
\n\n

كيف يعمل المقتطف الأكثر شيوعًا؟

\n\n

هذا هو الكود الكلاسيكي المنتشر على الإنترنت:

\n\n
<?php\nfunction generateRandomString($length = 10) {\n    $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';\n    $charactersLength = strlen($characters);\n    $randomString = '';\n    for ($i = 0; $i < $length; $i++) {\n        $randomString .= $characters[rand(0, $charactersLength - 1)];\n    }\n    return $randomString;\n}\n?>
\n\n

للوهلة الأولى — يبدو منطقيًا. نأخذ سلسلة من الأحرف، نختار فهرسًا عشوائيًا، نكرر. لكن دعنا نحلل ما يحدث هنا فعليًا.

\n\n

المشكلة الأولى: rand() والبذرة الخاصة بها

\n\n

دالة rand() في PHP تستخدم افتراضيًا خوارزمية Linear Congruential Generator (LCG). وهي واحدة من أقدم وأكثر الطرق قابلية للتنبؤ. إذا لم تستدعِ srand() ببذرة عشوائية، يقوم PHP تلقائيًا بتهيئة المولد بالوقت الحالي (بالميكروثانية).

\n\n

بمعرفة الوقت الدقيق لتشغيل السكريبت (مثلًا من سجلات الخادم)، يمكن للمهاجم إعادة إنتاج تسلسل rand() بالكامل. بالنسبة لتوكن استعادة كلمة المرور — هذا طريق مباشر للاختراق.

\n\n

المشكلة الثانية: انحياز الاحتمالية (Bias)

\n\n

حتى لو تجاهلنا الأمان، هناك مشكلة رياضية. تخيل أن rand(0, 61) (62 حرفًا في السلسلة). PHP داخليًا يستخدم نطاقًا من 0 إلى getrandmax() (عادة 2147483647). 2147483647 لا يقبل القسمة على 62 بدون باقي. الباقي هو 31. هذا يعني أن أول 31 رقمًا في النطاق لها احتمالية ظهور أعلى قليلاً من البقية.

\n\n

عمليًا، الفرق ضئيل، لكن إذا كنت بحاجة إلى سلسلة عشوائية موزعة بالتساوي، فإن rand() ليس الخيار الأفضل. random_int() يحل هذه المشكلة باستخدام خوارزمية تضمن توزيعًا متساويًا.

\n\n

المولد المشفر: ما تحت الغطاء؟

\n\n

في PHP 7 ظهرت الدالتان random_int() و random_bytes(). تستخدمان مصدر الإنتروبيا الخاص بالنظام:

\n\n
    \

المدونات

توصيات الكتب