phpBB

Code Changes

File: includes/search/fulltext_native.php

  Unmodified   Added   Modified   Removed
Line 81Line 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 113Line 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 167Line 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 186Line 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 195Line 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 212Line 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 338Line 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 363Line 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 385Line 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 402Line 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 411Line 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 425Line 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 447Line 465
			'FROM'		=> array(
SEARCH_WORDMATCH_TABLE => array(),
SEARCH_WORDLIST_TABLE => array(),

			'FROM'		=> array(
SEARCH_WORDMATCH_TABLE => array(),
SEARCH_WORDLIST_TABLE => array(),

				POSTS_TABLE				=> 'p'

 
			),

			),

			'LEFT_JOIN'	=> array()




			'LEFT_JOIN' => array(array(
'FROM' => array(POSTS_TABLE => 'p'),
'ON' => 'm0.post_id = p.post_id',
)),

		);

		);

		$sql_where[] = 'm0.post_id = p.post_id';

 

$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 463Line 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 475Line 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 618Line 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 639Line 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 646Line 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 687Line 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 711Line 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 723Line 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 746Line 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 761Line 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 783Line 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 796Line 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 846Line 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 933Line 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 1264Line 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 1391Line 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 1673Line 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>
';