في هذا الدرس 6تصفّح المواضيع
يتيح تمرير عنصر <form> إلى الكائن new FormData(form) في JavaScript تجميع كافة حقول النموذج تلقائياً وإرسالها بحيث تملأ مصفوفتي $_POST و$_FILES في PHP مباشرة!
- استدعِ
event.preventDefault()داخل مستمع الحدثsubmitلمنع المتصفح من إعادة تحميل الصفحة تقليدياً. - مرر
body: new FormData(form)إلى دالةfetch(form.action, { method: "POST", body }). - عند إرسال كائن
FormData، لا تضبط رأس الطلبContent-Typeيدوياً؛ لأن المتصفح يضبطه تلقائياً مع رمز الفاصلboundaryالصحيح.
لأن كائن FormData يستخدم ترميز النماذج القياسي، يقرأ ملف PHP الحقول مباشرة عبر $_POST["name"] و$_POST["subject"] دون تعقيد.
<?php
// PHP receives FormData fields directly inside $_POST
$_POST = [
'name' => 'Nadia',
'subject' => 'AJAX Form Inquiry',
];
$name = trim((string) ($_POST['name'] ?? ''));
$subject = trim((string) ($_POST['subject'] ?? ''));
echo json_encode([
'ok' => true,
'received' => "$name: $subject",
]) . "\n";
بدلاً من تحويل المسار عند فشل التحقق، يضبط معالج نماذج AJAX رمز الحالة http_response_code(422) ويُرجع مصفوفة أخطاء errors مفهرسة باسم كل حقل.
- اجمع رسائل الخطأ لكل حقل في مصفوفة ترابطية مثل
$errors["email"] = "البريد الإلكتروني غير صالح.". - إذا لم تكن مصفوفة
$errorsفارغة، أرسل رمز الحالة422مع كائن{"ok": false, "errors": $errors}. - تمر الواجهة الأمامية على مفاتيح
data.errors، وتضبط الخاصيةaria-invalid="true"لكل حقل خاطئ وتعرض رسالته تحته مباشرة.
يتيح إرجاع جميع أخطاء الحقول دفعة واحدة في استجابة 422 للمستخدم تصحيح كافة المدخلات دون فقدان ما كتبه في النموذج.
<?php
$_POST = ['email' => 'not-an-email', 'comment' => 'Hi'];
$errors = [];
if (!filter_var($_POST['email'] ?? '', FILTER_VALIDATE_EMAIL)) {
$errors['email'] = 'Please enter a valid email address.';
}
if (mb_strlen(trim((string) ($_POST['comment'] ?? ''))) < 10) {
$errors['comment'] = 'Comment must be at least 10 characters.';
}
http_response_code(422);
echo json_encode(['ok' => false, 'errors' => $errors]) . "\n";
تشارك طلبات AJAX المرسلة بطرق POST وPUT وDELETE كوكيز جلسة المستخدم، ولذلك تتطلب التحقق من توكن CSRF تماماً كالنماذج التقليدية.
- في نماذج
FormData، يُرسل الحقل المخفي<input type="hidden" name="csrf_token">تلقائياً ويُقرأ من$_POST["csrf_token"]. - في طلبات JSON، اقرأ التوكن من وسم
<meta name="csrf-token" content="...">وأرسله في رأس الطلبX-CSRF-Token. - يحوّل PHP اسم الرأس
X-CSRF-Tokenتلقائياً ليصبح متاحاً داخل المصفوفة$_SERVER["HTTP_X_CSRF_TOKEN"].
يتيح استخدام سلسلة دمج الفارغ $_POST["csrf_token"] ?? $_SERVER["HTTP_X_CSRF_TOKEN"] ?? "" دعم كل من نماذج FormData وطلبات JSON المرسلة برأس مخصص.
<?php
$_SESSION['csrf_token'] = '7f4e9a2c1b8d6035';
$_SERVER['HTTP_X_CSRF_TOKEN'] = '7f4e9a2c1b8d6035';
$candidate = (string) ($_POST['csrf_token'] ?? $_SERVER['HTTP_X_CSRF_TOKEN'] ?? '');
$sessToken = $_SESSION['csrf_token'] ?? '';
$valid = ($sessToken !== '') && hash_equals($sessToken, $candidate);
echo json_encode(['ok' => $valid, 'csrf_verified' => $valid]) . "\n";
من أشهر التطبيقات العملية لتكامل PHP و AJAX بناء نظام استطلاع رأي تفاعلي يصوت فيه المستخدم فتظهر له نسب التصويت المحدثة فوراً دون مغادرة الصفحة.
- تحقق من أن معرف الخيار المرسل
option_idعدد صحيح وموجود ضمن خيارات الاستطلاع المتاحة. - زِد عداد الأصوات في قاعدة البيانات باستعلام محضر ذري
UPDATE poll_options SET votes = votes + 1 WHERE id = :id. - احسب النسبة المئوية لكل خيار عبر
round(($votes / max(1, $total)) * 100, 1)وأرجع النتائج المحدثة بصيغة JSON.
يحمي استخدام max(1, $total) من خطأ القسمة على صفر، وتضمن array_values() إخراج مصفوفة JSON مرقمة بانتظام.
<?php
$options = [
1 => ['label' => 'PHP 8.4', 'votes' => 78],
2 => ['label' => 'TypeScript', 'votes' => 30],
];
$votedId = 1;
$options[$votedId]['votes']++;
$total = array_sum(array_column($options, 'votes'));
foreach ($options as &$opt) {
$opt['percent'] = round(($opt['votes'] / max(1, $total)) * 100, 1);
}
echo json_encode(['ok' => true, 'total' => $total, 'options' => array_values($options)]) . "\n";
غالباً ما ينقر المستخدمون مرتين على زر الإرسال عند بطء الشبكة؛ لذا اجمع بين تعطيل الزر مؤقتاً في الواجهة وضوابط منع التكرار على الخادم.
- عطّل زر الإرسال (
submitBtn.disabled = true) فور بدء حدثsubmit، وأعد تفعيله داخل كتلةfinallyبعد اكتمال الطلب. - في PHP، حرر قفل ملف الجلسة مبكراً عبر
session_write_close()إذا كان السكريبت ينفذ عمليات قراءة طويلة بعد التحقق من$_SESSION. - على مستوى قاعدة البيانات، اعتمد على التحديث الذري
SET votes = votes + 1وقيودUNIQUEبدلاً من القراءة ثم الجمع في PHP.
يؤدي حساب بصمة الإرسال ومقارنتها بآخر عملية مسجلة في الجلسة إلى منع النقرات المزدوجة الخاطئة وإرجاع الرمز 409 Conflict.
<?php
$_SESSION = ['last_submit_hash' => ''];
$payloadHash = hash('sha256', 'user_42:comment:Hello world');
if ($_SESSION['last_submit_hash'] === $payloadHash) {
http_response_code(409);
echo json_encode(['ok' => false, 'error' => 'Duplicate submission']) . "\n";
} else {
$_SESSION['last_submit_hash'] = $payloadHash;
echo json_encode(['ok' => true, 'hash' => substr($payloadHash, 0, 12)]) . "\n";
}
اختر بين النماذج التقليدية بنمط PRG ونماذج AJAX التفاعلية بناءً على طبيعة تجربة المستخدم في كل شاشة.
- استخدم نماذج PRG التقليدية عندما يؤدي إرسال النموذج للانتقال إلى صفحة جديدة كلياً (مثل تسجيل الدخول أو الخروج).
- استخدم نماذج AJAX عندما يبقى المستخدم في نفس الشاشة (مثل التصويت الفوري، أو التعليقات، أو النوافذ المنبثقة، أو حفظ الإعدادات).
- يتطلب كلا الأسلوبين نفس ضوابط التحقق على الخادم واستعلامات PDO المحضرة وفحص توكن CSRF دون أي استثناء!
يتيح فحص الرأس HTTP_ACCEPT لنفس ملف PHP إرجاع استجابة JSON لطلبات AJAX أو التحويل بنمط PRG للنماذج العادية.
| وجه المقارنة | النموذج التقليدي POST + PRG | نموذج AJAX عبر FormData + fetch() |
|---|---|---|
| Page Reload | Full browser navigation (303 Redirect) | Zero reload (in-place DOM update) |
| Validation Errors | Stored in session flash + redirect back | Returned immediately as HTTP 422 JSON |
| CSRF Token Carrier | Hidden <input name="csrf_token"> | Hidden input in FormData or X-CSRF-Token header |
| Success Feedback | Session flash banner on next page | Live toast / progress bar update |
| Server Security Rules | Full validation + PDO + CSRF | Full validation + PDO + CSRF |
<?php
function wantsJson(array $server): bool {
$accept = $server['HTTP_ACCEPT'] ?? '';
$xhr = $server['HTTP_X_REQUESTED_WITH'] ?? '';
return str_contains($accept, 'application/json')
|| strtolower($xhr) === 'xmlhttprequest';
}
$simServer = ['HTTP_ACCEPT' => 'application/json, text/plain'];
echo "Client expects JSON? " . (wantsJson($simServer) ? "Yes" : "No") . "\n";
ملخص الدرس
حصاد الدرسمراجعة مركّزة لأهم المفاهيم والقواعد الهندسية التي أتقنتها في هذا الدرس قبل التطبيق العملي
ماذا تعلّمت في هذا الدرس؟
اختر بين النماذج التقليدية بنمط PRG ونماذج AJAX التفاعلية بناءً على طبيعة تجربة المستخدم في كل شاشة. استخدم نماذج PRG التقليدية عندما يؤدي إرسال النموذج للانتقال إلى صفحة جديدة كلياً (مثل تسجيل الدخول أو الخروج). استخدم نماذج AJAX عندما يبقى المستخدم في نفس الشاشة (مثل التصويت الفوري، أو التعليقات، أو النوافذ المنبثقة، أو حفظ الإعدادات). يتطلب كلا الأسلوبين نفس ضوابط التحقق على الخادم واستعلامات PDO المحضرة وفحص توكن CSRF دون أي استثناء!
سجّل الدخول لحفظ تقدمك
تابع إنجاز المواضيع والمصطلحات والمهام، وكمّل من آخر خطوة على أي جهاز.
المصطلحات4
راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.
- 01 AJAX Forms & Poll نماذج واستطلاعات AJAX
- أرسل النماذج بدون تحديث الصفحة باستخدام FormData، وأرجع أخطاء التحقق لكل حقل من PHP، وابنِ نظام تصويت تفاعلي فوري.
- للمراجعة
- 02 Submitting Forms with FormData and fetch إرسال النماذج غير المتزامن عبر الكائن FormData
- المفهوم الأساسي لقسم إرسال النماذج غير المتزامن عبر الكائن FormData في لغة PHP الحديثة.
- للمراجعة
- 03 Returning Field Validation Errors as JSON إرجاع أخطاء التحقق لكل حقل بصيغة JSON (422)
- الصياغة البرمجية والتطبيق العملي المباشر لقسم إرجاع أخطاء التحقق لكل حقل بصيغة JSON (422).
- للمراجعة
- 04 Verifying CSRF Tokens in AJAX Requests التحقق من توكن CSRF في طلبات AJAX
- قواعد التحقق وأفضل الممارسات القياسية الخاصة بقسم التحقق من توكن CSRF في طلبات AJAX.
- للمراجعة
لا توجد بطاقات تطابق البحث والتصفية.
اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.
الاختصارات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 ويرسلها إلى متصفح العميل بعد التنفيذ.
- للمراجعة
لا توجد بطاقات تطابق البحث والتصفية.
اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.
مهامك قبل الاختبار
خطوة صغيرة كل مرة. وإنجاز تقدر ترجع له.
-
أنشئ ملف PHP محلياً ونفّذ المثال البرمجي المشروح في قسم إرسال النماذج غير المتزامن عبر الكائن FormData للتحقق من المخرجات.
-
بدّل بين الحالات الثلاث في المحاكي التفاعلي ضمن قسم إرجاع أخطاء التحقق لكل حقل بصيغة JSON (422) وقارن مخرجات التنفيذ.
تأشير المهمة إقرار منك بإتمامها، وليس تصحيحًا آليًا للكود. يُحفظ تقدمك في حسابك.
اختبر فهمك.
ووصلها للإتقان.
كل سؤال خطوة لقدّام. اختار، اكتب كود، وشوف نتيجتك فورًا.
أكمل المهام، واجمع كل الإجابات الصحيحة. أقل من 100%؟ راجع وأعد المحاولة.
الأسئلة متاحة للاطلاع. سجّل الدخول للتفاعل وحفظ تقدمك.
لمحة عن التحدي8 أسئلة تنتظرك +
ماذا يحدث في PHP عندما ترسل نموذج HTML بشكل غير متزامن باستخدام body: new FormData(formEl) في دالة fetch()؟
يرسل الكائن FormData البيانات بترميز multipart/form-data فيقرأها PHP مباشرة في $_POST و $_FILES.
لماذا يجب عدم ضبط رأس الطلب "Content-Type": "multipart/form-data" يدوياً عند تمرير كائن FormData إلى دالة fetch()؟
بدون معامل boundary الذي يولده المتصفح لا يستطيع PHP فصل الحقول فتصل $_POST فارغة.
كيف يتيح PHP قراءة رأس الطلب المخصص المرسل من دالة fetch() باسم "X-CSRF-Token"؟
يحول PHP اسم الرأس إلى أحرف كبيرة ويستبدل الشرطات بشرطات سفلية ويضيف البادئة HTTP_.
ما النمط القياسي لإرجاع أخطاء التحقق الخاصة بالحقول من معالج نماذج AJAX في PHP؟
فهرسة الأخطاء باسم الحقل تتيح لـ JavaScript تمييز كل حقل وعرض رسالته الخاصة بدقة.
كيف يجب أن يزيد ملف التصويت في PHP عداد الأصوات في قاعدة البيانات لتجنب تعارض الطلبات المتزامنة في نفس اللحظة؟
الجمع الذري داخل محرك قاعدة البيانات يمنع ضياع الأصوات المتزامنة.
كيف تمنع خطأ القسمة على صفر (DivisionByZeroError) في PHP عند حساب النسب المئوية لخيارات الاستطلاع؟
القسمة على صفر في PHP 8 تطلق DivisionByZeroError؛ واستخدام max(1, $total) يضمن مقسوماً عليه آمناً.
ماذا يجب أن يفعل كود JavaScript فور بدء إرسال نموذج AJAX، وماذا يفعل في كتلة finally؟
تعطيل الزر أثناء الطلب يمنع إرسال النموذج مرتين عن طريق الخطأ.
هل يسمح استخدام نماذج AJAX بتخطي التحقق من المدخلات أو فحص توكن CSRF على خادم PHP؟
يمكن دائماً تجاوز الواجهة الأمامية بطلبات مباشرة، لذا يجب أن يفرض خادم PHP كافة الفحوصات الأمنية.