MediaWiki  1.23.15
SpecialActiveusers.php
Go to the documentation of this file.
1 <?php
34 
38  protected $opts;
39 
43  protected $hideGroups = array();
44 
48  protected $hideRights = array();
49 
55  function __construct( IContextSource $context = null, $group = null, $par = null ) {
56  global $wgActiveUserDays;
57 
58  parent::__construct( $context );
59 
60  $this->RCMaxAge = $wgActiveUserDays;
61  $un = $this->getRequest()->getText( 'username', $par );
62  $this->requestedUser = '';
63  if ( $un != '' ) {
64  $username = Title::makeTitleSafe( NS_USER, $un );
65  if ( !is_null( $username ) ) {
66  $this->requestedUser = $username->getText();
67  }
68  }
69 
70  $this->setupOptions();
71  }
72 
73  public function setupOptions() {
74  $this->opts = new FormOptions();
75 
76  $this->opts->add( 'hidebots', false, FormOptions::BOOL );
77  $this->opts->add( 'hidesysops', false, FormOptions::BOOL );
78 
79  $this->opts->fetchValuesFromRequest( $this->getRequest() );
80 
81  if ( $this->opts->getValue( 'hidebots' ) == 1 ) {
82  $this->hideRights[] = 'bot';
83  }
84  if ( $this->opts->getValue( 'hidesysops' ) == 1 ) {
85  $this->hideGroups[] = 'sysop';
86  }
87  }
88 
89  function getIndexField() {
90  return 'qcc_title';
91  }
92 
93  function getQueryInfo() {
94  $dbr = $this->getDatabase();
95 
96  $conds = array(
97  'qcc_type' => 'activeusers',
98  'qcc_namespace' => NS_USER,
99  'user_name = qcc_title',
100  'rc_user_text = qcc_title',
101  'rc_type != ' . $dbr->addQuotes( RC_EXTERNAL ) // Don't count wikidata.
102  );
103  if ( $this->requestedUser != '' ) {
104  $conds[] = 'qcc_title >= ' . $dbr->addQuotes( $this->requestedUser );
105  }
106  if ( !$this->getUser()->isAllowed( 'hideuser' ) ) {
107  $conds[] = 'NOT EXISTS (' . $dbr->selectSQLText(
108  'ipblocks', '1', array( 'ipb_user=user_id', 'ipb_deleted' => 1 )
109  ) . ')';
110  }
111 
112  if ( $dbr->implicitGroupby() ) {
113  $options = array( 'GROUP BY' => array( 'qcc_title' ) );
114  } else {
115  $options = array( 'GROUP BY' => array( 'user_name', 'user_id', 'qcc_title' ) );
116  }
117 
118  return array(
119  'tables' => array( 'querycachetwo', 'user', 'recentchanges' ),
120  'fields' => array( 'user_name', 'user_id', 'recentedits' => 'COUNT(*)', 'qcc_title' ),
121  'options' => $options,
122  'conds' => $conds
123  );
124  }
125 
126  function doBatchLookups() {
127  $uids = array();
128  foreach ( $this->mResult as $row ) {
129  $uids[] = $row->user_id;
130  }
131  // Fetch the block status of the user for showing "(blocked)" text and for
132  // striking out names of suppressed users when privileged user views the list.
133  // Although the first query already hits the block table for un-privileged, this
134  // is done in two queries to avoid huge quicksorts and to make COUNT(*) correct.
135  $dbr = $this->getDatabase();
136  $res = $dbr->select( 'ipblocks',
137  array( 'ipb_user', 'MAX(ipb_deleted) AS block_status' ),
138  array( 'ipb_user' => $uids ),
139  __METHOD__,
140  array( 'GROUP BY' => array( 'ipb_user' ) )
141  );
142  $this->blockStatusByUid = array();
143  foreach ( $res as $row ) {
144  $this->blockStatusByUid[$row->ipb_user] = $row->block_status; // 0 or 1
145  }
146  $this->mResult->seek( 0 );
147  }
148 
149  function formatRow( $row ) {
150  $userName = $row->user_name;
151 
152  $ulinks = Linker::userLink( $row->user_id, $userName );
153  $ulinks .= Linker::userToolLinks( $row->user_id, $userName );
154 
155  $lang = $this->getLanguage();
156 
157  $list = array();
158  $user = User::newFromId( $row->user_id );
159 
160  // User right filter
161  foreach ( $this->hideRights as $right ) {
162  // Calling User::getRights() within the loop so that
163  // if the hideRights() filter is empty, we don't have to
164  // trigger the lazy-init of the big userrights array in the
165  // User object
166  if ( in_array( $right, $user->getRights() ) ) {
167  return '';
168  }
169  }
170 
171  // User group filter
172  // Note: This is a different loop than for user rights,
173  // because we're reusing it to build the group links
174  // at the same time
175  foreach ( $user->getGroups() as $group ) {
176  if ( in_array( $group, $this->hideGroups ) ) {
177  return '';
178  }
179  $list[] = self::buildGroupLink( $group, $userName );
180  }
181 
182  $groups = $lang->commaList( $list );
183 
184  $item = $lang->specialList( $ulinks, $groups );
185 
186  $isBlocked = isset( $this->blockStatusByUid[$row->user_id] );
187  if ( $isBlocked && $this->blockStatusByUid[$row->user_id] == 1 ) {
188  $item = "<span class=\"deleted\">$item</span>";
189  }
190  $count = $this->msg( 'activeusers-count' )->numParams( $row->recentedits )
191  ->params( $userName )->numParams( $this->RCMaxAge )->escaped();
192  $blocked = $isBlocked ? ' ' . $this->msg( 'listusers-blocked', $userName )->escaped() : '';
193 
194  return Html::rawElement( 'li', array(), "{$item} [{$count}]{$blocked}" );
195  }
196 
197  function getPageHeader() {
198  global $wgScript;
199 
200  $self = $this->getTitle();
201  $limit = $this->mLimit ? Html::hidden( 'limit', $this->mLimit ) : '';
202 
203  $out = Xml::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript ) ); # Form tag
204  $out .= Xml::fieldset( $this->msg( 'activeusers' )->text() ) . "\n";
205  $out .= Html::hidden( 'title', $self->getPrefixedDBkey() ) . $limit . "\n";
206 
207  $out .= Xml::inputLabel( $this->msg( 'activeusers-from' )->text(),
208  'username', 'offset', 20, $this->requestedUser, array( 'tabindex' => 1 ) ) . '<br />';# Username field
209 
210  $out .= Xml::checkLabel( $this->msg( 'activeusers-hidebots' )->text(),
211  'hidebots', 'hidebots', $this->opts->getValue( 'hidebots' ), array( 'tabindex' => 2 ) );
212 
213  $out .= Xml::checkLabel( $this->msg( 'activeusers-hidesysops' )->text(),
214  'hidesysops', 'hidesysops', $this->opts->getValue( 'hidesysops' ), array( 'tabindex' => 3 ) ) . '<br />';
215 
216  $out .= Xml::submitButton( $this->msg( 'allpagessubmit' )->text(), array( 'tabindex' => 4 ) ) . "\n";# Submit button and form bottom
217  $out .= Xml::closeElement( 'fieldset' );
218  $out .= Xml::closeElement( 'form' );
219 
220  return $out;
221  }
222 }
223 
227 class SpecialActiveUsers extends SpecialPage {
228 
232  public function __construct() {
233  parent::__construct( 'Activeusers' );
234  }
235 
241  public function execute( $par ) {
242  global $wgActiveUserDays;
243 
244  $this->setHeaders();
245  $this->outputHeader();
246 
247  $out = $this->getOutput();
248  $out->wrapWikiMsg( "<div class='mw-activeusers-intro'>\n$1\n</div>",
249  array( 'activeusers-intro', $this->getLanguage()->formatNum( $wgActiveUserDays ) ) );
250 
251  // Occasionally merge in new updates
252  $seconds = min( self::mergeActiveUsers( 600 ), $wgActiveUserDays * 86400 );
253  // Mention the level of staleness
254  $out->addWikiMsg( 'cachedspecial-viewing-cached-ttl',
255  $this->getLanguage()->formatDuration( $seconds ) );
256 
257  $up = new ActiveUsersPager( $this->getContext(), null, $par );
258 
259  # getBody() first to check, if empty
260  $usersbody = $up->getBody();
261 
262  $out->addHTML( $up->getPageHeader() );
263  if ( $usersbody ) {
264  $out->addHTML(
265  $up->getNavigationBar() .
266  Html::rawElement( 'ul', array(), $usersbody ) .
267  $up->getNavigationBar()
268  );
269  } else {
270  $out->addWikiMsg( 'activeusers-noresult' );
271  }
272  }
273 
274  protected function getGroupName() {
275  return 'users';
276  }
277 
282  public static function mergeActiveUsers( $period ) {
283  global $wgActiveUserDays;
284 
285  $dbr = wfGetDB( DB_SLAVE );
286  $cTime = $dbr->selectField( 'querycache_info',
287  'qci_timestamp',
288  array( 'qci_type' => 'activeusers' )
289  );
290  if ( !wfReadOnly() ) {
291  if ( !$cTime || ( time() - wfTimestamp( TS_UNIX, $cTime ) ) > $period ) {
292  $dbw = wfGetDB( DB_MASTER );
293  if ( $dbw->estimateRowCount( 'recentchanges' ) <= 10000 ) {
294  $window = $wgActiveUserDays * 86400; // small wiki
295  } else {
296  $window = $period * 2;
297  }
298  self::doQueryCacheUpdate( $dbw, $window );
299  }
300  }
301 
302  return ( time() -
303  ( $cTime ? wfTimestamp( TS_UNIX, $cTime ) : $wgActiveUserDays * 86400 ) );
304  }
305 
310  public static function cacheUpdate( DatabaseBase $dbw ) {
311  global $wgActiveUserDays;
312 
313  self::doQueryCacheUpdate( $dbw, $wgActiveUserDays * 86400 );
314  }
315 
323  protected static function doQueryCacheUpdate( DatabaseBase $dbw, $window ) {
324  global $wgActiveUserDays;
325 
326  $lockKey = wfWikiID() . '-activeusers';
327  if ( !$dbw->lock( $lockKey, __METHOD__, 1 ) ) {
328  return false; // exclusive update (avoids duplicate entries)
329  }
330 
331  $now = time();
332  $cTime = $dbw->selectField( 'querycache_info',
333  'qci_timestamp',
334  array( 'qci_type' => 'activeusers' )
335  );
336  $cTimeUnix = $cTime ? wfTimestamp( TS_UNIX, $cTime ) : 1;
337 
338  // Pick the date range to fetch from. This is normally from the last
339  // update to till the present time, but has a limited window for sanity.
340  // If the window is limited, multiple runs are need to fully populate it.
341  $sTimestamp = max( $cTimeUnix, $now - $wgActiveUserDays * 86400 );
342  $eTimestamp = min( $sTimestamp + $window, $now );
343 
344  // Get all the users active since the last update
345  $res = $dbw->select(
346  array( 'recentchanges' ),
347  array( 'rc_user_text', 'lastedittime' => 'MAX(rc_timestamp)' ),
348  array(
349  'rc_user > 0', // actual accounts
350  'rc_type != ' . $dbw->addQuotes( RC_EXTERNAL ), // no wikidata
351  'rc_log_type IS NULL OR rc_log_type != ' . $dbw->addQuotes( 'newusers' ),
352  'rc_timestamp >= ' . $dbw->addQuotes( $dbw->timestamp( $sTimestamp ) ),
353  'rc_timestamp <= ' . $dbw->addQuotes( $dbw->timestamp( $eTimestamp ) )
354  ),
355  __METHOD__,
356  array(
357  'GROUP BY' => array( 'rc_user_text' ),
358  'ORDER BY' => 'NULL' // avoid filesort
359  )
360  );
361  $names = array();
362  foreach ( $res as $row ) {
363  $names[$row->rc_user_text] = $row->lastedittime;
364  }
365 
366  // Rotate out users that have not edited in too long (according to old data set)
367  $dbw->delete( 'querycachetwo',
368  array(
369  'qcc_type' => 'activeusers',
370  'qcc_value < ' . $dbw->addQuotes( $now - $wgActiveUserDays * 86400 ) // TS_UNIX
371  ),
372  __METHOD__
373  );
374 
375  // Find which of the recently active users are already accounted for
376  if ( count( $names ) ) {
377  $res = $dbw->select( 'querycachetwo',
378  array( 'user_name' => 'qcc_title' ),
379  array(
380  'qcc_type' => 'activeusers',
381  'qcc_namespace' => NS_USER,
382  'qcc_title' => array_keys( $names ) ),
383  __METHOD__
384  );
385  foreach ( $res as $row ) {
386  unset( $names[$row->user_name] );
387  }
388  }
389 
390  // Insert the users that need to be added to the list (which their last edit time
391  if ( count( $names ) ) {
392  $newRows = array();
393  foreach ( $names as $name => $lastEditTime ) {
394  $newRows[] = array(
395  'qcc_type' => 'activeusers',
396  'qcc_namespace' => NS_USER,
397  'qcc_title' => $name,
398  'qcc_value' => wfTimestamp( TS_UNIX, $lastEditTime ),
399  'qcc_namespacetwo' => 0, // unused
400  'qcc_titletwo' => '' // unused
401  );
402  }
403  foreach ( array_chunk( $newRows, 500 ) as $rowBatch ) {
404  $dbw->insert( 'querycachetwo', $rowBatch, __METHOD__ );
405  wfWaitForSlaves();
406  }
407  }
408 
409  // Touch the data freshness timestamp
410  $dbw->replace( 'querycache_info',
411  array( 'qci_type' ),
412  array( 'qci_type' => 'activeusers',
413  'qci_timestamp' => $dbw->timestamp( $eTimestamp ) ), // not always $now
414  __METHOD__
415  );
416 
417  $dbw->unlock( $lockKey, __METHOD__ );
418 
419  return true;
420  }
421 }
Xml\checkLabel
static checkLabel( $label, $name, $id, $checked=false, $attribs=array())
Convenience function to build an HTML checkbox with a label.
Definition: Xml.php:433
ContextSource\$context
IContextSource $context
Definition: ContextSource.php:33
DatabaseBase\replace
replace( $table, $uniqueIndexes, $rows, $fname=__METHOD__)
REPLACE query wrapper.
Definition: Database.php:2630
User\newFromId
static newFromId( $id)
Static factory method for creation from a given user ID.
Definition: User.php:412
RC_EXTERNAL
const RC_EXTERNAL
Definition: Defines.php:183
DB_MASTER
const DB_MASTER
Definition: Defines.php:56
SpecialActiveUsers\execute
execute( $par)
Show the special page.
Definition: SpecialActiveusers.php:238
UsersPager\buildGroupLink
static buildGroupLink( $group, $username)
Format a link to a group description page.
Definition: SpecialListusers.php:353
php
skin txt MediaWiki includes four core it has been set as the default in MediaWiki since the replacing Monobook it had been been the default skin since before being replaced by Vector largely rewritten in while keeping its appearance Several legacy skins were removed in the as the burden of supporting them became too heavy to bear Those in etc for skin dependent CSS etc for skin dependent JavaScript These can also be customised on a per user by etc This feature has led to a wide variety of user styles becoming that gallery is a good place to ending in php
Definition: skin.txt:62
SpecialActiveUsers\getGroupName
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
Definition: SpecialActiveusers.php:271
SpecialActiveUsers\cacheUpdate
static cacheUpdate(DatabaseBase $dbw)
Definition: SpecialActiveusers.php:307
ContextSource\msg
msg()
Get a Message object with context set Parameters are the same as wfMessage()
Definition: ContextSource.php:175
Linker\userLink
static userLink( $userId, $userName, $altUserName=false)
Make user link (or user contributions for unregistered users)
Definition: Linker.php:1081
SpecialPage\getOutput
getOutput()
Get the OutputPage being used for this instance.
Definition: SpecialPage.php:535
ActiveUsersPager\getQueryInfo
getQueryInfo()
Definition: SpecialActiveusers.php:90
wfGetDB
& wfGetDB( $db, $groups=array(), $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:3714
text
design txt This is a brief overview of the new design More thorough and up to date information is available on the documentation wiki at etc Handles the details of getting and saving to the user table of the and dealing with sessions and cookies OutputPage Encapsulates the entire HTML page that will be sent in response to any server request It is used by calling its functions to add text
Definition: design.txt:12
ActiveUsersPager\setupOptions
setupOptions()
Definition: SpecialActiveusers.php:70
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition: GlobalFunctions.php:2530
IndexPager\getDatabase
getDatabase()
Get the Database object in use.
Definition: Pager.php:191
$right
return false if a UserGetRights hook might remove the named right $right
Definition: hooks.txt:2809
$limit
if( $sleep) $limit
Definition: importImages.php:99
wfReadOnly
wfReadOnly()
Check whether the wiki is in read-only mode.
Definition: GlobalFunctions.php:1360
Html\hidden
static hidden( $name, $value, $attribs=array())
Convenience function to produce an input element with type=hidden.
Definition: Html.php:607
SpecialActiveUsers\__construct
__construct()
Constructor.
Definition: SpecialActiveusers.php:229
ActiveUsersPager\getPageHeader
getPageHeader()
Definition: SpecialActiveusers.php:194
ContextSource\getRequest
getRequest()
Get the WebRequest object.
Definition: ContextSource.php:77
SpecialPage\getLanguage
getLanguage()
Shortcut to get user's language.
Definition: SpecialPage.php:578
ContextSource\getUser
getUser()
Get the User object.
Definition: ContextSource.php:132
ContextSource\getTitle
getTitle()
Get the Title object.
Definition: ContextSource.php:87
DatabaseBase\timestamp
timestamp( $ts=0)
Convert a timestamp in one of the formats accepted by wfTimestamp() to the format used for inserting ...
Definition: Database.php:3607
Xml\openElement
static openElement( $element, $attribs=null)
This opens an XML element.
Definition: Xml.php:109
SpecialActiveUsers\mergeActiveUsers
static mergeActiveUsers( $period)
Definition: SpecialActiveusers.php:279
$dbr
$dbr
Definition: testCompression.php:48
ContextSource\getLanguage
getLanguage()
Get the Language object.
Definition: ContextSource.php:154
ActiveUsersPager
This class is used to get a list of active users.
Definition: SpecialActiveusers.php:33
ActiveUsersPager\__construct
__construct(IContextSource $context=null, $group=null, $par=null)
Definition: SpecialActiveusers.php:52
DatabaseBase\addQuotes
addQuotes( $s)
Adds quotes and backslashes.
Definition: Database.php:2477
DatabaseBase\selectField
selectField( $table, $var, $cond='', $fname=__METHOD__, $options=array())
A SELECT wrapper which returns a single field from a single result row.
Definition: Database.php:1281
DatabaseBase\unlock
unlock( $lockName, $method)
Release a lock.
Definition: Database.php:4019
$out
$out
Definition: UtfNormalGenerate.php:167
DatabaseBase\select
select( $table, $vars, $conds='', $fname=__METHOD__, $options=array(), $join_conds=array())
Execute a SELECT query constructed using the various parameters provided.
Definition: Database.php:1575
ActiveUsersPager\$hideGroups
Array $hideGroups
Definition: SpecialActiveusers.php:41
SpecialActiveUsers\doQueryCacheUpdate
static doQueryCacheUpdate(DatabaseBase $dbw, $window)
Update the query cache as needed.
Definition: SpecialActiveusers.php:320
UsersPager
This class is used to get a list of user.
Definition: SpecialListusers.php:35
array
the array() calling protocol came about after MediaWiki 1.4rc1.
List of Api Query prop modules.
SpecialPage\setHeaders
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
Definition: SpecialPage.php:352
Xml\inputLabel
static inputLabel( $label, $name, $id, $size=false, $value=false, $attribs=array())
Convenience function to build an HTML text input field with a label.
Definition: Xml.php:398
global
when a variable name is used in a it is silently declared as a new masking the global
Definition: design.txt:93
form
null means default in associative array form
Definition: hooks.txt:1530
wfWaitForSlaves
wfWaitForSlaves( $maxLag=false, $wiki=false, $cluster=false)
Modern version of wfWaitForSlaves().
Definition: GlobalFunctions.php:3859
ActiveUsersPager\formatRow
formatRow( $row)
Definition: SpecialActiveusers.php:146
SpecialPage\getContext
getContext()
Gets the context this SpecialPage is executed in.
Definition: SpecialPage.php:508
$options
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped & $options
Definition: hooks.txt:1530
Title\makeTitleSafe
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:422
wfWikiID
wfWikiID()
Get an ASCII string identifying this wiki This is used as a prefix in memcached keys.
Definition: GlobalFunctions.php:3668
ActiveUsersPager\getIndexField
getIndexField()
Definition: SpecialActiveusers.php:86
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:336
Linker\userToolLinks
static userToolLinks( $userId, $userText, $redContribsWhenNoEdits=false, $flags=0, $edits=null)
Generate standard user tool links (talk, contributions, block link, etc.)
Definition: Linker.php:1109
SpecialPage
Parent class for all special pages.
Definition: SpecialPage.php:33
DatabaseBase
Database abstraction object.
Definition: Database.php:219
ActiveUsersPager\$opts
FormOptions $opts
Definition: SpecialActiveusers.php:37
$user
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a account $user
Definition: hooks.txt:237
IContextSource
Interface for objects which can provide a context on request.
Definition: IContextSource.php:29
$count
$count
Definition: UtfNormalTest2.php:96
$self
$self
Definition: doMaintenance.php:54
SpecialActiveUsers
Definition: SpecialActiveusers.php:224
DatabaseBase\lock
lock( $lockName, $method, $timeout=5)
Acquire a named lock.
Definition: Database.php:4005
DB_SLAVE
const DB_SLAVE
Definition: Defines.php:55
Xml\closeElement
static closeElement( $element)
Shortcut to close an XML element.
Definition: Xml.php:118
DatabaseBase\delete
delete( $table, $conds, $fname=__METHOD__)
DELETE query wrapper.
Definition: Database.php:2884
TS_UNIX
const TS_UNIX
Unix time - the number of seconds since 1970-01-01 00:00:00 UTC.
Definition: GlobalFunctions.php:2473
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
NS_USER
const NS_USER
Definition: Defines.php:81
ActiveUsersPager\$hideRights
Array $hideRights
Definition: SpecialActiveusers.php:45
Xml\submitButton
static submitButton( $value, $attribs=array())
Convenience function to build an HTML submit button.
Definition: Xml.php:463
FormOptions
Helper class to keep track of options when mixing links and form elements.
Definition: FormOptions.php:35
Html\rawElement
static rawElement( $element, $attribs=array(), $contents='')
Returns an HTML element in a string.
Definition: Html.php:121
ActiveUsersPager\doBatchLookups
doBatchLookups()
Called from getBody(), before getStartBody() is called and after doQuery() was called.
Definition: SpecialActiveusers.php:123
$res
$res
Definition: database.txt:21
SpecialPage\outputHeader
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages Per default the message key is the canonical name o...
Definition: SpecialPage.php:443
Xml\fieldset
static fieldset( $legend=false, $content=false, $attribs=array())
Shortcut for creating fieldsets.
Definition: Xml.php:563
FormOptions\BOOL
const BOOL
Boolean type, maps guessType() to WebRequest::getBool()
Definition: FormOptions.php:50
DatabaseBase\insert
insert( $table, $a, $fname=__METHOD__, $options=array())
INSERT wrapper, inserts an array into a table.
Definition: Database.php:1860