php استغلال قاعدة البيانات

php MySql : الإستعلام باستعمال المتغيرات

آخر تحيين: 10-01-2015

php MySQL إدخال و تعديل البيانات php MySql : معايير اختيار البيانات


سنتعرف في هذا الدّرس على الطّرق الآمنة لاستعمال المتغيّرات في الإستعلام . لاحظوا أنني أتجاهل و سأتجاهل التحدّث عن الطّرق القديمة لاستغلال قاعدة البيانات . وداعاً لطرق "mysql_query" و مثيلاتها .
لنأخذ مثلا هذا المثال الكلاسيكي للإستعلام

$query =mysql_query('SELECT username FROM users WHERE username = "'.$_GET['pseudo'].'"';)

قمنا بالإستعلام باستعمال متغيّر . و سنحصل على البيانات المرجوة . المشكلة أن استعلامنا يتضمّن أيضا مشروع ثغرة SQL . صدّقوني ، هذه الثغرة لازالت موجودة بكثرة في العديد من مواقع الويب . و يمكن استغلالها بسهولة . و تمكن القرصان من تنفيذ استعلاماته الخاصة باستعمال شريط عناوين المتصفح فقط أو إستمارات الموقع الضحية . إذ يمكنه أخذ البيانات التي يريدها أو حذفها أو تعديلها في القاعدة . مثلا يمكنه تغيير جميع كلمات مرور الأعضاء بكلمة سر واحدة . بكل بساطة سيختلّ نظام موقعكم .
أقول لكم هذا ، لأنكم ستصادفون لا محالة في بعض السكريبتات مثل هذه الإستعلامات الكلاسيكية . لقد تم تجاوزها ، و أصبحت من الأرشيف . إن كان بعضكم لا زال يتردد في استعمالها ، إعلموا أن فريق مشروع MySql لم يعد يراجعها أو يُحيّنها أو يصحّح ثغراتها . إذاً ، مهما فعلتم لحماية بياناتكم ، أنتم دائما معرّضون لتهديد الإختراق .

pdo هي الحاضر و المستقبل . تعرّفنا كيف يمكننا تهييء استعلامنا باستعمال "prepare" ، لسد الطريق مام ثغرة (SQL injection) ، سنتعرف هنا عن تهييء متغيراتنا أيضا . بحيث لن نقحمها مباشرة في شيفرة الإستعلام كما فعلنا في الشيفرة أعلى . بل سنكتفي بحجز مكان لها . المثال أسفله يكفينا شر الثرثرة :

<?php 
//...
$query = $db->prepare('SELECT username FROM users WHERE username = :name');
//...
?>

قمنا بتهييء و حجز مكان للمتغير و ذلك بإضافة نقطتين ثم أي إسم من إختيارنا :name
الآن فقط يمكننا تعيين متغيرنا . و ذلك باستعمال إما bindValue أو bindParam ، لكم كامل الإختيار ، إذ تؤدّيان نفس الوظيفة

<?php
$query = $db->prepare('SELECT username FROM users WHERE username = :name');
$query->bindValue(':name', $_GET['pseudo']);
//...

قمنا بربط مفتاح الحجز :name بمتغيرّنا $_GET['pseudo'] . لأسباب الحماية ، يجب دائما إضافة قيمة ثالثة لتأكيد نوع بياناتنا ، كما بدر إلى أذهانكم ، سنستعمل "INT" للبيانات الرقمية و "STR" للبيانات النصية . :

  • PDO::PARAM_STR : للبيانات النصية
  • PDO::PARAM_INT : للبيانات الرقمية

ستصبح شيفرتنا الآن كاملة و جاهزة كالتالي

<?php
$query = $db->prepare('SELECT username
                       FROM users 
                       WHERE username = :name 
                     ');
$query->bindValue(':name', $_GET['pseudo'], PDO::PARAM_STR);
$query->execute();
//...

لنأخذ جدولنا السابق "employees" و نرى مثالا تطبيقيا للإستعلام بواسطة المتغيرات .
: لاختيار بيانات الموظفين ذوي الخبرة 4 على سبيل المثال :

<?php
$task = 'موظف'; // STR string
$experience = 4;  // INT integer

$response = $db->prepare('SELECT name, task, experience 
                          FROM employees 
                          WHERE task = :tsk AND experience = :expr
                        ');
$response->bindValue(':tsk', $task, PDO::PARAM_STR);
$response->bindValue(':expr', $experience, PDO::PARAM_INT);
$response->execute();

$employees = $response->fetchAll();
$response->CloseCursor();

foreach($employees as $employee) {
  echo 'الإسم : '.$employee['name'].' -
        المهمة : '.$employee['task'].' -
        الخبرة : '.$employee['experience'].'<br>';
}
?>

لا تنسوا أبدا حماية المتغيّرات أثناء عرضها باستخدام echo أو print . لا أفعل ذلك في الأمثلة التي أقدمها حتى لا أملأها بأشياء تعرفونها مسبّقا . أحاول دائما التركيز على المعلومات الجديدة التي ستضاف إلى رصيد معارفكم .
echo htmlspecialchars($employee['name']);

بالإضافة إلى عامل المقارنة "=" الذي استخدمناه في الإستعلام ، لدينا عوامل أخرى ، كنا رأيناها سابقا و هي :

  • < : أكبر من
  • > : أصغر من
  • <> : تختلف عن

مثلا لاختيار جميع العمال ذوي الخبرة أكبر من 4 :

<?php
//...
$response = $db->prepare('SELECT name, salary 
                          FROM employees 
                          WHERE experience > :expr
                        ');
//...

قبل إنهاء هذا الدّرس ، أودّ أن أعرفكم إلى طريقة أخرى لحجز مكان المتغير في الإستعلام . بدل النقطتين و الإسم :placeholder ، نستعمل علامة استفهام ? .
أثناء ربط المتغير بالمكان الذي حجزناه له . نستعمل العد التصاعدي بدءا من العدد "1" :

<?php
//...
$response = $db->prepare('SELECT name, salary 
                          FROM employees 
                          WHERE task = ? AND experience = ?
                        ');
$response->bindValue(1, $task, PDO::PARAM_STR);
$response->bindValue(2, $experience, PDO::PARAM_INT);
$response->execute();
//...
?>

الترتيب جد ضروري . فالعدد "1" : يمثل مباشرة أوّل علامة استفهام في الإستعلام . و العدد "2" : ثاني علامة استفهام ، و دواليك ...