أساسيات PHP
نظام تسجيل المستخدمين
نظام تسجيل المستخدمين
بناء نظام تسجيل مستخدمين آمن هو مهارة أساسية في تطوير الويب. في هذا الدرس، سنقوم بإنشاء نظام تسجيل كامل مع التحقق المناسب، تشفير كلمات المرور، والتكامل مع قاعدة البيانات.
إعداد قاعدة البيانات
أولاً، لنقم بإنشاء جدول المستخدمين لتخزين معلومات المستخدم:
SQL:
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
full_name VARCHAR(100) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
last_login TIMESTAMP NULL,
is_active BOOLEAN DEFAULT TRUE,
INDEX idx_email (email),
INDEX idx_username (username)
);
ملاحظة: حقل كلمة المرور هو VARCHAR(255) لاستيعاب خوارزميات التشفير الحديثة مثل bcrypt، والتي تنتج تجزئات من 60 حرفاً. نستخدم 255 للتوافق المستقبلي.
نموذج التسجيل HTML
إنشاء نموذج تسجيل سهل الاستخدام مع سمات التحقق المناسبة:
register.php:
<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>تسجيل مستخدم جديد</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Cairo', Arial, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.register-container {
background: white;
padding: 40px;
border-radius: 10px;
box-shadow: 0 10px 40px rgba(0,0,0,0.2);
max-width: 500px;
width: 100%;
}
h1 {
color: #333;
margin-bottom: 30px;
text-align: center;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 5px;
color: #555;
font-weight: bold;
}
input {
width: 100%;
padding: 12px;
border: 2px solid #ddd;
border-radius: 5px;
font-size: 16px;
transition: border-color 0.3s;
direction: rtl;
}
input:focus {
outline: none;
border-color: #667eea;
}
.error {
color: #e74c3c;
font-size: 14px;
margin-top: 5px;
display: block;
}
.success {
background: #2ecc71;
color: white;
padding: 15px;
border-radius: 5px;
margin-bottom: 20px;
text-align: center;
}
button {
width: 100%;
padding: 12px;
background: #667eea;
color: white;
border: none;
border-radius: 5px;
font-size: 16px;
font-weight: bold;
cursor: pointer;
transition: background 0.3s;
}
button:hover {
background: #5568d3;
}
.login-link {
text-align: center;
margin-top: 20px;
color: #555;
}
.login-link a {
color: #667eea;
text-decoration: none;
font-weight: bold;
}
.password-strength {
height: 5px;
margin-top: 5px;
border-radius: 3px;
transition: all 0.3s;
}
.strength-weak { background: #e74c3c; width: 33%; }
.strength-medium { background: #f39c12; width: 66%; }
.strength-strong { background: #2ecc71; width: 100%; }
</style>
</head>
<body>
<div class="register-container">
<h1>إنشاء حساب جديد</h1>
<?php if (isset($success_message)): ?>
<div class="success"><?php echo $success_message; ?></div>
<?php endif; ?>
<form method="POST" action="register.php" id="registerForm">
<div class="form-group">
<label for="full_name">الاسم الكامل</label>
<input type="text" id="full_name" name="full_name"
value="<?php echo htmlspecialchars($full_name ?? ''); ?>"
required>
<?php if (isset($errors['full_name'])): ?>
<span class="error"><?php echo $errors['full_name']; ?></span>
<?php endif; ?>
</div>
<div class="form-group">
<label for="username">اسم المستخدم</label>
<input type="text" id="username" name="username"
value="<?php echo htmlspecialchars($username ?? ''); ?>"
required>
<?php if (isset($errors['username'])): ?>
<span class="error"><?php echo $errors['username']; ?></span>
<?php endif; ?>
</div>
<div class="form-group">
<label for="email">البريد الإلكتروني</label>
<input type="email" id="email" name="email"
value="<?php echo htmlspecialchars($email ?? ''); ?>"
required>
<?php if (isset($errors['email'])): ?>
<span class="error"><?php echo $errors['email']; ?></span>
<?php endif; ?>
</div>
<div class="form-group">
<label for="password">كلمة المرور</label>
<input type="password" id="password" name="password" required>
<div class="password-strength" id="strengthBar"></div>
<?php if (isset($errors['password'])): ?>
<span class="error"><?php echo $errors['password']; ?></span>
<?php endif; ?>
</div>
<div class="form-group">
<label for="confirm_password">تأكيد كلمة المرور</label>
<input type="password" id="confirm_password" name="confirm_password" required>
<?php if (isset($errors['confirm_password'])): ?>
<span class="error"><?php echo $errors['confirm_password']; ?></span>
<?php endif; ?>
</div>
<button type="submit">تسجيل</button>
</form>
<div class="login-link">
لديك حساب بالفعل؟ <a href="login.php">تسجيل الدخول هنا</a>
</div>
</div>
<script>
// مؤشر قوة كلمة المرور
document.getElementById('password').addEventListener('input', function(e) {
const password = e.target.value;
const strengthBar = document.getElementById('strengthBar');
let strength = 0;
if (password.length >= 8) strength++;
if (/[a-z]/.test(password) && /[A-Z]/.test(password)) strength++;
if (/[0-9]/.test(password)) strength++;
if (/[^a-zA-Z0-9]/.test(password)) strength++;
strengthBar.className = 'password-strength';
if (strength <= 1) strengthBar.classList.add('strength-weak');
else if (strength <= 3) strengthBar.classList.add('strength-medium');
else strengthBar.classList.add('strength-strong');
});
</script>
</body>
</html>
منطق التسجيل مع التحقق
الآن لنضيف منطق PHP للتعامل مع إرسال النموذج بشكل آمن:
register.php (منطق PHP في الأعلى):
<?php
session_start();
// إعدادات قاعدة البيانات
$host = 'localhost';
$dbname = 'your_database';
$db_username = 'your_username';
$db_password = 'your_password';
// تهيئة المتغيرات
$errors = [];
$success_message = '';
$full_name = '';
$username = '';
$email = '';
// إنشاء اتصال بقاعدة البيانات
try {
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $db_username, $db_password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("فشل الاتصال: " . $e->getMessage());
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// الحصول على المدخلات وتنظيفها
$full_name = trim($_POST['full_name'] ?? '');
$username = trim($_POST['username'] ?? '');
$email = trim($_POST['email'] ?? '');
$password = $_POST['password'] ?? '';
$confirm_password = $_POST['confirm_password'] ?? '';
// التحقق من الاسم الكامل
if (empty($full_name)) {
$errors['full_name'] = 'الاسم الكامل مطلوب';
} elseif (strlen($full_name) < 2) {
$errors['full_name'] = 'الاسم الكامل يجب أن يكون حرفين على الأقل';
} elseif (strlen($full_name) > 100) {
$errors['full_name'] = 'الاسم الكامل يجب ألا يتجاوز 100 حرف';
}
// التحقق من اسم المستخدم
if (empty($username)) {
$errors['username'] = 'اسم المستخدم مطلوب';
} elseif (strlen($username) < 3) {
$errors['username'] = 'اسم المستخدم يجب أن يكون 3 أحرف على الأقل';
} elseif (strlen($username) > 50) {
$errors['username'] = 'اسم المستخدم يجب ألا يتجاوز 50 حرف';
} elseif (!preg_match('/^[a-zA-Z0-9_]+$/', $username)) {
$errors['username'] = 'اسم المستخدم يمكن أن يحتوي فقط على حروف وأرقام وشرطة سفلية';
} else {
// التحقق من وجود اسم المستخدم
$stmt = $pdo->prepare('SELECT id FROM users WHERE username = ?');
$stmt->execute([$username]);
if ($stmt->fetch()) {
$errors['username'] = 'اسم المستخدم مستخدم بالفعل';
}
}
// التحقق من البريد الإلكتروني
if (empty($email)) {
$errors['email'] = 'البريد الإلكتروني مطلوب';
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors['email'] = 'تنسيق البريد الإلكتروني غير صالح';
} else {
// التحقق من وجود البريد الإلكتروني
$stmt = $pdo->prepare('SELECT id FROM users WHERE email = ?');
$stmt->execute([$email]);
if ($stmt->fetch()) {
$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 (empty($confirm_password)) {
$errors['confirm_password'] = 'يرجى تأكيد كلمة المرور';
} elseif ($password !== $confirm_password) {
$errors['confirm_password'] = 'كلمات المرور غير متطابقة';
}
// إذا لم تكن هناك أخطاء، قم بإنشاء المستخدم
if (empty($errors)) {
try {
// تشفير كلمة المرور
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
// إدراج المستخدم في قاعدة البيانات
$stmt = $pdo->prepare('
INSERT INTO users (username, email, password, full_name)
VALUES (?, ?, ?, ?)
');
$stmt->execute([$username, $email, $hashed_password, $full_name]);
$success_message = 'تم التسجيل بنجاح! يمكنك الآن تسجيل الدخول.';
// مسح حقول النموذج
$full_name = '';
$username = '';
$email = '';
} catch (PDOException $e) {
$errors['general'] = 'فشل التسجيل. يرجى المحاولة مرة أخرى.';
error_log($e->getMessage());
}
}
}
?>
تحذير أمني: لا تقم أبداً بتخزين كلمات المرور بنص عادي! استخدم دائماً
password_hash() مع PASSWORD_DEFAULT، والذي يستخدم حالياً bcrypt وسيقوم تلقائياً بالترقية إلى خوارزميات أقوى في إصدارات PHP المستقبلية.
أفضل الممارسات
- قم دائماً بتشفير كلمات المرور باستخدام
password_hash()معPASSWORD_DEFAULT - التحقق من جانب العميل والخادم - لا تثق أبداً في التحقق من جانب العميل فقط
- استخدم العبارات المحضرة لمنع حقن SQL
- تنظيف والتحقق من جميع المدخلات قبل المعالجة
- التحقق من أسماء المستخدمين/البريد الإلكتروني المكررة قبل الإدراج
- استخدم HTTPS لتشفير نقل البيانات
- تنفيذ تقييد المعدل لمنع هجمات القوة الغاشمة
تمرين:
- أنشئ جدول المستخدمين في قاعدة البيانات الخاصة بك
- قم بتنفيذ نموذج التسجيل مع جميع قواعد التحقق
- اختبر بمدخلات مختلفة: كلمات مرور قصيرة، رسائل بريد إلكتروني غير صالحة، أسماء مستخدمين مكررة
- أضف خانة اختيار "الشروط والأحكام" يجب تحديدها قبل التسجيل
- قم بتنفيذ التحقق من البريد الإلكتروني (إرسال رمز تحقق إلى بريد المستخدم)
- أضف حماية CAPTCHA لمنع تسجيلات الروبوتات