الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

مقدمة إلى PDO في PHP

بدأه SIFE في 14 يناير 2011 · 4 رد · 3,913 مشاهدة · في منتدى تطوير المواقع بـ PHP
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم و رحمة الله و بركاته

سيكون درس اليوم إن شاء الله عن إستخدام PDO.

محتويات الدرس:

مقدمة

لماذا PDO

مميزات PDO

القواعد البيانات المدعومة

تنصيب PDO

الإتصال بقاعدة البيانات

معالجة الإستثناءات

تحديد الخيارات لإتصال

إستخدام bindValue و تحضير الإستعلام

تنفيذ الإستعلام بإستخدام execute

الفرق بين execute، exec و query

إستخدام fetch، fetchAll

قطع الإتصال بقاعدة البيانات

مقدمة: ماهو معروف في عالم قواعد البيانات أن MySQL هو الرائج في هذا المجال مما جعل أغلب المبرمجين يتبنونه في تطبيقاتهم، حتى أنك لو فتحت مصدر سكريبت ما سترى mysql_* منتشرة في كل مكان، ماذا لو كان من سيستخدم السكربت يستعمل محرك قواعد بيانات غير MySQL، هذا بالتأكيد سيتطلب إعادة كتابة أجزاء كبيرة من السكريبت، هنا ظهرت بعض الكائنات بال PHP تدعم أكثر من محرك قواعد بيانات و توفر واجهة دوال محمولة، يمكنك إستخدامها مع أي محرك مدعوم من طرف الكائن، كمثال على ذلك ADOdb و PDO.

لماذا PDO:

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

مميزات PDO:

_ دعم لعدد قواعد بيانات كبيرة.

_ إستخدام OOP.

_ قابلية الإضافة مما يتيح دعم نوع جديد من القواعد البيانات.

_ نفس الدوال تقريبا لجميع قواعد البيانات، مما يكسب سكربتك تعدد القواعد البيانات(cross databases).

_ تعدد الخيارات على حسب قاعدة البيانات.

_ حماية من SQL injection إلى درجة ما.

القواعد البيانات المدعومة:

حاليا القواعد المدعومة هي:

FreeTDS / Microsoft SQL Server / Sybase

Firebird/Interbase 6

IBM DB2

IBM Informix Dynamic Server

MySQL 3.x/4.x/5.x

Oracle Call Interface

ODBC v3 (IBM DB2, unixODBC and win32 ODBC)

PostgreSQL

4D

SQLite 3 and SQLite 2

تنصيب PDO:

بالنسبة لأنظمة unix-like فإن تنصيبها يأتي عند تنصيب PHP كالآتي:

tar -xjf php-5.3.4.tar.bz2
cd php-5.3.4
./configure --with-pdo-mysql=shared –with-pdo-pgsql=shared

في حالتي هذه قمت بدعم MySQL و PostgreSQL.

بالنسبة لمستخدمي أنظمة Windows فإنه يتوجب التعديل على الملف php.ini و تفعيل PDP و القواعد البيانات التي نريد إستخدامها بحذف الفاصلة المنقوطة قبل كل إضافة في قسم extension كالآتي:

extension=php_pdo.so
extension=php_pdo_pgsql.so
extension=php_pdo_mysql.so
;extension=php_pdo_sqlite.so

بعدها نعيد تشغيل السيرفر.

الإتصال بقاعدة البيانات:

كما قلنا سابقا أن PDO تستخدم OOP، لهذا فإن عند إستخدامها في PHP علينا أولا إستدعاء الكائن PDO كالآتي:

<?php
$host = "localhost";
$db = "test";
$user = "dev";
$pass = "pass";
$db = new PDO("mysql:host=$host;dbname=$db", $user, $pass); 
?>

عند إستدعاء الكائن فإنه يقبل 3 وسائط و 4 إختياري، الوسيط الأول نحدد فيه نوع قاعدة البيانات التي نريد إستخدامها، في حالتنا هذه كانت MySQL، مع عنوان السيرفر الذي يحتوي على قاعدة البيانات و لا ننسى إسم قاعدة البيانات التي نريد إستخدامها.

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

معالجة الإستثناءات:

في حالة عدم نجاح الإتصال بقاعدة بيانات، سيكون من الجيد معرفة السبب، الكود سيكون كالآتي:

