?
This document uses PHP Chinese website manual Release
PDO 是一個(gè)數(shù)據(jù)庫(kù)連接抽象類庫(kù) — 自 5.1.0 版本起內(nèi)置于 PHP 當(dāng)中 — 它提供了一個(gè)通用的接口來與不同的數(shù)據(jù)庫(kù)進(jìn)行交互。比如你可以使用相同的簡(jiǎn)單代碼來連接 MySQL 或是 SQLite:
<?php // PDO + MySQL $pdo = new PDO('mysql:host=example.com;dbname=database', 'user', 'password'); $statement = $pdo->query("SELECT some_field FROM some_table"); $row = $statement->fetch(PDO::FETCH_ASSOC); echo htmlentities($row['some_field']); // PDO + SQLite $pdo = new PDO('sqlite:/path/db/foo.sqlite'); $statement = $pdo->query("SELECT some_field FROM some_table"); $row = $statement->fetch(PDO::FETCH_ASSOC); echo htmlentities($row['some_field']);
PDO 并不會(huì)對(duì) SQL 請(qǐng)求進(jìn)行轉(zhuǎn)換或者模擬實(shí)現(xiàn)并不存在的功能特性;它只是單純地使用相同的 API 連接不同種類的數(shù)據(jù)庫(kù)。
更重要的是,PDO 使你能夠安全的插入外部輸入(例如 ID)到你的 SQL 請(qǐng)求中而不必?fù)?dān)心 SQL 注入的問題。這可以通過使用 PDO 語(yǔ)句和限定參數(shù)來實(shí)現(xiàn)。
我們來假設(shè)一個(gè) PHP 腳本接收一個(gè)數(shù)字 ID 作為一個(gè)請(qǐng)求參數(shù)。這個(gè) ID 應(yīng)該被用來從數(shù)據(jù)庫(kù)中取出一條用戶記錄。下面是一個(gè)錯(cuò)誤的做法:
<?php $pdo = new PDO('sqlite:/path/db/users.db'); $pdo->query("SELECT name FROM users WHERE id = " . $_GET['id']); // <-- NO!
這是一段糟糕的代碼。你正在插入一個(gè)原始的請(qǐng)求參數(shù)到 SQL 請(qǐng)求中。這將讓被黑客輕松地利用[SQL 注入]方式進(jìn)行攻擊。想一下如果黑客將一個(gè)構(gòu)造的 id參數(shù)通過像 http://domain.com/?id=1%3BDELETE+FROM+users 這樣的 URL 傳入。這將會(huì)使 $_GET['id'] 變量的值被設(shè)為 1;DELETE FROM users 然后被執(zhí)行從而刪除所有的 user 記錄!因此,你應(yīng)該使用 PDO 限制參數(shù)來過濾 ID 輸入。
<?php $pdo = new PDO('sqlite:/path/db/users.db'); $stmt = $pdo->prepare('SELECT name FROM users WHERE id = :id'); $id = filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT); // <-- filter your data first (see [Data Filtering](#data_filtering)), especially important for INSERT, UPDATE, etc. $stmt->bindParam(':id', $id, PDO::PARAM_INT); // <-- Automatically sanitized for SQL by PDO $stmt->execute();
這是正確的代碼。它在一條 PDO 語(yǔ)句中使用了一個(gè)限制參數(shù)。這將對(duì)外部 ID 輸入在發(fā)送給數(shù)據(jù)庫(kù)之前進(jìn)行轉(zhuǎn)義來防止?jié)撛诘?SQL 注入攻擊。
對(duì)于寫入操作,例如 INSERT 或者 UPDATE,進(jìn)行數(shù)據(jù)過濾并對(duì)其他內(nèi)容進(jìn)行清理(去除 HTML 標(biāo)簽,Javascript 等等)是尤其重要的。PDO 只會(huì)為 SQL 進(jìn)行清理,并不會(huì)為你的應(yīng)用做任何處理。
你也應(yīng)該知道數(shù)據(jù)庫(kù)連接有時(shí)會(huì)耗盡全部資源,如果連接沒有被隱式地關(guān)閉的話,有可能會(huì)造成可用資源枯竭的情況。不過這通常在其他語(yǔ)言中更為常見一些。使用 PDO 你可以通過銷毀(destroy)對(duì)象,也就是將值設(shè)為 NULL,來隱式地關(guān)閉這些連接,確保所有剩余的引用對(duì)象的連接都被刪除。如果你沒有親自做這件事情,PHP 會(huì)在你的腳本結(jié)束的時(shí)候自動(dòng)為你完成 —— 除非你使用的是持久鏈接。