طَبِّقْهاتعلّم المبدأ، وطبّقه بيدكمقرر 132 · تقنيات تطوير الواجهات الخلفية
الدرس 7 · الوحدة 3: تنفيذ منطق التطبيق واستجابة الطلبات

التحقق من بيانات الطلب ورموز الاستجابة

خط الدفاع الحقيقي: تحقّق من كل ما يصل، وأجب بالرمز الصحيح. ⏱ نحو 35 دقيقة.

بعد هذا الدرس ستستطيع أن:
  • تشرح لماذا التحقق في الخادم إلزامي.
  • تتحقق من الحقول بخطواتها: الوجود والتنظيف والإلزام والشكل والحدود.
  • ترد برمز الحالة المناسب: 200 و201 و405 و422.
  • تعيد عرض النموذج بقيم المستخدم، وتطبّق نمط POST ثم التحويل.

١لا تثق بأي شيء يصل من الطلب

النموذج في المتصفح قد يكون فيه required و type="email"، فهل يكفي ذلك؟ لا. التحقق في المتصفح لراحة المستخدم فقط، لأن أي شخص يستطيع إرسال طلب مباشرة للخادم متجاوزًا النموذج كله: بأداة مثل Postman، أو من تبويب «📮 طلب يدوي» في مختبرنا.

التحقق في المتصفح (131)التحقق في الخادم
هدفهتجربة استخدام أفضل وتنبيه فوريحماية البيانات ومنطق التطبيق
هل يمكن تجاوزه؟نعم، بسهولةلا: كل الطلبات تمر عليه
هل يكفي وحده؟لانعم، وهو إلزامي

والقاعدة: تحقّق من كل حقل على الخادم، كأن النموذج غير موجود أصلًا.

٢خطوات التحقق

  1. الوجود: هل وصل الحقل؟ $_POST['x'] ?? ''
  2. التنظيف: احذف المسافات الزائدة بـ trim.
  3. الإلزام: هل هو فارغ؟ $x === ''
  4. الشكل والنوع: بريد صحيح؟ عدد؟ تاريخ؟ بـ filter_var.
  5. الحدود: الطول بـ mb_strlen، والمدى (العمر بين 16 و60)، والقيم المسموحة بـ in_array.
  6. الرد: إن وُجدت أخطاء اجمعها كلها وأعدها برمز مناسب، وإلا فنفّذ العملية.

الدالة filter_var تتحقق من الشكل، وتعيد القيمة الصحيحة أو false:

<?phpvar_dump(filter_var("saud@tvtc.gov.sa", FILTER_VALIDATE_EMAIL));var_dump(filter_var("saud@", FILTER_VALIDATE_EMAIL));var_dump(filter_var("25", FILTER_VALIDATE_INT));var_dump(filter_var("25abc", FILTER_VALIDATE_INT));var_dump(filter_var("70", FILTER_VALIDATE_INT, ['options' => ['min_range' => 16, 'max_range' => 60]]));var_dump(in_array("كبير", ["صغير", "وسط", "كبير"]));

٣اجمع الأخطاء وردّ بالرمز المناسب

لا تتوقف عند أول خطأ؛ اجمعها كلها في مصفوفة، ليصلح المستخدم كل شيء مرة واحدة. ثم اختر رمز الحالة الذي يصف النتيجة:

الرمزمتى؟
200 OKنجح الطلب (عرض أو تعديل).
201 Createdنجح وأُنشئ عنصر جديد (تسجيل، إضافة).
400 Bad Requestالطلب نفسه مشوّه أو ناقص بشكل لا يُفهم.
422 Unprocessable Contentالطلب مفهوم لكن البيانات لم تجتز التحقق.
405 Method Not Allowedطريقة غير مقبولة، مثل GET على ملف يقبل POST فقط.
<?php$errors = [];$name  = trim($_POST['name'] ?? '');$email = trim($_POST['email'] ?? '');$age   = $_POST['age'] ?? ''; if ($name === '') {    $errors[] = 'الاسم مطلوب.';} elseif (mb_strlen($name) < 3) {    $errors[] = 'الاسم قصير جدًّا.';}if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {    $errors[] = 'البريد الإلكتروني غير صحيح.';}if (filter_var($age, FILTER_VALIDATE_INT, ['options' => ['min_range' => 16, 'max_range' => 60]]) === false) {    $errors[] = 'العمر يجب أن يكون عددًا من 16 إلى 60.';} if ($errors) {    http_response_code(422);    echo "<ul>";    foreach ($errors as $e) echo "<li>$e</li>";    echo "</ul>";} else {    http_response_code(201);    echo "<p>✓ تم تسجيل " . htmlspecialchars($name) . "</p>";}

الطلب الأول فيه ثلاثة أخطاء فعاد بها كلها مع 422، والثاني سليم فعاد بـ 201. جرّب في المختبر إرسال طلب بلا أي حقول.

٤النموذج اللاصق: لا تجعل المستخدم يكتب من جديد

إن أخطأ المستخدم في حقل واحد ثم عاد له النموذج فارغًا، سيغضب. أعد عرض النموذج بالقيم التي كتبها مع رسالة بجانب الحقل الخاطئ. ولاحظ: القيمة المعادة تمر على htmlspecialchars لأنها من المستخدم:

