我正在编写一个脚本,基本上是将数据从API加载到本地MySQL数据库.根据API返回的内容,这些值是可变的.

到目前为止,一切都很正常,直到我try 将这些行插入MySQL数据库.具体来说,我知道我应该使用prepared语句,但当我试图将变量绑定到prepared语句时,我遇到了麻烦.当我try 运行以下代码时,我得到:

PHP Warning:  mysqli_stmt::bind_param(): Number of elements in type definition string doesn't match number of bind variables in /opt/awn2sql/functions.php on line 212

下面是有问题的代码:

$readingValues = array_values($read); //array of just the values in the original array
array_push($readingValues, $devicemac); //add the MAC address of the device that recorded the reading to the array
    
$columns = implode(", ",$readingTypes); //create a string of column names to build the SQL query
    
$valuesCount = count($readingValues); //get a count of the values to fill an array with placeholders
$stmt_placeholders = implode(',',array_fill(0,$valuesCount,'?')); //fill an array with placeholders (i.e. ?,?,?) - see above
$stmt_param = null; //$stmt_param will hold the type definitions string for binding the 
    
foreach ($readingValues as $param) { //iterate through each value in the $readingValues array, get the type, and add it to the type definitions string
    if (gettype($param) == 'integer')
    {
        $stmt_param = $stmt_param.'i';
    }
    else if (gettype($param) == 'double')
    {
        $stmt_param = $stmt_param.'d';
    }               
    else if (gettype($param) == 'string')
    {
    $stmt_param = $stmt_param.'s';
    }
    else if (gettype($param) == 'blob')
    {
        $stmt_param = $stmt_param.'b';
    }
    else
    {
        echo "Invalid data type!";
    }
}

$val_insert_query = "INSERT INTO ".$config['mysql_db'].".readings (".$columns.") VALUES (".$stmt_placeholders.");"; //Template for the query
    
$stmt=$mysqli->prepare($val_insert_query); //Prepares the template for the query for binding, prepared statement becomes $stmt

echo ($stmt_param." (".strlen($stmt_param).")\n"); //for debugging, echo the type definiton string and get its length (which should match the number of values)

echo (count($readingValues)); //count the number of values, which should match the number of elements in the type defintion string
    
$stmt->bind_param($stmt_param, $readingValues); //Binding
    
$stmt->execute(); //execute the statement

我坦率地承认,我在这方面有点新手,所以我愿意接受任何关于如何做得更好的建议.值得一提的是,从来没有任何直接的用户输入,所以我相对不关心安全问题,如果这对如何最好地实现这一点有影响的话.

提前谢谢!

推荐答案

bind_param()实际上接受变量参数,而不是数组参数.但现代PHP有将数组转换为多个标量参数的语法:

$stmt->bind_param($stmt_param, ...$readingValues); //Binding

这相当于将数组元素作为单个参数传递:

$stmt->bind_param($stmt_param, $readingValues[0], $readingValues[1],
    $readingValues[2], etc.);

但如果你不知道数组中有多少个元素,那就很尴尬了.


仅供参考,我喜欢使用PDO而不是mysqli.无需绑定任何内容,只需将值数组作为参数传递给execute():

$stmt=$pdo->prepare($val_insert_query); 

$stmt->execute( $readingValues );

我发现PDO要容易得多.使用mysqli的原因是如果你有很多2000年中期遗留的代码需要修改.如果你刚刚开始,你没有旧代码.所以你不妨先采用PDO.

PDO有一个很好的教程:https://phpdelusions.net/pdo/

Php相关问答推荐

将带有值的属性添加到WooCommerce产品,保留现有属性

致命错误:无法使用简单的php博客重新声明spl_autoload_Register()

Symfony Api平台:按自定义实体方式排序结果

使用.htaccess将任何路由重定向到文件

PHP:PHP手册-Manual

PHP测试字符串的所有POST值

在WordPress中从CPT中删除插件

从字符串转换日期和/或时间时,Laravel转换失败

Laravel路由到控制器传输变量解决方案需要

按类别层次 struct 过滤 Laravel 集合

如何在 Woocommerce 中自动删除旧的已完成订单

我不明白为什么我收到未定义的数组键异常错误 - Laravel 9 PHP 8

如何判断php中wordpress路径之外的文件夹是否存在?

在 WordPress 中将自定义帖子类型永久链接设置为 root

根据所选付款方式启用/禁用 WooCommerce 所需的 checkout 字段

加载 Xdebug PHP 7.4.0 失败

PHP 中是否有 is_closure() 函数?

正则表达式抓取递归括号的内容

标头内容类型:image/jpeg 无效

从 d-m-Y 日期格式 laravel 计算月份 = 01 的列的总和