'pdo'에 해당되는 글 1건

  1. [PHP] PDO 사용법 정리 2018.03.27

[PHP] PDO 사용법 정리[PHP] PDO 사용법 정리

Posted at 2018. 3. 27. 09:26 | Posted in PHP




참고 : 바쁜 팀장님 대신 알려주는 신입 PHP 개발자 안내서





■ PDO(PHP Data Objects) 란?


 -. PDO(PHP Data Objects)는 여러 종류의 데이터베이스를 같은 방식으로 사용할 수 있게 해준다. 

 -. 그리고 PDOStatement와 데이터 바인딩을 통해 SQL 인젝션을 막아주고, 성능을 향상해준다.





■ PDO를 사용하면 좋은 점



 -. PDO(PHP Data Objects)는 같은 방법으로 여러 데이터베이스에 접근할 수 있게 해주는 PHP 확장 모듈입니다.

   (PHP는 데이터 베이스별로 확장 모듈을 가지고 있다.)

 -. PDO를 사용하면 MySQL, Oracle, MS SQL, PostgreSQL을 포함한 12개의 데이터 베이스를 같은 방식으로 다룰 수 있게 된다.



# 소스코드

<?php
    $dbHost = "localhost";      // 호스트 주소(localhost, 120.0.0.1)
    $dbName = "test_db";      // 데이타 베이스(DataBase) 이름
    $dbUser = "tester";          // DB 아이디
    $dbPass = "1q2w3e";        // DB 패스워드

    // PDO + MariaDB 연결하기
    $pdo = new PDO("mysql:host={$dbHost};dbname={$dbName}", $dbUser, $dbPass);
    $statement = $pdo -> query("SELECT CURDATE() AS date FROM DUAL");
    $row = $statement -> fetch(PDO::FETCH_ASSOC);
    echo htmlentities($row['date']);
?>


# 출력결과



 -. PDO를 사용하는 또 다른 이유는 준비 구문(Prepare Statements)을 활용할 수 있기 때문이다.

    준비 구문을 사용하면 SQL 인젝션 공격을 막을 수 있고, 애플리케이션의 성능이 향상된다.

 -. SQL 인젝션 취약점은 사용자 입력값과 함께 동적으로 쿼리를 만들 때 발생한다.


<?php
      $query = “UPATE tasks SET name = ‘{$name}’ WHERE id = ‘{$args[’id’]}’”;
?>


 -. 사용자가 입력한 $name과 $args[’id’]를 포함해서 동적으로 쿼리를 만들고 있다.

 -.  $name의 값에 해킹됐음’— 이 들어오면 ‘;—가 데이터가 이닌 SQL 코드로 인식되어 모든 데이터의 name 컬럼이 해킹됐음으로 변경된다.


<?php

$query = “UPATE tasks SET name = ‘해킹됐음’;—’ WHERE id = ‘{$args[’id’]}’”;

?>


 -. 준비 구문을 이용할 떄는 우선 SQL 코드를 정의하고 나중에 파라미터를 대입한다.


<?php

$stmt = $pdo -> prepare(”UPDATE tasks SET NAME = :name WHERE id = :id”);

$stmt = bindParam(”:name”, $name);

?> 


 -. 데이터베이스가 SQL 코드와 데이터를 명확히 구분할 수 있기 떄문에, 준비 구문을 쓰는 것만으로도 SQL인젝션 공격이 막힌다.

 -. 준비 구문을 만들고 값만 바꿔가며 여러 번 실행하는 경우 클라이언트와 서버 양쪽에서 쿼리 계획과 메타 정보를 캐시할 수 있게 되어

   애플리케이션 성능이 향상된다.





■ PDO 사용법




# 소스코드

