PageRenderTime 48ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/includes/specials/SpecialStatistics.php

https://github.com/daevid/MWFork
PHP | 295 lines | 212 code | 30 blank | 53 comment | 21 complexity | f84e970908aa0eb222f3c69606cc9de8 MD5 | raw file
  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. * Special page lists various statistics, including the contents of
  25. * `site_stats`, plus page view details if enabled
  26. *
  27. * @ingroup SpecialPage
  28. */
  29. class SpecialStatistics extends SpecialPage {
  30. private $views, $edits, $good, $images, $total, $users,
  31. $activeUsers = 0;
  32. public function __construct() {
  33. parent::__construct( 'Statistics' );
  34. }
  35. public function execute( $par ) {
  36. global $wgMemc, $wgDisableCounters, $wgMiserMode;
  37. $this->setHeaders();
  38. $this->getOutput()->addModuleStyles( 'mediawiki.special' );
  39. $this->views = SiteStats::views();
  40. $this->edits = SiteStats::edits();
  41. $this->good = SiteStats::articles();
  42. $this->images = SiteStats::images();
  43. $this->total = SiteStats::pages();
  44. $this->users = SiteStats::users();
  45. $this->activeUsers = SiteStats::activeUsers();
  46. $this->hook = '';
  47. # Staticic - views
  48. $viewsStats = '';
  49. if( !$wgDisableCounters ) {
  50. $viewsStats = $this->getViewsStats();
  51. }
  52. # Set active user count
  53. if( !$wgMiserMode ) {
  54. $key = wfMemcKey( 'sitestats', 'activeusers-updated' );
  55. // Re-calculate the count if the last tally is old...
  56. if( !$wgMemc->get($key) ) {
  57. $dbw = wfGetDB( DB_MASTER );
  58. SiteStatsUpdate::cacheUpdate( $dbw );
  59. $wgMemc->set( $key, '1', 24*3600 ); // don't update for 1 day
  60. }
  61. }
  62. $text = Xml::openElement( 'table', array( 'class' => 'wikitable mw-statistics-table' ) );
  63. # Statistic - pages
  64. $text .= $this->getPageStats();
  65. # Statistic - edits
  66. $text .= $this->getEditStats();
  67. # Statistic - users
  68. $text .= $this->getUserStats();
  69. # Statistic - usergroups
  70. $text .= $this->getGroupStats();
  71. $text .= $viewsStats;
  72. # Statistic - popular pages
  73. if( !$wgDisableCounters && !$wgMiserMode ) {
  74. $text .= $this->getMostViewedPages();
  75. }
  76. # Statistic - other
  77. $extraStats = array();
  78. if( wfRunHooks( 'SpecialStatsAddExtra', array( &$extraStats ) ) ) {
  79. $text .= $this->getOtherStats( $extraStats );
  80. }
  81. $text .= Xml::closeElement( 'table' );
  82. # Customizable footer
  83. $footer = wfMessage( 'statistics-footer' );
  84. if ( !$footer->isBlank() ) {
  85. $text .= "\n" . $footer->parse();
  86. }
  87. $this->getOutput()->addHTML( $text );
  88. }
  89. /**
  90. * Format a row
  91. * @param $text String: description of the row
  92. * @param $number Float: a statistical number
  93. * @param $trExtraParams Array: params to table row, see Html::elememt
  94. * @param $descMsg String: message key
  95. * @param $descMsgParam Array: message params
  96. * @return string table row in HTML format
  97. */
  98. private function formatRow( $text, $number, $trExtraParams = array(), $descMsg = '', $descMsgParam = '' ) {
  99. if( $descMsg ) {
  100. $msg = wfMessage( $descMsg, $descMsgParam );
  101. if ( $msg->exists() ) {
  102. $descriptionText = $msg->parse();
  103. $text .= "<br />" . Xml::element( 'small', array( 'class' => 'mw-statistic-desc'),
  104. " ($descriptionText)" );
  105. }
  106. }
  107. return Html::rawElement( 'tr', $trExtraParams,
  108. Html::rawElement( 'td', array(), $text ) .
  109. Html::rawElement( 'td', array( 'class' => 'mw-statistics-numbers' ), $number )
  110. );
  111. }
  112. /**
  113. * Each of these methods is pretty self-explanatory, get a particular
  114. * row for the table of statistics
  115. * @return string
  116. */
  117. private function getPageStats() {
  118. return Xml::openElement( 'tr' ) .
  119. Xml::tags( 'th', array( 'colspan' => '2' ), wfMsgExt( 'statistics-header-pages', array( 'parseinline' ) ) ) .
  120. Xml::closeElement( 'tr' ) .
  121. $this->formatRow( wfMsgExt( 'statistics-articles', array( 'parseinline' ) ),
  122. $this->getLang()->formatNum( $this->good ),
  123. array( 'class' => 'mw-statistics-articles' ) ) .
  124. $this->formatRow( wfMsgExt( 'statistics-pages', array( 'parseinline' ) ),
  125. $this->getLang()->formatNum( $this->total ),
  126. array( 'class' => 'mw-statistics-pages' ),
  127. 'statistics-pages-desc' ) .
  128. $this->formatRow( wfMsgExt( 'statistics-files', array( 'parseinline' ) ),
  129. $this->getLang()->formatNum( $this->images ),
  130. array( 'class' => 'mw-statistics-files' ) );
  131. }
  132. private function getEditStats() {
  133. return Xml::openElement( 'tr' ) .
  134. Xml::tags( 'th', array( 'colspan' => '2' ), wfMsgExt( 'statistics-header-edits', array( 'parseinline' ) ) ) .
  135. Xml::closeElement( 'tr' ) .
  136. $this->formatRow( wfMsgExt( 'statistics-edits', array( 'parseinline' ) ),
  137. $this->getLang()->formatNum( $this->edits ),
  138. array( 'class' => 'mw-statistics-edits' ) ) .
  139. $this->formatRow( wfMsgExt( 'statistics-edits-average', array( 'parseinline' ) ),
  140. $this->getLang()->formatNum( sprintf( '%.2f', $this->total ? $this->edits / $this->total : 0 ) ),
  141. array( 'class' => 'mw-statistics-edits-average' ) );
  142. }
  143. private function getUserStats() {
  144. global $wgActiveUserDays;
  145. return Xml::openElement( 'tr' ) .
  146. Xml::tags( 'th', array( 'colspan' => '2' ), wfMsgExt( 'statistics-header-users', array( 'parseinline' ) ) ) .
  147. Xml::closeElement( 'tr' ) .
  148. $this->formatRow( wfMsgExt( 'statistics-users', array( 'parseinline' ) ),
  149. $this->getLang()->formatNum( $this->users ),
  150. array( 'class' => 'mw-statistics-users' ) ) .
  151. $this->formatRow( wfMsgExt( 'statistics-users-active', array( 'parseinline' ) ) . ' ' .
  152. Linker::linkKnown(
  153. SpecialPage::getTitleFor( 'Activeusers' ),
  154. wfMsgHtml( 'listgrouprights-members' )
  155. ),
  156. $this->getLang()->formatNum( $this->activeUsers ),
  157. array( 'class' => 'mw-statistics-users-active' ),
  158. 'statistics-users-active-desc',
  159. $this->getLang()->formatNum( $wgActiveUserDays ) );
  160. }
  161. private function getGroupStats() {
  162. global $wgGroupPermissions, $wgImplicitGroups;
  163. $text = '';
  164. foreach( $wgGroupPermissions as $group => $permissions ) {
  165. # Skip generic * and implicit groups
  166. if ( in_array( $group, $wgImplicitGroups ) || $group == '*' ) {
  167. continue;
  168. }
  169. $groupname = htmlspecialchars( $group );
  170. $msg = wfMessage( 'group-' . $groupname );
  171. if ( $msg->isBlank() ) {
  172. $groupnameLocalized = $groupname;
  173. } else {
  174. $groupnameLocalized = $msg->text();
  175. }
  176. $msg = wfMessage( 'grouppage-' . $groupname )->inContentLanguage();
  177. if ( $msg->isBlank() ) {
  178. $grouppageLocalized = MWNamespace::getCanonicalName( NS_PROJECT ) . ':' . $groupname;
  179. } else {
  180. $grouppageLocalized = $msg->text();
  181. }
  182. $linkTarget = Title::newFromText( $grouppageLocalized );
  183. $grouppage = Linker::link(
  184. $linkTarget,
  185. htmlspecialchars( $groupnameLocalized )
  186. );
  187. $grouplink = Linker::linkKnown(
  188. SpecialPage::getTitleFor( 'Listusers' ),
  189. wfMsgHtml( 'listgrouprights-members' ),
  190. array(),
  191. array( 'group' => $group )
  192. );
  193. # Add a class when a usergroup contains no members to allow hiding these rows
  194. $classZero = '';
  195. $countUsers = SiteStats::numberingroup( $groupname );
  196. if( $countUsers == 0 ) {
  197. $classZero = ' statistics-group-zero';
  198. }
  199. $text .= $this->formatRow( $grouppage . ' ' . $grouplink,
  200. $this->getLang()->formatNum( $countUsers ),
  201. array( 'class' => 'statistics-group-' . Sanitizer::escapeClass( $group ) . $classZero ) );
  202. }
  203. return $text;
  204. }
  205. private function getViewsStats() {
  206. return Xml::openElement( 'tr' ) .
  207. Xml::tags( 'th', array( 'colspan' => '2' ), wfMsgExt( 'statistics-header-views', array( 'parseinline' ) ) ) .
  208. Xml::closeElement( 'tr' ) .
  209. $this->formatRow( wfMsgExt( 'statistics-views-total', array( 'parseinline' ) ),
  210. $this->getLang()->formatNum( $this->views ),
  211. array ( 'class' => 'mw-statistics-views-total' ), 'statistics-views-total-desc' ) .
  212. $this->formatRow( wfMsgExt( 'statistics-views-peredit', array( 'parseinline' ) ),
  213. $this->getLang()->formatNum( sprintf( '%.2f', $this->edits ?
  214. $this->views / $this->edits : 0 ) ),
  215. array ( 'class' => 'mw-statistics-views-peredit' ) );
  216. }
  217. private function getMostViewedPages() {
  218. $text = '';
  219. $dbr = wfGetDB( DB_SLAVE );
  220. $res = $dbr->select(
  221. 'page',
  222. array(
  223. 'page_namespace',
  224. 'page_title',
  225. 'page_counter',
  226. ),
  227. array(
  228. 'page_is_redirect' => 0,
  229. 'page_counter > 0',
  230. ),
  231. __METHOD__,
  232. array(
  233. 'ORDER BY' => 'page_counter DESC',
  234. 'LIMIT' => 10,
  235. )
  236. );
  237. if( $res->numRows() > 0 ) {
  238. $text .= Xml::openElement( 'tr' );
  239. $text .= Xml::tags( 'th', array( 'colspan' => '2' ), wfMsgExt( 'statistics-mostpopular', array( 'parseinline' ) ) );
  240. $text .= Xml::closeElement( 'tr' );
  241. foreach ( $res as $row ) {
  242. $title = Title::makeTitleSafe( $row->page_namespace, $row->page_title );
  243. if( $title instanceof Title ) {
  244. $text .= $this->formatRow( Linker::link( $title ),
  245. $this->getLang()->formatNum( $row->page_counter ) );
  246. }
  247. }
  248. $res->free();
  249. }
  250. return $text;
  251. }
  252. private function getOtherStats( $stats ) {
  253. if ( !count( $stats ) )
  254. return '';
  255. $return = Xml::openElement( 'tr' ) .
  256. Xml::tags( 'th', array( 'colspan' => '2' ), wfMsgExt( 'statistics-header-hooks', array( 'parseinline' ) ) ) .
  257. Xml::closeElement( 'tr' );
  258. foreach( $stats as $name => $number ) {
  259. $name = htmlspecialchars( $name );
  260. $number = htmlspecialchars( $number );
  261. $return .= $this->formatRow( $name, $this->getLang()->formatNum( $number ), array( 'class' => 'mw-statistics-hook' ) );
  262. }
  263. return $return;
  264. }
  265. }