In Special:AllPages, limit the size of hierarchical lists
[lhc/web/wiklou.git] / includes / specials / SpecialAllpages.php
index 7505df8..388705d 100644 (file)
@@ -49,6 +49,16 @@ class SpecialAllpages extends IncludableSpecialPage {
         */
        protected $maxPageLength = 70;
 
+       /**
+        * Maximum number of pages in a hierarchical ("top level") list.
+        *
+        * Traversal of the entire page list by spidering the top levels is thought
+        * to require O(N^3) DB CPU time where N is the number of pages on the wiki.
+        * See bug 56840. If this limit is exceeded, the behaviour becomes like a
+        * simple alphabetic pager.
+        */
+       protected $maxTopLevelPages = 50000;
+
        /**
         * Determines, which message describes the input field 'nsfrom'.
         *
@@ -71,7 +81,6 @@ class SpecialAllpages extends IncludableSpecialPage {
         * @param string $par becomes "FOO" when called like Special:Allpages/FOO (default NULL)
         */
        function execute( $par ) {
-               global $wgContLang;
                $request = $this->getRequest();
                $out = $this->getOutput();
 
@@ -85,7 +94,7 @@ class SpecialAllpages extends IncludableSpecialPage {
                $namespace = $request->getInt( 'namespace' );
                $hideredirects = $request->getBool( 'hideredirects', false );
 
-               $namespaces = $wgContLang->getNamespaces();
+               $namespaces = $this->getContext()->getLanguage()->getNamespaces();
 
                $out->setPageTitle(
                        ( $namespace > 0 && in_array( $namespace, array_keys( $namespaces ) ) ) ?
@@ -160,6 +169,7 @@ class SpecialAllpages extends IncludableSpecialPage {
                $out .= Xml::closeElement( 'fieldset' );
                $out .= Xml::closeElement( 'form' );
                $out .= Xml::closeElement( 'div' );
+
                return $out;
        }
 
@@ -201,6 +211,14 @@ class SpecialAllpages extends IncludableSpecialPage {
                $lines = $wgMemc->get( $key );
 
                $count = $dbr->estimateRowCount( 'page', '*', $where, __METHOD__ );
+
+               // Don't show a hierarchical list if the number of pages is very large,
+               // since generating it will cause a lot of scanning
+               if ( $count > $this->maxTopLevelPages ) {
+                       $this->showChunk( $namespace, $from, $to, $hideredirects );
+                       return;
+               }
+
                $maxPerSubpage = intval( $count / $this->maxLineCount );
                $maxPerSubpage = max( $maxPerSubpage, $this->maxPerPage );
 
@@ -259,6 +277,7 @@ class SpecialAllpages extends IncludableSpecialPage {
                        } else {
                                $output->addHTML( $this->namespaceForm( $namespace, $from, $to, $hideredirects ) );
                        }
+
                        return;
                }
 
@@ -305,32 +324,37 @@ class SpecialAllpages extends IncludableSpecialPage {
         * @return string
         */
        function showline( $inpoint, $outpoint, $namespace = NS_MAIN, $hideRedirects = false ) {
+               // Use content language since page titles are considered to use content language
                global $wgContLang;
-               $inpointf = htmlspecialchars( str_replace( '_', ' ', $inpoint ) );
-               $outpointf = htmlspecialchars( str_replace( '_', ' ', $outpoint ) );
+
+               $inpointf = str_replace( '_', ' ', $inpoint );
+               $outpointf = str_replace( '_', ' ', $outpoint );
+
                // Don't let the length runaway
                $inpointf = $wgContLang->truncate( $inpointf, $this->maxPageLength );
                $outpointf = $wgContLang->truncate( $outpointf, $this->maxPageLength );
 
-               $queryParams = array (
+               $queryParams = array(
                        'from' => $inpoint,
                        'to' => $outpoint,
                );
 
-               if( $namespace ) {
+               if ( $namespace ) {
                        $queryParams['namespace'] = $namespace;
                }
                if ( $hideRedirects ) {
                        $queryParams['hideredirects'] = 1;
                }
 
-               $link = htmlspecialchars(
-                       $this->getTitle()->getLocalURL( $queryParams ) );
+               $url = $this->getTitle()->getLocalURL( $queryParams );
+               $inlink = Html::element( 'a', array( 'href' => $url ), $inpointf );
+               $outlink = Html::element( 'a', array( 'href' => $url ), $outpointf );
 
                $out = $this->msg( 'alphaindexline' )->rawParams(
-                       "<a href=\"$link\">$inpointf</a></td><td>",
-                       "</td><td><a href=\"$link\">$outpointf</a>"
+                       "$inlink</td><td>",
+                       "</td><td>$outlink"
                )->escaped();
+
                return '<tr><td class="mw-allpages-alphaindexline">' . $out . '</td></tr>';
        }
 
@@ -341,12 +365,11 @@ class SpecialAllpages extends IncludableSpecialPage {
         * @param bool $hideredirects dont show redirects (default FALSE)
         */
        function showChunk( $namespace = NS_MAIN, $from = false, $to = false, $hideredirects = false ) {
-               global $wgContLang;
                $output = $this->getOutput();
 
                $fromList = $this->getNamespaceKeyAndText( $namespace, $from );
                $toList = $this->getNamespaceKeyAndText( $namespace, $to );
-               $namespaces = $wgContLang->getNamespaces();
+               $namespaces = $this->getContext()->getLanguage()->getNamespaces();
                $n = 0;
 
                if ( !$fromList || !$toList ) {
@@ -532,7 +555,6 @@ class SpecialAllpages extends IncludableSpecialPage {
                                        )
                        );
                }
-
        }
 
        /**