<?php
$host = "localhost";
$db = "test";
$user = "dev";
$pass = "pass";
 try 
  {
   $db = new PDO("mysql:host=$host;dbname=$db", $user, $pass); 
  }

 catch(PDOException $err)
  {
   die('Error : ' . $err->getMessage());
  }
?>

في السطر 8 سنقوم بمحاولة الإتصال داخل الحاجز try، في حالة خطأ ما ستلتطقه PDOException في المتغير err$، بعدها نقوم بإنهاء عمل السكربت في السطر 13 و إظهار رسالة الخطأ بإستخدام ال method getMessage.

تحديد الخيارات لإتصال:

تتيح لك ال method setAttribute تحديد خيارات على مقبض إتصال، بعض الخيارات تكون متاحة في كل محركات قواعد البيانات المدعومة و بعضها الآخر يكون خاص فقط ببعض المحركات.

مثلا نريد أن نحدد طريقة تتبع الأخطاء بإستخدام Exceptions، بهذا سيكون إستخدام setAttribute كالآتي:

<?php
$host = "localhost";
$db = "test";
$user = "dev";
$pass = "pass";
 try 
  {
   $db = new PDO("mysql:host=$host;dbname=$db", $user, $pass); 
   $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  }
 catch(Exception $err)
  {
   die('Error : ' . $err->getMessage());
  }
?>

في السطر التاسع، getAttribute تأخذ وسيطين، الأول يكون نوع الخيار و الثاني قيمة الإختيار.

إستخدام bindValue و تحضير الإستعلام:

توفر PDO دالة ممتازة إسمها ()prepare، مهمتها توفير لك إستعلام مترجم تقوم بالإحتفاظ به ايضا في حالة إستخدمته مرة أخرى، مما يوفر لك هذا وقتا، و لن يبقى سوى الإرسال إلى السيرفر.

BindValue مهمتها توفير لك متغيرات داخل إستعلامك، مثال على ما سبق:

<?php
$host = "localhost";
$db = "test";
$user = "dev";
$pass = "pass";
 try 
  {
   $db = new PDO("mysql:host=$host;dbname=$db", $user, $pass); 
   $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  }
 catch(Exception $err)
  {
   die('Error : ' . $err->getMessage());
  }
$uid = $_GET['user'];
$tid = $_GET['travel'];
$db->prepare("SELECT * FROM Orders where id_travel =:tid and id_user =:uid");  
$db->bindValue(':uid', (int)$uid, PDO::PARAM_INT);
$db->bindValue(':tid', (int)$tid, PDO::PARAM_INT);
?>

نقوم أولا بإستقبال رقم المستخدم و رقم رحلته مثلا من نموذج ملئ الرحلة، بعدها في السطرين 18 و 19 نقوم بإستخدام bindValue ال تي تساعدنا بتضمين متغيراتنا داخل ال method prepare، الفائدة الجلية هنا سيكون لك إستعلام محضر سابقا في حالة إستخدامه لاحقا، و الفائدة الأخرى أننا سنتجنب مشكل ال SQL injection.

BindValue عادة تأخذ 3 وسائط، الأول يكون بمثابة متغير نستخدمه داخل ال method prepare، هذا المتغير يكون داخل " أو ' و يبتدأ ب نقطتين مزدوجتين.

الوسيط الثاني يكون القيمة التي سنضمنها للمتغير الخاص ب ال method prepare، الوسيط الأخير نحدد فيه نوع المتغير هل هو عدد أم حروف (PDO::PARAM_STR)، الوسيط الرابع في حال إستخدمناه يكون حجم المتغير في حالة كان من نوع PDO::PARAM_STR.

تنفيذ الإستعلام بإستخدام execute:

آخر شيء بقي هو تنفيذ الإستعلام:

<?php
$host = "localhost";
$db = "test";
$user = "dev";
$pass = "pass";
 try 
  {
   $db = new PDO("mysql:host=$host;dbname=$db", $user, $pass); 
   $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  }
 catch(Exception $err)
  {
   die('Error : ' . $err->getMessage());
  }
$uid = $_GET['user'];
$tid = $_GET['travel'];
$db->prepare("SELECT * FROM Orders where id_travel =:tid and id_user =:uid");  
$db->bindValue(':uid', (int)$uid, PDO::PARAM_INT);
$db->bindValue(':tid', (int)$tid, PDO::PARAM_INT);
$db->execute();
echo "Number of row returned are: ".$db->rowCount();
?>

