يُرسل نموذج PHP إلى السكربت الذي طبعه: اكتب <form method="post"> مع حقول مسماة، وعندما تكون $_SERVER['REQUEST_METHOD'] مساوية لـ 'POST'، اقرأ كل حقل على شكل $_POST['name']. وهرّب كل ما تطبعه مرة أخرى بـ htmlspecialchars().
شغّل هذه الكتلة، واكتب اسمًا في النموذج واضغط Send: يعمل السكربت نفسه مرة أخرى، هذه المرة مع امتلاء $_POST.
تحدث هنا ثلاثة أمور يحتاجها كل معالج نماذج:
- فحص طريقة الطلب. في الزيارة الأولى يكون الطلب GET ولا شيء يُعالج. ولا تهم
?? 'GET'إلا حين يعمل الملف من سطر الأوامر، حيث لا تكونREQUEST_METHODمضبوطة؛ أما على خادم ويب فهي مضبوطة دائمًا. ?? ''على كل حقل. قد يكون حقل مفقودًا (حقل أُعيدت تسميته، أو طلب أرسله سكربت)، وقراءة مفتاح مفقود تطبع تحذيرًا.- التهريب عند الإخراج. يعود الاسم إلى الصفحة مرتين، وتضمن
htmlspecialchars()أن تُعرض قيمة مثل<b>Ada</b>نصًا بدل أن تصبح وسومًا. والتفاصيل في صفحة htmlspecialchars.
التحقق من نموذج وعرض الأخطاء بجانب الحقول
اجمع الأخطاء في مصفوفة مفاتيحها أسماء الحقول. إذا كانت المصفوفة فارغة، فالنموذج صالح؛ وإلا فاطبع النموذج مرة أخرى مع كل رسالة تحت حقلها ومُدخلات الزائر ما زالت في مكانها. أرسله فارغًا، ثم ببريد خاطئ، ثم بقيم صالحة.
يوقف novalidate فحوص المتصفح الخاصة لتشاهد فحوص PHP وهي تعمل. واحتفظ بالاثنين في نموذج حقيقي: تحقق المتصفح راحة للزائر، وتحقق PHP هو الذي يُعتد به، لأن أي شخص يستطيع إرسال طلب دون نموذجك. تفحص filter_var() البريد ونطاق العدد الصحيح باستدعاء واحد لكل منهما؛ وتشرح صفحة filter_var مرشحاتها الأخرى.
مربعات الاختيار وأزرار الراديو والقوائم المنسدلة
يرسل الحقل النصي قيمة دائمًا، ولو فارغة. أما عناصر التحكم الأخرى فلا:
- مربع الاختيار غير المحدد لا يرسل شيئًا أصلًا، فيكون مفتاحه مفقودًا من
$_POST. - مربعات الاختيار المسماة
topics[]تصل مصفوفةً:$_POST['topics']هي['php', 'sql']. - ترسل مجموعة الراديو أو
<select>قيمةvalueللخيار المختار.
للاحتفاظ بالاختيار بعد الإرسال، اطبع checked أو selected على الخيار المطابق. حدّد بضعة مربعات، واختر مستوى واضغط Save.
للفحصين بعد قراءة المُدخلات أهمية أكبر مما يبدو. تُسقط array_intersect() أي موضوع لم يكن في قائمتك، ويعيد فحص is_string() مع array_key_exists() المستوى إلى قيمة افتراضية إذا أرسل أحدهم قيمة لم تعرضها أبدًا (أو مصفوفة، ستجعل $levels[$level] ترمي خطأً). القائمة المنسدلة تحدّ ما يستطيع المتصفح إرساله، لا ما يمكن أن يحتويه الطلب.
نماذج متعددة الخطوات بالحقول المخفية
يحمل الحقل المخفي قيمة من خطوة إلى التالية دون عرضها. هنا تطلب الخطوة 1 اسمًا، وتطلب الخطوة 2 لغة وترسل الاسم معها في حقل مخفي، وتعرض الخطوة 3 كليهما. مرّ بالخطوات الثلاث.
الحقول المخفية مرئية في مصدر الصفحة وقابلة للتعديل مثل أي حقل آخر، لذا فهي مناسبة لحمل إجابات الزائر نفسه بين الخطوات، لكن ليس أبدًا لسعر أو معرّف مستخدم أو دور. احتفظ بتلك على الخادم، في جلسة؛ راجع الجلسات وملفات تعريف الارتباط.
Post/Redirect/Get: منع إعادة الإرسال عند التحديث
بعد POST ناجح، إذا طبع السكربت صفحة «شكرًا» مباشرة، فإن الضغط على التحديث يطلب من المتصفح إرسال POST مرة أخرى، فيُحفظ الطلب أو التعليق مرتين. والحل أن تحفظ، ثم تحوّل، ثم تعرض النتيجة في GET:
<?php
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$errors = validate($_POST);
if (!$errors) {
save_comment($_POST);
$_SESSION['flash'] = 'Comment posted.';
header('Location: /comments.php', true, 303);
exit;
}
// On errors, fall through and print the form with the messages.
}
$flash = $_SESSION['flash'] ?? null;
unset($_SESSION['flash']);
يخبر 303 See Other المتصفح باتباع التحويل بطلب GET. ولـ exit بعد header() أهمية: دونها تواصل بقية السكربت العمل. ويجب أيضًا أن يحدث التحويل قبل أي مخرجات، وإلا رفضت PHP برسالة "headers already sent".
تضيف النماذج الحقيقية أيضًا رمز CSRF: قيمة عشوائية مخزنة في الجلسة وفي حقل مخفي، تُقارن بـ hash_equals() عند الإرسال، فلا يستطيع موقع آخر الإرسال إلى نموذجك نيابة عن زائر مسجل دخوله.
اختبار التحقق دون متصفح
ضع القواعد في دالة تأخذ مصفوفة وتعيد الأخطاء. تستدعيها الصفحة بـ $_POST، ويمكنك أن تستدعيها بأي مصفوفة تشاء، وهذا يجعل تجربة الحالات الحدية سهلة. أضف حالاتك الخاصة إلى القائمة.
الحالة الرابعة هي التي ينساها الناس. يمكن للطلب إرسال name[]=x، فتصبح $_POST['name'] مصفوفة، وتمرير مصفوفة إلى trim() يرمي TypeError ويوقف السكربت. وفحص is_string() أولًا يحوّل المُدخلات العدائية إلى خطأ تحقق عادي. ويتجنب التحويل (string) في الكتل السابقة الخطأ TypeError أيضًا، لكنه يحوّل المصفوفة إلى الكلمة Array ويطبع تحذيرًا، لذا فإن is_string() هو الفحص الأنظف.
خطأ شائع: قراءة $_POST قبل إرسال النموذج
أشهر سكربت نماذج أول يقرأ الحقول في أعلى الملف:
<?php
$name = $_POST['name'];
echo "Hello, $name";
في الزيارة الأولى لم يُرسل شيء، فتطبع PHP:
Warning: Undefined array key "name" in /var/www/form.php on line 2
الحل هو النمط من الكتلة الأولى: لا تعالج النموذج إلا حين يكون الطلب POST، واقرأ كل حقل مع قيمة افتراضية، $_POST['name'] ?? ''. وإذا ظهر التحذير بعد الإرسال، فقارن الخاصية name في HTML بالمفتاح في PHP: name="Name" و$_POST['name'] مفتاحان مختلفان.
الأسئلة الشائعة
كيف أرسل نموذج PHP إلى الصفحة نفسها؟
اكتب <form method="post"> دون action (أو action=""). يرسل المتصفح إلى الرابط الحالي، فيعرض السكربت نفسه النموذج ويعالجه: افحص $_SERVER['REQUEST_METHOD'] === 'POST' واقرأ الحقول من $_POST.
كيف أحتفظ بقيم النموذج بعد الإرسال في PHP؟
اطبع القيمة المرسلة مرة أخرى في الحقل، مهرّبة: <input name="email" value="<?= htmlspecialchars($_POST['email'] ?? '') ?>">. ولمربع الاختيار اطبع checked، ولخيار القائمة المنسدلة اطبع selected، عندما تطابق القيمة المرسلة.
كيف أحصل على قيم عدة مربعات اختيار في PHP؟
أعطِ مربعات الاختيار الاسم نفسه منتهيًا بقوسين، name="topics[]". عندها تضع PHP القيم المحددة في مصفوفة، $_POST['topics']. والمربعات غير المحددة لا ترسل شيئًا، لذا استخدم $_POST['topics'] ?? [] وافحص كل قيمة مقابل القائمة التي عرضتها.
لماذا يعيد تحديث الصفحة إرسال نموذج PHP؟
الطلب الأخير كان POST، فيكرره المتصفح عند التحديث. بعد إرسال ناجح، حوّل بـ header('Location: /thanks.php'); exit; (نمط Post/Redirect/Get). عندها يكرر التحديث طلب GET غير ضار.
هل استخدام $_POST آمن في PHP؟
لا، كل قيمة في $_POST تأتي من الزائر وقد تكون أي شيء، بما في ذلك HTML أو SQL أو مصفوفة حيث توقعت نصًا. تحقق منها عند الدخول (filter_var، وفحوص الطول والقائمة المسموحة) وهرّبها عند الخروج (htmlspecialchars لـ HTML، والجمل المُعدّة لـ SQL).