使用多个关键字搜索Mysql数据库

时间:2019-09-18 01:18:23

标签: php mysql pdo

我正在尝试在数据库中搜索$_POST['search']中传递的一个或多个关键字,但无法循环浏览这些关键字。

代码已从https://code-boxx.com/php-mysql-search/修改

我的脚本是:

$str = $_POST['search'];
$keywords = preg_split('/[\s]+/', $str);
$totalKeywords = count($keywords);
$query = "";
$i = 0;
while($keywords[i] != null)
{
    $query .= " AND name LIKE %".$keywords[i]."%" ;
}
$stmt = $pdo->prepare("SELECT * FROM MYTABLE WHERE MATCH (name) AGAINST (?) ". $query ." ");
$stmt->execute([$_POST['search']]);
$results = $stmt->fetchAll();

理想情况下,搜索应如下所示:

SELECT * FROM MYTABLE WHERE MATCH (name) AGAINST (Keyword1 Keyword2 Keyword3) AND name LIKE '%Keyword1%' AND name LIKE '%Keyword2%' AND name LIKE '%Keyword3%

搜索页面:

<?php
if (isset($_POST['search'])) {
  require "2.php";
}

?>
<!DOCTYPE html>
<html>
  <body>
    <!-- [SEARCH FORM] -->
    <form method="post">
      <input type="text" name="search" required/>
      <input type="submit" value="Search"/>
    </form>
    <!-- [SEARCH RESULTS] -->
    <?php
    if (isset($_POST['search'])) {
      if (count($results) > 0) {
        echo $sql;
        foreach ($results as $r) {
          printf("<div>%s</div>", $r['name']);
        }
      } else {
        echo "No results found";
      }
    }
    ?>
  </body>
</html>

感谢任何帮助。

1 个答案:

答案 0 :(得分:2)

在使用准备好的语句时,请避免将值直接注入查询语句中。您将失去为他们准备的目的。

因此,首先,您可以将陈述分为两部分。

一个是match against,两个是where like部分。

因此,首先构建基本查询:

$sql = "SELECT * FROM MYTABLE WHERE 1=1"; // base query

从那里开始,您可以在构建过程中追加对和的类似条款的匹配项。

然后,根据位创建匹配项:

MATCH (name) AGAINST (Keyword1* Keyword2* Keyword3* IN BOOLEAN MODE) // the ideal query
MATCH (name) AGAINST (? ? ? IN BOOLEAN MODE) // convert to question mark placeholders

要创建它,只需根据输入的数量将问号插入(粘上)空格即可。

$against_placeholder = implode(' ', array_fill(0, $totalKeywords, '?')); // = ? ? ?

并创建where like子句:

(name LIKE ? OR name LIKE ? OR name LIKE ?) // = like keyword1 or like keyword2 or like keyword3

所以在您的代码中:

$like_placeholder = implode(' OR ', array_fill(0, $totalKeywords, 'name LIKE ?'));

因此将它们拼凑在一起:

$against_placeholder = implode(' ', array_fill(0, $totalKeywords, '?'));
$like_placeholder = implode(' OR ', array_fill(0, $totalKeywords, 'name LIKE ?'));
$sql .= " AND MATCH (name) AGAINST ({$against_placeholder}) AND ({$like_placeholder})"; // build the query with placeholders

这将产生一个完整的查询语句,如下所示:

SELECT * FROM MYTABLE WHERE 1=1 AND (MATCH (name) AGAINST (? ? ? IN BOOLEAN MODE)) AND (name LIKE ? OR name LIKE ? OR name LIKE ?)

然后剩下的就是在执行中构建实际的有效负载。剩下的就是这

$sql = "SELECT * FROM MYTABLE WHERE 1=1"; // base query

$against_placeholder = implode(' ', array_fill(0, $totalKeywords, '?'));
$like_placeholder = implode(' OR ', array_fill(0, $totalKeywords, 'slug LIKE ?'));
$sql .= " AND (MATCH (slug) AGAINST ({$against_placeholder} IN BOOLEAN MODE)) OR ({$like_placeholder})"; // build the query with placeholders
// prep input
$against_keywords = array_map(function($value) {
    return "{$value}*";
}, $keywords);

$where_keywords = array_map(function($value) {
    return "%{$value}%";
}, $keywords);
$keywords = array_merge($keywords, $where_keywords);

$stmt = $pdo->prepare($sql);
$stmt->execute($keywords);
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);