【问题标题】:SQL full text search with PHP and PDO使用 PHP 和 PDO 进行 SQL 全文搜索
【发布时间】:2011-07-27 20:14:17
【问题描述】:

我正在尝试使用 PHP 和 PDO 编写一个简单的全文搜索。我不太确定通过 SQL 和 PDO 搜索数据库的最佳方法是什么。我找到了这个 this 脚本,但它是旧的 MySQL 扩展。我写了这个函数,女巫应该计算搜索匹配,但 SQL 不起作用。传入的搜索字符串如下所示:23+more+people

function checkSearchResult ($searchterm) {
    //globals
    global $lang; global $dbh_pdo; global $db_prefix;
    $searchterm = trim($searchterm);
    $searchterm = explode('+', $searchterm);
    foreach ($searchterm as $value) {
        $sql = "SELECT COUNT(*), MATCH (article_title_".$lang.", article_text_".$lang.") AGINST (':queryString') AS score FROM ".$db_prefix."_base WHERE MATCH (article_title_".$lang.", article_text_".$lang.") AGAINST ('+:queryString')";
        $sth = $dbh_pdo->prepare($sql);
        $sql_data = array('queryString' => $value);
        $sth->execute($sql_data);
        echo $sth->queryString;
        $row = $sth->fetchColumn();
        if ($row < 1) {
            $sql = "SELECT * FROM article_title_".$lang." LIKE :queryString OR aricle_text_".$lang." LIKE :queryString";
            $sth = $dbh_pdo->prepare($sql);
            $sql_data = array('queryString' => $value);
            $sth->execute($sql_data);
            $row = $sth->fetchColumn(); 
        }
    }
    //$row stays empty - no idea what is wrong
    if ($row > 1) {
        return true;
    }
    else {
        return false;
    }
}

【问题讨论】:

    标签: php sql pdo


    【解决方案1】:

    准备$sql_data数组时,需要在参数名前加上冒号:

    array('queryString' => $value);
    

    应该是:

    array(':queryString' => $value);
    

    在您的第一个 SELECT 中,您使用的是 AGINST 而不是 AGAINST

    您的第二个SELECT 似乎在FROMWHERE 子句之后缺少表名。 LIKE 参数的格式也不正确。它应该是这样的:

    sql = "SELECT * FROM ".$db_prefix."_base WHERE article_title_".$lang." LIKE '%:queryString%' OR aricle_text_".$lang." LIKE '%:queryString%'";
    

    更新 1 >>

    对于两个 SELECT 语句,您需要每个参数的唯一标识符,并且LIKE 通配符应该放在值中,而不是语句中。所以你的第二个语句应该是这样的:

    sql = "SELECT * FROM ".$db_prefix."_base WHERE article_title_".$lang." LIKE :queryString OR aricle_text_".$lang." LIKE :queryString2";
    

    注意queryString1queryString2,不带引号或% 通配符。然后你也需要更新你的数组:

    $sql_data = array(':queryString1' => "%$value%", ':queryString2' => "%$value%");
    

    有关使用具有相同值的多个参数的详细信息,请参阅PDOStatement->execute参数 部分。因此,我倾向于使用问号作为占位符,而不是命名参数。我觉得它更简单、更整洁,但这是一个选择问题。例如:

    sql = "SELECT * FROM ".$db_prefix."_base WHERE article_title_".$lang." LIKE ? OR aricle_text_".$lang." LIKE ?";
    
    $sql_data = array("%$value%", "%$value%");
    

    我不确定第二个SELECT 是做什么用的,因为我原以为如果第一个SELECT 没有找到查询值,那么第二个也找不到它。但是我对 MySQL 全文搜索做的不多,所以我可能会遗漏一些东西。

    无论如何,您确实需要仔细检查 SQL 和任何错误。打印PDOStatement-&gt;errorCode的结果可以得到错误信息:

    $sth->execute($sql_data);
    $arr = $sth->errorInfo();
    print_r($arr);
    

    更新 2 >>

    还有一点值得一提:确保在将变量插入 SQL 语句时,只使用可信数据。也就是说,不允许用户提供的数据用于表名或列名。使用准备好的语句很好,但这些只保护参数,而不是 SQL 关键字、表名和列名。所以:

    "SELECT * FROM ".$db_prefix."_base"
    

    ...正在使用变量作为表名的一部分。确保此变量包含可信数据。如果它来自用户输入,请先对照白名单进行检查。

    您应该阅读MySQL Full-Text Search FunctionsString Comparison Functions。您需要学习如何构建基本的 SQL 语句,否则即使是编写一个简单的搜索引擎也会变得非常困难。

    PHP 网站上也有很多 PDO 示例。您可以从 PDOStatement->execute 的文档开始,其中包含一些如何使用该函数的示例。

    如果您可以访问MySQL CLI,甚至是 PHPMyAdmin,您可以尝试您的 SQL,而不会让所有 PHP 混淆。如果您打算将任何数据库开发工作作为 PHP 应用程序的一部分进行,那么您会发现能够独立于 PHP 测试 SQL 会有很大帮助。

    【讨论】:

    • 感谢您的详细解答!我相应地更改了 SQL 并删除了 MySQL 特定的 MATCH 操作。我将 SQL 更改为 SELECT COUNT(*) FROM ".$db_prefix."_base WHERE article_content_title_".$lang." LIKE '%:queryString%' OR article_content_text_".$lang." LIKE '%:queryString%',但 queryString 没有被替换。与上面的代码相同,但修复了您指出的语法错误。知道为什么吗?
    • @wowpatrick:当你说queryString没有被替换时,你的意思是当你回显语句时,参数(:queryString部分)没有被你的用户替换-提供的字符串?如果是这样,这就是准备好的语句的工作方式。语句和参数分别发送到 MySQL。客户端(在本例中为 PHP)不会将两者结合起来。因为它们是分开发送的,所以 MySQL 知道哪些位是语句,哪些位是参数,所以它不必解析它来查找。这就是为什么它可以很好地防御 SQL 注入。
    • @wowpatrick:如果想看合并语句,可以查看MySQL General Query Log。默认情况下它是禁用的,因此请务必先阅读文档以了解如何启用和使用它。另外,您是否在 PHP 代码中添加了该行以显示可能发生的任何错误?
    • 是的,我添加了这一行,完全没有错误。如果我将 :queryString 替换为应该替换的字符串,则查询工作正常,不知道为什么它没有被替换。
    • 我想我知道它是什么。查看PDOStatement->execute 文档的Parameters 部分。每个参数只能绑定一次。因此,您需要将参数更改为queryString1queryString2,并相应地更新您的数组。我会更新我的答案...
    猜你喜欢
    • 1970-01-01
    • 2011-03-21
    • 2015-11-03
    • 1970-01-01
    • 2012-11-20
    • 1970-01-01
    • 2014-04-13
    • 2012-05-07
    • 2011-05-17
    相关资源
    最近更新 更多