- function powersearch() {
- global $wgUser, $wgOut, $wgContLang, $wgTitle, $wgRequest;
- $sk =& $wgUser->getSkin();
-
- $search = $this->rawText;
- $searchx = $wgRequest->getVal( 'searchx' );
- $listredirs = $wgRequest->getVal( 'redirs' );
-
- $ret = wfMsg('powersearchtext'); # Text to be returned
- $tempText = ''; # Temporary text, for substitution into $ret
-
- if( isset( $_REQUEST['searchx'] ) ) {
- $this->addToQuery['searchx'] = '1';
- }
-
- # Do namespace checkboxes
- $namespaces = $wgContLang->getNamespaces();
- foreach ( $namespaces as $i => $namespace ) {
- # Skip virtual namespaces
- if ( $i < 0 ) {
- continue;
- }
-
- $formVar = 'ns'.$i;
-
- # Initialise checkboxValues, either from defaults or from
- # a previous invocation
- if ( !isset( $searchx ) ) {
- $checkboxValue = $this->initNamespaceCheckbox( $i );
- } else {
- $checkboxValue = $wgRequest->getVal( $formVar );
- }
-
- $checked = '';
- if ( $checkboxValue == 1 ) {
- $checked = ' checked="checked"';
- $this->addToQuery['ns'.$i] = 1;
- array_push( $this->namespacesToSearch, $i );
- }
- $name = str_replace( '_', ' ', $namespaces[$i] );
- if ( '' == $name ) {
- $name = wfMsg( 'blanknamespace' );
- }
-
- if ( $tempText !== '' ) {
- $tempText .= ' ';
- }
- $tempText .= "<input type='checkbox' value=\"1\" name=\"" .
- "ns{$i}\"{$checked} />{$name}\n";
- }
- $ret = str_replace ( '$1', $tempText, $ret );
-
- # List redirects checkbox
-
- $checked = '';
- if ( $listredirs == 1 ) {
- $this->addToQuery['redirs'] = 1;
- $checked = ' checked="checked"';
- }
- $tempText = "<input type='checkbox' value='1' name=\"redirs\"{$checked} />\n";
- $ret = str_replace( '$2', $tempText, $ret );
-
- # Search field
-
- $tempText = "<input type='text' name=\"search\" value=\"" .
- htmlspecialchars( $search ) ."\" width=\"80\" />\n";
- $ret = str_replace( "$3", $tempText, $ret );
-
- # Searchx button
-
- $tempText = '<input type="submit" name="searchx" value="' .
- wfMsg('powersearch') . "\" />\n";
- $ret = str_replace( '$9', $tempText, $ret );
-
- $action = $sk->escapeSearchLink();
- $ret = "<br /><br />\n<form id=\"powersearch\" method=\"get\" " .
- "action=\"$action\">\n{$ret}\n</form>\n";
-
- if ( isset ( $searchx ) ) {
- if ( ! $listredirs ) {
- $this->doSearchRedirects = false;
- }
- }
- return $ret;
- }
-
- function setupPage() {
- global $wgOut;
- $wgOut->setPageTitle( wfMsg( 'searchresults' ) );
- $wgOut->setSubtitle( wfMsg( 'searchquery', htmlspecialchars( $this->rawText ) ) );
- $wgOut->setArticleRelated( false );
- $wgOut->setRobotpolicy( 'noindex,nofollow' );
- }
-
- /**
- * Perform the search and construct the results page
- */
- function showResults() {
- global $wgUser, $wgTitle, $wgOut, $wgLang;
- global $wgDisableTextSearch, $wgInputEncoding;
- $fname = 'SearchEngine::showResults';
-
- $search = $this->rawText;
-
- $powersearch = $this->powersearch(); /* Need side-effects here? */
-
- $this->setupPage();
-
- $sk = $wgUser->getSkin();
- $wgOut->addWikiText( wfMsg( 'searchresulttext' ) );
-
- if ( !$this->parseQuery() ) {
- $wgOut->addWikiText(
- '==' . wfMsg( 'badquery' ) . "==\n" .
- wfMsg( 'badquerytext' ) );
- return;
- }
- list( $limit, $offset ) = wfCheckLimits( 20, 'searchlimit' );
-
- if ( $wgDisableTextSearch ) {
- $wgOut->addHTML( wfMsg( 'searchdisabled' ) );
- $wgOut->addHTML( wfMsg( 'googlesearch',
- htmlspecialchars( $this->rawText ),
- htmlspecialchars( $wgInputEncoding ) ) );
- return;
- }
-
- $titleMatches = $this->getMatches( $this->titleCond, $limit, $offset );
- $textMatches = $this->getMatches( $this->textCond, $limit, $offset );
-
- $sk = $wgUser->getSkin();
-
- $num = count( $titleMatches ) + count( $textMatches );
- if ( $num >= $limit ) {
- $top = wfShowingResults( $offset, $limit );
- } else {
- $top = wfShowingResultsNum( $offset, $limit, $num );
- }
- $wgOut->addHTML( "<p>{$top}</p>\n" );
-
- # For powersearch
- $a2l = '';
- $akk = array_keys( $this->addToQuery );
- foreach ( $akk AS $ak ) {
- $a2l .= "&{$ak}={$this->addToQuery[$ak]}" ;
- }
-
- $prevnext = wfViewPrevNext( $offset, $limit, 'Special:Search',
- 'search=' . wfUrlencode( $this->filteredText ) . $a2l );
- $wgOut->addHTML( "<br />{$prevnext}\n" );
-
- $foundsome = $this->showMatches( $titleMatches, $offset, 'notitlematches', 'titlematches' )
- || $this->showMatches( $textMatches, $offset, 'notextmatches', 'textmatches' );
-
- if ( !$foundsome ) {
- $wgOut->addWikiText( wfMsg( 'nonefound' ) );
- }
- $wgOut->addHTML( "<p>{$prevnext}</p>\n" );
- $wgOut->addHTML( $powersearch );
- }
-
- function legalSearchChars() {
- $lc = "A-Za-z_'0-9\\x80-\\xFF\\-";
- return $lc;
- }
-
- function parseQuery() {
- global $wgDBmysql4;
- if (strlen($this->filteredText) < 1)
- return MW_SEARCH_BAD_QUERY;
-
- if( $wgDBmysql4 ) {
- # Use cleaner boolean search if available
- return $this->parseQuery4();
- } else {
- # Fall back to ugly hack with multiple search clauses
- return $this->parseQuery3();
- }
- }
-
- function parseQuery3() {
- global $wgDBminWordLen, $wgContLang;
-
- # on non mysql4 database: get list of words we don't want to search for
- require_once( 'FulltextStoplist.php' );
-
- $lc = SearchEngine::legalSearchChars() . '()';
- $q = preg_replace( "/([()])/", " \\1 ", $this->filteredText );
- $q = preg_replace( "/\\s+/", " ", $q );
- $w = explode( ' ', trim( $q ) );
-
- $last = $cond = '';
- foreach ( $w as $word ) {
- $word = $wgContLang->stripForSearch( $word );
- if ( 'and' == $word || 'or' == $word || 'not' == $word
- || '(' == $word || ')' == $word ) {
- $cond .= ' ' . strtoupper( $word );
- $last = '';
- } else if ( strlen( $word ) < $wgDBminWordLen ) {
- continue;
- } else if ( FulltextStoplist::inList( $word ) ) {
- continue;
- } else {
- if ( '' != $last ) { $cond .= ' AND'; }
- $cond .= " (MATCH (##field##) AGAINST ('" .
- $this->db->strencode( $word ). "'))";
- $last = $word;
- array_push( $this->searchTerms, "\\b" . $word . "\\b" );
- }
- }
- if ( 0 == count( $this->searchTerms ) ) {
- return MW_SEARCH_BAD_QUERY;
- }
-
- $this->titleCond = '(' . str_replace( '##field##',
- 'si_title', $cond ) . ' )';
-
- $this->textCond = '(' . str_replace( '##field##',
- 'si_text', $cond ) . ' AND (cur_is_redirect=0) )';
-
- return MW_SEARCH_OK;
- }
-
- function parseQuery4() {
- global $wgContLang;
- $lc = SearchEngine::legalSearchChars();
- $searchon = '';
- $this->searchTerms = array();
-
- # FIXME: This doesn't handle parenthetical expressions.
- if( preg_match_all( '/([-+<>~]?)(([' . $lc . ']+)(\*?)|"[^"]*")/',
- $this->filteredText, $m, PREG_SET_ORDER ) ) {
- foreach( $m as $terms ) {
- if( $searchon !== '' ) $searchon .= ' ';
- if( $this->strictMatching && ($terms[1] == '') ) {
- $terms[1] = '+';
- }
- $searchon .= $terms[1] . $wgContLang->stripForSearch( $terms[2] );
- if( !empty( $terms[3] ) ) {
- $regexp = preg_quote( $terms[3] );
- if( $terms[4] ) $regexp .= "[0-9A-Za-z_]+";
- } else {
- $regexp = preg_quote( str_replace( '"', '', $terms[2] ) );
- }
- $this->searchTerms[] = $regexp;
- }
- wfDebug( "Would search with '$searchon'\n" );
- wfDebug( "Match with /\b" . implode( '\b|\b', $this->searchTerms ) . "\b/\n" );
- } else {
- wfDebug( "Can't understand search query '{$this->filteredText}'\n" );
- }
-
- $searchon = $this->db->strencode( $searchon );
- $this->titleCond = " MATCH(si_title) AGAINST('$searchon' IN BOOLEAN MODE)";
- $this->textCond = " (MATCH(si_text) AGAINST('$searchon' IN BOOLEAN MODE) AND cur_is_redirect=0)";
- return MW_SEARCH_OK;
- }
-
- function &getMatches( $cond, $limit, $offset = 0 ) {
- $searchindex = $this->db->tableName( 'searchindex' );
- $cur = $this->db->tableName( 'cur' );
- $searchnamespaces = $this->queryNamespaces();
- $redircond = $this->searchRedirects();
-
- $sql = "SELECT cur_id,cur_namespace,cur_title," .
- "cur_text FROM $cur,$searchindex " .
- "WHERE cur_id=si_page AND {$cond} " .
- "{$searchnamespaces} {$redircond} " .
- $this->db->limitResult( $limit, $offset );
-
- $res = $this->db->query( $sql, 'SearchEngine::getMatches' );
- $matches = array();
- while ( $row = $this->db->fetchObject( $res ) ) {
- $matches[] = $row;
- }
- $this->db->freeResult( $res );
-
- return $matches;
- }
-
- function showMatches( &$matches, $offset, $msgEmpty, $msgFound ) {
- global $wgOut;
- if ( 0 == count( $matches ) ) {
- $wgOut->addHTML( "<h2>" . wfMsg( $msgEmpty ) .
- "</h2>\n" );
- return false;
- } else {
- $off = $offset + 1;
- $wgOut->addHTML( "<h2>" . wfMsg( $msgFound ) .
- "</h2>\n<ol start='{$off}'>" );
-
- foreach( $matches as $row ) {
- $this->showHit( $row );
- }
- $wgOut->addHTML( "</ol>\n" );
- return true;
- }
- }
-
- function showHit( $row ) {
- global $wgUser, $wgOut, $wgContLang;
-
- $t = Title::makeName( $row->cur_namespace, $row->cur_title );
- if( is_null( $t ) ) {
- $wgOut->addHTML( "<!-- Broken link in search result -->\n" );
- return;
- }
- $sk = $wgUser->getSkin();
-
- $contextlines = $wgUser->getOption( 'contextlines' );
- if ( '' == $contextlines ) { $contextlines = 5; }
- $contextchars = $wgUser->getOption( 'contextchars' );
- if ( '' == $contextchars ) { $contextchars = 50; }
-
- $link = $sk->makeKnownLink( $t, '' );
- $size = wfMsg( 'nbytes', strlen( $row->cur_text ) );
- $wgOut->addHTML( "<li>{$link} ({$size})" );
-
- $lines = explode( "\n", $row->cur_text );
- $pat1 = "/(.*)(" . implode( "|", $this->searchTerms ) . ")(.*)/i";
- $lineno = 0;
-
- foreach ( $lines as $line ) {
- if ( 0 == $contextlines ) {
- break;
- }
- --$contextlines;
- ++$lineno;
- if ( ! preg_match( $pat1, $line, $m ) ) {
- continue;
- }
-
- $pre = $wgContLang->truncate( $m[1], -$contextchars, '...' );
-
- if ( count( $m ) < 3 ) {
- $post = '';
- } else {
- $post = $wgContLang->truncate( $m[3], $contextchars, '...' );
- }
-
- $found = $m[2];
-
- $line = htmlspecialchars( $pre . $found . $post );
- $pat2 = '/(' . implode( '|', $this->searchTerms ) . ")/i";
- $line = preg_replace( $pat2,
- "<span class='searchmatch'>\\1</span>", $line );
-
- $wgOut->addHTML( "<br /><small>{$lineno}: {$line}</small>\n" );
- }
- $wgOut->addHTML( "</li>\n" );
- }
-
- function getNearMatch() {