MediaWiki  1.29.2
Block.php
Go to the documentation of this file.
1 <?php
26 
27 class Block {
29  public $mReason;
30 
32  public $mTimestamp;
33 
35  public $mAuto;
36 
38  public $mExpiry;
39 
41  public $mHideName;
42 
45 
47  protected $mId;
48 
50  protected $mFromMaster;
51 
53  protected $mBlockEmail;
54 
56  protected $mDisableUsertalk;
57 
59  protected $mCreateAccount;
60 
62  protected $target;
63 
65  protected $forcedTargetID;
66 
68  protected $type;
69 
71  protected $blocker;
72 
74  protected $isHardblock;
75 
77  protected $isAutoblocking;
78 
80  protected $systemBlockType;
81 
82  # TYPE constants
83  const TYPE_USER = 1;
84  const TYPE_IP = 2;
85  const TYPE_RANGE = 3;
86  const TYPE_AUTO = 4;
87  const TYPE_ID = 5;
88 
115  function __construct( $options = [] ) {
116  $defaults = [
117  'address' => '',
118  'user' => null,
119  'by' => null,
120  'reason' => '',
121  'timestamp' => '',
122  'auto' => false,
123  'expiry' => '',
124  'anonOnly' => false,
125  'createAccount' => false,
126  'enableAutoblock' => false,
127  'hideName' => false,
128  'blockEmail' => false,
129  'allowUsertalk' => false,
130  'byText' => '',
131  'systemBlock' => null,
132  ];
133 
134  if ( func_num_args() > 1 || !is_array( $options ) ) {
135  $options = array_combine(
136  array_slice( array_keys( $defaults ), 0, func_num_args() ),
137  func_get_args()
138  );
139  wfDeprecated( __METHOD__ . ' with multiple arguments', '1.26' );
140  }
141 
142  $options += $defaults;
143 
144  $this->setTarget( $options['address'] );
145 
146  if ( $this->target instanceof User && $options['user'] ) {
147  # Needed for foreign users
148  $this->forcedTargetID = $options['user'];
149  }
150 
151  if ( $options['by'] ) {
152  # Local user
153  $this->setBlocker( User::newFromId( $options['by'] ) );
154  } else {
155  # Foreign user
156  $this->setBlocker( $options['byText'] );
157  }
158 
159  $this->mReason = $options['reason'];
160  $this->mTimestamp = wfTimestamp( TS_MW, $options['timestamp'] );
161  $this->mExpiry = wfGetDB( DB_REPLICA )->decodeExpiry( $options['expiry'] );
162 
163  # Boolean settings
164  $this->mAuto = (bool)$options['auto'];
165  $this->mHideName = (bool)$options['hideName'];
166  $this->isHardblock( !$options['anonOnly'] );
167  $this->isAutoblocking( (bool)$options['enableAutoblock'] );
168 
169  # Prevention measures
170  $this->prevents( 'sendemail', (bool)$options['blockEmail'] );
171  $this->prevents( 'editownusertalk', !$options['allowUsertalk'] );
172  $this->prevents( 'createaccount', (bool)$options['createAccount'] );
173 
174  $this->mFromMaster = false;
175  $this->systemBlockType = $options['systemBlock'];
176  }
177 
184  public static function newFromID( $id ) {
185  $dbr = wfGetDB( DB_REPLICA );
186  $res = $dbr->selectRow(
187  'ipblocks',
188  self::selectFields(),
189  [ 'ipb_id' => $id ],
190  __METHOD__
191  );
192  if ( $res ) {
193  return self::newFromRow( $res );
194  } else {
195  return null;
196  }
197  }
198 
204  public static function selectFields() {
205  return [
206  'ipb_id',
207  'ipb_address',
208  'ipb_by',
209  'ipb_by_text',
210  'ipb_reason',
211  'ipb_timestamp',
212  'ipb_auto',
213  'ipb_anon_only',
214  'ipb_create_account',
215  'ipb_enable_autoblock',
216  'ipb_expiry',
217  'ipb_deleted',
218  'ipb_block_email',
219  'ipb_allow_usertalk',
220  'ipb_parent_block_id',
221  ];
222  }
223 
232  public function equals( Block $block ) {
233  return (
234  (string)$this->target == (string)$block->target
235  && $this->type == $block->type
236  && $this->mAuto == $block->mAuto
237  && $this->isHardblock() == $block->isHardblock()
238  && $this->prevents( 'createaccount' ) == $block->prevents( 'createaccount' )
239  && $this->mExpiry == $block->mExpiry
240  && $this->isAutoblocking() == $block->isAutoblocking()
241  && $this->mHideName == $block->mHideName
242  && $this->prevents( 'sendemail' ) == $block->prevents( 'sendemail' )
243  && $this->prevents( 'editownusertalk' ) == $block->prevents( 'editownusertalk' )
244  && $this->mReason == $block->mReason
245  );
246  }
247 
258  protected function newLoad( $vagueTarget = null ) {
259  $db = wfGetDB( $this->mFromMaster ? DB_MASTER : DB_REPLICA );
260 
261  if ( $this->type !== null ) {
262  $conds = [
263  'ipb_address' => [ (string)$this->target ],
264  ];
265  } else {
266  $conds = [ 'ipb_address' => [] ];
267  }
268 
269  # Be aware that the != '' check is explicit, since empty values will be
270  # passed by some callers (T31116)
271  if ( $vagueTarget != '' ) {
272  list( $target, $type ) = self::parseTarget( $vagueTarget );
273  switch ( $type ) {
274  case self::TYPE_USER:
275  # Slightly weird, but who are we to argue?
276  $conds['ipb_address'][] = (string)$target;
277  break;
278 
279  case self::TYPE_IP:
280  $conds['ipb_address'][] = (string)$target;
281  $conds[] = self::getRangeCond( IP::toHex( $target ) );
282  $conds = $db->makeList( $conds, LIST_OR );
283  break;
284 
285  case self::TYPE_RANGE:
286  list( $start, $end ) = IP::parseRange( $target );
287  $conds['ipb_address'][] = (string)$target;
288  $conds[] = self::getRangeCond( $start, $end );
289  $conds = $db->makeList( $conds, LIST_OR );
290  break;
291 
292  default:
293  throw new MWException( "Tried to load block with invalid type" );
294  }
295  }
296 
297  $res = $db->select( 'ipblocks', self::selectFields(), $conds, __METHOD__ );
298 
299  # This result could contain a block on the user, a block on the IP, and a russian-doll
300  # set of rangeblocks. We want to choose the most specific one, so keep a leader board.
301  $bestRow = null;
302 
303  # Lower will be better
304  $bestBlockScore = 100;
305 
306  # This is begging for $this = $bestBlock, but that's not allowed in PHP :(
307  $bestBlockPreventsEdit = null;
308 
309  foreach ( $res as $row ) {
310  $block = self::newFromRow( $row );
311 
312  # Don't use expired blocks
313  if ( $block->isExpired() ) {
314  continue;
315  }
316 
317  # Don't use anon only blocks on users
318  if ( $this->type == self::TYPE_USER && !$block->isHardblock() ) {
319  continue;
320  }
321 
322  if ( $block->getType() == self::TYPE_RANGE ) {
323  # This is the number of bits that are allowed to vary in the block, give
324  # or take some floating point errors
325  $end = Wikimedia\base_convert( $block->getRangeEnd(), 16, 10 );
326  $start = Wikimedia\base_convert( $block->getRangeStart(), 16, 10 );
327  $size = log( $end - $start + 1, 2 );
328 
329  # This has the nice property that a /32 block is ranked equally with a
330  # single-IP block, which is exactly what it is...
331  $score = self::TYPE_RANGE - 1 + ( $size / 128 );
332 
333  } else {
334  $score = $block->getType();
335  }
336 
337  if ( $score < $bestBlockScore ) {
338  $bestBlockScore = $score;
339  $bestRow = $row;
340  $bestBlockPreventsEdit = $block->prevents( 'edit' );
341  }
342  }
343 
344  if ( $bestRow !== null ) {
345  $this->initFromRow( $bestRow );
346  $this->prevents( 'edit', $bestBlockPreventsEdit );
347  return true;
348  } else {
349  return false;
350  }
351  }
352 
359  public static function getRangeCond( $start, $end = null ) {
360  if ( $end === null ) {
361  $end = $start;
362  }
363  # Per T16634, we want to include relevant active rangeblocks; for
364  # rangeblocks, we want to include larger ranges which enclose the given
365  # range. We know that all blocks must be smaller than $wgBlockCIDRLimit,
366  # so we can improve performance by filtering on a LIKE clause
367  $chunk = self::getIpFragment( $start );
368  $dbr = wfGetDB( DB_REPLICA );
369  $like = $dbr->buildLike( $chunk, $dbr->anyString() );
370 
371  # Fairly hard to make a malicious SQL statement out of hex characters,
372  # but stranger things have happened...
373  $safeStart = $dbr->addQuotes( $start );
374  $safeEnd = $dbr->addQuotes( $end );
375 
376  return $dbr->makeList(
377  [
378  "ipb_range_start $like",
379  "ipb_range_start <= $safeStart",
380  "ipb_range_end >= $safeEnd",
381  ],
382  LIST_AND
383  );
384  }
385 
392  protected static function getIpFragment( $hex ) {
393  global $wgBlockCIDRLimit;
394  if ( substr( $hex, 0, 3 ) == 'v6-' ) {
395  return 'v6-' . substr( substr( $hex, 3 ), 0, floor( $wgBlockCIDRLimit['IPv6'] / 4 ) );
396  } else {
397  return substr( $hex, 0, floor( $wgBlockCIDRLimit['IPv4'] / 4 ) );
398  }
399  }
400 
406  protected function initFromRow( $row ) {
407  $this->setTarget( $row->ipb_address );
408  if ( $row->ipb_by ) { // local user
409  $this->setBlocker( User::newFromId( $row->ipb_by ) );
410  } else { // foreign user
411  $this->setBlocker( $row->ipb_by_text );
412  }
413 
414  $this->mReason = $row->ipb_reason;
415  $this->mTimestamp = wfTimestamp( TS_MW, $row->ipb_timestamp );
416  $this->mAuto = $row->ipb_auto;
417  $this->mHideName = $row->ipb_deleted;
418  $this->mId = (int)$row->ipb_id;
419  $this->mParentBlockId = $row->ipb_parent_block_id;
420 
421  // I wish I didn't have to do this
422  $this->mExpiry = wfGetDB( DB_REPLICA )->decodeExpiry( $row->ipb_expiry );
423 
424  $this->isHardblock( !$row->ipb_anon_only );
425  $this->isAutoblocking( $row->ipb_enable_autoblock );
426 
427  $this->prevents( 'createaccount', $row->ipb_create_account );
428  $this->prevents( 'sendemail', $row->ipb_block_email );
429  $this->prevents( 'editownusertalk', !$row->ipb_allow_usertalk );
430  }
431 
437  public static function newFromRow( $row ) {
438  $block = new Block;
439  $block->initFromRow( $row );
440  return $block;
441  }
442 
449  public function delete() {
450  if ( wfReadOnly() ) {
451  return false;
452  }
453 
454  if ( !$this->getId() ) {
455  throw new MWException( "Block::delete() requires that the mId member be filled\n" );
456  }
457 
458  $dbw = wfGetDB( DB_MASTER );
459  $dbw->delete( 'ipblocks', [ 'ipb_parent_block_id' => $this->getId() ], __METHOD__ );
460  $dbw->delete( 'ipblocks', [ 'ipb_id' => $this->getId() ], __METHOD__ );
461 
462  return $dbw->affectedRows() > 0;
463  }
464 
473  public function insert( $dbw = null ) {
474  global $wgBlockDisablesLogin;
475 
476  if ( $this->getSystemBlockType() !== null ) {
477  throw new MWException( 'Cannot insert a system block into the database' );
478  }
479 
480  wfDebug( "Block::insert; timestamp {$this->mTimestamp}\n" );
481 
482  if ( $dbw === null ) {
483  $dbw = wfGetDB( DB_MASTER );
484  }
485 
486  # Periodic purge via commit hooks
487  if ( mt_rand( 0, 9 ) == 0 ) {
489  }
490 
491  $row = $this->getDatabaseArray();
492  $row['ipb_id'] = $dbw->nextSequenceValue( "ipblocks_ipb_id_seq" );
493 
494  $dbw->insert( 'ipblocks', $row, __METHOD__, [ 'IGNORE' ] );
495  $affected = $dbw->affectedRows();
496  $this->mId = $dbw->insertId();
497 
498  # Don't collide with expired blocks.
499  # Do this after trying to insert to avoid locking.
500  if ( !$affected ) {
501  # T96428: The ipb_address index uses a prefix on a field, so
502  # use a standard SELECT + DELETE to avoid annoying gap locks.
503  $ids = $dbw->selectFieldValues( 'ipblocks',
504  'ipb_id',
505  [
506  'ipb_address' => $row['ipb_address'],
507  'ipb_user' => $row['ipb_user'],
508  'ipb_expiry < ' . $dbw->addQuotes( $dbw->timestamp() )
509  ],
510  __METHOD__
511  );
512  if ( $ids ) {
513  $dbw->delete( 'ipblocks', [ 'ipb_id' => $ids ], __METHOD__ );
514  $dbw->insert( 'ipblocks', $row, __METHOD__, [ 'IGNORE' ] );
515  $affected = $dbw->affectedRows();
516  $this->mId = $dbw->insertId();
517  }
518  }
519 
520  if ( $affected ) {
521  $auto_ipd_ids = $this->doRetroactiveAutoblock();
522 
523  if ( $wgBlockDisablesLogin && $this->target instanceof User ) {
524  // Change user login token to force them to be logged out.
525  $this->target->setToken();
526  $this->target->saveSettings();
527  }
528 
529  return [ 'id' => $this->mId, 'autoIds' => $auto_ipd_ids ];
530  }
531 
532  return false;
533  }
534 
542  public function update() {
543  wfDebug( "Block::update; timestamp {$this->mTimestamp}\n" );
544  $dbw = wfGetDB( DB_MASTER );
545 
546  $dbw->startAtomic( __METHOD__ );
547 
548  $dbw->update(
549  'ipblocks',
550  $this->getDatabaseArray( $dbw ),
551  [ 'ipb_id' => $this->getId() ],
552  __METHOD__
553  );
554 
555  $affected = $dbw->affectedRows();
556 
557  if ( $this->isAutoblocking() ) {
558  // update corresponding autoblock(s) (T50813)
559  $dbw->update(
560  'ipblocks',
561  $this->getAutoblockUpdateArray(),
562  [ 'ipb_parent_block_id' => $this->getId() ],
563  __METHOD__
564  );
565  } else {
566  // autoblock no longer required, delete corresponding autoblock(s)
567  $dbw->delete(
568  'ipblocks',
569  [ 'ipb_parent_block_id' => $this->getId() ],
570  __METHOD__
571  );
572  }
573 
574  $dbw->endAtomic( __METHOD__ );
575 
576  if ( $affected ) {
577  $auto_ipd_ids = $this->doRetroactiveAutoblock();
578  return [ 'id' => $this->mId, 'autoIds' => $auto_ipd_ids ];
579  }
580 
581  return false;
582  }
583 
589  protected function getDatabaseArray( $db = null ) {
590  if ( !$db ) {
591  $db = wfGetDB( DB_REPLICA );
592  }
593  $expiry = $db->encodeExpiry( $this->mExpiry );
594 
595  if ( $this->forcedTargetID ) {
596  $uid = $this->forcedTargetID;
597  } else {
598  $uid = $this->target instanceof User ? $this->target->getId() : 0;
599  }
600 
601  $a = [
602  'ipb_address' => (string)$this->target,
603  'ipb_user' => $uid,
604  'ipb_by' => $this->getBy(),
605  'ipb_by_text' => $this->getByName(),
606  'ipb_reason' => $this->mReason,
607  'ipb_timestamp' => $db->timestamp( $this->mTimestamp ),
608  'ipb_auto' => $this->mAuto,
609  'ipb_anon_only' => !$this->isHardblock(),
610  'ipb_create_account' => $this->prevents( 'createaccount' ),
611  'ipb_enable_autoblock' => $this->isAutoblocking(),
612  'ipb_expiry' => $expiry,
613  'ipb_range_start' => $this->getRangeStart(),
614  'ipb_range_end' => $this->getRangeEnd(),
615  'ipb_deleted' => intval( $this->mHideName ), // typecast required for SQLite
616  'ipb_block_email' => $this->prevents( 'sendemail' ),
617  'ipb_allow_usertalk' => !$this->prevents( 'editownusertalk' ),
618  'ipb_parent_block_id' => $this->mParentBlockId
619  ];
620 
621  return $a;
622  }
623 
627  protected function getAutoblockUpdateArray() {
628  return [
629  'ipb_by' => $this->getBy(),
630  'ipb_by_text' => $this->getByName(),
631  'ipb_reason' => $this->mReason,
632  'ipb_create_account' => $this->prevents( 'createaccount' ),
633  'ipb_deleted' => (int)$this->mHideName, // typecast required for SQLite
634  'ipb_allow_usertalk' => !$this->prevents( 'editownusertalk' ),
635  ];
636  }
637 
644  protected function doRetroactiveAutoblock() {
645  $blockIds = [];
646  # If autoblock is enabled, autoblock the LAST IP(s) used
647  if ( $this->isAutoblocking() && $this->getType() == self::TYPE_USER ) {
648  wfDebug( "Doing retroactive autoblocks for " . $this->getTarget() . "\n" );
649 
650  $continue = Hooks::run(
651  'PerformRetroactiveAutoblock', [ $this, &$blockIds ] );
652 
653  if ( $continue ) {
654  self::defaultRetroactiveAutoblock( $this, $blockIds );
655  }
656  }
657  return $blockIds;
658  }
659 
667  protected static function defaultRetroactiveAutoblock( Block $block, array &$blockIds ) {
668  global $wgPutIPinRC;
669 
670  // No IPs are in recentchanges table, so nothing to select
671  if ( !$wgPutIPinRC ) {
672  return;
673  }
674 
675  $dbr = wfGetDB( DB_REPLICA );
676 
677  $options = [ 'ORDER BY' => 'rc_timestamp DESC' ];
678  $conds = [ 'rc_user_text' => (string)$block->getTarget() ];
679 
680  // Just the last IP used.
681  $options['LIMIT'] = 1;
682 
683  $res = $dbr->select( 'recentchanges', [ 'rc_ip' ], $conds,
684  __METHOD__, $options );
685 
686  if ( !$res->numRows() ) {
687  # No results, don't autoblock anything
688  wfDebug( "No IP found to retroactively autoblock\n" );
689  } else {
690  foreach ( $res as $row ) {
691  if ( $row->rc_ip ) {
692  $id = $block->doAutoblock( $row->rc_ip );
693  if ( $id ) {
694  $blockIds[] = $id;
695  }
696  }
697  }
698  }
699  }
700 
708  public static function isWhitelistedFromAutoblocks( $ip ) {
709  // Try to get the autoblock_whitelist from the cache, as it's faster
710  // than getting the msg raw and explode()'ing it.
711  $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
712  $lines = $cache->getWithSetCallback(
713  wfMemcKey( 'ipb', 'autoblock', 'whitelist' ),
714  $cache::TTL_DAY,
715  function ( $curValue, &$ttl, array &$setOpts ) {
716  $setOpts += Database::getCacheSetOptions( wfGetDB( DB_REPLICA ) );
717 
718  return explode( "\n",
719  wfMessage( 'autoblock_whitelist' )->inContentLanguage()->plain() );
720  }
721  );
722 
723  wfDebug( "Checking the autoblock whitelist..\n" );
724 
725  foreach ( $lines as $line ) {
726  # List items only
727  if ( substr( $line, 0, 1 ) !== '*' ) {
728  continue;
729  }
730 
731  $wlEntry = substr( $line, 1 );
732  $wlEntry = trim( $wlEntry );
733 
734  wfDebug( "Checking $ip against $wlEntry..." );
735 
736  # Is the IP in this range?
737  if ( IP::isInRange( $ip, $wlEntry ) ) {
738  wfDebug( " IP $ip matches $wlEntry, not autoblocking\n" );
739  return true;
740  } else {
741  wfDebug( " No match\n" );
742  }
743  }
744 
745  return false;
746  }
747 
754  public function doAutoblock( $autoblockIP ) {
755  # If autoblocks are disabled, go away.
756  if ( !$this->isAutoblocking() ) {
757  return false;
758  }
759 
760  # Don't autoblock for system blocks
761  if ( $this->getSystemBlockType() !== null ) {
762  throw new MWException( 'Cannot autoblock from a system block' );
763  }
764 
765  # Check for presence on the autoblock whitelist.
766  if ( self::isWhitelistedFromAutoblocks( $autoblockIP ) ) {
767  return false;
768  }
769 
770  // Avoid PHP 7.1 warning of passing $this by reference
771  $block = $this;
772  # Allow hooks to cancel the autoblock.
773  if ( !Hooks::run( 'AbortAutoblock', [ $autoblockIP, &$block ] ) ) {
774  wfDebug( "Autoblock aborted by hook.\n" );
775  return false;
776  }
777 
778  # It's okay to autoblock. Go ahead and insert/update the block...
779 
780  # Do not add a *new* block if the IP is already blocked.
781  $ipblock = Block::newFromTarget( $autoblockIP );
782  if ( $ipblock ) {
783  # Check if the block is an autoblock and would exceed the user block
784  # if renewed. If so, do nothing, otherwise prolong the block time...
785  if ( $ipblock->mAuto && // @todo Why not compare $ipblock->mExpiry?
786  $this->mExpiry > Block::getAutoblockExpiry( $ipblock->mTimestamp )
787  ) {
788  # Reset block timestamp to now and its expiry to
789  # $wgAutoblockExpiry in the future
790  $ipblock->updateTimestamp();
791  }
792  return false;
793  }
794 
795  # Make a new block object with the desired properties.
796  $autoblock = new Block;
797  wfDebug( "Autoblocking {$this->getTarget()}@" . $autoblockIP . "\n" );
798  $autoblock->setTarget( $autoblockIP );
799  $autoblock->setBlocker( $this->getBlocker() );
800  $autoblock->mReason = wfMessage( 'autoblocker', $this->getTarget(), $this->mReason )
801  ->inContentLanguage()->plain();
802  $timestamp = wfTimestampNow();
803  $autoblock->mTimestamp = $timestamp;
804  $autoblock->mAuto = 1;
805  $autoblock->prevents( 'createaccount', $this->prevents( 'createaccount' ) );
806  # Continue suppressing the name if needed
807  $autoblock->mHideName = $this->mHideName;
808  $autoblock->prevents( 'editownusertalk', $this->prevents( 'editownusertalk' ) );
809  $autoblock->mParentBlockId = $this->mId;
810 
811  if ( $this->mExpiry == 'infinity' ) {
812  # Original block was indefinite, start an autoblock now
813  $autoblock->mExpiry = Block::getAutoblockExpiry( $timestamp );
814  } else {
815  # If the user is already blocked with an expiry date, we don't
816  # want to pile on top of that.
817  $autoblock->mExpiry = min( $this->mExpiry, Block::getAutoblockExpiry( $timestamp ) );
818  }
819 
820  # Insert the block...
821  $status = $autoblock->insert();
822  return $status
823  ? $status['id']
824  : false;
825  }
826 
831  public function deleteIfExpired() {
832 
833  if ( $this->isExpired() ) {
834  wfDebug( "Block::deleteIfExpired() -- deleting\n" );
835  $this->delete();
836  $retVal = true;
837  } else {
838  wfDebug( "Block::deleteIfExpired() -- not expired\n" );
839  $retVal = false;
840  }
841 
842  return $retVal;
843  }
844 
849  public function isExpired() {
850  $timestamp = wfTimestampNow();
851  wfDebug( "Block::isExpired() checking current " . $timestamp . " vs $this->mExpiry\n" );
852 
853  if ( !$this->mExpiry ) {
854  return false;
855  } else {
856  return $timestamp > $this->mExpiry;
857  }
858  }
859 
864  public function isValid() {
865  return $this->getTarget() != null;
866  }
867 
871  public function updateTimestamp() {
872  if ( $this->mAuto ) {
873  $this->mTimestamp = wfTimestamp();
874  $this->mExpiry = Block::getAutoblockExpiry( $this->mTimestamp );
875 
876  $dbw = wfGetDB( DB_MASTER );
877  $dbw->update( 'ipblocks',
878  [ /* SET */
879  'ipb_timestamp' => $dbw->timestamp( $this->mTimestamp ),
880  'ipb_expiry' => $dbw->timestamp( $this->mExpiry ),
881  ],
882  [ /* WHERE */
883  'ipb_id' => $this->getId(),
884  ],
885  __METHOD__
886  );
887  }
888  }
889 
895  public function getRangeStart() {
896  switch ( $this->type ) {
897  case self::TYPE_USER:
898  return '';
899  case self::TYPE_IP:
900  return IP::toHex( $this->target );
901  case self::TYPE_RANGE:
902  list( $start, /*...*/ ) = IP::parseRange( $this->target );
903  return $start;
904  default:
905  throw new MWException( "Block with invalid type" );
906  }
907  }
908 
914  public function getRangeEnd() {
915  switch ( $this->type ) {
916  case self::TYPE_USER:
917  return '';
918  case self::TYPE_IP:
919  return IP::toHex( $this->target );
920  case self::TYPE_RANGE:
921  list( /*...*/, $end ) = IP::parseRange( $this->target );
922  return $end;
923  default:
924  throw new MWException( "Block with invalid type" );
925  }
926  }
927 
933  public function getBy() {
934  $blocker = $this->getBlocker();
935  return ( $blocker instanceof User )
936  ? $blocker->getId()
937  : 0;
938  }
939 
945  public function getByName() {
946  $blocker = $this->getBlocker();
947  return ( $blocker instanceof User )
948  ? $blocker->getName()
949  : (string)$blocker; // username
950  }
951 
956  public function getId() {
957  return $this->mId;
958  }
959 
964  public function getSystemBlockType() {
965  return $this->systemBlockType;
966  }
967 
974  public function fromMaster( $x = null ) {
975  return wfSetVar( $this->mFromMaster, $x );
976  }
977 
983  public function isHardblock( $x = null ) {
984  wfSetVar( $this->isHardblock, $x );
985 
986  # You can't *not* hardblock a user
987  return $this->getType() == self::TYPE_USER
988  ? true
990  }
991 
996  public function isAutoblocking( $x = null ) {
997  wfSetVar( $this->isAutoblocking, $x );
998 
999  # You can't put an autoblock on an IP or range as we don't have any history to
1000  # look over to get more IPs from
1001  return $this->getType() == self::TYPE_USER
1002  ? $this->isAutoblocking
1003  : false;
1004  }
1005 
1013  public function prevents( $action, $x = null ) {
1014  global $wgBlockDisablesLogin;
1015  $res = null;
1016  switch ( $action ) {
1017  case 'edit':
1018  # For now... <evil laugh>
1019  $res = true;
1020  break;
1021  case 'createaccount':
1022  $res = wfSetVar( $this->mCreateAccount, $x );
1023  break;
1024  case 'sendemail':
1025  $res = wfSetVar( $this->mBlockEmail, $x );
1026  break;
1027  case 'editownusertalk':
1028  $res = wfSetVar( $this->mDisableUsertalk, $x );
1029  break;
1030  case 'read':
1031  $res = false;
1032  break;
1033  }
1034  if ( !$res && $wgBlockDisablesLogin ) {
1035  // If a block would disable login, then it should
1036  // prevent any action that all users cannot do
1037  $anon = new User;
1038  $res = $anon->isAllowed( $action ) ? $res : true;
1039  }
1040 
1041  return $res;
1042  }
1043 
1048  public function getRedactedName() {
1049  if ( $this->mAuto ) {
1050  return Html::rawElement(
1051  'span',
1052  [ 'class' => 'mw-autoblockid' ],
1053  wfMessage( 'autoblockid', $this->mId )
1054  );
1055  } else {
1056  return htmlspecialchars( $this->getTarget() );
1057  }
1058  }
1059 
1066  public static function getAutoblockExpiry( $timestamp ) {
1067  global $wgAutoblockExpiry;
1068 
1069  return wfTimestamp( TS_MW, wfTimestamp( TS_UNIX, $timestamp ) + $wgAutoblockExpiry );
1070  }
1071 
1075  public static function purgeExpired() {
1076  if ( wfReadOnly() ) {
1077  return;
1078  }
1079 
1081  wfGetDB( DB_MASTER ),
1082  __METHOD__,
1083  function ( IDatabase $dbw, $fname ) {
1084  $dbw->delete(
1085  'ipblocks',
1086  [ 'ipb_expiry < ' . $dbw->addQuotes( $dbw->timestamp() ) ],
1087  $fname
1088  );
1089  }
1090  ) );
1091  }
1092 
1113  public static function newFromTarget( $specificTarget, $vagueTarget = null, $fromMaster = false ) {
1114 
1115  list( $target, $type ) = self::parseTarget( $specificTarget );
1116  if ( $type == Block::TYPE_ID || $type == Block::TYPE_AUTO ) {
1117  return Block::newFromID( $target );
1118 
1119  } elseif ( $target === null && $vagueTarget == '' ) {
1120  # We're not going to find anything useful here
1121  # Be aware that the == '' check is explicit, since empty values will be
1122  # passed by some callers (T31116)
1123  return null;
1124 
1125  } elseif ( in_array(
1126  $type,
1128  ) {
1129  $block = new Block();
1130  $block->fromMaster( $fromMaster );
1131 
1132  if ( $type !== null ) {
1133  $block->setTarget( $target );
1134  }
1135 
1136  if ( $block->newLoad( $vagueTarget ) ) {
1137  return $block;
1138  }
1139  }
1140  return null;
1141  }
1142 
1153  public static function getBlocksForIPList( array $ipChain, $isAnon, $fromMaster = false ) {
1154  if ( !count( $ipChain ) ) {
1155  return [];
1156  }
1157 
1158  $conds = [];
1159  $proxyLookup = MediaWikiServices::getInstance()->getProxyLookup();
1160  foreach ( array_unique( $ipChain ) as $ipaddr ) {
1161  # Discard invalid IP addresses. Since XFF can be spoofed and we do not
1162  # necessarily trust the header given to us, make sure that we are only
1163  # checking for blocks on well-formatted IP addresses (IPv4 and IPv6).
1164  # Do not treat private IP spaces as special as it may be desirable for wikis
1165  # to block those IP ranges in order to stop misbehaving proxies that spoof XFF.
1166  if ( !IP::isValid( $ipaddr ) ) {
1167  continue;
1168  }
1169  # Don't check trusted IPs (includes local squids which will be in every request)
1170  if ( $proxyLookup->isTrustedProxy( $ipaddr ) ) {
1171  continue;
1172  }
1173  # Check both the original IP (to check against single blocks), as well as build
1174  # the clause to check for rangeblocks for the given IP.
1175  $conds['ipb_address'][] = $ipaddr;
1176  $conds[] = self::getRangeCond( IP::toHex( $ipaddr ) );
1177  }
1178 
1179  if ( !count( $conds ) ) {
1180  return [];
1181  }
1182 
1183  if ( $fromMaster ) {
1184  $db = wfGetDB( DB_MASTER );
1185  } else {
1186  $db = wfGetDB( DB_REPLICA );
1187  }
1188  $conds = $db->makeList( $conds, LIST_OR );
1189  if ( !$isAnon ) {
1190  $conds = [ $conds, 'ipb_anon_only' => 0 ];
1191  }
1192  $selectFields = array_merge(
1193  [ 'ipb_range_start', 'ipb_range_end' ],
1195  );
1196  $rows = $db->select( 'ipblocks',
1197  $selectFields,
1198  $conds,
1199  __METHOD__
1200  );
1201 
1202  $blocks = [];
1203  foreach ( $rows as $row ) {
1204  $block = self::newFromRow( $row );
1205  if ( !$block->isExpired() ) {
1206  $blocks[] = $block;
1207  }
1208  }
1209 
1210  return $blocks;
1211  }
1212 
1234  public static function chooseBlock( array $blocks, array $ipChain ) {
1235  if ( !count( $blocks ) ) {
1236  return null;
1237  } elseif ( count( $blocks ) == 1 ) {
1238  return $blocks[0];
1239  }
1240 
1241  // Sort hard blocks before soft ones and secondarily sort blocks
1242  // that disable account creation before those that don't.
1243  usort( $blocks, function ( Block $a, Block $b ) {
1244  $aWeight = (int)$a->isHardblock() . (int)$a->prevents( 'createaccount' );
1245  $bWeight = (int)$b->isHardblock() . (int)$b->prevents( 'createaccount' );
1246  return strcmp( $bWeight, $aWeight ); // highest weight first
1247  } );
1248 
1249  $blocksListExact = [
1250  'hard' => false,
1251  'disable_create' => false,
1252  'other' => false,
1253  'auto' => false
1254  ];
1255  $blocksListRange = [
1256  'hard' => false,
1257  'disable_create' => false,
1258  'other' => false,
1259  'auto' => false
1260  ];
1261  $ipChain = array_reverse( $ipChain );
1262 
1264  foreach ( $blocks as $block ) {
1265  // Stop searching if we have already have a "better" block. This
1266  // is why the order of the blocks matters
1267  if ( !$block->isHardblock() && $blocksListExact['hard'] ) {
1268  break;
1269  } elseif ( !$block->prevents( 'createaccount' ) && $blocksListExact['disable_create'] ) {
1270  break;
1271  }
1272 
1273  foreach ( $ipChain as $checkip ) {
1274  $checkipHex = IP::toHex( $checkip );
1275  if ( (string)$block->getTarget() === $checkip ) {
1276  if ( $block->isHardblock() ) {
1277  $blocksListExact['hard'] = $blocksListExact['hard'] ?: $block;
1278  } elseif ( $block->prevents( 'createaccount' ) ) {
1279  $blocksListExact['disable_create'] = $blocksListExact['disable_create'] ?: $block;
1280  } elseif ( $block->mAuto ) {
1281  $blocksListExact['auto'] = $blocksListExact['auto'] ?: $block;
1282  } else {
1283  $blocksListExact['other'] = $blocksListExact['other'] ?: $block;
1284  }
1285  // We found closest exact match in the ip list, so go to the next Block
1286  break;
1287  } elseif ( array_filter( $blocksListExact ) == []
1288  && $block->getRangeStart() <= $checkipHex
1289  && $block->getRangeEnd() >= $checkipHex
1290  ) {
1291  if ( $block->isHardblock() ) {
1292  $blocksListRange['hard'] = $blocksListRange['hard'] ?: $block;
1293  } elseif ( $block->prevents( 'createaccount' ) ) {
1294  $blocksListRange['disable_create'] = $blocksListRange['disable_create'] ?: $block;
1295  } elseif ( $block->mAuto ) {
1296  $blocksListRange['auto'] = $blocksListRange['auto'] ?: $block;
1297  } else {
1298  $blocksListRange['other'] = $blocksListRange['other'] ?: $block;
1299  }
1300  break;
1301  }
1302  }
1303  }
1304 
1305  if ( array_filter( $blocksListExact ) == [] ) {
1306  $blocksList = &$blocksListRange;
1307  } else {
1308  $blocksList = &$blocksListExact;
1309  }
1310 
1311  $chosenBlock = null;
1312  if ( $blocksList['hard'] ) {
1313  $chosenBlock = $blocksList['hard'];
1314  } elseif ( $blocksList['disable_create'] ) {
1315  $chosenBlock = $blocksList['disable_create'];
1316  } elseif ( $blocksList['other'] ) {
1317  $chosenBlock = $blocksList['other'];
1318  } elseif ( $blocksList['auto'] ) {
1319  $chosenBlock = $blocksList['auto'];
1320  } else {
1321  throw new MWException( "Proxy block found, but couldn't be classified." );
1322  }
1323 
1324  return $chosenBlock;
1325  }
1326 
1336  public static function parseTarget( $target ) {
1337  # We may have been through this before
1338  if ( $target instanceof User ) {
1339  if ( IP::isValid( $target->getName() ) ) {
1340  return [ $target, self::TYPE_IP ];
1341  } else {
1342  return [ $target, self::TYPE_USER ];
1343  }
1344  } elseif ( $target === null ) {
1345  return [ null, null ];
1346  }
1347 
1348  $target = trim( $target );
1349 
1350  if ( IP::isValid( $target ) ) {
1351  # We can still create a User if it's an IP address, but we need to turn
1352  # off validation checking (which would exclude IP addresses)
1353  return [
1356  ];
1357 
1358  } elseif ( IP::isValidBlock( $target ) ) {
1359  # Can't create a User from an IP range
1361  }
1362 
1363  # Consider the possibility that this is not a username at all
1364  # but actually an old subpage (bug #29797)
1365  if ( strpos( $target, '/' ) !== false ) {
1366  # An old subpage, drill down to the user behind it
1367  $target = explode( '/', $target )[0];
1368  }
1369 
1370  $userObj = User::newFromName( $target );
1371  if ( $userObj instanceof User ) {
1372  # Note that since numbers are valid usernames, a $target of "12345" will be
1373  # considered a User. If you want to pass a block ID, prepend a hash "#12345",
1374  # since hash characters are not valid in usernames or titles generally.
1375  return [ $userObj, Block::TYPE_USER ];
1376 
1377  } elseif ( preg_match( '/^#\d+$/', $target ) ) {
1378  # Autoblock reference in the form "#12345"
1379  return [ substr( $target, 1 ), Block::TYPE_AUTO ];
1380 
1381  } else {
1382  # WTF?
1383  return [ null, null ];
1384  }
1385  }
1386 
1391  public function getType() {
1392  return $this->mAuto
1393  ? self::TYPE_AUTO
1394  : $this->type;
1395  }
1396 
1404  public function getTargetAndType() {
1405  return [ $this->getTarget(), $this->getType() ];
1406  }
1407 
1414  public function getTarget() {
1415  return $this->target;
1416  }
1417 
1423  public function getExpiry() {
1424  return $this->mExpiry;
1425  }
1426 
1431  public function setTarget( $target ) {
1432  list( $this->target, $this->type ) = self::parseTarget( $target );
1433  }
1434 
1439  public function getBlocker() {
1440  return $this->blocker;
1441  }
1442 
1447  public function setBlocker( $user ) {
1448  $this->blocker = $user;
1449  }
1450 
1457  public function setCookie( WebResponse $response ) {
1458  // Calculate the default expiry time.
1459  $maxExpiryTime = wfTimestamp( TS_MW, wfTimestamp() + ( 24 * 60 * 60 ) );
1460 
1461  // Use the Block's expiry time only if it's less than the default.
1462  $expiryTime = $this->getExpiry();
1463  if ( $expiryTime === 'infinity' || $expiryTime > $maxExpiryTime ) {
1464  $expiryTime = $maxExpiryTime;
1465  }
1466 
1467  // Set the cookie. Reformat the MediaWiki datetime as a Unix timestamp for the cookie.
1468  $expiryValue = DateTime::createFromFormat( 'YmdHis', $expiryTime )->format( 'U' );
1469  $cookieOptions = [ 'httpOnly' => false ];
1470  $cookieValue = $this->getCookieValue();
1471  $response->setCookie( 'BlockID', $cookieValue, $expiryValue, $cookieOptions );
1472  }
1473 
1479  public static function clearCookie( WebResponse $response ) {
1480  $response->clearCookie( 'BlockID', [ 'httpOnly' => false ] );
1481  }
1482 
1489  public function getCookieValue() {
1490  $config = RequestContext::getMain()->getConfig();
1491  $id = $this->getId();
1492  $secretKey = $config->get( 'SecretKey' );
1493  if ( !$secretKey ) {
1494  // If there's no secret key, don't append a HMAC.
1495  return $id;
1496  }
1497  $hmac = MWCryptHash::hmac( $id, $secretKey, false );
1498  $cookieValue = $id . '!' . $hmac;
1499  return $cookieValue;
1500  }
1501 
1508  public static function getIdFromCookieValue( $cookieValue ) {
1509  // Extract the ID prefix from the cookie value (may be the whole value, if no bang found).
1510  $bangPos = strpos( $cookieValue, '!' );
1511  $id = ( $bangPos === false ) ? $cookieValue : substr( $cookieValue, 0, $bangPos );
1512  // Get the site-wide secret key.
1513  $config = RequestContext::getMain()->getConfig();
1514  $secretKey = $config->get( 'SecretKey' );
1515  if ( !$secretKey ) {
1516  // If there's no secret key, just use the ID as given.
1517  return $id;
1518  }
1519  $storedHmac = substr( $cookieValue, $bangPos + 1 );
1520  $calculatedHmac = MWCryptHash::hmac( $id, $secretKey, false );
1521  if ( $calculatedHmac === $storedHmac ) {
1522  return $id;
1523  } else {
1524  return null;
1525  }
1526  }
1527 
1536  $blocker = $this->getBlocker();
1537  if ( $blocker instanceof User ) { // local user
1538  $blockerUserpage = $blocker->getUserPage();
1539  $link = "[[{$blockerUserpage->getPrefixedText()}|{$blockerUserpage->getText()}]]";
1540  } else { // foreign user
1541  $link = $blocker;
1542  }
1543 
1544  $reason = $this->mReason;
1545  if ( $reason == '' ) {
1546  $reason = $context->msg( 'blockednoreason' )->text();
1547  }
1548 
1549  /* $ip returns who *is* being blocked, $intended contains who was meant to be blocked.
1550  * This could be a username, an IP range, or a single IP. */
1551  $intended = $this->getTarget();
1552 
1554 
1555  $lang = $context->getLanguage();
1556  return [
1557  $systemBlockType !== null
1558  ? 'systemblockedtext'
1559  : ( $this->mAuto ? 'autoblockedtext' : 'blockedtext' ),
1560  $link,
1561  $reason,
1562  $context->getRequest()->getIP(),
1563  $this->getByName(),
1564  $systemBlockType !== null ? $systemBlockType : $this->getId(),
1565  $lang->formatExpiry( $this->mExpiry ),
1566  (string)$intended,
1567  $lang->userTimeAndDate( $this->mTimestamp, $context->getUser() ),
1568  ];
1569  }
1570 }
Block\prevents
prevents( $action, $x=null)
Get/set whether the Block prevents a given action.
Definition: Block.php:1013
IP\toHex
static toHex( $ip)
Return a zero-padded upper case hexadecimal representation of an IP address.
Definition: IP.php:405
Block\isHardblock
isHardblock( $x=null)
Get/set whether the Block is a hardblock (affects logged-in users on a given IP/range)
Definition: Block.php:983
Wikimedia\Rdbms\Database
Relational database abstraction object.
Definition: Database.php:45
$context
error also a ContextSource you ll probably need to make sure the header is varied on and they can depend only on the ResourceLoaderContext $context
Definition: hooks.txt:2612
User\newFromId
static newFromId( $id)
Static factory method for creation from a given user ID.
Definition: User.php:579
Block\getSystemBlockType
getSystemBlockType()
Get the system block type, if any.
Definition: Block.php:964
Block\equals
equals(Block $block)
Check if two blocks are effectively equal.
Definition: Block.php:232
Block\getType
getType()
Get the type of target for this particular block.
Definition: Block.php:1391
false
processing should stop and the error should be shown to the user * false
Definition: hooks.txt:189
User\getId
getId()
Get the user's ID.
Definition: User.php:2200
Block\getCookieValue
getCookieValue()
Get the BlockID cookie's value for this block.
Definition: Block.php:1489
MWCryptHash\hmac
static hmac( $data, $key, $raw=true)
Generate an acceptably unstable one-way-hmac of some text making use of the best hash algorithm that ...
Definition: MWCryptHash.php:106
Block\clearCookie
static clearCookie(WebResponse $response)
Unset the 'BlockID' cookie.
Definition: Block.php:1479
ContextSource\msg
msg()
Get a Message object with context set Parameters are the same as wfMessage()
Definition: ContextSource.php:187
Block\$mCreateAccount
bool $mCreateAccount
Definition: Block.php:59
Block\getIpFragment
static getIpFragment( $hex)
Get the component of an IP address which is certain to be the same between an IP address and a rangeb...
Definition: Block.php:392
Block\isExpired
isExpired()
Has the block expired?
Definition: Block.php:849
$lang
if(!isset( $args[0])) $lang
Definition: testCompression.php:33
Block\newFromID
static newFromID( $id)
Load a blocked user from their block id.
Definition: Block.php:184
wfSetVar
wfSetVar(&$dest, $source, $force=false)
Sets dest to source and returns the original value of dest If source is NULL, it just returns the val...
Definition: GlobalFunctions.php:1713
Block\$isHardblock
bool $isHardblock
Definition: Block.php:74
Block\TYPE_IP
const TYPE_IP
Definition: Block.php:84
captcha-old.count
count
Definition: captcha-old.py:225
Block\TYPE_RANGE
const TYPE_RANGE
Definition: Block.php:85
Block\getBy
getBy()
Get the user id of the blocking sysop.
Definition: Block.php:933
Block\chooseBlock
static chooseBlock(array $blocks, array $ipChain)
From a list of multiple blocks, find the most exact and strongest Block.
Definition: Block.php:1234
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition: GlobalFunctions.php:1994
Block\update
update()
Update a block in the DB with new parameters.
Definition: Block.php:542
$status
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist Do not use this to implement individual filters if they are compatible with the ChangesListFilter and ChangesListFilterGroup structure use sub classes of those in conjunction with the ChangesListSpecialPageStructuredFilters hook This hook can be used to implement filters that do not implement that or custom behavior that is not an individual filter e g Watchlist and Watchlist you will want to construct new ChangesListBooleanFilter or ChangesListStringOptionsFilter objects When constructing you specify which group they belong to You can reuse existing or create your you must register them with $special registerFilterGroup removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set $status
Definition: hooks.txt:1049
Block\getId
getId()
Get the block ID.
Definition: Block.php:956
use
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
Definition: MIT-LICENSE.txt:10
Block\setCookie
setCookie(WebResponse $response)
Set the 'BlockID' cookie to this block's ID and expiry time.
Definition: Block.php:1457
$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:246
DeferredUpdates\addUpdate
static addUpdate(DeferrableUpdate $update, $stage=self::POSTSEND)
Add an update to the deferred list to be run later by execute()
Definition: DeferredUpdates.php:76
$fname
if(!defined( 'MEDIAWIKI')) $fname
This file is not a valid entry point, perform no further processing unless MEDIAWIKI is defined.
Definition: Setup.php:36
WebResponse\setCookie
setCookie( $name, $value, $expire=0, $options=[])
Set the browser cookie.
Definition: WebResponse.php:99
Block\newFromTarget
static newFromTarget( $specificTarget, $vagueTarget=null, $fromMaster=false)
Given a target and the target's type, get an existing Block object if possible.
Definition: Block.php:1113
wfReadOnly
wfReadOnly()
Check whether the wiki is in read-only mode.
Definition: GlobalFunctions.php:1277
User\newFromName
static newFromName( $name, $validate='valid')
Static factory method for creation from username.
Definition: User.php:556
Block\isValid
isValid()
Is the block address valid (i.e.
Definition: Block.php:864
Block\initFromRow
initFromRow( $row)
Given a database row from the ipblocks table, initialize member variables.
Definition: Block.php:406
User\getUserPage
getUserPage()
Get this user's personal page title.
Definition: User.php:4288
Block\getRangeEnd
getRangeEnd()
Get the IP address at the end of the range in Hex form.
Definition: Block.php:914
Block\$mDisableUsertalk
bool $mDisableUsertalk
Definition: Block.php:56
$res
$res
Definition: database.txt:21
Block\__construct
__construct( $options=[])
Create a new block with specified parameters on a user, IP or IP range.
Definition: Block.php:115
ContextSource\getRequest
getRequest()
Get the WebRequest object.
Definition: ContextSource.php:78
User
User
Definition: All_system_messages.txt:425
Block\$mParentBlockId
int $mParentBlockId
Definition: Block.php:44
ContextSource\getUser
getUser()
Get the User object.
Definition: ContextSource.php:133
Block\getExpiry
getExpiry()
Definition: Block.php:1423
Block\deleteIfExpired
deleteIfExpired()
Check if a block has expired.
Definition: Block.php:831
Block\insert
insert( $dbw=null)
Insert a block into the block table.
Definition: Block.php:473
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
LIST_AND
const LIST_AND
Definition: Defines.php:41
Wikimedia\Rdbms\IDatabase
Basic database interface for live and lazy-loaded relation database handles.
Definition: IDatabase.php:40
Block\getRedactedName
getRedactedName()
Get the block name, but with autoblocked IPs hidden as per standard privacy policy.
Definition: Block.php:1048
Block\newLoad
newLoad( $vagueTarget=null)
Load a block from the database which affects the already-set $this->target: 1) A block directly on th...
Definition: Block.php:258
Block\$type
int $type
Block::TYPE_ constant.
Definition: Block.php:68
Wikimedia\Rdbms\IDatabase\timestamp
timestamp( $ts=0)
Convert a timestamp in one of the formats accepted by wfTimestamp() to the format used for inserting ...
LIST_OR
const LIST_OR
Definition: Defines.php:44
MWException
MediaWiki exception.
Definition: MWException.php:26
wfMemcKey
wfMemcKey()
Make a cache key for the local wiki.
Definition: GlobalFunctions.php:2961
wfDeprecated
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
Definition: GlobalFunctions.php:1128
Block\parseTarget
static parseTarget( $target)
From an existing Block, get the target and the type of target.
Definition: Block.php:1336
Block\$mBlockEmail
bool $mBlockEmail
Definition: Block.php:53
Block\getRangeCond
static getRangeCond( $start, $end=null)
Get a set of SQL conditions which will select rangeblocks encompassing a given range.
Definition: Block.php:359
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:3060
Block\doAutoblock
doAutoblock( $autoblockIP)
Autoblocks the given IP, referring to this Block.
Definition: Block.php:754
Block\TYPE_ID
const TYPE_ID
Definition: Block.php:87
Block\isWhitelistedFromAutoblocks
static isWhitelistedFromAutoblocks( $ip)
Checks whether a given IP is on the autoblock whitelist.
Definition: Block.php:708
$lines
$lines
Definition: router.php:67
Block\getAutoblockUpdateArray
getAutoblockUpdateArray()
Definition: Block.php:627
global
when a variable name is used in a it is silently declared as a new masking the global
Definition: design.txt:93
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
IP\isInRange
static isInRange( $addr, $range)
Determine if a given IPv4/IPv6 address is in a given CIDR network.
Definition: IP.php:638
wfTimestampNow
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
Definition: GlobalFunctions.php:2023
Block\isAutoblocking
isAutoblocking( $x=null)
Definition: Block.php:996
Block\$isAutoblocking
bool $isAutoblocking
Definition: Block.php:77
DB_MASTER
const DB_MASTER
Definition: defines.php:26
wfDebug
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:999
string
This code would result in ircNotify being run twice when an article is and once for brion Hooks can return three possible true was required This is the default since MediaWiki *some string
Definition: hooks.txt:177
list
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition: deferred.txt:11
Block\getBlocksForIPList
static getBlocksForIPList(array $ipChain, $isAnon, $fromMaster=false)
Get all blocks that match any IP from an array of IP addresses.
Definition: Block.php:1153
Block\getTargetAndType
getTargetAndType()
Get the target and target type for this particular Block.
Definition: Block.php:1404
AtomicSectionUpdate
Deferrable Update for closure/callback updates via IDatabase::doAtomicSection()
Definition: AtomicSectionUpdate.php:9
$line
$line
Definition: cdb.php:58
Block\doRetroactiveAutoblock
doRetroactiveAutoblock()
Retroactively autoblocks the last IP used by the user (if it is a user) blocked by this Block.
Definition: Block.php:644
$expiryTime
$expiryTime
Definition: opensearch_desc.php:42
Block\getIdFromCookieValue
static getIdFromCookieValue( $cookieValue)
Get the stored ID from the 'BlockID' cookie.
Definition: Block.php:1508
Block\updateTimestamp
updateTimestamp()
Update the timestamp on autoblocks.
Definition: Block.php:871
Block\$systemBlockType
string null $systemBlockType
Definition: Block.php:80
IP\parseRange
static parseRange( $range)
Given a string range in a number of formats, return the start and end of the range in hexadecimal.
Definition: IP.php:501
Block\$mId
int $mId
Definition: Block.php:47
Block\getBlocker
getBlocker()
Get the user who implemented this block.
Definition: Block.php:1439
Block\setBlocker
setBlocker( $user)
Set the user who implemented (or will implement) this block.
Definition: Block.php:1447
Block\$blocker
User $blocker
Definition: Block.php:71
Block\fromMaster
fromMaster( $x=null)
Get/set a flag determining whether the master is used for reads.
Definition: Block.php:974
Block\getTarget
getTarget()
Get the target for this particular Block.
Definition: Block.php:1414
Block\purgeExpired
static purgeExpired()
Purge expired blocks from the ipblocks table.
Definition: Block.php:1075
Block\TYPE_AUTO
const TYPE_AUTO
Definition: Block.php:86
RequestContext\getMain
static getMain()
Static methods.
Definition: RequestContext.php:468
IP\isValid
static isValid( $ip)
Validate an IP address.
Definition: IP.php:113
plain
either a plain
Definition: hooks.txt:2007
$response
this hook is for auditing only $response
Definition: hooks.txt:783
IContextSource
Interface for objects which can provide a MediaWiki context on request.
Definition: IContextSource.php:55
Block\TYPE_USER
const TYPE_USER
Definition: Block.php:83
IP\sanitizeIP
static sanitizeIP( $ip)
Convert an IP into a verbose, uppercase, normalized form.
Definition: IP.php:140
type
This document describes the state of Postgres support in and is fairly well maintained The main code is very well while extensions are very hit and miss it is probably the most supported database after MySQL Much of the work in making MediaWiki database agnostic came about through the work of creating Postgres as and are nearing end of but without copying over all the usage comments General notes on the but these can almost always be programmed around *Although Postgres has a true BOOLEAN type
Definition: postgres.txt:22
$dbr
if(! $regexes) $dbr
Definition: cleanup.php:94
$cache
$cache
Definition: mcc.php:33
Block\$mAuto
bool $mAuto
Definition: Block.php:35
Wikimedia\Rdbms\IDatabase\addQuotes
addQuotes( $s)
Adds quotes and backslashes.
Block\selectFields
static selectFields()
Return the list of ipblocks fields that should be selected to create a new block.
Definition: Block.php:204
Block\$mHideName
bool $mHideName
Definition: Block.php:41
Block\$forcedTargetID
int $forcedTargetID
Hack for foreign blocking (CentralAuth)
Definition: Block.php:65
Block\$target
User string $target
Definition: Block.php:62
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
Block\$mExpiry
string $mExpiry
Definition: Block.php:38
Block
Definition: Block.php:27
Html\rawElement
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition: Html.php:209
Block\getRangeStart
getRangeStart()
Get the IP address at the start of the range in Hex form.
Definition: Block.php:895
$link
usually copyright or history_copyright This message must be in HTML not wikitext & $link
Definition: hooks.txt:2929
true
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 noclasses just before the function returns a value If you return true
Definition: hooks.txt:1956
Block\$mReason
string $mReason
Definition: Block.php:29
Block\getPermissionsError
getPermissionsError(IContextSource $context)
Get the key and parameters for the corresponding error message.
Definition: Block.php:1535
wfMessage
either a unescaped string or a HtmlArmor object after in associative array form externallinks including delete and has completed for all link tables whether this was an auto creation default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a set this to the key of the message First element is the message additional optional elements are parameters for the key that are processed with wfMessage() -> params() ->parseAsBlock() - offset Set to overwrite offset parameter in $wgRequest set to '' to unset offset - wrap String Wrap the message in html(usually something like "&lt
Block\getDatabaseArray
getDatabaseArray( $db=null)
Get an array suitable for passing to $dbw->insert() or $dbw->update()
Definition: Block.php:589
Block\getByName
getByName()
Get the username of the blocking sysop.
Definition: Block.php:945
MediaWikiServices
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency MediaWikiServices
Definition: injection.txt:23
WebResponse
Allow programs to request this object from WebRequest::response() and handle all outputting (or lack ...
Definition: WebResponse.php:28
Block\newFromRow
static newFromRow( $row)
Create a new Block object from a database row.
Definition: Block.php:437
User
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition: User.php:50
Hooks\run
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:131
IP\isValidBlock
static isValidBlock( $ipblock)
Validate an IP Block (valid address WITH a valid prefix).
Definition: IP.php:126
User\getName
getName()
Get the user name, or the IP of an anonymous user.
Definition: User.php:2225
Block\defaultRetroactiveAutoblock
static defaultRetroactiveAutoblock(Block $block, array &$blockIds)
Retroactively autoblocks the last IP used by the user (if it is a user) blocked by this Block.
Definition: Block.php:667
IP\sanitizeRange
static sanitizeRange( $range)
Gets rid of unneeded numbers in quad-dotted/octet IP strings For example, 127.111....
Definition: IP.php:713
$options
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist Do not use this to implement individual filters if they are compatible with the ChangesListFilter and ChangesListFilterGroup structure use sub classes of those in conjunction with the ChangesListSpecialPageStructuredFilters hook This hook can be used to implement filters that do not implement that or custom behavior that is not an individual filter e g Watchlist and Watchlist you will want to construct new ChangesListBooleanFilter or ChangesListStringOptionsFilter objects When constructing you specify which group they belong to You can reuse existing or create your you must register them with $special registerFilterGroup removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content as context as context $options
Definition: hooks.txt:1049
Wikimedia\Rdbms\IDatabase\delete
delete( $table, $conds, $fname=__METHOD__)
DELETE query wrapper.
Block\setTarget
setTarget( $target)
Set the target for this block, and update $this->type accordingly.
Definition: Block.php:1431
IContextSource\getLanguage
getLanguage()
Get the Language object.
array
the array() calling protocol came about after MediaWiki 1.4rc1.
Block\$mFromMaster
bool $mFromMaster
Definition: Block.php:50
Block\$mTimestamp
string $mTimestamp
Definition: Block.php:32
Block\getAutoblockExpiry
static getAutoblockExpiry( $timestamp)
Get a timestamp of the expiry for autoblocks.
Definition: Block.php:1066