Dữ liệu vào php

Nếu bạn là một Nhà phát triển PHP, chắc chắn bạn đã rất quen thuộc với việc truy xuất Cơ sở dữ liệu (Cơ sở dữ liệu) bằng các tiện ích mở rộng MySQL và MySQLi. Từ PHP 5. 1 ta có một cách thức tối ưu hơn đó là sử dụng PHP Data Objects. PDO cung cấp các cơ chế câu lệnh được chuẩn bị sẵn, các thủ tục được lưu trữ và giúp bạn thao tác với cơ sở dữ liệu thông qua các đối tượng (Object) làm cho công việc trở nên hiệu quả, dễ dàng hơn

So sánh PDO và MySQLi

PDOMySQLiDatabase SupportHơn 12 LoạiChỉ hỗ trợ MySQLAPIHướng đối tượng (OOP)Hướng đối tượng (OOP) - Hướng thủ tục (Thủ tục)Kết nối Cơ sở dữ liệuDễ dàngDễ dàngĐặt tên tham sốCóKhôngObject MappingCóCóPrepared StatementsCóKhôngHiệu năngCaoCaoStoredProceduresCóCóCó

1. Giới thiệu PDO - PHP Data Objects

Đối tượng dữ liệu PHP (PDO) là một lớp truy xuất cơ sở dữ liệu cung cấp một phương pháp hệ thống tốt nhất để làm việc với nhiều loại cơ sở dữ liệu khác nhau. Khi làm việc với PDO, bạn sẽ không cần phải viết các câu lệnh SQL cụ thể mà chỉ sử dụng các phương thức mà PDO cung cấp, giúp tiết kiệm thời gian điện và làm cho việc chuyển đổi Hệ quản trị cơ sở dữ liệu trở nên dễ dàng

Bạn chỉ cần xác định API mà PDO cung cấp là có thể làm việc được với nhiều Hệ thống quản trị cơ sở dữ liệu khác nhau như MySQL, SQLite, PostgreSQL, Microsoft SQL Server,. and could easy easy convert them

Hệ thống quản trị cơ sở dữ liệu (Database Management System) mà PDO hỗ trợ bao gồm

Tên trình điều khiểnDBMSPDO_CUBRIDCubridPDO_DBLIB FreeTDSMicrosoft SQL Server / SybasePDO_FIREBIRDFirebirdPDO_IBMIBM DB2PDO_INFORMIXIBM Informix Dynamic ServerPDO_MYSQLMySQL 3. x/4. x/5. xPDO_OCIOGiao diện cuộc gọi OraclePDO_ODBCODBC v3 (IBM DB2, unixODBC và win32 ODBC)PDO_PGSQLPostgreSQLPDO_SQLITESQLite 3 và SQLite 2PDO_SQLSRVMicrosoft SQL Server / SQL AzurePDO_4D4D

2. Kết nối cơ sở dữ liệu

Mỗi DBMS sẽ có các phương thức kết nối khác nhau (có các loại cần Tên người dùng, Mật khẩu, Cơ sở dữ liệu đường dẫn, Cổng, có loại không). Chuỗi kết nối của các biến DBMS phổ biến hầu hết đều có dạng như sau

$conn = new PDO('mysql:host=localhost;dbname=izlearn', $username, $password);

Với mysql là tên của DBMS, localhost có nghĩa là cơ sở dữ liệu được đặt trên cùng một máy chủ, izlearn là tên của cơ sở dữ liệu. $username và $password là 2 biến chứa thông tin xác thực

Đối với SQLite, DBMS này không có cơ chế xác thực bằng Tên người dùng và Mật khẩu mà chỉ đơn giản là đường dẫn đến tệp dữ liệu

$conn = new PDO("sqlite:your/database/path/izlearn.db");

Đây là lúc để bạn quên đi Connection String error mysql_connect('localhost', 'username', 'password') or die('Could not connect. '. mysql_error()); . Thực ra họ chỉ đang dẫn bạn đi về quá khứ mà thôi. Đế ngắt kết nối khi không cần thao tác với cơ sở dữ liệu nữa, các bạn chỉ cần set biến $conn về null;

