我最近使用prepare()
和bind_param()
了解了SQL Injection和避免使用PHP的PHP建议。
现在,我想动态地准备SQL查询,同时添加列名和值。
我希望这样做,因为HTML输入的name
字段与MySQL数据库列的名称相同。
<input type="text" name="firstname" >
<input type="text" name="lastname" >
然后,使用mysqli动态创建SQL查询。
// Extract values from POST
$parameters = $_POST;
// Organize the values in two strings
foreach ($parameters as $id => $value) {
$fields = $fields . "`" . $id . "`,";
$values = $values . "'" . $value . "',";
/*e.g.
$fields = `firstname`,`lastname`
$values = 'John','Wick'
*/
}
// Write into the database
$sql = "INSERT INTO `user` ($fields) VALUES ($values)";
/*e.g.
INSERT INTO `user` (`firstname`,`lastname`) VALUES ('John','Wick')
*/
我想知道是否有一种方法可以使用prepare()
和bind_param()
来避免SQL注入,可能是在HTML输入标签中添加了一些data-type="s"
,或者是否有一种更好的,更好的最佳实践方式。
答案 0 :(得分:4)
您只能将绑定参数用于将是常量值的元素(带引号的字符串,带引号的日期时间或数字文字)。
您不能在SQL中的其他任何内容上使用参数占位符,例如列名,表名,值列表,SQL关键字或表达式或其他语法。
如果您需要使列名动态化,唯一的选择是根据已知列的列表来验证它们。
$columns_in_user_table = [
'userid'=>null,
'username'=>'',
'firstname'=>'',
'lastname'=>''
];
// Extract values from POST, but only those that match known columns
$parameters = array_intersect_key($_POST, $columns_in_user_table);
// Make sure no columns are missing; assign default values as needed
$parameters = array_merge($columns_in_user_table, $parameters);
如果使用PDO代替mysqli,则可以跳过绑定。只需使用命名参数,然后将您的列值对的关联数组直接传递到execute()
:
$columns = [];
$placeholders = [];
foreach ($parameters as $col => $value) {
$columns[] = "`$col`";
$placeholders[] = ":$col";
}
$column_list = implode($columns, ',');
$placeholder_list = implode($placeholders, ',');
// Write into the database
$sql = "INSERT INTO `user` ($column_list) VALUES ($placeholder_list)";
$stmt = $pdo->prepare($sql);
$stmt->execute($parameters);
答案 1 :(得分:-1)
我注意到您在问题中包括mysqli标记,因此,假设您的数据库是MySQL,并且您正在使用本机MySQL函数,则可以执行以下操作:
$stmt = mysqli_prepare($link, "INSERT INTO CountryLanguage VALUES (?, ?, ?, ?)");
mysqli_stmt_bind_param($stmt, 'sssd', $code, $language, $official, $percent);
$code = 'DEU';
$language = 'Bavarian';
$official = "F";
$percent = 11.2;
/* execute prepared statement */
mysqli_stmt_execute($stmt);
是的,我直接从PHP manual page on mysqli_stmt_bind_param.中删除了