انتقل إلى محتوى الدرس
الدرس 94
دورة PHP

بناء نظام تسجيل المستخدمين الكامل مع التحقق وقاعدة البيانات PDO في PHPBuilding a Complete PHP User Registration System with PDO

ابنِ نظام تسجيل مستخدمين متكاملاً في PHP 8 يجمع التحقق من CSRF وتنقية المدخلات وفحص عدم تكرار البريد وتشفير كلمة المرور وحفظها بـ PDO.
أقسام الدرس
6
الأمثلة
6
اللغة
العربية
تاريخ النشر
غير محدد
المشاهدات
0
محتوى الدرس
في هذا الدرس 6تصفّح المواضيع

يتطلب جدول المستخدمين users الآمن مفتاحاً أساسياً تلقائياً، وقيد تفرد UNIQUE على عمود البريد email، وعمود VARCHAR(255) لحفظ تجزئة كلمة المرور.

  • اجعل طول عمود كلمة المرور دائماً VARCHAR(255) حتى لا يتم اقتطاع أي تجزئة مستقبلية لـ Bcrypt أو Argon2id.
  • أضف قيد UNIQUE على مستوى قاعدة البيانات لعمود email لمنع تكرار الحسابات.
  • أضف عمود created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP لتوثيق وقت التسجيل.

تفرض الهيكلة قيد NOT NULL على جميع الحقول الأساسية وقيد UNIQUE على البريد الإلكتروني بترميز utf8mb4.

مخطط توضيحي: محاكي خطوات تسجيل المستخدمين والتحقق والحفظ بـ PDO
PHP
<?php

$sql = "CREATE TABLE IF NOT EXISTS users (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(190) NOT NULL UNIQUE,
    password_hash VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";

echo "Users DDL schema ready (" . strlen($sql) . " bytes)\n";

قبل الاتصال بقاعدة البيانات، هذّب الاسم والبريد بـ trim، وتحقق من صيغة البريد عبر filter_var، وافحص طول كلمة المرور وتطابق تأكيدها.

  • وحّد حالة أحرف البريد عبر strtolower(trim($_POST["email"] ?? "")) لمنع تكرار نفس البريد بأحرف كبيرة.
  • لا تستخدم trim مع كلمة المرور، ولكن تحقق من أن طولها لا يقل عن 8 محارف strlen($password) >= 8.
  • اجمع رسائل الخطأ لكل حقل في مصفوفة ترابطية $errors لعرضها تحت كل حقل.

اجتازت الحقول الثلاثة شروط التحقق وتم توحيد البريد الإلكتروني للأحرف الصغيرة.

PHP
<?php

$name = trim('Rami Adel');
$email = strtolower(trim('[email protected]'));
$pass = 'Secret#2026';
$confirm = 'Secret#2026';
$errors = [];

if ($name === '') $errors['name'] = 'Name is required.';
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) $errors['email'] = 'Invalid email.';
if (strlen($pass) < 8 || $pass !== $confirm) $errors['password'] = 'Invalid password.';
echo "Errors count: " . count($errors) . " | Normalized: $email\n";

استعلم من جدول users عبر استعلام محضر SELECT id FROM users WHERE email = :email LIMIT 1 لإظهار رسالة واضحة إذا كان البريد مسجلاً مسبقاً.

  • استخدم $stmt->fetchColumn() للتحقق مما إذا كان الاستعلام يرجع معرف مستخدم موجود.
  • حتى مع هذا الفحص المسبق، احتفظ بقيد UNIQUE في الجدول لمنع تضارب الطلبات المتزامنة.
  • التزم دائماً بالمعاملات المربوطة (:email) لمنع حقن SQL.

ترجع fetchColumn() معرف السجل المطابق، مما ينبه التطبيق بأن البريد مسجل بالفعل.

PHP
<?php

$pdo = new PDO('sqlite::memory:');
$pdo->exec('CREATE TABLE users (id INTEGER PRIMARY KEY, email TEXT UNIQUE)');
$pdo->exec("INSERT INTO users (email) VALUES ('[email protected]')");

$stmt = $pdo->prepare('SELECT id FROM users WHERE email = :email LIMIT 1');
$stmt->execute(['email' => '[email protected]']);
$exists = (bool) $stmt->fetchColumn();

echo $exists ? "Email already registered!\n" : "Email available.\n";

بمجرد نجاح التحقق، جزّئ كلمة المرور عبر password_hash($password, PASSWORD_DEFAULT) وأدرج السجل باستعلام PDO محضر.

  • لا تخزن أو تطبع أو تسجل كلمة المرور النصية الخام في أي مكان أبداً.
  • تولّد دالة password_hash() ملحاً تشفيرياً عشوائياً تلقائياً وتدمجه داخل النص الناتج.
  • احصل على معرف المستخدم الجديد عبر (int) $pdo->lastInsertId().

تمت تجزئة كلمة المرور بأمان قبل تنفيذ استعلام الإدراج المحضر، وأرجعت lastInsertId() المعرف 1.

