Merge "Deprecate overriding SearchEngine::search*"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Wed, 16 May 2018 13:31:56 +0000 (13:31 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Wed, 16 May 2018 13:31:56 +0000 (13:31 +0000)
1  2 
RELEASE-NOTES-1.32
includes/search/SearchEngine.php
includes/search/SearchMssql.php
includes/search/SearchMySQL.php
includes/search/SearchOracle.php
includes/search/SearchPostgres.php
includes/search/SearchSqlite.php

diff --combined RELEASE-NOTES-1.32
@@@ -17,10 -17,6 +17,10 @@@ production
    'html5-legacy' value for $wgFragmentMode is no longer accepted.
  * The experimental Html5Internal and Html5Depurate tidy drivers were removed.
    RemexHtml, which is the default, should be used instead.
 +* (T135963) You can now define a Content Security Policy for your wiki. This
 +  adds a defense-in-depth feature to stop an attacker who has found a bug in
 +  the parser allowing them to insert malicious attributes. Disabled by default,
 +  you can configure this via $wgCSPHeader and $wgCSPReportOnlyHeader.
  
  === New features in 1.32 ===
  * (T112474) Generalized the ResourceLoader mechanism for overriding modules
@@@ -96,6 -92,9 +96,9 @@@ because of Phabricator reports
    of queueing style modules as well.
  * OutputPage::addModuleScripts() and ParserOutput::addModuleScripts are
    deprecated. Use addModules() instead.
+ * Overriding SearchEngine::{searchText,searchTitle,searchArchiveTitle}
+   in extending classes is deprecated.  Extend related doSearch* methods
+   instead.
  
  === Other changes in 1.32 ===
  * …
@@@ -69,12 -69,25 +69,25 @@@ abstract class SearchEngine 
        /**
         * Perform a full text search query and return a result set.
         * If full text searches are not supported or disabled, return null.
-        * STUB
+        *
+        * As of 1.32 overriding this function is deprecated. It will
+        * be converted to final in 1.34. Override self::doSearchText().
+        *
+        * @param string $term Raw search term
+        * @return SearchResultSet|Status|null
+        */
+       public function searchText( $term ) {
+               return $this->doSearchText( $term );
+       }
+       /**
+        * Perform a full text search query and return a result set.
         *
         * @param string $term Raw search term
         * @return SearchResultSet|Status|null
+        * @since 1.32
         */
-       function searchText( $term ) {
+       protected function doSearchText( $term ) {
                return null;
        }
  
         * The results returned by this methods are only sugegstions and
         * may not end up being shown to the user.
         *
+        * As of 1.32 overriding this function is deprecated. It will
+        * be converted to final in 1.34. Override self::doSearchArchiveTitle().
+        *
         * @param string $term Raw search term
         * @return Status<Title[]>
         * @since 1.29
         */
-       function searchArchiveTitle( $term ) {
+       public function searchArchiveTitle( $term ) {
+               return $this->doSearchArchiveTitle( $term );
+       }
+       /**
+        * Perform a title search in the article archive.
+        *
+        * @param string $term Raw search term
+        * @return Status<Title[]>
+        * @since 1.32
+        */
+       protected function doSearchArchiveTitle( $term ) {
                return Status::newGood( [] );
        }
  
         * If title searches are not supported or disabled, return null.
         * STUB
         *
+        * As of 1.32 overriding this function is deprecated. It will
+        * be converted to final in 1.34. Override self::doSearchTitle().
+        *
+        * @param string $term Raw search term
+        * @return SearchResultSet|null
+        */
+       public function searchTitle( $term ) {
+               return $this->doSearchTitle( $term );
+       }
+       /**
+        * Perform a title-only search query and return a result set.
+        *
         * @param string $term Raw search term
         * @return SearchResultSet|null
+        * @since 1.32
         */
-       function searchTitle( $term ) {
+       protected function doSearchTitle( $term ) {
                return null;
        }
  
                        return false;
                }
                $extractedNamespace = null;
 +              $allkeywords = [];
  
 -              $allkeyword = wfMessage( 'searchall' )->inContentLanguage()->text() . ":";
 -              if ( strncmp( $query, $allkeyword, strlen( $allkeyword ) ) == 0 ) {
 -                      $extractedNamespace = null;
 -                      $parsed = substr( $query, strlen( $allkeyword ) );
 -              } elseif ( strpos( $query, ':' ) !== false ) {
 +              $allkeywords[] = wfMessage( 'searchall' )->inContentLanguage()->text() . ":";
 +              // force all: so that we have a common syntax for all the wikis
 +              if ( !in_array( 'all:', $allkeywords ) ) {
 +                      $allkeywords[] = 'all:';
 +              }
 +
 +              $allQuery = false;
 +              foreach ( $allkeywords as $kw ) {
 +                      if ( strncmp( $query, $kw, strlen( $kw ) ) == 0 ) {
 +                              $extractedNamespace = null;
 +                              $parsed = substr( $query, strlen( $kw ) );
 +                              $allQuery = true;
 +                              break;
 +                      }
 +              }
 +
 +              if ( !$allQuery && strpos( $query, ':' ) !== false ) {
                        // TODO: should we unify with PrefixSearch::extractNamespace ?
                        $prefix = str_replace( ' ', '_', substr( $query, 0, strpos( $query, ':' ) ) );
                        $index = $wgContLang->getNsIndex( $prefix );
@@@ -31,9 -31,8 +31,8 @@@ class SearchMssql extends SearchDatabas
         *
         * @param string $term Raw search term
         * @return SqlSearchResultSet
-        * @access public
         */
-       function searchText( $term ) {
+       protected function doSearchText( $term ) {
                $resultSet = $this->db->query( $this->getQuery( $this->filter( $term ), true ) );
                return new SqlSearchResultSet( $resultSet, $this->searchTerms );
        }
@@@ -43,9 -42,8 +42,8 @@@
         *
         * @param string $term Raw search term
         * @return SqlSearchResultSet
-        * @access public
         */
-       function searchTitle( $term ) {
+       protected function doSearchTitle( $term ) {
                $resultSet = $this->db->query( $this->getQuery( $this->filter( $term ), false ) );
                return new SqlSearchResultSet( $resultSet, $this->searchTerms );
        }
@@@ -54,8 -52,9 +52,8 @@@
         * Return a partial WHERE clause to limit the search to the given namespaces
         *
         * @return string
 -       * @private
         */
 -      function queryNamespaces() {
 +      private function queryNamespaces() {
                $namespaces = implode( ',', $this->namespaces );
                if ( $namespaces == '' ) {
                        $namespaces = '0';
@@@ -70,7 -69,7 +68,7 @@@
         *
         * @return string
         */
 -      function queryLimit( $sql ) {
 +      private function queryLimit( $sql ) {
                return $this->db->limitResult( $sql, $this->limit, $this->offset );
        }
  
@@@ -94,7 -93,7 +92,7 @@@
         * @param bool $fulltext
         * @return string
         */
 -      function getQuery( $filteredTerm, $fulltext ) {
 +      private function getQuery( $filteredTerm, $fulltext ) {
                return $this->queryLimit( $this->queryMain( $filteredTerm, $fulltext ) . ' ' .
                        $this->queryNamespaces() . ' ' .
                        $this->queryRanking( $filteredTerm, $fulltext ) . ' ' );
         * @param string $filteredTerm
         * @param bool $fulltext
         * @return string
 -       * @private
         */
 -      function queryMain( $filteredTerm, $fulltext ) {
 +      private function queryMain( $filteredTerm, $fulltext ) {
                $match = $this->parseQuery( $filteredTerm, $fulltext );
                $page = $this->db->tableName( 'page' );
                $searchindex = $this->db->tableName( 'searchindex' );
         * @param bool $fulltext
         * @return string
         */
 -      function parseQuery( $filteredText, $fulltext ) {
 +      private function parseQuery( $filteredText, $fulltext ) {
                global $wgContLang;
                $lc = $this->legalSearchChars( self::CHARS_NO_SYNTAX );
                $this->searchTerms = [];
@@@ -42,7 -42,7 +42,7 @@@ class SearchMySQL extends SearchDatabas
         *
         * @return array
         */
 -      function parseQuery( $filteredText, $fulltext ) {
 +      private function parseQuery( $filteredText, $fulltext ) {
                global $wgContLang;
  
                $lc = $this->legalSearchChars( self::CHARS_NO_SYNTAX ); // Minus syntax chars (" and *)
                ];
        }
  
 -      function regexTerm( $string, $wildcard ) {
 +      private function regexTerm( $string, $wildcard ) {
                global $wgContLang;
  
                $regex = preg_quote( $string, '/' );
         * @param string $term Raw search term
         * @return SqlSearchResultSet
         */
-       function searchText( $term ) {
+       protected function doSearchText( $term ) {
                return $this->searchInternal( $term, true );
        }
  
         * @param string $term Raw search term
         * @return SqlSearchResultSet
         */
-       function searchTitle( $term ) {
+       protected function doSearchTitle( $term ) {
                return $this->searchInternal( $term, false );
        }
  
         * @return array
         * @since 1.18 (changed)
         */
 -      function getQuery( $filteredTerm, $fulltext ) {
 +      private function getQuery( $filteredTerm, $fulltext ) {
                $query = [
                        'tables' => [],
                        'fields' => [],
         * @param bool $fulltext
         * @return string
         */
 -      function getIndexField( $fulltext ) {
 +      private function getIndexField( $fulltext ) {
                return $fulltext ? 'si_text' : 'si_title';
        }
  
         * @param bool $fulltext
         * @since 1.18 (changed)
         */
 -      function queryMain( &$query, $filteredTerm, $fulltext ) {
 +      private function queryMain( &$query, $filteredTerm, $fulltext ) {
                $match = $this->parseQuery( $filteredTerm, $fulltext );
                $query['tables'][] = 'page';
                $query['tables'][] = 'searchindex';
         * @param bool $fulltext
         * @return array
         */
 -      function getCountQuery( $filteredTerm, $fulltext ) {
 +      private function getCountQuery( $filteredTerm, $fulltext ) {
                $match = $this->parseQuery( $filteredTerm, $fulltext );
  
                $query = [
@@@ -64,7 -64,7 +64,7 @@@ class SearchOracle extends SearchDataba
         * @param string $term Raw search term
         * @return SqlSearchResultSet
         */
-       function searchText( $term ) {
+       protected function doSearchText( $term ) {
                if ( $term == '' ) {
                        return new SqlSearchResultSet( false, '' );
                }
@@@ -79,7 -79,7 +79,7 @@@
         * @param string $term Raw search term
         * @return SqlSearchResultSet
         */
-       function searchTitle( $term ) {
+       protected function doSearchTitle( $term ) {
                if ( $term == '' ) {
                        return new SqlSearchResultSet( false, '' );
                }
@@@ -92,7 -92,7 +92,7 @@@
         * Return a partial WHERE clause to limit the search to the given namespaces
         * @return string
         */
 -      function queryNamespaces() {
 +      private function queryNamespaces() {
                if ( is_null( $this->namespaces ) ) {
                        return '';
                }
         *
         * @return string
         */
 -      function queryLimit( $sql ) {
 +      private function queryLimit( $sql ) {
                return $this->db->limitResult( $sql, $this->limit, $this->offset );
        }
  
         * @param bool $fulltext
         * @return string
         */
 -      function getQuery( $filteredTerm, $fulltext ) {
 +      private function getQuery( $filteredTerm, $fulltext ) {
                return $this->queryLimit( $this->queryMain( $filteredTerm, $fulltext ) . ' ' .
                        $this->queryNamespaces() . ' ' .
                        $this->queryRanking( $filteredTerm, $fulltext ) . ' ' );
         * @param bool $fulltext
         * @return string
         */
 -      function getIndexField( $fulltext ) {
 +      private function getIndexField( $fulltext ) {
                return $fulltext ? 'si_text' : 'si_title';
        }
  
         * @param bool $fulltext
         * @return string
         */
 -      function parseQuery( $filteredText, $fulltext ) {
 +      private function parseQuery( $filteredText, $fulltext ) {
                global $wgContLang;
                $lc = $this->legalSearchChars( self::CHARS_NO_SYNTAX );
                $this->searchTerms = [];
@@@ -37,7 -37,7 +37,7 @@@ class SearchPostgres extends SearchData
         * @param string $term Raw search term
         * @return SqlSearchResultSet
         */
-       function searchTitle( $term ) {
+       protected function doSearchTitle( $term ) {
                $q = $this->searchQuery( $term, 'titlevector', 'page_title' );
                $olderror = error_reporting( E_ERROR );
                $resultSet = $this->db->query( $q, 'SearchPostgres', true );
@@@ -45,7 -45,7 +45,7 @@@
                return new SqlSearchResultSet( $resultSet, $this->searchTerms );
        }
  
-       function searchText( $term ) {
+       protected function doSearchText( $term ) {
                $q = $this->searchQuery( $term, 'textvector', 'old_text' );
                $olderror = error_reporting( E_ERROR );
                $resultSet = $this->db->query( $q, 'SearchPostgres', true );
@@@ -61,7 -61,7 +61,7 @@@
         *
         * @return string
         */
 -      function parseQuery( $term ) {
 +      private function parseQuery( $term ) {
                wfDebug( "parseQuery received: $term \n" );
  
                # # No backslashes allowed
         * @param string $colname
         * @return string
         */
 -      function searchQuery( $term, $fulltext, $colname ) {
 +      private function searchQuery( $term, $fulltext, $colname ) {
                # Get the SQL fragment for the given term
                $searchstring = $this->parseQuery( $term );
  
@@@ -42,7 -42,7 +42,7 @@@ class SearchSqlite extends SearchDataba
         * @param bool $fulltext
         * @return string
         */
 -      function parseQuery( $filteredText, $fulltext ) {
 +      private function parseQuery( $filteredText, $fulltext ) {
                global $wgContLang;
                $lc = $this->legalSearchChars( self::CHARS_NO_SYNTAX ); // Minus syntax chars (" and *)
                $searchon = '';
                return " $field MATCH $searchon ";
        }
  
 -      function regexTerm( $string, $wildcard ) {
 +      private function regexTerm( $string, $wildcard ) {
                global $wgContLang;
  
                $regex = preg_quote( $string, '/' );
         * @param string $term Raw search term
         * @return SqlSearchResultSet
         */
-       function searchText( $term ) {
+       protected function doSearchText( $term ) {
                return $this->searchInternal( $term, true );
        }
  
         * @param string $term Raw search term
         * @return SqlSearchResultSet
         */
-       function searchTitle( $term ) {
+       protected function doSearchTitle( $term ) {
                return $this->searchInternal( $term, false );
        }
  
         * Return a partial WHERE clause to limit the search to the given namespaces
         * @return string
         */
 -      function queryNamespaces() {
 +      private function queryNamespaces() {
                if ( is_null( $this->namespaces ) ) {
                        return '';  # search all
                }
         * @param string $sql
         * @return string
         */
 -      function limitResult( $sql ) {
 +      private function limitResult( $sql ) {
                return $this->db->limitResult( $sql, $this->limit, $this->offset );
        }
  
         * @param bool $fulltext
         * @return string
         */
 -      function getQuery( $filteredTerm, $fulltext ) {
 +      private function getQuery( $filteredTerm, $fulltext ) {
                return $this->limitResult(
                        $this->queryMain( $filteredTerm, $fulltext ) . ' ' .
                        $this->queryNamespaces()
         * @param bool $fulltext
         * @return string
         */
 -      function getIndexField( $fulltext ) {
 +      private function getIndexField( $fulltext ) {
                return $fulltext ? 'si_text' : 'si_title';
        }
  
         * @param bool $fulltext
         * @return string
         */
 -      function queryMain( $filteredTerm, $fulltext ) {
 +      private function queryMain( $filteredTerm, $fulltext ) {
                $match = $this->parseQuery( $filteredTerm, $fulltext );
                $page = $this->db->tableName( 'page' );
                $searchindex = $this->db->tableName( 'searchindex' );
                        "WHERE page_id=$searchindex.rowid AND $match";
        }
  
 -      function getCountQuery( $filteredTerm, $fulltext ) {
 +      private function getCountQuery( $filteredTerm, $fulltext ) {
                $match = $this->parseQuery( $filteredTerm, $fulltext );
                $page = $this->db->tableName( 'page' );
                $searchindex = $this->db->tableName( 'searchindex' );