【问题标题】:PHP Prepared Statement - Dynamic Vars Number of Element ErrorPHP Prepared Statement - 元素错误的动态变量数
【发布时间】:2017-11-15 13:43:03
【问题描述】:

我之前的问题已关闭,因为他们说这是重复的,但重复的帖子没有回答我的问题。所以我又来了,我在编辑部分添加了一些额外的 cmets 来说明为什么重复的帖子对我没有帮助。

我正在尝试动态构造一个准备好的语句,但我不断收到以下错误:

mysqli_stmt_bind_param():类型定义字符串中的元素个数 与

中的绑定变量数不匹配

当我回显我的语句时,类型定义的数量与绑定变量匹配,所以我不知道出了什么问题。我认为我的代码可能是在传递字符串、引号或其他东西而不是变量,但我是准备好的语句的新手,不知道如何检查我的查询。当使用简单的mysqli_query 时,我可以回显查询并查看我的错误所在。我不确定如何使用准备好的语句来做到这一点,所以我希望有人可以帮助发现我的错误。

我正在尝试动态构造 prepare 语句,以便我可以重用代码,如下所示:

$db = mysqli_stmt_init($dbconnection);

// I have looped through my fields and constructed a string that when 
// echoed returns this:
// ?, ?, ?, ?, 
// I use sub str just to remove the last comma and space leaving me 
// with the string
// ?, ?, ?, ?. 
// Ive echoed this to the browser to make sure it is correct.

$preparedQs = substr($preparedQs, 0, -2);

 // I then loop through each field using their datatype and constructs
 // the type string as follows ssss. Ive echoed this to the browser to 
 // make sure it is correct.

$preparedType = 'ssss';

 // I then loop through my post array verifying and cleaning the data 
 // and then it constructing a string of clean values that results in
 // Mike, null, Smith, Sr., (First, Middle, Last, Suffix) I use substr 
 // again just to remove the last comma and space. Ive echoed this to 
 // the browser to make sure it is correct.

    $cleanstr = substr($cleanstr, 0, -2);

 // I then explode that string into a an array that I can loop through 
 // and assign/bind each value to a variable as follows and use substr
 // again to remove last comma and space.

    $cleanstr = explode(", ", $cleanstr);
    $ct2 = 0;
    foreach ( $cleanstr as $cl){
        $name = "a".$ct2;
        $$name = $cl;
        $varstr .= "$".$name.", ";
        $ct2 = $ct2 +1;    
    }
   $varstr = substr($varstr, 0, -2);

 // I've echoed the $varstr to the browser and get $a1, $a2, $a3, $a4.
 // I have also echo their value outside of the loop and know values 
 // have been assigned.

 // I then try to assign each step above the appropriate 
 // prepared statement place holder

   $stmt = mysqli_stmt_prepare($db, "INSERT INTO Contacts VALUES (". $preparedQs. ")");
    mysqli_stmt_bind_param($db, "'".$preparedType."'", $varstr);
    mysqli_stmt_execute($stmt);

我不确定自己做错了什么,因为当我回显 $preparedQs$preparedType$varstr 它们都有相同数量的元素但我得到“mysqli_stmt_bind_param(): Number of类型定义字符串中的元素与...中的绑定变量数不匹配”错误。我所能想到的只是我有引号或不应该的东西,但我尝试在某些区域添加和删除引号并且无法解决错误。

另外,我阅读了一些关于在准备好的语句中传递 null 的帖子,但即使我将 null 替换为实际值,我仍然得到同样的错误。

可能值得注意的是,当使用简单的程序 mysqli_querymysqli_real_escape_string 清理我的数据时,一切正常。我试图通过将我的应用程序转换为准备好的语句来提高我的安全性,只是为了增加安全性。

这个问题的不同有两个原因

  1. 我使用的是过程编码,而不是对象或 PDO。因此,作为准备好的语句的新手,给出的示例即使在尝试理解它们之后也无济于事。

  2. 我使用的是插入语句,而不是选择或更新语句,在程序 php 中,查询字符串的写入方式与插入语句与选择或更新语句不同。

//更新代码

