为准备好的语句动态生成类型定义字符串
Dynamically generate type definition string for prepared statement
我正在编写一个脚本,该脚本实质上是将数据从 API 加载到本地 MySQL 数据库中。这些值是可变的,具体取决于 API.
返回的内容
到目前为止,一切正常,直到我尝试将行实际插入到 MySQL 数据库中。具体来说,我知道我应该使用准备好的语句,但是当我尝试将变量绑定到准备好的语句时遇到了麻烦。当我尝试 运行 下面的代码时,我得到:
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/
我正在编写一个脚本,该脚本实质上是将数据从 API 加载到本地 MySQL 数据库中。这些值是可变的,具体取决于 API.
返回的内容到目前为止,一切正常,直到我尝试将行实际插入到 MySQL 数据库中。具体来说,我知道我应该使用准备好的语句,但是当我尝试将变量绑定到准备好的语句时遇到了麻烦。当我尝试 运行 下面的代码时,我得到:
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/