PDO در مقابل Mysqli

اسفند ۲۸, ۱۳۹۰ توسط : سعید

زمانی که میخواهیم در php  به دیتابیس دسترسی داشته باشیم دو انتخاب داریم : MySqli و PDO . میدونید کدوم یکی از این دو رو باید انتخاب کنید؟ در این مقاله به بررسی تفاوت ها ، پایداری ، پشتیبانی از دیتابیس های مختلف و … در PDO  و MySqli میپردازیم.

اتصال به دیتابیس

در PDO و MySqli اتصال به دیتابیس به راحتی امکان پذیره.

// PDO
$pdo = new PDO("mysql:host=localhost;dbname=database", 'username', 'password');

// mysqli, procedural way
$mysqli = mysqli_connect('localhost','username','password','database');

// mysqli, object oriented way
$mysqli = new mysqli('localhost','username','password','database'); 

در  MySqli استفاده از توابع هم به صورت “روالی” (procedural) و هم به صورت شیء گرا امکان پذیره.اگر به توابع پیش فرض mysql در php آشنایی دارید استفاده از mysqli  به صورت رویه ای براتون راحت تره.اما اگر به شیء گرایی مسلط هستید هم میتونید از PDO استفاده کنید  و هم از Mysqli

پشتیبانی از دیتابیس ها

یکی از فواید استفاده از PDO نسبت به Mysqli  تعداد دیتابیس هایی هست که پشتیبانی میکنند.PDO از ۱۲ نوع دیتابیس مختلف پشتیبانی میکنه در حالی که MySqli فقط از mysql پشتیبانی میکنه.
برای دیدن نام دیتابیس های پشتیبانی شده در PDO میتونید از دستور زیر استفاده کنید :

<pre>var_dump(PDO::getAvailableDrivers());

خب این چه معنی میده؟ هنگامی که در یک پروژه مجبور بشید از یک دیتابیس به دیتابیس دیگه مهاجرت کنید PDO این رو به راحتی در اختیارتون میذاره.تمام کاری که باید انجام بدید اینه که نوع اتصال رو تغییر بدید و query هایی که باید در دیتابیس جدید پشتیبانی بشه.اما با mySqli باید تمام کدها رو تغییر بدید به اضافه query ها.

Named Parameters

این قابلیت هم یکی دیگه از فواید استفاده از PDO نسبت به MySqli که به طور قابل ملاحظه ای کار رو ساده تر میکنه :

$params = array(':username' => 'test', ':email' => $mail, ':last_login' => time() - 3600);

