مقدمة
مرحباً بكم في هذا الدرس العملي حول بناء تطبيق CRUD بسيط باستخدام PHP و MySQL! سنتعلم معاً كيفية إنشاء تطبيق ويب يمكنه التعامل مع قاعدة بيانات من خلال عمليات CRUD الأساسية: الإنشاء (Create)، القراءة (Read)، التحديث (Update)، والحذف (Delete).
هذا المشروع مناسب للمبتدئين الذين لديهم معرفة أساسية بـ PHP و HTML، وسيساعدك على فهم كيفية ربط تطبيق ويب بقاعدة بيانات MySQL وإدارة البيانات بشكل فعال.
المتطلبات الأساسية
قبل البدء، تأكد من توفر ما يلي:
- خادم ويب محلي مثل XAMPP أو WAMP أو Laragon
- PHP (الإصدار 7.0 أو أحدث)
- MySQL
- محرر نصوص مثل Visual Studio Code أو Sublime Text
- معرفة أساسية بـ HTML و PHP
إعداد قاعدة البيانات
أول خطوة هي إنشاء قاعدة بيانات MySQL وجدول لتخزين بيانات المستخدمين. سنستخدم phpMyAdmin لإنشاء قاعدة البيانات والجدول.
- افتح phpMyAdmin (عادة ما يكون متاحاً على http://localhost/phpmyadmin/)
- أنشئ قاعدة بيانات جديدة باسم
user_management
- داخل قاعدة البيانات، أنشئ جدولاً باسم
users
بالحقول التالية:
CREATE TABLE users (
id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) NOT NULL,
phone VARCHAR(15) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
يمكنك أيضاً إضافة بعض البيانات الافتراضية للاختبار:
INSERT INTO users (name, email, phone) VALUES
('أحمد محمد', '[email protected]', '0612345678'),
('سارة أحمد', '[email protected]', '0698765432'),
('محمد علي', '[email protected]', '0654321987');
هيكل المشروع
سننشئ مشروعاً بسيطاً بالهيكل التالي:
user_management/
├── config/
│ └── database.php
├── create.php
├── delete.php
├── index.php
├── read.php
├── update.php
└── css/
└── style.css
إنشاء اتصال بقاعدة البيانات
أولاً، سننشئ ملف الإعدادات لإدارة الاتصال بقاعدة البيانات. أنشئ ملف config/database.php
:
<?php
// معلومات الاتصال بقاعدة البيانات
$host = "localhost";
$username = "root";
$password = ""; // قد تحتاج لتغيير كلمة المرور حسب إعدادات خادم MySQL الخاص بك
$database = "user_management";
// إنشاء اتصال
$conn = new mysqli($host, $username, $password, $database);
// التحقق من الاتصال
if ($conn->connect_error) {
die("فشل الاتصال بقاعدة البيانات: " . $conn->connect_error);
}
// ضبط الترميز لدعم اللغة العربية
$conn->set_charset("utf8");
?>
صفحة عرض المستخدمين (Read)
الآن سننشئ الصفحة الرئيسية index.php
التي ستعرض قائمة المستخدمين وتوفر روابط للعمليات الأخرى:
<?php
// تضمين ملف الاتصال بقاعدة البيانات
require_once "config/database.php";
// استعلام لجلب جميع المستخدمين
$sql = "SELECT * FROM users ORDER BY created_at DESC";
$result = $conn->query($sql);
?>
<!DOCTYPE html>
<html dir="rtl" lang="ar">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>إدارة المستخدمين</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="container">
<h1>نظام إدارة المستخدمين</h1>
<a href="create.php" class="btn btn-primary">إضافة مستخدم جديد</a>
<table class="table">
<thead>
<tr>
<th>الرقم</th>
<th>الاسم</th>
<th>البريد الإلكتروني</th>
<th>رقم الهاتف</th>
<th>تاريخ الإنشاء</th>
<th>الإجراءات</th>
</tr>
</thead>
<tbody>
<?php
if ($result->num_rows > 0) {
while ($row = $result->fetch_assoc()) {
echo "<tr>";
echo "<td>" . $row['id'] . "</td>";
echo "<td>" . $row['name'] . "</td>";
echo "<td>" . $row['email'] . "</td>";
echo "<td>" . $row['phone'] . "</td>";
echo "<td>" . $row['created_at'] . "</td>";
echo "<td>
<a href='read.php?id=" . $row['id'] . "' class='btn btn-info'>عرض</a>
<a href='update.php?id=" . $row['id'] . "' class='btn btn-warning'>تعديل</a>
<a href='delete.php?id=" . $row['id'] . "' class='btn btn-danger' onclick='return confirm(\"هل أنت متأكد من حذف هذا المستخدم؟\")'>حذف</a>
</td>";
echo "</tr>";
}
} else {
echo "<tr><td colspan='6'>لا يوجد مستخدمين</td></tr>";
}
?>
</tbody>
</table>
</div>
</body>
</html>
<?php
// إغلاق الاتصال
$conn->close();
?>
إنشاء مستخدم جديد (Create)
الآن سننشئ صفحة create.php
لإضافة مستخدمين جدد:
<?php
// تضمين ملف الاتصال بقاعدة البيانات
require_once "config/database.php";
// تعريف متغيرات لتخزين رسائل الخطأ والنجاح
$nameErr = $emailErr = $phoneErr = "";
$name = $email = $phone = "";
$success_message = "";
// التحقق من إرسال النموذج
if ($_SERVER["REQUEST_METHOD"] == "POST") {
// التحقق من الاسم
if (empty($_POST["name"])) {
$nameErr = "الاسم مطلوب";
} else {
$name = trim($_POST["name"]);
}
// التحقق من البريد الإلكتروني
if (empty($_POST["email"])) {
$emailErr = "البريد الإلكتروني مطلوب";
} else {
$email = trim($_POST["email"]);
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$emailErr = "صيغة البريد الإلكتروني غير صحيحة";
}
}
// التحقق من رقم الهاتف
if (empty($_POST["phone"])) {
$phoneErr = "رقم الهاتف مطلوب";
} else {
$phone = trim($_POST["phone"]);
}
// إذا لم تكن هناك أخطاء، قم بإدخال البيانات
if (empty($nameErr) && empty($emailErr) && empty($phoneErr)) {
// استعلام لإدخال بيانات المستخدم الجديد
$sql = "INSERT INTO users (name, email, phone) VALUES (?, ?, ?)";
if ($stmt = $conn->prepare($sql)) {
// ربط المتغيرات بالاستعلام كمعلمات
$stmt->bind_param("sss", $name, $email, $phone);
// تنفيذ الاستعلام
if ($stmt->execute()) {
$success_message = "تم إضافة المستخدم بنجاح";
// إعادة تعيين القيم
$name = $email = $phone = "";
} else {
echo "حدث خطأ أثناء تنفيذ الاستعلام: " . $stmt->error;
}
// إغلاق الاستعلام
$stmt->close();
} else {
echo "حدث خطأ في إعداد الاستعلام: " . $conn->error;
}
}
}
?>
<!DOCTYPE html>
<html dir="rtl" lang="ar">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>إضافة مستخدم جديد</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="container">
<h1>إضافة مستخدم جديد</h1>
<a href="index.php" class="btn btn-secondary">العودة إلى القائمة</a>
<?php if (!empty($success_message)): ?>
<div class="alert alert-success"><?php echo $success_message; ?></div>
<?php endif; ?>
<form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" method="post">
<div class="form-group">
<label>الاسم</label>
<input type="text" name="name" class="form-control <?php echo (!empty($nameErr)) ? 'is-invalid' : ''; ?>" value="<?php echo $name; ?>">
<span class="invalid-feedback"><?php echo $nameErr; ?></span>
</div>
<div class="form-group">
<label>البريد الإلكتروني</label>
<input type="email" name="email" class="form-control <?php echo (!empty($emailErr)) ? 'is-invalid' : ''; ?>" value="<?php echo $email; ?>">
<span class="invalid-feedback"><?php echo $emailErr; ?></span>
</div>
<div class="form-group">
<label>رقم الهاتف</label>
<input type="text" name="phone" class="form-control <?php echo (!empty($phoneErr)) ? 'is-invalid' : ''; ?>" value="<?php echo $phone; ?>">
<span class="invalid-feedback"><?php echo $phoneErr; ?></span>
</div>
<input type="submit" class="btn btn-primary" value="إضافة مستخدم">
</form>
</div>
</body>
</html>
<?php
// إغلاق الاتصال
$conn->close();
?>
عرض تفاصيل مستخدم (Read Single)
الآن سننشئ صفحة read.php
لعرض تفاصيل مستخدم واحد:
<?php
// تضمين ملف الاتصال بقاعدة البيانات
require_once "config/database.php";
// التحقق من وجود معرف المستخدم في عنوان URL
if (isset($_GET["id"]) && !empty(trim($_GET["id"]))) {
// تحضير استعلام SELECT
$sql = "SELECT * FROM users WHERE id = ?";
if ($stmt = $conn->prepare($sql)) {
// ربط المتغيرات بالاستعلام كمعلمات
$stmt->bind_param("i", $param_id);
// تعيين المعلمات
$param_id = trim($_GET["id"]);
// محاولة تنفيذ الاستعلام
if ($stmt->execute()) {
$result = $stmt->get_result();
if ($result->num_rows == 1) {
// استخراج صف النتيجة كمصفوفة ترابطية
$row = $result->fetch_assoc();
// استخراج قيم الحقول الفردية
$name = $row["name"];
$email = $row["email"];
$phone = $row["phone"];
$created_at = $row["created_at"];
} else {
// لم يتم العثور على سجل بهذا المعرف
header("location: index.php");
exit();
}
} else {
echo "حدث خطأ! يرجى المحاولة مرة أخرى لاحقاً.";
}
}
// إغلاق الاستعلام
$stmt->close();
} else {
// معرف URL غير موجود
header("location: index.php");
exit();
}
?>
<!DOCTYPE html>
<html dir="rtl" lang="ar">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>عرض تفاصيل المستخدم</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="container">
<h1>عرض تفاصيل المستخدم</h1>
<a href="index.php" class="btn btn-secondary">العودة إلى القائمة</a>
<div class="user-details">
<div class="form-group">
<label>الاسم</label>
<p class="form-control-static"><?php echo $name; ?></p>
</div>
<div class="form-group">
<label>البريد الإلكتروني</label>
<p class="form-control-static"><?php echo $email; ?></p>
</div>
<div class="form-group">
<label>رقم الهاتف</label>
<p class="form-control-static"><?php echo $phone; ?></p>
</div>
<div class="form-group">
<label>تاريخ الإنشاء</label>
<p class="form-control-static"><?php echo $created_at; ?></p>
</div>
</div>
</div>
</body>
</html>
<?php
// إغلاق الاتصال
$conn->close();
?>
تحديث بيانات مستخدم (Update)
الآن سننشئ صفحة update.php
لتحديث بيانات المستخدمين:
<?php
// تضمين ملف الاتصال بقاعدة البيانات
require_once "config/database.php";
// تعريف متغيرات وتهيئتها بقيم فارغة
$name = $email = $phone = "";
$nameErr = $emailErr = $phoneErr = "";
// معالجة بيانات النموذج عند إرساله
if (isset($_POST["id"]) && !empty($_POST["id"])) {
// الحصول على معرف المدخل المخفي
$id = $_POST["id"];
// التحقق من الاسم
if (empty($_POST["name"])) {
$nameErr = "الاسم مطلوب";
} else {
$name = trim($_POST["name"]);
}
// التحقق من البريد الإلكتروني
if (empty($_POST["email"])) {
$emailErr = "البريد الإلكتروني مطلوب";
} else {
$email = trim($_POST["email"]);
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$emailErr = "صيغة البريد الإلكتروني غير صحيحة";
}
}
// التحقق من رقم الهاتف
if (empty($_POST["phone"])) {
$phoneErr = "رقم الهاتف مطلوب";
} else {
$phone = trim($_POST["phone"]);
}
// التحقق من أخطاء الإدخال قبل تحديث قاعدة البيانات
if (empty($nameErr) && empty($emailErr) && empty($phoneErr)) {
// تحضير بيان التحديث
$sql = "UPDATE users SET name=?, email=?, phone=? WHERE id=?";
if ($stmt = $conn->prepare($sql)) {
// ربط المتغيرات بالاستعلام المعد
$stmt->bind_param("sssi", $name, $email, $phone, $param_id);
// تعيين المعلمات
$param_id = $id;
// محاولة تنفيذ الاستعلام المعد
if ($stmt->execute()) {
// تم تحديث السجلات بنجاح. إعادة التوجيه إلى الصفحة الرئيسية
header("location: index.php");
exit();
} else {
echo "حدث خطأ! يرجى المحاولة مرة أخرى لاحقاً.";
}
}
// إغلاق البيان
$stmt->close();
}
} else {
// التحقق من وجود معلمة معرف قبل معالجة البيانات الإضافية
if (isset($_GET["id"]) && !empty(trim($_GET["id"]))) {
// الحصول على معلمة URL
$id = trim($_GET["id"]);
// تحضير بيان تحديد
$sql = "SELECT * FROM users WHERE id = ?";
if ($stmt = $conn->prepare($sql)) {
// ربط المتغيرات بالبيان المعد كمعلمات
$stmt->bind_param("i", $param_id);
// تعيين المعلمات
$param_id = $id;
// محاولة تنفيذ البيان المعد
if ($stmt->execute()) {
$result = $stmt->get_result();
if ($result->num_rows == 1) {
// استخراج صف النتيجة كمصفوفة ترابطية
$row = $result->fetch_assoc();
// استخراج قيم الحقول الفردية
$name = $row["name"];
$email = $row["email"];
$phone = $row["phone"];
} else {
// لم يتم العثور على سجل بهذا المعرف. إعادة التوجيه إلى صفحة الخطأ
header("location: index.php");
exit();
}
} else {
echo "حدث خطأ! يرجى المحاولة مرة أخرى لاحقاً.";
}
}
// إغلاق البيان
$stmt->close();
} else {
// معلمة URL غير موجودة. إعادة التوجيه إلى صفحة الخطأ
header("location: index.php");
exit();
}
}
?>
<!DOCTYPE html>
<html dir="rtl" lang="ar">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>تحديث بيانات المستخدم</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="container">
<h1>تحديث بيانات المستخدم</h1>
<a href="index.php" class="btn btn-secondary">العودة إلى القائمة</a>
<form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" method="post">
<div class="form-group">
<label>الاسم</label>
<input type="text" name="name" class="form-control <?php echo (!empty($nameErr)) ? 'is-invalid' : ''; ?>" value="<?php echo $name; ?>">
<span class="invalid-feedback"><?php echo $nameErr; ?></span>
</div>
<div class="form-group">
<label>البريد الإلكتروني</label>
<input type="email" name="email" class="form-control <?php echo (!empty($emailErr)) ? 'is-invalid' : ''; ?>" value="<?php echo $email; ?>">
<span class="invalid-feedback"><?php echo $emailErr; ?></span>
</div>
<div class="form-group">
<label>رقم الهاتف</label>
<input type="text" name="phone" class="form-control <?php echo (!empty($phoneErr)) ? 'is-invalid' : ''; ?>" value="<?php echo $phone; ?>">
<span class="invalid-feedback"><?php echo $phoneErr; ?></span>
</div>
<input type="hidden" name="id" value="<?php echo $id; ?>">
<input type="submit" class="btn btn-primary" value="تحديث">
</form>
</div>
</body>
</html>
<?php
// إغلاق الاتصال
$conn->close();
?>
حذف مستخدم (Delete)
أخيراً، سننشئ صفحة delete.php
لحذف المستخدمين:
<?php
// تضمين ملف الاتصال بقاعدة البيانات
require_once "config/database.php";
// معالجة عملية الحذف
if (isset($_GET["id"]) && !empty(trim($_GET["id"]))) {
// تحضير بيان الحذف
$sql = "DELETE FROM users WHERE id = ?";
if ($stmt = $conn->prepare($sql)) {
// ربط المتغيرات بالبيان المعد كمعلمات
$stmt->bind_param("i", $param_id);
// تعيين المعلمات
$param_id = trim($_GET["id"]);
// محاولة تنفيذ البيان المعد
if ($stmt->execute()) {
// تم حذف السجل بنجاح. إعادة التوجيه إلى الصفحة الرئيسية
header("location: index.php");
exit();
} else {
echo "حدث خطأ! يرجى المحاولة مرة أخرى لاحقاً.";
}
}
// إغلاق البيان
$stmt->close();
} else {
// معلمة URL غير موجودة
header("location: index.php");
exit();
}
// إغلاق الاتصال
$conn->close();
?>
تصميم CSS
لتحسين مظهر التطبيق، سننشئ ملف css/style.css
بالمحتوى التالي:
/* تنسيقات عامة */
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: #f8f9fa;
margin: 0;
padding: 20px;
}
.container {
max-width: 1000px;
margin: 0 auto;
background-color: #fff;
padding: 20px;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
h1 {
color: #343a40;
margin-bottom: 20px;
border-bottom: 1px solid #dee2e6;
padding-bottom: 10px;
}
/* تنسيقات الأزرار */
.btn {
display: inline-block;
padding: 8px 12px;
margin-bottom: 20px;
font-size: 14px;
font-weight: 400;
text-align: center;
white-space: nowrap;
vertical-align: middle;
cursor: pointer;
border: 1px solid transparent;
border-radius: 4px;
text-decoration: none;
}
.btn-primary {
color: #fff;
background-color: #007bff;
border-color: #007bff;
}
.btn-secondary {
color: #fff;
background-color: #6c757d;
border-color: #6c757d;
}
.btn-info {
color: #fff;
background-color: #17a2b8;
border-color: #17a2b8;
}
.btn-warning {
color: #212529;
background-color: #ffc107;
border-color: #ffc107;
}
.btn-danger {
color: #fff;
background-color: #dc3545;
border-color: #dc3545;
}
/* تنسيقات الجدول */
.table {
width: 100%;
margin-bottom: 1rem;
color: #212529;
border-collapse: collapse;
}
.table th,
.table td {
padding: 12px;
vertical-align: top;
border-top: 1px solid #dee2e6;
text-align: right;
}
.table thead th {
vertical-align: bottom;
border-bottom: 2px solid #dee2e6;
background-color: #f8f9fa;
}
.table tbody tr:hover {
background-color: rgba(0, 123, 255, 0.05);
}
/* تنسيقات النموذج */
.form-group {
margin-bottom: 1rem;
}
.form-group label {
display: inline-block;
margin-bottom: 0.5rem;
font-weight: bold;
}
.form-control {
display: block;
width: 100%;
padding: 0.375rem 0.75rem;
font-size: 1rem;
line-height: 1.5;
color: #495057;
background-color: #fff;
background-clip: padding-box;
border: 1px solid #ced4da;
border-radius: 0.25rem;
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}
.form-control:focus {
color: #495057;
background-color: #fff;
border-color: #80bdff;
outline: 0;
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}
.is-invalid {
border-color: #dc3545;
}
.invalid-feedback {
display: block;
width: 100%;
margin-top: 0.25rem;
font-size: 80%;
color: #dc3545;
}
.form-control-static {
padding-top: 0.375rem;
padding-bottom: 0.375rem;
margin-bottom: 0;
line-height: 1.5;
border-bottom: 1px solid #eee;
}
/* تنسيقات التنبيهات */
.alert {
position: relative;
padding: 0.75rem 1.25rem;
margin-bottom: 1rem;
border: 1px solid transparent;
border-radius: 0.25rem;
}
.alert-success {
color: #155724;
background-color: #d4edda;
border-color: #c3e6cb;
}
/* تنسيقات تفاصيل المستخدم */
.user-details {
background-color: #f8f9fa;
padding: 20px;
border-radius: 5px;
margin-top: 20px;
}
الخلاصة
في هذا الدرس، قمنا ببناء تطبيق CRUD بسيط باستخدام PHP و MySQL. تعلمنا كيفية:
- إنشاء قاعدة بيانات MySQL وجدول لتخزين البيانات
- إنشاء اتصال آمن بقاعدة البيانات باستخدام PHP
- تنفيذ عمليات CRUD الأساسية:
- إنشاء سجلات جديدة (Create)
- قراءة وعرض البيانات (Read)
- تحديث السجلات الموجودة (Update)
- حذف السجلات (Delete)
- التحقق من صحة بيانات المستخدم
- استخدام الاستعلامات المعدة (Prepared Statements) لمنع هجمات حقن SQL
- تصميم واجهة مستخدم بسيطة وسهلة الاستخدام
هذا المشروع يمكن أن يكون نقطة انطلاق ممتازة لبناء تطبيقات ويب أكثر تعقيداً باستخدام PHP و MySQL. يمكنك توسيع هذا المشروع بإضافة ميزات إضافية مثل:
- تسجيل الدخول والمصادقة
- البحث والتصفية
- تحميل الصور
- تصدير البيانات إلى CSV أو PDF
- إضافة المزيد من الجداول والعلاقات
لا تتردد في تجربة هذا المشروع وتخصيصه حسب احتياجاتك. إذا كان لديك أي أسئلة أو استفسارات، فلا تتردد في مشاركتها في قسم التعليقات أدناه.
هل جربت بناء تطبيق CRUD باستخدام PHP و MySQL من قبل؟ ما هي التحديات التي واجهتك؟ شاركنا تجربتك!