RSS

PHP Data Objects (PDO)

45 13 Kasım 2012 ~ Musa Avcı — İleri

Artık “mysql_connect“, “mysql_query” fonksiyonlarının müfredattan kalkma zamanı geliyor, PHP’de kendi resmi dökümantasyonunda da bunun sinyalini vermeye başlamış; “mysql” fonksiyonlarının sayfasında aşağıdaki gibi bir öneriyle karşılaşıyoruz;

This extension is not recommended for writing new code. Instead, either the mysqli or PDO_MySQL extension should be used. See also the MySQL API Overview for further help while choosing a MySQL API.

Özetle artık bunları kullanmanızı önermiyoruz, PDO ya da MySQLi‘ye geçin diyor. Peki nedir bunlar? Şuradaki karşılaştırmaya baktığımızda MySQLi ile PDO arasında çok fark olmadığını görebilirsiniz.

PDO’da çoğu veritabanı sürücüsü kullanılmasına olanak sağlayan, MySQLi ise sadece MySQL destekleyen ve PDO’ya göre biraz daha karmaşık ve kapsamlı bir arayüz diyebiliriz. Sonuç olarak ikisi de öneriliyor. Ben burada PDO’dan bahsetmeye çalışacağım, iksinden birisinin kullanım şeklini kavradığınızda diğerini de rahatlıkla kullana bileceğinize inanıyorum. 

PDO nedir?

PDO(PHP Data Objects / PHP Veri Objeleri) özetle; hafif ve tutarlı bir şekilde veritabanına erişimi sağlayan bir arayüz. Adından da anlayacağınız üzerie “Object Oriented Programming” arayüzüne sahip, onlarca veritabanı sürücüsü destekliyor;

  • Cubrid
  • 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
  • SQLite 3 and SQLite 2
  • Microsoft SQL Server / SQL Azure

İleride daha farklı bir veritabanı sürücüsüne geçmek istediğinizde sisteminizi temelli olarak değiştirmek yerine PDO ile kaldığınız yerden bir takım ufak modifikasyonlar ile bu işi gerçekleştirebilirsiniz.

Bunların haricinde PDO 5.1‘den itibaren geliyor, yani çalışabilmesi için güncel versiyonlara ihtiyacınız olacak.

PDO ile MYSQL’e bağlanmak

Genel olarak bağlantı olaylarını bir PDO sınıfını tanımlarken bir DSN yani “Data Source Name” ile belirtiyoruz. Hangi veritabanı sürücüsüne bağlanacağımızı ve bilgilerimizi DSN ile ifade ediyoruz. Diğer iki parametrede ise veritabanı kullanıcı adı ve şifremizi giriyoruz.

$db = new PDO('mysql:host=localhost;dbname=test', $user, $pass);

Diğer sürücülerin DSN ifadeleri için şuraya bakın.

$dsn = 'mysql:host=localhost;dbname=test';
$user = 'dbuser';
$password = 'mypassword';

try {
    $db = new PDO($dsn, $user, $password);
} catch (PDOException $e) {
    echo 'Connection failed: ' . $e->getMessage();
}

Bu şekilde de bağlantı hatalarını yakalıyoruz.

Sorgu hatalarını yönetmek

Query ya da exec gibi sorgu gönderdiğimiz metodlar eğer sorguyu gerçekleştirdiklerinde bir hata ile karşılaşırlarsa false dönerler. Başarısız gerçekleşen bu sorguların hata mesajlarına ulaşmak için errorInfo metodunu kullanacağız.

Bu metod bize son yaptığımız sorgudaki hatanın kodunu ve mesajını içeren bir array döndürür. 3 adet elemanı bulunan bu dizide 0. ve 1. eleman hata kodlarını, 2. eleman ise hata mesajını verir.

if($users = $db->query('SELECT * FROM users WHERE'))
{
    // Sorgu başarıyla çalışırsa üyeleri listeleriz
}
else
{
    echo 'Sorguda bir hata meydana geldi.';
    $error = $db->errorInfo();
    echo 'Hata mesajı: ' . $error[2];
}

Örnekteki sorguda WHERE dedikten sonra herhangi bir koşul belirtmediğimiz için hata verecektir ve ekrana ilgili hatanın mesajı yazacaktır.

PDO ile sorgu göndermek