السطر 21 أضفناه لكي نرى عدد الحقول التي تم إعادتها من الإستعلام.

الفرق بين execute، exec و query:

PDO توفر 3 طرق لتنفيذ إستعلام SQL، كل واحدة لها محل من الإعراب أقصد في الإستخدام كالآتي:

execute: تقوم بتنفيذ إستعلام SQL بإستخدام ال method prepare، هذا يوفر حماية من SQL injection مع الإحتفاظ بالإستعلام من طرف PDO في حالة إستخدامه لاحقا.

في حالة فشلها تعود لنا ب FALSE أما في النجاح تعيد TRUE، إن أردنا أن نعرف عدد الحقول نستخدم ال() method rowCount.

exec: تنفذ إستعلام SQL مباشرة من دون الإعتماد على ال method prepare، خطر الإصابة ب ال SQL injection كبير ما لم يقم المطور بتنقيح مدخلات المستخدم.

تعيد FALSE في حالة الفشل، 0 في حالة لم يكن هناك أي حقل معاد أو عدد الحقول المعادة في حال وجدت.

query: نفس سابقتها exec غير ان القيمة المعادة هنا تكون عبارة عن كائن يحتوي على أسماء الحقول المعادة.

<em>مثال:</em>

<?php
$host = "localhost";
$db = "test";
$user = "dev";
$pass = "pass";
 try 
  {
   $db = new PDO("mysql:host=$host;dbname=$db", $user, $pass); 
   $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  }
 catch(Exception $err)
  {
   die('Error : ' . $err->getMessage());
  }
$uid = $_GET['user'];
$tid = $_GET['travel'];
foreach($db->query("SELECT FROM Orders") as $row)  
 {
  $row['id_user']."\t";
  $row['id_travel']."\t";
  $row['name_travel']."\n";
 }
?>

يمكنك أن تدعو ال method query بـ mysql_fetch_row.

إستخدام fetch، fetchAll:

توفر PDO عدة أشكال لإعادة البيانات من قاعدة البيانات، مما يتيح لك الإختيار في كيفية الوصول إلى حقول القاعدة، المثال الآتي يوضح المقصود:

<?php
$host = "localhost";
$db = "test";
$user = "dev";
$pass = "pass";
 try 
  {
   $db = new PDO("mysql:host=$host;dbname=$db", $user, $pass); 
   $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  }
 catch(Exception $err)
  {
   die('Error : ' . $err->getMessage());
  }
$uid = $_GET['user'];
$tid = $_GET['travel'];
$db->prepare("SELECT * FROM Orders where id_travel =:tid and id_user =:uid");  
$db->bindValue(':uid', (int)$uid, PDO::PARAM_INT);
$db->bindValue(':tid', (int)$tid, PDO::PARAM_INT);
$db->execute();
$row = $db->fetch(PDO::FETCH_ASSOC); 
echo $row['user']."\t".$row['email']."\t".$row['address']."\n";
?>

بالنظر إلى السطر 21 نرى ال method fetch، هي تأخذ 3 وسائط لكن عادة نحتاج الوسيط الأول فقط الذي يكون طريقة إستخراج البيانات من القاعدة، هل ستكون على شكل مصفوفة تكون مفهرسة بأسماء الحقول في الجدول، أم مفهرسة على شكل أرقام إبتداءا من 0، هذه بعض القيم من الممكن أن تأخذها ال method fetch:

PDO::FETCH_ASSOC: إعادة نتيجة الإستعلام على شكل مصفوفة مفهرسة بأسماء الحقول الموجودة.

PDO::FETCH_NUM: إعادة نتيجة الإستعلام على شكل مصفوفة مفهرسة بأرقام إبتداءا من 0.

PDO::FETCH_BOTH: إعادة نتيجة الإستعلام على شكل مصفوفة مفهرسة بأسماء الحقول و أرقام.

توجد أشكال أخرى مذكورة في php manual يمكنكم الإطلاع عليها.

ال method fetchAll مهمتها إرجاع جميع القيم الموجودة في حقل ما على شكل مصفوفة، الوسيط الأول نفس سابقتها ال method fetch، أما الوسيطين الآخرين فعادة لانحتاجهما.

<?php
$host = "localhost";
$db = "test";
$user = "dev";
$pass = "pass";
 try 
  {
   $db = new PDO("mysql:host=$host;dbname=$db", $user, $pass); 
   $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  }
 catch(Exception $err)
  {
   die('Error : ' . $err->getMessage());
  }
