في هذا الدرس 6تصفّح المواضيع
تُعد ثغرة حقن أوامر SQL (SQL Injection — SQLi) من أخطر الثغرات الأمنية في تطبيقات الويب، وتحدث عندما يقوم المبرمج بدمج متغيرات المستخدم نصياً داخل جملة الاستعلام:
- كيف يقع الاختراق: عند كتابة متغير مباشرة داخل نص SQL، يستطيع المهاجم إدخال علامة تنصيص مفردة متبوعة بأوامر منطقية مثل
' OR '1'='1لتغيير معنى الاستعلام بالكامل أو مسح الجداول. - القاعدة الذهبية الصارمة: لا تدمج أي متغير نصياً داخل جملة SQL تحت أي ظرف كان.
<?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
$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
$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([...]):
- صياغة مختصرة وسريعة: مناسبة جداً للاستعلامات القصيرة التي تحتوي على معامل واحد أو معاملين.
- التطابق الصارم في العدد والترتيب: يجب أن يتطابق عدد عناصر المصفوفة الممررة وترتيبها مع علامات الاستفهام في الاستعلام تماماً.
<?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
$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]); | ربط قيم المدخلات بأمان وتنفيذ الاستعلام المحضر |
| المعامل المسمى | جملة SQL | VALUES (:email, :role) | ربط واضح بالاسم للاستعلامات متعددة الحقول |
| المعامل الموضعي | جملة SQL | VALUES (?, ?) | ربط مختصر بالترتيب للاستعلامات السريعة |
lastInsertId() | $pdo | $id = $pdo->lastInsertId(); | إرجاع المعرف التلقائي للسجل المضاف حديثاً |
ملخص الدرس
حصاد الدرسمراجعة مركّزة لأهم المفاهيم والقواعد الهندسية التي أتقنتها في هذا الدرس قبل التطبيق العملي
ماذا تعلّمت في هذا الدرس؟
تعلمت في هذا الدرس كيف تحدث ثغرة حقن SQL عند دمج المتغيرات نصياً، وكيف تمنعها الاستعلامات المحضرة عبر فصل التحضير prepare() عن التنفيذ execute()، وكيفية إدراج البيانات بالمعاملات المسماة والموضعية، وقراءة معرف السجل الجديد عبر $pdo->lastInsertId(). الخطوة التالية: انتقل إلى الدرس الخامس والخمسين «استعلامات الجلب والفلترة والترتيب عبر PDO في PHP» لقراءة البيانات من الجداول بمرونة وأمان.
سجّل الدخول لحفظ تقدمك
تابع إنجاز المواضيع والمصطلحات والمهام، وكمّل من آخر خطوة على أي جهاز.
المصطلحات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
راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.
- 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 ويرسلها إلى متصفح العميل بعد التنفيذ.
- للمراجعة
لا توجد بطاقات تطابق البحث والتصفية.
اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.
مهامك قبل الاختبار
خطوة صغيرة كل مرة. وإنجاز تقدر ترجع له.
-
أنشئ ملف PHP محلياً ونفّذ المثال البرمجي المشروح في قسم كيف تحدث ثغرة حقن SQL للتحقق من المخرجات.
-
بدّل بين الحالات الثلاث في المحاكي التفاعلي ضمن قسم كيف تفصل الاستعلامات المحضرة الكود وقارن مخرجات التنفيذ.
تأشير المهمة إقرار منك بإتمامها، وليس تصحيحًا آليًا للكود. يُحفظ تقدمك في حسابك.
اختبر فهمك.
ووصلها للإتقان.
كل سؤال خطوة لقدّام. اختار، اكتب كود، وشوف نتيجتك فورًا.
أكمل المهام، واجمع كل الإجابات الصحيحة. أقل من 100%؟ راجع وأعد المحاولة.
الأسئلة متاحة للاطلاع. سجّل الدخول للتفاعل وحفظ تقدمك.
لمحة عن التحدي8 أسئلة تنتظرك +
ما السبب الجذري لظهور ثغرة حقن SQL (SQL Injection) في تطبيقات PHP؟
دمج المتغيرات ومدخلات المستخدم نصياً داخل جملة SQL بدلاً من فصلها عبر الاستعلامات المحضرة.
ما نوع الكائن الذي تُرجعه الدالة $pdo->prepare($sql) عند تحضير الاستعلام؟
تُرجع الدالة $pdo->prepare() كائناً من الصنف PDOStatement.
أي صياغة مما يلي تستخدم المعاملات المسماة (Named Placeholders) بشكل صحيح في استعلام PDO محضر؟
تبدأ المعاملات المسماة بنقطتين رأسيتين مثل :email و :role داخل جملة SQL.
يمكنك الخلط بين المعاملات المسماة (:email) والمعاملات الموضعية (?) داخل نفس جملة SQL الواحدة في PDO.
خطأ؛ يمنع PDO الجمع بين المعاملات المسماة وعلامات الاستفهام الموضعية في نفس جملة الاستعلام.
عند استخدام المعاملات الموضعية (?)، كيف يجب تمرير القيم إلى الدالة $stmt->execute()؟
كمصفوفة مفهرسة متسلسلة تطابق عدد وترتيب علامات الاستفهام في جملة الاستعلام تماماً.
كيف تحصل على قيمة المفتاح الأساسي التلقائي (Auto-Increment ID) مباشرة بعد تنفيذ استعلام INSERT في PDO؟
عبر استدعاء الدالة $pdo->lastInsertId() من كائن الاتصال $pdo.
يمكن تنفيذ كائن الاستعلام المحضر PDOStatement عدة مرات داخل حلقة تكرارية بقيم مختلفة عبر $stmt->execute() دون الحاجة لإعادة استدعاء $pdo->prepare().
صواب؛ تحضير القالب مرة واحدة وتنفيذه عدة مرات يوفر أداءً عالياً في الإدراج المتكرر.
أي عبارتين مما يلي صحيحتان حول الاستعلامات المحضرة في PDO؟
القيم الممررة عبر execute() تعامل كبيانات خالصة لا كأوامر SQL، وتُستدعى الدالة lastInsertId() من الكائن $pdo.