$conn = null;

3. Chèn và cập nhật

Thêm mới (chèn) và cập nhật (update) dữ liệu là những hoạt động cơ bản khi thao tác với cơ sở dữ liệu. Với PDO, mỗi hoạt động chèn hoặc cập nhật được thực hiện qua 3 quá trình sử dụng cơ chế Câu lệnh đã chuẩn bị

  • chuẩn bị tuyên bố. Chuẩn bị sẵn một câu lệnh SQL làm khung/mẫu được gọi là Tuyên bố đã chuẩn bị với các trình giữ chỗ (có thể hiểu trình giữ chỗ đóng vai trò như tham số của các phương thức khi bạn khai báo hàm)
  • tham số ràng buộc. Gắn giá trị thực vào các trình giữ chỗ (tương tự như khi bạn truyền giá trị vào các tham số của phương thức)
  • Hành hình. Thực thi câu lệnh

Tuyên bố chuẩn bị

Có 2 loại Trình giữ chỗ trong Tuyên bố đã chuẩn bị là Trình giữ chỗ không được định danh (Phần giữ chỗ không được đặt tên) và Trình giữ chỗ được định danh (Phần giữ chỗ được đặt tên) như ví dụ sau

$stmt = $conn->prepare('INSERT INTO users (name, email, age) values (?, ?, ?)');
$stmt = $conn->prepare('INSERT INTO users (name, email, age) values (:name, :mail, :age)');

Dòng lệnh thứ nhất sử dụng Trình giữ chỗ không được định danh là các dấu hỏi - ?. Dòng lệnh thứ 2 sử dụng Placeholder định danh. . tên,. thư,. tuổi (lưu dấu hai chấm và trình giữ chỗ không nhất thiết phải giống tên cột). Sau đây là toàn bộ quá trình Chèn và Cập nhật sử dụng 2 loại Trình giữ chỗ nêu trên

Trình giữ chỗ chưa đặt tên

//Khởi tạo Prepared Statement từ biến $conn ở phần trước
$stmt = $conn->prepare('INSERT INTO users (name, email, age) values (?, ?, ?)');

//Gán các biến (lúc này chưa mang giá trị) vào các placeholder theo thứ tự tương ứng
$stmt->bindParam(1, $name);
$stmt->bindParam(2, $mail);
$stmt->bindParam(3, $age);

//Gán giá trị và thực thi
$name = "Vu Hoang Lam"<
$mail = "[email protected]";
$age = 22;
$stmt->execute();

//Gán những giá trị khác và tiếp tục thực thi
$name = "Nguyen Van A";
$mail = "[email protected]";
$age = 23;
$stmt->execute();

Như các bạn đã thấy, chúng ta chỉ cần khởi động Chuẩn bị Tuyên bố một lần và có thể sử dụng lại nhiều lần. Với mỗi cột - placeholder ta phải thực hiện gán tham số một lần, điều này sẽ không sao với những bảng có ít cột như ví dụ trên, nhưng sẽ rất bất tiện nếu bảng có nhiều bảng, rất may ta có cách khác để

$stmt = $conn->prepare('INSERT INTO users (name, email, age) values (?, ?, ?)');
$data = array('Vu Hoang Lam', '[email protected]', 22);

//Phương thức execute() dưới đây sẽ gán lần lượt giá trị trong mảng vào các Placeholder theo thứ tự
$stmt->execute($data);

Trình giữ chỗ được đặt tên

Đối với Trình giữ chỗ được đặt tên, cách thực hiện cũng khá tương đồng với Trình giữ chỗ không được đặt tên, chỉ khác là ta không sử dụng trình giữ chỗ thứ tự để gán giá trị (ràng buộc) mà sử dụng tên chính của trình giữ chỗ

//Khởi tạo Prepared Statement từ biến $conn ở phần trước
$stmt = $conn->prepare('INSERT INTO users (name, email, age) values (:name, :mail, :age)');

//Gán các biến (lúc này chưa mang giá trị) vào các placeholder theo tên của chúng
$stmt->bindParam(':name', $name);
$stmt->bindParam(':mail', $mail);
$stmt->bindParam(':age', $age);

