2

我有一个用户表和id字段和 10 个其他字段,用于存储用户可以通过各种 Web 表单更改的各种类型的用户详细信息。我想要一个 PHP 脚本来获取这些字段的某些子集的 POST 更改值,并且只更新在 POST 数据中收到的那些字段。我发现以一种不糟糕的方式很难做到这一点。我们在此应用程序的其余部分中使用 mysqli 进行所有数据库交互,因此强烈首选基于 mysqli 的解决方案。

到目前为止我已经考虑并驳回的选项:

1) 为 POST 数据中提供的每个字段运行单独的UPDATE查询 -糟糕,我不想在一次查询中完成最多 10 次的数据库访问。

2)有一个字典将字段名称映射到字段的数据类型,并通过循环提供的字段来迭代构造查询,检查它们是否是文本字段,调用mysqli_real_escape_string字符串字段并以其他方式清理其他字段(例如按类型检查或sprintf使用 '%i' 占位符)。-呸!如果我小心点,我可能可以安全地这样做,但我不想养成使用这种方法的习惯,因为如果我不小心,我会让自己对 SQL 注入持开放态度。参数化查询不会给我带来危险的可能性,但这种方法可以。我的理想是永远不要手动将任何数据连接到 SQL 查询中,并且始终依赖参数化查询;其他语言的数据库库,如 Python,

3) 使用参数化查询 - 这是我对所有事情的理想选择,因为只要我通过bind_parammysqli 语句对象的方法将所有外部提供的数据插入到我的查询中,我就不会受到 SQL 注入的影响并且不必担心清理,但在这里使用参数化查询似乎是不可能的。问题是bind_param需要将数据作为变量传递,因为第一个参数之后的所有参数都是通过引用传递的。我可以相当优雅地迭代地构造一个带有?占位符的查询,当我在它构造作为第一个参数传递给bind_param'ssiddsi'等)的类型字符串时,我无法在运行时选择哪个我传递给我的 10 个字段bind_params(除非我有一个switch包含 10^2 个案例的声明)。

是否有一些我缺少的 PHP 语言结构(类似于数组解包的东西)允许我在运行时选择哪些变量作为参数传递给bind_param?或者有没有其他我没有考虑过的方法可以让我干净安全地解决这个简单的问题?

4

2 回答 2

2

您可以通过我的SafeMySQL 库轻松组合 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 也会被正确更新。

尽管如此,使用准备好的语句虽然很麻烦,但也很有可能。

于 2013-01-24T20:38:10.303 回答
-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() 函数。

于 2016-06-17T18:11:44.170 回答