Eğer yapacağımız sorgudan bir sonuç almayı beklemiyorsak “exec“, bir sonuç isteniyorsa “query” metodlarını kullanmalıyız. Özetle; “DELETE/UPDATE/INSERT” gibi sorgularımız için “exec”, “SELECT” gibi sorgularımız için “query”.

try {
    $db = new PDO('mysql:host=localhost;dbname=test', $user, $password);
    $db->exec('SET NAMES `UTF-8`');
    $count = $db->exec('DELETE FROM messages WHERE old = 1');
    echo $count . ' messages deleted';
} catch (PDOException $e) {
    echo 'Connection failed: ' . $e->getMessage();
}

Exec metodu sonuç olarak etki ettiği satır sayısını döndürür.

Değişkenleri sorgulara dahil etmek

PDO’nun en önemli özelliklerinden birisi olan binding yöntemi sayesinde hazırladığımız sorgulara değişkenlerimizi güvenli ve düzgün bir şekilde yerleştirebiliyoruz.

Bunun için önce prepare metodu ile sorgumuzu hazırlayıp dışarıdan değerler vereceğimiz yerlere “?” (soru işareti) yerleştiriyoruz. Sonrasında hazırladığımızı sorguya execute metodu ile soru işareti olan yerlere gelecek değerlerimizi gönderiyoruz.

// Sorgumuzu hazırlıyoruz
$query = $db->prepare('INSERT INTO users (name, email) VALUES(?, ?)');

// Sorguda belirttiğimiz yerlere gelecek değerleri veriyoruz
$query->execute(array('Musa', 'email@email.com'));

Bu ifadeyi çalıştırdığımızda çalıştırılacak sorgu aşağıdaki gibi olacaktır;

INSERT INTO users (name, email) VALUES('Musa', 'email@email.com')

PDO kullanırken tüm dışarıdan aldığımız değişkenleri sorgularımıza bu yöntem ile dahil etmemiz uygulamamızın güvenliği ve düzeni açısından çok önemlidir. Bu yöntem sayesinde SQL injection açıklarından da arınmış oluyoruz.

PDO ile verileri listelemek

Bunun için yukarıda bahsettiğim query metodunu kullanacağız.

foreach($db->query('SELECT * FROM users') as $row) {
    echo $row['name'] . '<br/>';
}

PDO ile bir satır veri çekmek

Bunun için query ile sorgumuzu çağırdıktan sonra fetch ile ilk sonucu alacağız.

$row = $db->query('SELECT * FROM users WHERE id = 1')->fetch();
echo $row['name'];

Yeni bir kayıt eklemek

Yeni bir kayıt eklemek için exec metodunu kullanacağız. Sonrasında eğer eklediğimiz satırın ID’sini almak istiyorsak lastInsertId metodunu çağıracağız. Eklerken bir sorun gerçekleşirse exec metodu false dönecektir. Bu nedenle öncelikle eklenip eklenmediği kontrol edip sonrasında ID’yi ekrana yazdırabiliriz.

if($db->exec('INSERT INTO users (name) VALUES ("Musa")'))
{
    $id = $db->lastInsertId();
    echo 'Yeni eklenen üyenin IDsi: ' . $id;
}
else
{
    echo 'Yeni kayıt eklerken bir hata meydana geldi.';
}

Sorguları geri alabilme

PDO’nun bir diğer önemli özelliği ise transaction denilen ifade edilen sorguları istenildiğinde geri alabilme ya da uygulayabilmesidir.

Yukarıdaki sorgu ifadelerini kullanmadan önce beginTransaction metodunu çağırarak geri alma işlemi yapabileceğimiz sorguları yazmaya başladığımızı ifade etmemiz gerekiyor.

BeginTransaction metodunu çalıştırdıktan sonra yazacağımız tüm ekleme, düzenleme ve silme sorguları normal kullandığımız şekilde çalışmaya devam eder. Eğer sorgular devam ederken tüm bu aralıktaki sorguları geri almak istersek rollBack metodunu çağırırız. Bu metodu çalıştırdığımızda beginTransaction’dan rollBack metoduna kadar yazdığımız tüm ekleme, düzenleme ve silme sorguları geri alınır.

Bu ifadeleri kullanırken bilmeniz gereken önemli bir konu; DROP TABLE ya da CREATE TABLE gibi tabloları komple silen ya da yeni tablolar ekleyen sorgular geri alınamaz. Fakat DELETE sorgusu ile sildiğiniz ya da UPDATE ile düzenlediğiniz her sorguyu geri alabilirsiniz.


