IN() و PDO: الربط الصحيح للمصفوفة وأهم الأخطاء

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: "لماذا لا يفهم PDO المصفوفة الخاصة بي؟"

\n

كل مطور PHP يعمل مع قواعد البيانات، سيواجه عاجلاً أم آجلاً موقفًا يحتاج فيه إلى تنفيذ استعلام باستخدام العامل IN(). قد يبدو الأمر بسيطًا: تمرير مصفوفة من القيم والحصول على البيانات المفلترة. لكن هنا يكمن المأزق الرئيسي.

\n

إليك مثالًا تقليديًا يتبادر إلى ذهن المبتدئ:

\n
<?php\n$ids = [1, 2, 3, 5];\n$stmt = $pdo->prepare("SELECT * FROM users WHERE id IN (:ids)");\n$stmt->execute([':ids' => $ids]); // خطأ!\n?>
\n

وهنا يرمي PDO خطأ: "Array to string conversion" أو ببساطة يعيد نتيجة فارغة. لماذا يحدث هذا؟ لا يستطيع PDO "فك" المصفوفات في استعلامات SQL. إنه يتوقع قيمة مفردة لكل عنصر نائب مُسمى، وليس مصفوفة كاملة.

\n

في هذه المقالة، سنستعرض أهم الأخطاء التي يقع فيها المطورون عند محاولة ربط مصفوفة بـ IN()، ونعرض الحلول الصحيحة والآمنة والفعالة.

\n\n

الخطأ رقم 1: تمرير المصفوفة مباشرة إلى execute()

\n

هذا هو الخطأ الأكثر شيوعًا. يعتقد المطور أن PDO سيفهم تلقائيًا كيفية وضع كل قيمة من المصفوفة في شرط IN(). ولكن، كما اكتشفنا، PDO لا يعمل بهذه الطريقة.

\n

كيف يبدو هذا في الكود

\n
<?php\n$ids = [10, 20, 30];\n$stmt = $pdo->prepare("SELECT * FROM products WHERE id IN (:ids)");\n$stmt->execute([':ids' => $ids]); // خطأ فادح\n?>
\n

النتيجة: خطأ أو تحذير حول تحويل المصفوفة إلى سلسلة نصية. حتى لو "مر" الكود، سيقوم PDO بإدراج كلمة "Array" في الاستعلام - وستحصل على WHERE id IN ('Array')، وهو أمر غير منطقي.

\n

لماذا يحدث هذا؟ يتطلب PDO أن يقابل كل عنصر نائب قيمة واحدة. المصفوفة ليست قيمة، بل مجموعة من القيم. PDO لا يستطيع ولا يجب عليه أن يخمن ما تريد فعله.

\n\n

الخطأ رقم 2: استخدام bindValue() مع مصفوفة

\n

أحيانًا يحاول المطورون خداع PDO باستخدام bindValue():

\n
<?php\n$ids = [1, 2, 3];\n$stmt = $pdo->prepare("SELECT * FROM users WHERE id IN (:ids)");\n$stmt->bindValue(':ids', $ids, PDO::PARAM_STR); // خطأ!\n$stmt->execute();\n?>
\n

المشكلة نفسها: bindValue() يتوقع قيمة مفردة. سيتم تحويل المصفوفة إلى سلسلة نصية "Array"، ولن يتم تنفيذ الاستعلام بشكل صحيح. المعامل الثالث (PDO::PARAM_STR) لا ينقذ الموقف - فهو يحدد نوع البيانات فقط، لكنه لا يغير منطق التعامل مع المصفوفة.

\n\n

الخطأ رقم 3: الربط المباشر (حقن SQL)

\n

بعد اليأس، يسلك بعض المطورين طريق المقاومة الأقل - ببساطة إدراج المصفوفة في الاستعلام عبر implode():

\n
<?php\n$ids = [1, 2, 3];\n$ids_str = implode(',', $ids);\n$stmt = $pdo->query("SELECT * FROM users WHERE id IN ($ids_str)"); // خطير!\n?>
\n

ما خطورة هذا؟ إذا كانت القيم في المصفوفة تأتي من المستخدم (مثل معاملات GET أو نموذج)، يمكن للمهاجم تمرير 1; DROP TABLE users; --. سيتحول الاستعلام إلى IN (1; DROP TABLE users; --)، وسيتم تدمير قاعدة البيانات الخاصة بك. هذا هو حقن SQL الكلاسيكي.

\n

حتى لو كنت متأكدًا من أن البيانات آمنة، فهذه الممارسة سيئة للغاية. في يوم من الأيام ستنسى التحقق من مصدر البيانات، وستكون العواقب كارثية.

\n\n

الحل الصحيح: العناصر النائبة الديناميكية

\n

الآن إلى الأخبار الجيدة. يسمح PDO بإنشاء عناصر نائبة ديناميكيًا. تحتاج إلى توليد سلسلة نصية بالعدد المطلوب من ? أو :id1, :id2, ... وتمرير مصفوفة القيم بشكل منفصل.

\n

الطريقة 1: استخدام العناصر النائبة الموضعية (?)

\n

هذه هي الطريقة الأبسط والأكثر شيوعًا:

\n
<?php\n                

المدونات

توصيات الكتب