Preparedstatement

프리페어드 스테이트먼트(prepared statement), 파라미터라이즈드 스테이트먼트(parameterized statement)는 데이터베이스 관리 시스템(DBMS)에서 동일하거나 비슷한 데이터베이스 문을 높은 효율성으로 반복적으로 실행하기 위해 사용되는 기능이다. 일반적으로 쿼리나 업데이트와 같은 SQL 문과 함께 사용되는 프리페어드 스테이트먼트는 템플릿의 형태를 취하며, 그 템플릿 안으로 특정한 상수값이 매 실행 때마다 대체된다. -위키백과-


Preparedstatement는 보안적 측면에서 SQL Injection을 예방할 수 있는 방법이다. SQL문을 미리 변환하기 때문에 문자 ', " <, > (, ) 와같은 SQL에 사용되는 특수문자들이 SQL 구문이 아닌 문자열로 인식 할 수 있게 해준다.

 

로그인과 게시판 조회에 Preparedstatement를 적용해보자.

login_function.php

<?php
    require_once 'db_connection.php';
   
   ...

    //로그인로직
    function login($id, $pw) {
        global $db_conn;
        $pw = hash("sha256", $pw);
		
        // 바인딩 SQL 구문에 ?를 넣는다.
        $stmtSQL =$db_conn ->prepare("SELECT COUNT(USER_ID) as count 
        FROM user WHERE USER_ID = ? and PW = ?");
        
        // 바인딩할 값을 지정 한다, integer일 경우 i, 문자열의 경우 s 
        // 아래의 예시는 아이디와 비밀번호 모두 문자열이기때문에 첫 인자를 ss로 넣어준다.
        // pw가 integer라면 "si"가 된다.
        $stmtSQL->bind_param("ss", $id, $pw);
        $stmtSQL->execute();
        $result = $stmtSQL->get_result(); 

        $row = mysqli_fetch_array($result);
        var_dump($row);
        
        return $row['count'];
    }
...
?>

 

 

위의 쿼리는 select로 결과값을 가져올 수 있지만 insert, update등은 결과 값이 없기에 성공여부를 가져오기위해 아래와 같은 방법으로 확인한다.

 function register($id, $name, $pw) {
        global $db_conn;
        
        $pw = hash("sha256", $pw);
        // echo "pw : {$pw}";

        $sql = "INSERT INTO user (USER_ID, USER_NM, PW) VALUE(
            '{$id}'
            , '{$name}'
            , '{$pw}'
        )";
        $stmtSQL =$db_conn -> prepare("INSERT INTO user (USER_ID, USER_NM, PW) 
        VALUE( ?, ?, ?)
        ");
        $stmtSQL->bind_param("sss", $id, $name ,$pw);
        
        // excute의 결과는 성공여부에 대한 boolean 값이다.
        $result = $stmtSQL->execute();
        var_dump($result);
       
        return $result;
    }

 

board_function.php(변경 전)

function getBoardList($currentPage, $itemPerPage, $searchType, $searchValue)  {
  $db_conn = getDbConn();
  $token = $_COOKIE['REFRESH_TOKEN'];

  $sql = "SELECT IDX AS idx
  , TITLE as title
  , CONTENT as content
  , FIRST_REG_USER as regUser
  , FIRST_REG_TIME as regTime
   FROM tbl_board ";
  echo "searchValue is {$searchValue}";
  if(!$searchValue=='' && $searchType == 'title') {
    $sql = $sql. "WHERE TITLE like'%{$searchValue}%' ";
  }

  $order = "ORDER BY IDX DESC limit {$currentPage},{$itemPerPage}";

  $sql = $sql.$order;

  echo $sql;
  return mysqli_query($db_conn, $sql);
}

 

board_function.php(변경 후)

function getBoardList($currentPage, $itemPerPage, $searchType, $searchValue)  {
  $db_conn = getDbConn();
  $token = $_COOKIE['REFRESH_TOKEN'];


  $sql = "SELECT IDX AS idx
  , TITLE as title
  , CONTENT as content
  , FIRST_REG_USER as regUser
  , FIRST_REG_TIME as regTime
   FROM tbl_board ";
  
  // 검색입력값이 있다면 적용
  if(!$searchValue == '' && $searchType == 'title') {
    $sql = $sql. "WHERE TITLE like ? ";
  }
  $order = "ORDER BY IDX DESC limit ?,?";
  $sql = $sql.$order;
  $stmtSQL = $db_conn->prepare($sql);
  
  // limit에 들어가는 값은 integer이기 때문에 i
  if(!$searchValue == '' && $searchType == 'title') {
    $stmtSQL->bind_param("sii", $searchValue, $currentPage, $itemPerPage);
  } else {
    $stmtSQL->bind_param("ii",$currentPage, $itemPerPage);
  }
  $stmtSQL->execute();
  $result = $stmtSQL->get_result(); 

  echo $sql;
  return  $result;
}

+ Recent posts