static function getSearchEngine() { if (!self::$searchEngine) { self::$searchEngine = SearchEngine::create(); } return self::$searchEngine; }
/** * Perform actual update for the entry */ public function doUpdate() { global $wgDisableSearchUpdate; if ($wgDisableSearchUpdate || !$this->id) { return; } foreach (SearchEngine::getSearchTypes() as $type) { $search = SearchEngine::create($type); if (!$search->supports('search-update')) { continue; } $normalTitle = $this->getNormalizedTitle($search); if ($this->getLatestPage() === null) { $search->delete($this->id, $normalTitle); continue; } elseif ($this->content === false) { $search->updateTitle($this->id, $normalTitle); continue; } $text = $search->getTextFromContent($this->title, $this->content); if (!$search->textAlreadyUpdatedForIndex()) { $text = self::updateText($text); } # Perform the actual update $search->update($this->id, $normalTitle, $search->normalizeText($text)); } }
/** * Perform actual update for the entry */ public function doUpdate() { global $wgDisableSearchUpdate; if ($wgDisableSearchUpdate || !$this->id) { return; } wfProfileIn(__METHOD__); $page = WikiPage::newFromId($this->id, WikiPage::READ_LATEST); $indexTitle = Title::indexTitle($this->title->getNamespace(), $this->title->getText()); foreach (SearchEngine::getSearchTypes() as $type) { $search = SearchEngine::create($type); if (!$search->supports('search-update')) { continue; } $normalTitle = $search->normalizeText($indexTitle); if ($page === null) { $search->delete($this->id, $normalTitle); continue; } elseif ($this->content === false) { $search->updateTitle($this->id, $normalTitle); continue; } $text = $search->getTextFromContent($this->title, $this->content); if (!$search->textAlreadyUpdatedForIndex()) { $text = self::updateText($text); } # Perform the actual update $search->update($this->id, $normalTitle, $search->normalizeText($text)); } wfProfileOut(__METHOD__); }
public function execute($parameters) { global $wgOut, $wgRequest, $wgDisableTextSearch, $wgScript; $this->setHeaders(); list($limit, $offset) = wfCheckLimits(); $wgOut->addWikiText(wfMsgForContentNoTrans('proofreadpage_specialpage_text')); $this->searchList = null; $this->searchTerm = $wgRequest->getText('key'); $this->suppressSqlOffset = false; if (!$wgDisableTextSearch) { $self = $this->getTitle(); $wgOut->addHTML(Xml::openElement('form', array('action' => $wgScript)) . Html::hidden('title', $this->getTitle()->getPrefixedText()) . Xml::input('limit', false, $limit, array('type' => 'hidden')) . Xml::openElement('fieldset') . Xml::element('legend', null, wfMsg('proofreadpage_specialpage_legend')) . Xml::input('key', 20, $this->searchTerm) . ' ' . Xml::submitButton(wfMsg('ilsubmit')) . Xml::closeElement('fieldset') . Xml::closeElement('form')); if ($this->searchTerm) { $index_namespace = $this->index_namespace; $index_ns_index = MWNamespace::getCanonicalIndex(strtolower(str_replace(' ', '_', $index_namespace))); $searchEngine = SearchEngine::create(); $searchEngine->setLimitOffset($limit, $offset); $searchEngine->setNamespaces(array($index_ns_index)); $searchEngine->showRedirects = false; $textMatches = $searchEngine->searchText($this->searchTerm); $escIndex = preg_quote($index_namespace, '/'); $this->searchList = array(); while ($result = $textMatches->next()) { $title = $result->getTitle(); if ($title->getNamespace() == $index_ns_index) { array_push($this->searchList, $title->getDBkey()); } } $this->suppressSqlOffset = true; } } parent::execute($parameters); }
protected function setUp() { parent::setUp(); if (!$this->isWikitextNS(NS_MAIN)) { $this->markTestSkipped('Main namespace does not support wikitext.'); } // Avoid special pages from extensions interferring with the tests $this->setMwGlobals('wgSpecialPages', array()); $this->search = SearchEngine::create(); $this->search->setNamespaces(array()); }
/** * @param ApiPageSet $resultPageSet */ private function run($resultPageSet = null) { $params = $this->extractRequestParams(); $search = $params['search']; $limit = $params['limit']; $namespaces = $params['namespace']; $offset = $params['offset']; $searchEngine = SearchEngine::create(); $searchEngine->setLimitOffset($limit + 1, $offset); $searchEngine->setNamespaces($namespaces); $titles = $searchEngine->extractTitles($searchEngine->completionSearchWithVariants($search)); if ($resultPageSet) { $resultPageSet->setRedirectMergePolicy(function (array $current, array $new) { if (!isset($current['index']) || $new['index'] < $current['index']) { $current['index'] = $new['index']; } return $current; }); if (count($titles) > $limit) { $this->setContinueEnumParameter('offset', $offset + $params['limit']); array_pop($titles); } $resultPageSet->populateFromTitles($titles); foreach ($titles as $index => $title) { $resultPageSet->setGeneratorData($title, array('index' => $index + $offset + 1)); } } else { $result = $this->getResult(); $count = 0; foreach ($titles as $title) { if (++$count > $limit) { $this->setContinueEnumParameter('offset', $offset + $params['limit']); break; } $vals = array('ns' => intval($title->getNamespace()), 'title' => $title->getPrefixedText()); if ($title->isSpecialPage()) { $vals['special'] = true; } else { $vals['pageid'] = intval($title->getArticleId()); } $fit = $result->addValue(array('query', $this->getModuleName()), null, $vals); if (!$fit) { $this->setContinueEnumParameter('offset', $offset + $count - 1); break; } } $result->addIndexedTagName(array('query', $this->getModuleName()), $this->getModulePrefix()); } }
private function run($resultPageSet = null) { global $wgUser; // XX Added to minimize perf issues with full text searching if ($wgUser->isAnon()) { $this->dieUsage("Search query api is disabled", 'param-search'); } $params = $this->extractRequestParams(); $limit = $params['limit']; $query = $params['search']; if (is_null($query) || empty($query)) { $this->dieUsage("empty search string is not allowed", 'param-search'); } $search = SearchEngine::create(); $search->setLimitOffset($limit + 1, $params['offset']); $search->setNamespaces($params['namespace']); $search->showRedirects = $params['redirects']; if ($params['what'] == 'text') { $matches = $search->searchText($query); } else { $matches = $search->searchTitle($query); } $data = array(); $count = 0; while ($result = $matches->next()) { if (++$count > $limit) { // We've reached the one extra which shows that there are additional items to be had. Stop here... $this->setContinueEnumParameter('offset', $params['offset'] + $params['limit']); break; } $title = $result->getTitle(); if (is_null($resultPageSet)) { $data[] = array('ns' => intval($title->getNamespace()), 'title' => $title->getPrefixedText()); } else { $data[] = $title; } } if (is_null($resultPageSet)) { $result = $this->getResult(); $result->setIndexedTagName($data, 'p'); $result->addValue('query', $this->getModuleName(), $data); } else { $resultPageSet->populateFromTitles($data); } }
function doUpdate() { global $wgContLang, $wgDisableSearchUpdate; if ($wgDisableSearchUpdate || !$this->mId) { return false; } wfProfileIn(__METHOD__); $search = SearchEngine::create(); $lc = SearchEngine::legalSearchChars() . '&#;'; if ($this->mText === false) { $search->updateTitle($this->mId, $search->normalizeText(Title::indexTitle($this->mNamespace, $this->mTitle))); wfProfileOut(__METHOD__); return; } # Language-specific strip/conversion $text = $wgContLang->normalizeForSearch($this->mText); wfProfileIn(__METHOD__ . '-regexps'); $text = preg_replace("/<\\/?\\s*[A-Za-z][^>]*?>/", ' ', $wgContLang->lc(" " . $text . " ")); # Strip HTML markup $text = preg_replace("/(^|\\n)==\\s*([^\\n]+)\\s*==(\\s)/sD", "\\1\\2 \\2 \\2\\3", $text); # Emphasize headings # Strip external URLs $uc = "A-Za-z0-9_\\/:.,~%\\-+&;#?!=()@\\x80-\\xFF"; $protos = "http|https|ftp|mailto|news|gopher"; $pat = "/(^|[^\\[])({$protos}):[{$uc}]+([^{$uc}]|\$)/"; $text = preg_replace($pat, "\\1 \\3", $text); $p1 = "/([^\\[])\\[({$protos}):[{$uc}]+]/"; $p2 = "/([^\\[])\\[({$protos}):[{$uc}]+\\s+([^\\]]+)]/"; $text = preg_replace($p1, "\\1 ", $text); $text = preg_replace($p2, "\\1 \\3 ", $text); # Internal image links $pat2 = "/\\[\\[image:([{$uc}]+)\\.(gif|png|jpg|jpeg)([^{$uc}])/i"; $text = preg_replace($pat2, " \\1 \\3", $text); $text = preg_replace("/([^{$lc}])([{$lc}]+)]]([a-z]+)/", "\\1\\2 \\2\\3", $text); # Handle [[game]]s # Strip all remaining non-search characters $text = preg_replace("/[^{$lc}]+/", " ", $text); # Handle 's, s' # # $text = preg_replace( "/([{$lc}]+)'s /", "\\1 \\1's ", $text ); # $text = preg_replace( "/([{$lc}]+)s' /", "\\1s ", $text ); # # These tail-anchored regexps are insanely slow. The worst case comes # when Japanese or Chinese text (ie, no word spacing) is written on # a wiki configured for Western UTF-8 mode. The Unicode characters are # expanded to hex codes and the "words" are very long paragraph-length # monstrosities. On a large page the above regexps may take over 20 # seconds *each* on a 1GHz-level processor. # # Following are reversed versions which are consistently fast # (about 3 milliseconds on 1GHz-level processor). # $text = strrev(preg_replace("/ s'([{$lc}]+)/", " s'\\1 \\1", strrev($text))); $text = strrev(preg_replace("/ 's([{$lc}]+)/", " s\\1", strrev($text))); # Strip wiki '' and ''' $text = preg_replace("/''[']*/", " ", $text); wfProfileOut(__METHOD__ . '-regexps'); wfRunHooks('SearchUpdate', array($this->mId, $this->mNamespace, $this->mTitle, &$text)); # Perform the actual update $search->update($this->mId, $search->normalizeText(Title::indexTitle($this->mNamespace, $this->mTitle)), $search->normalizeText($text)); wfProfileOut(__METHOD__); }
/** * @param $fieldSet String */ public function showResults($fieldSet) { global $wgOut, $wgUser, $wgContLang, $wgScript, $wgSolrShowRelated, $wgSolrDebug; wfProfileIn(__METHOD__); $sk = $wgUser->getSkin(); $this->searchEngine = SearchEngine::create(); $search =& $this->searchEngine; $search->setLimitOffset($this->limit, $this->offset); $this->setupPage($fieldSet); $t = Title::newFromText($fieldSet->getName()); //Do we have Title matches $fields = $fieldSet->getFields(); //Build Solr query string form the fields if (isset($fields['solrsearch'])) { $query = $fields['solrsearch']; } else { $query = ''; } $firsttime = true; $fieldSeperator = $fieldSet->getFieldSeperator(); foreach ($fields as $key => $value) { if ($key != 'solrsearch' && !empty($value)) { if ($firsttime) { $query = trim($query) . ' ' . trim(substr($key, 4)) . ':' . '(' . $value . ')'; $firsttime = false; } else { $query = trim($query) . " {$fieldSeperator} " . trim(substr($key, 4)) . ':' . '(' . $value . ')'; } } } if (!empty($query)) { $query .= $fieldSet->getQuery(); } // TODO: More Exception Handling for Format Exceptions try { $titleMatches = $search->searchTitle($query); if (!$titleMatches instanceof SearchResultTooMany) { $textMatches = $search->searchText($query); } // did you mean... suggestions if ($textMatches && $textMatches->hasSuggestion()) { $st = SpecialPage::getTitleFor('SolrSearch'); # mirror Go/Search behaviour of original request .. $didYouMeanParams = array('solrsearch' => $textMatches->getSuggestionQuery()); $stParams = $didYouMeanParams; $suggestionSnippet = $textMatches->getSuggestionSnippet(); if ($suggestionSnippet == '') { $suggestionSnippet = null; } $suggestLink = $sk->linkKnown($st, $suggestionSnippet, array(), $stParams); $this->didYouMeanHtml = '<div class="searchdidyoumean">' . wfMsg('search-suggest', $suggestLink) . '</div>'; } } catch (Exception $exc) { #Todo: Catch different Exceptions not just one for all $textMatches = false; $titleMatches = false; $wgOut->addHTML('<p class="solr-error">' . wfMsg('solrstore-error') . '<p\\>'); if ($wgSolrDebug) { $wgOut->addHTML('<p class="solr-error">' . $exc . '<p\\>'); } } // start rendering the page $wgOut->addHtml(Xml::openElement('form', array('id' => 'solrsearch', 'method' => 'get', 'action' => $wgScript))); $wgOut->addHtml(Xml::openElement('table', array('id' => 'mw-search-top-table', 'border' => 0, 'cellpadding' => 0, 'cellspacing' => 0)) . Xml::openElement('tr') . Xml::openElement('td') . "\n" . $this->shortDialog($fieldSet) . Xml::closeElement('td') . Xml::closeElement('tr') . Xml::closeElement('table')); // Sometimes the search engine knows there are too many hits if ($titleMatches instanceof SearchResultTooMany) { $wgOut->addWikiText('==' . wfMsg('toomanymatches') . "==\n"); wfProfileOut(__METHOD__); return; } $filePrefix = $wgContLang->getFormattedNsText(NS_FILE) . ':'; if (trim($query) === '' || $filePrefix === trim($query)) { $wgOut->addHTML($this->formHeader(0, 0)); $wgOut->addHTML('</form>'); // Empty query -- straight view of search form wfProfileOut(__METHOD__); return; } // Get number of results $titleMatchesNum = $titleMatches ? $titleMatches->numRows() : 0; $textMatchesNum = $textMatches ? $textMatches->numRows() : 0; // Total initial query matches (possible false positives) $num = $titleMatchesNum + $textMatchesNum; // Get total actual results (after second filtering, if any) $numTitleMatches = $titleMatches && !is_null($titleMatches->getTotalHits()) ? $titleMatches->getTotalHits() : $titleMatchesNum; $numTextMatches = $textMatches && !is_null($textMatches->getTotalHits()) ? $textMatches->getTotalHits() : $textMatchesNum; // get total number of results if backend can calculate it $totalRes = 0; if ($titleMatches && !is_null($titleMatches->getTotalHits())) { $totalRes += $titleMatches->getTotalHits(); } if ($textMatches && !is_null($textMatches->getTotalHits())) { $totalRes += $textMatches->getTotalHits(); } // show number of results and current offset $wgOut->addHTML($this->formHeader($num, $totalRes)); $wgOut->addHtml(Xml::closeElement('form')); $wgOut->addHtml("<div class='searchresults'>"); // prev/next links if ($num || $this->offset) { // Show the create link ahead if ($wgSolrShowRelated) { $this->showCreateLink($t); } $prevnext = wfViewPrevNext($this->offset, $this->limit, SpecialPage::getTitleFor('SolrSearch/' . $fieldSet->mName), wfArrayToCGI($fieldSet->mFields), max($titleMatchesNum, $textMatchesNum) < $this->limit); wfRunHooks('SpecialSolrSearchResults', array($fieldSet, &$titleMatches, &$textMatches)); } else { wfRunHooks('SpecialSolrSearchNoResults', array($fieldSet)); } if ($titleMatches) { if ($numTitleMatches > 0) { $wgOut->wrapWikiMsg("==\$1==\n", 'titlematches'); $wgOut->addHTML($this->showMatches($titleMatches)); } $titleMatches->free(); } if ($textMatches) { // output appropriate heading if ($numTextMatches > 0 && $numTitleMatches > 0) { // if no title matches the heading is redundant $wgOut->wrapWikiMsg("==\$1==\n", 'textmatches'); } elseif ($totalRes == 0) { # Don't show the 'no text matches' if we received title matches $wgOut->wrapWikiMsg("==\$1==\n", 'notextmatches'); } // show results if ($numTextMatches > 0) { $wgOut->addHTML($this->showMatches($textMatches)); } $textMatches->free(); } $wgOut->addHtml("</div>"); if ($num || $this->offset) { $wgOut->addHTML("<p class='mw-search-pager-bottom'>{$prevnext}</p>\n"); } wfProfileOut(__METHOD__); }
/** * Lazy initialization of article text from DB */ protected function initText() { if (!isset($this->mText)) { if ($this->mRevision != null) { $this->mText = SearchEngine::create()->getTextFromContent($this->mTitle, $this->mRevision->getContent()); } else { // TODO: can we fetch raw wikitext for commons images? $this->mText = ''; } } }
private function run($resultPageSet = null) { $params = $this->extractRequestParams(); $limit = $params['limit']; $query = $params['search']; $what = $params['what']; if (strval($query) === '') { $this->dieUsage("empty search string is not allowed", 'param-search'); } $search = SearchEngine::create(); $search->setLimitOffset($limit + 1, $params['offset']); $search->setNamespaces($params['namespace']); $search->showRedirects = $params['redirects']; if ($what == 'text') { $matches = $search->searchText($query); } elseif ($what == 'title') { $matches = $search->searchTitle($query); } else { // We default to title searches; this is a terrible legacy // of the way we initially set up the MySQL fulltext-based // search engine with separate title and text fields. // In the future, the default should be for a combined index. $what = 'title'; $matches = $search->searchTitle($query); // Not all search engines support a separate title search, // for instance the Lucene-based engine we use on Wikipedia. // In this case, fall back to full-text search (which will // include titles in it!) if (is_null($matches)) { $what = 'text'; $matches = $search->searchText($query); } } if (is_null($matches)) { $this->dieUsage("{$what} search is disabled", "search-{$what}-disabled"); } $titles = array(); $count = 0; while ($result = $matches->next()) { if (++$count > $limit) { // We've reached the one extra which shows that there are additional items to be had. Stop here... $this->setContinueEnumParameter('offset', $params['offset'] + $params['limit']); break; } // Silently skip broken and missing titles if ($result->isBrokenTitle() || $result->isMissingRevision()) { continue; } $title = $result->getTitle(); if (is_null($resultPageSet)) { $vals = array(); ApiQueryBase::addTitleInfo($vals, $title); $fit = $this->getResult()->addValue(array('query', $this->getModuleName()), null, $vals); if (!$fit) { $this->setContinueEnumParameter('offset', $params['offset'] + $count - 1); break; } } else { $titles[] = $title; } } if (is_null($resultPageSet)) { $this->getResult()->setIndexedTagName_internal(array('query', $this->getModuleName()), 'p'); } else { $resultPageSet->populateFromTitles($titles); } }
/** * @param $resultPageSet ApiPageSet * @return void */ private function run($resultPageSet = null) { global $wgContLang; $params = $this->extractRequestParams(); // Extract parameters $limit = $params['limit']; $query = $params['search']; $what = $params['what']; $searchInfo = array_flip($params['info']); $prop = array_flip($params['prop']); // Create search engine instance and set options $search = isset($params['backend']) && $params['backend'] != self::BACKEND_NULL_PARAM ? SearchEngine::create($params['backend']) : SearchEngine::create(); $search->setLimitOffset($limit + 1, $params['offset']); $search->setNamespaces($params['namespace']); $search->showRedirects = $params['redirects']; $query = $search->transformSearchTerm($query); $query = $search->replacePrefixes($query); // Perform the actual search if ($what == 'text') { $matches = $search->searchText($query); } elseif ($what == 'title') { $matches = $search->searchTitle($query); } elseif ($what == 'nearmatch') { $matches = SearchEngine::getNearMatchResultSet($query); } else { // We default to title searches; this is a terrible legacy // of the way we initially set up the MySQL fulltext-based // search engine with separate title and text fields. // In the future, the default should be for a combined index. $what = 'title'; $matches = $search->searchTitle($query); // Not all search engines support a separate title search, // for instance the Lucene-based engine we use on Wikipedia. // In this case, fall back to full-text search (which will // include titles in it!) if (is_null($matches)) { $what = 'text'; $matches = $search->searchText($query); } } if (is_null($matches)) { $this->dieUsage("{$what} search is disabled", "search-{$what}-disabled"); } elseif ($matches instanceof Status && !$matches->isGood()) { $this->dieUsage($matches->getWikiText(), 'search-error'); } $apiResult = $this->getResult(); // Add search meta data to result if (isset($searchInfo['totalhits'])) { $totalhits = $matches->getTotalHits(); if ($totalhits !== null) { $apiResult->addValue(array('query', 'searchinfo'), 'totalhits', $totalhits); } } if (isset($searchInfo['suggestion']) && $matches->hasSuggestion()) { $apiResult->addValue(array('query', 'searchinfo'), 'suggestion', $matches->getSuggestionQuery()); } // Add the search results to the result $terms = $wgContLang->convertForSearchResult($matches->termMatches()); $titles = array(); $count = 0; $result = $matches->next(); while ($result) { if (++$count > $limit) { // We've reached the one extra which shows that there are // additional items to be had. Stop here... $this->setContinueEnumParameter('offset', $params['offset'] + $params['limit']); break; } // Silently skip broken and missing titles if ($result->isBrokenTitle() || $result->isMissingRevision()) { $result = $matches->next(); continue; } $title = $result->getTitle(); if (is_null($resultPageSet)) { $vals = array(); ApiQueryBase::addTitleInfo($vals, $title); if (isset($prop['snippet'])) { $vals['snippet'] = $result->getTextSnippet($terms); } if (isset($prop['size'])) { $vals['size'] = $result->getByteSize(); } if (isset($prop['wordcount'])) { $vals['wordcount'] = $result->getWordCount(); } if (isset($prop['timestamp'])) { $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $result->getTimestamp()); } if (!is_null($result->getScore()) && isset($prop['score'])) { $vals['score'] = $result->getScore(); } if (isset($prop['titlesnippet'])) { $vals['titlesnippet'] = $result->getTitleSnippet($terms); } if (!is_null($result->getRedirectTitle())) { if (isset($prop['redirecttitle'])) { $vals['redirecttitle'] = $result->getRedirectTitle(); } if (isset($prop['redirectsnippet'])) { $vals['redirectsnippet'] = $result->getRedirectSnippet($terms); } } if (!is_null($result->getSectionTitle())) { if (isset($prop['sectiontitle'])) { $vals['sectiontitle'] = $result->getSectionTitle()->getFragment(); } if (isset($prop['sectionsnippet'])) { $vals['sectionsnippet'] = $result->getSectionSnippet(); } } if (isset($prop['hasrelated']) && $result->hasRelated()) { $vals['hasrelated'] = ''; } // Add item to results and see whether it fits $fit = $apiResult->addValue(array('query', $this->getModuleName()), null, $vals); if (!$fit) { $this->setContinueEnumParameter('offset', $params['offset'] + $count - 1); break; } } else { $titles[] = $title; } $result = $matches->next(); } if (is_null($resultPageSet)) { $apiResult->setIndexedTagName_internal(array('query', $this->getModuleName()), 'p'); } else { $resultPageSet->populateFromTitles($titles); } }
/** * Return an array of subpages beginning with $search that this special page will accept. * * @param string $search Prefix to search for * @param int $limit Maximum number of results to return (usually 10) * @param int $offset Number of results to skip (usually 0) * @return string[] Matching subpages */ public function prefixSearchSubpages($search, $limit, $offset) { $title = Title::newFromText($search, NS_FILE); if (!$title || $title->getNamespace() !== NS_FILE) { // No prefix suggestion outside of file namespace return array(); } $search = SearchEngine::create(); $search->setLimitOffset($limit, $offset); // Autocomplete subpage the same as a normal search, but just for files $search->setNamespaces(array(NS_FILE)); $result = $search->defaultPrefixSearch($search); return array_map(function (Title $t) { // Remove namespace in search suggestion return $t->getText(); }, $result); }
function tagSearch($action, $article) { if ($action != 'tagSearch') { return true; } global $wgRequest, $wgOut; wfProfileIn(__METHOD__); $wgOut->setArticleBodyOnly(true); $query = $wgRequest->getText('q'); $query = preg_replace("/[\"'<>]/", '', $query); $search = SearchEngine::create(); $search->setLimitOffset(10, 0); $search->setNamespaces(array(NS_MAIN)); $search->showRedirects = true; $titleMatches = $search->searchTitle($query); $numResults = $titleMatches ? $titleMatches->numRows() : 0; if ($numResults > 0) { $wgOut->addHTML(wfTagSearchShowMatches($titleMatches)); } wfProfileOut(__METHOD__); return false; }
/** * @param string $term * @public */ function showResults($term) { $fname = 'SpecialSearch::showResults'; wfProfileIn($fname); $this->setupPage($term); global $wgOut; $wgOut->addWikiMsg('searchresulttext'); if ('' === trim($term)) { // Empty query -- straight view of search form $wgOut->setSubtitle(''); $wgOut->addHTML($this->powerSearchBox($term)); $wgOut->addHTML($this->powerSearchFocus()); wfProfileOut($fname); return; } global $wgDisableTextSearch; if ($wgDisableTextSearch) { global $wgForwardSearchUrl; if ($wgForwardSearchUrl) { $url = str_replace('$1', urlencode($term), $wgForwardSearchUrl); $wgOut->redirect($url); return; } global $wgInputEncoding; $wgOut->addHTML(wfMsg('searchdisabled')); $wgOut->addHTML(wfMsg('googlesearch', htmlspecialchars($term), htmlspecialchars($wgInputEncoding), htmlspecialchars(wfMsg('searchbutton')))); wfProfileOut($fname); return; } $search = SearchEngine::create(); $search->setLimitOffset($this->limit, $this->offset); $search->setNamespaces($this->namespaces); $search->showRedirects = $this->searchRedirects; $titleMatches = $search->searchTitle($term); // Sometimes the search engine knows there are too many hits if ($titleMatches instanceof SearchResultTooMany) { $wgOut->addWikiText('==' . wfMsg('toomanymatches') . "==\n"); $wgOut->addHTML($this->powerSearchBox($term)); $wgOut->addHTML($this->powerSearchFocus()); wfProfileOut($fname); return; } $textMatches = $search->searchText($term); $num = ($titleMatches ? $titleMatches->numRows() : 0) + ($textMatches ? $textMatches->numRows() : 0); if ($num > 0) { if ($num >= $this->limit) { $top = wfShowingResults($this->offset, $this->limit); } else { $top = wfShowingResultsNum($this->offset, $this->limit, $num); } $wgOut->addHTML("<p>{$top}</p>\n"); } if ($num || $this->offset) { $prevnext = wfViewPrevNext($this->offset, $this->limit, SpecialPage::getTitleFor('Search'), wfArrayToCGI($this->powerSearchOptions(), array('search' => $term)), $num < $this->limit); $wgOut->addHTML("<br />{$prevnext}\n"); } if ($titleMatches) { if ($titleMatches->numRows()) { $wgOut->wrapWikiMsg("==\$1==\n", 'titlematches'); $wgOut->addHTML($this->showMatches($titleMatches)); } else { $wgOut->wrapWikiMsg("==\$1==\n", 'notitlematches'); } $titleMatches->free(); } if ($textMatches) { if ($textMatches->numRows()) { $wgOut->wrapWikiMsg("==\$1==\n", 'textmatches'); $wgOut->addHTML($this->showMatches($textMatches)); } elseif ($num == 0) { # Don't show the 'no text matches' if we received title matches $wgOut->wrapWikiMsg("==\$1==\n", 'notextmatches'); } $textMatches->free(); } if ($num == 0) { $wgOut->addWikiMsg('nonefound'); } if ($num || $this->offset) { $wgOut->addHTML("<p>{$prevnext}</p>\n"); } $wgOut->addHTML($this->powerSearchBox($term)); wfProfileOut($fname); }
/** * Perform the search * * @param string $search Text to search * @param int $limit Maximum items to return * @param array $namespaces Namespaces to search * @param bool $resolveRedir Whether to resolve redirects * @param array &$results Put results here. Keys have to be integers. */ protected function search($search, $limit, $namespaces, $resolveRedir, &$results) { $searchEngine = SearchEngine::create(); $searchEngine->setLimitOffset($limit); $searchEngine->setNamespaces($namespaces); $titles = $searchEngine->extractTitles($searchEngine->completionSearchWithVariants($search)); if (!$titles) { return; } // Special pages need unique integer ids in the return list, so we just // assign them negative numbers because those won't clash with the // always positive articleIds that non-special pages get. $nextSpecialPageId = -1; if ($resolveRedir) { // Query for redirects $redirects = array(); $lb = new LinkBatch($titles); if (!$lb->isEmpty()) { $db = $this->getDB(); $res = $db->select(array('page', 'redirect'), array('page_namespace', 'page_title', 'rd_namespace', 'rd_title'), array('rd_from = page_id', 'rd_interwiki IS NULL OR rd_interwiki = ' . $db->addQuotes(''), $lb->constructSet('page', $db)), __METHOD__); foreach ($res as $row) { $redirects[$row->page_namespace][$row->page_title] = array($row->rd_namespace, $row->rd_title); } } // Bypass any redirects $seen = array(); foreach ($titles as $title) { $ns = $title->getNamespace(); $dbkey = $title->getDBkey(); $from = null; if (isset($redirects[$ns][$dbkey])) { list($ns, $dbkey) = $redirects[$ns][$dbkey]; $from = $title; $title = Title::makeTitle($ns, $dbkey); } if (!isset($seen[$ns][$dbkey])) { $seen[$ns][$dbkey] = true; $resultId = $title->getArticleID(); if ($resultId === 0) { $resultId = $nextSpecialPageId; $nextSpecialPageId -= 1; } $results[$resultId] = array('title' => $title, 'redirect from' => $from, 'extract' => false, 'extract trimmed' => false, 'image' => false, 'url' => wfExpandUrl($title->getFullURL(), PROTO_CURRENT)); } } } else { foreach ($titles as $title) { $resultId = $title->getArticleId(); if ($resultId === 0) { $resultId = $nextSpecialPageId; $nextSpecialPageId -= 1; } $results[$resultId] = array('title' => $title, 'redirect from' => null, 'extract' => false, 'extract trimmed' => false, 'image' => false, 'url' => wfExpandUrl($title->getFullUrl(), PROTO_CURRENT)); } } }
/** * @param string $term */ public function showResults($term) { global $wgOut, $wgUser, $wgDisableTextSearch, $wgContLang, $wgScript; wfProfileIn(__METHOD__); $sk = $wgUser->getSkin(); $this->searchEngine = SearchEngine::create(); $search =& $this->searchEngine; $search->setLimitOffset($this->limit, $this->offset); $search->setNamespaces($this->namespaces); $search->showRedirects = $this->searchRedirects; $search->prefix = $this->mPrefix; $term = $search->transformSearchTerm($term); $this->setupPage($term); if ($wgDisableTextSearch) { global $wgSearchForwardUrl; if ($wgSearchForwardUrl) { $url = str_replace('$1', urlencode($term), $wgSearchForwardUrl); $wgOut->redirect($url); wfProfileOut(__METHOD__); return; } global $wgInputEncoding; $wgOut->addHTML(Xml::openElement('fieldset') . Xml::element('legend', null, wfMsg('search-external')) . Xml::element('p', array('class' => 'mw-searchdisabled'), wfMsg('searchdisabled')) . wfMsg('googlesearch', htmlspecialchars($term), htmlspecialchars($wgInputEncoding), htmlspecialchars(wfMsg('searchbutton'))) . Xml::closeElement('fieldset')); wfProfileOut(__METHOD__); return; } $t = Title::newFromText($term); // fetch search results $rewritten = $search->replacePrefixes($term); $titleMatches = $search->searchTitle($rewritten); if (!$titleMatches instanceof SearchResultTooMany) { $textMatches = $search->searchText($rewritten); } // did you mean... suggestions if ($textMatches && $textMatches->hasSuggestion()) { $st = SpecialPage::getTitleFor('Search'); # mirror Go/Search behaviour of original request .. $didYouMeanParams = array('search' => $textMatches->getSuggestionQuery()); if ($this->fulltext != null) { $didYouMeanParams['fulltext'] = $this->fulltext; } $stParams = array_merge($didYouMeanParams, $this->powerSearchOptions()); $suggestionSnippet = $textMatches->getSuggestionSnippet(); if ($suggestionSnippet == '') { $suggestionSnippet = null; } $suggestLink = $sk->linkKnown($st, $suggestionSnippet, array(), $stParams); $this->didYouMeanHtml = '<div class="searchdidyoumean">' . wfMsg('search-suggest', $suggestLink) . '</div>'; } // start rendering the page $wgOut->addHtml(Xml::openElement('form', array('id' => $this->searchAdvanced ? 'powersearch' : 'search', 'method' => 'get', 'action' => $wgScript))); $wgOut->addHtml(Xml::openElement('table', array('id' => 'mw-search-top-table', 'border' => 0, 'cellpadding' => 0, 'cellspacing' => 0)) . Xml::openElement('tr') . Xml::openElement('td') . "\n" . $this->shortDialog($term) . Xml::closeElement('td') . Xml::closeElement('tr') . Xml::closeElement('table')); // Sometimes the search engine knows there are too many hits if ($titleMatches instanceof SearchResultTooMany) { $wgOut->addWikiText('==' . wfMsg('toomanymatches') . "==\n"); wfProfileOut(__METHOD__); return; } $filePrefix = $wgContLang->getFormattedNsText(NS_FILE) . ':'; if (trim($term) === '' || $filePrefix === trim($term)) { $wgOut->addHTML($this->searchFocus()); $wgOut->addHTML($this->formHeader($term, 0, 0)); if ($this->searchAdvanced) { $wgOut->addHTML($this->powerSearchBox($term)); } $wgOut->addHTML('</form>'); // Empty query -- straight view of search form wfProfileOut(__METHOD__); return; } // Get number of results $titleMatchesNum = $titleMatches ? $titleMatches->numRows() : 0; $textMatchesNum = $textMatches ? $textMatches->numRows() : 0; // Total initial query matches (possible false positives) $num = $titleMatchesNum + $textMatchesNum; // Get total actual results (after second filtering, if any) $numTitleMatches = $titleMatches && !is_null($titleMatches->getTotalHits()) ? $titleMatches->getTotalHits() : $titleMatchesNum; $numTextMatches = $textMatches && !is_null($textMatches->getTotalHits()) ? $textMatches->getTotalHits() : $textMatchesNum; // get total number of results if backend can calculate it $totalRes = 0; if ($titleMatches && !is_null($titleMatches->getTotalHits())) { $totalRes += $titleMatches->getTotalHits(); } if ($textMatches && !is_null($textMatches->getTotalHits())) { $totalRes += $textMatches->getTotalHits(); } // show number of results and current offset $wgOut->addHTML($this->formHeader($term, $num, $totalRes)); if ($this->searchAdvanced) { $wgOut->addHTML($this->powerSearchBox($term)); } $wgOut->addHtml(Xml::closeElement('form')); $wgOut->addHtml("<div class='searchresults'>"); // prev/next links if ($num || $this->offset) { // Show the create link ahead $this->showCreateLink($t); $prevnext = wfViewPrevNext($this->offset, $this->limit, SpecialPage::getTitleFor('Search'), wfArrayToCGI($this->powerSearchOptions(), array('search' => $term)), max($titleMatchesNum, $textMatchesNum) < $this->limit); //$wgOut->addHTML( "<p class='mw-search-pager-top'>{$prevnext}</p>\n" ); wfRunHooks('SpecialSearchResults', array($term, &$titleMatches, &$textMatches)); } else { wfRunHooks('SpecialSearchNoResults', array($term)); } if ($titleMatches) { if ($numTitleMatches > 0) { $wgOut->wrapWikiMsg("==\$1==\n", 'titlematches'); $wgOut->addHTML($this->showMatches($titleMatches)); } $titleMatches->free(); } if ($textMatches) { // output appropriate heading if ($numTextMatches > 0 && $numTitleMatches > 0) { // if no title matches the heading is redundant $wgOut->wrapWikiMsg("==\$1==\n", 'textmatches'); } elseif ($totalRes == 0) { # Don't show the 'no text matches' if we received title matches # $wgOut->wrapWikiMsg( "==$1==\n", 'notextmatches' ); } // show interwiki results if any if ($textMatches->hasInterwikiResults()) { $wgOut->addHTML($this->showInterwiki($textMatches->getInterwikiResults(), $term)); } // show results if ($numTextMatches > 0) { $wgOut->addHTML($this->showMatches($textMatches)); } $textMatches->free(); } if ($num === 0) { $wgOut->addWikiMsg('search-nonefound', wfEscapeWikiText($term)); $this->showCreateLink($t); } $wgOut->addHtml("</div>"); if ($num === 0) { $wgOut->addHTML($this->searchFocus()); } if ($num || $this->offset) { $wgOut->addHTML("<p class='mw-search-pager-bottom'>{$prevnext}</p>\n"); } wfProfileOut(__METHOD__); }
/** * @param ApiPageSet $resultPageSet * @return void */ private function run($resultPageSet = null) { global $wgContLang; $params = $this->extractRequestParams(); // Extract parameters $limit = $params['limit']; $query = $params['search']; $what = $params['what']; $interwiki = $params['interwiki']; $searchInfo = array_flip($params['info']); $prop = array_flip($params['prop']); // Deprecated parameters if (isset($prop['hasrelated'])) { $this->logFeatureUsage('action=search&srprop=hasrelated'); $this->setWarning('srprop=hasrelated has been deprecated'); } if (isset($prop['score'])) { $this->logFeatureUsage('action=search&srprop=score'); $this->setWarning('srprop=score has been deprecated'); } // Create search engine instance and set options $search = isset($params['backend']) && $params['backend'] != self::BACKEND_NULL_PARAM ? SearchEngine::create($params['backend']) : SearchEngine::create(); $search->setLimitOffset($limit + 1, $params['offset']); $search->setNamespaces($params['namespace']); $search->setFeatureData('rewrite', (bool) $params['enablerewrites']); $query = $search->transformSearchTerm($query); $query = $search->replacePrefixes($query); // Perform the actual search if ($what == 'text') { $matches = $search->searchText($query); } elseif ($what == 'title') { $matches = $search->searchTitle($query); } elseif ($what == 'nearmatch') { // near matches must receive the user input as provided, otherwise // the near matches within namespaces are lost. $matches = SearchEngine::getNearMatchResultSet($params['search']); } else { // We default to title searches; this is a terrible legacy // of the way we initially set up the MySQL fulltext-based // search engine with separate title and text fields. // In the future, the default should be for a combined index. $what = 'title'; $matches = $search->searchTitle($query); // Not all search engines support a separate title search, // for instance the Lucene-based engine we use on Wikipedia. // In this case, fall back to full-text search (which will // include titles in it!) if (is_null($matches)) { $what = 'text'; $matches = $search->searchText($query); } } if (is_null($matches)) { $this->dieUsage("{$what} search is disabled", "search-{$what}-disabled"); } elseif ($matches instanceof Status && !$matches->isGood()) { $this->dieUsage($matches->getWikiText(), 'search-error'); } if ($resultPageSet === null) { $apiResult = $this->getResult(); // Add search meta data to result if (isset($searchInfo['totalhits'])) { $totalhits = $matches->getTotalHits(); if ($totalhits !== null) { $apiResult->addValue(array('query', 'searchinfo'), 'totalhits', $totalhits); } } if (isset($searchInfo['suggestion']) && $matches->hasSuggestion()) { $apiResult->addValue(array('query', 'searchinfo'), 'suggestion', $matches->getSuggestionQuery()); $apiResult->addValue(array('query', 'searchinfo'), 'suggestionsnippet', $matches->getSuggestionSnippet()); } if (isset($searchInfo['rewrittenquery']) && $matches->hasRewrittenQuery()) { $apiResult->addValue(array('query', 'searchinfo'), 'rewrittenquery', $matches->getQueryAfterRewrite()); $apiResult->addValue(array('query', 'searchinfo'), 'rewrittenquerysnippet', $matches->getQueryAfterRewriteSnippet()); } } // Add the search results to the result $terms = $wgContLang->convertForSearchResult($matches->termMatches()); $titles = array(); $count = 0; $result = $matches->next(); while ($result) { if (++$count > $limit) { // We've reached the one extra which shows that there are // additional items to be had. Stop here... $this->setContinueEnumParameter('offset', $params['offset'] + $params['limit']); break; } // Silently skip broken and missing titles if ($result->isBrokenTitle() || $result->isMissingRevision()) { $result = $matches->next(); continue; } $title = $result->getTitle(); if ($resultPageSet === null) { $vals = array(); ApiQueryBase::addTitleInfo($vals, $title); if (isset($prop['snippet'])) { $vals['snippet'] = $result->getTextSnippet($terms); } if (isset($prop['size'])) { $vals['size'] = $result->getByteSize(); } if (isset($prop['wordcount'])) { $vals['wordcount'] = $result->getWordCount(); } if (isset($prop['timestamp'])) { $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $result->getTimestamp()); } if (isset($prop['titlesnippet'])) { $vals['titlesnippet'] = $result->getTitleSnippet(); } if (isset($prop['categorysnippet'])) { $vals['categorysnippet'] = $result->getCategorySnippet(); } if (!is_null($result->getRedirectTitle())) { if (isset($prop['redirecttitle'])) { $vals['redirecttitle'] = $result->getRedirectTitle()->getPrefixedText(); } if (isset($prop['redirectsnippet'])) { $vals['redirectsnippet'] = $result->getRedirectSnippet(); } } if (!is_null($result->getSectionTitle())) { if (isset($prop['sectiontitle'])) { $vals['sectiontitle'] = $result->getSectionTitle()->getFragment(); } if (isset($prop['sectionsnippet'])) { $vals['sectionsnippet'] = $result->getSectionSnippet(); } } if (isset($prop['isfilematch'])) { $vals['isfilematch'] = $result->isFileMatch(); } // Add item to results and see whether it fits $fit = $apiResult->addValue(array('query', $this->getModuleName()), null, $vals); if (!$fit) { $this->setContinueEnumParameter('offset', $params['offset'] + $count - 1); break; } } else { $titles[] = $title; } $result = $matches->next(); } $hasInterwikiResults = false; $totalhits = null; if ($interwiki && $resultPageSet === null && $matches->hasInterwikiResults()) { foreach ($matches->getInterwikiResults() as $matches) { $matches = $matches->getInterwikiResults(); $hasInterwikiResults = true; // Include number of results if requested if ($resultPageSet === null && isset($searchInfo['totalhits'])) { $totalhits += $matches->getTotalHits(); } $result = $matches->next(); while ($result) { $title = $result->getTitle(); if ($resultPageSet === null) { $vals = array('namespace' => $result->getInterwikiNamespaceText(), 'title' => $title->getText(), 'url' => $title->getFullUrl()); // Add item to results and see whether it fits $fit = $apiResult->addValue(array('query', 'interwiki' . $this->getModuleName(), $result->getInterwikiPrefix()), null, $vals); if (!$fit) { // We hit the limit. We can't really provide any meaningful // pagination info so just bail out break; } } else { $titles[] = $title; } $result = $matches->next(); } } if ($totalhits !== null) { $apiResult->addValue(array('query', 'interwikisearchinfo'), 'totalhits', $totalhits); } } if ($resultPageSet === null) { $apiResult->addIndexedTagName(array('query', $this->getModuleName()), 'p'); if ($hasInterwikiResults) { $apiResult->addIndexedTagName(array('query', 'interwiki' . $this->getModuleName()), 'p'); } } else { $resultPageSet->populateFromTitles($titles); $offset = $params['offset'] + 1; foreach ($titles as $index => $title) { $resultPageSet->setGeneratorData($title, array('index' => $index + $offset)); } } }
/** * @since 1.18 * * @return SearchEngine */ public function getSearchEngine() { if ( $this->searchEngine === null ) { $this->searchEngine = $this->searchEngineType ? SearchEngine::create( $this->searchEngineType ) : SearchEngine::create(); } return $this->searchEngine; }
/** * @param string $term * @public */ function showResults($term) { wfProfileIn(__METHOD__); global $wgOut, $wgUser; $sk = $wgUser->getSkin(); $search = SearchEngine::create(); $search->setLimitOffset($this->limit, $this->offset); $search->setNamespaces($this->namespaces); $search->showRedirects = $this->searchRedirects; $search->prefix = $this->mPrefix; $term = $search->transformSearchTerm($term); $this->setupPage($term); $rewritten = $search->replacePrefixes($term); $titleMatches = $search->searchTitle($rewritten); $textMatches = $search->searchText($rewritten); // did you mean... suggestions if ($textMatches && $textMatches->hasSuggestion()) { $st = SpecialPage::getTitleFor('Search'); $stParams = wfArrayToCGI(array('search' => $textMatches->getSuggestionQuery(), 'fulltext' => wfMsg('search')), $this->powerSearchOptions()); $suggestLink = $sk->makeKnownLinkObj($st, $textMatches->getSuggestionSnippet(), $stParams); $wgOut->addHTML('<div class="searchdidyoumean">' . wfMsg('search-suggest', $suggestLink) . '</div>'); } $wgOut->addWikiMsg('searchresulttext'); if ('' === trim($term)) { // Empty query -- straight view of search form $wgOut->setSubtitle(''); $wgOut->addHTML($this->powerSearchBox($term)); $wgOut->addHTML($this->powerSearchFocus()); wfProfileOut(__METHOD__); return; } global $wgDisableTextSearch; if ($wgDisableTextSearch) { global $wgSearchForwardUrl; if ($wgSearchForwardUrl) { $url = str_replace('$1', urlencode($term), $wgSearchForwardUrl); $wgOut->redirect($url); wfProfileOut(__METHOD__); return; } global $wgInputEncoding; $wgOut->addHTML(Xml::openElement('fieldset') . Xml::element('legend', null, wfMsg('search-external')) . Xml::element('p', array('class' => 'mw-searchdisabled'), wfMsg('searchdisabled')) . wfMsg('googlesearch', htmlspecialchars($term), htmlspecialchars($wgInputEncoding), htmlspecialchars(wfMsg('searchbutton'))) . Xml::closeElement('fieldset')); wfProfileOut(__METHOD__); return; } $wgOut->addHTML($this->shortDialog($term)); // Sometimes the search engine knows there are too many hits if ($titleMatches instanceof SearchResultTooMany) { $wgOut->addWikiText('==' . wfMsg('toomanymatches') . "==\n"); $wgOut->addHTML($this->powerSearchBox($term)); $wgOut->addHTML($this->powerSearchFocus()); wfProfileOut(__METHOD__); return; } // show number of results $num = ($titleMatches ? $titleMatches->numRows() : 0) + ($textMatches ? $textMatches->numRows() : 0); $totalNum = 0; if ($titleMatches && !is_null($titleMatches->getTotalHits())) { $totalNum += $titleMatches->getTotalHits(); } if ($textMatches && !is_null($textMatches->getTotalHits())) { $totalNum += $textMatches->getTotalHits(); } if ($num > 0) { if ($totalNum > 0) { $top = wfMsgExt('showingresultstotal', array('parseinline'), $this->offset + 1, $this->offset + $num, $totalNum, $num); } elseif ($num >= $this->limit) { $top = wfShowingResults($this->offset, $this->limit); } else { $top = wfShowingResultsNum($this->offset, $this->limit, $num); } $wgOut->addHTML("<p class='mw-search-numberresults'>{$top}</p>\n"); } // prev/next links if ($num || $this->offset) { $prevnext = wfViewPrevNext($this->offset, $this->limit, SpecialPage::getTitleFor('Search'), wfArrayToCGI($this->powerSearchOptions(), array('search' => $term)), $num < $this->limit); $wgOut->addHTML("<p class='mw-search-pager-top'>{$prevnext}</p>\n"); wfRunHooks('SpecialSearchResults', array($term, &$titleMatches, &$textMatches)); } else { wfRunHooks('SpecialSearchNoResults', array($term)); } if ($titleMatches) { if ($titleMatches->numRows()) { $wgOut->wrapWikiMsg("==\$1==\n", 'titlematches'); $wgOut->addHTML($this->showMatches($titleMatches)); } $titleMatches->free(); } if ($textMatches) { // output appropriate heading if ($textMatches->numRows()) { if ($titleMatches) { $wgOut->wrapWikiMsg("==\$1==\n", 'textmatches'); } else { // if no title matches the heading is redundant $wgOut->addHTML("<hr/>"); } } elseif ($num == 0) { # Don't show the 'no text matches' if we received title matches $wgOut->wrapWikiMsg("==\$1==\n", 'notextmatches'); } // show interwiki results if any if ($textMatches->hasInterwikiResults()) { $wgOut->addHTML($this->showInterwiki($textMatches->getInterwikiResults(), $term)); } // show results if ($textMatches->numRows()) { $wgOut->addHTML($this->showMatches($textMatches)); } $textMatches->free(); } if ($num == 0) { $wgOut->addWikiMsg('nonefound'); } if ($num || $this->offset) { $wgOut->addHTML("<p class='mw-search-pager-bottom'>{$prevnext}</p>\n"); } $wgOut->addHTML($this->powerSearchBox($term)); wfProfileOut(__METHOD__); }
/** * Generate a MATCH condition * @param $arr array $m{Incl,Excl}{Text,Cats} * @return string A MATCH condition */ protected function getMatchString($arr) { $conds = array(); $searchEngine = SearchEngine::create(); foreach ($arr as $a) { $subconds = array(); foreach ((array) $a as $b) { if (is_array($b)) { $m = $this->getMatchString($b); if (!empty($m)) { $subconds[] = "+({$m})"; } } else { global $wgContLang; $s = $wgContLang->normalizeForSearch($b); $s = $searchEngine->normalizeText($s); $s = $this->mDb->strencode($s); # If $s contains spaces or ( ) :, quote it if (strpos($s, ' ') !== false || strpos($s, '(') !== false || strpos($s, ')') !== false || strpos($s, ':') !== false) { $s = "\"{$s}\""; } if (!empty($s)) { $subconds[] = "+{$s}"; } } } $sc = implode(' ', $subconds); if (!empty($sc)) { $conds[] = "({$sc})"; } } return implode(' ', $conds); }
/** * @param string $term * @access public */ function showResults($term) { $fname = 'SpecialSearch::showResults'; wfProfileIn($fname); $this->setupPage($term); global $wgUser, $wgOut; $sk = $wgUser->getSkin(); $wgOut->addWikiText(wfMsg('searchresulttext')); #if ( !$this->parseQuery() ) { if ('' === trim($term)) { $wgOut->setSubtitle(''); $wgOut->addHTML($this->powerSearchBox($term)); wfProfileOut($fname); return; } global $wgDisableTextSearch; if ($wgDisableTextSearch) { global $wgForwardSearchUrl; if ($wgForwardSearchUrl) { $url = str_replace('$1', urlencode($term), $wgForwardSearchUrl); $wgOut->redirect($url); return; } global $wgInputEncoding; $wgOut->addHTML(wfMsg('searchdisabled')); $wgOut->addHTML(wfMsg('googlesearch', htmlspecialchars($term), htmlspecialchars($wgInputEncoding), htmlspecialchars(wfMsg('search')))); wfProfileOut($fname); return; } $search =& SearchEngine::create(); $search->setLimitOffset($this->limit, $this->offset); $search->setNamespaces($this->namespaces); $titleMatches = $search->searchTitle($term); $textMatches = $search->searchText($term); $num = ($titleMatches ? $titleMatches->numRows() : 0) + ($textMatches ? $textMatches->numRows() : 0); if ($num >= $this->limit) { $top = wfShowingResults($this->offset, $this->limit); } else { $top = wfShowingResultsNum($this->offset, $this->limit, $num); } $wgOut->addHTML("<p>{$top}</p>\n"); if ($num || $this->offset) { $prevnext = wfViewPrevNext($this->offset, $this->limit, 'Special:Search', wfArrayToCGI($this->powerSearchOptions(), array('search' => $term))); $wgOut->addHTML("<br />{$prevnext}\n"); } if ($titleMatches) { if ($titleMatches->numRows()) { $wgOut->addWikiText('==' . wfMsg('titlematches') . "==\n"); $wgOut->addHTML($this->showMatches($titleMatches)); } else { $wgOut->addWikiText('==' . wfMsg('notitlematches') . "==\n"); } } if ($textMatches) { if ($textMatches->numRows()) { $wgOut->addWikiText('==' . wfMsg('textmatches') . "==\n"); $wgOut->addHTML($this->showMatches($textMatches)); } elseif ($num == 0) { # Don't show the 'no text matches' if we received title matches $wgOut->addWikiText('==' . wfMsg('notextmatches') . "==\n"); } } if ($num == 0) { $wgOut->addWikiText(wfMsg('nonefound')); } if ($num || $this->offset) { $wgOut->addHTML("<p>{$prevnext}</p>\n"); } $wgOut->addHTML($this->powerSearchBox($term)); wfProfileOut($fname); }
function search( &$serverOptions ) { $serverOptions['namespaces']['http://subversion.tigris.org/xmlns/dav/'] = 'V'; $status = array(); $search = SearchEngine::create(); # TODO: Use (int)$wgUser->getOption( 'searchlimit' ); $search->setLimitOffset( MW_SEARCH_LIMIT ); $results = $search->searchText( $serverOptions['xpath']->evaluate( 'string(/D:searchrequest/D:basicsearch/D:where/D:contains)' ) ); while ( ( $result = $results->next() ) !== false ) { $title = $result->getTitle(); $revision = Revision::newFromTitle( $title ); $response = array(); $response['path'] = 'webdav.php/' . $title->getPrefixedUrl(); $response['props'][] = WebDavServer::mkprop( 'checked-in', $this->getUrl( array( 'path' => 'deltav.php/ver/' . $revision->getId() ) ) ); $response['props'][] = WebDavServer::mkprop( 'displayname', $title->getText() ); $response['props'][] = WebDavServer::mkprop( 'getcontentlength', $revision->getSize() ); $response['props'][] = WebDavServer::mkprop( 'getcontenttype', 'text/x-wiki' ); $response['props'][] = WebDavServer::mkprop( 'getlastmodified', wfTimestamp( TS_UNIX, $revision->mTimestamp ) ); $response['props'][] = WebDavServer::mkprop( 'resourcetype', null ); $response['props'][] = WebDavServer::mkprop( 'version-controlled-configuration', $this->getUrl( array( 'path' => 'deltav.php/vcc/default' ) ) ); $response['props'][] = WebDavServer::mkprop( 'http://subversion.tigris.org/xmlns/dav/', 'baseline-relative-path', $title->getFullUrl() ); $response['score'] = $result->getScore(); $status[] = $response; } # TODO: Check if we exceed our limit #$response = array(); #$response['status'] = '507 Insufficient Storage'; #$status[] = $response; return $status; }
/** * Perform a regular substring search for prefixSearchSubpages * @param string $search Prefix to search for * @param int $limit Maximum number of results to return (usually 10) * @param int $offset Number of results to skip (usually 0) * @return string[] Matching subpages */ protected function prefixSearchString($search, $limit, $offset) { $title = Title::newFromText($search); if (!$title || !$title->canExist()) { // No prefix suggestion in special and media namespace return array(); } $search = SearchEngine::create(); $search->setLimitOffset($limit, $offset); $search->setNamespaces(array()); $result = $search->defaultPrefixSearch($search); return array_map(function (Title $t) { return $t->getPrefixedText(); }, $result); }