<?php
    $dbHost = "localhost";      // 호스트 주소(localhost, 120.0.0.1)
    $dbName = "test_db";      // 데이타 베이스(DataBase) 이름
    $dbUser = "tester";          // DB 아이디
    $dbPass = "1q2w3e";        // DB 패스워드
    $dbChar = "utf8";            // 문자 인코딩

    // PDO 객체 생성 & DB 접속
    $dsn = "mysql:host={$dbHost};dbname={$dbName};charset={$dbChar}";
    $pdo = new PDO($dsn, $dbUser, $dbPass);

    // 쿼리를 담은 PDOStatement 객체 생성
    $stmt = $pdo -> prepare("SELECT * FROM girl_group WHERE name = :name");

    // PDOStatement 객체가 가진 쿼리의 파라메터에 변수 값을 바인드
    $stmt -> bindValue(":name", "나연");

    // PDOStatement 객체가 가진 쿼리를 실행
    $stmt -> execute();

    // PDOStatement 객체가 실행한 쿼리의 결과값 가져오기
    $row = $stmt -> fetch();

    echo "<pre>";
    print_r($row);
    echo "</pre>";
?>




# 출력결과





#01. 데이터베이스 연결


데이터베이스에 접속하기 위해서는 PDO 객체를 생성해야 한다. PDO 객체를 생성할 때는 데이터 소스 네임(DSN, Data Source Name)과

데이터 베이스 유저명 패스워드를 인자로 넘겨준다.


<?php

      $pdo = new PDO($dsn$dbUser$dbPass);

?>


일반적으로 DSN은 PDO 드라이버명:PDO 드라이버별 접속 문법의 형태로 구성된다.

각 PDO 드라이버별 접속 방법은 PDO 드라이버를 참고하면 된다.


<?php

      $dsn = "mysql:host={$dbHost};dbname={$dbName};charset={$dbChar}";

?>




#02. 쿼리 준비


쿼리 준비는 PDO::prepare 메소드를 이용한다.

PDO::prepare 메소드는 PDOStatement 객체를 반환한다.


<?php

      $pdoStatement = $pdo -> prepare("SELECT * FROM member WHERE name = :name OR email = :email");

?> 


① PDO::prepare로 준비하는 SQL구문은 파라미터를 가질 수 있다.
② 파라미터는 이름을 붙여주거나 물음표로 표시할 수 있다.
③ 이름을 붙인 파라미터는 위의 예제에서 보듯이 이름 앞에 를 붙여서 만든다.
④ 하나의 SQL 문장에 여러 파라미터가 있는 경우 모두 이름을 붙여주거나 모두 물음표로 표기해야 한다.
   (물음표보다는 이름을 붙인 파라미터가 내용을 이해하기 쉬우므로 될 수 있는대로 이름을 붙인 파라미터를 상용하는 것이 좋다.)


<?php

      $name = "이름";

      $email = "이메일";


      // 이름 붙인 파라미터를 사용할 때

      $pdoStatement = $pdo -> prepare("SELECT * FROM member WHERE name = :name OR email = :email");

      $pdoStatement = bindValue(":name", $name);

      $pdoStatement bindValue(":email", $email);


      // 물음표를 사용할때 파라미터가 많아지면 물음표(?)의 경우 순서를 파악하기 어려워 진다.

      $pdoStatement = $pdo -> prepare("SELECT * FROM member WHERE name = OR email = ?");

      $pdoStatement bindValue(1, $name);

      $pdoStatement bindValue(2, $email);

?>




#03. 쿼리 파라미터에 값 배정(데이터 바인딩)


쿼리 파라미터에 값을 대입할 때는 PDOStatement:bindValue, PDOStatement::bindParam 두 가지 메소드를 이용한다.

binValue 메소드는 값을 집접 대입하고, bindParam은 변수를 대입한다.



# 소스코드 - bindValue를 사용한 경우

