المحطّة ٥: إدارة المهامّ — CRUD لكل مستخدم
قلب المنتج: أضِف واعرض وعدّل مهامّك — ولا أحد يرى مهامّك سواك. ⏱ نحو 28 دقيقة.
- تنفّذ أفعال
CRUDالأربعة بـPDOوالمعاملات المُعدّة. - تقيّد كل استعلامٍ بصاحب البيانات عبر
user_idمن الجلسة. - تحمي كل صفحةٍ بحارس جلسةٍ في أعلاها.
- تتحقّق من المدخلات وتمنع العبث بمهامّ مستخدمٍ آخر.
١CRUD: الأفعال الأربعة لأيّ تطبيق
جوهر أيّ تطبيقٍ يدير بياناتٍ أربعة أفعال، نختصرها CRUD:
| الفعل | بالعربيّة | SQL | في مشروعنا |
|---|---|---|---|
| Create | إنشاء | INSERT | إضافة مهمّة |
| Read | قراءة | SELECT | عرض قائمة المهامّ |
| Update | تعديل | UPDATE | تعليم مهمّةٍ منجَزة |
| Delete | حذف | DELETE | حذف مهمّة |
شرطٌ واحدٌ يتكرّر في كل فعلٍ ويحمي خصوصيّة المستخدم: WHERE user_id = ? بقيمة $_SESSION['uid']. به «يرى كلٌّ مهامّه فقط» — وهو أهمّ متطلّبٍ في مشروعنا.
٢حارس الصفحة المحميّة
كل صفحةٍ تدير مهامًّا يجب أن تبدأ بالتأكّد من أنّ المستخدم داخلٌ فعلًا. نكرّر هذا «الحارس» في أعلى كل صفحة:
<?phpsession_start();require __DIR__ . '/db.php';if (!isset($_SESSION['uid'])) { http_response_code(401); echo 'سجّل الدخول أوّلًا'; exit; }$uid = $_SESSION['uid']; // هويّة صاحب المهامّ في كل استعلام
٣اعرض وأضِف — مقيّدًا بصاحب المهامّ
نجرّب دورةً: ندخل باسم sarah، نعرض مهامّها (ثلاث)، نضيف واحدةً، ثم نعرض من جديد (أربع). لاحظ أنّ كل استعلامٍ يحمل $uid:
<?phpsession_start();require __DIR__ . '/db.php';if (!isset($_SESSION['uid'])) { echo 'سجّل الدخول أوّلًا'; exit; } $st = $pdo->prepare('SELECT id, title, done FROM tasks WHERE user_id = ? ORDER BY id');$st->execute([$_SESSION['uid']]);foreach ($st->fetchAll() as $t) { $mark = $t['done'] ? '[✓]' : '[ ]'; echo "{$mark} {$t['title']}\n";}
<?phpsession_start();require __DIR__ . '/db.php';if (!isset($_SESSION['uid'])) { echo 'سجّل الدخول أوّلًا'; exit; } $title = trim($_POST['title'] ?? '');if ($title === '') { echo 'العنوان مطلوب'; exit; } $st = $pdo->prepare('INSERT INTO tasks (user_id, title, done, created_at) VALUES (?, ?, 0, ?)');$st->execute([$_SESSION['uid'], $title, date('Y-m-d')]);echo 'أُضيفت';
<?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']; echo "ok";} else { echo "no"; }
<?php$pdo = new PDO('sqlite:' . __DIR__ . '/tasks.sqlite');$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
توقّع وتحقّق
ما الشرط الذي يجعل «كلٌّ يرى مهامّه فقط»؟
أيّ أمر SQL لتعليم مهمّةٍ منجَزة؟
لماذا نضيف AND user_id = ? في التعديل والحذف؟
ما أوّل ما تفعله الصفحة المحميّة؟
الخلاصة
CRUD = INSERT/SELECT/UPDATE/DELETE= أضِف/اعرض/عدّل/احذف.- كل استعلامٍ يحمل
WHERE user_id= ? بقيمة $_SESSION['uid']— به يُعزَل كل مستخدم. - حارس الجلسة في أعلى كل صفحةٍ محميّةٍ يمنع الوصول بلا دخول.
- التعديل/الحذف يضيفان
AND user_id= ? لمنع العبث بمهامّ الغير. - تحقّق من المدخلات (عنوانٌ غير فارغٍ) قبل الكتابة في القاعدة.
تحدٍّ برمجي: إدارة المهامّ لكل مستخدم
برمجيابنِ قلب المشروع: صفحاتٌ تدير مهامّ المستخدم الحاليّ فقط — عرضٌ وإضافةٌ وتعليمٌ كمنجَز. كل استعلامٍ مقيّدٌ بصاحب المهامّ.
list.php: يعرض مهامّ المستخدم الحاليّ فقط، كلٌّ بعلامة[✓]أو[ ]ثم العنوان.add.php(POST title): يضيف مهمّةً للمستخدم الحاليّ (غير منجَزة)، ويطبعأُضيفت؛ ويرفض العنوان الفارغ.toggle.php(POST id): يقلب حالة الإنجاز لمهمّةٍ يملكها المستخدم، ويطبعتمّ.- كل صفحةٍ تبدأ بحارس الجلسة، وكل استعلامٍ مُعدٌّ ومقيّدٌ بـ user_id.
👀 اعرض الاستجابة المطلوبة
POST /login.php(username=sarah&password=sarah123)GET /list.phpPOST /add.php(title=اجتماع الفريق)GET /list.phpPOST /toggle.php(id=1)GET /list.php
- الكود يعمل بلا أخطاء أو تحذيرات
- يعرض مهامّ sarah
- لا يعرض مهامّ مستخدمٍ آخر
- الإضافة تعمل وتظهر في القائمة
- التعليم كمنجَز يقلب الحالة
- العلامة تظهر للمهامّ غير المنجَزة
💡 تلميح 1
$_SESSION["uid"] كمعاملٍ مُعدّ.💡 تلميح 2
UPDATE tasks SET done = 1 - done WHERE id = ? AND user_id = ? — الشرط الثاني يمنع العبث بمهامّ الغير.💡 تلميح 3
$t["done"] ? "[✓]" : "[ ]".حاول بنفسك أولًا؛ للمسألة أكثر من حلّ صحيح.
<?phpsession_start();require __DIR__ . '/db.php';if (!isset($_SESSION['uid'])) { echo 'سجّل الدخول أوّلًا'; exit; } $st = $pdo->prepare('SELECT id, title, done FROM tasks WHERE user_id = ? ORDER BY id');$st->execute([$_SESSION['uid']]);foreach ($st->fetchAll() as $t) { $mark = $t['done'] ? '[✓]' : '[ ]'; echo "{$mark} {$t['title']}\n";}
<?phpsession_start();require __DIR__ . '/db.php';if (!isset($_SESSION['uid'])) { echo 'سجّل الدخول أوّلًا'; exit; } $title = trim($_POST['title'] ?? '');if ($title === '') { echo 'العنوان مطلوب'; exit; }$st = $pdo->prepare('INSERT INTO tasks (user_id, title, done, created_at) VALUES (?, ?, 0, ?)');$st->execute([$_SESSION['uid'], $title, date('Y-m-d')]);echo 'أُضيفت';
<?phpsession_start();require __DIR__ . '/db.php';if (!isset($_SESSION['uid'])) { echo 'سجّل الدخول أوّلًا'; exit; } $st = $pdo->prepare('UPDATE tasks SET done = 1 - done WHERE id = ? AND user_id = ?');$st->execute([$_POST['id'] ?? 0, $_SESSION['uid']]);echo 'تمّ';
<?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']; echo "ok";} else { echo "no"; }
<?php$pdo = new PDO('sqlite:' . __DIR__ . '/tasks.sqlite');$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);