summaryrefslogtreecommitdiff
path: root/includes/specials/SpecialRandompage.php
blob: fd3f17f2ff2f93db570e196443f8eaa53f676f94 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
<?php

/**
 * Special page to direct the user to a random page
 *
 * @ingroup SpecialPage
 * @author Rob Church <robchur@gmail.com>, Ilmari Karonen
 * @license GNU General Public Licence 2.0 or later
 */
class RandomPage extends SpecialPage {
	private $namespaces;  // namespaces to select pages from
	protected $isRedir = false; // should the result be a redirect?
	protected $extra = array(); // Extra SQL statements

	public function __construct( $name = 'Randompage' ){
		global $wgContentNamespaces;
		$this->namespaces = $wgContentNamespaces;
		parent::__construct( $name );
	}

	public function getNamespaces() {
		return $this->namespaces;
	}

	public function setNamespace ( $ns ) {
		if( !$ns || $ns < NS_MAIN ) $ns = NS_MAIN;
		$this->namespaces = array( $ns );
	}

	// select redirects instead of normal pages?
	public function isRedirect(){
		return $this->isRedir;
	}

	public function execute( $par ) {
		global $wgOut, $wgContLang;

		if ($par) {
			$this->setNamespace( $wgContLang->getNsIndex( $par ) );
		}

		$title = $this->getRandomTitle();

		if( is_null( $title ) ) {
			$this->setHeaders();
			$wgOut->addWikiMsg( strtolower( $this->mName ) . '-nopages', 
				$this->getNsList(), count( $this->namespaces ) );
			return;
		}

		$query = $this->isRedirect() ? 'redirect=no' : '';
		$wgOut->redirect( $title->getFullUrl( $query ) );
	}

	/**
	 * Get a comma-delimited list of namespaces we don't have
	 * any pages in
	 * @return String
	 */
	private function getNsList() {
		global $wgContLang;
		$nsNames = array();
		foreach( $this->namespaces as $n ) {
			if( $n === NS_MAIN )
				$nsNames[] = wfMsgForContent( 'blanknamespace' );
			else
				$nsNames[] = $wgContLang->getNsText( $n );
		}
		return $wgContLang->commaList( $nsNames );
	}


	/**
	 * Choose a random title.
	 * @return Title object (or null if nothing to choose from)
	 */
	public function getRandomTitle() {
		$randstr = wfRandom();
		$title = null;
		if ( !wfRunHooks( 'SpecialRandomGetRandomTitle', array( &$randstr, &$this->isRedir, &$this->namespaces, &$this->extra, &$title ) ) ) {
			return $title;
		}
		$row = $this->selectRandomPageFromDB( $randstr );

		/* If we picked a value that was higher than any in
		 * the DB, wrap around and select the page with the
		 * lowest value instead!  One might think this would
		 * skew the distribution, but in fact it won't cause
		 * any more bias than what the page_random scheme
		 * causes anyway.  Trust me, I'm a mathematician. :)
		 */
		if( !$row )
			$row = $this->selectRandomPageFromDB( "0" );

		if( $row )
			return Title::makeTitleSafe( $row->page_namespace, $row->page_title );
		else
			return null;
	}

	private function selectRandomPageFromDB( $randstr ) {
		global $wgExtraRandompageSQL;
		$dbr = wfGetDB( DB_SLAVE );

		$use_index = $dbr->useIndexClause( 'page_random' );
		$page = $dbr->tableName( 'page' );

		$ns = implode( ",", $this->namespaces );
		$redirect = $this->isRedirect() ? 1 : 0;
		
		if ( $wgExtraRandompageSQL ) {
			$this->extra[] = $wgExtraRandompageSQL;
		}
		if ( $this->addExtraSQL() ) {
			$this->extra[] = $this->addExtraSQL();
		}
		$extra = '';
		if ( $this->extra ) {
			$extra = 'AND (' . implode( ') AND (', $this->extra ) . ')';
		}
		$sql = "SELECT page_title, page_namespace
			FROM $page $use_index
			WHERE page_namespace IN ( $ns )
			AND page_is_redirect = $redirect
			AND page_random >= $randstr
			$extra
			ORDER BY page_random";

		$sql = $dbr->limitResult( $sql, 1, 0 );
		$res = $dbr->query( $sql, __METHOD__ );
		return $dbr->fetchObject( $res );
	}

	/* an alternative to $wgExtraRandompageSQL so subclasses
	 * can add their own SQL by overriding this function
	 * @deprecated, append to $this->extra instead
	 */
	public function addExtraSQL() {
		return '';
	}
}