<?php

    $name = "Kei";


    $stmt = $pdo -> prepare("SELECT * FROM girl_group WHERE name = :name");


    $stmt -> bindValue(":name", $name); // 변수에 바인딩 하기 위해 bindValue을 사용

    $name = "서지수"; // 쿼리를 실행하기전에 $name 변수의 값을 변경한다.

    $stmt -> execute(); // WHERE name = "Kei"으로 실행된다.

    $row$stmt -> fetch(); // 객체가 실행한 쿼리의 결과값 가져오기


    echo "<pre>";

    print_r($row);

    echo "</pre>";

?>




# 출력결과 - bindValue를 사용한 경우

binvValue는 값 작체를 대입한다. 그래서 위와같이 변수에 새로운 값을 넣어도 반영되지 않는다.



# 소스코드 - bindParam를 사용한 경우

<?php

    $name = "유지애";


    $stmt = $pdo -> prepare("SELECT * FROM girl_group WHERE name = :name");


    $stmt -> bindParam(":name", $name); // 변수에 바인딩 하기 위해 bindParam을 사용

    $name = "정예인"; // 쿼리를 실행하기전에 $name 변수의 값을 변경한다.

    $stmt -> execute(); // WHERE name = "정예인"으로 실행된다.

    $row$stmt -> fetch(); // 객체가 실행한 쿼리의 결과값 가져오기


    echo "<pre>";

    print_r($row);

    echo "</pre>";

?>




# 출력결과 - bindParam를 사용한 경우

※ bindParam은 변수를 대입한것이기 때문에 대입한 이후에 값을 변경할 수 있다.




#04. 쿼리 실행


PDOStament 객체에 준비된 쿼리를 실행할 때는 PDOStatement::execute() 메소드를 사용한다.


<?php

    $pdoStatement = $pdo -> prepare("SELECT * FROM member WHERE name = :name OR email = :email");

    $pdoStatement -> bindValue(":name", $name);

    $pdoStatement -> bindValue(":email", $email);

    $pdoStatement -> execute();

?>


데이터 바인딩을 하지 않고, PDOStatment::execute() 메소드의 인수로 쿼리 파라미터에 사용할 값을 넘겨줄 수 있다.


<?php

    $pdoStatement = $pdo -> prepare("SELECT * FROM member WHERE name = ? OR email = ?");

    $pdoStatement -> execute([

    ":name" => $name

          , ":email" => $email

    ]);

?>


이렇게 쓸 경우에는 모든 데이터의 타입이 PDO::PARAM_STR로 처리된다.

데이터 타입을 지정하고 싶다면 PDOStatement::bindValue()나 PODStatement::bindParam()을 이용하면된다.


PDOStatement::execute() 메소드는 쿼리 실행이 성공했는지만 되돌려준다.

쿼리 실행 결과를 되돌려주지않는다는 점에 주의해야 한다.


추출한 데이터나 쿼리에 영향받은 행의 개수는 별도의 메소드를 이용해 조회해야 한다.




#05. 결과값 조회 - 데이터 가져오기



① PDOStatement:fetch()


쿼리 결과를 가져올 때는 PDOStatement:fetch() 메소드를 사용한다.

PDOStatement::fetch() 메소드를 한번 실행하면 쿼리 결과에서 한 행을 가져온다.

그래서 다음과 같이 반복문으로 모든 행을 가져와서 처리하는 경우가 많다.


# 소스코드

<?

    $dbHost = "localhost";
    $dbName = "test_db";
    $dbUser = "tester";
    $dbPass = "1q2w3e";
    $dbChar = "utf8";


    $dsn = "mysql:host={$dbHost};dbname={$dbName};charset={$dbChar}";
    $pdo = new PDO($dsn$dbUser$dbPass);


    $group = "REDVELVET";


    $stmt$pdo -> prepare("SELECT * FROM girl_group WHERE group_name = :group");

    $stmt -> bindValue(":group", $group);

    $stmt -> execute();


    $result = array();

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

$result[] = $row;

    }


    echo "<pre>";

    print_r($result);

    echo "</pre>";

?>




# 출력결과




② PDOStatement:fetchAll()


한 번에 모든 행을 가져오고자 할 때는 PDOStatement::fetchAll() 메소드를 사용한다.


