[ Index ] |
PHP Cross Reference of MediaWiki-1.24.0 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Implements Special:Statistics 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 * http://www.gnu.org/copyleft/gpl.html 19 * 20 * @file 21 * @ingroup SpecialPage 22 */ 23 24 /** 25 * Special page lists various statistics, including the contents of 26 * `site_stats`, plus page view details if enabled 27 * 28 * @ingroup SpecialPage 29 */ 30 class SpecialStatistics extends SpecialPage { 31 private $views, $edits, $good, $images, $total, $users, 32 $activeUsers = 0; 33 34 public function __construct() { 35 parent::__construct( 'Statistics' ); 36 } 37 38 public function execute( $par ) { 39 global $wgMemc; 40 41 $disableCounters = $this->getConfig()->get( 'DisableCounters' ); 42 $miserMode = $this->getConfig()->get( 'MiserMode' ); 43 44 $this->setHeaders(); 45 $this->getOutput()->addModuleStyles( 'mediawiki.special' ); 46 47 $this->views = SiteStats::views(); 48 $this->edits = SiteStats::edits(); 49 $this->good = SiteStats::articles(); 50 $this->images = SiteStats::images(); 51 $this->total = SiteStats::pages(); 52 $this->users = SiteStats::users(); 53 $this->activeUsers = SiteStats::activeUsers(); 54 $this->hook = ''; 55 56 # Staticic - views 57 $viewsStats = ''; 58 if ( !$disableCounters ) { 59 $viewsStats = $this->getViewsStats(); 60 } 61 62 # Set active user count 63 if ( !$miserMode ) { 64 $key = wfMemcKey( 'sitestats', 'activeusers-updated' ); 65 // Re-calculate the count if the last tally is old... 66 if ( !$wgMemc->get( $key ) ) { 67 $dbw = wfGetDB( DB_MASTER ); 68 SiteStatsUpdate::cacheUpdate( $dbw ); 69 $wgMemc->set( $key, '1', 24 * 3600 ); // don't update for 1 day 70 } 71 } 72 73 $text = Xml::openElement( 'table', array( 'class' => 'wikitable mw-statistics-table' ) ); 74 75 # Statistic - pages 76 $text .= $this->getPageStats(); 77 78 # Statistic - edits 79 $text .= $this->getEditStats(); 80 81 # Statistic - users 82 $text .= $this->getUserStats(); 83 84 # Statistic - usergroups 85 $text .= $this->getGroupStats(); 86 $text .= $viewsStats; 87 88 # Statistic - popular pages 89 if ( !$disableCounters && !$miserMode ) { 90 $text .= $this->getMostViewedPages(); 91 } 92 93 # Statistic - other 94 $extraStats = array(); 95 if ( wfRunHooks( 'SpecialStatsAddExtra', array( &$extraStats ) ) ) { 96 $text .= $this->getOtherStats( $extraStats ); 97 } 98 99 $text .= Xml::closeElement( 'table' ); 100 101 # Customizable footer 102 $footer = $this->msg( 'statistics-footer' ); 103 if ( !$footer->isBlank() ) { 104 $text .= "\n" . $footer->parse(); 105 } 106 107 $this->getOutput()->addHTML( $text ); 108 } 109 110 /** 111 * Format a row 112 * @param string $text Description of the row 113 * @param float $number A statistical number 114 * @param array $trExtraParams Params to table row, see Html::elememt 115 * @param string $descMsg Message key 116 * @param array|string $descMsgParam Message parameters 117 * @return string Table row in HTML format 118 */ 119 private function formatRow( $text, $number, $trExtraParams = array(), 120 $descMsg = '', $descMsgParam = '' 121 ) { 122 if ( $descMsg ) { 123 $msg = $this->msg( $descMsg, $descMsgParam ); 124 if ( $msg->exists() ) { 125 $descriptionText = $this->msg( 'parentheses' )->rawParams( $msg->parse() )->escaped(); 126 $text .= "<br />" . Xml::element( 'small', array( 'class' => 'mw-statistic-desc' ), 127 " $descriptionText" ); 128 } 129 } 130 131 return Html::rawElement( 'tr', $trExtraParams, 132 Html::rawElement( 'td', array(), $text ) . 133 Html::rawElement( 'td', array( 'class' => 'mw-statistics-numbers' ), $number ) 134 ); 135 } 136 137 /** 138 * Each of these methods is pretty self-explanatory, get a particular 139 * row for the table of statistics 140 * @return string 141 */ 142 private function getPageStats() { 143 return Xml::openElement( 'tr' ) . 144 Xml::tags( 'th', array( 'colspan' => '2' ), $this->msg( 'statistics-header-pages' )->parse() ) . 145 Xml::closeElement( 'tr' ) . 146 $this->formatRow( Linker::linkKnown( SpecialPage::getTitleFor( 'Allpages' ), 147 $this->msg( 'statistics-articles' )->parse() ), 148 $this->getLanguage()->formatNum( $this->good ), 149 array( 'class' => 'mw-statistics-articles' ) ) . 150 $this->formatRow( $this->msg( 'statistics-pages' )->parse(), 151 $this->getLanguage()->formatNum( $this->total ), 152 array( 'class' => 'mw-statistics-pages' ), 153 'statistics-pages-desc' ) . 154 $this->formatRow( Linker::linkKnown( SpecialPage::getTitleFor( 'MediaStatistics' ), 155 $this->msg( 'statistics-files' )->parse() ), 156 $this->getLanguage()->formatNum( $this->images ), 157 array( 'class' => 'mw-statistics-files' ) ); 158 } 159 160 private function getEditStats() { 161 return Xml::openElement( 'tr' ) . 162 Xml::tags( 'th', array( 'colspan' => '2' ), $this->msg( 'statistics-header-edits' )->parse() ) . 163 Xml::closeElement( 'tr' ) . 164 $this->formatRow( $this->msg( 'statistics-edits' )->parse(), 165 $this->getLanguage()->formatNum( $this->edits ), 166 array( 'class' => 'mw-statistics-edits' ) 167 ) . 168 $this->formatRow( $this->msg( 'statistics-edits-average' )->parse(), 169 $this->getLanguage() 170 ->formatNum( sprintf( '%.2f', $this->total ? $this->edits / $this->total : 0 ) ), 171 array( 'class' => 'mw-statistics-edits-average' ) 172 ); 173 } 174 175 private function getUserStats() { 176 return Xml::openElement( 'tr' ) . 177 Xml::tags( 'th', array( 'colspan' => '2' ), $this->msg( 'statistics-header-users' )->parse() ) . 178 Xml::closeElement( 'tr' ) . 179 $this->formatRow( $this->msg( 'statistics-users' )->parse(), 180 $this->getLanguage()->formatNum( $this->users ), 181 array( 'class' => 'mw-statistics-users' ) 182 ) . 183 $this->formatRow( $this->msg( 'statistics-users-active' )->parse() . ' ' . 184 Linker::linkKnown( 185 SpecialPage::getTitleFor( 'Activeusers' ), 186 $this->msg( 'listgrouprights-members' )->escaped() 187 ), 188 $this->getLanguage()->formatNum( $this->activeUsers ), 189 array( 'class' => 'mw-statistics-users-active' ), 190 'statistics-users-active-desc', 191 $this->getLanguage()->formatNum( $this->getConfig()->get( 'ActiveUserDays' ) ) 192 ); 193 } 194 195 private function getGroupStats() { 196 $text = ''; 197 foreach ( $this->getConfig()->get( 'GroupPermissions' ) as $group => $permissions ) { 198 # Skip generic * and implicit groups 199 if ( in_array( $group, $this->getConfig()->get( 'ImplicitGroups' ) ) || $group == '*' ) { 200 continue; 201 } 202 $groupname = htmlspecialchars( $group ); 203 $msg = $this->msg( 'group-' . $groupname ); 204 if ( $msg->isBlank() ) { 205 $groupnameLocalized = $groupname; 206 } else { 207 $groupnameLocalized = $msg->text(); 208 } 209 $msg = $this->msg( 'grouppage-' . $groupname )->inContentLanguage(); 210 if ( $msg->isBlank() ) { 211 $grouppageLocalized = MWNamespace::getCanonicalName( NS_PROJECT ) . ':' . $groupname; 212 } else { 213 $grouppageLocalized = $msg->text(); 214 } 215 $linkTarget = Title::newFromText( $grouppageLocalized ); 216 $grouppage = Linker::link( 217 $linkTarget, 218 htmlspecialchars( $groupnameLocalized ) 219 ); 220 $grouplink = Linker::linkKnown( 221 SpecialPage::getTitleFor( 'Listusers' ), 222 $this->msg( 'listgrouprights-members' )->escaped(), 223 array(), 224 array( 'group' => $group ) 225 ); 226 # Add a class when a usergroup contains no members to allow hiding these rows 227 $classZero = ''; 228 $countUsers = SiteStats::numberingroup( $groupname ); 229 if ( $countUsers == 0 ) { 230 $classZero = ' statistics-group-zero'; 231 } 232 $text .= $this->formatRow( $grouppage . ' ' . $grouplink, 233 $this->getLanguage()->formatNum( $countUsers ), 234 array( 'class' => 'statistics-group-' . Sanitizer::escapeClass( $group ) . $classZero ) ); 235 } 236 237 return $text; 238 } 239 240 private function getViewsStats() { 241 return Xml::openElement( 'tr' ) . 242 Xml::tags( 'th', array( 'colspan' => '2' ), $this->msg( 'statistics-header-views' )->parse() ) . 243 Xml::closeElement( 'tr' ) . 244 $this->formatRow( $this->msg( 'statistics-views-total' )->parse(), 245 $this->getLanguage()->formatNum( $this->views ), 246 array( 'class' => 'mw-statistics-views-total' ), 'statistics-views-total-desc' ) . 247 $this->formatRow( $this->msg( 'statistics-views-peredit' )->parse(), 248 $this->getLanguage()->formatNum( sprintf( '%.2f', $this->edits ? 249 $this->views / $this->edits : 0 ) ), 250 array( 'class' => 'mw-statistics-views-peredit' ) ); 251 } 252 253 private function getMostViewedPages() { 254 $text = ''; 255 $dbr = wfGetDB( DB_SLAVE ); 256 $res = $dbr->select( 257 'page', 258 array( 259 'page_namespace', 260 'page_title', 261 'page_counter', 262 ), 263 array( 264 'page_is_redirect' => 0, 265 'page_counter > 0', 266 ), 267 __METHOD__, 268 array( 269 'ORDER BY' => 'page_counter DESC', 270 'LIMIT' => 10, 271 ) 272 ); 273 274 if ( $res->numRows() > 0 ) { 275 $text .= Xml::openElement( 'tr' ); 276 $text .= Xml::tags( 277 'th', 278 array( 'colspan' => '2' ), 279 $this->msg( 'statistics-mostpopular' )->parse() 280 ); 281 $text .= Xml::closeElement( 'tr' ); 282 283 foreach ( $res as $row ) { 284 $title = Title::makeTitleSafe( $row->page_namespace, $row->page_title ); 285 286 if ( $title instanceof Title ) { 287 $text .= $this->formatRow( Linker::link( $title ), 288 $this->getLanguage()->formatNum( $row->page_counter ) ); 289 } 290 } 291 $res->free(); 292 } 293 294 return $text; 295 } 296 297 /** 298 * Conversion of external statistics into an internal representation 299 * Following a ([<header-message>][<item-message>] = number) pattern 300 * 301 * @param array $stats 302 * @return string 303 */ 304 private function getOtherStats( array $stats ) { 305 $return = ''; 306 307 foreach ( $stats as $header => $items ) { 308 // Identify the structure used 309 if ( is_array( $items ) ) { 310 311 // Ignore headers that are recursively set as legacy header 312 if ( $header !== 'statistics-header-hooks' ) { 313 $return .= $this->formatRowHeader( $header ); 314 } 315 316 // Collect all items that belong to the same header 317 foreach ( $items as $key => $value ) { 318 $name = $this->msg( $key )->parse(); 319 $number = htmlspecialchars( $value ); 320 321 $return .= $this->formatRow( 322 $name, 323 $this->getLanguage()->formatNum( $number ), 324 array( 'class' => 'mw-statistics-hook', 'id' => 'mw-' . $key ) 325 ); 326 } 327 } else { 328 // Create the legacy header only once 329 if ( $return === '' ) { 330 $return .= $this->formatRowHeader( 'statistics-header-hooks' ); 331 } 332 333 // Recursively remap the legacy structure 334 $return .= $this->getOtherStats( array( 'statistics-header-hooks' => 335 array( $header => $items ) ) ); 336 } 337 } 338 339 return $return; 340 } 341 342 /** 343 * Format row header 344 * 345 * @param string $header 346 * @return string 347 */ 348 private function formatRowHeader( $header ) { 349 return Xml::openElement( 'tr' ) . 350 Xml::tags( 'th', array( 'colspan' => '2' ), $this->msg( $header )->parse() ) . 351 Xml::closeElement( 'tr' ); 352 } 353 354 protected function getGroupName() { 355 return 'wiki'; 356 } 357 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 14:03:12 2014 | Cross-referenced by PHPXref 0.7.1 |