break; default: // two or more words were okay - use them as an OR clause foreach ($checkwords as $checkword) { $words['OR']["{$word}"]["{$checkword}"] = 'OR'; $queryWords["{$checkword}"] =& $words['OR']["{$word}"]["{$checkword}"]; } break; } } $querysplit = preg_replace($syntax['OR'], '', " {$querysplit}"); } // ############################################################################# // other words must be required (AND) foreach (preg_split($syntax['AND'], $querysplit, -1, PREG_SPLIT_NO_EMPTY) as $word) { if (verify_word_allowed($word)) { // word is okay - add it to the list of AND words to be queried $words['AND']["{$word}"] = 'AND'; $queryWords["{$word}"] =& $words['AND']["{$word}"]; } else { // word is bad or unindexed - add to list of common words $display['common'][] = $word; } } if (sizeof($display['common']) > 0) { $displayCommon = "<p>{$vbphrase['words_very_common']} : <b>" . implode('</b>, <b>', htmlspecialchars_uni($display['common'])) . '</b></p>'; } else { $displayCommon = ''; } // now that we've checked all the words, are there still some terms to search with? if (empty($queryWords) and empty($display['users'])) {
/** * Prepares the search text for use in a full-text query * * @param string Raw query text with AND, OR, and NOT * @param array (Output) Array of errors * * @return string Full-text query */ function prepare_search_text($query_text, &$errors) { $old_ft_search = $this->registry->options['fulltextsearch']; $this->registry->options['fulltextsearch'] = 1; // look for entire words that consist of "Ӓ". MySQL boolean // search will tokenize them seperately. Wrap them in quotes if they're // not already to emulate search for exactly that word. $query = explode('"', $query_text); $query_part_count = count($query); $query_text = ''; for ($i = 0; $i < $query_part_count; $i++) { // exploding by " means the 0th, 2nd, 4th... entries in the array // are outside of quotes if ($i % 2 == 1) { // 1st, 3rd.. entry = in quotes $query_text .= '"' . $query["{$i}"] . '"'; } else { // look for words that are entirely Ӓ $query_text .= preg_replace('/(?<=^|\\s)((&#[0-9]+;)+)(?=\\s|$)/', '"$1"', $query["{$i}"]); } } $query_text = preg_replace('#"([^"]+)"#sie', "stripslashes(str_replace(' ' , '*', '\\0'))", $query_text); require_once DIR . '/includes/functions_search.php'; $query_text = sanitize_search_query($query_text, $errors); if (!$errors) { // a tokenizing based approach to building a search query preg_match_all('#("[^"]*"|[^\\s]+)#', $query_text, $matches, PREG_SET_ORDER); $new_query_text = ''; $token_joiner = null; foreach ($matches as $match) { if ($match[1][0] == '-') { // NOT has already been converted $new_query_text = "({$new_query_text}) {$match['1']}"; continue; } switch (strtoupper($match[1])) { case 'OR': case 'AND': case 'NOT': // this isn't a searchable word, but a joiner $token_joiner = strtoupper($match[1]); break; default: verify_word_allowed($match[1]); if ($new_query_text !== '') { switch ($token_joiner) { case 'OR': // OR is no operator $new_query_text .= " {$match['1']}"; break; case 'NOT': // NOT this, but everything before it $new_query_text = "({$new_query_text}) -{$match['1']}"; break; case 'AND': default: // if we didn't have a joiner, default to and $new_query_text = "+({$new_query_text}) +{$match['1']}"; break; } } else { $new_query_text = $match[1]; } $token_joiner = null; } } $query_text = $new_query_text; } $this->registry->options['fulltextsearch'] = $old_ft_search; return trim($query_text); }