我使用这段代码更新mysql表中的字段。
foreach ($_POST['changed'] as $SubArray) {
foreach ($SubArray as $key => $value) {
if ($key === 'recid') continue;
$STH = $DBH->prepare("UPDATE clients SET $key = '$value' WHERE id = $SubArray[recid]");
$STH->execute();
}
}
我认为查询中的$key
、$value
和$SubArray[recid]
等变量是非常不安全的。有没有一种方法可以确保这一点的安全,即$_POST
不会让不需要的代码进入查询?
(用占位符调用列是不可能的,因为我不知道表中的列名)
只有在确保$key
的值是安全的情况下,这才是安全的。例如:
$approved = array('fname', 'lname' ,'email');
foreach ($_POST['changed'] as $SubArray) {
foreach ($SubArray as $key => $value) {
// if ($key === 'recid') continue; (Since we're using in_array - no need in this line)
if(in_array($key , $approved))
{
//$key is safe:
$STH = $DBH->prepare("UPDATE clients SET $key = :value WHERE id = :id");
$STH->execute(array(':value' => $value , ':id' => $SubArray['recid']));
}
}
}
更新请注意,您使用的是循环中的循环,为了提高效率,请考虑更改代码。
有了safeMysql,这就是小菜一碟:
include 'safemysql.class.php';
$db = new safeMysql();
$allowed = array('name', 'surname', 'all the fields you want to save');
foreach ($_POST['changed'] as $SubArray)
{
$insert = $db->filterArray($SubArray, $allowed);
$db->query("UPDATE clients SET ?u WHERE id = ?s", $insert, $SubArray['recid']);
}
而有缺陷的PDO会给你带来更多的麻烦
首先,您需要使用一个函数来动态创建值列表,因为没有一个理智的开发人员会逐个更新字段:
function pdoSet($fields, &$values, $source = array()) {
$set = '';
$values = array();
if (!$source) $source = &$_POST;
foreach ($fields as $field) {
if (isset($source[$field])) {
$set.="`".str_replace("`","``",$field)."`". "=:$field, ";
$values[$field] = $source[$field];
}
}
return substr($set, 0, -2);
}
现在你可以开始运行你的更新
$allowed = array('name', 'surname', 'all the fields you want to save');
foreach ($_POST['changed'] as $SubArray)
{
$set = pdoSet($allowed, $values, $SubArray);
$sql = "UPDATE clients SET $set WHERE id = :id";
$stm = $dbh->prepare($sql);
$values["id"] = $SubArray['recid'];
$stm->execute($values);
}
回答评论中的问题:
首先,一个不了解自己领域的开发人员是胡说八道。不可能。像phpmyadmin这样的自由格式应用程序是一个罕见的例外,但事实显然并非如此。
毕竟,这是一个安全问题。自由形式阵列存在两种危险:
- 表中可能有客户不允许的字段。您肯定会重用这些代码,让客户编辑他们的详细信息。因此,最好总是知道必须更新的字段
- 通过命名占位符的纯SQL注入(正如您可能注意到的那样,它们直接从用户输入开始)
因此,如果你100%确定不能添加任何人工场,你可能会省略这个检查,但你会把自己置于持续的危险之中。无论如何,str_replace必须用于字段名称,而必须使用位置(?)占位符而不是命名占位符。