أساسيات PHP

التحقق من النماذج

13 دقيقة الدرس 18 من 45

التحقق من النماذج

التحقق من النماذج أمر أساسي لضمان جودة البيانات والأمان وتجربة مستخدم جيدة. توفر PHP أدوات قوية للتحقق من إدخال المستخدم على جانب الخادم.

قاعدة حاسمة: لا تثق أبدًا في التحقق من جانب العميل وحده. يمكن تجاوز التحقق بـ JavaScript. تحقق دائمًا على الخادم باستخدام PHP.

أنواع التحقق

هناك نوعان رئيسيان من التحقق:

  • التحقق من جانب العميل: JavaScript/HTML5 (سريع، تجربة مستخدم أفضل، لكن يمكن تجاوزه)
  • التحقق من جانب الخادم: PHP (آمن، مطلوب، لكن ردود فعل أبطأ)
أفضل ممارسة: استخدم كليهما! جانب العميل للملاحظات الفورية، جانب الخادم للأمان.

تقنيات التحقق الأساسية

1. الحقول المطلوبة

<?php // التحقق من أن الحقل فارغ if (empty($_POST['username'])) { $errors[] = "اسم المستخدم مطلوب"; } // التحقق من وجود الحقل وأنه غير فارغ if (!isset($_POST['email']) || trim($_POST['email']) === '') { $errors[] = "البريد الإلكتروني مطلوب"; } // بديل مع معالجة أفضل $username = isset($_POST['username']) ? trim($_POST['username']) : ''; if ($username === '') { $errors[] = "اسم المستخدم مطلوب"; } ?>

2. التحقق من طول النص

<?php $username = trim($_POST['username']); // الحد الأدنى للطول if (strlen($username) < 3) { $errors[] = "يجب أن يكون اسم المستخدم 3 أحرف على الأقل"; } // الحد الأقصى للطول if (strlen($username) > 20) { $errors[] = "يجب أن يكون اسم المستخدم أقل من 20 حرفًا"; } // نطاق if (strlen($username) < 3 || strlen($username) > 20) { $errors[] = "يجب أن يكون اسم المستخدم بين 3 و 20 حرفًا"; } // للنصوص متعددة البايتات (العربية، الصينية، إلخ) if (mb_strlen($username) < 3) { $errors[] = "يجب أن يكون اسم المستخدم 3 أحرف على الأقل"; } ?>

3. التحقق من البريد الإلكتروني

<?php $email = trim($_POST['email']); // استخدام filter_var (موصى به) if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { $errors[] = "صيغة البريد الإلكتروني غير صحيحة"; } // فحص إضافي: البريد الإلكتروني موجود وصحيح if (empty($email)) { $errors[] = "البريد الإلكتروني مطلوب"; } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) { $errors[] = "صيغة البريد الإلكتروني غير صحيحة"; } // التحقق المخصص باستخدام regex (أكثر صرامة) if (!preg_match('/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/', $email)) { $errors[] = "صيغة البريد الإلكتروني غير صحيحة"; } ?>

4. التحقق من الأرقام

<?php $age = $_POST['age']; // التحقق من أنه رقم if (!is_numeric($age)) { $errors[] = "العمر يجب أن يكون رقمًا"; } // تحويل والتحقق من النطاق $age = intval($age); if ($age < 18 || $age > 120) { $errors[] = "العمر يجب أن يكون بين 18 و 120"; } // التحقق من الأرقام الموجبة $price = floatval($_POST['price']); if ($price <= 0) { $errors[] = "السعر يجب أن يكون أكبر من الصفر"; } // استخدام filter_var للأعداد الصحيحة $quantity = filter_var($_POST['quantity'], FILTER_VALIDATE_INT); if ($quantity === false || $quantity < 1) { $errors[] = "الكمية يجب أن تكون عددًا صحيحًا موجبًا"; } ?>

5. التحقق من الرابط

<?php $website = trim($_POST['website']); // استخدام filter_var if (!empty($website) && !filter_var($website, FILTER_VALIDATE_URL)) { $errors[] = "صيغة الرابط غير صحيحة"; } // التحقق من بروتوكول معين if (!empty($website)) { if (!preg_match('/^https?:\/\//i', $website)) { $errors[] = "الرابط يجب أن يبدأ بـ http:// أو https://"; } } ?>

