PDO Kullanımı (PHP Data Objects)

 bcakir
 29 Aralık 2013

PHP Veri Nesneleri (PDO) eklentisi, veritabanı işlemlerini gerçekleştirmek için sunulan bir arayüzdür. Php’nin v5.5 sürümünden itibaren mysql_ şeklinde tanımladığımız fonksiyonlara destek vermemesi nedeniyle, veritabanı işlemlerini PDO veya Mysqli ile yapmak zorundayız. Bizlere sunulan bu iki alternatifin birbirine göre avantajları olduğu durumlar bulunmaktadır. Bunlar;

PDO Mysqli
Sadece nesne yönelimli kullanılır Nesne yönelimsiz de kullanılabilir
12 farklı veritabanını ile kullanılabilir Sadece MySQL ile kullanılır
SQL Injection korumalıdır SQL Injection kontrolünü yazılımcı yapılmalıdır
İsimlendirilmiş parametreyi destekler İsimlendirilmiş parametreyi desteklemez
Hız konusunda Mysqli’den yavaştır PDO’dan %5 civarı daha performanslıdır

temel olarak yukarıdaki şekildedir diyebiliriz. Ben daha önce “Nesne Yönelimli Programla (OOP)” ile anlatım yapmayı tercih edeceğimi söylediğim için, buna ek olarak da uygulamalarımda PDO’yu tercih ettiğimden (MsSQL için de kullanıyorum ve SQL Injection kontrolünü yapmama gerek kalmıyor), bu yazım sadece PDO’nun temel kullanımı ile ilgili olacaktır. Eğer Mysqli kullanmayı seçecekler varsa, kullanımında mysql_ fonksiyonlarından pek bir fark bulunmuyor. Bu arada, Php sürümünüz v5 altındaysa bu eklentileri kullanamazsınız. Bu önemli notu da ekledikten sonra artık PDO’nun temel fonksiyonlarının kullanımını anlatmaya geçebiliriz.

<?php
class baglan{
    //veritabanı bilgileri
	const host = 'localhost';
	const user = 'root';
	const pass = '';
	const db = 'pdo';
    public $conn;

	public function __construct(){ //açılışta çalıştır
		$this->dbBaglantiKur();
	}

	public function dbBaglantiKur(){ //veritabanı bağlantısı kurma
		try{
            $this->conn = new PDO("mysql:dbname=".self::db.";host=".self::host, self::user, self::pass);
    		$this->conn->query("SET NAMES 'utf8'");
    		$this->conn->query('set character set utf8');
        }catch(PDOException $e){
             die($e->getMessage());
        }
    }

	public function dbOlustur(){ //pdo adlı veritabanında yazilar adlı tablo açma
		$sql = "CREATE TABLE IF NOT EXISTS `yazilar`(
			`id` INT AUTO_INCREMENT NOT NULL,
			`baslik` varchar(100) NOT NULL,
			`icerik` varchar(400),
			PRIMARY KEY (`id`)
		)";
		$olustur = $this->conn->prepare($sql);
		return $olustur->execute();
	}

	public function dbVerileriEkle(){ //yazılar tablosuna kayıt ekleme (siralı parametre)
		$yazilar = array('1. yazının başlığı','1. içerik', '2. başlık','2. içerik', '3. başlık','3. içerik');
		$ekle = $this->conn->prepare('INSERT INTO yazilar (baslik,icerik) VALUES (?,?),(?,?),(?,?)');
		return $ekle->execute($yazilar);
	}

	public function dbSonKayitIdAl(){ //son kayıt id değeri !(bu bağlantıda ekleme işlemi yapılmışsa)
		return $this->conn->lastInsertId();
	}

	public function dbVerileriSay(){ //kayıt sayısını bulma
		$say = $this->conn->prepare('SELECT id FROM yazilar');
		$say->execute();
		return $say->fetchColumn();
	}

	public function dbVerileriCek(){ //bütün verileri alma
		$veriler = $this->conn->prepare('SELECT id,baslik,icerik FROM yazilar');
		$veriler->execute();
		return $veriler->fetchAll(PDO::FETCH_ASSOC);
	}

	public function dbVeriyiCek($id){ //sadece bir kayıtı (parametredeki) alma
		$veri = $this->conn->prepare('SELECT id,baslik,icerik FROM yazilar WHERE id=?');
		$veri->execute(array($id));
		return $veri->fetch(PDO::FETCH_ASSOC);
	}

	public function dbVerilerdeAra($aranan){ //kayıtlarda arama yapma
		$bul = $this->conn->prepare('SELECT id,baslik,icerik FROM yazilar WHERE baslik LIKE ?');
		$bul->execute(array('%'.$aranan.'%'));
		return $bul->fetchAll(PDO::FETCH_ASSOC);
	}

	public function dbVeriyiGuncelle($id){ //parametredeki veriyi güncelleme (isimlendirilmiş parametre)
		$guncelle = $this->conn->prepare('UPDATE yazilar SET baslik = :baslik WHERE id = :id');
		return $guncelle->execute(array('baslik' => 'bu başlığı değiştirdim', 'id' => $id));
	}

	public function dbVeriyiSil($id){ //parametredeki kayıtı silme
		$sil = $this->conn->prepare('DELETE FROM yazilar WHERE id=?');
		return $sil->execute(array($id));
	}

	public function __destruct(){ //bağlantıyı sonlandırma
		$this->conn = null;
	}
}

//örnek kullanım
$baglanti = new baglan;
$baglanti->dbVerileriEkle();
echo $baglanti->dbSonKayitIdAl();
?>

