本文目录导读:

- 使用 PDO(PHP Data Objects)【推荐】
- 使用 MySQLi(MySQL Improved Extension)
- PDO vs MySQLi 对比
- 最佳实践与注意事项
- 完整的 PDO 封装示例
在 PHP 中,参数化查询(Parameterized Query)是防止 SQL 注入的最佳实践,它通过将 SQL 语句与数据分离,让数据库引擎预编译 SQL 模板,然后安全地绑定参数值。
以下是 PHP 中实现参数化查询的三种主流方式:
使用 PDO(PHP Data Objects)【推荐】
PDO 提供了统一的接口来访问多种数据库。
基本示例(MySQL)
<?php
$dsn = 'mysql:host=localhost;dbname=testdb;charset=utf8mb4';
$username = 'root';
$password = '';
try {
$pdo = new PDO($dsn, $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// 参数化查询:使用命名占位符
$sql = "SELECT * FROM users WHERE email = :email AND status = :status";
$stmt = $pdo->prepare($sql);
// 绑定参数
$stmt->bindParam(':email', $email);
$stmt->bindParam(':status', $status);
$email = 'user@example.com';
$status = 'active';
$stmt->execute();
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
var_dump($results);
} catch (PDOException $e) {
echo "数据库错误: " . $e->getMessage();
}
?>
使用问号占位符(位置参数)
$sql = "SELECT * FROM users WHERE email = ? AND status = ?"; $stmt = $pdo->prepare($sql); $stmt->execute(['user@example.com', 'active']); // 或者 $stmt->execute([$email, $status]);
插入数据示例
$sql = "INSERT INTO users (name, email, age) VALUES (:name, :email, :age)";
$stmt = $pdo->prepare($sql);
$data = [
':name' => '张三',
':email' => 'zhangsan@example.com',
':age' => 25
];
$stmt->execute($data);
echo "插入成功,ID: " . $pdo->lastInsertId();
使用 MySQLi(MySQL Improved Extension)
MySQLi 专门用于 MySQL 数据库,支持面向对象和过程式两种风格。
面向对象风格
<?php
$mysqli = new mysqli('localhost', 'root', '', 'testdb');
if ($mysqli->connect_error) {
die('连接失败: ' . $mysqli->connect_error);
}
// 准备 SQL 语句
$sql = "SELECT id, name, email FROM users WHERE email = ? AND status = ?";
$stmt = $mysqli->prepare($sql);
// 绑定参数(s=string, i=integer, d=double, b=blob)
$email = 'user@example.com';
$status = 'active';
$stmt->bind_param("ss", $email, $status);
// 执行查询
$stmt->execute();
// 绑定结果变量(可选)
$stmt->bind_result($id, $name, $email_result);
// 获取结果
while ($stmt->fetch()) {
echo "ID: $id, Name: $name, Email: $email_result<br>";
}
// 关闭语句和连接
$stmt->close();
$mysqli->close();
?>
插入数据
$sql = "INSERT INTO users (name, email, age) VALUES (?, ?, ?)";
$stmt = $mysqli->prepare($sql);
$name = '李四';
$email = 'lisi@example.com';
$age = 30;
$stmt->bind_param("ssi", $name, $email, $age);
if ($stmt->execute()) {
echo "插入成功,ID: " . $stmt->insert_id;
} else {
echo "错误: " . $stmt->error;
}
$stmt->close();
PDO vs MySQLi 对比
| 特性 | PDO | MySQLi |
|---|---|---|
| 数据库支持 | 12+ 种数据库 | 仅 MySQL |
| 命名占位符 | 支持 (name) |
仅问号 |
| 面向对象 | 是 | 是(也支持过程式) |
| 预处理语句 | 是 | 是 |
| 性能 | 类似 | 类似 |
| 推荐指数 |
最佳实践与注意事项
始终使用参数化查询
- ✅ 正确:
$stmt->execute(['user@example.com']) - ❌ 错误:
$pdo->query("SELECT * FROM users WHERE email='$email'")
不要手动转义(已过时)
- 不要使用
mysqli_real_escape_string(),参数化查询已经自动处理转义
处理批量插入(事务)
try {
$pdo->beginTransaction();
$sql = "INSERT INTO users (name, email) VALUES (:name, :email)";
$stmt = $pdo->prepare($sql);
foreach ($users as $user) {
$stmt->execute([
':name' => $user['name'],
':email' => $user['email']
]);
}
$pdo->commit();
} catch (Exception $e) {
$pdo->rollBack();
echo "失败: " . $e->getMessage();
}
使用 LIKE 查询(注意通配符处理)
$search = "%{$keyword}%"; // 通配符在参数中,SQL 模板不变
$sql = "SELECT * FROM products WHERE name LIKE :keyword";
$stmt = $pdo->prepare($sql);
$stmt->execute([':keyword' => $search]);
完整的 PDO 封装示例
<?php
class Database {
private static $instance = null;
private $pdo;
private function __construct() {
$config = [
'host' => 'localhost',
'dbname' => 'testdb',
'charset' => 'utf8mb4',
'username' => 'root',
'password' => ''
];
$dsn = "mysql:host={$config['host']};dbname={$config['dbname']};charset={$config['charset']}";
$this->pdo = new PDO($dsn, $config['username'], $config['password'], [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false, // 关闭模拟预处理,使用真实的预处理
]);
}
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
public function query($sql, $params = []) {
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
return $stmt;
}
public function fetchAll($sql, $params = []) {
return $this->query($sql, $params)->fetchAll();
}
public function fetchOne($sql, $params = []) {
return $this->query($sql, $params)->fetch();
}
public function insert($table, $data) {
$columns = implode(', ', array_keys($data));
$placeholders = ':' . implode(', :', array_keys($data));
$sql = "INSERT INTO $table ($columns) VALUES ($placeholders)";
$this->query($sql, $data);
return $this->pdo->lastInsertId();
}
public function update($table, $data, $where, $whereParams = []) {
$set = '';
foreach ($data as $key => $value) {
$set .= "$key = :$key, ";
}
$set = rtrim($set, ', ');
$sql = "UPDATE $table SET $set WHERE $where";
$params = array_merge($data, $whereParams);
return $this->query($sql, $params)->rowCount();
}
}
// 使用示例
$db = Database::getInstance();
$users = $db->fetchAll("SELECT * FROM users WHERE age > :age", [':age' => 18]);
$user = $db->fetchOne("SELECT * FROM users WHERE id = :id", [':id' => 1]);
$newId = $db->insert('users', ['name' => '王五', 'email' => 'wangwu@example.com']);
?>
| 方法 | 推荐场景 |
|---|---|
| PDO | 通用、跨数据库、现代 PHP 项目首选 |
| MySQLi | 仅使用 MySQL、已有遗留项目 |
核心原则:永远不要直接将用户输入拼接到 SQL 语句中,始终使用参数化查询,这不仅防止 SQL 注入,还能提高查询性能和代码可读性。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播