6. مطابقة الأنماط (Regex)

<?php // اسم المستخدم: حروف وأرقام وشرطة سفلية فقط $username = $_POST['username']; if (!preg_match('/^[a-zA-Z0-9_]+$/', $username)) { $errors[] = "اسم المستخدم يمكن أن يحتوي فقط على حروف وأرقام وشرطة سفلية"; } // رقم الهاتف (صيغة أمريكية) $phone = $_POST['phone']; if (!preg_match('/^\d{3}-\d{3}-\d{4}$/', $phone)) { $errors[] = "الهاتف يجب أن يكون بالصيغة: 123-456-7890"; } // كلمة مرور قوية: 8 أحرف على الأقل، أحرف كبيرة وصغيرة، رقم، حرف خاص $password = $_POST['password']; if (!preg_match('/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/', $password)) { $errors[] = "كلمة المرور يجب أن تكون 8 أحرف على الأقل مع أحرف كبيرة وصغيرة ورقم وحرف خاص"; } // صيغة التاريخ (YYYY-MM-DD) $date = $_POST['date']; if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)) { $errors[] = "التاريخ يجب أن يكون بالصيغة: YYYY-MM-DD"; } ?>

مثال كامل للتحقق

<?php // registration_validation.php $errors = []; $success = false; if ($_SERVER['REQUEST_METHOD'] === 'POST') { // الحصول على وتنظيف الإدخال $username = trim($_POST['username']); $email = trim($_POST['email']); $password = $_POST['password']; $confirm_password = $_POST['confirm_password']; $age = isset($_POST['age']) ? $_POST['age'] : ''; $website = trim($_POST['website']); $terms = isset($_POST['terms']); // التحقق من اسم المستخدم if (empty($username)) { $errors['username'] = "اسم المستخدم مطلوب"; } elseif (strlen($username) < 3) { $errors['username'] = "اسم المستخدم يجب أن يكون 3 أحرف على الأقل"; } elseif (strlen($username) > 20) { $errors['username'] = "اسم المستخدم يجب أن يكون أقل من 20 حرفًا"; } elseif (!preg_match('/^[a-zA-Z0-9_]+$/', $username)) { $errors['username'] = "اسم المستخدم يمكن أن يحتوي فقط على حروف وأرقام وشرطة سفلية"; } // التحقق من البريد الإلكتروني if (empty($email)) { $errors['email'] = "البريد الإلكتروني مطلوب"; } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) { $errors['email'] = "صيغة البريد الإلكتروني غير صحيحة"; } // التحقق من كلمة المرور if (empty($password)) { $errors['password'] = "كلمة المرور مطلوبة"; } elseif (strlen($password) < 8) { $errors['password'] = "كلمة المرور يجب أن تكون 8 أحرف على الأقل"; } elseif (!preg_match('/[A-Z]/', $password)) { $errors['password'] = "كلمة المرور يجب أن تحتوي على حرف كبير واحد على الأقل"; } elseif (!preg_match('/[a-z]/', $password)) { $errors['password'] = "كلمة المرور يجب أن تحتوي على حرف صغير واحد على الأقل"; } elseif (!preg_match('/[0-9]/', $password)) { $errors['password'] = "كلمة المرور يجب أن تحتوي على رقم واحد على الأقل"; } // التحقق من تأكيد كلمة المرور if ($password !== $confirm_password) { $errors['confirm_password'] = "كلمات المرور غير متطابقة"; } // التحقق من العمر if (empty($age)) { $errors['age'] = "العمر مطلوب"; } elseif (!is_numeric($age)) { $errors['age'] = "العمر يجب أن يكون رقمًا"; } else { $age = intval($age); if ($age < 18) { $errors['age'] = "يجب أن يكون عمرك 18 عامًا على الأقل"; } elseif ($age > 120) { $errors['age'] = "يرجى إدخال عمر صحيح"; } } // التحقق من الموقع (حقل اختياري) if (!empty($website) && !filter_var($website, FILTER_VALIDATE_URL)) { $errors['website'] = "رابط الموقع غير صحيح"; } // التحقق من قبول الشروط if (!$terms) { $errors['terms'] = "يجب الموافقة على الشروط والأحكام"; } // إذا لم توجد أخطاء، معالجة التسجيل if (empty($errors)) { $hashed_password = password_hash($password, PASSWORD_DEFAULT); // الحفظ في قاعدة البيانات هنا $success = true; } } ?> <!DOCTYPE html> <html> <head> <title>التسجيل مع التحقق</title> <style> .error { color: red; font-size: 0.9em; } .field-error { border: 2px solid red; } .success { color: green; padding: 10px; background: #d4edda; } .form-group { margin-bottom: 15px; } label { display: block; margin-bottom: 5px; font-weight: bold; } input[type="text"], input[type="email"], input[type="password"], input[type="number"], input[type="url"] { padding: 8px; width: 100%; max-width: 400px; } </style> </head> <body> <h1>تسجيل المستخدم</h1> <?php if ($success): ?> <div class="success"> <h2>تم التسجيل بنجاح!</h2> <p>مرحبًا، <?php echo htmlspecialchars($username); ?>!</p> </div> <?php else: ?> <form method="post" action="" novalidate> <div class="form-group"> <label for="username">اسم المستخدم *</label> <input type="text" id="username" name="username" class="<?php echo isset($errors['username']) ? 'field-error' : ''; ?>" value="<?php echo isset($username) ? htmlspecialchars($username) : ''; ?>"> <?php if (isset($errors['username'])): ?> <div class="error"><?php echo $errors['username']; ?></div> <?php endif; ?> </div> <div class="form-group"> <label for="email">البريد الإلكتروني *</label> <input type="email" id="email" name="email" class="<?php echo isset($errors['email']) ? 'field-error' : ''; ?>" value="<?php echo isset($email) ? htmlspecialchars($email) : ''; ?>"> <?php if (isset($errors['email'])): ?> <div class="error"><?php echo $errors['email']; ?></div> <?php endif; ?> </div> <div class="form-group"> <label for="password">كلمة المرور *</label> <input type="password" id="password" name="password" class="<?php echo isset($errors['password']) ? 'field-error' : ''; ?>"> <?php if (isset($errors['password'])): ?> <div class="error"><?php echo $errors['password']; ?></div> <?php endif; ?> <small>8 أحرف على الأقل، أحرف كبيرة وصغيرة، ورقم</small> </div> <div class="form-group"> <label for="confirm_password">تأكيد كلمة المرور *</label> <input type="password" id="confirm_password" name="confirm_password" class="<?php echo isset($errors['confirm_password']) ? 'field-error' : ''; ?>"> <?php if (isset($errors['confirm_password'])): ?> <div class="error"><?php echo $errors['confirm_password']; ?></div> <?php endif; ?> </div> <div class="form-group"> <label for="age">العمر *</label> <input type="number" id="age" name="age" class="<?php echo isset($errors['age']) ? 'field-error' : ''; ?>" value="<?php echo isset($age) ? htmlspecialchars($age) : ''; ?>"> <?php if (isset($errors['age'])): ?> <div class="error"><?php echo $errors['age']; ?></div> <?php endif; ?> </div> <div class="form-group"> <label for="website">الموقع الإلكتروني (اختياري)</label> <input type="url" id="website" name="website" class="<?php echo isset($errors['website']) ? 'field-error' : ''; ?>" value="<?php echo isset($website) ? htmlspecialchars($website) : ''; ?>" placeholder="https://example.com"> <?php if (isset($errors['website'])): ?> <div class="error"><?php echo $errors['website']; ?></div> <?php endif; ?> </div> <div class="form-group"> <input type="checkbox" id="terms" name="terms" value="1"> <label for="terms" style="display: inline;">أوافق على الشروط *</label> <?php if (isset($errors['terms'])): ?> <div class="error"><?php echo $errors['terms']; ?></div> <?php endif; ?> </div> <button type="submit">تسجيل</button> </form> <?php endif; ?> </body> </html>

