18 Jun

Neden PDO Kullanmalıyız ? İşlevsellik

PDO kullanmanın yararlarına dair burada ve şuradaki yazılarım ile başlayan PDO serisinin, kendimce son halkası olan bu yazı ile son buluyor.

Yoğun veritabanı işlemlerinin olduğu, çok fazla girdi olan işlemler hep sıkmıştır beni. Çünkü her parametreyi tek tek kontrol etmek, hata takibi vb işlemler.

Bu söylediğim can sıkıcı durumu hafifleten PDO, sunduğu olanaklar ile kodlamada ve kontrolde bize yardımcı oluyor. Bunu nasıl mı yapıyor ?

PDO bildirimleri ile, SQL cümleciklerine gönderilmesi gereken paremetreleri zahmetsizce ekleyebiliyor ve aynı zamanda etkisizleştirebiliyoruz :

1
2
3
4
5
6
7
try{
  $pdo=new PDO('mysql:dbname=testdb;host=localhost','kullanici','sifre');
  $sorgu=$pdo->prepare('INSERT INTO kullanicilar VALUES (?,?,?)');
  $sorgu->execute(array('ersin dogan','ersin','12345'));
}catch(Exception $e){
  echo $e->getMessage();
}

Yukarıdaki kod ile yapmaya çalıştığım şey, veritabanına bağlanarak kullanıcılar tablosuna verilen bilgileri kaydetmek. Eski yönteme göre yapmmış olsaydık :
– bağlantıyı açacak
– veritabanını seçecek
– verilen her parametreyi SQLe geçirecek
– sorguyu çalıştırcak
– ve her adımda hata kontrolü yapacaktık.

Yukarıda yazdığım adımları, aklınızdan koda döktüğünüzde, PDO ile yazılmış örnekten çok daha fazla satıra ve uğraşa mal olacağını kolaylıkla bulabilirsiniz.

Örneğimizde bütün işlemleri try – catch bloğu içerisine alarak hata kontrolünü kolaylıkla yapabiliyoruz.

prepare metodu ile, SQL cümleciğini bir PDO bildirimine (statement) dönüştürüyoruz. Bu bildirimin execute metoduna gerekli parametreleri verdiğimizde, bu bildirim otomatik olarak parametre eşleşmelerini yaparak sorguyu çalışıtırır.

Eşleşmeyi ? işareti yerine , execute içerisine verilen array deki parametreleri sırası ile vererek yapar. Eğer arraydeki parametreleri yanlış sıralarsanız tabloya yanlış kaydedilir veya hiç kaydedilmez.

Bunu önlemek için , parametre eşleşmelerini isim vererek de yapabilirsiniz :

1
2
3
4
5
6
7
try{
  $pdo=new PDO('mysql:dbname=testdb;host=localhost','kullanici','sifre');
  $sorgu=$pdo->prepare('INSERT INTO kullanicilar VALUES (:adsoyad,:kullanici,:sifre)');
  $sorgu->execute(array('adsoyad'=>'ersin dogan','kullanici'=>'ersin','sifre'=>'12345'));
}catch(Exception $e){
  echo $e->getMessage();
}

Bu yöntem karışıklıkları engellemek için daha etkili. Daha önceki konuda verdiğim kodları incelerseniz, konuya dair daha fazla fikre sahip olabilirsiniz.

Konuya dair toparlayabildiklerim bunlar. Eksik, anlaşılmayan veya hatalı yerler var ise beni uyarırısanız, gerekli değişiklikleri en kısa zamanda yaparım.

Güzel günler dileği ile.

09 Jun

Neden PDO Kullanmalıyız – Esneklik

Evet, nerde kalmıştık. Esneklik ile kastettiğim şeyi açıklayabilmek için bir örnek hazırladım. Örneği buradan indirebilirsiniz.

Bu örnek ile yapmaya çalıştığım şey, kodda yapısal hiçbir değişikliğe gitmeden 2 farklı veritabanını kullanabilen bir uygulama yapabilmekti.

Kolay ve bilinen bir örnek olarak , basit ötesi bir ziyaretçi defteri oluşturdum. Bu ziyaretçi defteri hem sqlite hem de mysql destekliyor. Bunu PDO sayesinde yapabiliyor.

