정상우
hELLO.
정상우
전체 방문자
384,472
오늘
91
어제
1,174
  • hELLO. (121)
    • 컴퓨터과학 (4)
      • 알고리즘 & 자료구조 (4)
    • 언어 & 프레임워크 (63)
      • Go (23)
      • PHP & Laravel (40)
    • 웹 (7)
    • 블록체인 (12)
      • 메인넷 (9)
      • 암호화폐 플랫폼 (3)
    • 포트폴리오 (10)
    • 칼럼 (20)
      • 에세이 (4)
      • 개발자스럽게 살기 (14)
      • 회고 (2)
    • 티스토리 (5)

블로그 메뉴

  • ⚡ 개발자 이력서
  • 🌟 깃허브
  • 💻 강의
  • ✨ 예제코드
  • ⭐ 브런치
  • 태그 클라우드
  • 방명록

공지사항

  • 2차 도메인을 설정했습니다 ✨

인기 글

  • JWT(JSON Web Token)의 개념부⋯
    2021.07.29
    JWT(JSON Web Token)의 개념부⋯
  • 'REST' 를 보다 'RESTful' 하게⋯
    2021.08.14
    'REST' 를 보다 'RESTful' 하게⋯
  • [Laravel] 라라벨 프레임워크⋯
    2021.06.10
    [Laravel] 라라벨 프레임워크⋯
  • 깃허브를 포트폴리오로 쓰려면⋯
    2021.12.25
    깃허브를 포트폴리오로 쓰려면⋯
  • 암호화폐 트레이딩 봇을 만들었⋯
    2021.05.12
    암호화폐 트레이딩 봇을 만들었⋯

태그

  • 라라벨
  • go
  • 포트폴리오
  • 개발 리뷰
  • 개발
  • php
  • 블록체인
  • 프로그래머스
  • Algorithm
  • 코딩테스트

최근 댓글

  • 고맙습니다 ~^^
    정상우
  • 오늘 블로그 만들었는데 검색하⋯
    엥뿌삐
  • 좋은 스킨 정말 감사드립니다.⋯
    이태홍
  • 고맙습니다 ㅎㅎ
    정상우
  • 제가 원하던 최고의 스킨입니다⋯
    _HEON

최근 글

  • 빠르게 성장하는 개발자의 세⋯
    2022.06.08
    빠르게 성장하는 개발자의 세⋯
  • 개발자와 엔지니어, 그 사이에서
    2022.05.10
    개발자와 엔지니어, 그 사이에서
  • 아임포트(Iamport)로 결제기능⋯
    2022.04.03
    아임포트(Iamport)로 결제기능⋯
  • 아임포트(Iamport)로 결제기능⋯
    2022.04.01
    아임포트(Iamport)로 결제기능⋯
  • [Laravel] 카페24 호스팅에 라⋯
    2022.03.29
    [Laravel] 카페24 호스팅에 라⋯

티스토리

hELLO · Designed By 정상우.
정상우

hELLO.

언어 & 프레임워크/PHP & Laravel

PHP: 데이터베이스 (MySQLi, PDO)

2020. 6. 10. 18:11

데이터베이스

데이터베이스를 사용하는 일은 웹 어플리케이션을 작성한다면 대부분 있는 일이기에 이 부분을 빼놓을 수는 없다. PHP도 물론 오라클이나 MS-SQL 같은 다양한 데이터베이스에 연결할 수 있으나, 가장 많이 사용하는 것이 아무래도 MySQL 이기에 이부분을 중점으로 이야기하고자 한다. 또한 데이터베이스 관련 함수는 실무에서도 조차 올바르지 못한 방법으로 사용되어 해킹에 노출되고 있기 때문에 바르게 익혀둘 필요가 있다.

MySQLi

레거시 프로젝트에는 mysql_ 로 시작하는 비교적 오래된 함수가 사용된 것을 볼 수 있는데, 이는 문제가 있어 mysqli_ 로 대체할 것을 권장하고 있다. mysqli 조차도 요즘에 쓸만한 함수도 아니고, API 수준에서 바라보자면 상당히 로우한 수준이기에 그다지 현업에서 사용할 것을 권장하지는 않는다. PDO(PHP Data Object)를 놔두고 mysqli 를 굳이 사용할 이유는 없다.

 

참고로 mysqli 는 객체지향과 함수를 둘다 제공하지만, 객체지향을 사용하고자 한다면 차라리 PDO를 쓰도록 하자. 

