From: Ilmari Karonen Date: Thu, 19 Apr 2007 10:19:27 +0000 (+0000) Subject: make Special:Random retry (once, but more carefully) if the chosen random offset... X-Git-Tag: 1.31.0-rc.0~53364 X-Git-Url: http://git.cyclocoop.org/%22.%24image2.%22?a=commitdiff_plain;h=a5d5a6b5b8f1dde97bd9797834c1fe1f6065aa13;p=lhc%2Fweb%2Fwiklou.git make Special:Random retry (once, but more carefully) if the chosen random offset was too high, provide error message if there really are no pages to choose from rather than going to the main page. rewrite Special:Randomredirect to reuse code from Special:Random. --- diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 95396eab3b..f305988c99 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -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 == diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php index 7bf879e51f..5d334da081 100644 --- a/includes/AutoLoader.php +++ b/includes/AutoLoader.php @@ -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', diff --git a/includes/GlobalFunctions.php b/includes/GlobalFunctions.php index 291224b832..26cbd0db6b 100644 --- a/includes/GlobalFunctions.php +++ b/includes/GlobalFunctions.php @@ -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; } diff --git a/includes/SpecialRandompage.php b/includes/SpecialRandompage.php index 0dd0f51d29..051c9f94d7 100644 --- a/includes/SpecialRandompage.php +++ b/includes/SpecialRandompage.php @@ -1,57 +1,122 @@ , 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; + } +} + ?> diff --git a/includes/SpecialRandomredirect.php b/includes/SpecialRandomredirect.php index 903702a2d4..75a6b81d02 100644 --- a/includes/SpecialRandomredirect.php +++ b/includes/SpecialRandomredirect.php @@ -4,7 +4,7 @@ * Special page to direct the user to a random redirect page (minus the second redirect) * * @addtogroup SpecialPage - * @author Rob Church + * @author Rob Church , Ilmari Karonen * @license GNU General Public Licence 2.0 or later */ @@ -12,40 +12,20 @@ * 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' ) ); } diff --git a/languages/messages/MessagesEn.php b/languages/messages/MessagesEn.php index 345bbb996e..c1dc18c138 100644 --- a/languages/messages/MessagesEn.php +++ b/languages/messages/MessagesEn.php @@ -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' => '', diff --git a/languages/messages/MessagesFi.php b/languages/messages/MessagesFi.php index 266184a605..9a03ddbd4f 100644 --- a/languages/messages/MessagesFi.php +++ b/languages/messages/MessagesFi.php @@ -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ä',