如何在 PHP 中使用 multi_query 制作准备好的语句
How to make prepared statement with multi_query in PHP
我目前正在尝试 post 使用 php 和 mysqli 将有关用户的一些元数据发送到 mysql 数据库。我检索了一个数组,其中 key/value 对对应于 key/value 对,它们应该存储在数据库中。
function insert_metadata_to_db ($user_id, $metaData) {
$conn = mysqli_connect("127.0.0.1", "root", "", "test");
foreach($metaData as $key => $value) {
$metaDataSql .= "insert into usermeta (user_id, meta_key, meta_value) values ($user_id, '$key', '$value');";
}
if(!$conn->multi_query($metaDataSql)) {
echo("Failed to execute the queries." . $conn->error);
}
mysqli_close($conn);
}
我的下一步是避免 SQL 注入。我已经尝试过,但失败了,用准备好的语句在上面制作了这个方法。这是我的尝试:
function insert_metadata_to_db ($user_id, $metaData) {
$conn = mysqli_connect("127.0.0.1", "root", "", "test");
foreach($metaData as $key => $value) {
$metaDataSql .= $conn->prepare("insert into usermeta (user_id, meta_key, meta_value) values (?, '?', '?');");
$metaDataSql->bind_param("iss", $user_id, $key, $value);
}
if(!$conn->multi_query($metaDataSql)) {
echo("Failed to execute the queries." . $conn->error);
}
mysqli_close($conn);
}
这样可以吗?如果不是 - 处理多次插入数据库同时保持安全免受 SQL 注入的最佳方法是什么。
您无法准备 mysqli::multi_query
- 但使用准备好的语句,您可以迭代相同的查询,只是使用不同的值。这比迭代和 运行 标准 query()
.
更优化
mysqli_stmt::bind_param()
是引用,所以你只需要绑定一次,然后每次迭代都执行它。
function insert_metadata_to_db ($user_id, $metaData) {
$conn = new mysqli("127.0.0.1", "root", "", "test");
$stmt = $conn->prepare("INSERT INTO usermeta (user_id, meta_key, meta_value) VALUES (?, ?, ?");
$stmt->bind_param("iss", $user_id, $key, $value);
foreach($metaData as $key => $value) {
$stmt->execute();
}
$stmt->close();
$conn->close();
}
如果您只想执行一次,也可以构建单个查询。这不一定比上面快很多,但可以稍微快一点。使用解包运算符(或 "splat operator")...
在绑定它的位置解包整个数组。
function insert_metadata_to_db ($user_id, $metaData) {
$conn = new mysqli("127.0.0.1", "root", "", "test");
$query = "INSERT INTO usermeta (user_id, meta_key, meta_value) VALUES ";
$data = [];
// Build the query, by appending values and inserting into the $data array
foreach($metaData as $key => $value) {
$query .= "(?, ?, ?), ";
$data[] = $user_id;
$data[] = $key;
$data[] = $value;
}
// Trim away trailing comma
$query = rtrim($query, ",");
// If there are any data to bind, we can execute the query
if (count($data)) {
$stmt = $conn->prepare($query);
$stmt->bind_param(str_repeat("iss", count($metaData)), ...$data);
$stmt->execute();
$stmt->close();
}
$conn->close();
}
旁注
在函数内初始化连接通常是一个非常糟糕的主意!您应该改为将全局连接作为参数传递给该函数。现在,每次使用该功能时都会建立一个新连接。
我目前正在尝试 post 使用 php 和 mysqli 将有关用户的一些元数据发送到 mysql 数据库。我检索了一个数组,其中 key/value 对对应于 key/value 对,它们应该存储在数据库中。
function insert_metadata_to_db ($user_id, $metaData) {
$conn = mysqli_connect("127.0.0.1", "root", "", "test");
foreach($metaData as $key => $value) {
$metaDataSql .= "insert into usermeta (user_id, meta_key, meta_value) values ($user_id, '$key', '$value');";
}
if(!$conn->multi_query($metaDataSql)) {
echo("Failed to execute the queries." . $conn->error);
}
mysqli_close($conn);
}
我的下一步是避免 SQL 注入。我已经尝试过,但失败了,用准备好的语句在上面制作了这个方法。这是我的尝试:
function insert_metadata_to_db ($user_id, $metaData) {
$conn = mysqli_connect("127.0.0.1", "root", "", "test");
foreach($metaData as $key => $value) {
$metaDataSql .= $conn->prepare("insert into usermeta (user_id, meta_key, meta_value) values (?, '?', '?');");
$metaDataSql->bind_param("iss", $user_id, $key, $value);
}
if(!$conn->multi_query($metaDataSql)) {
echo("Failed to execute the queries." . $conn->error);
}
mysqli_close($conn);
}
这样可以吗?如果不是 - 处理多次插入数据库同时保持安全免受 SQL 注入的最佳方法是什么。
您无法准备 mysqli::multi_query
- 但使用准备好的语句,您可以迭代相同的查询,只是使用不同的值。这比迭代和 运行 标准 query()
.
mysqli_stmt::bind_param()
是引用,所以你只需要绑定一次,然后每次迭代都执行它。
function insert_metadata_to_db ($user_id, $metaData) {
$conn = new mysqli("127.0.0.1", "root", "", "test");
$stmt = $conn->prepare("INSERT INTO usermeta (user_id, meta_key, meta_value) VALUES (?, ?, ?");
$stmt->bind_param("iss", $user_id, $key, $value);
foreach($metaData as $key => $value) {
$stmt->execute();
}
$stmt->close();
$conn->close();
}
如果您只想执行一次,也可以构建单个查询。这不一定比上面快很多,但可以稍微快一点。使用解包运算符(或 "splat operator")...
在绑定它的位置解包整个数组。
function insert_metadata_to_db ($user_id, $metaData) {
$conn = new mysqli("127.0.0.1", "root", "", "test");
$query = "INSERT INTO usermeta (user_id, meta_key, meta_value) VALUES ";
$data = [];
// Build the query, by appending values and inserting into the $data array
foreach($metaData as $key => $value) {
$query .= "(?, ?, ?), ";
$data[] = $user_id;
$data[] = $key;
$data[] = $value;
}
// Trim away trailing comma
$query = rtrim($query, ",");
// If there are any data to bind, we can execute the query
if (count($data)) {
$stmt = $conn->prepare($query);
$stmt->bind_param(str_repeat("iss", count($metaData)), ...$data);
$stmt->execute();
$stmt->close();
}
$conn->close();
}
旁注
在函数内初始化连接通常是一个非常糟糕的主意!您应该改为将全局连接作为参数传递给该函数。现在,每次使用该功能时都会建立一个新连接。