/** * Splits keywords entered by a user into an array of words stored in $this->split_words * * @param string $keywords Contains the keyword as entered by the user * @param string $terms is either 'all' or 'any' * @return boolean false if no valid keywords were found and otherwise true */ function split_keywords(&$keywords, $terms) { global $db, $config, $user; // $keywords input format: each word seperated by a space, words in a bracket are not seperated // the user wants to search for any word, convert the search query if ($terms == 'any') { $words = array(); preg_match_all('#([^\\s+\\-|()]+)(?:$|[\\s+\\-|()])#', $keywords, $words); if (sizeof($words)) { $keywords = '(' . implode('|', $words) . ')'; } } // generate the split_words array shown to the user $this->split_words = explode(' ', $keywords); $exact_words = array(); preg_match_all('#([^\\s+\\-|*()]+)(?:$|[\\s+\\-|()])#', $keywords, $exact_words); if (sizeof($exact_words[1])) { $exact_words = $exact_words[1]; // start with building a query to retrieve all word ids $where_sql = array(); foreach ($exact_words as $i => $word) { $exact_words[$i] = '\'' . $db->sql_escape($word) . '\''; } // we can match exact words with one IN $sql = 'SELECT word_text, word_id FROM ' . SEARCH_WORDLIST_TABLE . ' WHERE word_text IN (' . implode(', ', $exact_words) . ')'; $result = $db->sql_query($sql); // replace text with ids and prefix ids with # while ($row = $db->sql_fetchrow($result)) { $words[$row['word_text']] = (int) $row['word_id']; } $db->sql_freeresult($result); } unset($exact_words); // now analyse the search query, first split it using the spaces $query = explode(' ', $keywords); $this->must_contain_ids = array(); $this->must_not_contain_ids = array(); $this->must_exclude_one_ids = array(); $mode = ''; $ignore_no_id = true; foreach ($query as $word) { // words which should not be included if ($word[0] == '-') { $word = substr($word, 1); // a group of which at least one may not be in the resulting posts if ($word[0] == '(') { $word = explode('|', substr($word, 1, -1)); $mode = 'exclude_one'; } // one word which should not be in the resulting posts else { $mode = 'must_not_contain'; } $ignore_no_id = true; } // words which have to be included else { // no prefix is the same as a +prefix if ($word[0] == '+') { $word = substr($word, 1); } // a group of words of which at least one word should be in every resulting post if ($word[0] == '(') { $word = explode('|', substr($word, 1, -1)); } $ignore_no_id = false; $mode = 'must_contain'; } // if this is an array of words then retrieve an id for each if (is_array($word)) { $id_words = array(); foreach ($word as $i => $word_part) { if (isset($words[$word_part])) { $id_words[] = $words[$word_part]; } } if (sizeof($id_words)) { $id_words = array_values($id_words); switch ($mode) { case 'exclude_one': if (sizeof($ids > 1)) { $this->must_exclude_one_ids[] = $id_words; } else { $this->must_not_contain_ids[] = $id_words[0]; } break; case 'must_contain': $this->must_contain_ids[] = (sizeof($id_words > 1)) ? $id_words : $id_words[0]; break; } } // throw an error if we shall not ignore unexistant words else if (!$ignore_no_id) { trigger_error(sprintf($user->lang['WORDS_IN_NO_POST'], implode(', ', $word))); } } // else we only need one id else if (isset($words[$word])) { switch ($mode) { case 'must_not_contain': $this->must_not_contain_ids[] = $words[$word]; break; case 'must_contain': $this->must_contain_ids[] = $words[$word]; break; } } // throw an error if we shall not ignore unexistant words else if (!$ignore_no_id) { trigger_error(sprintf($user->lang['WORD_IN_NO_POST'], $word)); } } // we can't search for negatives only if (!sizeof($this->must_contain_ids)) { return false; } if (sizeof($this->split_words)) { $this->split_words = array_values($this->split_words); return true; } return false; }