936 lines
40 KiB
Plaintext
936 lines
40 KiB
Plaintext
<?php
|
|
/******************************************************************************
|
|
* Search.php *
|
|
*******************************************************************************
|
|
* SMF: Simple Machines Forum *
|
|
* Open-Source Project Inspired by Zef Hemel (zef@zefhemel.com) *
|
|
* =========================================================================== *
|
|
* Software Version: SMF 1.0.7 *
|
|
* Software by: Simple Machines (http://www.simplemachines.org) *
|
|
* Copyright 2001-2005 by: Lewis Media (http://www.lewismedia.com) *
|
|
* Support, News, Updates at: http://www.simplemachines.org *
|
|
*******************************************************************************
|
|
* This program is free software; you may redistribute it and/or modify it *
|
|
* under the terms of the provided license as published by Lewis Media. *
|
|
* *
|
|
* This program is distributed in the hope that it is and will be useful, *
|
|
* but WITHOUT ANY WARRANTIES; without even any implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
|
* *
|
|
* See the "license.txt" file for details of the Simple Machines license. *
|
|
* The latest version can always be found at http://www.simplemachines.org. *
|
|
******************************************************************************/
|
|
if (!defined('SMF'))
|
|
die('Hacking attempt...');
|
|
|
|
/* These functions are here for searching, and they are:
|
|
|
|
void PlushSearch1()
|
|
- shows the screen to search forum posts (action=search), and uses the
|
|
simple version if the simpleSearch setting is enabled.
|
|
- uses the main sub template of the Search template.
|
|
- requires the search_posts permission.
|
|
- decodes and loads search parameters given in the URL (if any).
|
|
- the form redirects to index.php?action=search2.
|
|
|
|
void PlushSearch2()
|
|
- checks user input and searches the messages table for messages
|
|
matching the query.
|
|
- requires the search_posts permission.
|
|
- stores the results into the search cache (if enabled).
|
|
- show the results of the search query.
|
|
- uses the results sub template of the Search template.
|
|
|
|
array prepareSearchContext(bool reset = false)
|
|
- callback function for the results sub template.
|
|
- loads the necessary contextual data to show a search result.
|
|
*/
|
|
|
|
// Ask the user what they want to search for.
|
|
function PlushSearch1()
|
|
{
|
|
global $txt, $scripturl, $db_prefix, $modSettings, $user_info, $context;
|
|
|
|
loadTemplate('Search');
|
|
|
|
// Check the user's permissions.
|
|
isAllowedTo('search_posts');
|
|
|
|
// Link tree....
|
|
$context['linktree'][] = array(
|
|
'url' => $scripturl . '?action=search',
|
|
'name' => $txt[182]
|
|
);
|
|
|
|
// If you got back from search2 by using the linktree, you get your original search parameters back.
|
|
if (isset($_REQUEST['params']))
|
|
{
|
|
$temp_params = explode('|"|', base64_decode($_REQUEST['params']));
|
|
$context['search_params'] = array();
|
|
foreach ($temp_params as $i => $data)
|
|
{
|
|
list ($k, $v) = explode('|\'|', $data);
|
|
$context['search_params'][$k] = stripslashes($v);
|
|
}
|
|
if (isset($context['search_params']['brd']))
|
|
$context['search_params']['brd'] = $context['search_params']['brd'] == '' ? array() : explode(',', $context['search_params']['brd']);
|
|
}
|
|
|
|
if (isset($context['search_params']['search']))
|
|
$context['search_params']['search'] = htmlspecialchars($context['search_params']['search']);
|
|
if (isset($context['search_params']['userspec']))
|
|
$context['search_params']['userspec'] = htmlspecialchars(stripslashes($context['search_params']['userspec']));
|
|
|
|
// Find all the boards this user is allowed to see.
|
|
$request = db_query("
|
|
SELECT b.ID_CAT, c.name AS catName, b.ID_BOARD, b.name, b.childLevel
|
|
FROM {$db_prefix}boards AS b
|
|
LEFT JOIN {$db_prefix}categories AS c ON (c.ID_CAT = b.ID_CAT)
|
|
WHERE $user_info[query_see_board]
|
|
ORDER BY c.catOrder, b.boardOrder", __FILE__, __LINE__);
|
|
$context['num_boards'] = mysql_num_rows($request);
|
|
$context['categories'] = array();
|
|
while ($row = mysql_fetch_assoc($request))
|
|
{
|
|
// This category hasn't been set up yet..
|
|
if (!isset($context['categories'][$row['ID_CAT']]))
|
|
$context['categories'][$row['ID_CAT']] = array(
|
|
'id' => $row['ID_CAT'],
|
|
'name' => $row['catName'],
|
|
'boards' => array()
|
|
);
|
|
|
|
// Set this board up, and let the template know when it's a child. (indent them..)
|
|
$context['categories'][$row['ID_CAT']]['boards'][$row['ID_BOARD']] = array(
|
|
'id' => $row['ID_BOARD'],
|
|
'name' => $row['name'],
|
|
'child_level' => $row['childLevel']
|
|
);
|
|
}
|
|
mysql_free_result($request);
|
|
|
|
// Simple or not?
|
|
$context['simple_search'] = !empty($modSettings['simpleSearch']) && !isset($_GET['advanced']);
|
|
$context['page_title'] = $txt[183];
|
|
}
|
|
|
|
// Gather the results and show them.
|
|
function PlushSearch2()
|
|
{
|
|
global $modSettings, $sourcedir;
|
|
global $scripturl, $txt, $db_prefix, $user_info, $context, $messages_request, $attachments, $boards_can;
|
|
|
|
$weight_factors = array(
|
|
'frequency',
|
|
'age',
|
|
'length',
|
|
'subject',
|
|
'first_message',
|
|
);
|
|
|
|
$weight = array();
|
|
$weight_total = 0;
|
|
foreach ($weight_factors as $weight_factor)
|
|
{
|
|
$weight[$weight_factor] = empty($modSettings['search_weight_' . $weight_factor]) ? 0 : (int) $modSettings['search_weight_' . $weight_factor];
|
|
$weight_total += $weight[$weight_factor];
|
|
}
|
|
|
|
// Zero weight. Weightless.
|
|
if (empty($weight_total))
|
|
fatal_lang_error('search_invalid_weights');
|
|
|
|
|
|
// Fine-tune the weight of each search factor. These factors should add up to 100.
|
|
$weight = array(
|
|
// The more message within a topic match the search query, the higher the ranking.
|
|
'frequency' => 50,
|
|
// The more recent a message is, the higher its ranking.
|
|
'age' => 5,
|
|
// The larger the topic is, the higher its ranking.
|
|
'length' => 20,
|
|
// If a search string happens to be part of the topic subject, it's probably a better match.
|
|
'subject' => 15,
|
|
// If the first message of a topic is a match, then the whole topic might be more interesting.
|
|
'first_message' => 10,
|
|
);
|
|
|
|
|
|
// These vars don't require an interface, the're just here for tweaking.
|
|
$recentPercentage = 0.30;
|
|
$humungousTopicPosts = 200;
|
|
$maxMembersToSearch = 500;
|
|
|
|
loadTemplate('Search');
|
|
|
|
// Are you allowed?
|
|
isAllowedTo('search_posts');
|
|
|
|
// So, we're allowed here, let's clean up the start variable - just incase.
|
|
$_REQUEST['start'] = (int) $_REQUEST['start'];
|
|
|
|
require_once($sourcedir . '/Display.php');
|
|
|
|
// $search_params will carry all settings that differ from the default search parameters.
|
|
// That way, the URLs involved in a search page will be kept as short as possible.
|
|
$search_params = array();
|
|
|
|
if (isset($_REQUEST['params']))
|
|
{
|
|
$temp_params = explode('|"|', base64_decode($_REQUEST['params']));
|
|
foreach ($temp_params as $i => $data)
|
|
{
|
|
list ($k, $v) = explode('|\'|', $data);
|
|
$search_params[$k] = stripslashes($v);
|
|
}
|
|
if (isset($search_params['brd']))
|
|
$search_params['brd'] = $search_params['brd'] == '' ? array() : explode(',', $search_params['brd']);
|
|
}
|
|
else
|
|
{
|
|
$search_params['subject_only'] = true;
|
|
}
|
|
|
|
|
|
// 1 => 'allwords' (default, don't set as param) / 2 => 'anywords'.
|
|
if (!empty($search_params['searchtype']) || (!empty($_REQUEST['searchtype']) && $_REQUEST['searchtype'] == 2))
|
|
$search_params['searchtype'] = 2;
|
|
|
|
// Minimum age of messages. Default to zero (don't set param in that case).
|
|
if (!empty($search_params['minage']) || (!empty($_REQUEST['minage']) && $_REQUEST['minage'] > 0))
|
|
$search_params['minage'] = !empty($search_params['minage']) ? (int) $search_params['minage'] : (int) $_REQUEST['minage'];
|
|
|
|
// Maximum age of messages. Default to infinite (9999 days: param not set).
|
|
if (!empty($search_params['maxage']) || (!empty($_REQUEST['maxage']) && $_REQUEST['maxage'] != 9999))
|
|
$search_params['maxage'] = !empty($search_params['maxage']) ? (int) $search_params['maxage'] : (int) $_REQUEST['maxage'];
|
|
|
|
$timeAddition = '';
|
|
$timeAddition .= !empty($search_params['minage']) ? ' AND m.posterTime <= ' . (time() - $search_params['minage'] * 86400) : '';
|
|
$timeAddition .= !empty($search_params['maxage']) ? ' AND m.posterTime >= ' . (time() - $search_params['maxage'] * 86400) : '';
|
|
|
|
// Default the user name to a wildcard matching every user (*).
|
|
if (!empty($search_params['user_spec']) || (!empty($_REQUEST['userspec']) && $_REQUEST['userspec'] != '*'))
|
|
$search_params['userspec'] = isset($search_params['userspec']) ? $search_params['userspec'] : $_REQUEST['userspec'];
|
|
|
|
// If there's no specific user, then don't mention it in the main query.
|
|
if (empty($search_params['userspec']))
|
|
$userQuery = '';
|
|
else
|
|
{
|
|
$userString = strtolower(addslashes(strtr($search_params['userspec'], array('%' => '\%', '_' => '\_', '*' => '%', '?' => '_'))));
|
|
// Retrieve a list of possible members.
|
|
$request = db_query("
|
|
SELECT ID_MEMBER
|
|
FROM {$db_prefix}members
|
|
WHERE realName LIKE '$userString'", __FILE__, __LINE__);
|
|
// Simply do nothing if there're too many members matching the criteria.
|
|
if (mysql_num_rows($request) > $maxMembersToSearch)
|
|
$userQuery = '';
|
|
elseif (mysql_num_rows($request) == 0)
|
|
$userQuery = "m.ID_MEMBER = 0 AND m.posterName LIKE '$userString'";
|
|
else
|
|
{
|
|
$memberlist = array();
|
|
while ($row = mysql_fetch_assoc($request))
|
|
$memberlist[] = $row['ID_MEMBER'];
|
|
$userQuery = "(m.ID_MEMBER IN (" . implode(', ', $memberlist) . ") OR (m.ID_MEMBER = 0 AND m.posterName LIKE '$userString'))";
|
|
}
|
|
}
|
|
|
|
// If the boards were passed by URL (params=), temporarily put them back in $_REQUEST.
|
|
if (!empty($search_params['brd']) && is_array($search_params['brd']))
|
|
$_REQUEST['brd'] = $search_params['brd'];
|
|
|
|
// Make sure all boards are integers.
|
|
if (!empty($_REQUEST['brd']))
|
|
foreach ($_REQUEST['brd'] as $id => $brd)
|
|
$_REQUEST['brd'][$id] = (int) $brd;
|
|
|
|
// Select all boards you've selected AND are allowed to see.
|
|
if ($user_info['is_admin'])
|
|
$search_params['brd'] = empty($_REQUEST['brd']) ? array() : $_REQUEST['brd'];
|
|
else
|
|
{
|
|
$request = db_query("
|
|
SELECT b.ID_BOARD
|
|
FROM {$db_prefix}boards AS b
|
|
WHERE $user_info[query_see_board]" . (empty($_REQUEST['brd']) ? '' : "
|
|
AND b.ID_BOARD IN (" . implode(', ', $_REQUEST['brd']) . ")"), __FILE__, __LINE__);
|
|
$search_params['brd'] = array();
|
|
while ($row = mysql_fetch_assoc($request))
|
|
$search_params['brd'][] = $row['ID_BOARD'];
|
|
mysql_free_result($request);
|
|
|
|
// This error should pro'bly only happen for hackers.
|
|
if (empty($search_params['brd']))
|
|
fatal_lang_error('search_no_boards');
|
|
}
|
|
|
|
// If we've selected all boards, this parameter can be left empty.
|
|
$request = db_query("
|
|
SELECT COUNT(ID_BOARD)
|
|
FROM {$db_prefix}boards", __FILE__, __LINE__);
|
|
list ($num_boards) = mysql_fetch_row($request);
|
|
mysql_free_result($request);
|
|
|
|
if ($num_boards == count($search_params['brd']))
|
|
$search_params['brd'] = array();
|
|
// Make sure these all boards are numbers.
|
|
elseif (!empty($search_params['brd']))
|
|
{
|
|
foreach ($search_params['brd'] as $k => $v)
|
|
$search_params['brd'][$k] = (int) $v;
|
|
}
|
|
|
|
$search_params['show_complete'] = !empty($search_params['show_complete']) || !empty($_REQUEST['show_complete']);
|
|
$search_params['subject_only'] = !empty($search_params['subject_only']) || !empty($_REQUEST['subject_only']);
|
|
|
|
$context['compact'] = !$search_params['show_complete'];
|
|
|
|
// What are we searching for?
|
|
$search_params['search'] = !empty($search_params['search']) ? $search_params['search'] : (isset($_REQUEST['search']) ? stripslashes($_REQUEST['search']) : '');
|
|
// Nothing??
|
|
if (!isset($search_params['search']) || $search_params['search'] == '')
|
|
fatal_lang_error('no_valid_search_string', false);
|
|
|
|
// Extract phrase parts first (e.g. some words "this is a phrase" some more words.)
|
|
preg_match_all('/(?:^|\s)"([^"]+)"(?:$|\s)/', $search_params['search'], $matches, PREG_PATTERN_ORDER);
|
|
$searchArray = $matches[1];
|
|
|
|
// Remove the phrase parts and extract the words.
|
|
$searchArray = array_merge($searchArray, explode(' ', preg_replace('/(?:^|\s)"([^"]+)"(?:$|\s)/', ' ', $search_params['search'])));
|
|
|
|
// Trim everything and make sure there are no words that are the same.
|
|
foreach ($searchArray as $index => $value)
|
|
{
|
|
$searchArray[$index] = addslashes(strtolower(trim($value)));
|
|
if (!isset($searchArray[$index]) || $searchArray[$index] == '')
|
|
unset($searchArray[$index]);
|
|
}
|
|
$searchArray = array_slice(array_unique($searchArray), 0, 10);
|
|
|
|
if (empty($searchArray))
|
|
fatal_lang_error('no_valid_search_string', false);
|
|
|
|
// Each word is matched against the body and the subject.
|
|
$searchParts = array();
|
|
foreach ($searchArray as $word)
|
|
{
|
|
if (empty($modSettings['search_match_complete_words']))
|
|
$searchParts[] = " LIKE '%" . strtr($word, array('_' => '\\_', '%' => '\\%')) . "%'";
|
|
else
|
|
$searchParts[] = " RLIKE '[[:<:]]" . addcslashes(preg_replace(array('/([\[\]$.+?|{}])/', '/\*/'), array('[$1]', '.+'), $word), '') . "[[:>:]]'";
|
|
}
|
|
|
|
$searchQuery = 0;
|
|
|
|
// Either all words must match (searchtype == 1) or any of the words (searchtype == 2).
|
|
if (empty($search_params['searchtype']))
|
|
{
|
|
if (!$search_params['subject_only'])
|
|
$searchQuery = 'm.body' . implode(' AND m.body', $searchParts) . $timeAddition;
|
|
$topicQuery = 'm.subject' . implode(' AND m.subject', $searchParts) . $timeAddition;
|
|
}
|
|
else
|
|
{
|
|
if (!$search_params['subject_only'])
|
|
$searchQuery = (count($searchParts) > 1 ? '(' : '') . 'm.body' . implode(' OR m.body', $searchParts) . (count($searchParts) > 1 ? ')' : '') . $timeAddition;
|
|
$topicQuery = (count($searchParts) > 1 ? '(' : '') . 'm.subject' . implode(' OR m.subject', $searchParts) . (count($searchParts) > 1 ? ')' : '') . $timeAddition;
|
|
}
|
|
|
|
// Get the sorting parameters right. Default to sort by relevance descending.
|
|
$sort_columns = array(
|
|
'relevance',
|
|
'numReplies',
|
|
'ID_MSG',
|
|
);
|
|
if (empty($search_params['sort']) && !empty($_REQUEST['sort']))
|
|
list ($search_params['sort'], $search_params['sort_dir']) = array_pad(explode('|', $_REQUEST['sort']), 2, '');
|
|
$search_params['sort'] = !empty($search_params['sort']) && in_array($search_params['sort'], $sort_columns) ? $search_params['sort'] : 'relevance';
|
|
$search_params['sort_dir'] = !empty($search_params['sort_dir']) && $search_params['sort_dir'] == 'asc' ? 'asc' : 'desc';
|
|
|
|
$context['mark'] = array();
|
|
foreach ($searchArray as $word)
|
|
$context['mark'][$word] = '<b class="highlight">' . $word . '</b>';
|
|
|
|
// All search params have been checked, let's compile them to a single string... made less simple by PHP 4.3.9 and below.
|
|
$temp_params = $search_params;
|
|
if (isset($temp_params['brd']))
|
|
$temp_params['brd'] = implode(',', $temp_params['brd']);
|
|
$context['params'] = array();
|
|
foreach ($temp_params as $k => $v)
|
|
$context['params'][] = $k . '|\'|' . addslashes($v);
|
|
$context['params'] = base64_encode(implode('|"|', $context['params']));
|
|
|
|
// ... and add the links to the link tree.
|
|
$context['linktree'][] = array(
|
|
'url' => $scripturl . '?action=search;params=' . $context['params'],
|
|
'name' => $txt[182]
|
|
);
|
|
$context['linktree'][] = array(
|
|
'url' => $scripturl . '?action=search2;params=' . $context['params'],
|
|
'name' => $txt['search_results']
|
|
);
|
|
|
|
// Determine some values needed to calculate the relevance.
|
|
$minMsg = (int) (1 - $recentPercentage) * $modSettings['maxMsgID'];
|
|
$recentMsg = $modSettings['maxMsgID'] - $minMsg;
|
|
|
|
$mainQuery = "
|
|
t.ID_TOPIC,
|
|
$weight[frequency] * IF(m.ID_MSG IS NOT NULL, COUNT(m.ID_MSG) / (t.numReplies + 1), 0) +
|
|
$weight[age] * IF(m.ID_MSG IS NULL OR MAX(m.ID_MSG) < $minMsg, 0, (MAX(m.ID_MSG) - $minMsg) / $recentMsg) +
|
|
$weight[length] * IF(t.numReplies < $humungousTopicPosts, t.numReplies / $humungousTopicPosts, 1) +
|
|
$weight[subject] * t.is_subject +
|
|
$weight[first_message] * IF(MIN(m.ID_MSG) = t.ID_FIRST_MSG, 1, 0) AS relevance,
|
|
IF(COUNT(m.ID_MSG) = 0, t.ID_FIRST_MSG, MAX(m.ID_MSG)) AS ID_MSG, COUNT(m.ID_MSG) AS num_matches
|
|
FROM {$db_prefix}matches AS t
|
|
LEFT JOIN {$db_prefix}messages AS m ON (m.ID_TOPIC = t.ID_TOPIC AND $searchQuery)" . (empty($userQuery) ? '' : "
|
|
WHERE $userQuery") ."
|
|
GROUP BY t.ID_TOPIC";
|
|
|
|
$context['topics'] = array();
|
|
$use_cache = !empty($modSettings['search_cache_size']);
|
|
|
|
// Either the results are not cached, or caching is disabled, so we need to create a temporary table.
|
|
if (!$use_cache || empty($_SESSION['search_cache']) || $_SESSION['search_cache']['params'] != $context['params'])
|
|
{
|
|
// Temporary tables are preferrable, but require the right MySQL permissions.
|
|
if (empty($modSettings['disableTemporaryTables']))
|
|
{
|
|
// Get rid of it if it already exists.
|
|
mysql_query("
|
|
DROP TABLE {$db_prefix}matches");
|
|
|
|
$result = mysql_query("
|
|
CREATE TEMPORARY TABLE {$db_prefix}matches (
|
|
ID_TOPIC mediumint(8) unsigned NOT NULL default '0',
|
|
ID_FIRST_MSG int(10) unsigned NOT NULL default '0',
|
|
numReplies int(11) NOT NULL default '0',
|
|
is_subject tinyint(3) unsigned NOT NULL default '0',
|
|
PRIMARY KEY (ID_TOPIC)
|
|
) TYPE=HEAP");
|
|
|
|
if ($result === false)
|
|
{
|
|
updateSettings(array('disableTemporaryTables' => '1'));
|
|
fatal_lang_error('unable_to_create_temporary');
|
|
}
|
|
|
|
if (!$search_params['subject_only'])
|
|
{
|
|
// Let's determine how many results we can expect.
|
|
db_query("
|
|
INSERT INTO {$db_prefix}matches
|
|
SELECT DISTINCT t.ID_TOPIC, t.ID_FIRST_MSG, t.numReplies, 0 AS is_subject
|
|
FROM {$db_prefix}topics AS t, {$db_prefix}messages AS m
|
|
WHERE t.ID_TOPIC = m.ID_TOPIC" . (empty($search_params['brd']) ? '' : "
|
|
AND m.ID_BOARD IN (" . implode(', ', $search_params['brd']) . ")") . (empty($userQuery) ? '' : "
|
|
AND $userQuery") . "
|
|
AND $searchQuery", __FILE__, __LINE__);
|
|
$messageMatches = db_affected_rows();
|
|
}
|
|
|
|
// Select all topics that have subjects matching the search query.
|
|
db_query("
|
|
INSERT IGNORE INTO {$db_prefix}matches
|
|
SELECT m.ID_TOPIC AS ID_TOPIC, m.ID_MSG, t.numReplies, 1 AS is_subject
|
|
FROM {$db_prefix}topics AS t, {$db_prefix}messages AS m
|
|
WHERE m.ID_MSG = t.ID_FIRST_MSG" . (empty($search_params['brd']) ? '' : "
|
|
AND m.ID_BOARD IN (" . implode(', ', $search_params['brd']) . ")") . (empty($userQuery) ? '' : "
|
|
AND $userQuery") . "
|
|
AND $topicQuery", __FILE__, __LINE__);
|
|
$subjectMatches = db_affected_rows();
|
|
|
|
if (!$search_params['subject_only'])
|
|
{
|
|
$request = db_query("
|
|
SELECT COUNT(ID_TOPIC)
|
|
FROM {$db_prefix}matches", __FILE__, __LINE__);
|
|
list ($numResults) = mysql_fetch_row($request);
|
|
mysql_free_result($request);
|
|
}
|
|
else
|
|
$numResults = $subjectMatches;
|
|
|
|
if (empty($numResults))
|
|
$use_cache = false;
|
|
elseif (!$use_cache || $numResults <= $modSettings['search_results_per_page'])
|
|
{
|
|
$request = db_query("
|
|
SELECT$mainQuery
|
|
ORDER BY $search_params[sort] $search_params[sort_dir]
|
|
LIMIT $_REQUEST[start], $modSettings[search_results_per_page]", __FILE__, __LINE__);
|
|
while ($row = mysql_fetch_assoc($request))
|
|
$context['topics'][$row['ID_MSG']] = array(
|
|
'id' => $row['ID_TOPIC'],
|
|
'relevance' => round(100 * $row['relevance'] / $weight_total, 1) . '%',
|
|
'num_matches' => $row['num_matches'],
|
|
'matches' => array(),
|
|
);
|
|
mysql_free_result($request);
|
|
|
|
// We don't need cache, thank you.
|
|
$use_cache = false;
|
|
}
|
|
// Search is not yet cached, let's cache it.
|
|
elseif ($use_cache)
|
|
{
|
|
$modSettings['search_pointer'] = empty($modSettings['search_pointer']) ? 0 : (int) $modSettings['search_pointer'];
|
|
|
|
// Increase the pointer.
|
|
updateSettings(array('search_pointer' => $modSettings['search_pointer'] >= 255 ? 0 : $modSettings['search_pointer'] + 1));
|
|
|
|
// Make sure this value isn't larger than 255 or the tinyint key field wouldn't be able to handle it.
|
|
$modSettings['search_cache_size'] = empty($modSettings['search_cache_size']) || $modSettings['search_cache_size'] > 255 ? 255 : $modSettings['search_cache_size'];
|
|
|
|
// Remove old cached results and (if set) the previous session cached result.
|
|
db_query("
|
|
DELETE FROM {$db_prefix}log_search
|
|
WHERE (ID_SEARCH >= $modSettings[search_pointer]" . ($modSettings['search_pointer'] < $modSettings['search_cache_size'] ? '
|
|
AND ID_SEARCH < ' . (256 + $modSettings['search_pointer'] - $modSettings['search_cache_size']) : '
|
|
OR ID_SEARCH < ' . ($modSettings['search_pointer'] - $modSettings['search_cache_size'])) . ')' . (isset($_SESSION['search_cache']['ID_SEARCH']) ? "
|
|
OR ID_SEARCH = " . $_SESSION['search_cache']['ID_SEARCH'] : ''), __FILE__, __LINE__);
|
|
|
|
// Insert the new cached results.
|
|
if (!empty($numResults))
|
|
db_query("
|
|
INSERT IGNORE INTO {$db_prefix}log_search
|
|
(ID_SEARCH, ID_TOPIC, relevance, ID_MSG, num_matches)
|
|
SELECT $modSettings[search_pointer], $mainQuery", __FILE__, __LINE__);
|
|
$numResults = empty($numResults) ? 0 : db_affected_rows();
|
|
|
|
// Store it for the session.
|
|
$_SESSION['search_cache'] = array(
|
|
'ID_SEARCH' => $modSettings['search_pointer'],
|
|
'num_results' => $numResults,
|
|
'params' => $context['params'],
|
|
);
|
|
}
|
|
|
|
// Get rid of the temporary table.
|
|
$request = db_query("
|
|
DROP TABLE {$db_prefix}matches", __FILE__, __LINE__);
|
|
}
|
|
// Create temporary tables is disabled, we're gonna need to use PHP's memory and sorting.
|
|
else
|
|
{
|
|
$matchingTopics = array();
|
|
|
|
if (!$search_params['subject_only'])
|
|
{
|
|
// Get all the topics with a message match.
|
|
$request = db_query("
|
|
SELECT DISTINCT t.ID_TOPIC, t.ID_FIRST_MSG, t.numReplies, 0 AS is_subject
|
|
FROM {$db_prefix}topics AS t, {$db_prefix}messages AS m
|
|
WHERE t.ID_TOPIC = m.ID_TOPIC" . (empty($search_params['brd']) ? '' : "
|
|
AND m.ID_BOARD IN (" . implode(', ', $search_params['brd']) . ")") . (empty($userQuery) ? '' : "
|
|
AND $userQuery") . "
|
|
AND $searchQuery", __FILE__, __LINE__);
|
|
while ($row = mysql_fetch_assoc($request))
|
|
$matchingTopics[$row['ID_TOPIC']] = $row;
|
|
$messageMatches = count($matchingTopics);
|
|
}
|
|
|
|
// Get all the topics with a subject match.
|
|
$request = db_query("
|
|
SELECT m.ID_TOPIC AS ID_TOPIC, t.ID_FIRST_MSG, t.numReplies, 1 AS is_subject
|
|
FROM {$db_prefix}topics AS t, {$db_prefix}messages AS m
|
|
WHERE m.ID_MSG = t.ID_FIRST_MSG" . (empty($search_params['brd']) ? '' : "
|
|
AND m.ID_BOARD IN (" . implode(', ', $search_params['brd']) . ")") . (empty($userQuery) ? '' : "
|
|
AND $userQuery") . "
|
|
AND $topicQuery", __FILE__, __LINE__);
|
|
while ($row = mysql_fetch_assoc($request))
|
|
$matchingTopics[$row['ID_TOPIC']] = $row;
|
|
$subjectMatches = db_affected_rows();
|
|
|
|
$numResults = $search_params['subject_only'] ? $subjectMatches : count($matchingTopics);
|
|
|
|
if (empty($numResults))
|
|
$use_cache = false;
|
|
elseif (!$use_cache || $numResults <= $modSettings['search_results_per_page'])
|
|
{
|
|
$sort = array();
|
|
$request = db_query("
|
|
SELECT
|
|
t.ID_TOPIC, COUNT(m.ID_MSG) AS numMsg, MAX(m.ID_MSG) AS lastMatch, MIN(m.ID_MSG) AS firstMatch,
|
|
COUNT(m.ID_MSG) AS num_matches
|
|
FROM {$db_prefix}topics AS t
|
|
LEFT JOIN {$db_prefix}messages AS m ON (m.ID_TOPIC = t.ID_TOPIC AND $searchQuery)" . (empty($userQuery) ? '
|
|
WHERE t.ID_TOPIC IN (' . implode(', ', array_keys($matchingTopics)) . ')' : "
|
|
WHERE $userQuery
|
|
AND t.ID_TOPIC IN (" . implode(', ', array_keys($matchingTopics)) . ")") . "
|
|
GROUP BY t.ID_TOPIC
|
|
LIMIT $_REQUEST[start], $modSettings[search_results_per_page]", __FILE__, __LINE__);
|
|
$tmp = array();
|
|
while ($row = mysql_fetch_assoc($request))
|
|
{
|
|
$relevance =
|
|
$weight['frequency'] * ($row['numMsg'] == 0 ? 0 : $row['numMsg'] / ($matchingTopics[$row['ID_TOPIC']]['numReplies'] + 1)) +
|
|
$weight['age'] * (!isset($row['ID_MSG']) || $row['ID_MSG'] === null || $row['lastMatch'] < $minMsg ? 0 : ($row['lastMatch'] - $minMsg) / $recentMsg) +
|
|
$weight['length'] * ($matchingTopics[$row['ID_TOPIC']]['numReplies'] < $humungousTopicPosts ? $matchingTopics[$row['ID_TOPIC']]['numReplies'] / $humungousTopicPosts : 1) +
|
|
$weight['subject'] * $matchingTopics[$row['ID_TOPIC']]['is_subject'] +
|
|
$weight['first_message'] * ($row['firstMatch'] == $matchingTopics[$row['ID_TOPIC']]['ID_FIRST_MSG'] ? 1 : 0);
|
|
$ID_MSG = $row['numMsg'] == 0 ? $matchingTopics[$row['ID_TOPIC']]['ID_FIRST_MSG'] : $row['lastMatch'];
|
|
$sort[$ID_MSG] = $search_params['sort'] == 'relevance' ? $relevance : ($search_params['sort'] == 'numReplies' ? $matchingTopics[$row['ID_TOPIC']]['numReplies'] : $ID_MSG);
|
|
$tmp[$ID_MSG] = array(
|
|
'id' => $row['ID_TOPIC'],
|
|
'relevance' => round(100 * $relevance / $weight_total, 1) . '%',
|
|
'num_matches' => $row['num_matches'],
|
|
'matches' => array(),
|
|
);
|
|
}
|
|
mysql_free_result($request);
|
|
|
|
// Do the manual sorting.
|
|
if ($search_params['sort_dir'] == 'desc')
|
|
krsort($sort);
|
|
else
|
|
ksort($sort);
|
|
foreach ($sort as $ID_MSG => $value)
|
|
$context['topics'][$ID_MSG] = $tmp[$ID_MSG];
|
|
unset($tmp);
|
|
|
|
// We don't need cache, thank you.
|
|
$use_cache = false;
|
|
}
|
|
// Search is not yet cached, let's do that now.
|
|
elseif ($use_cache)
|
|
{
|
|
$modSettings['search_pointer'] = empty($modSettings['search_pointer']) ? 0 : (int) $modSettings['search_pointer'];
|
|
|
|
$modSettings['search_cache_size'] = empty($modSettings['search_cache_size']) || $modSettings['search_cache_size'] > 255 ? 255 : $modSettings['search_cache_size'];
|
|
|
|
// Remove old cached results.
|
|
db_query("
|
|
DELETE FROM {$db_prefix}log_search
|
|
WHERE (ID_SEARCH >= $modSettings[search_pointer]" . ($modSettings['search_pointer'] < $modSettings['search_cache_size'] ? '
|
|
AND ID_SEARCH < ' . (256 + $modSettings['search_pointer'] - $modSettings['search_cache_size']) : '
|
|
OR ID_SEARCH < ' . ($modSettings['search_pointer'] - $modSettings['search_cache_size'])) . ')' . (isset($_SESSION['search_cache']['ID_SEARCH']) ? "
|
|
OR ID_SEARCH = " . $_SESSION['search_cache']['ID_SEARCH'] : ''), __FILE__, __LINE__);
|
|
|
|
// Insert the new results into cache.
|
|
if (!empty($numResults))
|
|
{
|
|
$insertRows = array();
|
|
$sort = array();
|
|
|
|
// Get all topics that match the search query.
|
|
$request = db_query("
|
|
SELECT
|
|
t.ID_TOPIC, COUNT(m.ID_MSG) AS numMsg, MAX(m.ID_MSG) AS lastMatch, MIN(m.ID_MSG) AS firstMatch
|
|
FROM {$db_prefix}topics AS t
|
|
LEFT JOIN {$db_prefix}messages AS m ON (m.ID_TOPIC = t.ID_TOPIC AND $searchQuery)" . (empty($userQuery) ? '
|
|
WHERE t.ID_TOPIC IN (' . implode(', ', array_keys($matchingTopics)) . ')' : "
|
|
WHERE $userQuery
|
|
AND t.ID_TOPIC IN (" . implode(', ', array_keys($matchingTopics)) . ")") . "
|
|
GROUP BY t.ID_TOPIC", __FILE__, __LINE__);
|
|
$tmp = array();
|
|
while ($row = mysql_fetch_assoc($request))
|
|
{
|
|
$relevance =
|
|
$weight['frequency'] * ($row['numMsg'] == 0 ? 0 : $row['numMsg'] / ($matchingTopics[$row['ID_TOPIC']]['numReplies'] + 1)) +
|
|
$weight['age'] * (!isset($row['ID_MSG']) || $row['ID_MSG'] === null || $row['lastMatch'] < $minMsg ? 0 : ($row['lastMatch'] - $minMsg) / $recentMsg) +
|
|
$weight['length'] * ($matchingTopics[$row['ID_TOPIC']]['numReplies'] < $humungousTopicPosts ? $matchingTopics[$row['ID_TOPIC']]['numReplies'] / $humungousTopicPosts : 1) +
|
|
$weight['subject'] * $matchingTopics[$row['ID_TOPIC']]['is_subject'] +
|
|
$weight['first_message'] * ($row['firstMatch'] == $matchingTopics[$row['ID_TOPIC']]['ID_FIRST_MSG'] ? 1 : 0);
|
|
$ID_MSG = $row['numMsg'] == 0 ? $matchingTopics[$row['ID_TOPIC']]['ID_FIRST_MSG'] : $row['lastMatch'];
|
|
$sort[$ID_MSG] = $search_params['sort'] == 'relevance' ? $relevance : ($search_params['sort'] == 'numReplies' ? $matchingTopics[$row['ID_TOPIC']]['numReplies'] : $ID_MSG);
|
|
$tmp[$ID_MSG] = (isset($tmp[$ID_MSG]) ? $tmp[$ID_MSG] : '') . '(' . (int) $modSettings['search_pointer'] . ', ' . (int) $row['ID_TOPIC'] . ', ' . (int) $relevance . ', ' . (int) $ID_MSG . ', ' . (int) $row['numMsg'] . '),';
|
|
}
|
|
mysql_free_result($request);
|
|
|
|
// Do the sorting of the rows.
|
|
if ($search_params['sort_dir'] == 'desc')
|
|
krsort($sort);
|
|
else
|
|
ksort($sort);
|
|
foreach ($sort as $ID_MSG => $value)
|
|
$insertRows[$ID_MSG] = substr($tmp[$ID_MSG], 0, -1);
|
|
unset($tmp);
|
|
|
|
// Insert the matching topics into the cache.
|
|
if (!empty($insertRows))
|
|
db_query("
|
|
INSERT INTO {$db_prefix}log_search
|
|
(ID_SEARCH, ID_TOPIC, relevance, ID_MSG, num_matches)
|
|
VALUES " . implode(', ', $insertRows), __FILE__, __LINE__);
|
|
}
|
|
$numResults = empty($numResults) ? 0 : db_affected_rows();
|
|
|
|
// Store the cache information into the session.
|
|
$_SESSION['search_cache'] = array(
|
|
'ID_SEARCH' => $modSettings['search_pointer'],
|
|
'num_results' => $numResults,
|
|
'params' => $context['params'],
|
|
);
|
|
|
|
// Increase the cache pointer.
|
|
updateSettings(array('search_pointer' => $modSettings['search_pointer'] >= 255 ? 0 : $modSettings['search_pointer'] + 1));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Current search should be cached by now, grab it.
|
|
if ($use_cache)
|
|
{
|
|
$request = db_query("
|
|
SELECT ls.ID_TOPIC, ls.ID_MSG, ls.relevance, ls.num_matches
|
|
FROM {$db_prefix}log_search AS ls" . ($search_params['sort'] == 'numReplies' ? ", {$db_prefix}topics AS t" : '') . "
|
|
WHERE ID_SEARCH = " . $_SESSION['search_cache']['ID_SEARCH'] . ($search_params['sort'] == 'numReplies' ? "
|
|
AND t.ID_TOPIC = ls.ID_TOPIC" : '') . "
|
|
ORDER BY $search_params[sort] $search_params[sort_dir]
|
|
LIMIT $_REQUEST[start], $modSettings[search_results_per_page]", __FILE__, __LINE__);
|
|
while ($row = mysql_fetch_assoc($request))
|
|
$context['topics'][$row['ID_MSG']] = array(
|
|
'id' => $row['ID_TOPIC'],
|
|
'relevance' => round($row['relevance'] / 10, 1) . '%',
|
|
'num_matches' => $row['num_matches'],
|
|
'matches' => array(),
|
|
);
|
|
mysql_free_result($request);
|
|
|
|
$numResults = $_SESSION['search_cache']['num_results'];
|
|
}
|
|
|
|
// Now that we know how many results to expect we can start calculating the page numbers.
|
|
$context['page_index'] = constructPageIndex($scripturl . '?action=search2;params=' . $context['params'], $_REQUEST['start'], $numResults, $modSettings['search_results_per_page'], false);
|
|
|
|
if (!empty($context['topics']))
|
|
{
|
|
// Create an array for the permissions.
|
|
$boards_can = array(
|
|
'post_reply_own' => boardsAllowedTo('post_reply_own'),
|
|
'post_reply_any' => boardsAllowedTo('post_reply_any'),
|
|
'mark_any_notify' => boardsAllowedTo('mark_any_notify')
|
|
);
|
|
|
|
// Load the posters...
|
|
$request = db_query("
|
|
SELECT ID_MEMBER
|
|
FROM {$db_prefix}messages
|
|
WHERE ID_MEMBER != 0
|
|
AND ID_MSG IN (" . implode(', ', array_keys($context['topics'])) . ')', __FILE__, __LINE__);
|
|
$posters = array();
|
|
while ($row = mysql_fetch_assoc($request))
|
|
$posters[] = $row['ID_MEMBER'];
|
|
mysql_free_result($request);
|
|
|
|
if (!empty($posters))
|
|
loadMemberData(array_unique($posters));
|
|
|
|
// Get the messages out for the callback - select enough that it can be made to look just like Display.
|
|
$messages_request = db_query("
|
|
SELECT
|
|
m.ID_MSG, m.subject, m.posterName, m.posterEmail, m.posterTime, m.ID_MEMBER,
|
|
m.icon, m.posterIP, m.body, m.smileysEnabled, m.modifiedTime, m.modifiedName,
|
|
a.filename, IFNULL(a.size, 0) AS filesize, a.ID_ATTACH, a.downloads,
|
|
first_m.ID_MSG AS first_msg, first_m.subject AS first_subject, first_m.icon, first_m.posterTime AS first_posterTime,
|
|
first_mem.ID_MEMBER AS first_member_id, IFNULL(first_mem.realName, first_m.posterName) AS first_member_name,
|
|
last_m.ID_MSG AS last_msg, last_m.posterTime AS last_posterTime, last_mem.ID_MEMBER AS last_member_id,
|
|
IFNULL(last_mem.realName, last_m.posterName) AS last_member_name,
|
|
t.ID_TOPIC, t.isSticky, t.locked, t.ID_POLL, t.numReplies, t.numViews,
|
|
b.ID_BOARD, b.name AS bName, c.ID_CAT, c.name AS cName
|
|
FROM ({$db_prefix}messages AS m, {$db_prefix}topics AS t, {$db_prefix}boards AS b, {$db_prefix}categories AS c, {$db_prefix}messages AS first_m, {$db_prefix}messages AS last_m)
|
|
LEFT JOIN {$db_prefix}members AS first_mem ON (first_mem.ID_MEMBER = first_m.ID_MEMBER)
|
|
LEFT JOIN {$db_prefix}members AS last_mem ON (last_mem.ID_MEMBER = first_m.ID_MEMBER)
|
|
LEFT JOIN {$db_prefix}attachments AS a ON (a.ID_MSG = m.ID_MSG)
|
|
WHERE m.ID_MSG IN (" . implode(', ', array_keys($context['topics'])) . ")
|
|
AND t.ID_TOPIC = m.ID_TOPIC
|
|
AND b.ID_BOARD = t.ID_BOARD
|
|
AND c.ID_CAT = b.ID_CAT
|
|
AND first_m.ID_MSG = t.ID_FIRST_MSG
|
|
AND last_m.ID_MSG = t.ID_LAST_MSG
|
|
ORDER BY FIND_IN_SET(m.ID_MSG, '" . implode(',', array_keys($context['topics'])) . "')
|
|
LIMIT " . count($context['topics']), __FILE__, __LINE__);
|
|
// Note that the reg-exp slows things alot, but makes things make a lot more sense.
|
|
}
|
|
|
|
$context['key_words'] = &$searchArray;
|
|
|
|
// Set the basic stuff for the template.
|
|
$context['allow_hide_email'] = !empty($modSettings['allow_hideEmail']);
|
|
|
|
$context['sub_template'] = 'results';
|
|
$context['page_title'] = $txt[166];
|
|
$context['get_topics'] = 'prepareSearchContext';
|
|
$context['can_send_pm'] = allowedTo('pm_send');
|
|
|
|
loadJumpTo();
|
|
}
|
|
|
|
// Callback to return messages - saves memory.
|
|
function prepareSearchContext($reset = false)
|
|
{
|
|
global $txt, $modSettings, $scripturl, $ID_MEMBER;
|
|
global $themeUser, $context, $messages_request, $db_prefix, $attachments, $boards_can;
|
|
|
|
// Remember which message this is. (ie. reply #83)
|
|
static $counter = null;
|
|
if ($counter == null || $reset)
|
|
$counter = $_REQUEST['start'] + 1;
|
|
|
|
// If the query returned false, bail.
|
|
if ($messages_request == false)
|
|
return false;
|
|
|
|
// Start from the beginning...
|
|
if ($reset)
|
|
return @mysql_data_seek($messages_request, 0);
|
|
|
|
// Attempt to get the next message.
|
|
$message = mysql_fetch_assoc($messages_request);
|
|
if (!$message)
|
|
return false;
|
|
|
|
// Can't have an empty subject can we?
|
|
$message['subject'] = $message['subject'] != '' ? $message['subject'] : $txt[24];
|
|
$message['first_subject'] = $message['first_subject'] != '' ? $message['first_subject'] : $txt[24];
|
|
|
|
// If it couldn't load, or the user was a guest.... someday may be done with a guest table.
|
|
if (!loadMemberContext($message['ID_MEMBER']))
|
|
{
|
|
// Notice this information isn't used anywhere else.... *cough guest table cough*
|
|
$themeUser[$message['ID_MEMBER']]['name'] = $message['posterName'];
|
|
$themeUser[$message['ID_MEMBER']]['id'] = 0;
|
|
$themeUser[$message['ID_MEMBER']]['group'] = $txt[28];
|
|
$themeUser[$message['ID_MEMBER']]['link'] = $message['posterName'];
|
|
$themeUser[$message['ID_MEMBER']]['email'] = $message['posterEmail'];
|
|
}
|
|
$themeUser[$message['ID_MEMBER']]['ip'] = $message['posterIP'];
|
|
|
|
// Do the censor thang...
|
|
censorText($message['body']);
|
|
censorText($message['subject']);
|
|
|
|
censorText($message['first_subject']);
|
|
|
|
// Shorten this message if necessary.
|
|
if ($context['compact'])
|
|
{
|
|
// Set the number of characters before and after the searched keyword.
|
|
$charLimit = 40;
|
|
|
|
$message['body'] = strtr($message['body'], array("\n" => ' ', '<br />' => "\n"));
|
|
$message['body'] = doUBBC($message['body'], $message['smileysEnabled']);
|
|
$message['body'] = strip_tags($message['body']);
|
|
|
|
if (strlen($message['body']) > $charLimit)
|
|
{
|
|
if (empty($context['key_words']))
|
|
$message['body'] = htmlspecialchars(substr(un_htmlspecialchars($message['body']), 0, $charLimit) . (strlen($message['body']) > $charLimit ? '<b>...</b>' : ''), ENT_QUOTES);
|
|
else
|
|
{
|
|
$matchString = '';
|
|
foreach ($context['key_words'] as $keyword)
|
|
$matchString .= strtr(preg_quote($keyword, '/'), array('\*' => '.+?')) . '|';
|
|
$matchString = substr($matchString, 0, -1);
|
|
$message['body'] = un_htmlspecialchars(str_replace(' ', ' ', $message['body']));
|
|
if (empty($modSettings['search_match_complete_words']))
|
|
preg_match_all('/([^\s\W]{' . $charLimit . '}[\s\W]|[\s\W].{0,' . $charLimit . '}?|^)(' . $matchString . ')(.{0,' . $charLimit . '}[\s\W]|[^\s\W]{' . $charLimit . '})/is', $message['body'], $matches);
|
|
else
|
|
preg_match_all('/([^\s\W]{' . $charLimit . '}[\s\W]|[\s\W].{0,' . $charLimit . '}?[\s\W]|^)(' . $matchString . ')([\s\W].{0,' . $charLimit . '}[\s\W]|[\s\W][^\s\W]{' . $charLimit . '})/is', $message['body'], $matches);
|
|
$message['body'] = '';
|
|
foreach ($matches[0] as $index => $match)
|
|
$message['body'] .= '<b>...</b> ' . htmlspecialchars($match, ENT_QUOTES) . ' <b>...</b><br />';
|
|
}
|
|
|
|
// Re-fix the international characters.
|
|
$message['body'] = preg_replace('~&#(\d{4,5}|[3-9]\d{2,4}|2[6-9]\d);~', '&#$1;', $message['body']);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Run UBBC interpreter on the message.
|
|
$message['body'] = doUBBC($message['body'], $message['smileysEnabled']);
|
|
}
|
|
|
|
$output = array_merge($context['topics'][$message['ID_MSG']], array(
|
|
'is_sticky' => !empty($modSettings['enableStickyTopics']) && !empty($message['isSticky']),
|
|
'is_locked' => !empty($message['locked']),
|
|
'is_poll' => $modSettings['pollMode'] == '1' && $message['ID_POLL'] > 0,
|
|
'is_hot' => $message['numReplies'] >= $modSettings['hotTopicPosts'],
|
|
'is_very_hot' => $message['numReplies'] >= $modSettings['hotTopicVeryPosts'],
|
|
'views' => $message['numViews'],
|
|
'replies' => $message['numReplies'],
|
|
'can_reply' => in_array($message['ID_BOARD'], $boards_can['post_reply_any']) || in_array(0, $boards_can['post_reply_any']),
|
|
'can_mark_notify' => in_array($message['ID_BOARD'], $boards_can['mark_any_notify']) || in_array(0, $boards_can['mark_any_notify']),
|
|
'first_post' => array(
|
|
'id' => $message['first_msg'],
|
|
'time' => timeformat($message['first_posterTime']),
|
|
'subject' => $message['first_subject'],
|
|
'href' => $scripturl . '?topic=' . $message['ID_TOPIC'] . '.0',
|
|
'link' => '<a href="' . $scripturl . '?topic=' . $message['ID_TOPIC'] . '.0">' . $message['first_subject'] . '</a>',
|
|
'icon' => $message['icon'],
|
|
'member' => array(
|
|
'id' => $message['first_member_id'],
|
|
'name' => $message['first_member_name'],
|
|
'href' => !empty($message['first_member_id']) ? $scripturl . '?action=profile;u=' . $message['first_member_id'] : '',
|
|
'link' => !empty($message['first_member_id']) ? '<a href="' . $scripturl . '?action=profile;u=' . $message['first_member_id'] . '" title="' . $txt[92] . ' ' . $message['first_member_name'] . '">' . $message['first_member_name'] . '</a>' : $message['first_member_name']
|
|
)
|
|
),
|
|
'last_post' => array(
|
|
'id' => $message['last_msg'],
|
|
'time' => timeformat($message['last_posterTime']),
|
|
'timestamp' => $message['last_posterTime'],
|
|
'member' => array(
|
|
'id' => $message['last_member_id'],
|
|
'name' => $message['last_member_name'],
|
|
'href' => !empty($message['last_member_id']) ? $scripturl . '?action=profile;u=' . $message['last_member_id'] : '',
|
|
'link' => !empty($message['last_member_id']) ? '<a href="' . $scripturl . '?action=profile;u=' . $message['last_member_id'] . '" title="' . $txt[92] . ' ' . $message['last_member_name'] . '">' . $message['last_member_name'] . '</a>' : $message['last_member_name']
|
|
)
|
|
),
|
|
'board' => array(
|
|
'id' => $message['ID_BOARD'],
|
|
'name' => $message['bName'],
|
|
'href' => $scripturl . '?board=' . $message['ID_BOARD'] . '.0',
|
|
'link' => '<a href="' . $scripturl . '?board=' . $message['ID_BOARD'] . '.0">' . $message['bName'] . '</a>'
|
|
),
|
|
'category' => array(
|
|
'id' => $message['ID_CAT'],
|
|
'name' => $message['cName'],
|
|
'href' => $scripturl . '#' . $message['ID_CAT'],
|
|
'link' => '<a href="' . $scripturl . '#' . $message['ID_CAT'] . '">' . $message['cName'] . '</a>'
|
|
)
|
|
));
|
|
determineTopicClass($output);
|
|
|
|
$body_highlighted = $message['body'];
|
|
$subject_highlighted = $message['subject'];
|
|
|
|
foreach ($context['key_words'] as $query)
|
|
{
|
|
// Fix the international characters in the keyword too.
|
|
$query = preg_replace('~&#(\d{4,5}|[3-9]\d{2,4}|2[6-9]\d);~', '&#$1;', strtr(preg_quote($query, '/'), array('&' => '&')));
|
|
|
|
$body_highlighted = preg_replace('/((<[^>]*)|' . $query . ')/ie', "'\$2' == '\$1' ? stripslashes('\$1') : '<b class=\"highlight\">\$1</b>'", $body_highlighted);
|
|
$subject_highlighted = preg_replace('/((<[^>]*)|' . $query . ')/ie', "'$2' == '$1' ? stripslashes('$1') : '<b class=\"highlight\">$1</b>'", $subject_highlighted);
|
|
}
|
|
|
|
$output['matches'][] = array(
|
|
'id' => $message['ID_MSG'],
|
|
'attachment' => loadAttachmentContext($message['ID_MSG']),
|
|
'alternate' => $counter % 2,
|
|
'member' => &$themeUser[$message['ID_MEMBER']],
|
|
'icon' => $message['icon'],
|
|
'subject' => $message['subject'],
|
|
'subject_highlighted' => $subject_highlighted,
|
|
'time' => timeformat($message['posterTime']),
|
|
'timestamp' => $message['posterTime'],
|
|
'counter' => $counter,
|
|
'modified' => array(
|
|
'time' => timeformat($message['modifiedTime']),
|
|
'timestamp' => $message['modifiedTime'],
|
|
'name' => $message['modifiedName']
|
|
),
|
|
'body' => $message['body'],
|
|
'body_highlighted' => $body_highlighted,
|
|
'start' => 'msg' . $message['ID_MSG']
|
|
);
|
|
$counter++;
|
|
|
|
return $output;
|
|
}
|
|
|
|
?>
|