Файл: library/XenForo/ControllerPublic/Search.php
Строк: 667
<?php
/**
* Search controller.
*
* @package XenForo_Search
*/
class XenForo_ControllerPublic_Search extends XenForo_ControllerPublic_Abstract
{
/**
* Displays a form to do an advanced search.
*
* @return XenForo_ControllerResponse_Abstract
*/
public function actionIndex()
{
$search = array(
'child_nodes' => true,
'order' => 'date'
);
$searchId = $this->_input->filterSingle('search_id', XenForo_Input::UINT);
if ($searchId)
{
if ($this->_input->filterSingle('searchform', XenForo_Input::UINT))
{
$params = $this->_input->filter(array(
'q' => XenForo_Input::STRING,
't' => XenForo_Input::STRING,
'o' => XenForo_Input::STRING,
'g' => XenForo_Input::UINT,
'c' => XenForo_Input::ARRAY_SIMPLE
));
// allow this to pass through for the search type check later
$this->_request->setParam('type', $params['t']);
$users = '';
if (!empty($params['c']['user']))
{
foreach ($this->_getUserModel()->getUsersByIds($params['c']['user']) AS $user)
{
$users .= $user['username'] . ', ';
}
$users = substr($users, 0, -2);
}
if (!empty($params['c']['node']))
{
$nodes = array_fill_keys(explode(' ', $params['c']['node']), true);
}
else
{
$nodes = array();
}
if (!empty($params['c']['date']))
{
$date = XenForo_Locale::date(intval($params['c']['date']), 'picker');
}
else
{
$date = '';
}
if (!empty($params['c']['user_content']))
{
$userContent = $params['c']['user_content'];
}
else
{
$userContent = '';
}
$search = array_merge($search, array(
'keywords' => $params['q'],
'title_only' => !empty($params['c']['title_only']),
'users' => $users,
'user_content' => $userContent,
'date' => $date,
'nodes' => $nodes,
'child_nodes' => empty($nodes),
'order' => $params['o'],
'group_discussion' => $params['g'],
'existing' => true
));
}
else
{
return $this->responseReroute(__CLASS__, 'results');
}
}
if (!XenForo_Visitor::getInstance()->canSearch())
{
throw $this->getNoPermissionResponseException();
}
$nodeId = $this->_input->filterSingle('node_id', XenForo_Input::UINT);
if ($nodeId)
{
$search['nodes'][$nodeId] = true;
}
$viewParams = array(
'supportsRelevance' => XenForo_Search_SourceHandler_Abstract::getDefaultSourceHandler()->supportsRelevance(),
'nodes' => $this->_getNodeModel()->getViewableNodeList(null, true),
'search' => (empty($search) ? array() : $search)
);
$searchType = $this->_input->filterSingle('type', XenForo_Input::STRING);
if ($searchType)
{
$typeHandler = $this->_getSearchModel()->getSearchDataHandler($searchType);
if ($typeHandler)
{
$viewParams['searchType'] = $searchType;
$response = $typeHandler->getSearchFormControllerResponse($this, $this->_input, $viewParams);
if ($response)
{
return $response;
}
}
}
$viewParams['searchType'] = '';
return $this->responseView('XenForo_ViewPublic_Search_Form', 'search_form', $viewParams);
}
/**
* Performs a search.
*
* @return XenForo_ControllerResponse_Abstract
*/
public function actionSearch()
{
// note: intentionally not post-only
if (!XenForo_Visitor::getInstance()->canSearch())
{
throw $this->getNoPermissionResponseException();
}
$input = $this->_input->filter(array(
'keywords' => XenForo_Input::STRING,
'title_only' => XenForo_Input::UINT,
'date' => XenForo_Input::DATE_TIME,
'users' => XenForo_Input::STRING,
'nodes' => array(XenForo_Input::UINT, 'array' => true),
'child_nodes' => XenForo_Input::UINT,
'user_content' => XenForo_Input::STRING,
'order' => XenForo_Input::STRING,
'group_discussion' => XenForo_Input::UINT
));
$input['type'] = $this->_handleInputType($input);
if (!$input['order'])
{
$input['order'] = 'date';
}
$origKeywords = $input['keywords'];
$input['keywords'] = XenForo_Helper_String::censorString($input['keywords'], null, ''); // don't allow searching of censored stuff
$visitorUserId = XenForo_Visitor::getUserId();
$searchModel = $this->_getSearchModel();
$constraints = $searchModel->getGeneralConstraintsFromInput($input, $errors);
if ($errors)
{
return $this->responseError($errors);
}
if (!$input['type'] && $input['keywords'] === ''
&& count($constraints) == 1
&& !empty($constraints['user']) && count($constraints['user']) == 1
)
{
// we're searching for messages by a single user
$this->_request->setParam('user_id', reset($constraints['user']));
return $this->responseReroute(__CLASS__, 'member');
}
if ($input['keywords'] === '' && empty($constraints['user']))
{
// must have keyword or user constraint
return $this->responseError(new XenForo_Phrase('please_specify_search_query_or_name_of_member'));
}
$typeHandler = null;
if ($input['type'])
{
if (is_array($input['type']))
{
$typeInfo = $input['type'];
list($input['type'], $contentInfo) = each($input['type']);
list($contentType, $contentId) = each($contentInfo);
}
$typeHandler = $searchModel->getSearchDataHandler($input['type']);
if ($typeHandler)
{
$constraints = array_merge($constraints,
$typeHandler->getTypeConstraintsFromInput($this->_input)
);
}
else
{
$input['type'] = '';
}
}
$search = $searchModel->getExistingSearch(
$input['type'], $input['keywords'], $constraints, $input['order'], $input['group_discussion'], $visitorUserId
);
if (!$search)
{
$searcher = new XenForo_Search_Searcher($searchModel);
if ($typeHandler)
{
$results = $searcher->searchType(
$typeHandler, $input['keywords'], $constraints, $input['order'], $input['group_discussion']
);
$userResults = array();
}
else
{
$results = $searcher->searchGeneral($input['keywords'], $constraints, $input['order']);
$userResults = $this->_getUserSearch($input['keywords']);
}
if (!$results && !$userResults)
{
return $this->getNoSearchResultsResponse($searcher);
}
$warnings = $searcher->getErrors() + $searcher->getWarnings();
$search = $searchModel->insertSearch(
$results, $input['type'], $origKeywords, $constraints, $input['order'], $input['group_discussion'], $userResults,
$warnings, $visitorUserId
);
}
return $this->responseRedirect(
XenForo_ControllerResponse_Redirect::SUCCESS,
XenForo_Link::buildPublicLink('search', $search),
''
);
}
/**
* Handles the special case of 'type' being submitted as type[post][thread_id] = x,
* In which case, the input should be translated as type=post, thread_id=x
*
* @return string
*/
protected function _handleInputType(array &$input = array())
{
if ($this->_input->inRequest('type'))
{
$typeParam = $this->_request->get('type');
if (is_array($typeParam) && !empty($typeParam))
{
list($type, $typeExtra) = each($typeParam);
if (is_array($typeExtra)) {
foreach ($typeExtra AS $paramName => $paramValue)
{
if (!empty($paramName) && !empty($paramValue))
{
$paramNameClean = XenForo_Input::rawFilter($paramName, XenForo_Input::STRING);
$this->_request->setParam($paramNameClean, $paramValue);
if (isset($input[$paramNameClean]))
{
$input[$paramNameClean] = $paramValue;
}
}
}
}
return XenForo_Input::rawFilter($type, XenForo_Input::STRING);
}
else
{
return $this->_input->filterSingle('type', XenForo_Input::STRING);
}
}
return '';
}
/**
* Searches for recent content by the specified member.
*
* @return XenForo_ControllerResponse_Abstract
*/
public function actionMember()
{
$userId = $this->_input->filterSingle('user_id', XenForo_Input::UINT);
$user = $this->_getUserModel()->getUserById($userId);
if (!$user)
{
return $this->responseError(new XenForo_Phrase('requested_member_not_found'), 404);
}
$searchModel = $this->_getSearchModel();
$maxDate = $this->_input->filterSingle('before', XenForo_Input::UINT);
$content = $this->_input->filterSingle('content', XenForo_Input::STRING);
if ($content)
{
$constraints = array(
'user' => array($userId),
'content' => $content,
'title_only' => true
);
if ($maxDate)
{
$constraints['date_max'] = $maxDate;
}
$searcher = new XenForo_Search_Searcher($searchModel);
$results = $searcher->searchGeneral('', $constraints, 'date');
}
else
{
$searchModel = $this->_getSearchModel();
$searcher = new XenForo_Search_Searcher($searchModel);
$results = $searcher->searchUser($userId, $maxDate);
}
if (!$results)
{
return $this->getNoSearchResultsResponse($searcher);
}
$search = $searchModel->insertSearch($results, 'user', '', array('user_id' => $userId, 'content' => $content ? $content : false), 'date', false);
return $this->responseRedirect(
XenForo_ControllerResponse_Redirect::SUCCESS,
XenForo_Link::buildPublicLink('search', $search),
''
);
}
/**
* Displays the results of a search.
*
* @return XenForo_ControllerResponse_Abstract
*/
public function actionResults()
{
$searchModel = $this->_getSearchModel();
$searchId = $this->_input->filterSingle('search_id', XenForo_Input::UINT);
$searchQuery = $this->_input->filterSingle('q', XenForo_Input::STRING);
$search = $searchModel->getSearchById($searchId);
if (!$search)
{
$rerunSearch = true;
}
else if ($search['user_id'] != XenForo_Visitor::getUserId())
{
if ($search['search_query'] === '' || $search['search_query'] !== $searchQuery)
{
// just browsing searches without having query
return $this->responseError(new XenForo_Phrase('requested_search_not_found'), 404);
}
$rerunSearch = true;
}
else
{
$rerunSearch = false;
}
if ($rerunSearch)
{
$rerunInput = $this->_input->filter(array(
'q' => XenForo_Input::STRING,
't' => XenForo_Input::STRING,
'o' => XenForo_Input::STRING,
'g' => XenForo_Input::UINT,
'c' => XenForo_Input::ARRAY_SIMPLE
));
$rerun = array(
'search_query' => $rerunInput['q'],
'search_type' => $rerunInput['t'],
'search_order' => $rerunInput['o'],
'search_grouping' => $rerunInput['g'],
);
$newSearch = $this->rerunSearch($rerun, $rerunInput['c']);
return $this->responseRedirect(
XenForo_ControllerResponse_Redirect::SUCCESS,
XenForo_Link::buildPublicLink('search', $newSearch)
);
}
$page = max(1, $this->_input->filterSingle('page', XenForo_Input::UINT));
$perPage = XenForo_Application::get('options')->searchResultsPerPage;
$pageResultIds = $searchModel->sliceSearchResultsToPage($search, $page, $perPage);
$results = $searchModel->getSearchResultsForDisplay($pageResultIds);
if (!$results)
{
return $this->getNoSearchResultsResponse($search);
}
$resultStartOffset = ($page - 1) * $perPage + 1;
$resultEndOffset = ($page - 1) * $perPage + count($results['results']);
if ($search['search_type'] == 'user'
&& $search['result_count'] > $perPage
&& $resultEndOffset >= $search['result_count']
)
{
// user search on last page (with more than one page)
$last = end($results['results']);
$userSearchMaxDate = $results['handlers'][$last[XenForo_Model_Search::CONTENT_TYPE]]->getResultDate($last['content']);
}
else
{
$userSearchMaxDate = false;
}
$ignoredNames = array();
foreach ($results['results'] AS $result)
{
$content = $result['content'];
if (!empty($content['isIgnored']) && !empty($content['user_id']) && !empty($content['username']))
{
$ignoredNames[$content['user_id']] = $content['username'];
}
}
$viewParams = array(
'search' => $searchModel->prepareSearch($search),
'results' => $results,
'ignoredNames' => $ignoredNames,
'resultStartOffset' => $resultStartOffset,
'resultEndOffset' => $resultEndOffset,
'page' => $page,
'perPage' => $perPage,
'totalResults' => $search['result_count'],
'nextPage' => ($resultEndOffset < $search['result_count'] ? ($page + 1) : 0),
'userSearchMaxDate' => $userSearchMaxDate,
);
return $this->responseView('XenForo_ViewPublic_Search_Results', 'search_results', $viewParams);
}
/**
* Reruns the given search. If errors occur, a response exception will be thrown.
*
* @param array $search Search info (does not need search_id, constraints, results, or warnings)
* @param array $constraints Array of search constraints
*
* @return array New search
*/
public function rerunSearch(array $search, array $constraints)
{
if (!XenForo_Visitor::getInstance()->canSearch())
{
throw $this->getNoPermissionResponseException();
}
$visitorUserId = XenForo_Visitor::getUserId();
$searchModel = $this->_getSearchModel();
$existingSearch = $searchModel->getExistingSearch(
$search['search_type'], $search['search_query'], $constraints,
$search['search_order'], $search['search_grouping'], $visitorUserId
);
if ($existingSearch)
{
return $existingSearch;
}
$typeHandler = null;
if ($search['search_type'])
{
$typeHandler = $searchModel->getSearchDataHandler($search['search_type']);
}
$searcher = new XenForo_Search_Searcher($searchModel);
$userResults = array();
if ($typeHandler)
{
$results = $searcher->searchType(
$typeHandler, $search['search_query'], $constraints,
$search['search_order'], $search['search_grouping']
);
$userResults = array();
}
else
{
$search['search_type'] = '';
$results = $searcher->searchGeneral(
$search['search_query'], $constraints, $search['search_order']
);
$userResults = $this->_getUserSearch($search['search_query']);
}
if (!$results && !$userResults)
{
throw $this->responseException($this->getNoSearchResultsResponse($searcher));
}
return $searchModel->insertSearch(
$results, $search['search_type'], $search['search_query'], $constraints,
$search['search_order'], $existingSearch['search_grouping'], $userResults,
$searcher->getWarnings(), $visitorUserId
);
}
/**
* Performs a simple search for users with names matching the given query string as a prefix
*
* @param string $queryString
*
* @return array User IDs
*/
protected function _getUserSearch($queryString)
{
if (XenForo_Application::get('options')->searchUsersWithContent && utf8_strlen($queryString) >= 2)
{
$users = $this->_getUserModel()->getUsers(
array('username' => array($queryString , 'r'), 'user_state' => 'valid', 'is_banned' => 0),
array('limit' => 10)
);
return array_keys($users);
}
return array();
}
/**
* Handles the response behavior when there are no search results.
*
* @param XenForo_Search_Searcher|array $search
*
* @return XenForo_ControllerResponse_Abstract
*/
public function getNoSearchResultsResponse($search)
{
if ($search instanceof XenForo_Search_Searcher)
{
$errors = $search->getErrors();
if ($errors)
{
return $this->responseError($errors);
}
}
else if (is_array($search) && !empty($search['user_results']))
{
$viewParams = array('search' => $this->_getSearchModel()->prepareSearch($search));
return $this->responseView('XenForo_ViewPublic_Search_UserResults', 'search_results_users_only', $viewParams);
}
return $this->responseMessage(new XenForo_Phrase('no_results_found'));
}
/**
* Session activity details.
* @see XenForo_Controller::getSessionActivityDetailsForList()
*/
public static function getSessionActivityDetailsForList(array $activities)
{
return new XenForo_Phrase('searching');
}
/**
* Gets the specified search for the specified permission combination, or throws an error.
* A valid search with out
*
* @param integer $searchId
* @param string $searchQuery Text being searched for; prevents browsing of search terms
*
* @return array
*/
protected function _getSearchOrError($searchId, $searchQuery)
{
$searchModel = $this->_getSearchModel();
$search = $searchModel->getSearchById($searchId);
if (!$search || $search['search_query'] !== $searchQuery)
{
throw $this->responseException($this->responseError(new XenForo_Phrase('requested_search_not_found'), 404));
}
return $searchModel->prepareSearch($search);
}
/**
* @return XenForo_Model_Search
*/
protected function _getSearchModel()
{
return $this->getModelFromCache('XenForo_Model_Search');
}
/**
* @return XenForo_Model_Node
*/
protected function _getNodeModel()
{
return $this->getModelFromCache('XenForo_Model_Node');
}
/**
* @return XenForo_Model_User
*/
protected function _getUserModel()
{
return $this->getModelFromCache('XenForo_Model_User');
}
}