انتقل إلى محتوى الدرس
الدرس 80
دورة PHP

الاستعلامات المحضرة وإدراج البيانات بأمان ضد SQL Injection في PHPPHP PDO Prepared Statements and Inserting Data

تعلّم الاستعلامات المحضرة وإدراج البيانات بأمان ضد SQL Injection في PHP بأسلوب PHP 8 الحديث مع أمثلة عملية وتطبيقات تفاعلية.
أقسام الدرس
6
الأمثلة
5
اللغة
العربية
تاريخ النشر
غير محدد
المشاهدات
5
محتوى الدرس
في هذا الدرس 6تصفّح المواضيع

تُعد ثغرة حقن أوامر SQL (SQL Injection — SQLi) من أخطر الثغرات الأمنية في تطبيقات الويب، وتحدث عندما يقوم المبرمج بدمج متغيرات المستخدم نصياً داخل جملة الاستعلام:

  • كيف يقع الاختراق: عند كتابة متغير مباشرة داخل نص SQL، يستطيع المهاجم إدخال علامة تنصيص مفردة متبوعة بأوامر منطقية مثل ' OR '1'='1 لتغيير معنى الاستعلام بالكامل أو مسح الجداول.
  • القاعدة الذهبية الصارمة: لا تدمج أي متغير نصياً داخل جملة SQL تحت أي ظرف كان.
مخطط يوضح مراحل الاستعلام المحضر عبر prepare و execute وقراءة lastInsertId لمنع حقن SQL في PHP 8.4
PHP
<?php
// NEVER concatenate variables into SQL like this:
// $badSql = "INSERT INTO logs VALUES ('" . $input . "')";

// ALWAYS use placeholders (?) or (:name) with prepare():
$safeSql = "INSERT INTO logs (message) VALUES (:message)";
echo $safeSql;

تقضي الاستعلامات المحضرة (Prepared Statements) على ثغرة حقن SQL بنسبة 100% لأنها تنفذ الاستعلام عبر مرحلتين منفصلتين تماماً في بروتوكول قاعدة البيانات:

  • المرحلة الأولى — $pdo->prepare($sql): يرسل PHP قالب الاستعلام وبداخله رموز نائبة (Placeholders مثل :email أو ?) إلى خادم قاعدة البيانات ليقوم بتحليل هيكل الأمر وتثبيته أولاً.
  • المرحلة الثانية — $stmt->execute($params): تُرسل القيم الفعلية في حزمة منفصلة؛ وبما أن شجرة الأمر قد تُرجمت مسبقاً، يستحيل أن تتحول البيانات المرسلة إلى أوامر تنفيذية.
PHP
<?php
$pdo = new PDO("sqlite::memory:");
$pdo->exec("CREATE TABLE subscribers (email TEXT)");

// Step 1: Prepare template (returns PDOStatement)
$stmt = $pdo->prepare("INSERT INTO subscribers (email) VALUES (:email)");

// Step 2: Execute with bound data
$stmt->execute(["email" => "[email protected]"]);
echo "Subscriber saved safely.";

تُكتب المعاملات المسماة (Named Placeholders) بوضع نقطتين رأسيتين قبل اسم وصفي داخل جملة SQL (مثل :title و:price)، ثم تُمرر قيمها في مصفوفة ترابطية داخل الدالة $stmt->execute([...]):

  • وضوح القراءة والصيانة: تُعد الخيار الأفضل في استعلامات الإدراج والتحديث التي تضم عدة أعمدة لأن كل مفتاح يوضح اسم الحقل المرتبط به.
  • عدم التقيد بالترتيب: يطابق PDO المفاتيح بالاسم، ولا يشترط كتابة النقطتين الرأسيتين في مفاتيح مصفوفة execute ("title" => $val).
PHP
<?php
$pdo = new PDO("sqlite::memory:");
$pdo->exec("CREATE TABLE products (title TEXT, price REAL)");

$stmt = $pdo->prepare(
    "INSERT INTO products (title, price) VALUES (:title, :price)"
);
$stmt->execute([
    "title" => "Mechanical Keyboard",
    "price" => 129.99,
]);
echo "Product inserted.";

تستخدم المعاملات الموضعية (Positional Placeholders) علامة الاستفهام (?) داخل جملة SQL، وتُربط قيمها بتمرير مصفوفة متسلسلة إلى الدالة $stmt->execute([...]):

  • صياغة مختصرة وسريعة: مناسبة جداً للاستعلامات القصيرة التي تحتوي على معامل واحد أو معاملين.
  • التطابق الصارم في العدد والترتيب: يجب أن يتطابق عدد عناصر المصفوفة الممررة وترتيبها مع علامات الاستفهام في الاستعلام تماماً.