global $dbconnection;
if(!$dbconnection){
    die("Function wm_dynamicForm connection failed.</br>");
} else {
    //echo "</br>Function wm_connectionToDatabase connection success</br>";
}
$db = mysqli_stmt_init($dbconnection);
$preparedQs = substr($preparedQs, 0, -2); //removes the end , from my string
$cleanstr = substr($cleanstr, 0, -2); //removes the end , from my string
$cleanstr = explode(", ", $cleanstr);
$ct = 0;
foreach ( $cleanstr as $cl){
    $items[] = array(
        'a'.$ct => $cl,
    );
    $ct = $ct + 1;
}

$stmt = mysqli_stmt_prepare($db, "INSERT INTO Contacts VALUES (". $preparedQs. ")");
mysqli_stmt_bind_param($db, $preparedType, ...$items);
mysqli_stmt_execute($stmt);
if(!mysqli_stmt_execute($stmt)){ 
echo "Error: ".mysqli_error($db); 
}

【问题讨论】:

标签: php mysql prepared-statement


【解决方案1】:

尝试在准备好的语句中这样使用。

$servername = "localhost";
$username = "root";
$password = "";
$dbname = "test";
$conn = new mysqli($servername, $username, $password, $dbname);
$cleanstr = "John,Dew,Doe,Sr.";
$cleanstr = explode(",", $cleanstr);
$varstr=array();
foreach($cleanstr as $cl){
    $varstr[] = "$".$cl;
}

$operation = "INSERT INTO Contacts (firstname, middlename, lastname, suffix) VALUES (?, ?, ?, ?)";

$callfunc = insertCommon($conn,$varstr, $operation);

function insertCommon($conn,$varstr, $operation){
    $types = "";
    foreach($varstr as $value)
        $types .= "s";
    $varstr = array_merge(array($types),$varstr);
    $insertQry = $conn->prepare($operation);
    $refArray = array();
    foreach($varstr as $key => $value) $refArray[$key] = &$varstr[$key];
    call_user_func_array(array($insertQry, 'bind_param'), $refArray);
    $insertQry->execute();
    return true;
}

【讨论】:

  • 每个人都以同样的方式回应。我完全理解准备好的语句的结构,所以我不需要有人直接插入准备好的语句的结构并说这应该可以工作....我遇到的问题是我的绑定参数不起作用,因为我通过了一个字符串而不是单个变量。我需要有人向我展示如何将绑定参数中的字符串(通过循环创建)转换为单个变量。现在它正在传递一个字符串“$first, $middle $last”。 1 个 var 而不是 3 个单独的 var。我如何将字符串变成 $first, $middle $last 变量???
  • @user982853 我正在编辑我的代码。希望它可以帮助你。
【解决方案2】:

您可以使用 php 5.6 的功能进行动态绑定,称为解包运算符/省略号 ...

$db = mysqli_connect('localhost', 'root', 'pass', 'database');


$data = array('name' => 'foo', 'age' => 99, 'email' => 'abc@abc.com');

$stmt = mysqli_stmt_prepare($db, "INSERT INTO Contacts VALUES (". $preparedQs. ")");
mysqli_stmt_bind_param($db, $preparedType, ...$data);
mysqli_stmt_execute($stmt);

【讨论】:

  • 谢谢,因为这似乎摆脱了我的第一个错误,即我的数字不匹配,但现在我得到了错误:mysqli_stmt_execute() 期望参数 1 是 mysqli_stmt,布尔值在....任何知道为什么?
  • @user982853 表示查询失败,得到错误信息:if(!mysqli_stmt_execute($stmt)){ echo mysqli_error($db); }
  • mysqli_error() 期望参数 1 是 mysqli,给定对象
  • @user982853 您的连接变量的名称是什么?你必须把它传递给mysqli_error()
  • ……成功了。我的代码中也有一个错误,将我的所有变量都转换为字符串,这就是我遇到第二个错误的地方。但由于它与我最初的问题有关,...省略号解开了我的变量。谢谢。
【解决方案3】:

以前来过,动态准备语句,动态查询准备。

到目前为止,问题不在于您的代码,而在于您动态准备绑定的 sql 字段数组。 该数组的索引从零(0)开始,但您的 bindValue 的索引需要以一(1)开始。 所以你要做的就是让你的字段数组索引从 1 开始。

在 php 中,您可以强制数组的默认索引以 1 而不是 0 开始。

如果没有错,你有:

 dbfield="username, password, name"

dbvalue="?, ?, ?"

你有一个输入值数组,你正在循环使用:

 foreach($inputarray as $key=>$value){
 // key index must start from 1

 //now you can bind
 bindValue($key, $value);
 }

如果我正在流动,请回答接受。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多