Line 81 | Line 81 |
---|
*/ function split_keywords($keywords, $terms) {
|
*/ function split_keywords($keywords, $terms) {
|
global $db, $user;
| global $db, $user, $config;
|
|
|
$keywords = trim($this->cleanup($keywords, '+-|()*'));
| $tokens = '+-|()*';
$keywords = trim($this->cleanup($keywords, $tokens));
|
// allow word|word|word without brackets if ((strpos($keywords, ' ') === false) && (strpos($keywords, '|') !== false) && (strpos($keywords, '(') === false))
| // allow word|word|word without brackets if ((strpos($keywords, ' ') === false) && (strpos($keywords, '|') !== false) && (strpos($keywords, '(') === false))
|
Line 113 | Line 115 |
---|
case '-': case ' ': $keywords[$i] = '|';
|
case '-': case ' ': $keywords[$i] = '|';
|
| break; case '*': if ($i === 0 || ($keywords[$i - 1] !== '*' && strcspn($keywords[$i - 1], $tokens) === 0)) { if ($i === $n - 1 || ($keywords[$i + 1] !== '*' && strcspn($keywords[$i + 1], $tokens) === 0)) { $keywords = substr($keywords, 0, $i) . substr($keywords, $i + 1); } }
|
break; } }
| break; } }
|
Line 167 | Line 178 |
---|
);
$keywords = preg_replace($match, $replace, $keywords);
|
);
$keywords = preg_replace($match, $replace, $keywords);
|
| $num_keywords = sizeof(explode(' ', $keywords));
// We limit the number of allowed keywords to minimize load on the database if ($config['max_num_search_keywords'] && $num_keywords > $config['max_num_search_keywords']) { trigger_error($user->lang('MAX_NUM_SEARCH_KEYWORDS_REFINE', $config['max_num_search_keywords'], $num_keywords)); }
|
// $keywords input format: each word separated by a space, words in a bracket are not separated
| // $keywords input format: each word separated by a space, words in a bracket are not separated
|
Line 186 | Line 204 |
---|
$this->search_query = $keywords;
$exact_words = array();
|
$this->search_query = $keywords;
$exact_words = array();
|
preg_match_all('#([^\\s+\\-|*()]+)(?:$|[\\s+\\-|()])#u', $keywords, $exact_words);
| preg_match_all('#([^\\s+\\-|()]+)(?:$|[\\s+\\-|()])#u', $keywords, $exact_words);
|
$exact_words = $exact_words[1];
$common_ids = $words = array();
| $exact_words = $exact_words[1];
$common_ids = $words = array();
|
Line 195 | Line 213 |
---|
{ $sql = 'SELECT word_id, word_text, word_common FROM ' . SEARCH_WORDLIST_TABLE . '
|
{ $sql = 'SELECT word_id, word_text, word_common FROM ' . SEARCH_WORDLIST_TABLE . '
|
WHERE ' . $db->sql_in_set('word_text', $exact_words);
| WHERE ' . $db->sql_in_set('word_text', $exact_words) . ' ORDER BY word_count ASC';
|
$result = $db->sql_query($sql);
// store an array of words and ids, remove common words
| $result = $db->sql_query($sql);
// store an array of words and ids, remove common words
|
Line 212 | Line 231 |
---|
} $db->sql_freeresult($result); }
|
} $db->sql_freeresult($result); }
|
unset($exact_words);
| // Handle +, - without preceeding whitespace character $match = array('#(\S)\+#', '#(\S)-#'); $replace = array('$1 +', '$1 +');
$keywords = preg_replace($match, $replace, $keywords);
|
// now analyse the search query, first split it using the spaces $query = explode(' ', $keywords);
| // now analyse the search query, first split it using the spaces $query = explode(' ', $keywords);
|
Line 338 | Line 362 |
---|
$this->{$mode . '_ids'}[] = $words[$word]; } }
|
$this->{$mode . '_ids'}[] = $words[$word]; } }
|
// throw an error if we shall not ignore unexistant words else if (!$ignore_no_id)
| else
|
{ if (!isset($common_ids[$word]))
|
{ if (!isset($common_ids[$word]))
|
{ $len = utf8_strlen($word); if ($len >= $this->word_length['min'] && $len <= $this->word_length['max']) { trigger_error(sprintf($user->lang['WORD_IN_NO_POST'], $word)); } else { $this->common_words[] = $word; } } } else
| |
{ $len = utf8_strlen($word); if ($len < $this->word_length['min'] || $len > $this->word_length['max'])
| { $len = utf8_strlen($word); if ($len < $this->word_length['min'] || $len > $this->word_length['max'])
|
Line 363 | Line 373 |
---|
} } }
|
} } }
|
// we can't search for negatives only if (!sizeof($this->must_contain_ids)) { return false;
| |
}
|
}
|
sort($this->must_contain_ids); sort($this->must_not_contain_ids); sort($this->must_exclude_one_ids);
if (!empty($this->search_query))
| // Return true if all words are not common words if (sizeof($exact_words) - sizeof($this->common_words) > 0)
|
{ return true; }
| { return true; }
|
Line 385 | Line 387 |
---|
* Performs a search on keywords depending on display specific params. You have to run split_keywords() first. * * @param string $type contains either posts or topics depending on what should be searched for
|
* Performs a search on keywords depending on display specific params. You have to run split_keywords() first. * * @param string $type contains either posts or topics depending on what should be searched for
|
* @param string &$fields contains either titleonly (topic titles should be searched), msgonly (only message bodies should be searched), firstpost (only subject and body of the first post should be searched) or all (all post bodies and subjects should be searched) * @param string &$terms is either 'all' (use query as entered, words without prefix should default to "have to be in field") or 'any' (ignore search query parts and just return all posts that contain any of the specified words) * @param array &$sort_by_sql contains SQL code for the ORDER BY part of a query * @param string &$sort_key is the key of $sort_by_sql for the selected sorting * @param string &$sort_dir is either a or d representing ASC and DESC * @param string &$sort_days specifies the maximum amount of days a post may be old * @param array &$ex_fid_ary specifies an array of forum ids which should not be searched * @param array &$m_approve_fid_ary specifies an array of forum ids in which the searcher is allowed to view unapproved posts * @param int &$topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched * @param array &$author_ary an array of author ids if the author should be ignored during the search the array is empty
| * @param string $fields contains either titleonly (topic titles should be searched), msgonly (only message bodies should be searched), firstpost (only subject and body of the first post should be searched) or all (all post bodies and subjects should be searched) * @param string $terms is either 'all' (use query as entered, words without prefix should default to "have to be in field") or 'any' (ignore search query parts and just return all posts that contain any of the specified words) * @param array $sort_by_sql contains SQL code for the ORDER BY part of a query * @param string $sort_key is the key of $sort_by_sql for the selected sorting * @param string $sort_dir is either a or d representing ASC and DESC * @param string $sort_days specifies the maximum amount of days a post may be old * @param array $ex_fid_ary specifies an array of forum ids which should not be searched * @param array $m_approve_fid_ary specifies an array of forum ids in which the searcher is allowed to view unapproved posts * @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched * @param array $author_ary an array of author ids if the author should be ignored during the search the array is empty * @param string $author_name specifies the author match, when ANONYMOUS is also a search-match
|
* @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered * @param int $start indicates the first index of the page * @param int $per_page number of ids each page is supposed to contain
| * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered * @param int $start indicates the first index of the page * @param int $per_page number of ids each page is supposed to contain
|
Line 402 | Line 405 |
---|
* * @access public */
|
* * @access public */
|
function keyword_search($type, &$fields, &$terms, &$sort_by_sql, &$sort_key, &$sort_dir, &$sort_days, &$ex_fid_ary, &$m_approve_fid_ary, &$topic_id, &$author_ary, &$id_ary, $start, $per_page)
| function keyword_search($type, $fields, $terms, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $m_approve_fid_ary, $topic_id, $author_ary, $author_name, &$id_ary, $start, $per_page)
|
{ global $config, $db;
| { global $config, $db;
|
Line 411 | Line 414 |
---|
{ return false; }
|
{ return false; }
|
| // we can't search for negatives only if (empty($this->must_contain_ids)) { return false; }
$must_contain_ids = $this->must_contain_ids; $must_not_contain_ids = $this->must_not_contain_ids; $must_exclude_one_ids = $this->must_exclude_one_ids;
sort($must_contain_ids); sort($must_not_contain_ids); sort($must_exclude_one_ids);
|
// generate a search_key from all the options to identify the results $search_key = md5(implode('#', array(
|
// generate a search_key from all the options to identify the results $search_key = md5(implode('#', array(
|
serialize($this->must_contain_ids), serialize($this->must_not_contain_ids), serialize($this->must_exclude_one_ids),
| serialize($must_contain_ids), serialize($must_not_contain_ids), serialize($must_exclude_one_ids),
|
$type, $fields, $terms,
| $type, $fields, $terms,
|
Line 425 | Line 442 |
---|
$topic_id, implode(',', $ex_fid_ary), implode(',', $m_approve_fid_ary),
|
$topic_id, implode(',', $ex_fid_ary), implode(',', $m_approve_fid_ary),
|
implode(',', $author_ary)
| implode(',', $author_ary), $author_name,
|
)));
// try reading the results from cache
| )));
// try reading the results from cache
|
Line 455 | Line 473 |
---|
);
$title_match = '';
|
);
$title_match = '';
|
| $left_join_topics = false;
|
$group_by = true; // Build some display specific sql strings switch ($fields)
| $group_by = true; // Build some display specific sql strings switch ($fields)
|
Line 464 | Line 483 |
---|
$group_by = false; // no break case 'firstpost':
|
$group_by = false; // no break case 'firstpost':
|
$sql_array['FROM'][TOPICS_TABLE] = 't';
| $left_join_topics = true;
|
$sql_where[] = 'p.post_id = t.topic_first_post_id'; break;
| $sql_where[] = 'p.post_id = t.topic_first_post_id'; break;
|
Line 476 | Line 495 |
---|
if ($type == 'topics') {
|
if ($type == 'topics') {
|
if (!isset($sql_array['FROM'][TOPICS_TABLE])) { $sql_array['FROM'][TOPICS_TABLE] = 't'; $sql_where[] = 'p.topic_id = t.topic_id'; }
| $left_join_topics = true;
|
$group_by = true; }
| $group_by = true; }
|
Line 619 | Line 634 |
---|
if (sizeof($author_ary)) {
|
if (sizeof($author_ary)) {
|
$sql_where[] = $db->sql_in_set('p.poster_id', $author_ary);
| if ($author_name) { // first one matches post of registered users, second one guests and deleted users $sql_author = '(' . $db->sql_in_set('p.poster_id', array_diff($author_ary, array(ANONYMOUS)), false, true) . ' OR p.post_username ' . $author_name . ')'; } else { $sql_author = $db->sql_in_set('p.poster_id', $author_ary); } $sql_where[] = $sql_author;
|
}
if (sizeof($ex_fid_ary))
| }
if (sizeof($ex_fid_ary))
|
Line 640 | Line 664 |
---|
{ $sql = ''; $sql_array_count = $sql_array;
|
{ $sql = ''; $sql_array_count = $sql_array;
|
| if ($left_join_topics) { $sql_array_count['LEFT_JOIN'][] = array( 'FROM' => array(TOPICS_TABLE => 't'), 'ON' => 'p.topic_id = t.topic_id' ); }
|
switch ($db->sql_layer) {
| switch ($db->sql_layer) {
|
Line 647 | Line 679 |
---|
case 'mysqli':
// 3.x does not support SQL_CALC_FOUND_ROWS
|
case 'mysqli':
// 3.x does not support SQL_CALC_FOUND_ROWS
|
$sql_array['SELECT'] = 'SQL_CALC_FOUND_ROWS ' . $sql_array['SELECT'];
| // $sql_array['SELECT'] = 'SQL_CALC_FOUND_ROWS ' . $sql_array['SELECT'];
|
$is_mysql = true;
break;
| $is_mysql = true;
break;
|
Line 688 | Line 720 |
---|
break;
case 't':
|
break;
case 't':
|
if (!isset($sql_array['FROM'][TOPICS_TABLE])) { $sql_array['FROM'][TOPICS_TABLE] = 't'; $sql_where[] = 'p.topic_id = t.topic_id'; }
| $left_join_topics = true;
|
break;
case 'f': $sql_array['FROM'][FORUMS_TABLE] = 'f'; $sql_where[] = 'f.forum_id = p.forum_id'; break;
|
break;
case 'f': $sql_array['FROM'][FORUMS_TABLE] = 'f'; $sql_where[] = 'f.forum_id = p.forum_id'; break;
|
| }
if ($left_join_topics) { $sql_array['LEFT_JOIN'][] = array( 'FROM' => array(TOPICS_TABLE => 't'), 'ON' => 'p.topic_id = t.topic_id' );
|
}
$sql_array['WHERE'] = implode(' AND ', $sql_where);
| }
$sql_array['WHERE'] = implode(' AND ', $sql_where);
|
Line 712 | Line 748 |
---|
while ($row = $db->sql_fetchrow($result)) {
|
while ($row = $db->sql_fetchrow($result)) {
|
$id_ary[] = $row[(($type == 'posts') ? 'post_id' : 'topic_id')];
| $id_ary[] = (int) $row[(($type == 'posts') ? 'post_id' : 'topic_id')];
|
} $db->sql_freeresult($result);
| } $db->sql_freeresult($result);
|
Line 724 | Line 760 |
---|
// if we use mysql and the total result count is not cached yet, retrieve it from the db if (!$total_results && $is_mysql) {
|
// if we use mysql and the total result count is not cached yet, retrieve it from the db if (!$total_results && $is_mysql) {
|
| // Count rows for the executed queries. Replace $select within $sql with SQL_CALC_FOUND_ROWS, and run it. $sql_array_copy = $sql_array; $sql_array_copy['SELECT'] = 'SQL_CALC_FOUND_ROWS p.post_id ';
$sql = $db->sql_build_query('SELECT', $sql_array_copy); unset($sql_array_copy);
$db->sql_query($sql); $db->sql_freeresult($result);
|
$sql = 'SELECT FOUND_ROWS() as total_results'; $result = $db->sql_query($sql); $total_results = (int) $db->sql_fetchfield('total_results');
| $sql = 'SELECT FOUND_ROWS() as total_results'; $result = $db->sql_query($sql); $total_results = (int) $db->sql_fetchfield('total_results');
|
Line 747 | Line 793 |
---|
* * @param string $type contains either posts or topics depending on what should be searched for * @param boolean $firstpost_only if true, only topic starting posts will be considered
|
* * @param string $type contains either posts or topics depending on what should be searched for * @param boolean $firstpost_only if true, only topic starting posts will be considered
|
* @param array &$sort_by_sql contains SQL code for the ORDER BY part of a query * @param string &$sort_key is the key of $sort_by_sql for the selected sorting * @param string &$sort_dir is either a or d representing ASC and DESC * @param string &$sort_days specifies the maximum amount of days a post may be old * @param array &$ex_fid_ary specifies an array of forum ids which should not be searched * @param array &$m_approve_fid_ary specifies an array of forum ids in which the searcher is allowed to view unapproved posts * @param int &$topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched * @param array &$author_ary an array of author ids
| * @param array $sort_by_sql contains SQL code for the ORDER BY part of a query * @param string $sort_key is the key of $sort_by_sql for the selected sorting * @param string $sort_dir is either a or d representing ASC and DESC * @param string $sort_days specifies the maximum amount of days a post may be old * @param array $ex_fid_ary specifies an array of forum ids which should not be searched * @param array $m_approve_fid_ary specifies an array of forum ids in which the searcher is allowed to view unapproved posts * @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched * @param array $author_ary an array of author ids * @param string $author_name specifies the author match, when ANONYMOUS is also a search-match
|
* @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered * @param int $start indicates the first index of the page * @param int $per_page number of ids each page is supposed to contain
| * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered * @param int $start indicates the first index of the page * @param int $per_page number of ids each page is supposed to contain
|
Line 762 | Line 809 |
---|
* * @access public */
|
* * @access public */
|
function author_search($type, $firstpost_only, &$sort_by_sql, &$sort_key, &$sort_dir, &$sort_days, &$ex_fid_ary, &$m_approve_fid_ary, &$topic_id, &$author_ary, &$id_ary, $start, $per_page)
| function author_search($type, $firstpost_only, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $m_approve_fid_ary, $topic_id, $author_ary, $author_name, &$id_ary, $start, $per_page)
|
{ global $config, $db;
| { global $config, $db;
|
Line 784 | Line 831 |
---|
$topic_id, implode(',', $ex_fid_ary), implode(',', $m_approve_fid_ary),
|
$topic_id, implode(',', $ex_fid_ary), implode(',', $m_approve_fid_ary),
|
implode(',', $author_ary)
| implode(',', $author_ary), $author_name,
|
)));
// try reading the results from cache
| )));
// try reading the results from cache
|
Line 797 | Line 845 |
---|
$id_ary = array();
// Create some display specific sql strings
|
$id_ary = array();
// Create some display specific sql strings
|
$sql_author = $db->sql_in_set('p.poster_id', $author_ary);
| if ($author_name) { // first one matches post of registered users, second one guests and deleted users $sql_author = '(' . $db->sql_in_set('p.poster_id', array_diff($author_ary, array(ANONYMOUS)), false, true) . ' OR p.post_username ' . $author_name . ')'; } else { $sql_author = $db->sql_in_set('p.poster_id', $author_ary); }
|
$sql_fora = (sizeof($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : ''; $sql_time = ($sort_days) ? ' AND p.post_time >= ' . (time() - ($sort_days * 86400)) : ''; $sql_topic_id = ($topic_id) ? ' AND p.topic_id = ' . (int) $topic_id : '';
| $sql_fora = (sizeof($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : ''; $sql_time = ($sort_days) ? ' AND p.post_time >= ' . (time() - ($sort_days * 86400)) : ''; $sql_topic_id = ($topic_id) ? ' AND p.topic_id = ' . (int) $topic_id : '';
|
Line 847 | Line 903 |
---|
{ case 'mysql4': case 'mysqli':
|
{ case 'mysql4': case 'mysqli':
|
$select = 'SQL_CALC_FOUND_ROWS ' . $select;
| // $select = 'SQL_CALC_FOUND_ROWS ' . $select;
|
$is_mysql = true; break;
| $is_mysql = true; break;
|
Line 934 | Line 990 |
---|
while ($row = $db->sql_fetchrow($result)) {
|
while ($row = $db->sql_fetchrow($result)) {
|
$id_ary[] = $row[$field];
| $id_ary[] = (int) $row[$field];
|
} $db->sql_freeresult($result);
if (!$total_results && $is_mysql) {
|
} $db->sql_freeresult($result);
if (!$total_results && $is_mysql) {
|
| // Count rows for the executed queries. Replace $select within $sql with SQL_CALC_FOUND_ROWS, and run it. $sql = str_replace('SELECT ' . $select, 'SELECT DISTINCT SQL_CALC_FOUND_ROWS p.post_id', $sql);
$db->sql_query($sql); $db->sql_freeresult($result);
|
$sql = 'SELECT FOUND_ROWS() as total_results'; $result = $db->sql_query($sql); $total_results = (int) $db->sql_fetchfield('total_results');
| $sql = 'SELECT FOUND_ROWS() as total_results'; $result = $db->sql_query($sql); $total_results = (int) $db->sql_fetchfield('total_results');
|
Line 1265 | Line 1327 |
---|
$db->sql_query($sql); }
|
$db->sql_query($sql); }
|
$this->destroy_cache(array_unique($word_texts), $author_ids);
| $this->destroy_cache(array_unique($word_texts), array_unique($author_ids));
|
}
/**
| }
/**
|
Line 1392 | Line 1454 |
---|
{ global $db;
|
{ global $db;
|
$sql = 'SELECT COUNT(*) as total_words FROM ' . SEARCH_WORDLIST_TABLE; $result = $db->sql_query($sql); $this->stats['total_words'] = (int) $db->sql_fetchfield('total_words'); $db->sql_freeresult($result);
$sql = 'SELECT COUNT(*) as total_matches FROM ' . SEARCH_WORDMATCH_TABLE; $result = $db->sql_query($sql); $this->stats['total_matches'] = (int) $db->sql_fetchfield('total_matches'); $db->sql_freeresult($result);
| $this->stats['total_words'] = $db->get_estimated_row_count(SEARCH_WORDLIST_TABLE); $this->stats['total_matches'] = $db->get_estimated_row_count(SEARCH_WORDMATCH_TABLE);
|
}
/**
| }
/**
|
Line 1674 | Line 1727 |
---|
</dl> <dl> <dt><label for="fulltext_native_common_thres">' . $user->lang['COMMON_WORD_THRESHOLD'] . ':</label><br /><span>' . $user->lang['COMMON_WORD_THRESHOLD_EXPLAIN'] . '</span></dt>
|
</dl> <dl> <dt><label for="fulltext_native_common_thres">' . $user->lang['COMMON_WORD_THRESHOLD'] . ':</label><br /><span>' . $user->lang['COMMON_WORD_THRESHOLD_EXPLAIN'] . '</span></dt>
|
<dd><input id="fulltext_native_common_thres" type="text" size="3" maxlength="3" name="config[fulltext_native_common_thres]" value="' . (int) $config['fulltext_native_common_thres'] . '" /> %</dd>
| <dd><input id="fulltext_native_common_thres" type="text" size="3" maxlength="3" name="config[fulltext_native_common_thres]" value="' . (double) $config['fulltext_native_common_thres'] . '" /> %</dd>
|
</dl> ';
| </dl> ';
|