1

首先,如果在其他地方回答了这个问题,我深表歉意,但我找不到任何东西。

我对以下代码有问题:

function register_user ($register_data) {
    global $db;
    array_walk ($register_data, 'array_sanitize');
    $register_data ['password'] = md5 ($register_data ['password']); 

    $fields = '`' . implode ('`, `', array_keys ($register_data)) . '`';
    $data   = '\'' . implode ('\', \'', $register_data) . '\'';

    $query = $db -> prepare ("INSERT INTO `users` (:fields) VALUES (:data)");
    $query -> bindParam (':fields', $fields);
    $query -> bindParam (':data', $data);
    $query -> execute ();
}

问题是这被正确执行但查询没有运行并且行没有插入数据库中。

现在,如果我这样做:

$query = $db -> prepare ("INSERT INTO `users` ($fields) VALUES ($data)");
//$query -> bindParam (':fields', $fields);
//$query -> bindParam (':data', $data);
$query -> execute ();

一切都像魅力一样,所以我猜问题在于我如何将数据传递给占位符。

有人可以向我解释为什么这不起作用吗?我想首先正确理解它。

提前感谢您的帮助。

4

1 回答 1

1

有两种不同的用例可以描述为将内爆数组传递给查询占位符。一种是IN()在 SQL 中使用带有子句的预处理语句。这个答案已经完全涵盖了这种情况。

另一个用例是插入辅助函数,就像您的问题中提到的那样。我有一篇文章解释了如何为 PDO_MYSQL 创建一个 SQL 注入证明插入辅助函数

鉴于这样的函数不仅向查询添加数据值,而且还向表名和列名添加数据,因此准备好的语句不足以防止 SQL 注入。因此,这样的函数将需要它自己的辅助函数,以保护命名的表和字段。这是 MySQL 的一个:

function escape_mysql_identifier($field){
    return "`".str_replace("`", "``", $field)."`";
}

现在我们终于可以有一个函数,它接受一个表名和一个包含数据的数组,并对数据库运行一个准备好的 INSERT 查询:

function prepared_insert($pdo, $table, $data) {
    $keys = array_keys($data);
    $keys = array_map('escape_mysql_identifier', $keys);
    $fields = implode(",", $keys);
    $table = escape_mysql_identifier($table);
    $placeholders = str_repeat('?,', count($keys) - 1) . '?';
    $sql = "INSERT INTO $table ($fields) VALUES ($placeholders)";
    $pdo->prepare($sql)->execute(array_values($data));
}

可以这样使用:

prepared_insert($pdo, 'users', ['name' => $name, 'password' => $hashed_password]);

完整的解释可以在上面链接的文章中找到,但简而言之,我们正在从输入数组键创建一个列名列表,并为 SQL VALUES() 子句创建一个逗号分隔的占位符列表。最后,我们将输入数组值发送到 PDO 的 execute()。安全、方便、简洁。

于 2013-08-21T09:53:47.673 回答