الاتصال بقاعدة بيانات MySQL في PHP باستخدام PDO
حتى الآن، كل البيانات في برامجك تختفي بمجرد انتهاء تشغيل الصفحة. لكن المواقع الحقيقية تتذكر: الحسابات، والتعليقات، والطلبات. هذه البيانات تُحفظ في قاعدة بيانات (Database). في هذا الدرس الأخير من كورس PHP ستربط صفحاتك بقاعدة بيانات MySQL، وتقرأ منها وتكتب فيها بطريقة آمنة.
الصورة الكاملة
Section titled “الصورة الكاملة”قاعدة البيانات مثل أرشيف منظم فيه جداول، وكل جدول مثل جدول Excel: أعمدة (الاسم، العمر) وصفوف (كل صف طالب). وحتى تتحدث معها، تستخدم لغة اسمها SQL:
SELECT name, age FROM students;و PHP تعمل كـ وسيط: تستقبل طلب الزائر، وترسل استعلام SQL لقاعدة البيانات، ثم تحوّل النتيجة إلى صفحة HTML.
تجهيز قاعدة البيانات
Section titled “تجهيز قاعدة البيانات”إذا ثبّت XAMPP كما في الدرس الأول، فعندك MySQL جاهزة. شغّلها من لوحة التحكم، ثم افتح أداة phpMyAdmin على http://localhost/phpmyadmin، وأنشئ قاعدة بيانات باسم school، ونفّذ فيها هذا الأمر من تبويب SQL:
CREATE TABLE students ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) NOT NULL, age INT NOT NULL);هذا ينشئ جدولاً فيه ثلاثة أعمدة: رقم تلقائي id يزيد وحده مع كل طالب جديد، والاسم، والعمر.
الاتصال بـ PDO
Section titled “الاتصال بـ PDO”PHP تتصل بقواعد البيانات عبر PDO (PHP Data Objects)، وهي واجهة حديثة وآمنة تعمل مع MySQL وغيرها. نضع الاتصال في ملف مستقل لنستخدمه في كل الصفحات:
<?php$host = "localhost";$dbname = "school";$user = "root";$password = ""; // في XAMPP كلمة المرور فارغة افتراضياً
try { $pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $user, $password); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);} catch (PDOException $e) { die("فشل الاتصال بقاعدة البيانات");}- النص الأول يسمى DSN: نوع القاعدة (
mysql) والخادم واسم القاعدة. وcharset=utf8mb4ضروري لتُحفظ الحروف العربية سليمة. ERRMODE_EXCEPTION: أي خطأ في قاعدة البيانات يرمي استثناءً واضحاً بدل أن يمر بصمت.FETCH_ASSOC: النتائج تأتي كمصفوفات ترابطية، مثل$row["name"].tryوcatch: إذا فشل الاتصال، نعرض رسالة عامة. لا تعرض تفاصيل الخطأ$e->getMessage()للزوار، لأنها قد تكشف معلومات عن خادمك.
ثم في أي صفحة تحتاج قاعدة البيانات، اكتب في أولها require "db.php";.
قراءة البيانات
Section titled “قراءة البيانات”<?phprequire "db.php";
$stmt = $pdo->query("SELECT id, name, age FROM students ORDER BY id");$students = $stmt->fetchAll();
foreach ($students as $student) { echo $student["id"] . " - " . $student["name"] . " (" . $student["age"] . " سنة)\n";}إذا كان الجدول فيه ثلاثة طلاب، سيكون الناتج:
1 - سارة (14 سنة)2 - عمر (15 سنة)3 - منى (13 سنة)لاحظ أن fetchAll تعطيك مصفوفة متداخلة: قائمة صفوف، وكل صف مصفوفة ترابطية. هذا بالضبط ما تعلمته في درس المصفوفات.
عرض البيانات في جدول HTML
Section titled “عرض البيانات في جدول HTML”هنا يجتمع كل ما تعلمته في الكورس:
<?php require "db.php"; ?><?php $students = $pdo->query("SELECT * FROM students ORDER BY id")->fetchAll(); ?><table> <tr><th>الرقم</th><th>الاسم</th><th>العمر</th></tr> <?php foreach ($students as $s): ?> <tr> <td><?= $s["id"] ?></td> <td><?= htmlspecialchars($s["name"]) ?></td> <td><?= $s["age"] ?></td> </tr> <?php endforeach; ?></table>لاحظ htmlspecialchars حول الاسم: البيانات في القاعدة كتبها مستخدمون في الأصل، فهي مدخلات غير موثوقة أيضاً.
الإضافة الآمنة: الاستعلامات المجهزة
Section titled “الإضافة الآمنة: الاستعلامات المجهزة”لإضافة طالب جديد من نموذج، قد يخطر لك أن تكتب:
// خطير جداً، لا تفعل هذا أبداً$pdo->query("INSERT INTO students (name, age) VALUES ('$name', $age)");إذا كتب المهاجم في حقل الاسم نصاً يحتوي أوامر SQL، فسيصبح جزءاً من الاستعلام، ويستطيع قراءة أو حذف قاعدة بياناتك كلها! هذا الهجوم اسمه حقن SQL (SQL Injection).
الحل: الاستعلامات المجهزة (Prepared Statements). تكتب الاستعلام بعلامات ? مكان القيم، ثم ترسل القيم منفصلة:
<?phprequire "db.php";
$name = "سارة";$age = 14;
$stmt = $pdo->prepare("INSERT INTO students (name, age) VALUES (?, ?)");$stmt->execute([$name, $age]);
echo "تمت الإضافة، رقم الطالب: " . $pdo->lastInsertId();قاعدة البيانات تتعامل مع القيم المرسلة على أنها بيانات فقط، مهما كان محتواها، فلا يمكن أن تتحول إلى أوامر. تخيّل الفرق بين أن تعطي موظف البنك ورقة كتبها شخص غريب ليقرأها بصوت عالٍ وينفّذها، وبين أن تملأ أنت استمارة البنك الرسمية التي لا يُكتب في خاناتها إلا البيانات.
ويمكنك استخدام أسماء بدل علامات ?، وهي أوضح مع القيم الكثيرة:
<?php$stmt = $pdo->prepare("SELECT name FROM students WHERE age >= :age");$stmt->execute(["age" => 14]);
foreach ($stmt->fetchAll() as $row) { echo $row["name"] . "\n";}سارةعمرالتعديل والحذف
Section titled “التعديل والحذف”بنفس الطريقة الآمنة:
<?php$stmt = $pdo->prepare("UPDATE students SET age = ? WHERE id = ?");$stmt->execute([16, 2]);echo "عدد الصفوف المعدلة: " . $stmt->rowCount() . "\n";
$stmt = $pdo->prepare("DELETE FROM students WHERE id = ?");$stmt->execute([3]);echo "عدد الصفوف المحذوفة: " . $stmt->rowCount() . "\n";عدد الصفوف المعدلة: 1عدد الصفوف المحذوفة: 1rowCount تخبرك بعدد الصفوف التي تأثرت. وانتبه جيداً لشرط WHERE في التعديل والحذف: إذا نسيته، سيُعدَّل أو يُحذف كل الجدول!
جرّب بنفسك
Section titled “جرّب بنفسك”ابنِ صفحة صغيرة لإدارة الطلاب:
- أنشئ قاعدة
schoolوجدولstudentsكما سبق، والملفdb.php. - أنشئ
students.phpيعرض الطلاب في جدول. - أضف فوق الجدول نموذجاً بطريقة POST فيه حقلا الاسم والعمر، وعند الإرسال تحقق من البيانات كما في درس النماذج، ثم أضف الطالب باستعلام مجهز.
- تحدٍّ: أضف بجانب كل طالب زر «حذف» داخل نموذج POST صغير يرسل
idالطالب.
أخطاء شائعة
Section titled “أخطاء شائعة”- ظهور الحروف العربية كعلامات استفهام: نسيت
charset=utf8mb4في الاتصال، أو أن الجدول نفسه ليس بترميزutf8mb4. - وضع المتغيرات داخل نص الاستعلام: ثغرة حقن SQL. استخدم
prepareوexecuteدائماً. - عرض تفاصيل الخطأ للزوار: رسائل الأخطاء الكاملة للمطور فقط أثناء التطوير، لا في الموقع المنشور.
اختبر نفسك
Section titled “اختبر نفسك”سؤال
ما الطريقة الآمنة لإضافة اسم كتبه المستخدم إلى قاعدة البيانات؟
الاستعلامات المجهزة ترسل القيم منفصلة عن أمر SQL، فلا يمكن أن تتحول إلى أوامر، وهذا يمنع حقن SQL.
سؤال
لماذا نضيف charset=utf8mb4 في نص الاتصال؟
utf8mb4 ترميز يدعم كل الحروف، ومنها العربية والرموز التعبيرية، وبدونه قد تظهر علامات استفهام.
الخلاصة
Section titled “الخلاصة”- PHP تتصل بقاعدة البيانات عبر PDO، مع
charset=utf8mb4ووضع الاستثناءات. queryثمfetchAllلقراءة البيانات، والنتيجة مصفوفة صفوف ترابطية.prepareوexecuteلأي استعلام فيه مدخلات من المستخدم، لمنع حقن SQL.htmlspecialcharsعند عرض البيانات، وWHEREإجباري في التعديل والحذف.- أنت الآن تبني صفحات ديناميكية كاملة: نموذج يستقبل البيانات، وقاعدة بيانات تحفظها.