Bildiğiniz gibi PDO aşağıdaki veriatabanlarına destek veriyor :
* MS SQL Server (PDO) ? Microsoft SQL Server ve Sybase (PDO_DBLIB)
* Firebird/Interbase (PDO) ? Firebird/Interbase (PDO_FIREBIRD)
* IBM (PDO) ? IBM (PDO_IBM)
* Informix (PDO) ? Informix (PDO_INFORMIX)
* MySQL (PDO) ? MySQL (PDO_MYSQL)
* Oracle (PDO) ? Oracle (PDO_OCI)
* ODBC and DB2 (PDO) ? ODBC ve DB2 (PDO_ODBC)
* PostgreSQL (PDO) ? PostgreSQL (PDO_PGSQL)
* SQLite (PDO) ? SQLite (PDO_SQLITE)
* 4D (PDO) ? 4D (PDO_4D)

PDO (Php Data Object) bir arayüz sunarak, bu arayüzü destekleyen sürücüleri ile birlikte veritabanı üzerinde işlem yapılmasını sağlıyor. Bütün işlemler PDO üzerinden yürütüldüğü için kodda herhangi bir yapısal değişikliğe gidilmiyor, yani tek satır yeni kod yazmadan (sadece parametre değişikliği ile) birden fazla veritabanını ile çalışabilen bir uygulama mümkün oluyor.

Örneğimizin çalışabilmesi için testdb adında bir mysql veritabanı oluşturun. Bu veritabanı üzerinde, dosyalar içerisinde bulunan, schema.txt dosyasındaki mysql kodunu çalıştırın :

CREATE TABLE `defter` (
`id` INTEGER AUTO_INCREMENT,
`konu` VARCHAR(100),
`mesaj` TEXT,
`yazar` VARCHAR(32),
`eposta` VARCHAR(32),
PRIMARY KEY (`id`)
)
ENGINE = InnoDb
CHARACTER SET utf8 COLLATE utf8_general_ci;

Kodları web sunucunuza açın. Dosyalar arasındaki sayfa.php de bulunan şu satıra gidin

1
2
3
4
5
6
7
8
9
10
11
   public function __construct(){
      /**
       *  mysql dsn
       *  'mysql:dbname=testdb;host=127.0.0.1'
       *  
       *   sqlite dsn
       *   'sqlite:sqlite-defter.db'
       */

     
      $this->defter=new Defter('sqlite:sqlite-defter.db');
   }

Burada veritabanı işlemleri yapmamıza (defeteri okuyup yazmamıza) olanak sağlayan sınıfımızın ( Defter ) alacağı parametreler görülmekte.
Hiçbir değişiklik yapmadan ve PDO_SQLite sürücüsü aktif iken testi çalıştırırsanız SQLite destekli bir ziyaretçi defteri çalıştırmış olursunuz.

Bu ziyaretçi defterini mysql ile kullanmak isterseniz yapmanız gereken tek şey Defter sınıfının kurucusuna verilen parametreyi değiştirmek :

1
    $this->defter=new Defter('mysql:dbname=testdb;host=127.0.0.1','kullanici-adi','sifre');

Evet, hepsi bu. Sadece parametre değişikliği ile bu esnekliği sağlıyoruz. Burdaki parametre PDO nesnesinin ilgili veritabanı sürücüsünü yüklemesi için gereklidir.
Bunu PDO’suz da yapabilirdik, ama kodları incelediğinizde PDO’nun gücünü daha iyi anlayacaksınız.

Tabi herşey bu ziyaretçi defterindeki gibi kolay olmuyor, her veritabanı kendine has özelliklere sahip ve bu özellikler geçiş esnasında sıkıntılar yaşatabilir.
Ama eğer ara katman düzgün planlanmış / yazılmışsa , sadece veriatabanı /SQL değişiklikleri ile kodda çok fazla değişikliğe gidilmeden ( hatta bu örnekte olduğu gibi sadece DSN değişikliği ile ) geçiş yapmak mümkün olabilir.

03 Jun

Neden PDO kullanmalıyız – Güvenlik

Uzun bir ara oldu yazmayalı, iş-güç derken baya boşladım blogumu. Ayrıca, yazmak istediğim konulara dair pek bir kararsızdım. En sonunda PDO ya dair yazılar yazarak devam etmeye karar verdim.
Daha önce PDO ile ilgili yazılar yazmıştım, konuyu tamamlamak adına birkaç şey var, onları dilimin döndüğünce aktarmaya çalışacağım.
Güvenlik önemli bir unsur, web uygulamalarımızda her zaman karşı kaşıya kaldığımız bir konudur. Güvenlik açıklarından biri SQL Injection, yani SQL aşılamadır.
SQL Injection’ı, veritabanından veri çekmek için kullandığımız SQL sorgularının istemediğimiz biçimde değiştirilmesi olarak özetleyebiliriz.
Bir örnek ile olaya daha yakından bakalım :