<?

    $dbHost = "localhost";
    $dbName = "test_db";
    $dbUser = "tester";
    $dbPass = "1q2w3e";
    $dbChar = "utf8";


    $dsn = "mysql:host={$dbHost};dbname={$dbName};charset={$dbChar}";
    $pdo = new PDO($dsn$dbUser$dbPass);


    $group = "REDVELVET";


    $stmt = $pdo -> prepare("SELECT * FROM girl_group WHERE group_name = :group");

    $stmt -> bindValue(":group", $group);

    $stmt -> execute();


    $result = $stmt -> fetchAll();


    echo "<pre>";

    print_r($result);

    echo "</pre>";

?>





PDOStatement::fetchAll()을 사용할 때 데어티베이스에서 조회한 값이 많으면 메모리 부족으로 웹 서버가 다운될 수 있다.

조회 결과가 적다는 확신이 있는 때에만 신중하게 사용해야 한다.




#06. 결과값 조회 - 모드 지정



결과를 가져오는 모드는 PDO::FETCH_로 시작하는 혜약 상수를 PDOStatement::fetch(), PDOStatment::fetchAll() 메소드의 인수로 넘겨주어 지정한다.

자주 사용하는 예약 상수는 아래와 같다.



① PDO::FETCH_BOTH


 -. PDOStatement::fetch(), PODStatement::fetchAll() 메소드에 가져오기 모드를 지정해주지 않으면 PDO:FETCH_BOTH 모드로 결과를 가져온다.

 -. PDO::FETCH_BOTH는 결과값을 가져올 때 데이터베이스의 칼럼 이름을 키로 사용하는 배열과 칼럼의 순서를 키로 사용하는 배열, 둘 다 만드는 방식이다.

 -. 두가지 배열을 만들기 때문에 당연히 성능은 좋지 않다.

 -. 될 수 있는대로 사용하고자 하는 모드를 지정해서 사용하는것이 좋다.



② PDO::FETCH_ASSOC


 -. 컬럼명을 키로 사용하는 연관 배열을 반환한다.

 -. 가져온 데이터는 $row['id']와 같은 식드로 사용한다.



# 소스코드

<?php

        $dbHost = "localhost";
        $dbName = "test_db";
        $dbUser = "tester";
        $dbPass = "1q2w3e";
        $dbChar = "utf8";

        $dsn = "mysql:host={$dbHost};dbname={$dbName};charset={$dbChar}";
        $pdo = new PDO($dsn$dbUser$dbPass);

        $stmt = $pdo -> prepare("SELECT * FROM girl_group WHERE name = :name");
        $stmt -> bindValue(":name", "사나");
        $stmt -> execute();


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

echo "그룹&nbsp;:&nbsp;".$row['group_name'];

echo "<br/>";

echo "이름&nbsp;:&nbsp;".$row['name'];

echo "<br/>";

echo "포지션&nbsp;:&nbsp;".$row['position'];

echo "<br/>";

echo "회사&nbsp;:&nbsp;".$row['company'];

?>




# 출력결과




PDO::FETCH_NUM


 -. 컬럼의 순서를 키로 사용하는 배여을 반환한다.

 -. 가져온 데이터는 $row[0] 과 같은 식으로 사용한다.



 PDO::FETCH_OBJ


 -. 객체로 반환한다.

 -. 반환된 객체는 데이터베이스 컬럼명에 해당하는 프로퍼티를 갖고 있다.

 -. 가져온 데이터는 $row - > id와 같이 사용할 수 있다.



 PDO::FETCH_CLASS


 -. 지정한 클래스의 객체로 반환한다.

 -. PDO::FETCH_OBJ와 마찬가지로 컬럼명에 해당하는 프로퍼티에 값을 가진다.



# 소스코드 - 클래스

<?php