mysqli 를 사용하기 위해서는 php mysqli extension 이 활성화 되어 있어야 한다.

mysqli_connect([string, [string, [string, [string [...]]]]): mysqli

이 함수는 단순히 MySQL 에 연결해주고 관련 리소스를 리턴해준다. 참고로 이는 함수형으로 사용할 때 사용해야 하므로 잘 보관해두어야 한다.

mysqli_connect — Alias of mysqli::__construct()
string $host 데이터베이스 호스트 (localhost, 127.0.0.1 .etc)
string $username 데이터베이스 유저
string $passwd 데이터베이스 패스워드
string $dbname 데이터베이스 이름
// new mysqli(...)
$mysqli = mysqli_connect('__HOST_NAME__', '__USER_NAME__', '__PASSWORD__', '__DATABASE__');

// ...

mysqli_close($mysqli);

mysqli_query(mysqli, string, [, int]): mixed

이 함수는 쿼리를 날려주긴 하지만, 조심해서 사용해야 한다. 안전하지 않은 쿼리를 날릴 경우에는 SQL Injection 공격의 맛있는 먹잇감이 될 수 있으므로 주의해야 한다. 이에 대해서는 아래에서 언급하겠지만, 늘 강조한다. 절대 검증되지 않은 변수는 쿼리에 대입해서는 안 된다. 사용자는 어떤 값을 넣을지 알 수 없다.

mysqli::query -- mysqli_query — Performs a query on the database
mysqli $link mysqli 커넥션 객체
string $query SQL 쿼리 스트링
mysqli_query($mysqli, 'SELECT 1');

SELECT

다만 결과값에 대해서는 SELECT, SHOW, DESCRIBE 와 같은 경우에는 mysqli_result 객체를, 그렇지 않다면 bool 을 반환해준다고 적혀있으니 이는 참고해서 사용할 수 있다.

if ($result = mysqli_query($mysqli, 'SELECT * FROM posts LIMIT 10')) {
    while ($row = mysqli_fetch_object($result)) {
        var_dump($row);
    }
    mysqli_free_result($result);
}

mysqli_prepare(mysqli, string): mysqli_stmt

Prepare Statement 는 보안에 있어 매우 중요하다. 사용법은 mysqli_query() 와 비슷하다곤 하지만, 이것을 사용하게 되면 SQL Injection 에 대한 대처가 가능해진다. 허나 일부 레거시 프로젝트에서는 아직도 mysqli_query() 에다가 변수를 대입해서 사용하고 있기때문에 보안에 있어서 큰 문제가 되고 있다.

mysqli::prepare -- mysqli_prepare — Prepare an SQL statement for execution

mysqli_stmt

mysqli_prepare() 를 실행하고 나면 리턴되는 객체다. 이것을 따로 언급하는 이유는 바로 값 바인딩을 해야하기 때문이다. mysqli_stmt_bind_param() 을 사용하여 변수에 있는 값을 쿼리에 바인딩 해줄 수 있다.

$stmt = mysqli_prepare($mysqli, 'SELECT * FROM posts WHERE id = ?');

$id = 12;
mysqli_stmt_bind_param($stmt, 'i', $id);

if (mysqli_stmt_execute($stmt)) {
    $result = mysqli_stmt_get_result($stmt);
    // ...
    
    mysqli_stmt_close($stmt);
}

관련 함수들에 대해서는 자세히 언급하지는 않겠지만, mysqli_stmt_execute() 는 쿼리를 실행해주고, mysqli_stmt_get_result() 는 mysqli_result 를 얻어온다.

mysqli_stmt_fetch() 함수가 있으나 이는 직접 변수를 mysqli_stmt_bind_result() 로 바인딩 시켜주어야 하는 번거로움이 있다.

TRANSACTION

트랜잭션의 경우는 자세한 것은 생략하겠으나, mysqli_begin_transaction() 으로 트랜잭션을 시작한 다음 mysqli_commit() 또는 mysqli_rollback() 으로 처리할 수 있다. mysqli_autocommit() 을 사용하면 자동 커밋을 해제할 수 있다.

// mysqli_autocommit($mysqli, false);
mysqli_begin_transaction($mysqli, MYSQLI_TRANS_START_READ_ONLY);

// ...

// mysqli_commit($mysqli);
mysqli_rollback($mysqli);

PDO(PHP Data Object)

PDO(PHP Data Object)는 모던 PHP를 사용하고자 한다면 사용해야한다. 이는 데이터베이스를 보다 기능적으로 인터페이스화 시켜서 데이터베이스의 종류가 어떻든 공통 인터페이스의 형태로 쿼리를 전송하고 소통할 수 있기 때문에 로우한 API라 볼 수 없다. 따라서 함수의 이름이나 특정 데이터베이스만이 가지는 특별한 함수에 대해 결합도가 떨어지게 된다. 

 

게다가 mysqli 같은 경우는 비슷한 이름의 함수들, mysqli_query(), mysqli_real_query() 등 사용법이 헷갈리는 반면 PDO는 조금 더 간결하기 때문에 사용하기 좋을 것이다.

PDO 또한 php pdo extension 이 활성화 되어 있어야하며, 사용할 수 있는 드라이버가 여러 개이기 때문에 사용하고자 하는 데이터베이스를 확인하여야 한다.

PDO::__construct([string [, string [, string [, array]]]])

PDO 객체를 생성한다. 생성한 객체는 어플리케이션에서 발생하는 데이터베이스 처리를 위한 핸들이 될 것이다. 

string $dsn DSN(Data Source Name; mysql:dbname=myapp_test;host=127.0.0.1; .etc)
string $username 유저 이름
string $passwd 유저 패스워드
$pdo = new PDO('__DSN__', '__USERNAME__', '__PASSWORD__');

PDO::query(string): PDOStatement

mysqli_query() 처럼 쿼리를 던져준다. 이 메서드를 사용할 때는 준비된 쿼리를 사용해야 한다. 즉, 안전하지 않은 쿼리를 사용하면 안 된다는 이야기.

string $statement 준비된 쿼리
$pdo->query('SELECT 1');

SELECT

SELECT 와 같은 결과값은 mysqli 와 비슷한 코드로 긁어오면 된다. $sth->fetch_* 를 사용하면 된다.

while ($row = $sth->fetchObject()) {
    var_dump($row);
}

PDO::prepare(string): PDOStatement

mysqli_prepare() 와 비슷하다. 준비된 쿼리를 사용할 수 있고, ? 이외에도 또 다른 치환자를 사용할 수도 있다.

$sth = $pdo->prepare('SELECT * FROM posts WHERE id = :id');

if ($sth->execute([ ':id' => 12 ])) {
    // ...
}

PDO::bindParam(mixed, mixed [, int]): bool

mysqli_stmt_bind_param() 이라고 생각할 수 있는데, 위에서는 execute() 메서드에 바인딩을 하였다. 둘의 차이는 execute() 의 경우 PDO::PARAM_STR, 즉 문자열로 바인딩해주는 반면, 직접 바인딩을 시켜주게되면 다른 데이터 타입으로도 바인딩 할 수 있다.

$id = 12;
$sth->bindParam(':id', $id, PDO::PARAM_INT);

if ($sth->execute()) {
    // ...
}

TRANSACTION

트랜잭션 처리는 beginTransaction() 메서드와 commit() 또는 rollback() 메서드로 처리해줄 수 있다.

$pdo->beginTransaction();

if ($pdo->inTransaction()) {
    $pdo->exec('DELETE FROM posts WHERE id = 12');
    $pdo->rollback();
}
여기서 exec() 메서드를 사용했는데, 둘은 리턴값이 다르다. query() 메서드는 PDOStatement 를, exec() 는 int(affected rows) 를 반환한다.

더 읽을거리

https://www.inflearn.com/course/php7-reboot

https://www.inflearn.com/course/php7-oop

PHP 카테고리 목차 및 문서 정리

2020년, PHP 언어가 가지는 의미

https://www.php.net/manual/en/

    '언어 & 프레임워크/PHP & Laravel' 카테고리의 다른 글
    • PHP: MVC(Model, View, Controller)
    • PHP: 파일 업로드와 다운로드
    • PHP: 쿠키와 세션
    • PHP: HTML 폼 (GET, POST)
    mysqli, PDO, php, 데이터베이스, 보안
    정상우
    정상우
    과거의 배움으로 현재를 바꾸고 미래를 만듭니다. #25+2살 #INFJ #개발자 #브런치작가
    댓글쓰기
    다음 글
    PHP: 파일 업로드와 다운로드
    이전 글
    PHP: 쿠키와 세션
    • 이전
    • 1
    • ···
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • ···
    • 121
    • 다음

    티스토리툴바