MediaWiki  master
DatabaseBlock.php
Go to the documentation of this file.
1 <?php
23 namespace MediaWiki\Block;
24 
25 use CommentStore;
26 use Hooks;
27 use Html;
35 use MWException;
36 use stdClass;
37 use Title;
38 use Wikimedia\IPUtils;
41 
55  public $mAuto;
56 
62 
64  private $mId;
65 
67  private $mFromPrimary;
68 
70  private $isAutoblocking;
71 
73  private $restrictions;
74 
76  private $blocker;
77 
97  public function __construct( array $options = [] ) {
98  parent::__construct( $options );
99 
100  $defaults = [
101  'user' => null,
102  'auto' => false,
103  'expiry' => '',
104  'createAccount' => false,
105  'enableAutoblock' => false,
106  'blockEmail' => false,
107  'allowUsertalk' => false,
108  'sitewide' => true,
109  'by' => null,
110  ];
111 
112  $options += $defaults;
113 
114  if ( $options['by'] && $options['by'] instanceof UserIdentity ) {
115  $this->setBlocker( $options['by'] );
116  }
117 
118  $this->setExpiry( wfGetDB( DB_REPLICA )->decodeExpiry( $options['expiry'] ) );
119 
120  # Boolean settings
121  $this->mAuto = (bool)$options['auto'];
122  $this->isAutoblocking( (bool)$options['enableAutoblock'] );
123  $this->isSitewide( (bool)$options['sitewide'] );
124  $this->isEmailBlocked( (bool)$options['blockEmail'] );
125  $this->isCreateAccountBlocked( (bool)$options['createAccount'] );
126  $this->isUsertalkEditAllowed( (bool)$options['allowUsertalk'] );
127 
128  $this->mFromPrimary = false;
129  }
130 
137  public static function newFromID( $id ) {
138  $dbr = wfGetDB( DB_REPLICA );
139  $blockQuery = self::getQueryInfo();
140  $res = $dbr->selectRow(
141  $blockQuery['tables'],
142  $blockQuery['fields'],
143  [ 'ipb_id' => $id ],
144  __METHOD__,
145  [],
146  $blockQuery['joins']
147  );
148  if ( $res ) {
149  return self::newFromRow( $res );
150  } else {
151  return null;
152  }
153  }
154 
169  public static function getQueryInfo() {
170  $commentQuery = CommentStore::getStore()->getJoin( 'ipb_reason' );
171  return [
172  'tables' => [
173  'ipblocks',
174  'ipblocks_actor' => 'actor'
175  ] + $commentQuery['tables'],
176  'fields' => [
177  'ipb_id',
178  'ipb_address',
179  'ipb_timestamp',
180  'ipb_auto',
181  'ipb_anon_only',
182  'ipb_create_account',
183  'ipb_enable_autoblock',
184  'ipb_expiry',
185  'ipb_deleted',
186  'ipb_block_email',
187  'ipb_allow_usertalk',
188  'ipb_parent_block_id',
189  'ipb_sitewide',
190  'ipb_by_actor',
191  'ipb_by' => 'ipblocks_actor.actor_user',
192  'ipb_by_text' => 'ipblocks_actor.actor_name'
193  ] + $commentQuery['fields'],
194  'joins' => [
195  'ipblocks_actor' => [ 'JOIN', 'actor_id=ipb_by_actor' ]
196  ] + $commentQuery['joins'],
197  ];
198  }
199 
207  public function equals( DatabaseBlock $block ) {
208  return (
209  (string)$this->target == (string)$block->target
210  && $this->type == $block->type
211  && $this->mAuto == $block->mAuto
212  && $this->isHardblock() == $block->isHardblock()
213  && $this->isCreateAccountBlocked() == $block->isCreateAccountBlocked()
214  && $this->getExpiry() == $block->getExpiry()
215  && $this->isAutoblocking() == $block->isAutoblocking()
216  && $this->getHideName() == $block->getHideName()
217  && $this->isEmailBlocked() == $block->isEmailBlocked()
218  && $this->isUsertalkEditAllowed() == $block->isUsertalkEditAllowed()
219  && $this->getReasonComment()->text == $block->getReasonComment()->text
220  && $this->isSitewide() == $block->isSitewide()
221  // DatabaseBlock::getRestrictions() may perform a database query, so
222  // keep it at the end.
223  && $this->getBlockRestrictionStore()->equals(
224  $this->getRestrictions(), $block->getRestrictions()
225  )
226  );
227  }
228 
241  protected static function newLoad(
242  $specificTarget,
243  $specificType,
244  $fromPrimary,
245  $vagueTarget = null
246  ) {
247  $db = wfGetDB( $fromPrimary ? DB_PRIMARY : DB_REPLICA );
248 
249  if ( $specificType !== null ) {
250  $conds = [ 'ipb_address' => [ (string)$specificTarget ] ];
251  } else {
252  $conds = [ 'ipb_address' => [] ];
253  }
254 
255  # Be aware that the != '' check is explicit, since empty values will be
256  # passed by some callers (T31116)
257  if ( $vagueTarget != '' ) {
259  ->getBlockUtils()
260  ->parseBlockTarget( $vagueTarget );
261  switch ( $type ) {
262  case self::TYPE_USER:
263  # Slightly weird, but who are we to argue?
264  $conds['ipb_address'][] = (string)$target;
265  $conds = $db->makeList( $conds, LIST_OR );
266  break;
267 
268  case self::TYPE_IP:
269  $conds['ipb_address'][] = (string)$target;
270  $conds['ipb_address'] = array_unique( $conds['ipb_address'] );
271  $conds[] = self::getRangeCond( IPUtils::toHex( $target ) );
272  $conds = $db->makeList( $conds, LIST_OR );
273  break;
274 
275  case self::TYPE_RANGE:
276  list( $start, $end ) = IPUtils::parseRange( $target );
277  $conds['ipb_address'][] = (string)$target;
278  $conds[] = self::getRangeCond( $start, $end );
279  $conds = $db->makeList( $conds, LIST_OR );
280  break;
281 
282  default:
283  throw new MWException( "Tried to load block with invalid type" );
284  }
285  }
286 
287  $blockQuery = self::getQueryInfo();
288  $res = $db->select(
289  $blockQuery['tables'],
290  $blockQuery['fields'],
291  $conds,
292  __METHOD__,
293  [],
294  $blockQuery['joins']
295  );
296 
297  $blocks = [];
298  $blockIds = [];
299  $autoBlocks = [];
300  foreach ( $res as $row ) {
301  $block = self::newFromRow( $row );
302 
303  # Don't use expired blocks
304  if ( $block->isExpired() ) {
305  continue;
306  }
307 
308  # Don't use anon only blocks on users
309  if ( $specificType == self::TYPE_USER && !$block->isHardblock() ) {
310  continue;
311  }
312 
313  // Check for duplicate autoblocks
314  if ( $block->getType() === self::TYPE_AUTO ) {
315  $autoBlocks[] = $block;
316  } else {
317  $blocks[] = $block;
318  $blockIds[] = $block->getId();
319  }
320  }
321 
322  // Only add autoblocks that aren't duplicates
323  foreach ( $autoBlocks as $block ) {
324  if ( !in_array( $block->mParentBlockId, $blockIds ) ) {
325  $blocks[] = $block;
326  }
327  }
328 
329  return $blocks;
330  }
331 
342  protected static function chooseMostSpecificBlock( array $blocks ) {
343  if ( count( $blocks ) === 1 ) {
344  return $blocks[0];
345  }
346 
347  # This result could contain a block on the user, a block on the IP, and a russian-doll
348  # set of rangeblocks. We want to choose the most specific one, so keep a leader board.
349  $bestBlock = null;
350 
351  # Lower will be better
352  $bestBlockScore = 100;
353  foreach ( $blocks as $block ) {
354  if ( $block->getType() == self::TYPE_RANGE ) {
355  # This is the number of bits that are allowed to vary in the block, give
356  # or take some floating point errors
357  $target = $block->getTargetName();
358  $max = IPUtils::isIPv6( $target ) ? 128 : 32;
359  list( $network, $bits ) = IPUtils::parseCIDR( $target );
360  $size = $max - $bits;
361 
362  # Rank a range block covering a single IP equally with a single-IP block
363  $score = self::TYPE_RANGE - 1 + ( $size / $max );
364 
365  } else {
366  $score = $block->getType();
367  }
368 
369  if ( $score < $bestBlockScore ) {
370  $bestBlockScore = $score;
371  $bestBlock = $block;
372  }
373  }
374 
375  return $bestBlock;
376  }
377 
384  public static function getRangeCond( $start, $end = null ) {
385  if ( $end === null ) {
386  $end = $start;
387  }
388  # Per T16634, we want to include relevant active rangeblocks; for
389  # rangeblocks, we want to include larger ranges which enclose the given
390  # range. We know that all blocks must be smaller than $wgBlockCIDRLimit,
391  # so we can improve performance by filtering on a LIKE clause
392  $chunk = self::getIpFragment( $start );
393  $dbr = wfGetDB( DB_REPLICA );
394  $like = $dbr->buildLike( $chunk, $dbr->anyString() );
395 
396  # Fairly hard to make a malicious SQL statement out of hex characters,
397  # but stranger things have happened...
398  $safeStart = $dbr->addQuotes( $start );
399  $safeEnd = $dbr->addQuotes( $end );
400 
401  return $dbr->makeList(
402  [
403  "ipb_range_start $like",
404  "ipb_range_start <= $safeStart",
405  "ipb_range_end >= $safeEnd",
406  ],
407  LIST_AND
408  );
409  }
410 
417  protected static function getIpFragment( $hex ) {
418  global $wgBlockCIDRLimit;
419  if ( substr( $hex, 0, 3 ) == 'v6-' ) {
420  return 'v6-' . substr( substr( $hex, 3 ), 0, floor( $wgBlockCIDRLimit['IPv6'] / 4 ) );
421  } else {
422  return substr( $hex, 0, floor( $wgBlockCIDRLimit['IPv4'] / 4 ) );
423  }
424  }
425 
431  protected function initFromRow( $row ) {
432  $this->setTarget( $row->ipb_address );
433 
434  $this->setTimestamp( wfTimestamp( TS_MW, $row->ipb_timestamp ) );
435  $this->mAuto = (bool)$row->ipb_auto;
436  $this->setHideName( (bool)$row->ipb_deleted );
437  $this->mId = (int)$row->ipb_id;
438  $this->mParentBlockId = (int)$row->ipb_parent_block_id;
439 
441  ->getActorNormalization()
442  ->newActorFromRowFields( $row->ipb_by, $row->ipb_by_text, $row->ipb_by_actor ) );
443 
444  // I wish I didn't have to do this
445  $db = wfGetDB( DB_REPLICA );
446  $this->setExpiry( $db->decodeExpiry( $row->ipb_expiry ) );
447  $this->setReason(
449  // Legacy because $row may have come from self::selectFields()
450  ->getCommentLegacy( $db, 'ipb_reason', $row )
451  );
452 
453  $this->isHardblock( !$row->ipb_anon_only );
454  $this->isAutoblocking( (bool)$row->ipb_enable_autoblock );
455  $this->isSitewide( (bool)$row->ipb_sitewide );
456 
457  $this->isCreateAccountBlocked( (bool)$row->ipb_create_account );
458  $this->isEmailBlocked( (bool)$row->ipb_block_email );
459  $this->isUsertalkEditAllowed( (bool)$row->ipb_allow_usertalk );
460  }
461 
467  public static function newFromRow( $row ) {
468  $block = new DatabaseBlock;
469  $block->initFromRow( $row );
470  return $block;
471  }
472 
480  public function delete() {
482  ->getDatabaseBlockStore()
483  ->deleteBlock( $this );
484  }
485 
495  public function insert( IDatabase $dbw = null ) {
497  ->getDatabaseBlockStore()
498  ->insertBlock( $this, $dbw );
499  }
500 
509  public function update() {
511  ->getDatabaseBlockStore()
512  ->updateBlock( $this );
513  }
514 
523  public static function isWhitelistedFromAutoblocks( $ip ) {
524  // Hard-deprecated since MW 1.37.
525  wfDeprecated( __METHOD__, '1.36' );
526  return self::isExemptedFromAutoblocks( $ip );
527  }
528 
538  public static function isExemptedFromAutoblocks( $ip ) {
539  // Try to get the ip-autoblock_exemption from the cache, as it's faster
540  // than getting the msg raw and explode()'ing it.
541  $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
542  $lines = $cache->getWithSetCallback(
543  $cache->makeKey( 'ip-autoblock', 'exemption' ),
544  $cache::TTL_DAY,
545  static function ( $curValue, &$ttl, array &$setOpts ) {
547 
548  return explode( "\n",
549  wfMessage( 'block-autoblock-exemptionlist' )->inContentLanguage()->plain()
550  );
551  }
552  );
553 
554  wfDebug( "Checking the autoblock exemption list.." );
555 
556  foreach ( $lines as $line ) {
557  # List items only
558  if ( substr( $line, 0, 1 ) !== '*' ) {
559  continue;
560  }
561 
562  $wlEntry = substr( $line, 1 );
563  $wlEntry = trim( $wlEntry );
564 
565  wfDebug( "Checking $ip against $wlEntry..." );
566 
567  # Is the IP in this range?
568  if ( IPUtils::isInRange( $ip, $wlEntry ) ) {
569  wfDebug( " IP $ip matches $wlEntry, not autoblocking" );
570  return true;
571  } else {
572  wfDebug( " No match" );
573  }
574  }
575 
576  return false;
577  }
578 
585  public function doAutoblock( $autoblockIP ) {
586  # If autoblocks are disabled, go away.
587  if ( !$this->isAutoblocking() ) {
588  return false;
589  }
590 
591  # Check if autoblock exempt.
592  if ( self::isExemptedFromAutoblocks( $autoblockIP ) ) {
593  return false;
594  }
595 
596  # Allow hooks to cancel the autoblock.
597  if ( !Hooks::runner()->onAbortAutoblock( $autoblockIP, $this ) ) {
598  wfDebug( "Autoblock aborted by hook." );
599  return false;
600  }
601 
602  # It's okay to autoblock. Go ahead and insert/update the block...
603 
604  # Do not add a *new* block if the IP is already blocked.
605  $ipblock = self::newFromTarget( $autoblockIP );
606  if ( $ipblock ) {
607  # Check if the block is an autoblock and would exceed the user block
608  # if renewed. If so, do nothing, otherwise prolong the block time...
609  if ( $ipblock->mAuto && // @todo Why not compare $ipblock->mExpiry?
610  $this->getExpiry() > self::getAutoblockExpiry( $ipblock->getTimestamp() )
611  ) {
612  # Reset block timestamp to now and its expiry to
613  # $wgAutoblockExpiry in the future
614  $ipblock->updateTimestamp();
615  }
616  return false;
617  }
618 
619  # Make a new block object with the desired properties.
620  $autoblock = new DatabaseBlock;
621  wfDebug( "Autoblocking {$this->getTargetName()}@" . $autoblockIP );
622  $autoblock->setTarget( $autoblockIP );
623  $autoblock->setBlocker( $this->getBlocker() );
624  $autoblock->setReason(
625  wfMessage(
626  'autoblocker',
627  $this->getTargetName(),
628  $this->getReasonComment()->text
629  )->inContentLanguage()->plain()
630  );
631  $timestamp = wfTimestampNow();
632  $autoblock->setTimestamp( $timestamp );
633  $autoblock->mAuto = true;
634  $autoblock->isCreateAccountBlocked( $this->isCreateAccountBlocked() );
635  # Continue suppressing the name if needed
636  $autoblock->setHideName( $this->getHideName() );
637  $autoblock->isUsertalkEditAllowed( $this->isUsertalkEditAllowed() );
638  $autoblock->mParentBlockId = $this->mId;
639  $autoblock->isSitewide( $this->isSitewide() );
640  $autoblock->setRestrictions( $this->getRestrictions() );
641 
642  if ( $this->getExpiry() == 'infinity' ) {
643  # Original block was indefinite, start an autoblock now
644  $autoblock->setExpiry( self::getAutoblockExpiry( $timestamp ) );
645  } else {
646  # If the user is already blocked with an expiry date, we don't
647  # want to pile on top of that.
648  $autoblock->setExpiry( min( $this->getExpiry(), self::getAutoblockExpiry( $timestamp ) ) );
649  }
650 
651  # Insert the block...
652  $status = MediaWikiServices::getInstance()->getDatabaseBlockStore()->insertBlock(
653  $autoblock
654  );
655  return $status
656  ? $status['id']
657  : false;
658  }
659 
664  public function isExpired() {
665  $timestamp = wfTimestampNow();
666  wfDebug( __METHOD__ . " checking current " . $timestamp . " vs $this->mExpiry" );
667 
668  return $this->getExpiry() && $timestamp > $this->getExpiry();
669  }
670 
674  public function updateTimestamp() {
675  if ( $this->mAuto ) {
676  $this->setTimestamp( wfTimestamp() );
677  $this->setExpiry( self::getAutoblockExpiry( $this->getTimestamp() ) );
678 
679  $dbw = wfGetDB( DB_PRIMARY );
680  $dbw->update( 'ipblocks',
681  [ /* SET */
682  'ipb_timestamp' => $dbw->timestamp( $this->getTimestamp() ),
683  'ipb_expiry' => $dbw->timestamp( $this->getExpiry() ),
684  ],
685  [ /* WHERE */
686  'ipb_id' => $this->getId(),
687  ],
688  __METHOD__
689  );
690  }
691  }
692 
698  public function getRangeStart() {
699  switch ( $this->type ) {
700  case self::TYPE_USER:
701  return '';
702  case self::TYPE_IP:
703  return IPUtils::toHex( $this->target );
704  case self::TYPE_RANGE:
705  list( $start, /*...*/ ) = IPUtils::parseRange( $this->target );
706  return $start;
707  default:
708  throw new MWException( "Block with invalid type" );
709  }
710  }
711 
717  public function getRangeEnd() {
718  switch ( $this->type ) {
719  case self::TYPE_USER:
720  return '';
721  case self::TYPE_IP:
722  return IPUtils::toHex( $this->target );
723  case self::TYPE_RANGE:
724  list( /*...*/, $end ) = IPUtils::parseRange( $this->target );
725  return $end;
726  default:
727  throw new MWException( "Block with invalid type" );
728  }
729  }
730 
735  public function getReason() {
736  if ( $this->getType() === self::TYPE_AUTO ) {
737  return $this->reason->message->inContentLanguage()->plain();
738  }
739  return $this->reason->text;
740  }
741 
745  public function getId(): ?int {
746  return $this->mId;
747  }
748 
756  public function setId( $blockId ) {
757  $this->mId = (int)$blockId;
758 
759  if ( is_array( $this->restrictions ) ) {
760  $this->restrictions = $this->getBlockRestrictionStore()->setBlockId(
761  $blockId, $this->restrictions
762  );
763  }
764 
765  return $this;
766  }
767 
772  public function getParentBlockId() {
773  return $this->mParentBlockId;
774  }
775 
781  public function isHardblock( $x = null ): bool {
782  wfSetVar( $this->isHardblock, $x );
783 
784  # You can't *not* hardblock a user
785  return $this->getType() == self::TYPE_USER
786  ? true
788  }
789 
794  public function isAutoblocking( $x = null ) {
795  wfSetVar( $this->isAutoblocking, $x );
796 
797  # You can't put an autoblock on an IP or range as we don't have any history to
798  # look over to get more IPs from
799  return $this->getType() == self::TYPE_USER
800  ? $this->isAutoblocking
801  : false;
802  }
803 
808  public function getRedactedName() {
809  if ( $this->mAuto ) {
810  return Html::element(
811  'span',
812  [ 'class' => 'mw-autoblockid' ],
813  wfMessage( 'autoblockid', $this->mId )->text()
814  );
815  } else {
816  return htmlspecialchars( $this->getTargetName() );
817  }
818  }
819 
826  public static function getAutoblockExpiry( $timestamp ) {
827  global $wgAutoblockExpiry;
828 
829  return wfTimestamp( TS_MW, (int)wfTimestamp( TS_UNIX, $timestamp ) + $wgAutoblockExpiry );
830  }
831 
838  public static function purgeExpired() {
839  wfDeprecated( __METHOD__, '1.36' );
840  MediaWikiServices::getInstance()->getDatabaseBlockStore()->purgeExpiredBlocks();
841  }
842 
863  public static function newFromTarget( $specificTarget, $vagueTarget = null, $fromPrimary = false ) {
864  $blocks = self::newListFromTarget( $specificTarget, $vagueTarget, $fromPrimary );
865  return self::chooseMostSpecificBlock( $blocks );
866  }
867 
877  public static function newListFromTarget(
878  $specificTarget,
879  $vagueTarget = null,
880  $fromPrimary = false
881  ) {
883  ->getBlockUtils()
884  ->parseBlockTarget( $specificTarget );
885  if ( $type == self::TYPE_ID || $type == self::TYPE_AUTO ) {
886  $block = self::newFromID( $target );
887  return $block ? [ $block ] : [];
888  } elseif ( $target === null && $vagueTarget == '' ) {
889  # We're not going to find anything useful here
890  # Be aware that the == '' check is explicit, since empty values will be
891  # passed by some callers (T31116)
892  return [];
893  } elseif ( in_array(
894  $type,
895  [ self::TYPE_USER, self::TYPE_IP, self::TYPE_RANGE, null ] )
896  ) {
897  return self::newLoad( $target, $type, $fromPrimary, $vagueTarget );
898  }
899  return [];
900  }
901 
912  public static function getBlocksForIPList( array $ipChain, $isAnon, $fromPrimary = false ) {
913  if ( $ipChain === [] ) {
914  return [];
915  }
916 
917  $conds = [];
918  $proxyLookup = MediaWikiServices::getInstance()->getProxyLookup();
919  foreach ( array_unique( $ipChain ) as $ipaddr ) {
920  # Discard invalid IP addresses. Since XFF can be spoofed and we do not
921  # necessarily trust the header given to us, make sure that we are only
922  # checking for blocks on well-formatted IP addresses (IPv4 and IPv6).
923  # Do not treat private IP spaces as special as it may be desirable for wikis
924  # to block those IP ranges in order to stop misbehaving proxies that spoof XFF.
925  if ( !IPUtils::isValid( $ipaddr ) ) {
926  continue;
927  }
928  # Don't check trusted IPs (includes local CDNs which will be in every request)
929  if ( $proxyLookup->isTrustedProxy( $ipaddr ) ) {
930  continue;
931  }
932  # Check both the original IP (to check against single blocks), as well as build
933  # the clause to check for rangeblocks for the given IP.
934  $conds['ipb_address'][] = $ipaddr;
935  $conds[] = self::getRangeCond( IPUtils::toHex( $ipaddr ) );
936  }
937 
938  if ( $conds === [] ) {
939  return [];
940  }
941 
942  if ( $fromPrimary ) {
943  $db = wfGetDB( DB_PRIMARY );
944  } else {
945  $db = wfGetDB( DB_REPLICA );
946  }
947  $conds = $db->makeList( $conds, LIST_OR );
948  if ( !$isAnon ) {
949  $conds = [ $conds, 'ipb_anon_only' => 0 ];
950  }
951  $blockQuery = self::getQueryInfo();
952  $rows = $db->select(
953  $blockQuery['tables'],
954  array_merge( [ 'ipb_range_start', 'ipb_range_end' ], $blockQuery['fields'] ),
955  $conds,
956  __METHOD__,
957  [],
958  $blockQuery['joins']
959  );
960 
961  $blocks = [];
962  foreach ( $rows as $row ) {
963  $block = self::newFromRow( $row );
964  if ( !$block->isExpired() ) {
965  $blocks[] = $block;
966  }
967  }
968 
969  return $blocks;
970  }
971 
978  public function getType(): ?int {
979  return $this->mAuto
981  : parent::getType();
982  }
983 
987  public function getIdentifier() {
988  return $this->getId();
989  }
990 
998  public function getRestrictions() {
999  if ( $this->restrictions === null ) {
1000  // If the block id has not been set, then do not attempt to load the
1001  // restrictions.
1002  if ( !$this->mId ) {
1003  return [];
1004  }
1005  $this->restrictions = $this->getBlockRestrictionStore()->loadByBlockId( $this->mId );
1006  }
1007 
1008  return $this->restrictions;
1009  }
1010 
1017  public function getRawRestrictions(): ?array {
1018  return $this->restrictions;
1019  }
1020 
1026  public function setRestrictions( array $restrictions ) {
1027  $this->restrictions = array_filter( $restrictions, static function ( $restriction ) {
1028  return $restriction instanceof Restriction;
1029  } );
1030 
1031  return $this;
1032  }
1033 
1037  public function appliesToTitle( Title $title ) {
1038  if ( $this->isSitewide() ) {
1039  return true;
1040  }
1041 
1042  $restrictions = $this->getRestrictions();
1043  foreach ( $restrictions as $restriction ) {
1044  if ( $restriction->matches( $title ) ) {
1045  return true;
1046  }
1047  }
1048 
1049  return false;
1050  }
1051 
1055  public function appliesToNamespace( $ns ) {
1056  if ( $this->isSitewide() ) {
1057  return true;
1058  }
1059 
1060  // Blocks do not apply to virtual namespaces.
1061  if ( $ns < 0 ) {
1062  return false;
1063  }
1064 
1065  $restriction = $this->findRestriction( NamespaceRestriction::TYPE, $ns );
1066 
1067  return (bool)$restriction;
1068  }
1069 
1073  public function appliesToPage( $pageId ) {
1074  if ( $this->isSitewide() ) {
1075  return true;
1076  }
1077 
1078  // If the pageId is not over zero, the block cannot apply to it.
1079  if ( $pageId <= 0 ) {
1080  return false;
1081  }
1082 
1083  $restriction = $this->findRestriction( PageRestriction::TYPE, $pageId );
1084 
1085  return (bool)$restriction;
1086  }
1087 
1091  public function appliesToRight( $right ) {
1092  // Temporarily access service container until the feature flag is removed: T280532
1093  $config = MediaWikiServices::getInstance()->getMainConfig();
1094 
1095  $res = parent::appliesToRight( $right );
1096 
1097  if ( !$res && $config->get( 'EnablePartialActionBlocks' ) ) {
1098  $blockActions = MediaWikiServices::getInstance()->getBlockActionInfo()
1099  ->getAllBlockActions();
1100 
1101  if ( isset( $blockActions[$right] ) ) {
1102  $restriction = $this->findRestriction(
1104  $blockActions[$right]
1105  );
1106 
1107  // $res may be null or false. This should be preserved if there is no restriction.
1108  if ( $restriction ) {
1109  $res = true;
1110  }
1111  }
1112  }
1113 
1114  return $res;
1115  }
1116 
1124  private function findRestriction( $type, $value ) {
1125  $restrictions = $this->getRestrictions();
1126  foreach ( $restrictions as $restriction ) {
1127  if ( $restriction->getType() !== $type ) {
1128  continue;
1129  }
1130 
1131  if ( $restriction->getValue() === $value ) {
1132  return $restriction;
1133  }
1134  }
1135 
1136  return null;
1137  }
1138 
1145  return MediaWikiServices::getInstance()->getBlockRestrictionStore();
1146  }
1147 
1151  public function getBy() {
1152  return ( $this->blocker ) ? $this->blocker->getId() : 0;
1153  }
1154 
1158  public function getByName() {
1159  return ( $this->blocker ) ? $this->blocker->getName() : '';
1160  }
1161 
1167  public function getBlocker(): ?UserIdentity {
1168  return $this->blocker;
1169  }
1170 
1176  public function setBlocker( $user ) {
1177  if ( !$user->isRegistered() &&
1178  MediaWikiServices::getInstance()->getUserNameUtils()->isUsable( $user->getName() )
1179  ) {
1180  // Temporarily log some block details to debug T192964
1181  $logger = LoggerFactory::getInstance( 'BlockManager' );
1182  $logger->warning(
1183  'Blocker is neither a local user nor an invalid username',
1184  [
1185  'blocker' => (string)$user,
1186  'blockId' => $this->getId(),
1187  ]
1188  );
1189  throw new \InvalidArgumentException(
1190  'Blocker must be a local user or a name that cannot be a local user'
1191  );
1192  }
1193 
1194  $this->blocker = $user;
1195  }
1196 }
1197 
1201 class_alias( DatabaseBlock::class, 'Block' );
LIST_OR
const LIST_OR
Definition: Defines.php:46
MediaWiki\Block\DatabaseBlock\setBlocker
setBlocker( $user)
Set the user who implemented (or will implement) this block.
Definition: DatabaseBlock.php:1176
MediaWiki\Block\DatabaseBlock\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: DatabaseBlock.php:417
Wikimedia\Rdbms\Database
Relational database abstraction object.
Definition: Database.php:52
MediaWiki\Block\DatabaseBlock\equals
equals(DatabaseBlock $block)
Check if two blocks are effectively equal.
Definition: DatabaseBlock.php:207
MediaWiki\Block
Definition: AbstractBlock.php:21
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:199
MediaWiki\Block\AbstractBlock\getTargetName
getTargetName()
Definition: AbstractBlock.php:359
MediaWiki\Block\DatabaseBlock\initFromRow
initFromRow( $row)
Given a database row from the ipblocks table, initialize member variables.
Definition: DatabaseBlock.php:431
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:1512
MediaWiki\Logger\LoggerFactory\getInstance
static getInstance( $channel)
Get a named logger instance from the currently configured logger factory.
Definition: LoggerFactory.php:92
MediaWiki\Block\DatabaseBlock\getRangeStart
getRangeStart()
Get the IP address at the start of the range in Hex form.
Definition: DatabaseBlock.php:698
MediaWiki\Block\DatabaseBlock\$mParentBlockId
int $mParentBlockId
Definition: DatabaseBlock.php:61
true
return true
Definition: router.php:90
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition: GlobalFunctions.php:1665
$wgAutoblockExpiry
$wgAutoblockExpiry
Number of seconds before autoblock entries expire.
Definition: DefaultSettings.php:5823
LIST_AND
const LIST_AND
Definition: Defines.php:43
MediaWiki\Block\DatabaseBlock\getType
getType()
Get the type of target for this particular block.int|null AbstractBlock::TYPE_ constant,...
Definition: DatabaseBlock.php:978
MediaWiki\Block\Restriction\NamespaceRestriction\TYPE
const TYPE
Definition: NamespaceRestriction.php:30
MediaWiki\Block\AbstractBlock\isCreateAccountBlocked
isCreateAccountBlocked( $x=null)
Get or set the flag indicating whether this block blocks the target from creating an account.
Definition: AbstractBlock.php:210
MediaWiki\Block\DatabaseBlock\getBlocker
getBlocker()
Get the user who implemented this block.
Definition: DatabaseBlock.php:1167
MediaWiki\Block\DatabaseBlock\__construct
__construct(array $options=[])
Create a new block with specified option parameters on a user, IP or IP range.
Definition: DatabaseBlock.php:97
CommentStore
Handle database storage of comments such as edit summaries and log reasons.
Definition: CommentStore.php:42
MediaWiki\Block\DatabaseBlock\appliesToNamespace
appliesToNamespace( $ns)
Checks if a block applies to a particular namespace.1.33bool
Definition: DatabaseBlock.php:1055
wfMessage
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Definition: GlobalFunctions.php:1183
MediaWiki\Block\DatabaseBlock\getByName
getByName()
Get the username of the blocking sysop.string
Definition: DatabaseBlock.php:1158
MediaWiki\Block\DatabaseBlock\$mFromPrimary
bool $mFromPrimary
Definition: DatabaseBlock.php:67
$res
$res
Definition: testCompression.php:57
MediaWiki\Block\DatabaseBlock\getRawRestrictions
getRawRestrictions()
Get restrictions without loading from database if not yet loaded.
Definition: DatabaseBlock.php:1017
MediaWiki\User\UserIdentity
Interface for objects representing user identity.
Definition: UserIdentity.php:39
Wikimedia\Rdbms\IDatabase
Basic database interface for live and lazy-loaded relation database handles.
Definition: IDatabase.php:38
$dbr
$dbr
Definition: testCompression.php:54
MediaWiki\MediaWikiServices\getInstance
static getInstance()
Returns the global default instance of the top level service locator.
Definition: MediaWikiServices.php:260
MediaWiki\Block\DatabaseBlock\appliesToPage
appliesToPage( $pageId)
Checks if a block applies to a particular page.This check does not consider whether $this->isUsertalk...
Definition: DatabaseBlock.php:1073
MediaWiki\Block\DatabaseBlock
A DatabaseBlock (unlike a SystemBlock) is stored in the database, may give rise to autoblocks and may...
Definition: DatabaseBlock.php:50
MediaWiki\Block\DatabaseBlock\setRestrictions
setRestrictions(array $restrictions)
Definition: DatabaseBlock.php:1026
MWException
MediaWiki exception.
Definition: MWException.php:29
Wikimedia\Rdbms\Database\getCacheSetOptions
static getCacheSetOptions(?IDatabase ... $dbs)
Merge the result of getSessionLagStatus() for several DBs using the most pessimistic values to estima...
Definition: Database.php:5240
wfDeprecated
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.
Definition: GlobalFunctions.php:997
MediaWiki\Logger\LoggerFactory
PSR-3 logger instance factory.
Definition: LoggerFactory.php:45
Config\get
get( $name)
Get a configuration variable such as "Sitename" or "UploadMaintenance.".
MediaWiki\Block\DatabaseBlock\purgeExpired
static purgeExpired()
Purge expired blocks from the ipblocks table.
Definition: DatabaseBlock.php:838
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:2200
MediaWiki\Block\Block\isSitewide
isSitewide()
Indicates that the block is a sitewide block.
MediaWiki\Block\AbstractBlock\isEmailBlocked
isEmailBlocked( $x=null)
Get or set the flag indicating whether this block blocks the target from sending emails.
Definition: AbstractBlock.php:223
MediaWiki\Block\DatabaseBlock\newFromRow
static newFromRow( $row)
Create a new DatabaseBlock object from a database row.
Definition: DatabaseBlock.php:467
MediaWiki\Block\Restriction\Restriction
Definition: Restriction.php:25
MediaWiki\Block\AbstractBlock\getReasonComment
getReasonComment()
Get the reason for creating the block.
Definition: AbstractBlock.php:154
MediaWiki\Block\Restriction\PageRestriction\TYPE
const TYPE
Definition: PageRestriction.php:30
MediaWiki\Block\DatabaseBlock\isWhitelistedFromAutoblocks
static isWhitelistedFromAutoblocks( $ip)
Checks whether a given IP is on the autoblock exemption list.
Definition: DatabaseBlock.php:523
MediaWiki\Block\DatabaseBlock\getRangeEnd
getRangeEnd()
Get the IP address at the end of the range in Hex form.
Definition: DatabaseBlock.php:717
$title
$title
Definition: testCompression.php:38
MediaWiki\Block\Block\TYPE_RANGE
const TYPE_RANGE
Definition: Block.php:43
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
wfTimestampNow
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
Definition: GlobalFunctions.php:1694
MediaWiki\Block\DatabaseBlock\isExpired
isExpired()
Has the block expired?
Definition: DatabaseBlock.php:664
MediaWiki\Block\AbstractBlock\isSitewide
isSitewide( $x=null)
Indicates that the block is a sitewide block.
Definition: AbstractBlock.php:197
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:894
MediaWiki\Block\AbstractBlock\$isHardblock
bool $isHardblock
Definition: AbstractBlock.php:69
MediaWiki\Block\DatabaseBlock\getBlocksForIPList
static getBlocksForIPList(array $ipChain, $isAnon, $fromPrimary=false)
Get all blocks that match any IP from an array of IP addresses.
Definition: DatabaseBlock.php:912
MediaWiki\Block\DatabaseBlock\getRangeCond
static getRangeCond( $start, $end=null)
Get a set of SQL conditions which will select rangeblocks encompassing a given range.
Definition: DatabaseBlock.php:384
MediaWiki\Block\DatabaseBlock\getBlockRestrictionStore
getBlockRestrictionStore()
Get a BlockRestrictionStore instance.
Definition: DatabaseBlock.php:1144
MediaWiki\Block\DatabaseBlock\getRedactedName
getRedactedName()
Get the block name, but with autoblocked IPs hidden as per standard privacy policy.
Definition: DatabaseBlock.php:808
MediaWiki\Block\DatabaseBlock\isAutoblocking
isAutoblocking( $x=null)
Definition: DatabaseBlock.php:794
MediaWiki\Block\AbstractBlock\setTimestamp
setTimestamp( $timestamp)
Set the timestamp indicating when the block was created.
Definition: AbstractBlock.php:416
MediaWiki\Block\DatabaseBlock\getBy
getBy()
Get the user id of the blocking sysop.int (0 for foreign users)
Definition: DatabaseBlock.php:1151
MediaWiki\Block\Block\isHardblock
isHardblock()
Returns whether the block is a hardblock (affects logged-in users on a given IP/range)
MediaWiki\Block\DatabaseBlock\newFromTarget
static newFromTarget( $specificTarget, $vagueTarget=null, $fromPrimary=false)
Given a target and the target's type, get an existing block object if possible.
Definition: DatabaseBlock.php:863
MediaWiki\Block\DatabaseBlock\getIdentifier
getIdentifier()
Get the information that identifies this block, such that a user could look up everything that can be...
Definition: DatabaseBlock.php:987
MediaWiki\Block\DatabaseBlock\getParentBlockId
getParentBlockId()
Definition: DatabaseBlock.php:772
MediaWiki\Block\DatabaseBlock\$isAutoblocking
bool $isAutoblocking
Definition: DatabaseBlock.php:70
DB_PRIMARY
const DB_PRIMARY
Definition: defines.php:27
MediaWiki\Block\DatabaseBlock\getReason
getReason()
Get the reason given for creating the block, as a string.Deprecated, since this gives the caller no c...
Definition: DatabaseBlock.php:735
Hooks\runner
static runner()
Get a HookRunner instance for calling hooks using the new interfaces.
Definition: Hooks.php:173
$line
$line
Definition: mcc.php:119
MediaWiki\Block\DatabaseBlock\isExemptedFromAutoblocks
static isExemptedFromAutoblocks( $ip)
Checks whether a given IP is on the autoblock exemption list.
Definition: DatabaseBlock.php:538
MediaWiki\Block\AbstractBlock\$target
UserIdentity string null $target
Definition: AbstractBlock.php:72
MediaWiki\Block\AbstractBlock\setExpiry
setExpiry( $expiry)
Set the block expiry time.
Definition: AbstractBlock.php:395
MediaWiki\Block\AbstractBlock\getExpiry
getExpiry()
Get the block expiry time.
Definition: AbstractBlock.php:385
MediaWiki\Block\Block\TYPE_AUTO
const TYPE_AUTO
Definition: Block.php:44
MediaWiki\Block\Block\TYPE_USER
const TYPE_USER
Definition: Block.php:41
MediaWiki\Block\DatabaseBlock\update
update()
Update a block in the DB with new parameters.
Definition: DatabaseBlock.php:509
$lines
if(!file_exists( $CREDITS)) $lines
Definition: updateCredits.php:45
MediaWiki\Block\Restriction\NamespaceRestriction
Definition: NamespaceRestriction.php:25
MediaWiki\Block\AbstractBlock\getTimestamp
getTimestamp()
Get the timestamp indicating when the block was created.
Definition: AbstractBlock.php:406
MediaWiki\Block\DatabaseBlock\getId
getId()
Get the block ID.int|null
Definition: DatabaseBlock.php:745
Title
Represents a title within MediaWiki.
Definition: Title.php:47
MediaWiki\Block\Block\isCreateAccountBlocked
isCreateAccountBlocked()
Get the flag indicating whether this block blocks the target from creating an account.
$wgBlockCIDRLimit
$wgBlockCIDRLimit
Limits on the possible sizes of range blocks.
Definition: DefaultSettings.php:5848
MediaWiki\Block\DatabaseBlock\setId
setId( $blockId)
Set the block ID.
Definition: DatabaseBlock.php:756
$cache
$cache
Definition: mcc.php:33
MediaWiki\Block\DatabaseBlock\chooseMostSpecificBlock
static chooseMostSpecificBlock(array $blocks)
Choose the most specific block from some combination of user, IP and IP range blocks.
Definition: DatabaseBlock.php:342
MediaWiki\Block\Restriction\PageRestriction
Definition: PageRestriction.php:25
MediaWiki\Block\AbstractBlock\setReason
setReason( $reason)
Set the reason for creating the block.
Definition: AbstractBlock.php:164
MediaWiki\Block\DatabaseBlock\getRestrictions
getRestrictions()
Getting the restrictions will perform a database query if the restrictions are not already loaded.
Definition: DatabaseBlock.php:998
MediaWiki\$config
Config $config
Definition: MediaWiki.php:42
MediaWiki\Block\DatabaseBlock\newListFromTarget
static newListFromTarget( $specificTarget, $vagueTarget=null, $fromPrimary=false)
This is similar to DatabaseBlock::newFromTarget, but it returns all the relevant blocks.
Definition: DatabaseBlock.php:877
MediaWiki\Block\DatabaseBlock\updateTimestamp
updateTimestamp()
Update the timestamp on autoblocks.
Definition: DatabaseBlock.php:674
MediaWiki\Block\DatabaseBlock\getQueryInfo
static getQueryInfo()
Return the tables, fields, and join conditions to be selected to create a new block object.
Definition: DatabaseBlock.php:169
MediaWiki\Block\DatabaseBlock\doAutoblock
doAutoblock( $autoblockIP)
Autoblocks the given IP, referring to this block.
Definition: DatabaseBlock.php:585
MediaWiki\Block\DatabaseBlock\findRestriction
findRestriction( $type, $value)
Find Restriction by type and value.
Definition: DatabaseBlock.php:1124
MediaWiki\Block\DatabaseBlock\getAutoblockExpiry
static getAutoblockExpiry( $timestamp)
Get a timestamp of the expiry for autoblocks.
Definition: DatabaseBlock.php:826
MediaWiki\Block\AbstractBlock\getHideName
getHideName()
Get whether the block hides the target's username.
Definition: AbstractBlock.php:174
MediaWiki\Block\Restriction\ActionRestriction\TYPE
const TYPE
Definition: ActionRestriction.php:35
MediaWiki\Block\AbstractBlock\$type
int null $type
AbstractBlock::TYPE_ constant.
Definition: AbstractBlock.php:78
MediaWiki\Block\AbstractBlock
Definition: AbstractBlock.php:37
MediaWiki\Block\DatabaseBlock\appliesToRight
appliesToRight( $right)
Determine whether the block prevents a given right.A right may be allowed or disallowed by default,...
Definition: DatabaseBlock.php:1091
Html\element
static element( $element, $attribs=[], $contents='')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
Definition: Html.php:232
MediaWiki\Block\DatabaseBlock\$mAuto
bool $mAuto
Definition: DatabaseBlock.php:55
MediaWiki\Block\AbstractBlock\setTarget
setTarget( $target)
Set the target for this block, and update $this->type accordingly.
Definition: AbstractBlock.php:425
CommentStore\getStore
static getStore()
Definition: CommentStore.php:120
MediaWiki\Block\DatabaseBlock\insert
insert(IDatabase $dbw=null)
Insert a block into the block table.
Definition: DatabaseBlock.php:495
MediaWiki\Block\Restriction\ActionRestriction
Restriction for partial blocks of actions.
Definition: ActionRestriction.php:30
MediaWiki\Block\DatabaseBlock\appliesToTitle
appliesToTitle(Title $title)
Checks if a block applies to a particular title.This check does not consider whether $this->isUsertal...
Definition: DatabaseBlock.php:1037
MediaWiki\Block\DatabaseBlock\$blocker
UserIdentity null $blocker
Definition: DatabaseBlock.php:76
MediaWiki\Block\DatabaseBlock\isHardblock
isHardblock( $x=null)
Get/set whether the block is a hardblock (affects logged-in users on a given IP/range)
Definition: DatabaseBlock.php:781
MediaWiki\Block\DatabaseBlock\newLoad
static newLoad( $specificTarget, $specificType, $fromPrimary, $vagueTarget=null)
Load blocks from the database which target the specific target exactly, or which cover the vague targ...
Definition: DatabaseBlock.php:241
MediaWiki\Block\DatabaseBlock\$restrictions
Restriction[] $restrictions
Definition: DatabaseBlock.php:73
MediaWiki\Block\AbstractBlock\isUsertalkEditAllowed
isUsertalkEditAllowed( $x=null)
Get or set the flag indicating whether this block blocks the target from editing their own user talk ...
Definition: AbstractBlock.php:236
MediaWiki\Block\DatabaseBlock\$mId
int $mId
Definition: DatabaseBlock.php:64
MediaWiki\Block\Block\TYPE_IP
const TYPE_IP
Definition: Block.php:42
Hooks
Hooks class.
Definition: Hooks.php:38
MediaWiki\Block\BlockRestrictionStore
Definition: BlockRestrictionStore.php:35
MediaWiki\Block\DatabaseBlock\newFromID
static newFromID( $id)
Load a block from the block id.
Definition: DatabaseBlock.php:137
Html
This class is a collection of static functions that serve two purposes:
Definition: Html.php:49