2011-07-27 57 views
0

我正在尝试使用PHP和PDO编写一个简单的全文搜索。我不太确定最好的方法是通过SQL和PDO搜索数据库。我发现这个this脚本,但它是旧的MySQL扩展。我写这个函数的女巫应计算搜索匹配,但SQL不起作用。传入的搜索字符串看起来像这样:23+more+people使用PHP和PDO进行SQL全文搜索

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; 
    } 
} 

回答

2

当你准备$sql_data数组,你需要用冒号前缀参数名:

array('queryString' => $value); 

应该是:

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

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

你的第二个SELECT出现于FROM后缺少一个表名和一个WHERE条款。 LIKE参数的格式不正确。它应该是这样的:

更新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%"); 

< <更新1

我不知道什么是第二SELECT是,因为我本来以为,如果第一SELECT没有找到查询结束价值,第二个也不会找到它。但是我没有用MySQL全文搜索做很多事情,所以我可能会错过一些东西。

无论如何,你真的需要仔细检查SQL和任何错误。

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

更新2 >>

还有一点值得一提:您可以通过打印的PDOStatement->errorCode结果得到错误信息,请确保当你插变量到你的SQL语句,您仅使用可信数据。也就是说,不允许用户提供的数据用于表名或列名。使用预准备语句很好,但这些只保护参数,而不是SQL关键字,表名和列名。所以:

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

...使用变量作为表名的一部分。确保该变量包含可信数据。如果它来自用户输入,请首先检查白名单。更新1

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

PHP站点上也有大量的PDO示例。您可以从PDOStatement->execute的文档开始,其中包含一些如何使用该功能的示例。

如果您有机会获得MySQL CLI,甚至PHPMyAdmin的,你可以尝试一下你的SQL没有所有的PHP困惑的事情。如果你打算做任何数据库的开发工作作为你的PHP应用程序的一部分,你会发现能够独立测试SQL PHP有很大的帮助。

+0

感谢您的详细解答!我相应地更改了SQL,并删除了MySQL特定的MATCH操作。我改变了对SQL SELECT'COUNT(*) \t \t \t FROM “$ db_prefix。 ”_基础 \t \t \t WHERE article_content_title _“。$ LANG。” \t \t \t LIKE '%:查询字符串%' \t \t \t OR \t \t \t article_content_text _ “$ LANG。” \t \t \t LIKE'%:queryString%''但'queryString'没有被替换。与上面的代码相同,但修复了您指出的语法错误。任何想法为什么? – wowpatrick

+0

@wowpatrick:当你说是不是被替换'queryString',你的意思是,当你呼应声明中,参数(':queryString'部分)还没有被替换为您的用户提供的字符串?如果是这样,准备好的陈述就是如何工作的。该语句和参数分别发送给MySQL。客户端(在这种情况下是PHP)不会将两者结合起来。因为它们是分开发送的,所以MySQL知道哪些位是语句,哪些位是参数,所以它不需要解析它来查明。这就是为什么它能很好地防御SQL注入。 – Mike

+0

@wowpatrick:如果你想看到的合并报表,您可以检查[MySQL的通用查询日志(http://dev.mysql.com/doc/refman/5.5/en/query-log.html)。它在默认情况下是禁用的,因此请务必先阅读文档以了解如何启用和使用它。另外,您是否在PHP代码中添加了该行以显示可能发生的任何错误? – Mike