🧪 مختبر الخادمأرسل النموذج بحرفين فقط في الاسم، وراقب أن الاسم والمدينة بقيا في مكانهما مع رسالة الخطأ.

exit توقف تنفيذ الملف فورًا، فلا يُطبع النموذج بعد رسالة النجاح.

٥بعد POST الناجح: حوّل ولا تعرض

مشكلة: بعد إرسال طلب شراء بنجاح، يضغط المستخدم «تحديث» فيرسل المتصفح الطلب نفسه مرة أخرى… فيتكرر الشراء! الحل نمط مشهور اسمه POST ثم تحويل ثم GET (PRG): بعد نجاح POST لا تعرض صفحة، بل أرسل ترويسة Location برمز 303، فيطلب المتصفح صفحة التأكيد بـ GET:

<?phpif ($_SERVER['REQUEST_METHOD'] !== 'POST') {    http_response_code(405);    exit('هذه الصفحة تقبل POST فقط');}$item = $_POST['item'] ?? '';// … هنا نحفظ الطلب …header('Location: thanks.php?item=' . urlencode($item), true, 303);exit;

الطلب الأول ردّ بـ 303 وفيه Location، فطلب المتصفح thanks.php (الطلب الثاني). والآن «تحديث» الصفحة يعيد GET لـ thanks.php فقط. والطلب الثالث يبيّن 405 حين تُفتح order.php مباشرة.

توقّع وتحقّق

التحقق في المتصفح وحده:

الخادم هو خط الدفاع الحقيقي.

بيانات مفهومة لكنها لم تجتز التحقق. الرمز الأنسب:

Unprocessable Content.

filter_var("abc", FILTER_VALIDATE_INT) تعيد:

ليست عددًا صحيحًا.

الهدف من نمط PRG:

POST ثم Redirect ثم GET.

الخلاصة

تحدٍّ برمجي: التحقق من طلب حجز قاعة

متوسط

نظام حجز قاعات التدريب يستقبل POST فيه: room (رقم القاعة)، و hours (عدد الساعات)، و email. اكتب التحقق.

المطلوب:
  • القاعات المسموحة: 101 و 102 و 201 فقط. وإلا فالخطأ: <li>القاعة غير موجودة</li>
  • الساعات عدد صحيح من 1 إلى 4. وإلا: <li>الساعات من 1 إلى 4</li>
  • البريد صحيح الشكل. وإلا: <li>البريد غير صحيح</li>
  • إن وُجدت أخطاء: رمز 422 وكل الأخطاء داخل <ul>. وإن صح كل شيء: رمز 201 والنص <p>تم حجز القاعة 101 لمدة 2 ساعات</p>
  • إن لم يكن الطلب POST: رمز 405.
👀 اعرض الاستجابة المطلوبة
✓ التحقق الآلي: يرسل المختبر هذه الطلبات إلى خادمك بالترتيب ثم يفحص الاستجابات
  1. POST /book.php (room=101&hours=2&email=a@tvtc.sa)
  2. POST /book.php (room=999&hours=9&email=bad)
  3. POST /book.php (room=201&hours=0&email=b@tvtc.sa)
  4. GET /book.php
  5. POST /book.php
  • الكود يعمل بلا أخطاء أو تحذيرات
  • طلب سليم ← 201
  • طلب سليم ← تم حجز القاعة 101 لمدة 2 ساعات
  • ثلاثة أخطاء ← 422
  • ثلاثة أخطاء ← تظهر الرسائل الثلاث
  • hours=0 ← الساعات من 1 إلى 4 فقط
  • hours=0 ← لا تظهر أخطاء القاعة والبريد
  • GET ← 405
  • POST فارغ ← 422 بلا تحذيرات

💡 تلميح 1
اجمع الأخطاء في $errors = []; ثم if ($errors) بعد كل الفحوص.
💡 تلميح 2
لاحظ أن hours=0: استخدم === false مع filter_var.
💡 تلميح 3
كل حقل بـ ?? حتى لا يظهر تحذير في الطلب الفارغ.

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

<?phpif ($_SERVER['REQUEST_METHOD'] !== 'POST') {    http_response_code(405);    exit('POST فقط');}$room = $_POST['room'] ?? '';$hours = $_POST['hours'] ?? '';$email = trim($_POST['email'] ?? '');$errors = []; if (!in_array($room, ['101', '102', '201'], true)) {    $errors[] = 'القاعة غير موجودة';}if (filter_var($hours, FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 4]]) === false) {    $errors[] = 'الساعات من 1 إلى 4';}if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {    $errors[] = 'البريد غير صحيح';} if ($errors) {    http_response_code(422);    echo "<ul>";    foreach ($errors as $e) {        echo "<li>$e</li>";    }    echo "</ul>";} else {    http_response_code(201);    echo "<p>تم حجز القاعة $room لمدة $hours ساعات</p>";}
انتقل إلى تقييم الدرساختيار من متعدد، وصح وخطأ، وأكمل الفراغ، وتتبّع الناتج.ابدأ التقييم ←

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