Yukarıda PDO’nun temel kullanımını gösterdim. PDO’nın  başka bir çok methodu bulunmakta, eğer bunları incelemek isterseniz Php.net adresini önerebilirim. SQL Injection sorunundan korunmak için mutlaka prapared statements kullanın. Ayrıca, aldığınız parametrelerde bulunabilme ihtimali olan Html etiketlerini (<script></script>) temizlemeyi unutmayın, çünkü prapared statements XSS açığını önlemez.

 2.792 Okunma

Bu yazıya 22 yorum yapılmış.

  1. Sql injection açığından çok çekiyoruz, öğrendiğim iyi oldu.

  2. Ben bunu sql gönderilen bir sınıfa çevirip kullanmayı düşünüyorum, neredeyse bütün sorgu tipleri var, eline sağlık bu arada. Dönüşünü sabırsızlıkla bekliyordum.

  3. XSS Açıgını Engelleyecek Bir Fonksiyon Öneriyormusunuz

    Veritabına Post Ederken

    $baslik= mysql_real_escape_string($_POST[‘baslik’]);

    Böyle Kullanıyordum, PDO’da Sadece XSS Açıgını Önlemem Yeterli Olacakmı ?

    • Yukarıdaki kullanım XSS açığını önlemez (mysql_real_escape_string XSS açığını değil Sql injection açığını engeller). XSS açığını önlemek için strip_tags kullanman gerekir.

    • strip_tags ya da htmlentities kullan

  4. @Ayhan @Mustafa Kolcu İkinizede Çok Teşekkür Ederim

  5. Post kontrolünü strip_tags ile yaptığımda yazılara link vs atanmıyor, bunu nasıl kullanmam gerekir?

    • Silmeyip sadece zararsız hale getirtebilirsin, htmlentities ya da htmlspecialchars kullanarak. Hiç olmadı kendi fonksiyounu yazarsın istemediğin etiketleri temizleyen. Detaylı olarak bu konuları incelemek istersen güvenlik açıklarını kapatma yazımdan faydalanabilirsin.

      • Merhaba, PDO’da execute ilemi yoksa bindParam ilemi verileri kayıt etmek daha doğrudur?

        • Güvenlik açısından aralarında fark yok, prepared statements ile kullanılırsa ikisi de güvenlidir. Fakat bindParam ile gönderdiğimiz verilere (GET, POST metodu ile gelen verilerde daha çok tercih ediliyor) veri tipi uygulayabiliyoruz (PDO::PARAM_INT gibi). Ayrıca SQL LIMIT sorgusunu dinamik olarak belirliyorsanız (LIMIT mikarını dışarıdan gönderilen parametre aracılığıyla) bindParam kullanmak daha avantajlı çünkü execute kullandığınızda SQL sorgusunu string ifadeye (LIMIT ’10’ gibi) çeviriyor, bundan dolayı da hata meydana geliyor, bindParam’da veri tipini tanımlarsanız (PDO::PARAM_INT olarak), integer değer olarak göreceğinden hata meydana gelmez.

  6. Kodların Silineceğini Unuttum Pardon 🙂

    https://gist.github.com/canaytekin/ce75ea90036f1f55458e

    Yukarıdaki Linkten Bakabilirsiniz.

  7. PDO’nun fetchAll ile bir seferde bütün verileri alma kolaylığı çok hoşuma gidiyor, bir daha while gibi döngü kurmaya gerek bırakmıyor.

  8. Artık yeni sürümlerde destek verilmeyecek olması PDO öğrenimini mecbur kıldı. Biz de mecburen öğreneceğiz.

    • Haklısın ben de bu yüzden öğrenmek istedim ama Sql Injection önlemesi büyük avantaj olmuş.

  9. Object mapping özelliği de bulunmakta benim favorim.

  10. Hocam bu örneği bir de form üzerinde yapmanız mümkün mü acaba, araştırdım ama örnek bulamadım. Form ile kayıt, düzenleme, ve vt’den verileri çekme gibi.

    • Bu örneği daha önce yazdığım GET ve POST işlemleri örneğiyle birleştirirsen, istediğini elde edersin. Örneğin, arama işlemi yapmak için; $ara=$_POST[‘ara’]; şeklinde formdan değeri alıp, $baglanti->dbVerilerdeAra($ara); ile sınıfa göndermek.

  11. Hocam ya bir karar vereceğim artık diyorlar ki PDO güvenli olmayabilir en iyisi Laravele geçin diyorlar. Lütfen artık neye güveneceğim bilmiyorum :((( hem de geliştirme aşamasındayım!.

    • PDO en güvenli yöntem (prapered statements kullanırsan). Laravel’de PDO kullanıyor bu arada.

  12. Merhaba,
    Pdo olarak yazdığım sistemlerde yeni fark ettiğim bir sorun oluyor. Textareadan resim gönderildiğinde (boşluklar yok) olarak kaydediyor ve çağırırken sıkıntı yaratıyor. Bunu kaynağı pdo sanırım. Bir bilginiz var mi?

    • Boşlukların olmaması PDO ile alakalı değil kaydetme ve ekranda gösterme şeklinizle alakalıdır. Örneğin; textareadan yazılar arasında kullanılan alt satıra inme (enter) tuşunun ekranda o şekilde gösterilmesini isterseniz nl2br($str) fonksiyonunu kullanabilirsiniz.

  13. bindParam örneği de ekleseydiniz tadından yenmez bit yazı olurdu ama yine bütün örnek tiplerine değinmişsiniz. Baya işimi gördü teşekkürler.

Yazı hakkında görüşlerinizi belirtmek istermisiniz?

Daha fazla MySQL, Php
Kapat