دوال مساعدة للتحقق

<?php // إنشاء دوال تحقق قابلة لإعادة الاستخدام function validateRequired($value, $fieldName) { if (empty(trim($value))) { return "$fieldName مطلوب"; } return null; } function validateLength($value, $min, $max, $fieldName) { $length = strlen($value); if ($length < $min) { return "$fieldName يجب أن يكون $min أحرف على الأقل"; } if ($length > $max) { return "$fieldName يجب أن يكون أقل من $max حرفًا"; } return null; } function validateEmail($email) { if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { return "صيغة البريد الإلكتروني غير صحيحة"; } return null; } function validatePassword($password) { $errors = []; if (strlen($password) < 8) { $errors[] = "8 أحرف على الأقل"; } if (!preg_match('/[A-Z]/', $password)) { $errors[] = "حرف كبير واحد"; } if (!preg_match('/[a-z]/', $password)) { $errors[] = "حرف صغير واحد"; } if (!preg_match('/[0-9]/', $password)) { $errors[] = "رقم واحد"; } if (!empty($errors)) { return "كلمة المرور يجب أن تحتوي على " . implode('، ', $errors); } return null; } // الاستخدام $errors = []; if ($error = validateRequired($_POST['username'], 'اسم المستخدم')) { $errors['username'] = $error; } if ($error = validateLength($_POST['username'], 3, 20, 'اسم المستخدم')) { $errors['username'] = $error; } if ($error = validateEmail($_POST['email'])) { $errors['email'] = $error; } if ($error = validatePassword($_POST['password'])) { $errors['password'] = $error; } ?>

