00001 <?php
00002
00007 class SpecialAllpages extends IncludableSpecialPage {
00008
00012 protected $maxPerPage = 345;
00013
00017 protected $maxLineCount = 200;
00018
00022 protected $maxPageLength = 70;
00023
00027 protected $nsfromMsg = 'allpagesfrom';
00028
00029 function __construct( $name = 'Allpages' ){
00030 parent::__construct( $name );
00031 }
00032
00038 function execute( $par ) {
00039 global $wgRequest, $wgOut, $wgContLang;
00040
00041 $this->setHeaders();
00042 $this->outputHeader();
00043
00044 # GET values
00045 $from = $wgRequest->getVal( 'from', null );
00046 $to = $wgRequest->getVal( 'to', null );
00047 $namespace = $wgRequest->getInt( 'namespace' );
00048
00049 $namespaces = $wgContLang->getNamespaces();
00050
00051 $wgOut->setPagetitle( ( $namespace > 0 && in_array( $namespace, array_keys( $namespaces) ) ) ?
00052 wfMsg( 'allinnamespace', str_replace( '_', ' ', $namespaces[$namespace] ) ) :
00053 wfMsg( 'allarticles' )
00054 );
00055
00056 if( isset($par) ) {
00057 $this->showChunk( $namespace, $par, $to );
00058 } elseif( isset($from) && !isset($to) ) {
00059 $this->showChunk( $namespace, $from, $to );
00060 } else {
00061 $this->showToplevel( $namespace, $from, $to );
00062 }
00063 }
00064
00071 function namespaceForm( $namespace = NS_MAIN, $from = '', $to = '' ) {
00072 global $wgScript;
00073 $t = $this->getTitle();
00074
00075 $out = Xml::openElement( 'div', array( 'class' => 'namespaceoptions' ) );
00076 $out .= Xml::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript ) );
00077 $out .= Xml::hidden( 'title', $t->getPrefixedText() );
00078 $out .= Xml::openElement( 'fieldset' );
00079 $out .= Xml::element( 'legend', null, wfMsg( 'allpages' ) );
00080 $out .= Xml::openElement( 'table', array( 'id' => 'nsselect', 'class' => 'allpages' ) );
00081 $out .= "<tr>
00082 <td class='mw-label'>" .
00083 Xml::label( wfMsg( 'allpagesfrom' ), 'nsfrom' ) .
00084 "</td>
00085 <td class='mw-input'>" .
00086 Xml::input( 'from', 30, str_replace('_',' ',$from), array( 'id' => 'nsfrom' ) ) .
00087 "</td>
00088 </tr>
00089 <tr>
00090 <td class='mw-label'>" .
00091 Xml::label( wfMsg( 'allpagesto' ), 'nsto' ) .
00092 "</td>
00093 <td class='mw-input'>" .
00094 Xml::input( 'to', 30, str_replace('_',' ',$to), array( 'id' => 'nsto' ) ) .
00095 "</td>
00096 </tr>
00097 <tr>
00098 <td class='mw-label'>" .
00099 Xml::label( wfMsg( 'namespace' ), 'namespace' ) .
00100 "</td>
00101 <td class='mw-input'>" .
00102 Xml::namespaceSelector( $namespace, null ) . ' ' .
00103 Xml::submitButton( wfMsg( 'allpagessubmit' ) ) .
00104 "</td>
00105 </tr>";
00106 $out .= Xml::closeElement( 'table' );
00107 $out .= Xml::closeElement( 'fieldset' );
00108 $out .= Xml::closeElement( 'form' );
00109 $out .= Xml::closeElement( 'div' );
00110 return $out;
00111 }
00112
00116 function showToplevel( $namespace = NS_MAIN, $from = '', $to = '' ) {
00117 global $wgOut, $wgContLang;
00118 $align = $wgContLang->isRtl() ? 'left' : 'right';
00119
00120 # TODO: Either make this *much* faster or cache the title index points
00121 # in the querycache table.
00122
00123 $dbr = wfGetDB( DB_SLAVE );
00124 $out = "";
00125 $where = array( 'page_namespace' => $namespace );
00126
00127 $from = Title::makeTitleSafe( $namespace, $from );
00128 $to = Title::makeTitleSafe( $namespace, $to );
00129 $from = ( $from && $from->isLocal() ) ? $from->getDBKey() : null;
00130 $to = ( $to && $to->isLocal() ) ? $to->getDBKey() : null;
00131
00132 if( isset($from) )
00133 $where[] = 'page_title >= '.$dbr->addQuotes( $from );
00134 if( isset($to) )
00135 $where[] = 'page_title <= '.$dbr->addQuotes( $to );
00136
00137 global $wgMemc;
00138 $key = wfMemcKey( 'allpages', 'ns', $namespace, $from, $to );
00139 $lines = $wgMemc->get( $key );
00140
00141 $count = $dbr->estimateRowCount( 'page', '*', $where, __METHOD__ );
00142 $maxPerSubpage = intval($count/$this->maxLineCount);
00143 $maxPerSubpage = max($maxPerSubpage,$this->maxPerPage);
00144
00145 if( !is_array( $lines ) ) {
00146 $options = array( 'LIMIT' => 1 );
00147 $options['ORDER BY'] = 'page_title ASC';
00148 $firstTitle = $dbr->selectField( 'page', 'page_title', $where, __METHOD__, $options );
00149 $lastTitle = $firstTitle;
00150 # This array is going to hold the page_titles in order.
00151 $lines = array( $firstTitle );
00152 # If we are going to show n rows, we need n+1 queries to find the relevant titles.
00153 $done = false;
00154 while( !$done ) {
00155
00156 $chunk = ( $lastTitle === false )
00157 ? array()
00158 : array( 'page_title >= ' . $dbr->addQuotes( $lastTitle ) );
00159 $res = $dbr->select( 'page',
00160 'page_title',
00161 array_merge($where,$chunk),
00162 __METHOD__,
00163 array ('LIMIT' => 2, 'OFFSET' => $maxPerSubpage - 1, 'ORDER BY' => 'page_title ASC')
00164 );
00165
00166 if( $s = $dbr->fetchObject( $res ) ) {
00167 array_push( $lines, $s->page_title );
00168 } else {
00169
00170 $endTitle = $dbr->selectField( 'page', 'MAX(page_title)',
00171 array_merge($where,$chunk),
00172 __METHOD__ );
00173 array_push( $lines, $endTitle );
00174 $done = true;
00175 }
00176 if( $s = $res->fetchObject() ) {
00177 array_push( $lines, $s->page_title );
00178 $lastTitle = $s->page_title;
00179 } else {
00180
00181
00182 $done = true;
00183 }
00184 $res->free();
00185 }
00186 $wgMemc->add( $key, $lines, 3600 );
00187 }
00188
00189
00190
00191 if( count( $lines ) <= 2 ) {
00192 if( !empty($lines) ) {
00193 $this->showChunk( $namespace, $lines[0], $lines[count($lines)-1] );
00194 } else {
00195 $wgOut->addHTML( $this->namespaceForm( $namespace, $from, $to ) );
00196 }
00197 return;
00198 }
00199
00200 # At this point, $lines should contain an even number of elements.
00201 $out .= "<table class='allpageslist' style='background: inherit;'>";
00202 while( count ( $lines ) > 0 ) {
00203 $inpoint = array_shift( $lines );
00204 $outpoint = array_shift( $lines );
00205 $out .= $this->showline( $inpoint, $outpoint, $namespace );
00206 }
00207 $out .= '</table>';
00208 $nsForm = $this->namespaceForm( $namespace, $from, $to );
00209
00210 # Is there more?
00211 if( $this->including() ) {
00212 $out2 = '';
00213 } else {
00214 if( isset($from) || isset($to) ) {
00215 global $wgUser;
00216 $out2 = '<table style="background: inherit;" width="100%" cellpadding="0" cellspacing="0" border="0">';
00217 $out2 .= '<tr valign="top"><td>' . $nsForm;
00218 $out2 .= '</td><td align="' . $align . '" style="font-size: smaller; margin-bottom: 1em;">' .
00219 $wgUser->getSkin()->makeKnownLinkObj( $this->getTitle(), wfMsgHtml ( 'allpages' ) );
00220 $out2 .= "</td></tr></table>";
00221 } else {
00222 $out2 = $nsForm;
00223 }
00224 }
00225 $wgOut->addHTML( $out2 . $out );
00226 }
00227
00234 function showline( $inpoint, $outpoint, $namespace = NS_MAIN ) {
00235 global $wgContLang;
00236 $align = $wgContLang->isRtl() ? 'left' : 'right';
00237 $inpointf = htmlspecialchars( str_replace( '_', ' ', $inpoint ) );
00238 $outpointf = htmlspecialchars( str_replace( '_', ' ', $outpoint ) );
00239
00240 $inpointf = $wgContLang->truncate( $inpointf, $this->maxPageLength );
00241 $outpointf = $wgContLang->truncate( $outpointf, $this->maxPageLength );
00242
00243 $queryparams = $namespace ? "namespace=$namespace&" : '';
00244 $special = $this->getTitle();
00245 $link = $special->escapeLocalUrl( $queryparams . 'from=' . urlencode($inpoint) . '&to=' . urlencode($outpoint) );
00246
00247 $out = wfMsgHtml( 'alphaindexline',
00248 "<a href=\"$link\">$inpointf</a></td><td>",
00249 "</td><td><a href=\"$link\">$outpointf</a>"
00250 );
00251 return '<tr><td align="' . $align . '">'.$out.'</td></tr>';
00252 }
00253
00259 function showChunk( $namespace = NS_MAIN, $from = false, $to = false ) {
00260 global $wgOut, $wgUser, $wgContLang, $wgLang;
00261
00262 $sk = $wgUser->getSkin();
00263
00264 $fromList = $this->getNamespaceKeyAndText($namespace, $from);
00265 $toList = $this->getNamespaceKeyAndText( $namespace, $to );
00266 $namespaces = $wgContLang->getNamespaces();
00267 $align = $wgContLang->isRtl() ? 'left' : 'right';
00268
00269 $n = 0;
00270
00271 if ( !$fromList || !$toList ) {
00272 $out = wfMsgWikiHtml( 'allpagesbadtitle' );
00273 } elseif ( !in_array( $namespace, array_keys( $namespaces ) ) ) {
00274
00275 $out = wfMsgExt( 'allpages-bad-ns', array( 'parseinline' ), $namespace );
00276 $namespace = NS_MAIN;
00277 } else {
00278 list( $namespace, $fromKey, $from ) = $fromList;
00279 list( $namespace2, $toKey, $to ) = $toList;
00280
00281 $dbr = wfGetDB( DB_SLAVE );
00282 $conds = array(
00283 'page_namespace' => $namespace,
00284 'page_title >= ' . $dbr->addQuotes( $fromKey )
00285 );
00286 if( $toKey !== "" ) {
00287 $conds[] = 'page_title <= ' . $dbr->addQuotes( $toKey );
00288 }
00289
00290 $res = $dbr->select( 'page',
00291 array( 'page_namespace', 'page_title', 'page_is_redirect' ),
00292 $conds,
00293 __METHOD__,
00294 array(
00295 'ORDER BY' => 'page_title',
00296 'LIMIT' => $this->maxPerPage + 1,
00297 'USE INDEX' => 'name_title',
00298 )
00299 );
00300
00301 if( $res->numRows() > 0 ) {
00302 $out = '<table style="background: inherit;" border="0" width="100%">';
00303
00304 while( ( $n < $this->maxPerPage ) && ( $s = $res->fetchObject() ) ) {
00305 $t = Title::makeTitle( $s->page_namespace, $s->page_title );
00306 if( $t ) {
00307 $link = ( $s->page_is_redirect ? '<div class="allpagesredirect">' : '' ) .
00308 $sk->makeKnownLinkObj( $t, htmlspecialchars( $t->getText() ), false, false ) .
00309 ($s->page_is_redirect ? '</div>' : '' );
00310 } else {
00311 $link = '[[' . htmlspecialchars( $s->page_title ) . ']]';
00312 }
00313 if( $n % 3 == 0 ) {
00314 $out .= '<tr>';
00315 }
00316 $out .= "<td width=\"33%\">$link</td>";
00317 $n++;
00318 if( $n % 3 == 0 ) {
00319 $out .= '</tr>';
00320 }
00321 }
00322 if( ($n % 3) != 0 ) {
00323 $out .= '</tr>';
00324 }
00325 $out .= '</table>';
00326 } else {
00327 $out = '';
00328 }
00329 }
00330
00331 if ( $this->including() ) {
00332 $out2 = '';
00333 } else {
00334 if( $from == '' ) {
00335
00336 $prevTitle = null;
00337 } else {
00338 # Get the last title from previous chunk
00339 $dbr = wfGetDB( DB_SLAVE );
00340 $res_prev = $dbr->select(
00341 'page',
00342 'page_title',
00343 array( 'page_namespace' => $namespace, 'page_title < '.$dbr->addQuotes($from) ),
00344 __METHOD__,
00345 array( 'ORDER BY' => 'page_title DESC', 'LIMIT' => $this->maxPerPage, 'OFFSET' => ($this->maxPerPage - 1 ) )
00346 );
00347
00348 # Get first title of previous complete chunk
00349 if( $dbr->numrows( $res_prev ) >= $this->maxPerPage ) {
00350 $pt = $dbr->fetchObject( $res_prev );
00351 $prevTitle = Title::makeTitle( $namespace, $pt->page_title );
00352 } else {
00353 # The previous chunk is not complete, need to link to the very first title
00354 # available in the database
00355 $options = array( 'LIMIT' => 1 );
00356 if ( ! $dbr->implicitOrderby() ) {
00357 $options['ORDER BY'] = 'page_title';
00358 }
00359 $reallyFirstPage_title = $dbr->selectField( 'page', 'page_title',
00360 array( 'page_namespace' => $namespace ), __METHOD__, $options );
00361 # Show the previous link if it s not the current requested chunk
00362 if( $from != $reallyFirstPage_title ) {
00363 $prevTitle = Title::makeTitle( $namespace, $reallyFirstPage_title );
00364 } else {
00365 $prevTitle = null;
00366 }
00367 }
00368 }
00369
00370 $self = $this->getTitle();
00371
00372 $nsForm = $this->namespaceForm( $namespace, $from, $to );
00373 $out2 = '<table style="background: inherit;" width="100%" cellpadding="0" cellspacing="0" border="0">';
00374 $out2 .= '<tr valign="top"><td>' . $nsForm;
00375 $out2 .= '</td><td align="' . $align . '" style="font-size: smaller; margin-bottom: 1em;">' .
00376 $sk->makeKnownLinkObj( $self,
00377 wfMsgHtml ( 'allpages' ) );
00378
00379 # Do we put a previous link ?
00380 if( isset( $prevTitle ) && $pt = $prevTitle->getText() ) {
00381 $q = 'from=' . $prevTitle->getPartialUrl()
00382 . ( $namespace ? '&namespace=' . $namespace : '' );
00383 $prevLink = $sk->makeKnownLinkObj( $self,
00384 wfMsgHTML( 'prevpage', htmlspecialchars( $pt ) ), $q );
00385 $out2 = $wgLang->pipeList( array( $out2, $prevLink ) );
00386 }
00387
00388 if( $n == $this->maxPerPage && $s = $res->fetchObject() ) {
00389 # $s is the first link of the next chunk
00390 $t = Title::MakeTitle($namespace, $s->page_title);
00391 $q = 'from=' . $t->getPartialUrl()
00392 . ( $namespace ? '&namespace=' . $namespace : '' );
00393 $nextLink = $sk->makeKnownLinkObj( $self,
00394 wfMsgHtml( 'nextpage', htmlspecialchars( $t->getText() ) ), $q );
00395 $out2 = $wgLang->pipeList( array( $out2, $nextLink ) );
00396 }
00397 $out2 .= "</td></tr></table>";
00398 }
00399
00400 $wgOut->addHTML( $out2 . $out );
00401 if( isset($prevLink) or isset($nextLink) ) {
00402 $wgOut->addHTML( '<hr /><p style="font-size: smaller; float: ' . $align . '">' );
00403 if( isset( $prevLink ) ) {
00404 $wgOut->addHTML( $prevLink );
00405 }
00406 if( isset( $prevLink ) && isset( $nextLink ) ) {
00407 $wgOut->addHTML( wfMsgExt( 'pipe-separator' , 'escapenoentities' ) );
00408 }
00409 if( isset( $nextLink ) ) {
00410 $wgOut->addHTML( $nextLink );
00411 }
00412 $wgOut->addHTML( '</p>' );
00413
00414 }
00415
00416 }
00417
00425 function getNamespaceKeyAndText($ns, $text) {
00426 if ( $text == '' )
00427 return array( $ns, '', '' ); # shortcut for common case
00428
00429 $t = Title::makeTitleSafe($ns, $text);
00430 if ( $t && $t->isLocal() ) {
00431 return array( $t->getNamespace(), $t->getDBkey(), $t->getText() );
00432 } else if ( $t ) {
00433 return NULL;
00434 }
00435
00436 # try again, in case the problem was an empty pagename
00437 $text = preg_replace('/(#|$)/', 'X$1', $text);
00438 $t = Title::makeTitleSafe($ns, $text);
00439 if ( $t && $t->isLocal() ) {
00440 return array( $t->getNamespace(), '', '' );
00441 } else {
00442 return NULL;
00443 }
00444 }
00445 }