طَبِّقْهاتعلّم المبدأ، وطبّقه بيدكمقرر 301 · من الفكرة إلى المنتج (١): تطبيق ويب متكامل
الدرس 4 · الوحدة 2: بناء المنتج

المحطّة ٤: التسجيل والدخول — الجلسات وتعمية كلمة المرور

بوّابة المشروع: حسابٌ آمنٌ وجلسةٌ تعرف «مَن المستخدم الحاليّ». ⏱ نحو 28 دقيقة.

بعد هذا الدرس ستستطيع أن:
  • تعمّي كلمات المرور بـ password_hash وتتحقّق بـ password_verify.
  • تفتح جلسةً بـ session_start وتخزّن هويّة المستخدم في $_SESSION.
  • تبني تسجيلًا ودخولًا وخروجًا آمنًا متكاملًا.
  • تتجنّب كشف أسباب الفشل ورسائل الخطأ المُسرِّبة.

١القاعدة الذهبيّة: لا تحفظ كلمة المرور أبدًا

كما تعلّمت في مقرّر 243، كلمة المرور الصريحة لا تُحفظ في القاعدة قطّ. لو سُرِّبت القاعدة انكشفت حسابات الجميع — وكثيرٌ منهم يستخدم الكلمة نفسها في بنكه وبريده.

الحلّ: نحفظ تعميةً (hash) لا يمكن عكسها. عند الدخول نعمّي ما أدخله المستخدم ونقارن التعميتين. PHP توفّر دالّتين جاهزتين آمنتين:

<?php$hash = password_hash('noura123', PASSWORD_DEFAULT);   // عند التسجيل: نحفظ هذاecho $hash, "\n"; var_dump(password_verify('noura123', $hash));          // عند الدخول: صحيح؟var_dump(password_verify('wrong',   $hash));           // كلمة خاطئة

٢الجلسة: كيف «يتذكّر» الموقع أنك داخل؟

HTTP بلا ذاكرة: كل طلبٍ منفصل. فكيف يعرف الخادم أنك المستخدم نفسه عبر الصفحات؟ عبر الجلسة (Session): عند الدخول نحفظ معرّف المستخدم في $_SESSION، ويرسل الخادم للمتصفّح كوكيًّا يحمله في كل طلبٍ لاحق.

<?phpsession_start();                 // أوّل سطرٍ في كل صفحةٍ تستخدم الجلسة$_SESSION['uid'] = $user['id'];  // عند نجاح الدخول: احفظ هويّة المستخدم// في أيّ صفحةٍ محميّة:if (!isset($_SESSION['uid'])) { echo 'سجّل الدخول أوّلًا'; exit; }

$_SESSION['uid'] هو مفتاح مشروعنا كلّه: به نعرف «مَن الطالب الحاليّ»، ومنه نجلب مهامّه هو فقط في المحطّة القادمة.

٣دخولٌ يعمل: من النموذج إلى الجلسة

نجرّب دورةً كاملة: نسجّل الدخول باسم sarah (موجودةٌ في بيانات التجربة، كلمتها sarah123)، ثم نفتح صفحةً محميّةً تقرأ الجلسة:

<?phpsession_start();require __DIR__ . '/db.php'; $st = $pdo->prepare('SELECT * FROM users WHERE username = ?');$st->execute([$_POST['username'] ?? '']);$user = $st->fetch(); if ($user && password_verify($_POST['password'] ?? '', $user['pass_hash'])) {    $_SESSION['uid'] = $user['id'];    $_SESSION['username'] = $user['username'];    echo "مرحبًا {$user['username']}";} else {    echo "بيانات غير صحيحة";}

لاحظ: الطلب الثاني (me.php) عرف المستخدم دون إرسال كلمة مرورٍ — لأن الكوكي يحمل الجلسة. والطلب الثالث بكلمةٍ خاطئةٍ رُفِض.

توقّع وتحقّق

كيف نحفظ كلمة المرور بأمان؟

ما وظيفة session_start()؟

عند فشل الدخول، ما الرسالة الأأمن؟

لا تكشف أيّ الحقلين أخطأ.

أين نخزّن هويّة المستخدم بعد نجاح الدخول؟

الجلسة تبقى عبر الطلبات.

الخلاصة

تحدٍّ برمجي: التسجيل والدخول

برمجي

ابنِ مصادقة مشروعك: صفحة تسجيلٍ تنشئ حسابًا بكلمة مرورٍ مُعمّاة، وصفحة دخولٍ تتحقّق وتفتح جلسة، وصفحة تعرف المستخدم الحاليّ، وخروجٌ ينهي الجلسة.

المطلوب:
  • register.php (POST): يعمّي كلمة المرور بـ password_hash، يُدرج المستخدم، يفتح الجلسة، ويطبع تم إنشاء الحساب: الاسم.
  • login.php (POST): يتحقّق بـ password_verify؛ عند النجاح يطبع مرحبًا الاسم، وإلّا بيانات غير صحيحة.
  • me.php (GET): يطبع أنت: الاسم إن كان داخلًا، وإلّا زائر.
  • logout.php (GET): ينهي الجلسة ويطبع خرجت.
👀 اعرض الاستجابة المطلوبة
✓ التحقق الآلي: يرسل المختبر هذه الطلبات إلى خادمك بالترتيب ثم يفحص الاستجابات
  1. POST /register.php (username=noura&password=noura123)
  2. GET /me.php
  3. GET /logout.php
  4. GET /me.php
  5. POST /login.php (username=noura&password=noura123)
  6. POST /login.php (username=noura&password=wrong)
  • الكود يعمل بلا أخطاء أو تحذيرات
  • التسجيل يعمّي ويُنشئ الحساب
  • الجلسة تتذكّر المستخدم بعد التسجيل
  • الخروج ثم me يعيد «زائر»
  • الدخول بكلمةٍ صحيحةٍ ينجح
  • الدخول بكلمةٍ خاطئةٍ يُرفَض برسالةٍ محايدة
  • لا يكشف كلمة المرور في أيّ ردّ

💡 تلميح 1
التسجيل: password_hash ثم INSERT ثم $_SESSION، واستخدم lastInsertId للمعرّف الجديد.
💡 تلميح 2
الدخول: اجلب المستخدم بـ prepare، ثم password_verify($_POST[...], $user["pass_hash"]).
💡 تلميح 3
الخروج: session_destroy()؛ وصفحة me تقرأ $_SESSION["username"].

حاول بنفسك أولًا؛ للمسألة أكثر من حلّ صحيح.

<?phpsession_start();require __DIR__ . '/db.php'; $u = trim($_POST['username'] ?? '');$p = $_POST['password'] ?? '';$hash = password_hash($p, PASSWORD_DEFAULT); $st = $pdo->prepare('INSERT INTO users (username, pass_hash, created_at) VALUES (?, ?, ?)');$st->execute([$u, $hash, date('Y-m-d')]); $_SESSION['uid'] = $pdo->lastInsertId();$_SESSION['username'] = $u;echo "تم إنشاء الحساب: {$u}";

🐞 لاحظت خطأً في هذا الدرس؟ أبلغني بالبريد

📝 معلم؟ أرسل ملاحظة للمؤلف عن هذا الدرس