Câu lệnh chuẩn bị PHP MySQL
Các câu lệnh được chuẩn bị trước rất hữu ích trong việc chống lại việc tiêm SQL.
Báo cáo đã chuẩn bị và các tham số ràng buộc
Câu lệnh được chuẩn bị sẵn là một tính năng được sử dụng để thực thi lặp đi lặp lại các câu lệnh SQL giống nhau (hoặc tương tự) với hiệu quả cao.
Các câu lệnh được chuẩn bị về cơ bản hoạt động như thế này:
- Chuẩn bị: Một mẫu câu lệnh SQL được tạo và gửi đến cơ sở dữ liệu. Một số giá trị nhất định không được chỉ định, được gọi là tham số (được gắn nhãn "?"). Ví dụ: CHÈN VÀO GIÁ TRỊ MyGuests(?, ?, ?)
- Cơ sở dữ liệu phân tích cú pháp, biên dịch và thực hiện tối ưu hóa truy vấn trên mẫu câu lệnh SQL và lưu trữ kết quả mà không cần thực thi nó
- Thực thi: Sau đó, ứng dụng liên kết các giá trị với các tham số và cơ sở dữ liệu sẽ thực thi câu lệnh. Ứng dụng có thể thực thi câu lệnh bao nhiêu lần tùy thích với các giá trị khác nhau
So với việc thực thi trực tiếp các câu lệnh SQL, các câu lệnh được chuẩn bị sẵn có ba ưu điểm chính:
- Các câu lệnh được chuẩn bị sẵn giúp giảm thời gian phân tích cú pháp vì việc chuẩn bị truy vấn chỉ được thực hiện một lần (mặc dù câu lệnh được thực thi nhiều lần)
- Các tham số bị ràng buộc sẽ giảm thiểu băng thông đến máy chủ vì bạn chỉ cần gửi các tham số mỗi lần chứ không phải toàn bộ truy vấn
- Các câu lệnh được chuẩn bị sẵn rất hữu ích trong việc chống lại việc chèn SQL, bởi vì các giá trị tham số, được truyền sau đó bằng một giao thức khác, không cần phải thoát một cách chính xác. Nếu mẫu câu lệnh gốc không được lấy từ đầu vào bên ngoài thì việc chèn SQL không thể xảy ra.
Báo cáo đã chuẩn bị trong MySQLi
Ví dụ sau sử dụng các câu lệnh đã chuẩn bị sẵn và các tham số ràng buộc trong MySQLi:
Ví dụ (MySQLi với các câu lệnh được chuẩn bị sẵn)
<?php
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDB";
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// prepare and bind
$stmt = $conn->prepare("INSERT INTO MyGuests (firstname, lastname, email) VALUES (?, ?, ?)");
$stmt->bind_param("sss", $firstname, $lastname, $email);
// set parameters and execute
$firstname = "John";
$lastname = "Doe";
$email = " [email protected] ";
$stmt->execute();
$firstname = "Mary";
$lastname = "Moe";
$email = " [email protected] ";
$stmt->execute();
$firstname = "Julie";
$lastname = "Dooley";
$email = " [email protected] ";
$stmt->execute();
echo "New records created successfully";
$stmt->close();
$conn->close();
?>
Dòng mã để giải thích từ ví dụ trên:
"INSERT INTO MyGuests (firstname, lastname, email) VALUES (?, ?, ?)"
Trong SQL của chúng tôi, chúng tôi chèn một dấu chấm hỏi (?) vào nơi chúng tôi muốn thay thế bằng một giá trị số nguyên, chuỗi, gấp đôi hoặc blob.
Sau đó, hãy xem hàm bind_param():
$stmt->bind_param("sss", $firstname, $lastname, $email);
Hàm này liên kết các tham số với truy vấn SQL và cho cơ sở dữ liệu biết các tham số đó là gì. Đối số "sss" liệt kê các loại dữ liệu chứa tham số. Ký tự s cho mysql biết rằng tham số là một chuỗi.
Đối số có thể là một trong bốn loại:
- tôi - số nguyên
- d - đôi
- s - chuỗi
- b - BLOB
Chúng ta phải có một trong những điều này cho mỗi tham số.
Bằng cách cho mysql biết loại dữ liệu dự kiến, chúng tôi giảm thiểu nguy cơ bị chèn SQL.
Lưu ý: Nếu chúng ta muốn chèn bất kỳ dữ liệu nào từ các nguồn bên ngoài (chẳng hạn như thông tin đầu vào của người dùng), điều quan trọng là dữ liệu đó phải được vệ sinh và xác thực.
Báo cáo được chuẩn bị trong PDO
Ví dụ sau sử dụng các câu lệnh đã chuẩn bị sẵn và các tham số ràng buộc trong PDO:
Ví dụ (PDO với Báo cáo đã chuẩn bị sẵn)
<?php
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDBPDO";
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// prepare sql and bind parameters
$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);
// insert a row
$firstname = "John";
$lastname = "Doe";
$email = " [email protected] ";
$stmt->execute();
// insert another row
$firstname = "Mary";
$lastname = "Moe";
$email = " [email protected] ";
$stmt->execute();
// insert another row
$firstname = "Julie";
$lastname = "Dooley";
$email = " [email protected] ";
$stmt->execute();
echo "New records created successfully";
} catch(PDOException $e)
{
echo "Error: " . $e->getMessage();
}
$conn = null;
?>