التنظيف مقابل التحقق

تمييز مهم:
  • التحقق: التحقق من أن البيانات تلبي المتطلبات (رفض إذا كانت غير صحيحة)
  • التنظيف: تنظيف البيانات لجعلها آمنة (إزالة/تجاوز الأحرف الخطرة)
<?php // أمثلة التنظيف // إزالة علامات HTML $clean_text = strip_tags($_POST['comment']); // تنظيف البريد الإلكتروني $clean_email = filter_var($_POST['email'], FILTER_SANITIZE_EMAIL); // تنظيف النص (إزالة الأحرف الخاصة) $clean_string = filter_var($_POST['name'], FILTER_SANITIZE_STRING); // تجاوز HTML للإخراج (منع XSS) $safe_output = htmlspecialchars($_POST['username'], ENT_QUOTES, 'UTF-8'); // إزالة المسافات البيضاء $trimmed = trim($_POST['input']); // تنظيف الرابط $clean_url = filter_var($_POST['website'], FILTER_SANITIZE_URL); // تحويل إلى عدد صحيح $clean_number = intval($_POST['age']); ?>

الحماية من CSRF

حماية Cross-Site Request Forgery (CSRF) تمنع المهاجمين من إرسال النماذج نيابة عن المستخدمين.

<?php // إنشاء رمز CSRF session_start(); if (empty($_SESSION['csrf_token'])) { $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); } // إضافة إلى النموذج ?> <form method="post"> <input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>"> <!-- حقول أخرى --> </form> <?php // التحقق من رمز CSRF عند الإرسال if ($_SERVER['REQUEST_METHOD'] === 'POST') { if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) { die('رمز CSRF غير صحيح'); } // معالجة النموذج... } ?>

تمرين تطبيقي

المهمة: أنشئ نموذج اتصال مع التحقق من:

  1. الاسم (مطلوب، 2-50 حرفًا، حروف ومسافات فقط)
  2. البريد الإلكتروني (مطلوب، صيغة بريد إلكتروني صحيحة)
  3. الهاتف (اختياري، الصيغة: XXX-XXX-XXXX)
  4. الموضوع (مطلوب، اختر من: عام، دعم، مبيعات)
  5. الرسالة (مطلوبة، 10-500 حرف)

المتطلبات:

  • عرض رسائل أخطاء خاصة بالحقول
  • تسليط الضوء على الحقول غير الصحيحة بحد أحمر
  • الحفاظ على قيم النموذج عند الخطأ
  • عرض رسالة نجاح بعد التحقق
  • إضافة حماية CSRF

إضافي: أنشئ دوال مساعدة للتحقق وأضف سمات التحقق من HTML5 من جانب العميل.

الملخص

في هذا الدرس، تعلمت:

  • لماذا التحقق من جانب الخادم حاسم
  • التحقق من الحقول المطلوبة
  • التحقق من طول النص
  • التحقق من البريد الإلكتروني والرابط والأرقام
  • مطابقة الأنماط باستخدام التعبيرات العادية
  • التحقق من قوة كلمة المرور
  • إنشاء دوال تحقق قابلة لإعادة الاستخدام
  • الفرق بين التحقق والتنظيف
  • رسائل أخطاء خاصة بالحقول
  • حماية رمز CSRF

بعد ذلك، سنتعلم عن رفع الملفات في PHP!