0

我正在使用此代码更新 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

(无法使用占位符调用列,因为我不知道表中的列名)

4

2 回答 2

0

使用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 这样的自由格式应用程序是一个罕见的例外,显然情况并非如此。

毕竟,这是安全问题。2 个危险来自自由形式的数组:

  1. 表中可能存在不允许客户使用的字段。而且您肯定会重用此代码来让客户编辑他们的详细信息。因此,始终知道必须更新的字段要好得多。
  2. 通过命名占位符的普通 SQL 注入(您可能会注意到它们直接来自未触及的用户输入)。

因此,如果您 100% 确定不能添加任何人工场 - 您可以忽略此检查,但您会将自己置于持续的危险之中。无论如何都必须在字段名称上使用带有 str_replace 的东西,而必须使用位置 (?) 占位符而不是命名占位符。

于 2013-09-02T17:57:19.080 回答
0

当您确保 的值是安全的时,这才$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']));
         }

      }    
}

更新 请注意,您在循环中使用循环,为了提高效率,请考虑更改您的代码。

于 2013-09-02T17:57:42.693 回答