1. PDO 소개


1) 문제점 : PHP에서 사용되는 데이터베이스 extension(oci, mysql, postgresql, mssql 등)간의 일관성이 심각하게 결여된 상태

2) 문제점의 결과 : 이러한 문제로 유지보수가 어렵고 핵심 PHP 개발자 인력이 극히 제한된 현실. 

3) 문제 해결 : 따라서 2003년 독일에서 열린 LinuxTag 컨퍼런스 행사에서 PHP 데이터베이스 extension 관리 담당자들이     한자리에 모여 PHP의 데이터베이스 액세스에 관련한 몇 가지 목표를 설정함

   – 명확하게 정의되고 사용이 편리한 lightweight API 제공(가벼운 API 제공)

   – 여러 RDMBS 라이버르러들이 공통적으로 제공하는 기능들을 통합, but 각 라이브러리가 제공하는 고급기능은 제외시키지 않음

   – 추상화/호환성에 관련된 무거운 기능들을 PHP 스크립트를 통해 옵션으로 제공

4) PDO : 이러한 개념을 PHP Data Objects(PDO)라 부르기로 함


 2. PDO가 필요한 이유


1) 성능 : 기존 database extension의 성공/실폐 사례를 활용. PDO의 모든 코드는 새롭게 작성되고 PHP5 환경을 기반으로    성능 개선 효과를 극대화

2) 기능 : PDO는 공통 데이터베이스 기능을 기반 환경으로 제공, but 각 RDBMS 제품의 독특한 기능을 편리하게 접근할 수 있는   환경 제공

3) 편의성 : API에 구애 받지 않고 독립적인 코드를 작성하는 한편 각 함수 호출의 역할을 명확하게 정의

4) 런타임 확장 지원 : PDO extension은 모듈러 형태로 구현되며, PHP 배포본을 다시 컴파일하거나 재설치하지 않고도 런타임  환경에서 데이타베이스 드라이버를 로드할 수 있다. 예를 들어, PDO_OCI extension은 PDO extension을 위한 오라클  데이타베이스 API를 구현가능. 그 밖에도 MySQL, PostgreSQL, ODBC, Firebird 등을 위한 드라이버가 현재 개발 중


PDO (PHP Data Objects) 는 여러가지 데이터베이스를 객체지향적으로 제어하는 방법을 표준화 시킨 것이다. PHP 5.5 버전부터는 mysql client library를 지원하지 않을 예정이며, PHP는 데이터베이스 접근을 위해 PDO를 사용하기를 권장하고 있다.


php7에서는 아직 mysqli와 PDO같이 제공하고 있으나 추후 mysql이나 mysqli 관련 데이터베이스 접속 관련 함수는 php에서 제외 될 예정이니 참고하기 바랍니다 , 현재 PDO 환경에서 정상적으로 운영이 가능한 프로그램으로는 XpressEngine, WordPress, GNUBoard(영카트).  Drupal  등이 있으나, 일부 기능(플러그인)은 정상 동작하지 않을 수 있으니 이또한 참고하여 이용해 보시기 바랍니다.


3.  PDO 기본 사용법


객체 생성 : try catch 문에서 생성합니다.


t ry{

    // MySQL PDO 객체 생성

    // mysql을 다른 DB로 변경하면 다른 DB도 사용 가능

    $pdo = new PDO("mysql:host=$host;dbname=$db", $user, $pass);

    // 에러 출력

    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

}

catch(Exception $e) {

    echo$e->getMessage();

}


커넥션 닫기 : $pdo = null;


에러 모드


// 에러 출력하지 않음

$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);

// Warning만 출력

$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);

// 에러 출력

$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

 

SQL 실행


$st = $pdo->prepare('INSERT INTO table (col1) VALUE (`val1`)');

$st->execute();

 

Placeholder : PDO는 SQL 인젝션을 방지하기 위해 prepare와 placeholder를 사용합니다.


// placeholder 없음. SQL 인젝션의 위험이 있음.

$st = $pdo->("INSERT INTO table (col1, col2, col3) values ($val1, $val2, $val3)");


// 이름 없는 placeholder. SQL 인젝션 방지.

$st = $pdo->('INSERT INTO table (col1, col2, col3) values (?, ?, ?)');


// 값을 넘겨주고 실행

$st->execute(['val1', 'val2', 'val2']);


// 이름 있는 placeholder. SQL 인젝션 방지

$st = $pdo->("INSERT INTO table (col1, col2, col3) value (:col1, :col2, :col3)");


// 값을 넘겨주고 실행

$st->execute([':col1'=>'val1', ':col2'=>'val2', ':col3'=>'val3']);

 

Fetch : Object, Class로 데이터를 가져오는 방법도 있지만

여기선 배열로 가져오는 방법만 소개하겠습니다.


// SELECT

$st = $pdo->('SELECT * FROM table');

$st->execute();


// Fetch 모드를 설정

$st->setFetchMode(PDO::FETCH_ASSOC);


// 1 row 씩 가져오기

while($row= $st->fetch()) {

    echo$row['col1'].'<br/>';

    echo$row['col2'].'<br/>';

    echo$row['col3'].'<br/>';

}

 