$pdo->prepare('
SELECT * FROM users
WHERE username = :username
AND email = :email
AND last_login > :last_login');

$pdo->execute($params); 

Named Parameters به روشی گفته میشه که درکد بالا استفاده شده.این روش خوانایی برنامه رو به مراتب بالا میبره.
در مقابل MySqli از Named Parameters پشتیبانی نمیکنه :

$query = $mysqli->prepare('
SELECT * FROM users
WHERE username = ?
AND email = ?
AND last_login > ?');

$query->bind_param('sss', 'test', $mail, time() - 3600);
$query->execute();

Object Mapping

هم PDO و هم MySqli از Object mapping پشتیبانی میکنند  به این معنی که اگر شما نمیخواهید از یک DAL (Database Abstraction layer) استفاده کنید اما میخواهید رفتاری شبیه به یک ORM داشته باشه میتونید از یکی از این دو استفاده کنید. تصور کنید که یک کلاس به اسم User داریم با تعدادی properties که همنام با فیلدهای جدول User هستند :

class User {
public $id;
public $first_name;
public $last_name;

public function info()
{
return '#'.$this->id.': '.$this->first_name.' '.$this->last_name;
}
}

بدون Object Mapping قبل از استفاده از متد info باید به property های کلاس مقدار بدیم( یا به صورت دستی یا به وسیله constructor) .این قابلیت اجازه میده که قبل از ساخت شی< property ها مقدار دهی بشن :

$query = "SELECT id, first_name, last_name FROM users";

// PDO
$result = $pdo->query($query);
$result->setFetchMode(PDO::FETCH_CLASS, 'User');

while ($user = $result->fetch()) {
echo $user->info()."n";
}
// MySQLI, procedural way
if ($result = mysqli_query($mysqli, $query)) {
while ($user = mysqli_fetch_object($result, 'User')) {
echo $user->info()."n";
}
}
// MySQLi, object oriented way
if ($result = $mysqli->query($query)) {
while ($user = $result->fetch_object('User')) {
echo $user->info()."n";
}
}

امنیت

یک از روشهای هک سایت استفاده از Sql Injection  که هکر با قرار دادن کدهای sql در مقادیر ارسالی به سایت سعی میکنه خرابکاری کنه.این راه معمولا از طریق آدرسهایی انجام میشه که از متد GET برای ارسال مقادیر به سرور استفاده میکنن :
http://domain.com/index.php?username=phpro; DELETE FROM users;
اگر ما بدون escape کردن متغیر  $_GET[‘username’] ازش استفاده کنیم دستور DELETE هم در دیتابیس اجرا خواهد شد :

// PDO, "manual" escaping
$username = PDO::quote($_GET['username']);

$pdo->query("SELECT * FROM users WHERE username = $username");

// mysqli, "manual" escaping
$username = mysqli_real_escape_string($_GET['username']);

$mysqli->query("SELECT * FROM users WHERE username = '$username'");

PDO::quote در واقع رشته ورودی رو escape نمیکنه فقط quote میکنه (بین دو ‘ ‘ قرار میده) . اما درمقابل mysqli_real_escap_string یک رشته امن برای دیتابیس میسازه.

// PDO, prepared statement
$pdo->prepare('SELECT * FROM users WHERE username = :username');
$pdo->execute(array(':username' => $_GET['username']));

// mysqli, prepared statements
$query = $mysqli->prepare('SELECT * FROM users WHERE username = ?');
$query->bind_param('s', $_GET['username']);
$query->execute();

پیشنهاد میکنم همیشه برای اجرای query ها و به جای quote  و mysqli_real_escape_string از دستور prepare استفاده کنید.

کارایی (سرعت)

PDO و Mysqli هر دو از سرعت و کارایی بالای برخوردار هستند.در benchmark این دو Mysqli مقداری سریعتر از PDO کارها رو به اتمام رسونده.اما توابع داخلی   mysqlاز سرعت بسیار بیشتری برخوردار هستند.

نتیجه :

بدون شک PDO با پشتیبانی از ۱۲ نوع دیتابیس مختلف ، پشتیبانی از Named Parameters ، و چشم پوشی از  مقدار کمی عقب ماندگی در سرعت نسبت به MySqli برنده این مسابقه است.در مورد امنیت هم که دیدیم تا زمانی که شما از prepare استفاده کنید هر عملکرد خوبی دارن.

منبع :

http://net.tutsplus.com/tutorials/php/pdo-vs-mysqli-which-should-you-use/

بازدید : ۶۰۷۹

reza
تیر ۲۱, ۱۳۹۱ @ ۷:۴۴ ق.ظ

سلام
به هنگام استفاده از دستورات INSERT و UPDATE در pdo چگونه باید مقادیر دریافتی و ارسالی را

به جهت Sql Injection بررسی و پالایش نمود ؟

پاسخ دادن
    سعید
    تیر ۲۱, ۱۳۹۱ @ ۸:۰۱ ب.ظ

    مثال زیر رو ببین :


    $stm = $pdo->prepare('insert into users(username) values(:user)')
    $stm->bindValue(':user' , 'Saeed')

    توی مثال بالا برای جلوگیری از sql injection
    از متد prepare استفاده کن بعد با دستور bindValue
    مقدارت رو به کوئری پاس بده

    پاسخ دادن
دی ۱, ۱۳۹۱ @ ۴:۵۱ ب.ظ

تشکر از مطلب مفیدتون.

پاسخ دادن
laleh
دی ۲, ۱۳۹۱ @ ۱۲:۴۱ ب.ظ

salam
man ba estefade az pdo dastore inserto neveshtam vali kar nemikone mishe komakam konid moshkelesho peyda konam
kodi ke neveshtamo baraton mizaram
<?php
class InsertData {

		
	function __construct(){
		echo &quot;Control Datas";
		if(true){
			$this-&gt;name=$_POST['name'];
			$this-&gt;decription=$_POST['decription'];
			$this-&gt;author=$_POST['author'];
			$this-&gt;publisher=$_POST['publisher'];
			$this-&gt;pubdate=$_POST['pubdate'];
			
			$this-&gt;postData(NULL,$this-&gt;name,$this-&gt;decription,$this-&gt;author,$this-&gt;publisher,$this-&gt;pubdate);
		}//if
		
	}
	
	private function postData($a1,$a2,$a3,$a4,$a5,$a6){
		$db = new PDO('mysql:host=localhost;dbname=lib', 'root', '');
                $stmt = $db-&gt;prepare("INSERT INTO book (NULL,name,decription,author,publisher,pubdate) VALUES (':$this-&gt;id',':$this-&gt;name',':$this-&gt;decription',':$this-&gt;author',':$this-&gt;publisher',':$this-&gt;pubdate')");
                $stmt-&gt;bindParam(':id', $id);
                $stmt-&gt;bindParam(':$this-&gt;id', $this-&gt;id);
                $stmt-&gt;bindParam(':name', $name);
                $stmt-&gt;bindParam(':$this-&gt;name', $this-&gt;name);
                $stmt-&gt;bindParam(':decription', $decription);
                $stmt-&gt;bindParam(':$this-&gt;decription', $this-&gt;decription);
                $stmt-&gt;bindParam(':author', $author);
                $stmt-&gt;bindParam(':$this-&gt;author', $this-&gt;author);
                $stmt-&gt;bindParam(':publisher', $publisher);
                $stmt-&gt;bindParam(':$this-&gt;publisher', $this-&gt;publisher);
                $stmt-&gt;bindParam(':pubdate', $pubdate);
                $stmt-&gt;bindParam(':$this-&gt;pubdate', $this-&gt;pubdate);
                $db= null;
	}
}//endOfClass

$class=new InsertData();
?&gt;
پاسخ دادن
    سعید
    دی ۲, ۱۳۹۱ @ ۶:۱۳ ب.ظ

    باید در کلاس متغیرهای مورد نظر رو تعریف کنید : (خط ۳)

    <?php
    class InsertData {
    private $name,$decription , $autor,$publisher,$pudate;
    function __construct(){
    echo "Control Datas”;
    if(true){
    $this->name=$_POST['name'];
    $this->decription=$_POST['decription'];
    $this->author=$_POST['author'];
    $this->publisher=$_POST['publisher'];
    $this->pubdate=$_POST['pubdate'];
    
    $this->postData(NULL,$this->name,$this->decription,$this->author,$this->publisher,$this->pubdate);
    }//if
    
    }
    
    private function postData($a1,$a2,$a3,$a4,$a5,$a6){
    $db = new PDO(‘mysql:host=localhost;dbname=lib’, ‘root’, ”);
    $stmt = $db->prepare(“INSERT INTO book (NULL,name,decription,author,publisher,pubdate) VALUES (‘:$this->id’,':$this->name’,':$this->decription’,':$this->author’,':$this->publisher’,':$this->pubdate’)”);
    $stmt->bindParam(‘:id’, $id);
    $stmt->bindParam(‘:$this->id’, $this->id);
    $stmt->bindParam(‘:name’, $name);
    $stmt->bindParam(‘:$this->name’, $this->name);
    $stmt->bindParam(‘:decription’, $decription);
    $stmt->bindParam(‘:$this->decription’, $this->decription);
    $stmt->bindParam(‘:author’, $author);
    $stmt->bindParam(‘:$this->author’, $this->author);
    $stmt->bindParam(‘:publisher’, $publisher);
    $stmt->bindParam(‘:$this->publisher’, $this->publisher);
    $stmt->bindParam(‘:pubdate’, $pubdate);
    $stmt->bindParam(‘:$this->pubdate’, $this->pubdate);
    $db= null;
    }
    }//endOfClass
    
    $class=new InsertData();
    ?>
    
    پاسخ دادن
laleh
دی ۳, ۱۳۹۱ @ ۱۲:۳۳ ب.ظ

ممنون از راهنماییتون
من متغیراشم تعریف کردم ولی درست نشد
این دستورو هم بعد از دستورات bindparam اضافه کردم بازم درست نشد
$stmt->execute();
آخه error هم نمیده ولی اطلاعاتو توی بانک ثبت نمیکنه

پاسخ دادن
امیر
دی ۴, ۱۳۹۳ @ ۸:۳۳ ب.ظ

با سلام و خسته نباشید خدمت مدیران محترم این سایت، می خواستم بابت این مطلب خوبتون تشکر کنم. همچنین می خواستم به کاربرانتون سایت بیاموز رو معرفی کنم که در زمنیه آموزش PHP خوب عمل کرده. http://www.beyamooz.com/php

پاسخ دادن

پاسخ دهید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *


*