//Gán giá trị và thực thi
$name = "Vu Hoang Lam";
$mail = "[email protected]";
$age = 22;
$stmt->execute();

Các bạn cũng có thể sử dụng mảng để rút gọn

//Lưu ý: Không cần thiết phải sử dụng dấu hai chấm cho các key
$data = array('name' => 'Vu Hoang Lam', 'mail' => '[email protected]', 'age' => 22);
Một mẹo hữu ích khác khi sử dụng Named Placeholder đó là insert Object

class $user
{
    public $name;
    public $mail;
    public $age;
}

$person = new $user();
$person->name = 'Vu Hoang Lam';
$person->mail = '[email protected]';
$person->age = 22;

$stmt = $conn->prepare('INSERT INTO users (name, email, age) values (:name, :mail, :age)');

$stmt->execute((array)$person);

Ở dòng cuối cùng, tôi đã thực hiện "ép kiểu" (ép) Đối tượng $person thành mảng để truyền vào phương thức thực thi();

Việc sử dụng Tuyên bố đã chuẩn bị sẽ giúp bạn tránh bị SQL Injection, tôi sẽ đi sâu giải thích vấn đề này trong một bài viết khác

4. Chọn Dữ liệu - "Đọc" dữ liệu từ cơ sở dữ liệu

Khi đọc dữ liệu từ cơ sở dữ liệu, PDO sẽ trả về dữ liệu theo cấu trúc mảng (mảng) hoặc đối tượng (đối tượng) thông qua phương thức tìm nạp(). Bạn nên thiết lập trước cấu trúc dữ liệu trước khi gọi phương thức này, PDO hỗ trợ các tùy chọn sau

  • PDO. FETCH_ASSOC. Trả về dữ liệu dạng mảng với key là tên của cột (cột của các bảng trong cơ sở dữ liệu)
  • PDO. FETCH_BOTH (mặc định). Trả về dữ liệu dạng mảng với khóa là tên của cột và số thứ tự của cột
  • PDO. FETCH_BOUND. Gán giá trị của từng cột cho từng biến đã khởi tạo trước đó thông qua phương thức bindColumn()
  • PDO. FETCH_CLASS. Gán giá trị của từng cột cho từng thuộc tính (thuộc tính/thuộc tính) của một lớp Lớp theo tên cột và tên thuộc tính
  • PDO. FETCH_INTO. Gán giá trị của từng cột cho từng thuộc tính của một Phiên bản lớp (có thể hiển thị của một lớp)
  • PDO. FETCH_LAZY. Gop chung PDO. FETCH_BOTH/PDO. FETCH_OBJ
  • PDO. FETCH_NUM. Trả về dữ liệu dạng mảng với key là số thứ tự của cột
  • PDO. FETCH_OBJ. Trả về một đối tượng của stdClass (link is external) với tên thuộc tính của đối tượng là tên của cột

Trong thực tế, chúng ta chỉ thường sử dụng 3 kiểu tìm nạp đó là. FETCH_ASSOC, FETCH_CLASS và FETCH_OBJ. Để thiết lập cấu trúc dữ liệu cấu trúc (Tìm nạp kiểu hoặc Chế độ tìm nạp) trước khi tìm nạp ta sử dụng câu lệnh sau

________số 8_______

Hoặc nếu muốn, bạn cũng có thể thiết lập kiểu tìm nạp khi gọi hàm tìm nạp()

$stmt->fetch(PDO::FETCH_ASSOC);

FETCH_ASSOC

Kiểu tìm nạp này sẽ tạo ra một kết hợp mảng lập chỉ mục theo tên cột (nghĩa là các phím của mảng chính là tên của cột), tương tự như khi ta sử dụng MySQL/MySQLi Extension

$conn = new PDO("sqlite:your/database/path/izlearn.db");
0

FETCH_OBJ

Kiểu tìm nạp này trả về một đối tượng của stdClass cho mỗi hàng của kết quả

$conn = new PDO("sqlite:your/database/path/izlearn.db");
1

FETCH_CLASS

