make Special:Random retry (once, but more carefully) if the chosen random offset...
authorIlmari Karonen <vyznev@users.mediawiki.org>
Thu, 19 Apr 2007 10:19:27 +0000 (10:19 +0000)
committerIlmari Karonen <vyznev@users.mediawiki.org>
Thu, 19 Apr 2007 10:19:27 +0000 (10:19 +0000)
RELEASE-NOTES
includes/AutoLoader.php
includes/GlobalFunctions.php
includes/SpecialRandompage.php
includes/SpecialRandomredirect.php
languages/messages/MessagesEn.php
languages/messages/MessagesFi.php

index 95396ea..f305988 100644 (file)
@@ -323,6 +323,9 @@ it from source control: http://www.mediawiki.org/wiki/Download_from_SVN
 * (bug 6910) Correct date/time formats in Vietnamese (vi)
 * (bug 9608) Correctly use ORDER BY in dumpLinks.php
 * (bug 9609) Correctly use ORDER BY in SpecialWhatlinkshere.php
+* Special:Random and Special:Randomredirect now try harder to send the user to
+  a random page, and will give an error message if none really can be found
+  instead of sending the user to the main page like they used to
 
 == Maintenance ==
 
index 7bf879e..5d334da 100644 (file)
@@ -246,6 +246,7 @@ function __autoload($className) {
                'Language' => 'languages/Language.php',
                'PasswordResetForm' => 'includes/SpecialResetpass.php',
                'PatrolLog' => 'includes/PatrolLog.php',
+               'RandomPage' => 'includes/SpecialRandompage.php',
 
                // API classes
                'ApiBase' => 'includes/api/ApiBase.php',
index 291224b..26cbd0d 100644 (file)
@@ -129,13 +129,14 @@ function wfSeedRandom() {
  * not likely to give duplicate values for any realistic
  * number of articles.
  *
+ * @param float $limit Upper limit of returned values, default 1.
  * @return string
  */
-function wfRandom() {
+function wfRandom( $limit = 1 ) {
        # The maximum random value is "only" 2^31-1, so get two random
        # values to reduce the chance of dupes
        $max = mt_getrandmax() + 1;
-       $rand = number_format( (mt_rand() * $max + mt_rand())
+       $rand = number_format( (mt_rand() * $max + mt_rand()) * $limit
                / $max / $max, 12, '.', '' );
        return $rand;
 }
index 0dd0f51..051c9f9 100644 (file)
 <?php
+
 /**
+ * Special page to direct the user to a random page
+ *
  * @addtogroup SpecialPage
+ * @author Rob Church <robchur@gmail.com>, Ilmari Karonen
+ * @license GNU General Public Licence 2.0 or later
  */
 
 /**
- * Constructor
- *
- * @param $par The namespace to get a random page from (default NS_MAIN),
- *               used as e.g. Special:Randompage/Category
+ * Main execution point
+ * @param $par Namespace to select the page from
  */
-function wfSpecialRandompage( $par = NS_MAIN ) {
-       global $wgOut, $wgExtraRandompageSQL;
-       $fname = 'wfSpecialRandompage';
-
-       # Determine namespace
-       $t = Title::newFromText ( $par . ":Dummy" ) ;
-       $namespace = $t->getNamespace () ;
-
-       # NOTE! We use a literal constant in the SQL instead of the RAND()
-       # function because RAND() will return a different value for every row
-       # in the table. That's both very slow and returns results heavily
-       # biased towards low values, as rows later in the table will likely
-       # never be reached for comparison.
-       #
-       # Using a literal constant means the whole thing gets optimized on
-       # the index, and the comparison is both fast and fair.
-
-       # interpolation and sprintf() can muck up with locale-specific decimal separator
-       $randstr = wfRandom();
-
-       $db = wfGetDB( DB_SLAVE );
-       $use_index = $db->useIndexClause( 'page_random' );
-       $page = $db->tableName( 'page' );
-
-       $extra = $wgExtraRandompageSQL ? "AND ($wgExtraRandompageSQL)" : '';
-       $sql = "SELECT page_id,page_title
-               FROM $page $use_index
-               WHERE page_namespace=$namespace AND page_is_redirect=0 $extra
-               AND page_random>$randstr
-               ORDER BY page_random";
-       $sql = $db->limitResult($sql, 1, 0);
-       $res = $db->query( $sql, $fname );
-
-       $title = null;
-       if( $s = $db->fetchObject( $res ) ) {
-               $title =& Title::makeTitle( $namespace, $s->page_title );
-       }
+function wfSpecialRandompage( $par = null ) {
+       global $wgOut, $wgContLang;
+
+       $rnd = new RandomPage();
+       $rnd->setNamespace( $wgContLang->getNsIndex( $par ) );
+       $rnd->setRedirect( false );
+
+       $title = $rnd->getRandomTitle();
+
        if( is_null( $title ) ) {
-               # That's not supposed to happen :)
-               $title = Title::newMainPage();
+               $wgOut->addWikiText( wfMsg( 'randompage-nopages' ) );
+               return;
        }
-       $wgOut->reportTime(); # for logfile
+
+       $wgOut->reportTime();
        $wgOut->redirect( $title->getFullUrl() );
 }
 
+
+class RandomPage {
+       private $namespace = NS_MAIN;  // namespace to select pages from
+       private $redirect = false;     // select redirects instead of normal pages?
+
+       public function getNamespace ( ) {
+               return $this->namespace;
+       }
+       public function setNamespace ( $ns ) {
+               if( $ns < NS_MAIN ) $ns = NS_MAIN;
+               $this->namespace = $ns;
+       }
+       public function getRedirect ( ) {
+               return $this->redirect;
+       }
+       public function setRedirect ( $redirect ) {
+               $this->redirect = $redirect;
+       }
+
+       /**
+        * Choose a random title.
+        * @return Title object (or null if nothing to choose from)
+        */
+       public function getRandomTitle ( ) {
+               $randstr = wfRandom();
+               $row = $this->selectRandomPageFromDB( $randstr );
+
+               if( !$row ) {
+                       // Try again with a normalized value
+                       $randstr = wfRandom( $this->getMaxPageRandom() );
+                       $row = $this->selectRandomPageFromDB( $randstr );
+               }
+
+               if( $row )
+                       return Title::makeTitleSafe( $this->namespace, $row->page_title );
+               else
+                       return null;
+       }
+
+       private function selectRandomPageFromDB ( $randstr ) {
+               global $wgExtraRandompageSQL;
+               $fname = 'RandomPage::selectRandomPageFromDB';
+
+               $dbr = wfGetDB( DB_SLAVE );
+
+               $from = $this->getSQLFrom( $dbr );
+               $where = $this->getSQLWhere( $dbr );
+
+               $sql = "SELECT page_title FROM $from
+                       WHERE $where AND page_random > $randstr
+                       ORDER BY page_random";
+
+               $sql = $dbr->limitResult( $sql, 1, 0 );
+               $res = $dbr->query( $sql, $fname );
+               return $dbr->fetchObject( $res );
+       }
+
+       private function getMaxPageRandom () {
+               $fname = 'RandomPage::getMaxPageRandom';
+
+               $dbr = wfGetDB( DB_SLAVE );
+
+               $from = $this->getSQLFrom( $dbr );
+               $where = $this->getSQLWhere( $dbr );
+
+               $sql = "SELECT MAX(page_random) AS max FROM $from WHERE $where";
+
+               $sql = $dbr->limitResult( $sql, 1, 0 );
+               $res = $dbr->query( $sql, $fname );
+               $row = $dbr->fetchObject( $res );
+
+               return $row ? $row->max : 0;
+       }
+
+       private function getSQLFrom ( $dbr ) {
+               $use_index = $dbr->useIndexClause( 'page_random' );
+               $page = $dbr->tableName( 'page' );
+               return "$page $use_index";
+       }
+
+       private function getSQLWhere ( $dbr ) {
+               global $wgExtraRandompageSQL;
+               $ns = (int) $this->namespace;
+               $redirect = $this->redirect ? 1 : 0;
+               $extra = $wgExtraRandompageSQL ? " AND ($wgExtraRandompageSQL)" : "";
+               return "page_namespace = $ns AND page_is_redirect = $redirect" . $extra;
+       }
+}
+
 ?>
index 903702a..75a6b81 100644 (file)
@@ -4,7 +4,7 @@
  * Special page to direct the user to a random redirect page (minus the second redirect)
  *
  * @addtogroup SpecialPage
- * @author Rob Church <robchur@gmail.com>
+ * @author Rob Church <robchur@gmail.com>, Ilmari Karonen
  * @license GNU General Public Licence 2.0 or later
  */
 
  * Main execution point
  * @param $par Namespace to select the redirect from
  */
-function wfSpecialRandomredirect( $par = NULL ) {
-       global $wgOut, $wgExtraRandompageSQL, $wgContLang;
-       $fname = 'wfSpecialRandomredirect';
+function wfSpecialRandomredirect( $par = null ) {
+       global $wgOut, $wgContLang;
 
-       # Validate the namespace
-       $namespace = $wgContLang->getNsIndex( $par );
-       if( $namespace === false || $namespace < NS_MAIN )
-               $namespace = NS_MAIN;
+       $rnd = new RandomPage();
+       $rnd->setNamespace( $wgContLang->getNsIndex( $par ) );
+       $rnd->setRedirect( true );
 
-       # Same logic as RandomPage
-       $randstr = wfRandom();
+       $title = $rnd->getRandomTitle();
 
-       $dbr = wfGetDB( DB_SLAVE );
-       $use_index = $dbr->useIndexClause( 'page_random' );
-       $page = $dbr->tableName( 'page' );
+       if( is_null( $title ) ) {
+               $wgOut->addWikiText( wfMsg( 'randomredirect-nopages' ) );
+               return;
+       }
 
-       $extra = $wgExtraRandompageSQL ? "AND ($wgExtraRandompageSQL)" : '';
-       $sql = "SELECT page_id,page_title
-               FROM $page $use_index
-               WHERE page_namespace = $namespace AND page_is_redirect = 1 $extra
-               AND page_random > $randstr
-               ORDER BY page_random";
-               
-       $sql = $dbr->limitResult( $sql, 1, 0 );
-       $res = $dbr->query( $sql, $fname );
-
-       $title = NULL;
-       if( $row = $dbr->fetchObject( $res ) )
-               $title = Title::makeTitleSafe( $namespace, $row->page_title );
-
-       # Catch dud titles and return to the main page
-       if( is_null( $title ) )
-               $title = Title::newMainPage();
-               
        $wgOut->reportTime();
        $wgOut->redirect( $title->getFullUrl( 'redirect=no' ) );
 }
index 345bbb9..c1dc18c 100644 (file)
@@ -1475,6 +1475,7 @@ this old version, (rev) = revert to this old version.
 
 # Random redirect
 'randomredirect' => 'Random redirect',
+'randomredirect-nopages' => 'There are no redirects in this namespace.',
 
 # Statistics
 #
@@ -1560,6 +1561,7 @@ The [http://meta.wikimedia.org/wiki/Help:Job_queue job queue] length is '''$7'''
 'prefixindex'   => 'Prefix index',
 'prefixindex-summary' => '',
 'randompage'   => 'Random page',
+'randompage-nopages'   => 'There are no pages in this namespace.',
 'randompage-url'=> 'Special:Random',
 'shortpages'   => 'Short pages',
 'shortpages-summary'     => '',
index 266184a..9a03ddb 100644 (file)
@@ -991,6 +991,7 @@ Huomaa, että {{GRAMMAR:inessive|{{SITENAME}}}} muut voivat muokata tai poistaa
 
 # Random redirect
 'randomredirect' => 'Satunnainen uudelleenohjaus',
+'randomredirect-nopages' => 'Tässä nimiavaruudessa ei ole uudelleenohjauksia.',
 
 # Statistics
 'statistics'             => 'Tilastot',
@@ -1049,6 +1050,7 @@ Ohjelmiston suorittamia ylläpitotöitä on jonossa '''$7''' {{PLURAL:$7|kappale
 'allpages'                => 'Kaikki sivut',
 'prefixindex'             => 'Sivut otsikon alun mukaan',
 'randompage'              => 'Satunnainen sivu',
+'randompage-nopages'      => 'Tässä nimiavaruudessa ei ole sivuja.',
 'shortpages'              => 'Lyhyet sivut',
 'longpages'               => 'Pitkät sivut',
 'deadendpages'            => 'Sivut, joilla ei ole linkkejä',