01/10/2018, 16:53

Bài 07: MySQL prepared với PHP

1. Lệnh prepared và các tham số ràng buộc. Một lệnh prepared là một tính năng được sử dụng để thực hiện các câu lệnh SQL giống nhau (hoặc tương tự) lặp đi lặp lại với hiệu quả rất cao. Các lệnh prepared về cơ bản hoạt động như sau: Prepared : Một mẫu câu lệnh SQL được tạo ra và gửi đến ...

1. Lệnh prepared và các tham số ràng buộc.

Một lệnh prepared là một tính năng được sử dụng để thực hiện các câu lệnh SQL giống nhau (hoặc tương tự) lặp đi lặp lại với hiệu quả rất cao.

Các lệnh prepared về cơ bản hoạt động như sau:

  • Prepared: Một mẫu câu lệnh SQL được tạo ra và gửi đến cơ sở dữ liệu của bạn. Một số giá trị còn lại không được xác định, được gọi là các tham số (có gắn nhãn "?"). e.g INSERT INTO MyGuests VALUES (?,?,?)
  • Cơ sở dữ liệu phân tích cú pháp, biên dịch và thực hiện tối ưu hoá truy vấn trên mẫu câu lệnh SQL và lưu kết quả mà không thực hiện nó.
  • Execute: Sau đó, ứng dụng sẽ hợp các giá trị với các tham số, tiếp đến là cơ sở dữ liệu thực thi câu lệnh, có thể thực hiện nhiều lần câu lệnh này theo ý muốn với các giá trị khác nhau.

2.Cơ chế prepared câu SQL

Thông thường chúng ta thường truyền các thâm số vào câu lệnh SQL như sau.

// Get param $slug
$slug = isset($_GET['slug']) ? $_GET['slug'] : ';

// Mẫu truy vấn
$sql = "SELECT * FROM News WHERE slug='$slug'"

Trong câu truy vấn trên thường tiềm ẩn nguy cơ bạn sẽ bị SQL Injections. Và chúng ta thường sử dụng hàm addslashes() để khắc phục phần nào khả năng bị tấn công SQL Injections.

// Get param $slug
$slug = isset($_GET['slug']) ? addslashes($_GET['slug']) : ';

// Mẫu truy vấn
$sql = "SELECT * FROM News WHERE slug='$slug'";

Bây giờ người ta đã không sử dụng cách này nữa cũng một phần nó chưa giải quyết được triệt để vấn đề. Thay vào đó người ta sử dụng chức năng sẵn có trong thư viện MySQLi và PDO. Mỗi thư viện có cách thể hiện khác nhau nhưng chúng đều có chung một quy tắc đó là:

  • Chúng ta đưa vào một câu truy vấn với các tham số là một ẩn danh
  • Chúng ta truyền vào giá trị tương ứng cho các ẩn danh đó
  • PHP sẽ dựa vào thư tự các tham số ẩn danh và các giá trị để prepared sao cho bảo mật nhất.
  • Cuối cùng sẽ thực thi câu truy vấn.
  • Khi bạn đã khai báo các tham số lần đầu rồi và sau đó muốn sử dụng tiếp thì không cần phải khai báo nữa. Đây cũng chính là lợi thế của cơ chế prepared trong PHP.

Prepared câu SQL trong MySQLi

Chúng ta chỉ thực hiện Prepared trong trường hợp sử dụng MySQLi Object-oriented.

Các tham số truyền vào sở là các dấu chấm hỏi ?, đây chính là tham số ẩn danh

$host = "localhost";
$username = "root";
$password = "";
$dbName = "MySQLDemo";

// Tạo kết nối
$dbconn = new mysqli($host, $username, $password, $dbName);
 
// Kiểm tra kết nối
if ($dbconn->connect_error) {
	die("Kết nối thất bại: " . $dbconn->connect_error);
}
 
// Câu SQL
$sql = "INSERT INTO News (title, slug, intro) VALUES (?, ?, ?)";

// Tạo đối tượng repared
$stmt = $dbconn->prepare($sql);

// Gán giá trị vào các tham số ẩn
$stmt->bind_param("sss", $title, $slug, $intro);

// Thực thi câu lệnh 1.
$title = 'Học lập trình PHP';
$slug = 'hoc-lap-trinh-php';
$content = 'Giới thiệu về học lập trình PHP';
$stmt->execute();

// Thực thi câu lệnh 2.
$title = 'Học lập trình MySQL';
$slug = 'hoc-lap-trinh-mysql';
$content = 'Giới thiệu về học lập trình MySQL';
$stmt->execute();

echo "Thêm thành công!";
// Giải phóng và ngắt kết nối
$stmt->close();
$dbconn->close();

Trong câu lệnh trên bạn cần chú ý một số điểm sau.

Thứ nhất: Bạn cần phải tạo ra mẫu câu truy vấn, sử dụng dấu ? là tham số ẩn danh.

$sql = "INSERT INTO News (title, slug, intro) VALUES (?, ?, ?)";

Thứ hai:Thực hiện bind dữ liệu

// Gán giá trị vào các tham số ẩn
$stmt->bind_param("sss", $title, $slug, $intro);

Giá trị đầu tiên là hai chữ sss, đây chính là khai báo dữ liệu cho ba tham số ẩn danh ở trên. Chúng có ý nghĩa như sau:

  • i: interger
  • d: double
  • s: string
  • b: blob

Các tham số còn lại như $title, $slug và $intro chính là các tham số dạng tham chiếu nên dù chưa được khai báo nhưng vẫn không bị lỗi.

Prepared câu SQL trong PDO.

Với PDO thì cú pháp có hơi khác một chút đó là tham số ẩn không phải là dấu hỏi nữa mà là ở dạng :varname

$host = "localhost";
$username = "root";
$password = "";
$dbName = "MySQLDemo";

try {
    // Kết nối
    $dbconn = new PDO("mysql:host=$host;dbname=$dbName", $username, $password);
    
	// Khai báo exception
    $dbconn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
 
    // prepare sql and bind parameters
    $stmt = $dbconn->prepare("INSERT INTO News (title, slug, content) VALUES (:title, :slug, :intro)");
    $stmt->bindParam(':title', $title);
	$stmt->bindParam(':slug', $slug);
    $stmt->bindParam(':content', $content);
 
    // Thực thi câu lệnh 1.
    $title = 'Học lập trình PHP';
	$slug = 'hoc-lap-trinh-php';
	$content = 'Giới thiệu về học lập trình PHP';
    $stmt->execute();
	
	 // Thực thi câu lệnh 1.
    $title = 'Học lập trình MySQL';
	$slug = 'hoc-lap-trinh-mysql';
	$content = 'Giới thiệu về học lập trình MySQL';
    $stmt->execute();
 
    echo "Thao tác thành công!";
} 
catch (PDOException $e) {
    echo "Error: " . $e->getMessage();
}
 
// Ngắt kết nối
$dbconn = null;

Tổng kết.

Như vậy mình đã giới thiệu tới các bạn cách sử dụng cơ chế prepared câu lệnh MySQL trong PHP bằng hai thư viện MySQLi và PDO. Thực tế thì bạn nên sử dụng nó trong ứng dụng của bạn một mặt đảm bảo an toàn dữ liệu, chống SQL Injection mặt khác tăng tính hiệu quả các câu lệnh SQL.

    Tạ Quốc Bảo

    23 chủ đề

    7270 bài viết

    Cùng chủ đề
    0