【问题标题】:Loop through array in bind parameters - prepared statement在绑定参数中循环遍历数组 - 准备好的语句
【发布时间】:2019-12-26 22:15:12
【问题描述】:

我正在编写一个函数,我可以在其中执行几个数据库操作,在本例中是基于简单数组的插入数据

"insert" => array (
    "1" => array (
        "tnt_role" => array (
            "rolename" => array (
                "value" => "administrator",
                "notation" => "string"
            )
        )
    ),  
    "2" => array (
        "tnt_role" => array (
            "rolename" => array (
                "value" => "user",
                "notation" => "string"
            )
        )
    ),
    "3" => array (  
        "tnt_users" => array (
            "username" => array (
                "value" => "administrator",
                "notation" => "string"
            ),
            "userpassword" => array (
                "value" => md5('admin', FALSE),
                "notation" => "string"
            ),
            "email" => array (
                "value" => "someone@something.com",
                "notation" => "string"
            ),
            "roleid" => array (
                "value" => "1",
                "notation" => "int"
            )
        )
    )   
)

这里是函数的具体部分

case "insert":
    foreach ($tables as $instance => $inserttables) {
        foreach ($inserttables as $table => $fields) {
            // create a count on the number of fields that are being parsed
            $countfields = count($fields);
            $sql = "INSERT INTO ". $table ." (" ;
            $i = 0;
            // set up the columns for the insert statement
            foreach ($fields as $field => $value) {     
                $i++;
                $sql .= $field;
                if ($countfields != $i ) {
                    $sql .= ", ";
                }
            }
            // close the column statement, open the value statement, since this is prepared, we will add question marks and add later the values
            $sql .= ") ";
            $sql .= "VALUES (";
            $i = 0;
            $parameters = "";
            $notation = "";
            foreach ($fields as $field => $value) {     
                $i++;
                $sql .= "?";
                // set up the notation in the bind parameters
                switch($value['notation']) {
                    case "int":
                        $notation .= "i";
                        break;
                    case "string":
                        $notation .= "s"    ;
                        break;  
                }
                // need to escape the email and username values 
                $parameters .= "'".$value['value']."'" ;
                if ($countfields != $i ) {
                    $sql .= ", ";
                    $parameters .= ", ";
                }
            }
            $sql .= ")";

            $stmt = mysqli_prepare($con, $sql);
            mysqli_stmt_bind_param($stmt, $notation, $parameters);
            if(mysqli_stmt_execute($stmt)) {
                    echo "data entered";
            } else {
                echo "error in following query:". $sql; 
            }                               
        }
    }
    break;

这一切都很好,除了 1 个小东西,那就是当我在数据库中输入超过 1 个项目时。它给了我以下错误

mysqli_stmt_bind_param():类型定义字符串中的元素个数 与 .... 第 647 行中的绑定变量数不匹配

过了一会儿,我意识到参数变量就是这种情况。这里的 bind 参数只有 1 个变量,我用逗号很好地将它们分开(为了模仿列表)。查看这个光学会说这看起来不错,但是我认为绑定参数语句确实需要单独的变量。此时它实际上只看到一个变量,而不是我的测试用例中的 4。

我试过这样循环:

mysqli_stmt_bind_param($stmt, $notation, 
    foreach ($fields as $field => $value) {     
        echo $value['value'];
        if ($countfields != $i ) {
            echo ",";
        }
    }
);

但无济于事,因为它会吐出以下内容。

解析错误:语法错误,意外'foreach' (T_FOREACH) in

有人知道如何解决这个问题吗?

== 编辑 ==

请求的表结构,虽然我怀疑是那个问题,因为我得到一个绑定参数错误,而不是执行语句时的错误。

== 编辑 2 ==

还尝试了以下方法,但没有帮助,因为它没有堆叠(我在 PDO 中看到了这个)

foreach ($fields as $field => $value) { 
    switch($value['notation']) {
        case "int":
            $notation = "i";
            break;
        case "string":
            $notation = "s" ;
            break;  
    }
    mysqli_stmt_bind_param($stmt, $notation, $value['value']);
}

【问题讨论】:

  • 你的数据库结构是什么样的?
  • 这与我的数据库无关,它纯粹是那部分,因为我可以毫无问题地填写我的角色表(它只是一个 id 和一个描述,然后我只输入描述)。如果您必须知道,我添加了它的结构图片,此时非常简单@gview
  • 附带说明一下,使用 PDO 甚至更好的东西(例如 DB 抽象类)会更容易,例如EasyDB。
  • 我强烈建议您看看phpdelusions.net/mysqli/simple 上的一些教程,如果您已经被它所困扰,他们会解释如何正确使用 mysqli。
  • 好的。查看password_hash() 和其中的相关链接。也不需要加盐,它会处理所有这些。另外,如果您使用的是 PHP 7,则可以从使用更强大的 Argon2 中受益。

标签: php mysqli prepared-statement


【解决方案1】:

您需要将每个变量单独传递给mysqli_stmt_bind_param,因此$parameters 需要是一个数组,而不是字符串。更改以下代码行:

$parameters = "";

到:

$parameters = array();

$parameters .= "'".$value['value']."'" ;

到:

$parameters[] = $value['value'];

(注意,使用准备好的语句时不需要转义值)

删除这一行:

$parameters .= ", ";

最后,改变

mysqli_stmt_bind_param($stmt, $notation, $parameters);

到:

mysqli_stmt_bind_param($stmt, $notation, ...$parameters);

它应该可以正常工作。

【讨论】:

  • @Dharman 我花了很多时间寻找副本但找不到 - 你有一个好的链接吗?
  • 不,我收集的链接非常少。我不喜欢强制关闭重复的问题。
  • @Dharman 我支持你,但之前与某人就这件事发生了争执——网站上肯定有两种思想流派。
  • @Nick 非常感谢您提供的解决方案,它确实可以解决问题。你能解释一下参数变量之前的句点是什么吗?我从来没有见过这个。我知道可以在某个地方传递一个数组,但我不知道如何访问它,这显然是我的问题的解决方案。我接受它作为遮阳篷。
  • @Dorvalla 句点是splat 运算符。它可用于组装数组,也可用于将它们解包到参数列表中。还有更多信息here
猜你喜欢
  • 2015-06-08
  • 1970-01-01
  • 1970-01-01
  • 2013-10-05
  • 1970-01-01
  • 2015-07-13
  • 1970-01-01
  • 2016-09-04
  • 1970-01-01
相关资源
最近更新 更多