مخطط تدفق التنفيذ العملي لقسم تشفير كلمة المرور وإدراج الحساب الجديد بأمان في لغة PHP
PHP
<?php

$pdo = new PDO('sqlite::memory:');
$pdo->exec('CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT, password_hash TEXT)');

$hash = password_hash('StrongPass!99', PASSWORD_DEFAULT);
$stmt = $pdo->prepare('INSERT INTO users (name, email, password_hash) VALUES (:n, :e, :p)');
$stmt->execute(['n' => 'Nour', 'e' => '[email protected]', 'p' => $hash]);

echo "Created User ID: " . $pdo->lastInsertId() . " (Hash len: " . strlen($hash) . ")\n";

بعد إنشاء الحساب، جدّد معرف الجلسة، وخزّن رسالة ترحيب مؤقتة في $_SESSION["flash"]، وأرسل تحويل 303 See Other.

  • التحويل بعد POST /register يمنع محاولة إعادة إرسال بيانات التسجيل عند تحديث الصفحة.
  • تدوير معرف الجلسة فور التسجيل يحمي المستخدم من ثغرات تثبيت الجلسة.
  • احذف رسالة التنبيه المؤقتة فور قراءتها وعرضها في صفحة الوجهة.

تُقرأ رسالة الترحيب مرة واحدة لعرضها للمستخدم ثم تُحذف فوراً من الجلسة عبر unset().

PHP
<?php

$_SESSION = [];
$_SESSION['user_id'] = 42;
$_SESSION['flash_success'] = 'Welcome aboard! Your account is ready.';

$flash = $_SESSION['flash_success'] ?? null;
unset($_SESSION['flash_success']);

echo "Flash Alert: $flash\n";
echo "Remaining Flash: " . (isset($_SESSION['flash_success']) ? 'Yes' : 'Cleared') . "\n";

راجع خطوات الأمان الست المتسلسلة اللازمة لبناء نقطة نهاية تسجيل مستخدمين جاهزة للإنتاج.

  • تحقق من توكن CSRF عبر hash_equals() قبل قراءة حقول النموذج.
  • وحّد صيغة البريد وتحقق من صحة الحقول وطول كلمة المرور.
  • جزّئ كلمة المرور بـ password_hash()، وأدرجها باستعلام PDO محضر، وحوّل المسار بنمط PRG.

تنفيذ هذه الخطوات الخمس بالترتيب يحمي من ثغرات CSRF وحقن SQL وتسرب كلمات المرور وتكرار الإرسال.

مرحلة التسجيلالأداة / الدالة في PHPالتهديد الأمني الذي تمنعه
CSRF Checkhash_equals($_SESSION["csrf"], $token)Cross-Site Request Forgery
Email Normalizationstrtolower(trim($email)) + FILTER_VALIDATE_EMAILDuplicate case variants & malformed emails
Password Hashingpassword_hash($pass, PASSWORD_DEFAULT)Plaintext & rainbow-table password leaks
PDO Prepared Insert$pdo->prepare("INSERT INTO users ...")SQL Injection (SQLi)
PRG Redirectheader("Location: /dashboard", true, 303)Duplicate POST form resubmission

PHP
<?php

$steps = [
    1 => 'Verify CSRF token (hash_equals)',
    2 => 'Validate & normalize inputs',
    3 => 'Check PDO email uniqueness',
    4 => 'Hash password & INSERT row',
    5 => 'Set flash & 303 Redirect (PRG)',
];
foreach ($steps as $n => $label) {
    echo "Step $n: $label\n";
}
خلاصة المعرفة ومحطة الانتقال

ملخص الدرس

حصاد الدرس

مراجعة مركّزة لأهم المفاهيم والقواعد الهندسية التي أتقنتها في هذا الدرس قبل التطبيق العملي

ماذا تعلّمت في هذا الدرس؟

راجع خطوات الأمان الست المتسلسلة اللازمة لبناء نقطة نهاية تسجيل مستخدمين جاهزة للإنتاج. تحقق من توكن CSRF عبر hash_equals() قبل قراءة حقول النموذج. وحّد صيغة البريد وتحقق من صحة الحقول وطول كلمة المرور. جزّئ كلمة المرور بـ password_hash()، وأدرجها باستعلام PDO محضر، وحوّل المسار بنمط PRG.

مشاركة

هل كان هذا الدرس مفيدًا؟

جارٍ تحميل الآراء…

ابنِ لغتك البرمجية

المصطلحات4

راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.

