PDO(PHP Data Object) 는 이기종 데이터베이스에 접근하는 공통 API를 제공하는 것을 목적으로 만들어 졌습니다. mysqli 는 객체 스타일과, 절차적 스타일의 API를 제공하는데 비해 PDO 는 객체 스타일의 API 만을 제공합니다. PDO 는 예전에 사용하던 mysql API 와는 달리 Prepared Statement 를 제공하므로 SQL Injection 방어에 사용될 수 있습니다.
Preapred Statement 는 원래 SQL 을 미리 데이터베이스에서 컴파일해 두고, 파라미터 값만 바꿔서 처리해서 쿼리의 성능을 올리는데 사용되었지만, 요즘은 SQL Injection 방어용으로 더욱 많이 예기 되어지는것 같습니다. 그만큼 요즘은 보안이 큰 이슈로 등장 하였습니다.
PDO를 사용하기 위해서는 PHP 5.1.0 이상의 버전을 사용해야 합니다.
PHP 데이터베이스 API 를 사용하다 보면 어떤 한 작업을 하는데 즉, 동일한 기능을 구현하는데 사용할 수 있는 방법이 여러가지가 있는 경우가 많습니다.
데이터베이스에 연결하는데 사용하는 정보를 제공하는 방법이라든가, 스테이트먼트에 파라미터를 제공하는 방법 등 각각 사용하는 적절한 상황이 있어서 많은 방식이 존재할거라고 생각하지만 너무 복잡하고, 매뉴얼 찾아보기도 힘들어지는 경향이 있는 것 같습니다.
물론 이건 어디까지나 개인적인 생각입니다.
1. 데이터베이스에 연결하기
<?php
$dsn = "mysql:host=localhost;port=3306;dbname=testdb;charset=utf8";
try {
$db = new PDO($dsn, "testuser", "testuser");
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo "데이터베이스 연결 성공!!<br/>";
} catch(PDOException $e) {
echo $e->getMessage();
}
?>
데이터베이스에 연결하기 위해서 PDO 객체의 생성자에 DSN(Data Source Name), 아이디, 비밀번호를 인자로 입력합니다. DSN의 port 는 기본값 3306 이 경우 생략해도 됩니다. 데이터베이스 연결 객체를 생성한 후에 setAttribute 메소드를 사용해서 두 가지 속성을 지정하고 있습니다.
- PDO::ATTR_EMULATE_PREPARES: 이 속성은 Preppared Statement 를 데이터베이스가 지원 하지 않을 경우 에뮬레이션 하는 기능으로 false 를 지정해서 데이터베이스의 기능을 사용하도록 합니다.
- PDO::ATTR_ERRMODE : 이 속성은 PDO 객체가 에러를 처리하는 방식을 결정합니다.
PDO::ERRMODE_EXCEPTION 은 에러가 발행했을때 PDOException 을 throw 하도록합니다. 이 경우 try {} catch{} 를 사용하여 에러를 처리하면 됩니다. 다른 방법으로는 PDO::ERRMODE_SILENT(에러 코드만 설정), PDO::ERRMODE_WARNING(E_WARNING 발생)이 있습니다.
2. 조회하기
<?php
$dsn = "mysql:host=localhost;port=3306;dbname=testdb;charset=utf8";
try {
$db = new PDO($dsn, "testuser", "testuser");
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$keyword = "%테스트%";
$no = 1;
$query = "SELECT num, name FROM tb_test WHERE name LIKE ? AND num > ?";
$stmt = $db->prepare($query);
$stmt->execute(array($keyword, $no));
$result = $stmt->fetchAll(PDO::FETCH_NUM);
for($i = 0; $i < count($result); $i++) {
printf ("%s : %s <br />", $result[$i][0], $result[$i][1]);
}
} catch(PDOException $e) {
echo $e->getMessage();
}
?>
- 쿼리에 값을 바꿔 넣을 곳에 ? (placeholder)를 사용합니다.
- $stmt = $db->prepare($query); : 스테이트먼트를 생성합니다.
- $stmt->execute(array($keyword, $no)); : 배열로 값을 입력합니다.
- $result = $stmt->fetchAll(PDO::FETCH_NUM); : 결과를 가져옵니다.
PDO::FETCH_NUM : 숫자 인덱스 배열 반환
PDO::FETCH_ASSOC : 컬럼명이 키인 연관배열 반환
PDO::FETCH_BOTH : 위 두가지 모두
PDO::FETCH_OBJ : 컬럼명이 프로퍼티인 인명 객체 반환
파라미터가 없는 쿼리의 경우, 파라미터 배열 없이 호출하면 됩니다.
<?php
$query = "SELECT num, name FROM tb_test";
$stmt = $db->prepare($query); $stmt->execute();
?>
Prepared Statement를 사용하는 또 다른 방법이 있습니다. statement 의 bindParam 또는 bindValue 메소드를 사용하는 방법 입니다. 두 가지 메소드를 서로 대체할 수 있습니다.
- Place Holder에 ?를 사용하고 값을 지정하는 메소드에는 숫자 인덱스를 사용해서 값을 바인딩할 수 있습니다.
<?php
$keyword = "%테스트%";
$no = 1;
$query = "SELECT num, name FROM tb_test WHERE name LIKE ? AND num > ?";
$stmt = $db->prepare($query);
$stmt->bindParam(1, $keyword, PDO::PARAM_STR);
$stmt->bindParam(2, $no, PDO::PARAM_INT);
//$stmt->bindValue(1, $keyword, PDO::PARAM_STR);
//$stmt->bindValue(2, $no, PDO::PARAM_INT);
$stmt->execute();
?>
- Place Holder에 이름을 지정해서 그 이름에 따라 값을 지정할 수 있습니다.
<?php
$keyword = "%테스트%";
$no = 1;
$query = "SELECT num, name FROM tb_test WHERE name LIKE :name AND num > :num";
$stmt = $db->prepare($query);
$stmt->bindParam(':name', $keyword, PDO::PARAM_STR);
$stmt->bindParam(':num', $no, PDO::PARAM_INT);
//$stmt->bindValue(':name', $keyword, PDO::PARAM_STR);
//$stmt->bindValue(':num', $no, PDO::PARAM_INT);
$stmt->execute();
?>
- 결과 값을 fetch 하는 다른 방법 입니다.
<?php
while ($row = $stmt->fetch(PDO::FETCH_NUM, PDO::FETCH_ORI_NEXT)) {
printf ("%s : %s <br />", $row[0], $row[1]);
}
?>
3. 입력, 수정, 삭제 및 트랜잭션 처리
<?php
$dsn = "mysql:host=localhost;port=3306;dbname=testdb;charset=utf8";
try {
$db = new PDO($dsn, "testuser", "testuser");
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$name = "테스트";
$query = "INSERT INTO tb_test (name) VALUES (?)";
$stmt = $db->prepare($query);
try {
$db->beginTransaction();
$stmt->execute(array($name));
$db->commit();
$id = $db->lastInsertId();
} catch(PDOException $e) {
$db->rollback();
echo $e->getMessage();
}
} catch(PDOException $e) {
echo $e->getMessage();
}
?>
'프로그래밍 > PHP' 카테고리의 다른 글
PHP 7.1 실행시 VCRUNTIME140.dll 오류 문제 해결하기 (2) | 2018.04.02 |
---|---|
PHP 7 에서 Oracle 연결하기 (5) | 2018.04.02 |
PDT, Eclipse 플러그인 설치 (2) | 2018.04.01 |
Windows용 XAMPP 설치하기 - (Apache, PHP, MariaDB) (0) | 2018.04.01 |
MySQL 데이터베이스에서 mysqli(MySQL Improved) 사용법 (0) | 2018.04.01 |