Kiểu tìm nạp này cho phép bạn đưa kết quả vào Đối tượng của một Lớp mà bạn chỉ định. Khi sử dụng FETCH_CLASS, thuộc tính của lớp sẽ được gán giá trị trước khi hàm tạo của lớp được gọi (phải chú ý vì điều này rất quan trọng). Nếu không có thuộc tính khớp với tên của một cột bất kỳ thì thuộc tính đó sẽ được tự động tạo ra (công khai)

Bảng giả sử người dùng có một Class User đã được định nghĩa như sau

$conn = new PDO("sqlite:your/database/path/izlearn.db");
2

Khi truy vấn dữ liệu từ cơ sở dữ liệu sử dụng đoạn mã sau

$conn = new PDO("sqlite:your/database/path/izlearn.db");
3

Vì hàm tạo được gọi sau khi thuộc tính $name được gán bằng Vũ Hoàng Lâm nên isAdmin sẽ mang lại giá trị Yes. Nếu muốn hàm tạo của lớp được gọi trước khi các thuộc tính được gán giá trị, bạn phải sử dụng thêm PDO. FETCH_PROPS_LATE. Cách sử dụng như sau

$conn = new PDO("sqlite:your/database/path/izlearn.db");
4

Nếu cần truyền các tham số cho hàm tạo của lớp thông qua phương thức tìm nạp(), bạn có thể đặt chúng trong một mảng theo thứ tự tương ứng với các công cụ như sau

$conn = new PDO("sqlite:your/database/path/izlearn.db");
5

Ngoại lệ - Xử lý ngoại lệ

PDO sử dụng các ngoại lệ để xử lý các lỗi phát sinh khi làm việc với cơ sở dữ liệu, vì thế tất cả những gì bạn làm với PDO nên được đặt trong một khối thử/bắt. PDO cung cấp 3 chế độ xử lý lỗi (Chế độ Lỗi) được thiết lập thông qua phương thức setAttribute()

$conn = new PDO("sqlite:your/database/path/izlearn.db");
6

PDO. ERRMODE_SILENT

Đây là chế độ xử lý lỗi mặc định của PDO, khi gặp lỗi bất thường, PDO sẽ im lặng (im lặng) và chương trình vẫn tiếp tục chạy. Bạn có thể lấy mã lỗi và thông tin về các lỗi đã xảy ra thông qua PDO. errorCode() và PDO. errorInfo()

PDO. ERRMODE_WARNING

Ở chế độ này khi gặp phải lỗi PDO sẽ ném ra một Cảnh báo PHP, chương trình sẽ tiếp tục chạy

PDO. ERRMODE_EXCEPTION

Đây là chế độ mà bạn nên sử dụng nhiều nhất, khi đặt trong một khối thử/bắt sẽ giúp bạn kiểm tra các lỗi phát sinh một cách nhẹ nhàng và ẩn các thông báo lỗi có thể khiến Kẻ tấn công khai thác hệ thống của bạn

$conn = new PDO("sqlite:your/database/path/izlearn.db");
7

Đoạn mã trên sẽ ghi thông báo lỗi vào một tệp văn bản với tên PDOErrors. txt

Một số phương thức hữu ích khác

$conn = new PDO("sqlite:your/database/path/izlearn.db");
8

Phương thức trả về ID tăng tự động của các hàng được bổ sung gần đây nhất

$conn = new PDO("sqlite:your/database/path/izlearn.db");
9

Đối với các lệnh SQL không có dữ liệu trả về và không cần thiết phải truyền tham số thì có thể sử dụng phương thức exec(). Phương thức này sẽ trả về số lượng hàng bị tác động sau khi thực hiện lệnh. As ví dụ trên sẽ trả về số lượng hàng bị xóa

$conn = null;
0

Phương thức quote() sẽ giúp bạn thêm dấu nháy cho một chuỗi để chuỗi đó an toàn khi sử dụng để truy vấn, nếu bạn không muốn sử dụng Câu lệnh Chuẩn bị

$conn = null;
1

Phương thức rowCount() trả về số lượng hàng được tác động sau khi thực hiện các thao tác DELETE, INSERT và UPDATE. Use rowCount() for the thao tác SELECT can't pay return result false with a number of database