도찐개찐

[PHP] PDO 사용법 본문

PHP

[PHP] PDO 사용법

도개진 2022. 6. 8. 14:38

■ 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;
?>

 

 

 

# 출력결과

 

출처 : https://wickedmagica.tistory.com/16

 

[PHP] PDO 사용법 정리

참고 : 바쁜 팀장님 대신 알려주는 신입 PHP 개발자 안내서 ■ PDO(PHP Data Objects) 란?  -. PDO(PHP Data Objects)는 여러 종류의 데이터베이스를 같은 방식으로 사용할 수 있게 해준다.  -. 그리고 PDOStat..

wickedmagica.tistory.com

 

728x90
Comments