$uid = $_GET['user'];
$tid = $_GET['travel'];
$db->prepare("SELECT * FROM Orders where id_travel =:tid and id_user =:uid");  
$db->bindValue(':uid', (int)$uid, PDO::PARAM_INT);
$db->bindValue(':tid', (int)$tid, PDO::PARAM_INT);
$db->execute();
$row = $db->fetchAll(PDO::FETCH_ASSOC); 
foreach($row as $res)
 foreach($res as $result)
   echo $result['user']."\t".$result['email']."\t".$result['address']."\n";
?>

ال method fetchAll تعيد مصفوفة ذات بعدين، البعد الأول يكون مفهرس بشكل أرقام و البعد الثاني يكون على حسب ما تم تحديده في الوسيط الأول لها، حيث هذا البعد على قيمة حقل أو حقول من إستعلام تم تنفيذه.

في السطر 22 نقوم كل مرة بإستخراج عنصر الذي هو في الحقيقة مؤشر لمصفوفة تحتوي على القيم المعادة، بعدها في السطر 23 نقوم بإستخراج القيم من المصفوفة التي تحتوي على القيم(أي أننا في البعد الثاني للمصفوفة)، أخيرا في السطر 23 نقوم بطباعة القيم.

قطع الإتصال بقاعدة البيانات:

آخر شيء يبقى لنا هو قطع الإتصال مع قاعدة بينات قمنا بالإتصال معها:

<?php
$host = "localhost";
$db = "test";
$user = "dev";
$pass = "pass";
 try 
  {
   $db = new PDO("mysql:host=$host;dbname=$db", $user, $pass); 
   $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  }
 catch(Exception $err)
  {
   die('Error : ' . $err->getMessage());
  }
$db = NULL;
?>

بكل بسطاة نقوم بتضمين NULL إلى المتغير الذي كان يحمل حدث إنشاء الإتصال.

ملاحظة:

هذه المقالة تحتاج إلى تعديل و تنقيح في اللغة لمن يريد التعديل فهو مرحب به.

مراجع:

http://www.php.net/manual/en/book.pdo.php

http://www.phpeveryday.com/articles/PDO-Error-Handling-P544.html

http://codeassembly.com/Are-you-still-worried-about-sql-injection-?/

http://stackoverflow.com/questions/134099/are-pdo-prepared-statements-sufficient-to-prevent-sql-injection

http://net.tutsplus.com/tutorials/php/why-you-should-be-using-phps-pdo-for-database-access/

2

''‏اللهم إني أسالك إيمانا دائما وأسألك قلبا خاشعا وأسألك علما ‏نافعا وأسألك يقينا صادقا وأسألك دينا قيما وأسألك العافية من كل ‏بلية''

'‏اللهم أغفر للمؤمنين و المؤمنات و المسلمين و المسلمات الأحياء ‏منهم و الأموات'

www.it-scoop.com

#2

رائع يا سيف، كنت أتعامل مع PDO من فترة في مشروع وهي خيار رائع للتعامل مع قواعد البيانات المختلفة إن كنت تعمل على استضافة Linux وتحتاج للتخاطب مع قاعدة بيانات MsSQL على نظام Windows.

Do as I say, not as I do

We are Anonymous. We are Legion. We don't forgive. We don't forget

#3

جميل جدا ياسيف ولكن في طبقات اعلى فى الإستخدام من PDO

انا شايف استخدام ORM هو انسب شئ واسهل شئ مثل doctrine او الإفتراضي في إطار العمل

(map share people)

فضلا لاتقم بمراسلتي من أجل أسئلة لها أقسامها في المنتدى حتى تعم الفائدة على الجميع وللحصول على إجابات أفضل من أعضاء أكثر خبرة.
Weblog
@bitbucket
@xmonader

#4

هذه أول مرة أسمع ب ORM.

''‏اللهم إني أسالك إيمانا دائما وأسألك قلبا خاشعا وأسألك علما ‏نافعا وأسألك يقينا صادقا وأسألك دينا قيما وأسألك العافية من كل ‏بلية''

'‏اللهم أغفر للمؤمنين و المؤمنات و المسلمين و المسلمات الأحياء ‏منهم و الأموات'

www.it-scoop.com

مواضيع مشابهة