SQL 注入是 Web 應用最常見的高風險漏洞。早期 PHP 開發者常用 addslashes() 或 mysql_real_escape_string() 轉義輸入,但現代開發強烈建議改用 PDO 預處理語句,從根本上分離 SQL 邏輯與資料,徹底杜絕注入風險。
缺點: 魔術引號已棄用、手動轉義易漏、字元集問題、無法防禦所有注入向量。
PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false, // 使用真正的預處理
]);
// 參數綁定範例
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email AND status = :status');
$stmt->execute(['email' => $email, 'status' => 1]);
$user = $stmt->fetch();
// 批次插入範例
$pdo->beginTransaction();
$stmt = $pdo->prepare('INSERT INTO logs (message, created_at) VALUES (:msg, NOW())');
foreach ($messages as $msg) {
$stmt->execute(['msg' => $msg]);
}
$pdo->commit();
?>
若專案需大量動態查詢,可封裝簡單的 Query Builder,核心原則仍是所有動態值皆走參數綁定:
pdo = $pdo; }
public function select(string $table, array $where = [], array $columns = ['*']): array {
$sql = 'SELECT ' . implode(', ', $columns) . ' FROM ' . $table;
$params = [];
if ($where) {
$conditions = [];
foreach ($where as $col => $val) {
$param = ':' . $col;
$conditions[] = "`$col` = $param";
$params[$param] = $val;
}
$sql .= ' WHERE ' . implode(' AND ', $conditions);
}
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
return $stmt->fetchAll();
}
}
?>
display_errors,記錄至日誌檔。| 方法 | 推薦度 | 適用場景 |
|---|---|---|
| PDO 預處理語句 | ⭐⭐⭐⭐⭐ | 所有新專案、所有動態查詢 |
| mysqli 預處理語句 | ⭐⭐⭐⭐ | 僅用 mysqli 專案 |
| addslashes / 手動轉義 | ⭐ | 維護舊代碼、極簡腳本(不建議) |
| ❌ 已移除 | PHP 5.4+ 已棄用,PHP 7.0+ 移除 |