0 / 4 مفهومةأول بطاقة، أول خطوة
01 User Registration نظام تسجيل المستخدمين
ابنِ نظام تسجيل مستخدمين متكاملاً في PHP 8 يجمع التحقق من CSRF وتنقية المدخلات وفحص عدم تكرار البريد وتشفير كلمة المرور وحفظها بـ PDO.
للمراجعة
02 Designing the users Database Table تصميم جدول المستخدمين users في قاعدة البيانات
المفهوم الأساسي لقسم تصميم جدول المستخدمين users في قاعدة البيانات في لغة PHP الحديثة.
للمراجعة
03 Validating Registration Inputs and Rules التحقق من حقول التسجيل وتطابق كلمة المرور
الصياغة البرمجية والتطبيق العملي المباشر لقسم التحقق من حقول التسجيل وتطابق كلمة المرور.
للمراجعة
04 Checking Email Uniqueness with PDO فحص عدم مسجلية البريد الإلكتروني مسبقاً عبر PDO
قواعد التحقق وأفضل الممارسات القياسية الخاصة بقسم فحص عدم مسجلية البريد الإلكتروني مسبقاً عبر PDO.
للمراجعة

اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.

حروف قليلة. معنى كامل.

الاختصارات4

راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.

0 / 4 مفهومةأول بطاقة، أول خطوة
01 PHP PHP
PHP: Hypertext Preprocessor
لغة البرمجة النصية على جانب الخادم لبناء تطبيقات الويب الديناميكية وواجهات البرمجة.
للمراجعة
02 CLI CLI
Command-Line Interface
واجهة سطر الأوامر التي تتيح تشغيل ملفات PHP مباشرة عبر الطرفية.
للمراجعة
03 FPM FPM
FastCGI Process Manager
مدير عمليات FastCGI عالي الأداء لمعالجة طلبات خادم الويب في PHP.
للمراجعة
04 HTML HTML
HyperText Markup Language
لغة الترميز القياسية التي يولدها محرك PHP ويرسلها إلى متصفح العميل بعد التنفيذ.
للمراجعة

اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.

من الفهم للتطبيق

مهامك قبل الاختبار

خطوة صغيرة كل مرة. وإنجاز تقدر ترجع له.

0/2مهام منجزة
  1. أنشئ ملف PHP محلياً ونفّذ المثال البرمجي المشروح في قسم تصميم جدول المستخدمين users في قاعدة البيانات للتحقق من المخرجات.

  2. بدّل بين الحالات الثلاث في المحاكي التفاعلي ضمن قسم التحقق من حقول التسجيل وتطابق كلمة المرور وقارن مخرجات التنفيذ.

تأشير المهمة إقرار منك بإتمامها، وليس تصحيحًا آليًا للكود. يُحفظ تقدمك في حسابك.

مساحة التحدي

اختبر فهمك.
ووصلها للإتقان.

كل سؤال خطوة لقدّام. اختار، اكتب كود، وشوف نتيجتك فورًا.

8أسئلة 1أنواع تحديات 100%هدف الإتقان
تصحيح تلقائي. فرص بلا حدود.

أكمل المهام، واجمع كل الإجابات الصحيحة. أقل من 100%؟ راجع وأعد المحاولة.

الأسئلة متاحة للاطلاع. سجّل الدخول للتفاعل وحفظ تقدمك.

لمحة عن التحدي8 أسئلة تنتظرك
01

ما طول العمود الموصى به لتخزين مخرجات الدالة password_hash() في جدول المستخدمين بقاعدة البيانات؟

يوصي دليل PHP الرسمي بطول VARCHAR(255) لاستيعاب تجزئة Bcrypt وArgon2id الأطول مستقبلاً.

02

لماذا يجب توحيد البريد المدخل عبر strtolower(trim($email)) قبل فحص عدم تكراره وحفظه؟

يضمن التوحيد معاملة [email protected] و[email protected] كبريد إلكتروني واحد.

03

لماذا لا ينبغي أبداً تطبيق دالة trim() على كلمة مرور المستخدم قبل تجزئتها؟

تعديل كلمة المرور بصمت قبل التجزئة يربك المستخدم إذا اعتمد على مسافات مقصودة.

04

لماذا يظل وجود قيد UNIQUE على عمود البريد في قاعدة البيانات ضرورياً حتى لو قام PHP بفحص SELECT أولاً؟

فقط قيد UNIQUE في قاعدة البيانات هو الذي يضمن عدم التكرار الذري عند تزامن الطلبات.

05

أي دالة في PDO ترجع المعرف التلقائي (ID) للمستخدم المسجل حديثاً فور تنفيذ INSERT؟

ترجع lastInsertId() آخر معرف تلقائي تم توليده في نفس الاتصال.

06

ما الحقول التي يجب الاحتفاظ بها كمدخلات سابقة عند إعادة التوجيه بعد خطأ في نموذج التسجيل؟

لا يجوز أبداً تخزين كلمات المرور في الجلسة أو إعادة طباعتها في خاصية value داخل HTML.

07

ماذا تتضمن السلسلة النصية التي ترجعها الدالة password_hash("Secret123", PASSWORD_DEFAULT)؟

دمج الخوارزمية والتكلفة والملح يسمح لدالة password_verify() بالتحقق دون الحاجة لعمود ملح منفصل.

08

لماذا يجب أن يقوم معالج التسجيل بالتحويل عبر الرمز 303 See Other بعد إدراج المستخدم الجديد؟

يلزم الرمز 303 المتصفح بتحويل الطلب التالي إلى GET آمن.