kullanıcı adında ,id -kullanici ve sifre alanlarının oluşan bir tablomuz var. Bu tabloyu üyelik sistemi için kullanıyoruz,kullanıcıya dair bilgileri bu tabloda saklıyoruz. Böylece sisteme girişleri (login) bu tablodaki bilgiler aracılığı ile gerçekleştiriyoruz. Buraya kadar herşey normal, şimdi basit bir şekilde bir sorgu yaparak, giriş yapmak isteyen kullanıcımzının bilgilerini kontrol edelim

1
2
3
4
5
6
$baglanti=mysql_connect('localhost','kullanici_adi','sifre');
mysql_select_db('testdb');
$sorgu='select*from user where name="'.$_GET['u'].'" and password="'.$_GET['p'].'"';
$sonuc=mysql_query($sorgu);
echo '<pre>',print_r(mysql_fetch_assoc($sonuc),true);
mysql_close($baglanti);

Test etmesi kolay olsun diye, sadece GET ile gelen verilere göre işlem yapıyoruz. Bu sorgudan veri dönerse kullanıcımız var demektir, böylece kullanıcımızı giriş yapmış olarak kabul edebiliriz. Tabiki yukarıdaki gibi bir yöntem hiçbir yerde kullanılamaz, ama konuya verilebilecek iyi bir örnek.
Bu dosyayı kendi sunucumuzun diznine yerleştirip şu şekilde çalıştırdığımızda :

Örn : http://localhost/test.php?u=ersin&p=12345

sorgumuz çalışacak, şartları sağlayan veri varsa ekrana yazdırılacak. Şimdi gelin biraz kötü niyetli davranalım, çünkü,bu kodu yazan hiçbir güvenlik önlemi almamış, cezalandırılmayı hak etmiş 🙂

Adres satırından şöyle bir giriş yaparsak :

http://localhost/test.php?u=” or 1=1–&p=” or 1=1–

karşımıza ilk kullanıcının verisi gelir. İşte bu SQL aşılamanın en bilinen örneği. Tabi bundan korunmanın tek yolu PDO değil ama gerçekten en akılcı ve etkin yöntemlerden biridir. Yukarıdaki satır, nasıl sonuç döndürülmesine sebep oldu derseniz, kullanıcıdan gelen veriyi filtrelemediğimiz için, kötü niyetli kullanıcı SQLi değiştirerek ( sorgu şu biçimde olur select*from user where name=”” or 1=1–” and password=”” or 1=1–“) , önemli bilgilere erişme olanağı bulmuştur.

Şimdi PDO ile bunun nasıl engellenebileceğine bakalım :

1
2
3
4
5
6
7
$p=new Pdo('mysql:dbname=testdb;host=127.0.0.1','kullanici','sifre');

$st=$p->prepare('select*from user where name=? and password=?');

$st->execute(array($_GET['u'],$_GET['p']));

echo '<pre>',print_r($st->fetchAll(),true);

Gördüğünüz gibi PDO ile hem daha anlaşılır, hem de daha kolay bir biçimde güvenli bir sorgulama yapabiliyoruz. Burada dikkat etmeniz gereken , PDO bizim yerimize verileri yerleştirirken (? işareti yerine bizim verdiğimiz veriler atanır), verdiğimiz parametrelerin sırasına göre yerleştirir .
Farklı yöntemlerde var ama şimdilik bu yazının konusu değil, sonrasında değinmeye çalışacağım.
PDO bu işlemi yaparken, kullanıcılar tarafından girilen verileri otomatik olarak etkisizleştirir. Böylece bizlere daha az yük düşer.

30 Mar

PDO (PHP Data Objects) nedir

“PHP Data Objects (PDO) eklentisi PHP içerisinde veritabanlarına erişim için küçük, kararlı bir arayüz tanımlar. PDO arayüzünü implemente eden herbir veritabanı sürücüsü kendi eklentilerindeki veritabanına has özelliklerini kullanılabilir hale getirirler. PDO eklentisinin kendisi ile herhangi bir veritabanı işlevi yerine getiremezsiniz. Veritabanına erişmek için veritabanına has PDO sürücüsünü kullanmalısınız.

