MediaWiki  REL1_22
SpecialStatistics.php
Go to the documentation of this file.
00001 <?php
00030 class SpecialStatistics extends SpecialPage {
00031 
00032     private $views, $edits, $good, $images, $total, $users,
00033             $activeUsers = 0;
00034 
00035     public function __construct() {
00036         parent::__construct( 'Statistics' );
00037     }
00038 
00039     public function execute( $par ) {
00040         global $wgMemc, $wgDisableCounters, $wgMiserMode;
00041 
00042         $this->setHeaders();
00043         $this->getOutput()->addModuleStyles( 'mediawiki.special' );
00044 
00045         $this->views = SiteStats::views();
00046         $this->edits = SiteStats::edits();
00047         $this->good = SiteStats::articles();
00048         $this->images = SiteStats::images();
00049         $this->total = SiteStats::pages();
00050         $this->users = SiteStats::users();
00051         $this->activeUsers = SiteStats::activeUsers();
00052         $this->hook = '';
00053 
00054         # Staticic - views
00055         $viewsStats = '';
00056         if ( !$wgDisableCounters ) {
00057             $viewsStats = $this->getViewsStats();
00058         }
00059 
00060         # Set active user count
00061         if ( !$wgMiserMode ) {
00062             $key = wfMemcKey( 'sitestats', 'activeusers-updated' );
00063             // Re-calculate the count if the last tally is old...
00064             if ( !$wgMemc->get( $key ) ) {
00065                 $dbw = wfGetDB( DB_MASTER );
00066                 SiteStatsUpdate::cacheUpdate( $dbw );
00067                 $wgMemc->set( $key, '1', 24 * 3600 ); // don't update for 1 day
00068             }
00069         }
00070 
00071         $text = Xml::openElement( 'table', array( 'class' => 'wikitable mw-statistics-table' ) );
00072 
00073         # Statistic - pages
00074         $text .= $this->getPageStats();
00075 
00076         # Statistic - edits
00077         $text .= $this->getEditStats();
00078 
00079         # Statistic - users
00080         $text .= $this->getUserStats();
00081 
00082         # Statistic - usergroups
00083         $text .= $this->getGroupStats();
00084         $text .= $viewsStats;
00085 
00086         # Statistic - popular pages
00087         if ( !$wgDisableCounters && !$wgMiserMode ) {
00088             $text .= $this->getMostViewedPages();
00089         }
00090 
00091         # Statistic - other
00092         $extraStats = array();
00093         if ( wfRunHooks( 'SpecialStatsAddExtra', array( &$extraStats ) ) ) {
00094             $text .= $this->getOtherStats( $extraStats );
00095         }
00096 
00097         $text .= Xml::closeElement( 'table' );
00098 
00099         # Customizable footer
00100         $footer = $this->msg( 'statistics-footer' );
00101         if ( !$footer->isBlank() ) {
00102             $text .= "\n" . $footer->parse();
00103         }
00104 
00105         $this->getOutput()->addHTML( $text );
00106     }
00107 
00117     private function formatRow( $text, $number, $trExtraParams = array(), $descMsg = '', $descMsgParam = '' ) {
00118         if ( $descMsg ) {
00119             $msg = $this->msg( $descMsg, $descMsgParam );
00120             if ( $msg->exists() ) {
00121                 $descriptionText = $this->msg( 'parentheses' )->rawParams( $msg->parse() )->escaped();
00122                 $text .= "<br />" . Xml::element( 'small', array( 'class' => 'mw-statistic-desc' ),
00123                     " $descriptionText" );
00124             }
00125         }
00126         return Html::rawElement( 'tr', $trExtraParams,
00127             Html::rawElement( 'td', array(), $text ) .
00128             Html::rawElement( 'td', array( 'class' => 'mw-statistics-numbers' ), $number )
00129         );
00130     }
00131 
00137     private function getPageStats() {
00138         return Xml::openElement( 'tr' ) .
00139             Xml::tags( 'th', array( 'colspan' => '2' ), $this->msg( 'statistics-header-pages' )->parse() ) .
00140             Xml::closeElement( 'tr' ) .
00141                 $this->formatRow( Linker::linkKnown( SpecialPage::getTitleFor( 'Allpages' ),
00142                         $this->msg( 'statistics-articles' )->parse() ),
00143                         $this->getLanguage()->formatNum( $this->good ),
00144                         array( 'class' => 'mw-statistics-articles' ) ) .
00145                 $this->formatRow( $this->msg( 'statistics-pages' )->parse(),
00146                         $this->getLanguage()->formatNum( $this->total ),
00147                         array( 'class' => 'mw-statistics-pages' ),
00148                         'statistics-pages-desc' ) .
00149                 $this->formatRow( Linker::linkKnown( SpecialPage::getTitleFor( 'Listfiles' ),
00150                         $this->msg( 'statistics-files' )->parse() ),
00151                         $this->getLanguage()->formatNum( $this->images ),
00152                         array( 'class' => 'mw-statistics-files' ) );
00153     }
00154     private function getEditStats() {
00155         return Xml::openElement( 'tr' ) .
00156             Xml::tags( 'th', array( 'colspan' => '2' ), $this->msg( 'statistics-header-edits' )->parse() ) .
00157             Xml::closeElement( 'tr' ) .
00158                 $this->formatRow( $this->msg( 'statistics-edits' )->parse(),
00159                         $this->getLanguage()->formatNum( $this->edits ),
00160                         array( 'class' => 'mw-statistics-edits' ) ) .
00161                 $this->formatRow( $this->msg( 'statistics-edits-average' )->parse(),
00162                         $this->getLanguage()->formatNum( sprintf( '%.2f', $this->total ? $this->edits / $this->total : 0 ) ),
00163                         array( 'class' => 'mw-statistics-edits-average' ) );
00164     }
00165 
00166     private function getUserStats() {
00167         global $wgActiveUserDays;
00168         return Xml::openElement( 'tr' ) .
00169             Xml::tags( 'th', array( 'colspan' => '2' ), $this->msg( 'statistics-header-users' )->parse() ) .
00170             Xml::closeElement( 'tr' ) .
00171                 $this->formatRow( $this->msg( 'statistics-users' )->parse(),
00172                         $this->getLanguage()->formatNum( $this->users ),
00173                         array( 'class' => 'mw-statistics-users' ) ) .
00174                 $this->formatRow( $this->msg( 'statistics-users-active' )->parse() . ' ' .
00175                             Linker::linkKnown(
00176                                 SpecialPage::getTitleFor( 'Activeusers' ),
00177                                 $this->msg( 'listgrouprights-members' )->escaped()
00178                             ),
00179                         $this->getLanguage()->formatNum( $this->activeUsers ),
00180                         array( 'class' => 'mw-statistics-users-active' ),
00181                         'statistics-users-active-desc',
00182                         $this->getLanguage()->formatNum( $wgActiveUserDays ) );
00183     }
00184 
00185     private function getGroupStats() {
00186         global $wgGroupPermissions, $wgImplicitGroups;
00187         $text = '';
00188         foreach ( $wgGroupPermissions as $group => $permissions ) {
00189             # Skip generic * and implicit groups
00190             if ( in_array( $group, $wgImplicitGroups ) || $group == '*' ) {
00191                 continue;
00192             }
00193             $groupname = htmlspecialchars( $group );
00194             $msg = $this->msg( 'group-' . $groupname );
00195             if ( $msg->isBlank() ) {
00196                 $groupnameLocalized = $groupname;
00197             } else {
00198                 $groupnameLocalized = $msg->text();
00199             }
00200             $msg = $this->msg( 'grouppage-' . $groupname )->inContentLanguage();
00201             if ( $msg->isBlank() ) {
00202                 $grouppageLocalized = MWNamespace::getCanonicalName( NS_PROJECT ) . ':' . $groupname;
00203             } else {
00204                 $grouppageLocalized = $msg->text();
00205             }
00206             $linkTarget = Title::newFromText( $grouppageLocalized );
00207             $grouppage = Linker::link(
00208                 $linkTarget,
00209                 htmlspecialchars( $groupnameLocalized )
00210             );
00211             $grouplink = Linker::linkKnown(
00212                 SpecialPage::getTitleFor( 'Listusers' ),
00213                 $this->msg( 'listgrouprights-members' )->escaped(),
00214                 array(),
00215                 array( 'group' => $group )
00216             );
00217             # Add a class when a usergroup contains no members to allow hiding these rows
00218             $classZero = '';
00219             $countUsers = SiteStats::numberingroup( $groupname );
00220             if ( $countUsers == 0 ) {
00221                 $classZero = ' statistics-group-zero';
00222             }
00223             $text .= $this->formatRow( $grouppage . ' ' . $grouplink,
00224                 $this->getLanguage()->formatNum( $countUsers ),
00225                 array( 'class' => 'statistics-group-' . Sanitizer::escapeClass( $group ) . $classZero ) );
00226         }
00227         return $text;
00228     }
00229 
00230     private function getViewsStats() {
00231         return Xml::openElement( 'tr' ) .
00232             Xml::tags( 'th', array( 'colspan' => '2' ), $this->msg( 'statistics-header-views' )->parse() ) .
00233             Xml::closeElement( 'tr' ) .
00234                 $this->formatRow( $this->msg( 'statistics-views-total' )->parse(),
00235                     $this->getLanguage()->formatNum( $this->views ),
00236                         array( 'class' => 'mw-statistics-views-total' ), 'statistics-views-total-desc' ) .
00237                 $this->formatRow( $this->msg( 'statistics-views-peredit' )->parse(),
00238                     $this->getLanguage()->formatNum( sprintf( '%.2f', $this->edits ?
00239                         $this->views / $this->edits : 0 ) ),
00240                         array( 'class' => 'mw-statistics-views-peredit' ) );
00241     }
00242 
00243     private function getMostViewedPages() {
00244         $text = '';
00245         $dbr = wfGetDB( DB_SLAVE );
00246         $res = $dbr->select(
00247                 'page',
00248                 array(
00249                     'page_namespace',
00250                     'page_title',
00251                     'page_counter',
00252                 ),
00253                 array(
00254                     'page_is_redirect' => 0,
00255                     'page_counter > 0',
00256                 ),
00257                 __METHOD__,
00258                 array(
00259                     'ORDER BY' => 'page_counter DESC',
00260                     'LIMIT' => 10,
00261                 )
00262             );
00263             if ( $res->numRows() > 0 ) {
00264                 $text .= Xml::openElement( 'tr' );
00265                 $text .= Xml::tags( 'th', array( 'colspan' => '2' ), $this->msg( 'statistics-mostpopular' )->parse() );
00266                 $text .= Xml::closeElement( 'tr' );
00267                 foreach ( $res as $row ) {
00268                     $title = Title::makeTitleSafe( $row->page_namespace, $row->page_title );
00269                     if ( $title instanceof Title ) {
00270                         $text .= $this->formatRow( Linker::link( $title ),
00271                                 $this->getLanguage()->formatNum( $row->page_counter ) );
00272 
00273                     }
00274                 }
00275                 $res->free();
00276             }
00277         return $text;
00278     }
00279 
00287     private function getOtherStats( array $stats ) {
00288         $return = '';
00289 
00290         foreach ( $stats as $header => $items ) {
00291             // Identify the structure used
00292             if ( is_array( $items ) ) {
00293 
00294                 // Ignore headers that are recursively set as legacy header
00295                 if ( $header !== 'statistics-header-hooks' ) {
00296                     $return .= $this->formatRowHeader( $header );
00297                 }
00298 
00299                 // Collect all items that belong to the same header
00300                 foreach ( $items as $key => $value ) {
00301                     $name = $this->msg( $key )->parse();
00302                     $number = htmlspecialchars( $value );
00303 
00304                     $return .= $this->formatRow( $name, $this->getLanguage()->formatNum( $number ), array( 'class' => 'mw-statistics-hook', 'id' => 'mw-' . $key ) );
00305                 }
00306             } else {
00307                 // Create the legacy header only once
00308                 if ( $return === '' ) {
00309                     $return .= $this->formatRowHeader( 'statistics-header-hooks' );
00310                 }
00311 
00312                 // Recursively remap the legacy structure
00313                 $return .= $this->getOtherStats( array( 'statistics-header-hooks' => array( $header => $items ) ) );
00314             }
00315         }
00316 
00317         return $return;
00318     }
00319 
00326     private function formatRowHeader( $header ) {
00327         return Xml::openElement( 'tr' ) .
00328             Xml::tags( 'th', array( 'colspan' => '2' ), $this->msg( $header )->parse() ) .
00329             Xml::closeElement( 'tr' );
00330     }
00331 
00332     protected function getGroupName() {
00333         return 'wiki';
00334     }
00335 }