我有一个带有id
字段的用户表和10个其他字段,用于存储用户可以通过各种Web表单更改的各种类型的用户详细信息。我希望有一个PHP脚本为这些字段的某些子集获取POSTed更改的值,并且只更新POST数据中接收的那些字段。我发现这很难以一种不吸引人的方式做到。我们在本应用程序的其余部分使用mysqli进行所有数据库交互,因此非常喜欢基于mysqli的解决方案。
到目前为止我考虑和解雇的选项:
1)对POST数据中提供的每个字段运行一个单独的UPDATE
查询 - yuck,我不想在一个查询中完成一些事情,最多可以访问数据库10次的
2)将字段名称映射到字段的数据类型,并通过循环提供的字段迭代构造查询,检查它们是否是文本字段,在字符串字段上调用mysqli_real_escape_string
和否则清理其他人(例如通过类型检查或sprintf
与'%i'占位符)。 - 哎呀!如果我小心的话,我可以安全地用这种方式做事,但我不想养成使用这种方法的习惯,因为如果我不小心,我会让自己接受SQL注入。参数化查询不会让我有可能危险地搞砸,但这种方法确实如此。我的理想是永远不要手动将任何数据连接到SQL查询,并始终依赖参数化查询;其他语言的数据库,比如Python,让我轻松做到这一点。
3)使用参数化查询 - 这是我理想的一切,因为只要我通过mysqli语句对象的bind_param
方法将所有外部提供的数据插入到我的查询中,我就免疫了SQL注入并不必担心清理,但在这里使用参数化查询似乎是不可能的。问题是bind_param
要求将数据作为变量传递,因为第一个之后的所有参数都是通过引用传递的。我可以合理地优雅地迭代地构造一个带有?
占位符的查询,而我正在构建一个类型的字符串,作为第一个参数传递给bind_param
('ssiddsi'
等) ,但是我无法在运行时选择将我的10个字段中的哪一个传递给bind_params
(除非我有一个switch
语句,其中包含10 ^ 2个案例。)
是否有一些PHP语言构造我缺少(类似于数组解包),这将允许我在运行时选择哪些变量作为参数传递给bind_param
?或者是否有一些其他方法我没有考虑过让我能干净安全地解决这个简单问题?
答案 0 :(得分:2)
您可以通过我的SafeMySQL library轻松组合2和3。 代码看起来像
$allowed = array('title','url','body','rating','term','type');
$data = $db->filterArray($_POST,$allowed);
$sql = "UPDATE table SET ?u WHERE id=?i";
$db->query($sql, $data, $_POST['id']);
请注意,$allowed
数组不会使所有这些字段都必须更新 - 它只是过滤掉POST字段。因此,即使只有id和url的$ _POST也会正确更新。
尽管如此,使用准备好的陈述虽然很辛苦,但也很有可能。
答案 1 :(得分:-2)
请参阅以下代码
public function update($data, $table, $where) {
$data_str = '' ;
foreach ($data as $column => $value) {
//append comma each time after first item
if (!empty($data_str)) $data_str .= ', ' ;
$data_str .= "$column = $value" ;
}
$sql = "UPDATE $table SET $data_str WHERE $where";
mysqli_query($sql) or die(mysqli_error());
return true;
}
$ data是一个数组,在你的情况下它是$ _POST。
如果要更加具体地说明要从$ _POST数组保存的数据,可以定义允许列的数组。例如,
$allowed = array('id', 'username', 'email', 'password');
通过执行此操作,您可以过滤$ _POST数组并将其传递给update()函数。