2011-07-27 85 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