مخطط تدفق التنفيذ العملي لقسم معاملات الاستفهام الموضعية في PDO في لغة PHP
PHP
<?php
$pdo = new PDO("sqlite::memory:");
$pdo->exec("CREATE TABLE tasks (title TEXT, done INTEGER)");

$stmt = $pdo->prepare("INSERT INTO tasks (title, done) VALUES (?, ?)");
$stmt->execute(["Deploy PHP 8.4", 1]);
$stmt->execute(["Run PDO Audit", 0]);
echo "2 tasks inserted.";

بعد إدراج سجل جديد في جدول يحتوي على مفتاح أساسي تلقائي الزيادة (AUTO_INCREMENT)، نستدعي الدالة $pdo->lastInsertId() للحصول على المعرف الرقمي الذي ولّدته قاعدة البيانات للسجل المضاف:

  • تُستدعى من الكائن $pdo وليس $stmt: انتبه دائماً إلى أن lastInsertId() دالة تابعة لكائن الاتصال $pdo وتُرجع المعرف كنص.
  • معزولة لكل جلسة اتصال: حتى لو قام مئات الزوار بإضافة سجلات في نفس اللحظة، تُرجع $pdo->lastInsertId() المعرف الخاص بعملية الإدراج التي تمت على اتصالك الحالي فقط.
PHP
<?php
$pdo = new PDO("sqlite::memory:");
$pdo->exec("CREATE TABLE orders (id INTEGER PRIMARY KEY AUTOINCREMENT, total REAL)");

$stmt = $pdo->prepare("INSERT INTO orders (total) VALUES (:total)");
$stmt->execute(["total" => 450.00]);

$newOrderId = (int) $pdo->lastInsertId();
echo "Created Order #" . $newOrderId;

يلخص الجدول المرجعي التالي دوال الاستعلامات المحضرة وأنماط المعاملات في واجهة PDO:

الدالة / الميزةتُستدعى عبرمثال الصياغةالوظيفة الأساسية
prepare()$pdo$stmt = $pdo->prepare($sql);تحضير قالب الاستعلام وإرجاع كائن PDOStatement
execute()$stmt$stmt->execute(["email" => $e]);ربط قيم المدخلات بأمان وتنفيذ الاستعلام المحضر
المعامل المسمىجملة SQLVALUES (:email, :role)ربط واضح بالاسم للاستعلامات متعددة الحقول
المعامل الموضعيجملة SQLVALUES (?, ?)ربط مختصر بالترتيب للاستعلامات السريعة
lastInsertId()$pdo$id = $pdo->lastInsertId();إرجاع المعرف التلقائي للسجل المضاف حديثاً
خلاصة المعرفة ومحطة الانتقال

ملخص الدرس

حصاد الدرس

مراجعة مركّزة لأهم المفاهيم والقواعد الهندسية التي أتقنتها في هذا الدرس قبل التطبيق العملي

ماذا تعلّمت في هذا الدرس؟

تعلمت في هذا الدرس كيف تحدث ثغرة حقن SQL عند دمج المتغيرات نصياً، وكيف تمنعها الاستعلامات المحضرة عبر فصل التحضير prepare() عن التنفيذ execute()، وكيفية إدراج البيانات بالمعاملات المسماة والموضعية، وقراءة معرف السجل الجديد عبر $pdo->lastInsertId(). الخطوة التالية: انتقل إلى الدرس الخامس والخمسين «استعلامات الجلب والفلترة والترتيب عبر PDO في PHP» لقراءة البيانات من الجداول بمرونة وأمان.

مشاركة

هل كان هذا الدرس مفيدًا؟

جارٍ تحميل الآراء…

ابنِ لغتك البرمجية

المصطلحات4

راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.

0 / 4 مفهومةأول بطاقة، أول خطوة
01 Prepared Statements الاستعلامات المحضرة
تعلّم الاستعلامات المحضرة وإدراج البيانات بأمان ضد SQL Injection في PHP بأسلوب PHP 8 الحديث مع أمثلة عملية وتطبيقات تفاعلية.
للمراجعة
02 How SQL Injection Attacks Happen كيف تحدث ثغرة حقن SQL
المفهوم الأساسي لقسم كيف تحدث ثغرة حقن SQL في لغة PHP الحديثة.
للمراجعة
03 How Prepared Statements Stop SQLi كيف تفصل الاستعلامات المحضرة الكود
الصياغة البرمجية والتطبيق العملي المباشر لقسم كيف تفصل الاستعلامات المحضرة الكود.
للمراجعة
04 Named Placeholders with execute المعاملات المسماة وتنفيذ الاستعلام
قواعد التحقق وأفضل الممارسات القياسية الخاصة بقسم المعاملات المسماة وتنفيذ الاستعلام.
للمراجعة

اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.

حروف قليلة. معنى كامل.

الاختصارات4

راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.

0 / 4 مفهومةأول بطاقة، أول خطوة
01 PHP PHP
PHP: Hypertext Preprocessor
لغة البرمجة النصية على جانب الخادم لبناء تطبيقات الويب الديناميكية وواجهات البرمجة.
للمراجعة
02 CLI CLI
Command-Line Interface
واجهة سطر الأوامر التي تتيح تشغيل ملفات PHP مباشرة عبر الطرفية.
للمراجعة
03 FPM FPM
FastCGI Process Manager
مدير عمليات FastCGI عالي الأداء لمعالجة طلبات خادم الويب في PHP.
للمراجعة
04 HTML HTML
HyperText Markup Language
لغة الترميز القياسية التي يولدها محرك PHP ويرسلها إلى متصفح العميل بعد التنفيذ.
للمراجعة

اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.

من الفهم للتطبيق

مهامك قبل الاختبار

خطوة صغيرة كل مرة. وإنجاز تقدر ترجع له.

0/2مهام منجزة
  1. أنشئ ملف PHP محلياً ونفّذ المثال البرمجي المشروح في قسم كيف تحدث ثغرة حقن SQL للتحقق من المخرجات.

  2. بدّل بين الحالات الثلاث في المحاكي التفاعلي ضمن قسم كيف تفصل الاستعلامات المحضرة الكود وقارن مخرجات التنفيذ.

تأشير المهمة إقرار منك بإتمامها، وليس تصحيحًا آليًا للكود. يُحفظ تقدمك في حسابك.

مساحة التحدي

اختبر فهمك.
ووصلها للإتقان.

كل سؤال خطوة لقدّام. اختار، اكتب كود، وشوف نتيجتك فورًا.

8أسئلة 3أنواع تحديات 100%هدف الإتقان
تصحيح تلقائي. فرص بلا حدود.

أكمل المهام، واجمع كل الإجابات الصحيحة. أقل من 100%؟ راجع وأعد المحاولة.

الأسئلة متاحة للاطلاع. سجّل الدخول للتفاعل وحفظ تقدمك.

لمحة عن التحدي8 أسئلة تنتظرك
01

ما السبب الجذري لظهور ثغرة حقن SQL (SQL Injection) في تطبيقات PHP؟

دمج المتغيرات ومدخلات المستخدم نصياً داخل جملة SQL بدلاً من فصلها عبر الاستعلامات المحضرة.

02

ما نوع الكائن الذي تُرجعه الدالة $pdo->prepare($sql) عند تحضير الاستعلام؟

تُرجع الدالة $pdo->prepare() كائناً من الصنف PDOStatement.

03

أي صياغة مما يلي تستخدم المعاملات المسماة (Named Placeholders) بشكل صحيح في استعلام PDO محضر؟

تبدأ المعاملات المسماة بنقطتين رأسيتين مثل :email و :role داخل جملة SQL.

04

يمكنك الخلط بين المعاملات المسماة (:email) والمعاملات الموضعية (?) داخل نفس جملة SQL الواحدة في PDO.

خطأ؛ يمنع PDO الجمع بين المعاملات المسماة وعلامات الاستفهام الموضعية في نفس جملة الاستعلام.

05

عند استخدام المعاملات الموضعية (?)، كيف يجب تمرير القيم إلى الدالة $stmt->execute()؟

كمصفوفة مفهرسة متسلسلة تطابق عدد وترتيب علامات الاستفهام في جملة الاستعلام تماماً.

06

كيف تحصل على قيمة المفتاح الأساسي التلقائي (Auto-Increment ID) مباشرة بعد تنفيذ استعلام INSERT في PDO؟

عبر استدعاء الدالة $pdo->lastInsertId() من كائن الاتصال $pdo.

07

يمكن تنفيذ كائن الاستعلام المحضر PDOStatement عدة مرات داخل حلقة تكرارية بقيم مختلفة عبر $stmt->execute() دون الحاجة لإعادة استدعاء $pdo->prepare().

صواب؛ تحضير القالب مرة واحدة وتنفيذه عدة مرات يوفر أداءً عالياً في الإدراج المتكرر.

08

أي عبارتين مما يلي صحيحتان حول الاستعلامات المحضرة في PDO؟

القيم الممررة عبر execute() تعامل كبيانات خالصة لا كأوامر SQL، وتُستدعى الدالة lastInsertId() من الكائن $pdo.