FetchAll  :  한번에 모든 row를 가져올 수 있습니다.


$st->setFetchMode(PDO::FETCH_ASSOC);

$fetch_all= $st->fetchAll();

print_r($fetch_all);


4. PDO 기본 심화


PDO 테스트를 위해 mysql에 test 테이블을 만들어 좀 더 배워보자.


CREATE TABLE test ( id INT UNSIGNED NOT NULL , name VARCHAR( 50 ), PRIMARY KEY (id))

 – mysql 데이터 삽입과 갱신 

prepare 를 통해 명령어를 준비한 뒤, 명령에 사용된 변수를 bindParam을 이용해 데이터를 연결한다. 이후 execute 실행하면 연결된 데이터의 값이 데이터베이스에 삽입된다.  이렇게 복잡하게 객체지향적으로 실행하는 이유는 php injection 해킹을 방지하기 위함이다. 


<?php

    try {

       $hostname=’localhost’;

         $dbname=’mysqldb’;

         $username=’username’;

         $password=’password’;

        $db=new PDO(‘mysql:host=localhost;dbname=testdb;charset=utf8′,’username’,’password’); 

        $stmt=$db->prepare(“INSERT INTO test (name) VALUES (:col2)”); 

        // 첫번째열은 auto_increment 이므로 삽입할 필요가 없다.

        $stmt->bindParam(‘:col2′,$data2);

        $data2=”Kelvin”;

        $stmt->execute();

        $db=null;  

    }

    catch(Exception $e) {

        echo $e->getMessage();

    }

?> 

 

다음은 데이터를 갱신하는 예제이다. col2는 문자열이지만 이전 mysql_query에서 사용되던 sql명령문과 달리 문자열을 ”로 감싸지 않아도 되고 변수를 연결해주기만 하면 되므로 injection이 불가능해진다. 


<?php

    try {

        $hostname=’localhost’;

        $dbname=’mysqldb’;

        $username=’username’;$password=’password’;

        $db=new PDO(‘mysql:host=localhost;dbname=testdb;charset=utf8′,’username’,’password’);

        $stmt=$db->prepare(“UPDATE test SET name=:col2 WHERE id=:col1“); 

        $stmt->bindParam(‘:col1’,$data1);   

        $stmt->bindParam(‘:col2’,$data2);        

        $data1=5;

        $data2=”Robin”;

        $stmt->execute();

        $db=null;  

    }

catch(Exception $e) {

      echo $e->getMessage();

}

?> 

 

테이블에 접속하기 위해 PDO 객체를 생성하고 개수를 출력하고 접속을 닫는다.


<?php

try {

$hostname=’localhost’;

$dbname=’mysqldb’;

$username=’username’;

$password=’password’;

$db=new PDO(“mysql:host=$hostname;dbname=$dbname;charset=utf8″,$username,$password);

$stmt=$db->prepare(“SELECT count(*) FROM test”);

$stmt->execute();

$result=$stmt->fetchAll(PDO::FETCH_ASSOC);

print_r($result); 

$db=null;        // 접속닫기

}

catch (PDOException $e) {

echo $e->getMessage();

}

?>

 


– fetch-style

PDO::FETCH_ASSOC – 배열 인덱스를 column name 으로

PDO::FETCH_BOTH (기본값) – 배열 인덱스를 column name과 0-indexed column number 둘다

PDO::FETCH_NUM – 배열 인덱스를 0-indexed column number 로

…등등


 데이터를 조회할 때 데이터 전부를 fetchAll 하는 방법과 각각의 데이터를 fetch 루프를 돌리는 방법이 있다. 이를 비교하면 별차이 없다고도 하고…메모리와 속도에서 차이가 난다고 하기도 하고… 아무튼 fetch 루프를 돌리는 방법이 더 자주 쓰이는 걸로 보인다.


<?php

try {

$db=new PDO(‘mysql:host=localhost;dbname=testdb;charset=utf8′,’username’,’password’);

$stmt=$db->prepare(“SELECT name FROM test”);

$stmt->execute();

while($row=$stmt->fetch()) {

echo $row[‘name’];

echo “<br>”;

}

$db=null;        // 접속닫기

}

catch (PDOException $e) {

echo $e->getMessage();

}

?>

    

– mysql query 결과를 PHP array에 집어넣기

조회한 결과를 php배열에 집어넣어야 할 때가 있다. 다음과 같이 루프를 돌리면 $new_array 배열에 내용이 저장된다.


while( $row=$stmt->fetch(PDO::FETCH_ASSOC) {

      $new_array[] = $row;

}

 

FETCH_ASSOC를 이용했으니, 아이템 키와 값이 새로운 배열에 저장되었을 것이다.

이를 사용하는 방법은 다음 예를 참조하자. id 열과 link 열을 참조한 경우이다. 

foreach( $new_array as $array) {

      echo $array[‘id’].”<br>”;        // row[‘id’] 는 $array[‘id’]로

      echo $array[‘link’].”<br>”;        // row[‘link’] 는 $array[‘link’]로