// İşlemleri başlattığımızı ifade ediyoruz
$db->beginTransaction();

$db->exec('INSERT INTO users (name) VALUES ("Ahmet")');
$db->exec('UPDATE users SET name = "Ali"');
$db->exec('DELETE FROM users WHERE name = "Hasan"');

// Yaptığımız sorguları geri aldık
$db->rollBack();

Yaptığımız sorguları geri almak yerine başarıyla sonuçlandığında gerçekten uygulamak istiyorsak commit metodunu çağırırız.

PDO bağlantısını kapatmak

Eski MySQL bağlantısında da olduğu gibi açtığınız bağlantıyı kapatmasanız da PHP otomatik olarak işlem sonunda bağlantıyı keser. Fakat ille de ben kapatacağım diyorsanız “null” tanımlamanız yeterli.

// bağlantıyı açtık
$db = new PDO('mysql:host=localhost;dbname=test', $user, $pass);[

// bağlantıyı kapattık
$db = null;

Dahası …

Ben bu yazıda PDO’nun temel ihtiyaç duyulan ifadelerinden bahsetmeye çalıştım. Fakat bununla yetinmeyip PDO hakkında daha fazla bilgi edinmek için şuralardaki örnekleri ve açıklamaları incelemeye devam edin.

Bir sonraki serüvende görüşmek üzere, hoşçakalın.

Etiketler:

Yazılanlar ilgini çektiyse, yenilerinden haberdar olmak için e-mail bültenine abone olabilirsin.

"PHP Data Objects (PDO)" yazısı için 45 yorum yapılmış.

  1. Piyasada kaliteli geliştiricilerin çoğalması adına daha çok Türkçe içeriğe ihtiyaç var. Bu anlamda kaynak olabilecek nitelikte başarılı bir yazı olmuş. Elinize sağlık.

  2. ismail dedi ki:

    Hocam temiz ve güzel bir anlatım. Teşekkür ederim. PDO konusunda ki diğer anlatımlarınızı da bekliyorum.

  3. ismail dedi ki:

    Hocam sormak istediğim bir konuda,
    PDO ile veri listelerken

    $row = $db-&gt;query('SELECT * FROM users WHERE id = 1')-&gt;fetch();

    Burada fetch(); i kullanmışınız. Ben bu fetch(); değerini hangisini tanımladığınızı anlayamadım.
    Yani normalde mysql_fetch_object, array, row, assoac gibi tanımlar var. Burada derleyici fetch(); değerini belirttiğinizde hangisini okuyarak işlem yapıyor.

  4. Aydın dedi ki:

    Çok güzel konular, anlatım ve kodlama yapınız da gayet temiz. İleri seviye daha çok konu bekliyoruz 🙂

    Emeğinize sağlık..

  5. Gunduz dedi ki:

    Salam. Gozel dersliklerdi. Yeri gelmiwken. AZERBAYCANDAN SIZE SALAMLAR

  6. Adnan dedi ki:

    Tesekkrler

  7. erkin dedi ki:

    hocam ben anlamadım bunu.mysql connectden vs ne farkı var ki şimdi.bence yazının sözel kısmını uzatmalısınız

    • Musa Avcı dedi ki:

      PDO’nun “mysql_connect” gibi ifadelerden farkı çok. Ama özetlememi istersen; yeni, daha kullanışlı, güvenilir ve fonksiyonel diyebiliriz. Daha iyi anlamak için mutlaka en yakın projenizde denemenizi öneririm.

  8. PDO veritabanı işlemleri için mysql_ gibi fonksiyonlardan çok daha güvenli ve hızlıdır. Ama gel de anlat bunu. Millet kullanmak istemiyor, kullanınca garip bakıyorlar.

    Hazırlanmış deyimleri de yazsaydınız keşke, SQL Injection’dan korunmak için bir numaralı PDO yöntemi.

    Teşekkürler, umarım PHP geliştiricilerinin çoğu PDO kullanmaya başlar.

  9. Enes dedi ki:

    Merhaba, öncelikle yeni php öğrenen biri olarak şu anda kendi blog scriptimi yazıyorum veritabanları ile ilgili bir araştırma yaparken pdo işlemlerini gördüm. Sormak istediğim ise, mysql_ komutlarını öğrenmek yerine pdo komutlarını öğrensem sizce daha mı mantıklı olur madem mysql_ komutları kalkacak yakında öğrenmemin ne anlamı olur değil mi ? sizin düşünceniz nedir ?

  10. zeyd özer dedi ki:

    pdo php 5.1’in üstü versiyonlarda gömülü olarakmı geliyor yoksa ayrı kurulum yapmak gereklimi?

    • Musa Avcı dedi ki:

      PDO and the PDO_SQLITE driver is enabled by default as of PHP 5.1.0

      aynen dediğiniz gibi, 5.1 ve üzerinde varsayılan olarak var.

      • zeyd özer dedi ki:

        db fonksiyonlarımı pdo’ya çevirdim. mysql fonksiyonlarına göre daha basit ve kullanışlı. sonuca giderken fazla dolanmıyosunuz 🙂

  11. arslanprefabrik.com dedi ki:

    umarım PHP geliştiricilerinin çoğu PDO kullanmaya başlar.

  12. ahmet dedi ki:

    eline sağlık çok güzel anlatım. Faydalı bir sunum oldu teşekkürler

  13. Kemal dedi ki:

    İleri Seviyede başka derslerde olsaydı güzel olurdu

  14. Nurettin dedi ki:

    Güzel döküman ellerinize saglık

  15. Kadir Malakcıoğlu dedi ki:

    performans bakımından özelliklede anlık mesajlaşma sistemi tarzı uygulamalarda pdo mu yoksa mysqli mi daha performanslı olur

  16. Bəhruz dedi ki:

    Təşəkkürlər. Faydalı məqalədir.

  17. Baran Şengül dedi ki:

    Hocam bilgiler çok yararlı ve çok sade anlatılmış şekilde gerçekten bunun için büyük bir teşekkürü kesinlikle hak ediyorsunuz. Benim sizden bir de ricam olacak. Kafamda bir fikir var yalnız bunu koda dökerken bir yerde tıkandım eğer benimle email üzerinden iletişime geçip yardımcı olursanız çok sevinirim.

  18. nakatakan dedi ki:

    evet kendimizi geliştirmemiz gerekiyor. demekki kodu bir kere yazıp yuz yere kopyalamak pek kendini geliştirmek olmuyor teşekkür ederim.

  19. Bəhruz dedi ki:

    Çox faydalı məqalədir.

  20. Uğur öztekin dedi ki:

    Bilgi için çok teşekkürler.

  21. Şener dedi ki:

    Makale için teşekkürler 🙂

  22. samet dedi ki:

    öncelikle verdiğiniz bilgiler için teşekkürler.
    ben ilk defa web sitesinde veri tabanı kullanmaya çalışıyorum ve sürekli

    SQLSTATE[HY000] [1045] Access denied for user ‘cupsamet_samet1’@’lineko72.isimtescil.net’ (using password: YES)

    böyle bir hata alıyorum
    kulanıcı adını ve şifreyi doğru girdiğime eminim

    try {
    $db = new PDO(“mysql:host=93.89.225.106;dbname=cupsamet_deneme”, “cupsamet_samet1”, “pass”);
    } catch ( PDOException $e ){
    print $e->getMessage();
    }

    site bu

    yardımcı olursanız sevinirim.

  23. kına tepsisi dedi ki:

    Paylaşım için Teşekkürler

  24. teoman dedi ki:

    PHP msql sınıfına olan desteğini ileride tamamen bitireceğini açıkladı. mysqli veya PDO kullanılmasını öneriyor. Wamp son sürümünü kurarsanız ve hataları gösteri seçtiyseniz mysql komutları bulunan php sayfası çalıştığında bu uyarıyı browserda görebilirsiniz.

  25. Hocam çok güzel anlatmışsınız ağzınıza sağlık.. Sadece birşey anladımadım exec methodu… query den farkı ne? Biraz detay verebilirmisiniz…

  26. Ramil dedi ki:

    Təşəkkürler. Size bi sorucam burda

    $count = current($db->query(“select count(*) from table where login=’.$login.'”)->fetch());
    echo “$count”;

    burda neden logini $login deyiskenine beraber olan sqllarin toplam cemini vermiyor ? Eger mumkunse cevaplandirardiz.

  27. Tekin Simsek dedi ki:
    $id=$_GET['id'];
    
    $icerikSorgu = $baglan-&gt;prepare(&quot;Select * from icerikler where icerikId=?&quot;);
    $icerikSorgu-&gt;execute(array($id));
    $icerikSonuc =$icerikSorgu-&gt;fetch(PDO::FETCH_OBJ);
    
    //ip Hit Baslangic
    if (!isset($icerikSonuc-&gt;icerikId)){
    	header(&quot;index.php&quot;);
    }
    else
    {
    	$ip = $_SERVER['REMOTE_ADDR'];
    	
    	date_default_timezone_set('Europe/Istanbul');
    	$tarih = date (&quot;y-m-d&quot;);
    	$saat = date (&quot;h:m:s&quot;);
    	
    	$hitSorgu =$baglan-&gt;prepare(&quot;Select * from reyting where ipAdresi='?' and icerikId='?'&quot;);
    	$hitSorgu-&gt;excute(array($ip,$icerikSonuc-&gt;icerikId));
    	$hitSonuc =$hitSorgu-&gt;fetch(PDO::FETCH_OBJ);
    	
    	if(!$hitSonuc){
    		$query=$baglan-&gt;prepare(&quot;Insert Into reyting (ipAdresi,tarih,icerikId,saat) values('?','?','?','?')&quot;);
    		$query-&gt;execute(array($ip,$tarih,$icerikSonuc-&gt;icerikId,$saat));
    		$query2=$baglan-&gt;prepare(&quot;Update icerikler set izlenme=izlenme +1 where icerikId='?'&quot;);
    		$query-&gt;execute(array($icereikSonuc-&gt;icerikId));
    	}
    }
    

    hocam suan kod hata vermiyor ama sitede göstermiyorda su şekilde cağiriyorum ama cağirmiyor

    echo $icerikSonuc[‘icerikBaslik’];
    

    bir ilgilenirsen sevinirim

  28. Hakan dedi ki:

    bu sayfada daha önce pdo ile güncelleme işlemi anlatılıyordu, kendim ve öğrencilerim bu kısımdan epey faydalanıyorlardı, sayfaya güncelleme kısmını tekrar ekler misiniz lütfen..
    Ayrıca sitenizdeki kısa ve öz anlatım da gayet başarılı..

  29. cebrail ilhan dedi ki:

    foreach($db->query(‘SELECT * FROM isimler’) as $row) {
    echo $row[‘name’] . ”;
    bu sadece “name” sütununu gösteriyor daha fazla sütunu görüntülemek için ne yazmamız gerek?
    [‘name’].[‘2.sutun]
    veya [‘1.sutun’ . ‘2.sutun’] tarzı denedim hiç biri işe yaramadı

    • Mehmet dedi ki:

      foreach($db->query(‘SELECT * FROM isimler’) as $row) {
      echo $row[‘name’];
      echo $row[‘2_sutun’];
      }

      şeklinde gerçekleşiyor.

  30. Tarık Demirci dedi ki:

    Çok güzel anlatmışsınız.
    Farkettiğim bir hata: “Değişkenleri sorgulara dahil etmek” bölümünde emai@email.com ‘dan sonra tek tırnak eksik.
    Yazım diliniz gayet açıklayıcı, Teşekkür ederim.

  31. Ayşe dedi ki:

    allah razı olsun sayenizde kimseye minnet duymadan 1-2 bişey öğreniyoruz

  32. Süleyman dedi ki:

    pdo konusunda güzel yazınızdan dolayı teşekkürler

  33. Emin dedi ki:

    Select ile Sql Injection açığı yemeyecek şekilde kullanıcıdan aldığım veriyi “where” ile kontrol ettikten sonra o veri ile ilgili veritabanından bazı bilgileri çekip ekranda göstermek istiyorum.(örn: Kullanıcının tıkladığı yazının idsini alıp veritabanındaki id ile eşleştirip, o id ile iligli içerik,resim,yazıbaşlığı gibi yerleri çekip ekrana yazdırmak-tabi bunları yaparken sql ınjection açığını yemeden) Sizce bunu nasıl yapabilriim?
    Verdiğiniz select örneklerini inceledim ama birinde sql ınjection açığı var diğerindede açık yok ama onda da veri çekmiyorsunuz.
    Yardımcı olurmusunuz?

  34. kamil karlı dedi ki:

    Millet mysql güvenlik ve verimli kullanımı üzerine konuşadursun biz halen eski usül mysql bağlantı kuralım..
    Faydalı bir konu.. Aslında direkt pdo verilse diğer mysql bağlantı yazıları buraya yönlendirilse daha iyi olacağı inancındayım.

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir