【问题标题】:Prepared Statements not returning the required multiple results准备好的语句没有返回所需的多个结果
【发布时间】:2022-01-05 18:57:27
【问题描述】:

在得到How to perform a LIKE query using multiple keywords from search field using mysqli prepared statement 的帮助后,我做了这个功能,但做了一些更改,因为我只有一个搜索参数。

function searchResult($con, $search) {
   $keywords = explode(" ", $search);
   $total_keywords = count($keywords);
   $myquery = "SELECT * FROM products WHERE name LIKE CONCAT('%',?,'%')";
      for ($i=1 ; $i < $total_keywords; $i++) {
          $myquery .= " OR name LIKE CONCAT('%',?,'%')";
      }
   $stmt = mysqli_stmt_init($con);
   //check if the statement is not prepared
   if (!mysqli_stmt_prepare($stmt, $myquery)) {
       header("location: search.php?errorid=stmt_failed");
       exit();
   }
   $typeparam = '';
   foreach ($keywords as $key => $value) {
       $typeparam .= 's';
   }
   $bind_param = array();
   $bind_param[] =& $typeparam;
   foreach ($keywords as $key => $value) {
       $bind_param[]=&$keywords[$key];
   }
   call_user_func_array(array($stmt,'bind_param'), $bind_param);
   mysqli_stmt_execute($stmt);
   $matches = mysqli_stmt_get_result($stmt);
   if ($searches = mysqli_fetch_assoc($matches)) {
       return $searches;
   } else {
       $result = false;
       return $result;
   }
   mysqli_stmt_close($stmt);
}

现在,我有一个名为 products 的表,在该表中我有:

尼康油漆桶

砖块

亚洲油漆 2 升蓝色饰面

PVC管

当我只搜索砖块时,它返回 砖块,同样返回所有其他产品。但是,通过搜索 bricks paint,它只返回 Nikon Paint bucket,但它应该返回 Bricks 以及表中的 Paint 结果。所以,有两个问题,一个是它没有考虑多个关键字。另一个问题是,它不会返回具有相同关键字的两个结果。

此外,Prepared statements 是防止 SQL 注入的最佳方法,但在搜索栏中使用它是否明智,因为 mysqli_real_escape_string() 似乎效率低下。有没有其他方法可以制作安全的搜索栏?

【问题讨论】:

  • 你为什么不使用 PDO?
  • 如果我是你,我会完全忘记mysqli_real_escape_string的存在。不要走那条路。只需要一直使用准备好的语句。
  • 我明白你关于逃跑的观点。另外,我对 PDO 不太熟悉,但看起来 PDO 相当可靠,而且付出更多。所以,PDO 是前进的方向。

标签: php mysqli


【解决方案1】:

您的函数只返回结果集中的一行。调用 mysqli_fetch_assoc() 只会产生一行。

如果你想从结果集中获取所有行,你应该调用mysqli_fetch_all()。我已经清理了实现并使用了mysqli_fetch_all(),它会给你一个行数组。

function searchResult(mysqli $con, string $search): array
{
    $keywords = explode(" ", $search);
    $total_keywords = count($keywords);
    $myquery = "SELECT * FROM products WHERE name LIKE CONCAT('%',?,'%')";
    for ($i = 1; $i < $total_keywords; $i++) {
        $myquery .= " OR name LIKE CONCAT('%',?,'%')";
    }
    $stmt = mysqli_prepare($con, $myquery);
    mysqli_stmt_bind_param($stmt, str_repeat('s', $total_keywords), ...$keywords);
    mysqli_stmt_execute($stmt);
    $matches = mysqli_stmt_get_result($stmt);

    return mysqli_fetch_all($matches, MYSQLI_ASSOC);
}

别忘了启用mysqli error reporting

但是,如果可以,我强烈建议您使用 PDO。 PDO 更容易使用。考虑使用 PDO 实现相同的功能:

function searchResult(PDO $con, string $search): array
{
    $keywords = explode(" ", $search);
    $total_keywords = count($keywords);
    $myquery = "SELECT * FROM products WHERE name LIKE CONCAT('%',?,'%')";
    for ($i = 1; $i < $total_keywords; $i++) {
        $myquery .= " OR name LIKE CONCAT('%',?,'%')";
    }
    $stmt = $con->prepare($myquery);
    $stmt->execute($keywords);
    return $stmt->fetchAll(PDO::FETCH_ASSOC);
}

【讨论】:

  • 这个答案有效,看起来 mysql_fetch_assoc() 毕竟是问题所在。但是,如果我可能会问,您为什么在 bind_param 中使用 $keywords 之前的三个点?此外,我如何在搜索中跳过下划线,因为每当我搜索 _ 它返回完整的表。 PDO 解决方案也可以正常工作,而且要简单得多。再次感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 2019-07-16
  • 1970-01-01
  • 1970-01-01
  • 2021-08-02
  • 1970-01-01
  • 1970-01-01
  • 2011-01-23
  • 2014-09-15
相关资源
最近更新 更多