【问题标题】:Dynamic select mysqli query with dynamic parameters returns error doesn't match number of bind variables具有动态参数的动态选择 mysqli 查询返回错误与绑定变量的数量不匹配
【发布时间】:2018-09-12 22:54:13
【问题描述】:

我正在尝试使用动态 where 子句和动态参数创建选择查询,但总是出错:

警告:mysqli_stmt::bind_param(): 类型中的元素数 定义字符串与绑定变量的数量不匹配

我真的不明白,因为计数似乎没问题。所以这就是代码在粗鲁格式下的真实样子。我看不出我做错了什么。

//get variables
$mediaArray ='Facebook,Twitter,Twitch,';
$otherMedia = 'House';

//convert string to array
$socialArray = explode(',', $mediaArray)

//declare some variables to be used later
$andwhere = '';
$bp = '';
$socialmarray = ''

 //get every value from array of social media
foreach($socialArray as $socialmedia){

    $socialmarray .=$socialmedia.',';
    $andwhere .= " AND socialmedianame=?";
    $bp .='s';
}

//test strings
echo $wheres = $andwhere;//AND socialmedianame=? AND socialmedianame=? AND socialmedianame=?
echo $bip = $bp.'s';//ssss
echo $validarayy = rtrim($socialmarray,',');//Facebook,Twitter,Twitch

//select query
$selectquery = $conn->prepare("select * from mediaservices where socialmedianame=? $wheres");
$selectquery->bind_param("$bip",$otherMedia,$validarayy);
$selectquery->execute();
$resultquery = $selectquery->get_result();

【问题讨论】:

  • 将所有关于 socialmedianame 的查询条件合并到一个批次中并使用:stackoverflow.com/a/48452420/2943403
  • @mickmackusa:感谢您的意见,但在查看了帖子后,我看不出它是如何重复的?
  • 我觉得我会复制我的答案以在此处重新发布。使用 IN 关键字而不是单独的多个 = 比较将使您生成的查询更加简洁并纠正您有缺陷的 WHERE 逻辑。我并不是在“抨击”你的问题——只是试图引导你和未来的研究人员找到我知道的合适的现有解决方案(因为我写了它)。
  • @mickmackusa:非常感谢您用我的代码回答。谢谢。

标签: php mysqli


【解决方案1】:

因为:

  1. 您正在使用用户提供的数据,您必须假设您的查询容易受到恶意注入攻击,并且
  2. 要构建到查询中的数据量是可变/不确定的,并且
  3. 您只是在单个表列上编写条件检查

您应该使用准备好的语句并将所有 WHERE 子句逻辑合并到单个 IN 语句中。

构建这个动态预处理语句比使用 pdo 更复杂(在语法方面),但这并不意味着你需要仅仅因为这个任务而放弃 mysqli。

$mediaArray ='Facebook,Twitter,Twitch,';
$otherMedia = 'House';

$media = array_unique(explode(',', $mediaArray . $otherMedia));
$count = count($media);

$conn = new mysqli("localhost", "root", "", "myDB");
$sql = "SELECT * FROM mediaservices";
if ($count) {
    $stmt = $conn->prepare("$sql WHERE socialmedianame IN (" . implode(',', array_fill(0, $count, '?')) . ")");
    $stmt->bind_param(str_repeat('s', $count), ...$media);
    $stmt->execute();
    $result = $stmt->get_result();
} else {
    $result = $conn->query($sql);
}
foreach ($result as $row) {
    // access values like $row['socialmedianame']
}

对于寻找类似动态查询技术的任何人:

【讨论】:

    【解决方案2】:

    在您的查询中:

    $selectquery = $conn->prepare("select * from mediaservices where socialmedianame=? $wheres");
    

    ? 代表一个要传入的参数,$wheres 的求值增加了另外三个,总共有四个参数。

    bind_param()应该将表示要插入的变量类型的字符串作为第一个参数,并将变量本身作为后续参数。

    在你的绑定中:

    $selectquery->bind_param("$bip",$otherMedia,$validarayy);
    

    $bip 的计算结果为 ssss$otherMedia 是单个字符串 ("House")。您可能认为$validarayy 是三个字符串,但rtrim() 返回一个字符串。因此,它只是 一个 字符串 ("Facebook,Twitter,Twitch")。当查询需要四个变量时,您会传递两个变量:

    $conn->prepare("select * from mediaservices where socialmedianame=House AND socialmedianame=Facebook,Twitter,Twitch AND socialmedianame=? AND socialmedianame=? AND socialmedianame=?"
    

    要更正此问题,您需要将 $validarayy 转换回数组,并将索引用于各种输入:

    $socialmarray2 = explode(',', $validarayy);
    $selectquery->bind_param("$bip", $otherMedia, $socialmarray2[0], $socialmarray2[1], $socialmarray2[2]);
    

    另请注意,您的示例代码缺少一些分号;您需要修复这些问题才能使您的代码正常工作。

    这可以看到工作here

    最后,请注意,即使您正确拆分了三个字符串,... AND socialmedianame=Facebook AND socialmedianame=Twitter AND socialmedianame=Twitch 的选择也不会匹配任何结果; socialmedianame 只能包含 一个 值。您可能希望将 AND 语句替换为 OR 语句。

    【讨论】:

    • 您的回答非常合理,谢谢。我需要说的是,我复制并硬编码了一个答案,在现实世界中是一个包含字符串的动态 $_Post。所以本质上我永远不知道数组中元素的数量。你会建议如何处理?使用 forloop?
    • 这正是我的链接解决方案来救援的情况。如果您无法根据需要进行调整,请询问我。
    猜你喜欢
    • 1970-01-01
    • 2012-09-24
    • 2016-12-20
    • 1970-01-01
    • 1970-01-01
    • 2012-08-04
    • 1970-01-01
    • 1970-01-01
    • 2021-06-04
    相关资源
    最近更新 更多