MediaWiki  master
DatabaseBlock.php
Go to the documentation of this file.
1 <?php
23 namespace MediaWiki\Block;
24 
25 use ActorMigration;
27 use CommentStore;
28 use DeferredUpdates;
29 use Hooks;
30 use Html;
31 use IContextSource;
32 use IP;
37 use MWException;
38 use RequestContext;
39 use stdClass;
40 use Title;
41 use User;
42 use WebResponse;
45 
59  public $mAuto;
60 
66 
68  private $mId;
69 
71  private $mFromMaster;
72 
74  private $forcedTargetID;
75 
77  private $isHardblock;
78 
80  private $isAutoblocking;
81 
83  private $restrictions;
84 
103  public function __construct( array $options = [] ) {
104  parent::__construct( $options );
105 
106  $defaults = [
107  'user' => null,
108  'auto' => false,
109  'expiry' => '',
110  'anonOnly' => false,
111  'createAccount' => false,
112  'enableAutoblock' => false,
113  'blockEmail' => false,
114  'allowUsertalk' => false,
115  'sitewide' => true,
116  ];
117 
118  $options += $defaults;
119 
120  if ( $this->target instanceof User && $options['user'] ) {
121  # Needed for foreign users
122  $this->forcedTargetID = $options['user'];
123  }
124 
125  $this->setExpiry( wfGetDB( DB_REPLICA )->decodeExpiry( $options['expiry'] ) );
126 
127  # Boolean settings
128  $this->mAuto = (bool)$options['auto'];
129  $this->isHardblock( !$options['anonOnly'] );
130  $this->isAutoblocking( (bool)$options['enableAutoblock'] );
131  $this->isSitewide( (bool)$options['sitewide'] );
132  $this->isEmailBlocked( (bool)$options['blockEmail'] );
133  $this->isCreateAccountBlocked( (bool)$options['createAccount'] );
134  $this->isUsertalkEditAllowed( (bool)$options['allowUsertalk'] );
135 
136  $this->mFromMaster = false;
137  }
138 
145  public static function newFromID( $id ) {
146  $dbr = wfGetDB( DB_REPLICA );
147  $blockQuery = self::getQueryInfo();
148  $res = $dbr->selectRow(
149  $blockQuery['tables'],
150  $blockQuery['fields'],
151  [ 'ipb_id' => $id ],
152  __METHOD__,
153  [],
154  $blockQuery['joins']
155  );
156  if ( $res ) {
157  return self::newFromRow( $res );
158  } else {
159  return null;
160  }
161  }
162 
172  public static function getQueryInfo() {
173  $commentQuery = CommentStore::getStore()->getJoin( 'ipb_reason' );
174  $actorQuery = ActorMigration::newMigration()->getJoin( 'ipb_by' );
175  return [
176  'tables' => [ 'ipblocks' ] + $commentQuery['tables'] + $actorQuery['tables'],
177  'fields' => [
178  'ipb_id',
179  'ipb_address',
180  'ipb_timestamp',
181  'ipb_auto',
182  'ipb_anon_only',
183  'ipb_create_account',
184  'ipb_enable_autoblock',
185  'ipb_expiry',
186  'ipb_deleted',
187  'ipb_block_email',
188  'ipb_allow_usertalk',
189  'ipb_parent_block_id',
190  'ipb_sitewide',
191  ] + $commentQuery['fields'] + $actorQuery['fields'],
192  'joins' => $commentQuery['joins'] + $actorQuery['joins'],
193  ];
194  }
195 
203  public function equals( DatabaseBlock $block ) {
204  return (
205  (string)$this->target == (string)$block->target
206  && $this->type == $block->type
207  && $this->mAuto == $block->mAuto
208  && $this->isHardblock() == $block->isHardblock()
209  && $this->isCreateAccountBlocked() == $block->isCreateAccountBlocked()
210  && $this->getExpiry() == $block->getExpiry()
211  && $this->isAutoblocking() == $block->isAutoblocking()
212  && $this->getHideName() == $block->getHideName()
213  && $this->isEmailBlocked() == $block->isEmailBlocked()
214  && $this->isUsertalkEditAllowed() == $block->isUsertalkEditAllowed()
215  && $this->getReason() == $block->getReason()
216  && $this->isSitewide() == $block->isSitewide()
217  // DatabaseBlock::getRestrictions() may perform a database query, so
218  // keep it at the end.
219  && $this->getBlockRestrictionStore()->equals(
220  $this->getRestrictions(), $block->getRestrictions()
221  )
222  );
223  }
224 
237  protected static function newLoad(
238  $specificTarget,
239  $specificType,
240  $fromMaster,
241  $vagueTarget = null
242  ) {
243  $db = wfGetDB( $fromMaster ? DB_MASTER : DB_REPLICA );
244 
245  if ( $specificType !== null ) {
246  $conds = [
247  'ipb_address' => [ (string)$specificTarget ],
248  ];
249  } else {
250  $conds = [ 'ipb_address' => [] ];
251  }
252 
253  # Be aware that the != '' check is explicit, since empty values will be
254  # passed by some callers (T31116)
255  if ( $vagueTarget != '' ) {
256  list( $target, $type ) = self::parseTarget( $vagueTarget );
257  switch ( $type ) {
258  case self::TYPE_USER:
259  # Slightly weird, but who are we to argue?
260  $conds['ipb_address'][] = (string)$target;
261  break;
262 
263  case self::TYPE_IP:
264  $conds['ipb_address'][] = (string)$target;
265  $conds[] = self::getRangeCond( IP::toHex( $target ) );
266  $conds = $db->makeList( $conds, LIST_OR );
267  break;
268 
269  case self::TYPE_RANGE:
270  list( $start, $end ) = IP::parseRange( $target );
271  $conds['ipb_address'][] = (string)$target;
272  $conds[] = self::getRangeCond( $start, $end );
273  $conds = $db->makeList( $conds, LIST_OR );
274  break;
275 
276  default:
277  throw new MWException( "Tried to load block with invalid type" );
278  }
279  }
280 
281  $blockQuery = self::getQueryInfo();
282  $res = $db->select(
283  $blockQuery['tables'], $blockQuery['fields'], $conds, __METHOD__, [], $blockQuery['joins']
284  );
285 
286  $blocks = [];
287  $blockIds = [];
288  $autoBlocks = [];
289  foreach ( $res as $row ) {
290  $block = self::newFromRow( $row );
291 
292  # Don't use expired blocks
293  if ( $block->isExpired() ) {
294  continue;
295  }
296 
297  # Don't use anon only blocks on users
298  if ( $specificType == self::TYPE_USER && !$block->isHardblock() ) {
299  continue;
300  }
301 
302  // Check for duplicate autoblocks
303  if ( $block->getType() === self::TYPE_AUTO ) {
304  $autoBlocks[] = $block;
305  } else {
306  $blocks[] = $block;
307  $blockIds[] = $block->getId();
308  }
309  }
310 
311  // Only add autoblocks that aren't duplicates
312  foreach ( $autoBlocks as $block ) {
313  if ( !in_array( $block->mParentBlockId, $blockIds ) ) {
314  $blocks[] = $block;
315  }
316  }
317 
318  return $blocks;
319  }
320 
333  protected static function chooseMostSpecificBlock( array $blocks ) {
334  if ( count( $blocks ) === 1 ) {
335  return $blocks[0];
336  }
337 
338  # This result could contain a block on the user, a block on the IP, and a russian-doll
339  # set of rangeblocks. We want to choose the most specific one, so keep a leader board.
340  $bestBlock = null;
341 
342  # Lower will be better
343  $bestBlockScore = 100;
344  foreach ( $blocks as $block ) {
345  if ( $block->getType() == self::TYPE_RANGE ) {
346  # This is the number of bits that are allowed to vary in the block, give
347  # or take some floating point errors
348  $target = $block->getTarget();
349  $max = IP::isIPv6( $target ) ? 128 : 32;
350  list( $network, $bits ) = IP::parseCIDR( $target );
351  $size = $max - $bits;
352 
353  # Rank a range block covering a single IP equally with a single-IP block
354  $score = self::TYPE_RANGE - 1 + ( $size / $max );
355 
356  } else {
357  $score = $block->getType();
358  }
359 
360  if ( $score < $bestBlockScore ) {
361  $bestBlockScore = $score;
362  $bestBlock = $block;
363  }
364  }
365 
366  return $bestBlock;
367  }
368 
375  public static function getRangeCond( $start, $end = null ) {
376  if ( $end === null ) {
377  $end = $start;
378  }
379  # Per T16634, we want to include relevant active rangeblocks; for
380  # rangeblocks, we want to include larger ranges which enclose the given
381  # range. We know that all blocks must be smaller than $wgBlockCIDRLimit,
382  # so we can improve performance by filtering on a LIKE clause
383  $chunk = self::getIpFragment( $start );
384  $dbr = wfGetDB( DB_REPLICA );
385  $like = $dbr->buildLike( $chunk, $dbr->anyString() );
386 
387  # Fairly hard to make a malicious SQL statement out of hex characters,
388  # but stranger things have happened...
389  $safeStart = $dbr->addQuotes( $start );
390  $safeEnd = $dbr->addQuotes( $end );
391 
392  return $dbr->makeList(
393  [
394  "ipb_range_start $like",
395  "ipb_range_start <= $safeStart",
396  "ipb_range_end >= $safeEnd",
397  ],
398  LIST_AND
399  );
400  }
401 
408  protected static function getIpFragment( $hex ) {
409  global $wgBlockCIDRLimit;
410  if ( substr( $hex, 0, 3 ) == 'v6-' ) {
411  return 'v6-' . substr( substr( $hex, 3 ), 0, floor( $wgBlockCIDRLimit['IPv6'] / 4 ) );
412  } else {
413  return substr( $hex, 0, floor( $wgBlockCIDRLimit['IPv4'] / 4 ) );
414  }
415  }
416 
422  protected function initFromRow( $row ) {
423  $this->setTarget( $row->ipb_address );
425  $row->ipb_by, $row->ipb_by_text, $row->ipb_by_actor ?? null
426  ) );
427 
428  $this->setTimestamp( wfTimestamp( TS_MW, $row->ipb_timestamp ) );
429  $this->mAuto = $row->ipb_auto;
430  $this->setHideName( $row->ipb_deleted );
431  $this->mId = (int)$row->ipb_id;
432  $this->mParentBlockId = $row->ipb_parent_block_id;
433 
434  // I wish I didn't have to do this
435  $db = wfGetDB( DB_REPLICA );
436  $this->setExpiry( $db->decodeExpiry( $row->ipb_expiry ) );
437  $this->setReason(
439  // Legacy because $row may have come from self::selectFields()
440  ->getCommentLegacy( $db, 'ipb_reason', $row )->text
441  );
442 
443  $this->isHardblock( !$row->ipb_anon_only );
444  $this->isAutoblocking( $row->ipb_enable_autoblock );
445  $this->isSitewide( (bool)$row->ipb_sitewide );
446 
447  $this->isCreateAccountBlocked( $row->ipb_create_account );
448  $this->isEmailBlocked( $row->ipb_block_email );
449  $this->isUsertalkEditAllowed( $row->ipb_allow_usertalk );
450  }
451 
457  public static function newFromRow( $row ) {
458  $block = new DatabaseBlock;
459  $block->initFromRow( $row );
460  return $block;
461  }
462 
469  public function delete() {
470  if ( wfReadOnly() ) {
471  return false;
472  }
473 
474  if ( !$this->getId() ) {
475  throw new MWException(
476  __METHOD__ . " requires that the mId member be filled\n"
477  );
478  }
479 
480  $dbw = wfGetDB( DB_MASTER );
481 
482  $this->getBlockRestrictionStore()->deleteByParentBlockId( $this->getId() );
483  $dbw->delete( 'ipblocks', [ 'ipb_parent_block_id' => $this->getId() ], __METHOD__ );
484 
485  $this->getBlockRestrictionStore()->deleteByBlockId( $this->getId() );
486  $dbw->delete( 'ipblocks', [ 'ipb_id' => $this->getId() ], __METHOD__ );
487 
488  return $dbw->affectedRows() > 0;
489  }
490 
499  public function insert( IDatabase $dbw = null ) {
500  global $wgBlockDisablesLogin;
501 
502  if ( !$this->getBlocker() || $this->getBlocker()->getName() === '' ) {
503  throw new MWException( 'Cannot insert a block without a blocker set' );
504  }
505 
506  wfDebug( __METHOD__ . "; timestamp {$this->mTimestamp}\n" );
507 
508  if ( $dbw === null ) {
509  $dbw = wfGetDB( DB_MASTER );
510  }
511 
512  self::purgeExpired();
513 
514  $row = $this->getDatabaseArray( $dbw );
515 
516  $dbw->insert( 'ipblocks', $row, __METHOD__, [ 'IGNORE' ] );
517  $affected = $dbw->affectedRows();
518  if ( $affected ) {
519  $this->setId( $dbw->insertId() );
520  if ( $this->restrictions ) {
521  $this->getBlockRestrictionStore()->insert( $this->restrictions );
522  }
523  }
524 
525  # Don't collide with expired blocks.
526  # Do this after trying to insert to avoid locking.
527  if ( !$affected ) {
528  # T96428: The ipb_address index uses a prefix on a field, so
529  # use a standard SELECT + DELETE to avoid annoying gap locks.
530  $ids = $dbw->selectFieldValues( 'ipblocks',
531  'ipb_id',
532  [
533  'ipb_address' => $row['ipb_address'],
534  'ipb_user' => $row['ipb_user'],
535  'ipb_expiry < ' . $dbw->addQuotes( $dbw->timestamp() )
536  ],
537  __METHOD__
538  );
539  if ( $ids ) {
540  $dbw->delete( 'ipblocks', [ 'ipb_id' => $ids ], __METHOD__ );
541  $this->getBlockRestrictionStore()->deleteByBlockId( $ids );
542  $dbw->insert( 'ipblocks', $row, __METHOD__, [ 'IGNORE' ] );
543  $affected = $dbw->affectedRows();
544  $this->setId( $dbw->insertId() );
545  if ( $this->restrictions ) {
546  $this->getBlockRestrictionStore()->insert( $this->restrictions );
547  }
548  }
549  }
550 
551  if ( $affected ) {
552  $auto_ipd_ids = $this->doRetroactiveAutoblock();
553 
554  if ( $wgBlockDisablesLogin && $this->target instanceof User ) {
555  // Change user login token to force them to be logged out.
556  $this->target->setToken();
557  $this->target->saveSettings();
558  }
559 
560  return [ 'id' => $this->mId, 'autoIds' => $auto_ipd_ids ];
561  }
562 
563  return false;
564  }
565 
573  public function update() {
574  wfDebug( __METHOD__ . "; timestamp {$this->mTimestamp}\n" );
575  $dbw = wfGetDB( DB_MASTER );
576 
577  $dbw->startAtomic( __METHOD__ );
578 
579  $result = $dbw->update(
580  'ipblocks',
581  $this->getDatabaseArray( $dbw ),
582  [ 'ipb_id' => $this->getId() ],
583  __METHOD__
584  );
585 
586  // Only update the restrictions if they have been modified.
587  if ( $this->restrictions !== null ) {
588  // An empty array should remove all of the restrictions.
589  if ( empty( $this->restrictions ) ) {
590  $success = $this->getBlockRestrictionStore()->deleteByBlockId( $this->getId() );
591  } else {
592  $success = $this->getBlockRestrictionStore()->update( $this->restrictions );
593  }
594  // Update the result. The first false is the result, otherwise, true.
595  $result = $result && $success;
596  }
597 
598  if ( $this->isAutoblocking() ) {
599  // update corresponding autoblock(s) (T50813)
600  $dbw->update(
601  'ipblocks',
602  $this->getAutoblockUpdateArray( $dbw ),
603  [ 'ipb_parent_block_id' => $this->getId() ],
604  __METHOD__
605  );
606 
607  // Only update the restrictions if they have been modified.
608  if ( $this->restrictions !== null ) {
609  $this->getBlockRestrictionStore()->updateByParentBlockId( $this->getId(), $this->restrictions );
610  }
611  } else {
612  // autoblock no longer required, delete corresponding autoblock(s)
613  $this->getBlockRestrictionStore()->deleteByParentBlockId( $this->getId() );
614  $dbw->delete(
615  'ipblocks',
616  [ 'ipb_parent_block_id' => $this->getId() ],
617  __METHOD__
618  );
619  }
620 
621  $dbw->endAtomic( __METHOD__ );
622 
623  if ( $result ) {
624  $auto_ipd_ids = $this->doRetroactiveAutoblock();
625  return [ 'id' => $this->mId, 'autoIds' => $auto_ipd_ids ];
626  }
627 
628  return $result;
629  }
630 
636  protected function getDatabaseArray( IDatabase $dbw ) {
637  $expiry = $dbw->encodeExpiry( $this->getExpiry() );
638 
639  if ( $this->forcedTargetID ) {
640  $uid = $this->forcedTargetID;
641  } else {
642  $uid = $this->target instanceof User ? $this->target->getId() : 0;
643  }
644 
645  $a = [
646  'ipb_address' => (string)$this->target,
647  'ipb_user' => $uid,
648  'ipb_timestamp' => $dbw->timestamp( $this->getTimestamp() ),
649  'ipb_auto' => $this->mAuto,
650  'ipb_anon_only' => !$this->isHardblock(),
651  'ipb_create_account' => $this->isCreateAccountBlocked(),
652  'ipb_enable_autoblock' => $this->isAutoblocking(),
653  'ipb_expiry' => $expiry,
654  'ipb_range_start' => $this->getRangeStart(),
655  'ipb_range_end' => $this->getRangeEnd(),
656  'ipb_deleted' => intval( $this->getHideName() ), // typecast required for SQLite
657  'ipb_block_email' => $this->isEmailBlocked(),
658  'ipb_allow_usertalk' => $this->isUsertalkEditAllowed(),
659  'ipb_parent_block_id' => $this->mParentBlockId,
660  'ipb_sitewide' => $this->isSitewide(),
661  ] + CommentStore::getStore()->insert( $dbw, 'ipb_reason', $this->getReason() )
662  + ActorMigration::newMigration()->getInsertValues( $dbw, 'ipb_by', $this->getBlocker() );
663 
664  return $a;
665  }
666 
671  protected function getAutoblockUpdateArray( IDatabase $dbw ) {
672  return [
673  'ipb_create_account' => $this->isCreateAccountBlocked(),
674  'ipb_deleted' => (int)$this->getHideName(), // typecast required for SQLite
675  'ipb_allow_usertalk' => $this->isUsertalkEditAllowed(),
676  'ipb_sitewide' => $this->isSitewide(),
677  ] + CommentStore::getStore()->insert( $dbw, 'ipb_reason', $this->getReason() )
678  + ActorMigration::newMigration()->getInsertValues( $dbw, 'ipb_by', $this->getBlocker() );
679  }
680 
687  protected function doRetroactiveAutoblock() {
688  $blockIds = [];
689  # If autoblock is enabled, autoblock the LAST IP(s) used
690  if ( $this->isAutoblocking() && $this->getType() == self::TYPE_USER ) {
691  wfDebug( "Doing retroactive autoblocks for " . $this->getTarget() . "\n" );
692 
693  $continue = Hooks::run(
694  'PerformRetroactiveAutoblock', [ $this, &$blockIds ] );
695 
696  if ( $continue ) {
697  self::defaultRetroactiveAutoblock( $this, $blockIds );
698  }
699  }
700  return $blockIds;
701  }
702 
710  protected static function defaultRetroactiveAutoblock( DatabaseBlock $block, array &$blockIds ) {
711  global $wgPutIPinRC;
712 
713  // No IPs are in recentchanges table, so nothing to select
714  if ( !$wgPutIPinRC ) {
715  return;
716  }
717 
718  // Autoblocks only apply to TYPE_USER
719  if ( $block->getType() !== self::TYPE_USER ) {
720  return;
721  }
722  $target = $block->getTarget(); // TYPE_USER => always a User object
723 
724  $dbr = wfGetDB( DB_REPLICA );
725  $rcQuery = ActorMigration::newMigration()->getWhere( $dbr, 'rc_user', $target, false );
726 
727  $options = [ 'ORDER BY' => 'rc_timestamp DESC' ];
728 
729  // Just the last IP used.
730  $options['LIMIT'] = 1;
731 
732  $res = $dbr->select(
733  [ 'recentchanges' ] + $rcQuery['tables'],
734  [ 'rc_ip' ],
735  $rcQuery['conds'],
736  __METHOD__,
737  $options,
738  $rcQuery['joins']
739  );
740 
741  if ( !$res->numRows() ) {
742  # No results, don't autoblock anything
743  wfDebug( "No IP found to retroactively autoblock\n" );
744  } else {
745  foreach ( $res as $row ) {
746  if ( $row->rc_ip ) {
747  $id = $block->doAutoblock( $row->rc_ip );
748  if ( $id ) {
749  $blockIds[] = $id;
750  }
751  }
752  }
753  }
754  }
755 
763  public static function isWhitelistedFromAutoblocks( $ip ) {
764  // Try to get the autoblock_whitelist from the cache, as it's faster
765  // than getting the msg raw and explode()'ing it.
766  $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
767  $lines = $cache->getWithSetCallback(
768  $cache->makeKey( 'ip-autoblock', 'whitelist' ),
769  $cache::TTL_DAY,
770  function ( $curValue, &$ttl, array &$setOpts ) {
772 
773  return explode( "\n",
774  wfMessage( 'autoblock_whitelist' )->inContentLanguage()->plain() );
775  }
776  );
777 
778  wfDebug( "Checking the autoblock whitelist..\n" );
779 
780  foreach ( $lines as $line ) {
781  # List items only
782  if ( substr( $line, 0, 1 ) !== '*' ) {
783  continue;
784  }
785 
786  $wlEntry = substr( $line, 1 );
787  $wlEntry = trim( $wlEntry );
788 
789  wfDebug( "Checking $ip against $wlEntry..." );
790 
791  # Is the IP in this range?
792  if ( IP::isInRange( $ip, $wlEntry ) ) {
793  wfDebug( " IP $ip matches $wlEntry, not autoblocking\n" );
794  return true;
795  } else {
796  wfDebug( " No match\n" );
797  }
798  }
799 
800  return false;
801  }
802 
809  public function doAutoblock( $autoblockIP ) {
810  # If autoblocks are disabled, go away.
811  if ( !$this->isAutoblocking() ) {
812  return false;
813  }
814 
815  # Check for presence on the autoblock whitelist.
816  if ( self::isWhitelistedFromAutoblocks( $autoblockIP ) ) {
817  return false;
818  }
819 
820  // Avoid PHP 7.1 warning of passing $this by reference
821  $block = $this;
822  # Allow hooks to cancel the autoblock.
823  if ( !Hooks::run( 'AbortAutoblock', [ $autoblockIP, &$block ] ) ) {
824  wfDebug( "Autoblock aborted by hook.\n" );
825  return false;
826  }
827 
828  # It's okay to autoblock. Go ahead and insert/update the block...
829 
830  # Do not add a *new* block if the IP is already blocked.
831  $ipblock = self::newFromTarget( $autoblockIP );
832  if ( $ipblock ) {
833  # Check if the block is an autoblock and would exceed the user block
834  # if renewed. If so, do nothing, otherwise prolong the block time...
835  if ( $ipblock->mAuto && // @todo Why not compare $ipblock->mExpiry?
836  $this->getExpiry() > self::getAutoblockExpiry( $ipblock->getTimestamp() )
837  ) {
838  # Reset block timestamp to now and its expiry to
839  # $wgAutoblockExpiry in the future
840  $ipblock->updateTimestamp();
841  }
842  return false;
843  }
844 
845  # Make a new block object with the desired properties.
846  $autoblock = new DatabaseBlock;
847  wfDebug( "Autoblocking {$this->getTarget()}@" . $autoblockIP . "\n" );
848  $autoblock->setTarget( $autoblockIP );
849  $autoblock->setBlocker( $this->getBlocker() );
850  $autoblock->setReason(
851  wfMessage( 'autoblocker', $this->getTarget(), $this->getReason() )
852  ->inContentLanguage()->plain()
853  );
854  $timestamp = wfTimestampNow();
855  $autoblock->setTimestamp( $timestamp );
856  $autoblock->mAuto = 1;
857  $autoblock->isCreateAccountBlocked( $this->isCreateAccountBlocked() );
858  # Continue suppressing the name if needed
859  $autoblock->setHideName( $this->getHideName() );
860  $autoblock->isUsertalkEditAllowed( $this->isUsertalkEditAllowed() );
861  $autoblock->mParentBlockId = $this->mId;
862  $autoblock->isSitewide( $this->isSitewide() );
863  $autoblock->setRestrictions( $this->getRestrictions() );
864 
865  if ( $this->getExpiry() == 'infinity' ) {
866  # Original block was indefinite, start an autoblock now
867  $autoblock->setExpiry( self::getAutoblockExpiry( $timestamp ) );
868  } else {
869  # If the user is already blocked with an expiry date, we don't
870  # want to pile on top of that.
871  $autoblock->setExpiry( min( $this->getExpiry(), self::getAutoblockExpiry( $timestamp ) ) );
872  }
873 
874  # Insert the block...
875  $status = $autoblock->insert();
876  return $status
877  ? $status['id']
878  : false;
879  }
880 
885  public function deleteIfExpired() {
886  if ( $this->isExpired() ) {
887  wfDebug( __METHOD__ . " -- deleting\n" );
888  $this->delete();
889  $retVal = true;
890  } else {
891  wfDebug( __METHOD__ . " -- not expired\n" );
892  $retVal = false;
893  }
894 
895  return $retVal;
896  }
897 
902  public function isExpired() {
903  $timestamp = wfTimestampNow();
904  wfDebug( __METHOD__ . " checking current " . $timestamp . " vs $this->mExpiry\n" );
905 
906  if ( !$this->getExpiry() ) {
907  return false;
908  } else {
909  return $timestamp > $this->getExpiry();
910  }
911  }
912 
919  public function isValid() {
920  wfDeprecated( __METHOD__, '1.33' );
921  return $this->getTarget() != null;
922  }
923 
927  public function updateTimestamp() {
928  if ( $this->mAuto ) {
929  $this->setTimestamp( wfTimestamp() );
930  $this->setExpiry( self::getAutoblockExpiry( $this->getTimestamp() ) );
931 
932  $dbw = wfGetDB( DB_MASTER );
933  $dbw->update( 'ipblocks',
934  [ /* SET */
935  'ipb_timestamp' => $dbw->timestamp( $this->getTimestamp() ),
936  'ipb_expiry' => $dbw->timestamp( $this->getExpiry() ),
937  ],
938  [ /* WHERE */
939  'ipb_id' => $this->getId(),
940  ],
941  __METHOD__
942  );
943  }
944  }
945 
951  public function getRangeStart() {
952  switch ( $this->type ) {
953  case self::TYPE_USER:
954  return '';
955  case self::TYPE_IP:
956  return IP::toHex( $this->target );
957  case self::TYPE_RANGE:
958  list( $start, /*...*/ ) = IP::parseRange( $this->target );
959  return $start;
960  default:
961  throw new MWException( "Block with invalid type" );
962  }
963  }
964 
970  public function getRangeEnd() {
971  switch ( $this->type ) {
972  case self::TYPE_USER:
973  return '';
974  case self::TYPE_IP:
975  return IP::toHex( $this->target );
976  case self::TYPE_RANGE:
977  list( /*...*/, $end ) = IP::parseRange( $this->target );
978  return $end;
979  default:
980  throw new MWException( "Block with invalid type" );
981  }
982  }
983 
987  public function getId() {
988  return $this->mId;
989  }
990 
997  private function setId( $blockId ) {
998  $this->mId = (int)$blockId;
999 
1000  if ( is_array( $this->restrictions ) ) {
1001  $this->restrictions = $this->getBlockRestrictionStore()->setBlockId(
1002  $blockId, $this->restrictions
1003  );
1004  }
1005 
1006  return $this;
1007  }
1008 
1013  public function getParentBlockId() {
1014  return $this->mParentBlockId;
1015  }
1016 
1023  public function fromMaster( $x = null ) {
1024  return wfSetVar( $this->mFromMaster, $x );
1025  }
1026 
1032  public function isHardblock( $x = null ) {
1033  wfSetVar( $this->isHardblock, $x );
1034 
1035  # You can't *not* hardblock a user
1036  return $this->getType() == self::TYPE_USER
1037  ? true
1039  }
1040 
1045  public function isAutoblocking( $x = null ) {
1046  wfSetVar( $this->isAutoblocking, $x );
1047 
1048  # You can't put an autoblock on an IP or range as we don't have any history to
1049  # look over to get more IPs from
1050  return $this->getType() == self::TYPE_USER
1051  ? $this->isAutoblocking
1052  : false;
1053  }
1054 
1059  public function getRedactedName() {
1060  if ( $this->mAuto ) {
1061  return Html::element(
1062  'span',
1063  [ 'class' => 'mw-autoblockid' ],
1064  wfMessage( 'autoblockid', $this->mId )->text()
1065  );
1066  } else {
1067  return htmlspecialchars( $this->getTarget() );
1068  }
1069  }
1070 
1077  public static function getAutoblockExpiry( $timestamp ) {
1078  global $wgAutoblockExpiry;
1079 
1080  return wfTimestamp( TS_MW, wfTimestamp( TS_UNIX, $timestamp ) + $wgAutoblockExpiry );
1081  }
1082 
1086  public static function purgeExpired() {
1087  if ( wfReadOnly() ) {
1088  return;
1089  }
1090 
1092  wfGetDB( DB_MASTER ),
1093  __METHOD__,
1094  function ( IDatabase $dbw, $fname ) {
1095  $ids = $dbw->selectFieldValues( 'ipblocks',
1096  'ipb_id',
1097  [ 'ipb_expiry < ' . $dbw->addQuotes( $dbw->timestamp() ) ],
1098  $fname
1099  );
1100  if ( $ids ) {
1101  $blockRestrictionStore = MediaWikiServices::getInstance()->getBlockRestrictionStore();
1102  $blockRestrictionStore->deleteByBlockId( $ids );
1103 
1104  $dbw->delete( 'ipblocks', [ 'ipb_id' => $ids ], $fname );
1105  }
1106  }
1107  ) );
1108  }
1109 
1130  public static function newFromTarget( $specificTarget, $vagueTarget = null, $fromMaster = false ) {
1131  $blocks = self::newListFromTarget( $specificTarget, $vagueTarget, $fromMaster );
1132  return self::chooseMostSpecificBlock( $blocks );
1133  }
1134 
1144  public static function newListFromTarget(
1145  $specificTarget,
1146  $vagueTarget = null,
1147  $fromMaster = false
1148  ) {
1149  list( $target, $type ) = self::parseTarget( $specificTarget );
1150  if ( $type == self::TYPE_ID || $type == self::TYPE_AUTO ) {
1151  $block = self::newFromID( $target );
1152  return $block ? [ $block ] : [];
1153  } elseif ( $target === null && $vagueTarget == '' ) {
1154  # We're not going to find anything useful here
1155  # Be aware that the == '' check is explicit, since empty values will be
1156  # passed by some callers (T31116)
1157  return [];
1158  } elseif ( in_array(
1159  $type,
1160  [ self::TYPE_USER, self::TYPE_IP, self::TYPE_RANGE, null ] )
1161  ) {
1162  return self::newLoad( $target, $type, $fromMaster, $vagueTarget );
1163  }
1164  return [];
1165  }
1166 
1177  public static function getBlocksForIPList( array $ipChain, $isAnon, $fromMaster = false ) {
1178  if ( $ipChain === [] ) {
1179  return [];
1180  }
1181 
1182  $conds = [];
1183  $proxyLookup = MediaWikiServices::getInstance()->getProxyLookup();
1184  foreach ( array_unique( $ipChain ) as $ipaddr ) {
1185  # Discard invalid IP addresses. Since XFF can be spoofed and we do not
1186  # necessarily trust the header given to us, make sure that we are only
1187  # checking for blocks on well-formatted IP addresses (IPv4 and IPv6).
1188  # Do not treat private IP spaces as special as it may be desirable for wikis
1189  # to block those IP ranges in order to stop misbehaving proxies that spoof XFF.
1190  if ( !IP::isValid( $ipaddr ) ) {
1191  continue;
1192  }
1193  # Don't check trusted IPs (includes local CDNs which will be in every request)
1194  if ( $proxyLookup->isTrustedProxy( $ipaddr ) ) {
1195  continue;
1196  }
1197  # Check both the original IP (to check against single blocks), as well as build
1198  # the clause to check for rangeblocks for the given IP.
1199  $conds['ipb_address'][] = $ipaddr;
1200  $conds[] = self::getRangeCond( IP::toHex( $ipaddr ) );
1201  }
1202 
1203  if ( $conds === [] ) {
1204  return [];
1205  }
1206 
1207  if ( $fromMaster ) {
1208  $db = wfGetDB( DB_MASTER );
1209  } else {
1210  $db = wfGetDB( DB_REPLICA );
1211  }
1212  $conds = $db->makeList( $conds, LIST_OR );
1213  if ( !$isAnon ) {
1214  $conds = [ $conds, 'ipb_anon_only' => 0 ];
1215  }
1216  $blockQuery = self::getQueryInfo();
1217  $rows = $db->select(
1218  $blockQuery['tables'],
1219  array_merge( [ 'ipb_range_start', 'ipb_range_end' ], $blockQuery['fields'] ),
1220  $conds,
1221  __METHOD__,
1222  [],
1223  $blockQuery['joins']
1224  );
1225 
1226  $blocks = [];
1227  foreach ( $rows as $row ) {
1228  $block = self::newFromRow( $row );
1229  if ( !$block->isExpired() ) {
1230  $blocks[] = $block;
1231  }
1232  }
1233 
1234  return $blocks;
1235  }
1236 
1258  public static function chooseBlock( array $blocks, array $ipChain ) {
1259  if ( $blocks === [] ) {
1260  return null;
1261  } elseif ( count( $blocks ) == 1 ) {
1262  return $blocks[0];
1263  }
1264 
1265  // Sort hard blocks before soft ones and secondarily sort blocks
1266  // that disable account creation before those that don't.
1267  usort( $blocks, function ( DatabaseBlock $a, DatabaseBlock $b ) {
1268  $aWeight = (int)$a->isHardblock() . (int)$a->appliesToRight( 'createaccount' );
1269  $bWeight = (int)$b->isHardblock() . (int)$b->appliesToRight( 'createaccount' );
1270  return strcmp( $bWeight, $aWeight ); // highest weight first
1271  } );
1272 
1273  $blocksListExact = [
1274  'hard' => false,
1275  'disable_create' => false,
1276  'other' => false,
1277  'auto' => false
1278  ];
1279  $blocksListRange = [
1280  'hard' => false,
1281  'disable_create' => false,
1282  'other' => false,
1283  'auto' => false
1284  ];
1285  $ipChain = array_reverse( $ipChain );
1286 
1287  foreach ( $blocks as $block ) {
1288  // Stop searching if we have already have a "better" block. This
1289  // is why the order of the blocks matters
1290  if ( !$block->isHardblock() && $blocksListExact['hard'] ) {
1291  break;
1292  } elseif ( !$block->appliesToRight( 'createaccount' ) && $blocksListExact['disable_create'] ) {
1293  break;
1294  }
1295 
1296  foreach ( $ipChain as $checkip ) {
1297  $checkipHex = IP::toHex( $checkip );
1298  if ( (string)$block->getTarget() === $checkip ) {
1299  if ( $block->isHardblock() ) {
1300  $blocksListExact['hard'] = $blocksListExact['hard'] ?: $block;
1301  } elseif ( $block->appliesToRight( 'createaccount' ) ) {
1302  $blocksListExact['disable_create'] = $blocksListExact['disable_create'] ?: $block;
1303  } elseif ( $block->mAuto ) {
1304  $blocksListExact['auto'] = $blocksListExact['auto'] ?: $block;
1305  } else {
1306  $blocksListExact['other'] = $blocksListExact['other'] ?: $block;
1307  }
1308  // We found closest exact match in the ip list, so go to the next block
1309  break;
1310  } elseif ( array_filter( $blocksListExact ) == []
1311  && $block->getRangeStart() <= $checkipHex
1312  && $block->getRangeEnd() >= $checkipHex
1313  ) {
1314  if ( $block->isHardblock() ) {
1315  $blocksListRange['hard'] = $blocksListRange['hard'] ?: $block;
1316  } elseif ( $block->appliesToRight( 'createaccount' ) ) {
1317  $blocksListRange['disable_create'] = $blocksListRange['disable_create'] ?: $block;
1318  } elseif ( $block->mAuto ) {
1319  $blocksListRange['auto'] = $blocksListRange['auto'] ?: $block;
1320  } else {
1321  $blocksListRange['other'] = $blocksListRange['other'] ?: $block;
1322  }
1323  break;
1324  }
1325  }
1326  }
1327 
1328  if ( array_filter( $blocksListExact ) == [] ) {
1329  $blocksList = &$blocksListRange;
1330  } else {
1331  $blocksList = &$blocksListExact;
1332  }
1333 
1334  $chosenBlock = null;
1335  if ( $blocksList['hard'] ) {
1336  $chosenBlock = $blocksList['hard'];
1337  } elseif ( $blocksList['disable_create'] ) {
1338  $chosenBlock = $blocksList['disable_create'];
1339  } elseif ( $blocksList['other'] ) {
1340  $chosenBlock = $blocksList['other'];
1341  } elseif ( $blocksList['auto'] ) {
1342  $chosenBlock = $blocksList['auto'];
1343  } else {
1344  throw new MWException( "Proxy block found, but couldn't be classified." );
1345  }
1346 
1347  return $chosenBlock;
1348  }
1349 
1356  public function getType() {
1357  return $this->mAuto
1358  ? self::TYPE_AUTO
1359  : parent::getType();
1360  }
1361 
1370  public function setCookie( WebResponse $response ) {
1371  MediaWikiServices::getInstance()->getBlockManager()->setBlockCookie( $this, $response );
1372  }
1373 
1381  public static function clearCookie( WebResponse $response ) {
1382  MediaWikiServices::getInstance()->getBlockManager()->clearBlockCookie( $response );
1383  }
1384 
1395  public function getCookieValue() {
1396  return MediaWikiServices::getInstance()->getBlockManager()->getCookieValue( $this );
1397  }
1398 
1408  public static function getIdFromCookieValue( $cookieValue ) {
1409  return MediaWikiServices::getInstance()->getBlockManager()->getIdFromCookieValue( $cookieValue );
1410  }
1411 
1418  $params = $this->getBlockErrorParams( $context );
1419 
1420  $msg = 'blockedtext';
1421  if ( $this->mAuto ) {
1422  $msg = 'autoblockedtext';
1423  } elseif ( !$this->isSitewide() ) {
1424  $msg = 'blockedtext-partial';
1425  }
1426 
1427  array_unshift( $params, $msg );
1428 
1429  return $params;
1430  }
1431 
1441  public function getRestrictions() {
1442  if ( $this->restrictions === null ) {
1443  // If the block id has not been set, then do not attempt to load the
1444  // restrictions.
1445  if ( !$this->mId ) {
1446  return [];
1447  }
1448  $this->restrictions = $this->getBlockRestrictionStore()->loadByBlockId( $this->mId );
1449  }
1450 
1451  return $this->restrictions;
1452  }
1453 
1461  public function setRestrictions( array $restrictions ) {
1462  $this->restrictions = array_filter( $restrictions, function ( $restriction ) {
1463  return $restriction instanceof Restriction;
1464  } );
1465 
1466  return $this;
1467  }
1468 
1472  public function appliesToTitle( Title $title ) {
1473  if ( $this->isSitewide() ) {
1474  return true;
1475  }
1476 
1477  $restrictions = $this->getRestrictions();
1478  foreach ( $restrictions as $restriction ) {
1479  if ( $restriction->matches( $title ) ) {
1480  return true;
1481  }
1482  }
1483 
1484  return false;
1485  }
1486 
1490  public function appliesToNamespace( $ns ) {
1491  if ( $this->isSitewide() ) {
1492  return true;
1493  }
1494 
1495  // Blocks do not apply to virtual namespaces.
1496  if ( $ns < 0 ) {
1497  return false;
1498  }
1499 
1500  $restriction = $this->findRestriction( NamespaceRestriction::TYPE, $ns );
1501 
1502  return (bool)$restriction;
1503  }
1504 
1508  public function appliesToPage( $pageId ) {
1509  if ( $this->isSitewide() ) {
1510  return true;
1511  }
1512 
1513  // If the pageId is not over zero, the block cannot apply to it.
1514  if ( $pageId <= 0 ) {
1515  return false;
1516  }
1517 
1518  $restriction = $this->findRestriction( PageRestriction::TYPE, $pageId );
1519 
1520  return (bool)$restriction;
1521  }
1522 
1530  private function findRestriction( $type, $value ) {
1531  $restrictions = $this->getRestrictions();
1532  foreach ( $restrictions as $restriction ) {
1533  if ( $restriction->getType() !== $type ) {
1534  continue;
1535  }
1536 
1537  if ( $restriction->getValue() === $value ) {
1538  return $restriction;
1539  }
1540  }
1541 
1542  return null;
1543  }
1544 
1550  public function shouldTrackWithCookie( $isAnon ) {
1551  wfDeprecated( __METHOD__, '1.34' );
1552  $config = RequestContext::getMain()->getConfig();
1553  switch ( $this->getType() ) {
1554  case self::TYPE_IP:
1555  case self::TYPE_RANGE:
1556  return $isAnon && $config->get( 'CookieSetOnIpBlock' );
1557  case self::TYPE_USER:
1558  return !$isAnon && $config->get( 'CookieSetOnAutoblock' ) && $this->isAutoblocking();
1559  default:
1560  return false;
1561  }
1562  }
1563 
1570  return MediaWikiServices::getInstance()->getBlockRestrictionStore();
1571  }
1572 }
1573 
1577 class_alias( DatabaseBlock::class, 'Block' );
insert(IDatabase $dbw=null)
Insert a block into the block table.
isUsertalkEditAllowed( $x=null)
Get or set the flag indicating whether this block blocks the target from editing their own user talk ...
Config $config
Definition: MediaWiki.php:43
static chooseBlock(array $blocks, array $ipChain)
From a list of multiple blocks, find the most exact and strongest block.
$response
initFromRow( $row)
Given a database row from the ipblocks table, initialize member variables.
static toHex( $ip)
Return a zero-padded upper case hexadecimal representation of an IP address.
Definition: IP.php:404
isCreateAccountBlocked( $x=null)
Get or set the flag indicating whether this block blocks the target from creating an account...
static element( $element, $attribs=[], $contents='')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
Definition: Html.php:231
getRangeStart()
Get the IP address at the start of the range in Hex form.
getDatabaseArray(IDatabase $dbw)
Get an array suitable for passing to $dbw->insert() or $dbw->update()
__construct(array $options=[])
Create a new block with specified option parameters on a user, IP or IP range.
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:500
$success
int $type
AbstractBlock::TYPE_ constant.
equals(DatabaseBlock $block)
Check if two blocks are effectively equal.
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
static newFromAnyId( $userId, $userName, $actorId, $dbDomain=false)
Static factory method for creation from an ID, name, and/or actor ID.
Definition: User.php:596
getAutoblockUpdateArray(IDatabase $dbw)
getCookieValue()
Get the BlockID cookie&#39;s value for this block.
deleteIfExpired()
Check if a block has expired.
setBlocker( $user)
Set the user who implemented (or will implement) this block.
A DatabaseBlock (unlike a SystemBlock) is stored in the database, may give rise to autoblocks and may...
static getInstance()
Returns the global default instance of the top level service locator.
const DB_MASTER
Definition: defines.php:26
get( $name)
Get a configuration variable such as "Sitename" or "UploadMaintenance.".
doRetroactiveAutoblock()
Retroactively autoblocks the last IP used by the user (if it is a user) blocked by this block...
timestamp( $ts=0)
Convert a timestamp in one of the formats accepted by ConvertibleTimestamp to the format used for ins...
static getBlocksForIPList(array $ipChain, $isAnon, $fromMaster=false)
Get all blocks that match any IP from an array of IP addresses.
static defaultRetroactiveAutoblock(DatabaseBlock $block, array &$blockIds)
Retroactively autoblocks the last IP used by the user (if it is a user) blocked by this block...
The User object encapsulates all of the user-specific settings (user_id, name, rights, email address, options, last login time).
Definition: User.php:51
int $forcedTargetID
Hack for foreign blocking (CentralAuth)
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
$wgBlockCIDRLimit
Limits on the possible sizes of range blocks.
static isWhitelistedFromAutoblocks( $ip)
Checks whether a given IP is on the autoblock whitelist.
wfReadOnly()
Check whether the wiki is in read-only mode.
static newMigration()
Static constructor.
static getMain()
Get the RequestContext object associated with the main request.
IContextSource $context
Definition: MediaWiki.php:38
const LIST_AND
Definition: Defines.php:39
setRestrictions(array $restrictions)
Set Restrictions.
isExpired()
Has the block expired?
getRangeEnd()
Get the IP address at the end of the range in Hex form.
isSitewide( $x=null)
Indicates that the block is a sitewide block.
fromMaster( $x=null)
Get/set a flag determining whether the master is used for reads.
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
$wgBlockDisablesLogin
If true, blocked users will not be allowed to login.
static isValid( $ip)
Validate an IP address.
Definition: IP.php:111
getRedactedName()
Get the block name, but with autoblocked IPs hidden as per standard privacy policy.
static getRangeCond( $start, $end=null)
Get a set of SQL conditions which will select rangeblocks encompassing a given range.
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
$wgPutIPinRC
Log IP addresses in the recentchanges table; can be accessed only by extensions (e.g.
$cache
Definition: mcc.php:33
encodeExpiry( $expiry)
Encode an expiry time into the DBMS dependent format.
static newLoad( $specificTarget, $specificType, $fromMaster, $vagueTarget=null)
Load blocks from the database which target the specific target exactly, or which cover the vague targ...
getBlockErrorParams(IContextSource $context)
Get block information used in different block error messages.
isEmailBlocked( $x=null)
Get or set the flag indicating whether this block blocks the target from sending emails.
static isInRange( $addr, $range)
Determine if a given IPv4/IPv6 address is in a given CIDR network.
Definition: IP.php:637
static purgeExpired()
Purge expired blocks from the ipblocks table.
static newFromRow( $row)
Create a new DatabaseBlock object from a database row.
getPermissionsError(IContextSource $context)
appliesToRight( $right)
Determine whether the block prevents a given right.
getBlockRestrictionStore()
Get a BlockRestrictionStore instance.
static getIdFromCookieValue( $cookieValue)
Get the stored ID from the &#39;BlockID&#39; cookie.
const LIST_OR
Definition: Defines.php:42
getTimestamp()
Get the timestamp indicating when the block was created.
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...
setTimestamp( $timestamp)
Set the timestamp indicating when the block was created.
static isIPv6( $ip)
Given a string, determine if it as valid IP in IPv6 only.
Definition: IP.php:88
selectFieldValues( $table, $var, $cond='', $fname=__METHOD__, $options=[], $join_conds=[])
A SELECT wrapper which returns a list of single field values from result rows.
getBlocker()
Get the user who implemented this block.
static addUpdate(DeferrableUpdate $update, $stage=self::POSTSEND)
Add an update to the deferred list to be run later by execute()
$lines
Definition: router.php:61
static getStore()
static getAutoblockExpiry( $timestamp)
Get a timestamp of the expiry for autoblocks.
Basic database interface for live and lazy-loaded relation database handles.
Definition: IDatabase.php:38
getId()
Get the user&#39;s ID.
Definition: User.php:2203
getHideName()
Get whether the block hides the target&#39;s username.
update()
Update a block in the DB with new parameters.
static getQueryInfo()
Return the tables, fields, and join conditions to be selected to create a new block object...
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
$line
Definition: cdb.php:59
static clearCookie(WebResponse $response)
Unset the &#39;BlockID&#39; cookie.
isHardblock( $x=null)
Get/set whether the block is a hardblock (affects logged-in users on a given IP/range) ...
setHideName( $hideName)
Set whether ths block hides the target&#39;s username.
setId( $blockId)
Set the block ID.
setTarget( $target)
Set the target for this block, and update $this->type accordingly.
setExpiry( $expiry)
Set the block expiry time.
getExpiry()
Get the block expiry time.
static getCacheSetOptions(IDatabase $db1, IDatabase $db2=null)
Merge the result of getSessionLagStatus() for several DBs using the most pessimistic values to estima...
Definition: Database.php:4403
getTarget()
Get the target for this particular block.
const DB_REPLICA
Definition: defines.php:25
getRestrictions()
Get Restrictions.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
static newListFromTarget( $specificTarget, $vagueTarget=null, $fromMaster=false)
This is similar to DatabaseBlock::newFromTarget, but it returns all the relevant blocks.
static newFromID( $id)
Load a block from the block id.
static getIpFragment( $hex)
Get the component of an IP address which is certain to be the same between an IP address and a rangeb...
doAutoblock( $autoblockIP)
Autoblocks the given IP, referring to this block.
isValid()
Is the block address valid (i.e.
delete( $table, $conds, $fname=__METHOD__)
DELETE query wrapper.
findRestriction( $type, $value)
Find Restriction by type and value.
setReason( $reason)
Set the reason for creating the block.
static parseCIDR( $range)
Convert a network specification in CIDR notation to an integer network and a number of bits...
Definition: IP.php:457
addQuotes( $s)
Escape and quote a raw value string for use in a SQL query.
static chooseMostSpecificBlock(array $blocks)
Choose the most specific block from some combination of user, IP and IP range blocks.
static newFromTarget( $specificTarget, $vagueTarget=null, $fromMaster=false)
Given a target and the target&#39;s type, get an existing block object if possible.
getReason()
Get the reason given for creating the block.
return true
Definition: router.php:82
setCookie(WebResponse $response)
Set the &#39;BlockID&#39; cookie to this block&#39;s ID and expiry time.
updateTimestamp()
Update the timestamp on autoblocks.
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:200
$wgAutoblockExpiry
Number of seconds before autoblock entries expire.