class iDol {

private $idx;

private $name;

private $position;

private $group;

private $company;

private $birthDay;


public function getIdx() {

return $this -> idx;

}


public function getName() {

return $this -> name;

}


public function getPosition() {

return $this -> position;

}


public function getGroup() {

return $this -> group_name;

}


public function getCompany() {

return $this -> company;

}


public function getBirthDay() {

return $this -> birthDay;

}

}

?>




# 소스코드 - PDO::FETCH_CLASS를 사용한 출력

<?php

        $dbHost = "localhost";

        $dbName = "test_db";
        $dbUser = "tester";
        $dbPass = "1q2w3e";
        $dbChar = "utf8";

        $dsn = "mysql:host={$dbHost};dbname={$dbName};charset={$dbChar}";
        $pdo = new PDO($dsn$dbUser$dbPass);

        $stmt = $pdo -> prepare("SELECT * FROM girl_group WHERE name = :name");
        $stmt -> bindValue(":name", "다현");
        $stmt -> execute();

    

$stmt -> setFetchMode(PDO::FETCH_CLASS, "iDol");

$row = $stmt -> fetch();


echo $row -> getGroup();

echo "<br/>";

echo $row -> getName();

echo "<br/>";

echo $row -> getPosition();

echo "<br/>";

echo $row -> getCompany();

?>




# 출력결과




⑥ PDOStatement::fetchColumn() 


 -. PDOStatement::fetchColumn()은 결과값 중 하나의 컬럼값만 가져오는 메소드 이다.

 -. 데이터 수를 조회할 경우 처럼 단 하나의 컬럼값만 필요한 경우 유용하게 사용할 수 있다.



# 소스코드

<?php

        $dbHost = "localhost";

        $dbName = "test_db";
        $dbUser = "tester";
        $dbPass = "1q2w3e";
        $dbChar = "utf8";

        $dsn = "mysql:host={$dbHost};dbname={$dbName};charset={$dbChar}";
        $pdo = new PDO($dsn$dbUser$dbPass);


        $stmt = $pdo -> prepare("SELECT COUNT(*) AS count FROM girl_group WHERE group_name = :group");

        $stmt -> bindValue(":group", "TWICE");

        $stmt -> execute();


        $row = $stmt -> fetchColumn();


echo "트와이스&nbsp;인원&nbsp;:&nbsp;".$row;

?>



# 출력결과




⑦ PDO:lastInsertId()


  -. 데이터베이스에 새로운 데이터를 입력하고 id 혹은 index값을 바로 사용해야 하는경우가 있다.

  -. PDO::lastInsertId()를 객체를 이용하면 마지막으로 입력한 데이터의 id 혹은 index 값을 확인 할 수 있다.

  ※ PDOStatement가 아닌 PDO 객체를 사용하는것에 주의




# 소스코드

<?php

        $dbHost = "localhost";

        $dbName = "test_db";
        $dbUser = "tester";
        $dbPass = "1q2w3e";
        $dbChar = "utf8";


        $dsn = "mysql:host={$dbHost};dbname={$dbName};charset={$dbChar}";
        $pdo = new PDO($dsn$dbUser$dbPass);


        $stmt = $pdo -> prepare("

              INSERT INTO girl_group (name, position, group_name, company, birthday)

              VALUE (:name, :position, :group, :company:birthday)

        ");


$stmt -> bindValue(":name", "정채연");

$stmt -> bindValue(":position", "센터, 서브보컬");

        $stmt -> bindValue(":group", "DIA");

$stmt -> bindValue(":company", "MBK엔터테인먼트");

$stmt -> bindValue(":birthday", "1997-12-01 00:00:00");

        $stmt -> execute();


        $taskIdx$pdo -> lastInsertId();


echo "정채연&nbsp;등록번호&nbsp;:&nbsp;".$taskIdx;

?>




# 출력결과






☞ 관련 포스팅 : [PHP] PDO + SimpleSql 라이브러리를 이용한 쿼리사용




Name __

Password __

Link (Your Website)

Comment

SECRET | 비밀글로 남기기