[PDO](http://php.net/pdo) 是一個數據庫連接抽象類庫 — 自 5.1.0 版本起內置于 PHP 當中 — 它提供了一個通用的接口來與不同的數據庫進行交互。比如你可以使用相同的簡單代碼來連接 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 并不會對 SQL 請求進行轉換或者模擬實現并不存在的功能特性;它只是單純地使用相同的 API 連接不同種類的數據庫。
更重要的是,PDO 使你能夠安全的插入外部輸入(例如 ID)到你的 SQL 請求中而不必擔心 SQL 注入的問題。這可以通過使用 PDO 語句和限定參數來實現。
我們來假設一個 PHP 腳本接收一個數字 ID 作為一個請求參數。這個 ID 應該被用來從數據庫中取出一條用戶記錄。下面是一個錯誤的做法:
~~~
<?php
$pdo = new PDO('sqlite:/path/db/users.db');
$pdo->query("SELECT name FROM users WHERE id = " . $_GET['id']); // <-- NO!
~~~
這是一段糟糕的代碼。你正在插入一個原始的請求參數到 SQL 請求中。這將讓被黑客輕松地利用[SQL 注入]方式進行攻擊。想一下如果黑客將一個構造的 id 參數通過像 `http://domain.com/?id=1%3BDELETE+FROM+users` 這樣的 URL 傳入。這將會使 `$_GET['id']` 變量的值被設為 `1;DELETE FROM users `然后被執行從而刪除所有的 user 記錄!因此,你應該使用 PDO 限制參數來過濾 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 語句中使用了一個限制參數。這將對外部 ID 輸入在發送給數據庫之前進行轉義來防止潛在的 SQL 注入攻擊。
對于寫入操作,例如 INSERT 或者 UPDATE,進行[數據過濾](http://laravel-china.github.io/php-the-right-way/#data_filtering)并對其他內容進行清理(去除 HTML 標簽,Javascript 等等)是尤其重要的。PDO 只會為 SQL 進行清理,并不會為你的應用做任何處理。
* [了解 PDO](http://php.net/book.pdo)
你也應該知道數據庫連接有時會耗盡全部資源,如果連接沒有被隱式地關閉的話,有可能會造成可用資源枯竭的情況。不過這通常在其他語言中更為常見一些。使用 PDO 你可以通過銷毀(destroy)對象,也就是將值設為 NULL,來隱式地關閉這些連接,確保所有剩余的引用對象的連接都被刪除。如果你沒有親自做這件事情,PHP 會在你的腳本結束的時候自動為你完成 —— 除非你使用的是持久鏈接。
* [了解 PDO 連接](http://php.net/pdo.connections)
- 歡迎
- 入門指南
- 使用當前穩定版本
- 內置的WEB服務器
- Mac安裝
- Windows安裝
- 代碼風格指南
- 語言亮點
- 編程范式
- 命名空間
- PHP標準庫
- 命令行接口
- Xdebug
- 依賴管理
- Composer 與 Packagist
- PEAR
- 開發實踐
- 基礎知識
- 日期和時間
- 設計模式
- 使用UTF8編碼
- 依賴注入
- 基本概念
- 復雜的問題
- 容器
- 延伸閱讀
- 數據庫
- MYSQL 擴展
- PDO 擴展
- 數據庫交互
- 數據庫抽象層
- 使用模板
- 好處
- 原生PHP模板
- 編譯模板
- 延伸閱讀
- 錯誤與異常
- 錯誤
- 異常
- 安全
- Web應用程序安全
- 密碼哈希
- 數據過濾
- 配置文件
- 注冊全局變量
- 錯誤報告
- 測試
- 測試驅動開發
- 行為驅動開發
- 其他測試工具
- 服務器與部署
- Platform as a Service (PaaS)
- 虛擬或專用服務器
- 共享服務器
- 構建及部署應用
- 虛擬化
- Vagrant
- Docker
- 緩存
- Opcode緩存
- 對象緩存
- 文檔撰寫
- 資源
- 社區
- Credits