준비된 명령문
준비된 문은 동일한(또는 유사한) SQL 문을 고효율로 반복적으로 실행하는 데 사용되는 기능이다.
준비된 문은 기본적으로 다음과 같이 작동한다.
- 준비: SQL 문 템플릿이 생성되어 데이터베이스로 전송됩니다. 매개변수라고 하는 특정 값은 지정되지 않은 상태로 남는다. 예: INSERT INTO MyGuests VALUES(?, ?, ?)
- 데이터베이스는 SQL 문 템플릿에 대해 구문 분석, 컴파일 및 쿼리 최적화를 수행하고 실행하지 않고 결과를 저장한다.
- 실행: 나중에 애플리케이션이 값을 매개변수에 바인딩하고 데이터베이스가 명령문을 실행합니다. 응용 프로그램은 다른 값으로 원하는 만큼 명령문을 실행할 수 있다.
SQL 문을 직접 실행하는 것과 비교할 때 준비된 문에는 세 가지 주요 이점이 있습니다.
- 준비된 문은 쿼리에 대한 준비가 한 번만 수행되므로 준비된 문이 여러번 수행되더라도 구문 분석 시간을 줄인다.
- 바인딩된 매개 변수는 전체 쿼리가 아닌 매번 매개 변수만 보내야 하므로 서버에 대한 대역폭을 최소화한다.
- 다른 프로토콜을 사용하여 나중에 전송되는 매개 변수 값을 올바르게 이스케이프할 필요가 없기 때문에 준비된 문은 SQL 주입에 대해 매우 유용하다. 원본 명령문 템플릿이 외부 입력에서 파생되지 않은 경우 SQL 인젝션이 발생할 수 없다.
MySQLi에서 준비된 명령문
MySQLi에서 준비된 명령문과 바인딩된 매개변수를 사용해보자.
PHP
<?php $servername = "localhost"; $username = "username"; $password = "password"; $dbname = "myDB"; $conn = new mysqli($servername, $username, $password, $dbname); if ($conn->connect_error) { die("Connection failed: " . $conn->connect_error); } $stmt = $conn->prepare("INSERT INTO MyGuests (firstname, lastname, email) VALUES (?, ?, ?)"); $stmt->bind_param("sss", $firstname, $lastname, $email); $firstname = "John"; $lastname = "Doe"; $email = "john@example.com"; $stmt->execute(); $firstname = "Mary"; $lastname = "Moe"; $email = "mary@example.com"; $stmt->execute(); $firstname = "Julie"; $lastname = "Dooley"; $email = "julie@example.com"; $stmt->execute(); echo "New records created successfully"; $stmt->close(); $conn->close(); ?>
"INSERT INTO MyGuests (firstname, lastname, email) VALUES (?, ?, ?)"
SQL에서 정수, 문자열, double 또는 blob 값으로 대체하려는 위치에 물음표(?)를 삽입한다.
$stmt->bind_param("sss", $firstname, $lastname, $email);
매개변수를 SQL 쿼리에 바인딩하고 매개변수가 무엇인지 데이터베이스에 알려준다.
“sss” 인수는 매개변수가 있는 데이터 유형을 나열한다.
s 문자는 매개변수가 문자열임을 mysql에 알린다.
인수는 다음 네 가지 유형 중 하나일 수 있다.
- i – 정수
- d – 더블
- s – 문자열
- b – BLOB
각 매개변수에 대해 이 중 하나가 있어야한다.
PDO에서 준비된 명령문
PDO에서 준비된 명령문과 바인딩된 매개변수를 사용해보자.
PHP
<?php $servername = "localhost"; $username = "username"; $password = "password"; $dbname = "myDBPDO"; try { $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password); $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $stmt = $conn->prepare("INSERT INTO MyGuests (firstname, lastname, email) VALUES (:firstname, :lastname, :email)"); $stmt->bindParam(':firstname', $firstname); $stmt->bindParam(':lastname', $lastname); $stmt->bindParam(':email', $email); $firstname = "John"; $lastname = "Doe"; $email = "john@example.com"; $stmt->execute(); $firstname = "Mary"; $lastname = "Moe"; $email = "mary@example.com"; $stmt->execute(); $firstname = "Julie"; $lastname = "Dooley"; $email = "julie@example.com"; $stmt->execute(); echo "New records created successfully"; } catch(PDOException $e) { echo "Error: " . $e->getMessage(); } $conn = null; ?>
참고
W3C School - PHP MySQL Prepared Statements
W3C School - SQL Tutorial
W3C School - PHP Tryit Editor