PDO veri-erişim katman soyutlaması sunar, yani kullandığınız veritabanı ne olursa olsun sorgu ve veri çekmek için aynı fonksiyonları kullanırsınız. PDO veritabanı soyutlaması sağlamaz; SQL in yeniden yazılması değildir, veya eksik özelliklerin tamamlanması değildir.” ***(php.net)

Php kendi sayfasında tanımladığı biçimiyle ve benim bedbahd ingilizcemin yettiği kadarıyla çevirisi bu biçimde. Şimdi durumu sadeleştirmek gerekirse. PHP nin Nesne Yönelimli Programlamaya ağırlık verdiği 5 sürümü ile gelen PDO bir veri erişim katmanıdır, PDO interface ini implemente ederek oluşturulmuş sürücülerini kullanarak standart bir veri erişim modeli oluşturmaktadır. PDO da standard fonksiyonlar vardır: exec,query,fetch v.b. Bu fonsiyonlar sürücü desteği bulunan bütün veritabanları için aynıdır.
Örneğin MySql e sorgu yapmak için PDO->query() metodu kullanılacaksa firebird,PgSql veya Oracle (PDO interface ini implemente ederek oluşturulmuş birkaç sürücü daha mevcuttur: IBM,Informix,SqLite,Sybase,MicrosoftSQL,ODBC) içinde aynı metod kullanılacaktır. Bu da bize farklı veritabanları kullanmamız gerektiği zaman bunların PHP için olan eklentilerine dalıp farklı fonksiyonları içerisinde kayolmamızın önüne geçmekte. Tabi sağladığı yararlar bununla sınırlı değil, ileride kullandıkça örneklerimizdeki açıklamalarla sağladığı faydalar daha net anlaşılabilir.

PDO 5.1 sürümü ile kullanılmaya başlamıştır. PDO yu kullanabilmek için  php.ini dosyasındaki PDO yu etkinleştirmelisiniz bununla birlikte veritabanına has olan PDO sürücüsünü de etkinleştirmelisiniz. Yoğun biçimde MySql kullanıldığı için biz MySql eklentisini etkinleştireceğiz, bunun için php.ini ye şu satırları ekleyebilirsiniz
[PHP_PDO]
extension=php_pdo.dll
[PHP_MYSQL]
extension=php_mysql.dll

Bu adımdan sonra bir örnek ile PDO kullanımını açıklayalım:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
try {
/**
* PDO __construct ( string $dsn [, string $username [, string $password [, array $driver_options ]]] )
*
**/

$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
foreach ($dbh->query('SHOW DATABASES') as $row) {
print_r($row);
}
$dbh = null;
} catch (PDOException $e) {
print "Hata!: " . $e->getMessage() . "
"
;
die();
}
?>

Yukarıdaki örneği açıklayalım. PDO kurucusunda bulunan “dsn” parametresi PDO nun hangi veritabanı sürücüsünü kullanacağını belirlemesine yardımcı olan veriyi barındırır. Burada “mysql” yerine “mssql” veritabanına bağlanmak isteseydik “dsn” imiz şöyle olacaktı: ‘mssql:host=localhost;dbname=test’. Bu durumda PDO MsSql sürücüsünü arka planda yükleyecekti (tabi MsSql sürücüsünü öncelikle sizin aktif etmiş olmanız şartıyla).

Burada PHP de daha önce olmayan ve 5. versiyonu ile gelen “try catch” bloğundan bahsetmek gerekecek sanırım.  “try catch” bir hata yakalama ve oluşan hatayı göz ardı etme mekanizmasıdır diyebiliriz kabaca. İki bloktan oluşan bu yapı ile ulaşılmaya çalışılan sağlamlıktır. Uygulamada bir hata gerçekleştiğinde oracıkta sonlanmak yerine size bu hatayı yönetebilmenize olanak sağlar.

Örneğimizdeki “try catch” bloğuında PDO kurucusu sağlıklı çalıştığında ve veritabanı bağlantısını sağladığında “try” bloku çalışacak ve sorgu sonucu yazılacak ekrana. Bir hata meydana geldiğinde ise “catch” bloğu çalışacak ve meydana gelen hata ekrana yazılcaktır.

PDO ile ilgili örneklere ve PHP5 yeniliklerine ilerleyen zamanlarda değinilecektir. Bol güneşli bahar günleri dilerim…