MediaWiki  1.33.0
Block.php
Go to the documentation of this file.
1 <?php
30 
31 class Block {
33  public $mReason;
34 
36  public $mTimestamp;
37 
39  public $mAuto;
40 
42  public $mExpiry;
43 
45  public $mHideName;
46 
49 
51  private $mId;
52 
54  private $mFromMaster;
55 
57  private $mBlockEmail;
58 
60  private $allowUsertalk;
61 
64 
66  private $target;
67 
69  private $forcedTargetID;
70 
75  private $type;
76 
78  private $blocker;
79 
81  private $isHardblock;
82 
84  private $isAutoblocking;
85 
88 
90  private $isSitewide;
91 
93  private $restrictions;
94 
95  # TYPE constants
96  const TYPE_USER = 1;
97  const TYPE_IP = 2;
98  const TYPE_RANGE = 3;
99  const TYPE_AUTO = 4;
100  const TYPE_ID = 5;
101 
131  function __construct( $options = [] ) {
132  $defaults = [
133  'address' => '',
134  'user' => null,
135  'by' => null,
136  'reason' => '',
137  'timestamp' => '',
138  'auto' => false,
139  'expiry' => '',
140  'anonOnly' => false,
141  'createAccount' => false,
142  'enableAutoblock' => false,
143  'hideName' => false,
144  'blockEmail' => false,
145  'allowUsertalk' => false,
146  'byText' => '',
147  'systemBlock' => null,
148  'sitewide' => true,
149  ];
150 
151  $options += $defaults;
152 
153  $this->setTarget( $options['address'] );
154 
155  if ( $this->target instanceof User && $options['user'] ) {
156  # Needed for foreign users
157  $this->forcedTargetID = $options['user'];
158  }
159 
160  if ( $options['by'] ) {
161  # Local user
162  $this->setBlocker( User::newFromId( $options['by'] ) );
163  } else {
164  # Foreign user
165  $this->setBlocker( $options['byText'] );
166  }
167 
168  $this->setReason( $options['reason'] );
169  $this->setTimestamp( wfTimestamp( TS_MW, $options['timestamp'] ) );
170  $this->setExpiry( wfGetDB( DB_REPLICA )->decodeExpiry( $options['expiry'] ) );
171 
172  # Boolean settings
173  $this->mAuto = (bool)$options['auto'];
174  $this->setHideName( (bool)$options['hideName'] );
175  $this->isHardblock( !$options['anonOnly'] );
176  $this->isAutoblocking( (bool)$options['enableAutoblock'] );
177  $this->isSitewide( (bool)$options['sitewide'] );
178  $this->isEmailBlocked( (bool)$options['blockEmail'] );
179  $this->isCreateAccountBlocked( (bool)$options['createAccount'] );
180  $this->isUsertalkEditAllowed( (bool)$options['allowUsertalk'] );
181 
182  $this->mFromMaster = false;
183  $this->systemBlockType = $options['systemBlock'];
184  }
185 
192  public static function newFromID( $id ) {
193  $dbr = wfGetDB( DB_REPLICA );
194  $blockQuery = self::getQueryInfo();
195  $res = $dbr->selectRow(
196  $blockQuery['tables'],
197  $blockQuery['fields'],
198  [ 'ipb_id' => $id ],
199  __METHOD__,
200  [],
201  $blockQuery['joins']
202  );
203  if ( $res ) {
204  return self::newFromRow( $res );
205  } else {
206  return null;
207  }
208  }
209 
216  public static function selectFields() {
218 
220  // If code is using this instead of self::getQueryInfo(), there's a
221  // decent chance it's going to try to directly access
222  // $row->ipb_by or $row->ipb_by_text and we can't give it
223  // useful values here once those aren't being used anymore.
224  throw new BadMethodCallException(
225  'Cannot use ' . __METHOD__
226  . ' when $wgActorTableSchemaMigrationStage has SCHEMA_COMPAT_READ_NEW'
227  );
228  }
229 
230  wfDeprecated( __METHOD__, '1.31' );
231  return [
232  'ipb_id',
233  'ipb_address',
234  'ipb_by',
235  'ipb_by_text',
236  'ipb_by_actor' => 'NULL',
237  'ipb_timestamp',
238  'ipb_auto',
239  'ipb_anon_only',
240  'ipb_create_account',
241  'ipb_enable_autoblock',
242  'ipb_expiry',
243  'ipb_deleted',
244  'ipb_block_email',
245  'ipb_allow_usertalk',
246  'ipb_parent_block_id',
247  'ipb_sitewide',
248  ] + CommentStore::getStore()->getFields( 'ipb_reason' );
249  }
250 
260  public static function getQueryInfo() {
261  $commentQuery = CommentStore::getStore()->getJoin( 'ipb_reason' );
262  $actorQuery = ActorMigration::newMigration()->getJoin( 'ipb_by' );
263  return [
264  'tables' => [ 'ipblocks' ] + $commentQuery['tables'] + $actorQuery['tables'],
265  'fields' => [
266  'ipb_id',
267  'ipb_address',
268  'ipb_timestamp',
269  'ipb_auto',
270  'ipb_anon_only',
271  'ipb_create_account',
272  'ipb_enable_autoblock',
273  'ipb_expiry',
274  'ipb_deleted',
275  'ipb_block_email',
276  'ipb_allow_usertalk',
277  'ipb_parent_block_id',
278  'ipb_sitewide',
279  ] + $commentQuery['fields'] + $actorQuery['fields'],
280  'joins' => $commentQuery['joins'] + $actorQuery['joins'],
281  ];
282  }
283 
292  public function equals( Block $block ) {
293  return (
294  (string)$this->target == (string)$block->target
295  && $this->type == $block->type
296  && $this->mAuto == $block->mAuto
297  && $this->isHardblock() == $block->isHardblock()
298  && $this->isCreateAccountBlocked() == $block->isCreateAccountBlocked()
299  && $this->getExpiry() == $block->getExpiry()
300  && $this->isAutoblocking() == $block->isAutoblocking()
301  && $this->getHideName() == $block->getHideName()
302  && $this->isEmailBlocked() == $block->isEmailBlocked()
303  && $this->isUsertalkEditAllowed() == $block->isUsertalkEditAllowed()
304  && $this->getReason() == $block->getReason()
305  && $this->isSitewide() == $block->isSitewide()
306  // Block::getRestrictions() may perform a database query, so keep it at
307  // the end.
308  && $this->getBlockRestrictionStore()->equals(
309  $this->getRestrictions(), $block->getRestrictions()
310  )
311  );
312  }
313 
324  protected function newLoad( $vagueTarget = null ) {
325  $db = wfGetDB( $this->mFromMaster ? DB_MASTER : DB_REPLICA );
326 
327  if ( $this->type !== null ) {
328  $conds = [
329  'ipb_address' => [ (string)$this->target ],
330  ];
331  } else {
332  $conds = [ 'ipb_address' => [] ];
333  }
334 
335  # Be aware that the != '' check is explicit, since empty values will be
336  # passed by some callers (T31116)
337  if ( $vagueTarget != '' ) {
338  list( $target, $type ) = self::parseTarget( $vagueTarget );
339  switch ( $type ) {
340  case self::TYPE_USER:
341  # Slightly weird, but who are we to argue?
342  $conds['ipb_address'][] = (string)$target;
343  break;
344 
345  case self::TYPE_IP:
346  $conds['ipb_address'][] = (string)$target;
347  $conds[] = self::getRangeCond( IP::toHex( $target ) );
348  $conds = $db->makeList( $conds, LIST_OR );
349  break;
350 
351  case self::TYPE_RANGE:
352  list( $start, $end ) = IP::parseRange( $target );
353  $conds['ipb_address'][] = (string)$target;
354  $conds[] = self::getRangeCond( $start, $end );
355  $conds = $db->makeList( $conds, LIST_OR );
356  break;
357 
358  default:
359  throw new MWException( "Tried to load block with invalid type" );
360  }
361  }
362 
363  $blockQuery = self::getQueryInfo();
364  $res = $db->select(
365  $blockQuery['tables'], $blockQuery['fields'], $conds, __METHOD__, [], $blockQuery['joins']
366  );
367 
368  # This result could contain a block on the user, a block on the IP, and a russian-doll
369  # set of rangeblocks. We want to choose the most specific one, so keep a leader board.
370  $bestRow = null;
371 
372  # Lower will be better
373  $bestBlockScore = 100;
374 
375  foreach ( $res as $row ) {
376  $block = self::newFromRow( $row );
377 
378  # Don't use expired blocks
379  if ( $block->isExpired() ) {
380  continue;
381  }
382 
383  # Don't use anon only blocks on users
384  if ( $this->type == self::TYPE_USER && !$block->isHardblock() ) {
385  continue;
386  }
387 
388  if ( $block->getType() == self::TYPE_RANGE ) {
389  # This is the number of bits that are allowed to vary in the block, give
390  # or take some floating point errors
391  $end = Wikimedia\base_convert( $block->getRangeEnd(), 16, 10 );
392  $start = Wikimedia\base_convert( $block->getRangeStart(), 16, 10 );
393  $size = log( $end - $start + 1, 2 );
394 
395  # This has the nice property that a /32 block is ranked equally with a
396  # single-IP block, which is exactly what it is...
397  $score = self::TYPE_RANGE - 1 + ( $size / 128 );
398 
399  } else {
400  $score = $block->getType();
401  }
402 
403  if ( $score < $bestBlockScore ) {
404  $bestBlockScore = $score;
405  $bestRow = $row;
406  }
407  }
408 
409  if ( $bestRow !== null ) {
410  $this->initFromRow( $bestRow );
411  return true;
412  } else {
413  return false;
414  }
415  }
416 
423  public static function getRangeCond( $start, $end = null ) {
424  if ( $end === null ) {
425  $end = $start;
426  }
427  # Per T16634, we want to include relevant active rangeblocks; for
428  # rangeblocks, we want to include larger ranges which enclose the given
429  # range. We know that all blocks must be smaller than $wgBlockCIDRLimit,
430  # so we can improve performance by filtering on a LIKE clause
431  $chunk = self::getIpFragment( $start );
432  $dbr = wfGetDB( DB_REPLICA );
433  $like = $dbr->buildLike( $chunk, $dbr->anyString() );
434 
435  # Fairly hard to make a malicious SQL statement out of hex characters,
436  # but stranger things have happened...
437  $safeStart = $dbr->addQuotes( $start );
438  $safeEnd = $dbr->addQuotes( $end );
439 
440  return $dbr->makeList(
441  [
442  "ipb_range_start $like",
443  "ipb_range_start <= $safeStart",
444  "ipb_range_end >= $safeEnd",
445  ],
446  LIST_AND
447  );
448  }
449 
456  protected static function getIpFragment( $hex ) {
457  global $wgBlockCIDRLimit;
458  if ( substr( $hex, 0, 3 ) == 'v6-' ) {
459  return 'v6-' . substr( substr( $hex, 3 ), 0, floor( $wgBlockCIDRLimit['IPv6'] / 4 ) );
460  } else {
461  return substr( $hex, 0, floor( $wgBlockCIDRLimit['IPv4'] / 4 ) );
462  }
463  }
464 
470  protected function initFromRow( $row ) {
471  $this->setTarget( $row->ipb_address );
473  $row->ipb_by, $row->ipb_by_text, $row->ipb_by_actor ?? null
474  ) );
475 
476  $this->setTimestamp( wfTimestamp( TS_MW, $row->ipb_timestamp ) );
477  $this->mAuto = $row->ipb_auto;
478  $this->setHideName( $row->ipb_deleted );
479  $this->mId = (int)$row->ipb_id;
480  $this->mParentBlockId = $row->ipb_parent_block_id;
481 
482  // I wish I didn't have to do this
483  $db = wfGetDB( DB_REPLICA );
484  $this->setExpiry( $db->decodeExpiry( $row->ipb_expiry ) );
485  $this->setReason(
487  // Legacy because $row may have come from self::selectFields()
488  ->getCommentLegacy( $db, 'ipb_reason', $row )->text
489  );
490 
491  $this->isHardblock( !$row->ipb_anon_only );
492  $this->isAutoblocking( $row->ipb_enable_autoblock );
493  $this->isSitewide( (bool)$row->ipb_sitewide );
494 
495  $this->isCreateAccountBlocked( $row->ipb_create_account );
496  $this->isEmailBlocked( $row->ipb_block_email );
497  $this->isUsertalkEditAllowed( $row->ipb_allow_usertalk );
498  }
499 
505  public static function newFromRow( $row ) {
506  $block = new Block;
507  $block->initFromRow( $row );
508  return $block;
509  }
510 
517  public function delete() {
518  if ( wfReadOnly() ) {
519  return false;
520  }
521 
522  if ( !$this->getId() ) {
523  throw new MWException( "Block::delete() requires that the mId member be filled\n" );
524  }
525 
526  $dbw = wfGetDB( DB_MASTER );
527 
528  $this->getBlockRestrictionStore()->deleteByParentBlockId( $this->getId() );
529  $dbw->delete( 'ipblocks', [ 'ipb_parent_block_id' => $this->getId() ], __METHOD__ );
530 
531  $this->getBlockRestrictionStore()->deleteByBlockId( $this->getId() );
532  $dbw->delete( 'ipblocks', [ 'ipb_id' => $this->getId() ], __METHOD__ );
533 
534  return $dbw->affectedRows() > 0;
535  }
536 
545  public function insert( $dbw = null ) {
546  global $wgBlockDisablesLogin;
547 
548  if ( $this->getSystemBlockType() !== null ) {
549  throw new MWException( 'Cannot insert a system block into the database' );
550  }
551  if ( !$this->getBlocker() || $this->getBlocker()->getName() === '' ) {
552  throw new MWException( 'Cannot insert a block without a blocker set' );
553  }
554 
555  wfDebug( "Block::insert; timestamp {$this->mTimestamp}\n" );
556 
557  if ( $dbw === null ) {
558  $dbw = wfGetDB( DB_MASTER );
559  }
560 
562 
563  $row = $this->getDatabaseArray( $dbw );
564 
565  $dbw->insert( 'ipblocks', $row, __METHOD__, [ 'IGNORE' ] );
566  $affected = $dbw->affectedRows();
567  if ( $affected ) {
568  $this->setId( $dbw->insertId() );
569  if ( $this->restrictions ) {
570  $this->getBlockRestrictionStore()->insert( $this->restrictions );
571  }
572  }
573 
574  # Don't collide with expired blocks.
575  # Do this after trying to insert to avoid locking.
576  if ( !$affected ) {
577  # T96428: The ipb_address index uses a prefix on a field, so
578  # use a standard SELECT + DELETE to avoid annoying gap locks.
579  $ids = $dbw->selectFieldValues( 'ipblocks',
580  'ipb_id',
581  [
582  'ipb_address' => $row['ipb_address'],
583  'ipb_user' => $row['ipb_user'],
584  'ipb_expiry < ' . $dbw->addQuotes( $dbw->timestamp() )
585  ],
586  __METHOD__
587  );
588  if ( $ids ) {
589  $dbw->delete( 'ipblocks', [ 'ipb_id' => $ids ], __METHOD__ );
590  $this->getBlockRestrictionStore()->deleteByBlockId( $ids );
591  $dbw->insert( 'ipblocks', $row, __METHOD__, [ 'IGNORE' ] );
592  $affected = $dbw->affectedRows();
593  $this->setId( $dbw->insertId() );
594  if ( $this->restrictions ) {
595  $this->getBlockRestrictionStore()->insert( $this->restrictions );
596  }
597  }
598  }
599 
600  if ( $affected ) {
601  $auto_ipd_ids = $this->doRetroactiveAutoblock();
602 
603  if ( $wgBlockDisablesLogin && $this->target instanceof User ) {
604  // Change user login token to force them to be logged out.
605  $this->target->setToken();
606  $this->target->saveSettings();
607  }
608 
609  return [ 'id' => $this->mId, 'autoIds' => $auto_ipd_ids ];
610  }
611 
612  return false;
613  }
614 
622  public function update() {
623  wfDebug( "Block::update; timestamp {$this->mTimestamp}\n" );
624  $dbw = wfGetDB( DB_MASTER );
625 
626  $dbw->startAtomic( __METHOD__ );
627 
628  $result = $dbw->update(
629  'ipblocks',
630  $this->getDatabaseArray( $dbw ),
631  [ 'ipb_id' => $this->getId() ],
632  __METHOD__
633  );
634 
635  // Only update the restrictions if they have been modified.
636  if ( $this->restrictions !== null ) {
637  // An empty array should remove all of the restrictions.
638  if ( empty( $this->restrictions ) ) {
639  $success = $this->getBlockRestrictionStore()->deleteByBlockId( $this->getId() );
640  } else {
641  $success = $this->getBlockRestrictionStore()->update( $this->restrictions );
642  }
643  // Update the result. The first false is the result, otherwise, true.
644  $result = $result && $success;
645  }
646 
647  if ( $this->isAutoblocking() ) {
648  // update corresponding autoblock(s) (T50813)
649  $dbw->update(
650  'ipblocks',
651  $this->getAutoblockUpdateArray( $dbw ),
652  [ 'ipb_parent_block_id' => $this->getId() ],
653  __METHOD__
654  );
655 
656  // Only update the restrictions if they have been modified.
657  if ( $this->restrictions !== null ) {
658  $this->getBlockRestrictionStore()->updateByParentBlockId( $this->getId(), $this->restrictions );
659  }
660  } else {
661  // autoblock no longer required, delete corresponding autoblock(s)
662  $this->getBlockRestrictionStore()->deleteByParentBlockId( $this->getId() );
663  $dbw->delete(
664  'ipblocks',
665  [ 'ipb_parent_block_id' => $this->getId() ],
666  __METHOD__
667  );
668  }
669 
670  $dbw->endAtomic( __METHOD__ );
671 
672  if ( $result ) {
673  $auto_ipd_ids = $this->doRetroactiveAutoblock();
674  return [ 'id' => $this->mId, 'autoIds' => $auto_ipd_ids ];
675  }
676 
677  return $result;
678  }
679 
685  protected function getDatabaseArray( IDatabase $dbw ) {
686  $expiry = $dbw->encodeExpiry( $this->getExpiry() );
687 
688  if ( $this->forcedTargetID ) {
689  $uid = $this->forcedTargetID;
690  } else {
691  $uid = $this->target instanceof User ? $this->target->getId() : 0;
692  }
693 
694  $a = [
695  'ipb_address' => (string)$this->target,
696  'ipb_user' => $uid,
697  'ipb_timestamp' => $dbw->timestamp( $this->getTimestamp() ),
698  'ipb_auto' => $this->mAuto,
699  'ipb_anon_only' => !$this->isHardblock(),
700  'ipb_create_account' => $this->isCreateAccountBlocked(),
701  'ipb_enable_autoblock' => $this->isAutoblocking(),
702  'ipb_expiry' => $expiry,
703  'ipb_range_start' => $this->getRangeStart(),
704  'ipb_range_end' => $this->getRangeEnd(),
705  'ipb_deleted' => intval( $this->getHideName() ), // typecast required for SQLite
706  'ipb_block_email' => $this->isEmailBlocked(),
707  'ipb_allow_usertalk' => $this->isUsertalkEditAllowed(),
708  'ipb_parent_block_id' => $this->mParentBlockId,
709  'ipb_sitewide' => $this->isSitewide(),
710  ] + CommentStore::getStore()->insert( $dbw, 'ipb_reason', $this->getReason() )
711  + ActorMigration::newMigration()->getInsertValues( $dbw, 'ipb_by', $this->getBlocker() );
712 
713  return $a;
714  }
715 
720  protected function getAutoblockUpdateArray( IDatabase $dbw ) {
721  return [
722  'ipb_create_account' => $this->isCreateAccountBlocked(),
723  'ipb_deleted' => (int)$this->getHideName(), // typecast required for SQLite
724  'ipb_allow_usertalk' => $this->isUsertalkEditAllowed(),
725  'ipb_sitewide' => $this->isSitewide(),
726  ] + CommentStore::getStore()->insert( $dbw, 'ipb_reason', $this->getReason() )
727  + ActorMigration::newMigration()->getInsertValues( $dbw, 'ipb_by', $this->getBlocker() );
728  }
729 
736  protected function doRetroactiveAutoblock() {
737  $blockIds = [];
738  # If autoblock is enabled, autoblock the LAST IP(s) used
739  if ( $this->isAutoblocking() && $this->getType() == self::TYPE_USER ) {
740  wfDebug( "Doing retroactive autoblocks for " . $this->getTarget() . "\n" );
741 
742  $continue = Hooks::run(
743  'PerformRetroactiveAutoblock', [ $this, &$blockIds ] );
744 
745  if ( $continue ) {
746  self::defaultRetroactiveAutoblock( $this, $blockIds );
747  }
748  }
749  return $blockIds;
750  }
751 
759  protected static function defaultRetroactiveAutoblock( Block $block, array &$blockIds ) {
760  global $wgPutIPinRC;
761 
762  // No IPs are in recentchanges table, so nothing to select
763  if ( !$wgPutIPinRC ) {
764  return;
765  }
766 
767  // Autoblocks only apply to TYPE_USER
768  if ( $block->getType() !== self::TYPE_USER ) {
769  return;
770  }
771  $target = $block->getTarget(); // TYPE_USER => always a User object
772 
773  $dbr = wfGetDB( DB_REPLICA );
774  $rcQuery = ActorMigration::newMigration()->getWhere( $dbr, 'rc_user', $target, false );
775 
776  $options = [ 'ORDER BY' => 'rc_timestamp DESC' ];
777 
778  // Just the last IP used.
779  $options['LIMIT'] = 1;
780 
781  $res = $dbr->select(
782  [ 'recentchanges' ] + $rcQuery['tables'],
783  [ 'rc_ip' ],
784  $rcQuery['conds'],
785  __METHOD__,
786  $options,
787  $rcQuery['joins']
788  );
789 
790  if ( !$res->numRows() ) {
791  # No results, don't autoblock anything
792  wfDebug( "No IP found to retroactively autoblock\n" );
793  } else {
794  foreach ( $res as $row ) {
795  if ( $row->rc_ip ) {
796  $id = $block->doAutoblock( $row->rc_ip );
797  if ( $id ) {
798  $blockIds[] = $id;
799  }
800  }
801  }
802  }
803  }
804 
812  public static function isWhitelistedFromAutoblocks( $ip ) {
813  // Try to get the autoblock_whitelist from the cache, as it's faster
814  // than getting the msg raw and explode()'ing it.
815  $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
816  $lines = $cache->getWithSetCallback(
817  $cache->makeKey( 'ip-autoblock', 'whitelist' ),
818  $cache::TTL_DAY,
819  function ( $curValue, &$ttl, array &$setOpts ) {
820  $setOpts += Database::getCacheSetOptions( wfGetDB( DB_REPLICA ) );
821 
822  return explode( "\n",
823  wfMessage( 'autoblock_whitelist' )->inContentLanguage()->plain() );
824  }
825  );
826 
827  wfDebug( "Checking the autoblock whitelist..\n" );
828 
829  foreach ( $lines as $line ) {
830  # List items only
831  if ( substr( $line, 0, 1 ) !== '*' ) {
832  continue;
833  }
834 
835  $wlEntry = substr( $line, 1 );
836  $wlEntry = trim( $wlEntry );
837 
838  wfDebug( "Checking $ip against $wlEntry..." );
839 
840  # Is the IP in this range?
841  if ( IP::isInRange( $ip, $wlEntry ) ) {
842  wfDebug( " IP $ip matches $wlEntry, not autoblocking\n" );
843  return true;
844  } else {
845  wfDebug( " No match\n" );
846  }
847  }
848 
849  return false;
850  }
851 
858  public function doAutoblock( $autoblockIP ) {
859  # If autoblocks are disabled, go away.
860  if ( !$this->isAutoblocking() ) {
861  return false;
862  }
863 
864  # Don't autoblock for system blocks
865  if ( $this->getSystemBlockType() !== null ) {
866  throw new MWException( 'Cannot autoblock from a system block' );
867  }
868 
869  # Check for presence on the autoblock whitelist.
870  if ( self::isWhitelistedFromAutoblocks( $autoblockIP ) ) {
871  return false;
872  }
873 
874  // Avoid PHP 7.1 warning of passing $this by reference
875  $block = $this;
876  # Allow hooks to cancel the autoblock.
877  if ( !Hooks::run( 'AbortAutoblock', [ $autoblockIP, &$block ] ) ) {
878  wfDebug( "Autoblock aborted by hook.\n" );
879  return false;
880  }
881 
882  # It's okay to autoblock. Go ahead and insert/update the block...
883 
884  # Do not add a *new* block if the IP is already blocked.
885  $ipblock = self::newFromTarget( $autoblockIP );
886  if ( $ipblock ) {
887  # Check if the block is an autoblock and would exceed the user block
888  # if renewed. If so, do nothing, otherwise prolong the block time...
889  if ( $ipblock->mAuto && // @todo Why not compare $ipblock->mExpiry?
890  $this->getExpiry() > self::getAutoblockExpiry( $ipblock->getTimestamp() )
891  ) {
892  # Reset block timestamp to now and its expiry to
893  # $wgAutoblockExpiry in the future
894  $ipblock->updateTimestamp();
895  }
896  return false;
897  }
898 
899  # Make a new block object with the desired properties.
900  $autoblock = new Block;
901  wfDebug( "Autoblocking {$this->getTarget()}@" . $autoblockIP . "\n" );
902  $autoblock->setTarget( $autoblockIP );
903  $autoblock->setBlocker( $this->getBlocker() );
904  $autoblock->setReason(
905  wfMessage( 'autoblocker', $this->getTarget(), $this->getReason() )
906  ->inContentLanguage()->plain()
907  );
908  $timestamp = wfTimestampNow();
909  $autoblock->setTimestamp( $timestamp );
910  $autoblock->mAuto = 1;
911  $autoblock->isCreateAccountBlocked( $this->isCreateAccountBlocked() );
912  # Continue suppressing the name if needed
913  $autoblock->setHideName( $this->getHideName() );
914  $autoblock->isUsertalkEditAllowed( $this->isUsertalkEditAllowed() );
915  $autoblock->mParentBlockId = $this->mId;
916  $autoblock->isSitewide( $this->isSitewide() );
917  $autoblock->setRestrictions( $this->getRestrictions() );
918 
919  if ( $this->getExpiry() == 'infinity' ) {
920  # Original block was indefinite, start an autoblock now
921  $autoblock->setExpiry( self::getAutoblockExpiry( $timestamp ) );
922  } else {
923  # If the user is already blocked with an expiry date, we don't
924  # want to pile on top of that.
925  $autoblock->setExpiry( min( $this->getExpiry(), self::getAutoblockExpiry( $timestamp ) ) );
926  }
927 
928  # Insert the block...
929  $status = $autoblock->insert();
930  return $status
931  ? $status['id']
932  : false;
933  }
934 
939  public function deleteIfExpired() {
940  if ( $this->isExpired() ) {
941  wfDebug( "Block::deleteIfExpired() -- deleting\n" );
942  $this->delete();
943  $retVal = true;
944  } else {
945  wfDebug( "Block::deleteIfExpired() -- not expired\n" );
946  $retVal = false;
947  }
948 
949  return $retVal;
950  }
951 
956  public function isExpired() {
957  $timestamp = wfTimestampNow();
958  wfDebug( "Block::isExpired() checking current " . $timestamp . " vs $this->mExpiry\n" );
959 
960  if ( !$this->getExpiry() ) {
961  return false;
962  } else {
963  return $timestamp > $this->getExpiry();
964  }
965  }
966 
973  public function isValid() {
974  wfDeprecated( __METHOD__, '1.33' );
975  return $this->getTarget() != null;
976  }
977 
981  public function updateTimestamp() {
982  if ( $this->mAuto ) {
983  $this->setTimestamp( wfTimestamp() );
984  $this->setExpiry( self::getAutoblockExpiry( $this->getTimestamp() ) );
985 
986  $dbw = wfGetDB( DB_MASTER );
987  $dbw->update( 'ipblocks',
988  [ /* SET */
989  'ipb_timestamp' => $dbw->timestamp( $this->getTimestamp() ),
990  'ipb_expiry' => $dbw->timestamp( $this->getExpiry() ),
991  ],
992  [ /* WHERE */
993  'ipb_id' => $this->getId(),
994  ],
995  __METHOD__
996  );
997  }
998  }
999 
1005  public function getRangeStart() {
1006  switch ( $this->type ) {
1007  case self::TYPE_USER:
1008  return '';
1009  case self::TYPE_IP:
1010  return IP::toHex( $this->target );
1011  case self::TYPE_RANGE:
1012  list( $start, /*...*/ ) = IP::parseRange( $this->target );
1013  return $start;
1014  default:
1015  throw new MWException( "Block with invalid type" );
1016  }
1017  }
1018 
1024  public function getRangeEnd() {
1025  switch ( $this->type ) {
1026  case self::TYPE_USER:
1027  return '';
1028  case self::TYPE_IP:
1029  return IP::toHex( $this->target );
1030  case self::TYPE_RANGE:
1031  list( /*...*/, $end ) = IP::parseRange( $this->target );
1032  return $end;
1033  default:
1034  throw new MWException( "Block with invalid type" );
1035  }
1036  }
1037 
1043  public function getBy() {
1044  return $this->getBlocker()->getId();
1045  }
1046 
1052  public function getByName() {
1053  return $this->getBlocker()->getName();
1054  }
1055 
1060  public function getId() {
1061  return $this->mId;
1062  }
1063 
1070  private function setId( $blockId ) {
1071  $this->mId = (int)$blockId;
1072 
1073  if ( is_array( $this->restrictions ) ) {
1074  $this->restrictions = $this->getBlockRestrictionStore()->setBlockId(
1075  $blockId, $this->restrictions
1076  );
1077  }
1078 
1079  return $this;
1080  }
1081 
1088  public function getReason() {
1089  return $this->mReason;
1090  }
1091 
1098  public function setReason( $reason ) {
1099  $this->mReason = $reason;
1100  }
1101 
1108  public function getHideName() {
1109  return $this->mHideName;
1110  }
1111 
1118  public function setHideName( $hideName ) {
1119  $this->mHideName = $hideName;
1120  }
1121 
1127  public function getSystemBlockType() {
1128  return $this->systemBlockType;
1129  }
1130 
1137  public function fromMaster( $x = null ) {
1138  return wfSetVar( $this->mFromMaster, $x );
1139  }
1140 
1146  public function isHardblock( $x = null ) {
1147  wfSetVar( $this->isHardblock, $x );
1148 
1149  # You can't *not* hardblock a user
1150  return $this->getType() == self::TYPE_USER
1151  ? true
1153  }
1154 
1159  public function isAutoblocking( $x = null ) {
1160  wfSetVar( $this->isAutoblocking, $x );
1161 
1162  # You can't put an autoblock on an IP or range as we don't have any history to
1163  # look over to get more IPs from
1164  return $this->getType() == self::TYPE_USER
1165  ? $this->isAutoblocking
1166  : false;
1167  }
1168 
1178  public function isSitewide( $x = null ) {
1179  return wfSetVar( $this->isSitewide, $x );
1180  }
1181 
1191  public function isCreateAccountBlocked( $x = null ) {
1192  return wfSetVar( $this->blockCreateAccount, $x );
1193  }
1194 
1204  public function isEmailBlocked( $x = null ) {
1205  return wfSetVar( $this->mBlockEmail, $x );
1206  }
1207 
1217  public function isUsertalkEditAllowed( $x = null ) {
1218  return wfSetVar( $this->allowUsertalk, $x );
1219  }
1220 
1231  public function appliesToRight( $right ) {
1232  $config = RequestContext::getMain()->getConfig();
1233  $blockDisablesLogin = $config->get( 'BlockDisablesLogin' );
1234 
1235  $res = null;
1236  switch ( $right ) {
1237  case 'edit':
1238  // TODO: fix this case to return proper value
1239  $res = true;
1240  break;
1241  case 'createaccount':
1242  $res = $this->isCreateAccountBlocked();
1243  break;
1244  case 'sendemail':
1245  $res = $this->isEmailBlocked();
1246  break;
1247  case 'upload':
1248  // Until T6995 is completed
1249  $res = $this->isSitewide();
1250  break;
1251  case 'read':
1252  $res = false;
1253  break;
1254  case 'purge':
1255  $res = false;
1256  break;
1257  }
1258  if ( !$res && $blockDisablesLogin ) {
1259  // If a block would disable login, then it should
1260  // prevent any right that all users cannot do
1261  $anon = new User;
1262  $res = $anon->isAllowed( $right ) ? $res : true;
1263  }
1264 
1265  return $res;
1266  }
1267 
1277  public function prevents( $action, $x = null ) {
1278  $config = RequestContext::getMain()->getConfig();
1279  $blockDisablesLogin = $config->get( 'BlockDisablesLogin' );
1280  $blockAllowsUTEdit = $config->get( 'BlockAllowsUTEdit' );
1281 
1282  $res = null;
1283  switch ( $action ) {
1284  case 'edit':
1285  # For now... <evil laugh>
1286  $res = true;
1287  break;
1288  case 'createaccount':
1289  $res = wfSetVar( $this->blockCreateAccount, $x );
1290  break;
1291  case 'sendemail':
1292  $res = wfSetVar( $this->mBlockEmail, $x );
1293  break;
1294  case 'upload':
1295  // Until T6995 is completed
1296  $res = $this->isSitewide();
1297  break;
1298  case 'editownusertalk':
1299  // NOTE: this check is not reliable on partial blocks
1300  // since partially blocked users are always allowed to edit
1301  // their own talk page unless a restriction exists on the
1302  // page or User_talk: namespace
1303  wfSetVar( $this->allowUsertalk, $x === null ? null : !$x );
1304  $res = !$this->isUsertalkEditAllowed();
1305 
1306  // edit own user talk can be disabled by config
1307  if ( !$blockAllowsUTEdit ) {
1308  $res = true;
1309  }
1310  break;
1311  case 'read':
1312  $res = false;
1313  break;
1314  case 'purge':
1315  $res = false;
1316  break;
1317  }
1318  if ( !$res && $blockDisablesLogin ) {
1319  // If a block would disable login, then it should
1320  // prevent any action that all users cannot do
1321  $anon = new User;
1322  $res = $anon->isAllowed( $action ) ? $res : true;
1323  }
1324 
1325  return $res;
1326  }
1327 
1332  public function getRedactedName() {
1333  if ( $this->mAuto ) {
1334  return Html::element(
1335  'span',
1336  [ 'class' => 'mw-autoblockid' ],
1337  wfMessage( 'autoblockid', $this->mId )->text()
1338  );
1339  } else {
1340  return htmlspecialchars( $this->getTarget() );
1341  }
1342  }
1343 
1350  public static function getAutoblockExpiry( $timestamp ) {
1351  global $wgAutoblockExpiry;
1352 
1353  return wfTimestamp( TS_MW, wfTimestamp( TS_UNIX, $timestamp ) + $wgAutoblockExpiry );
1354  }
1355 
1359  public static function purgeExpired() {
1360  if ( wfReadOnly() ) {
1361  return;
1362  }
1363 
1365  wfGetDB( DB_MASTER ),
1366  __METHOD__,
1367  function ( IDatabase $dbw, $fname ) {
1368  $ids = $dbw->selectFieldValues( 'ipblocks',
1369  'ipb_id',
1370  [ 'ipb_expiry < ' . $dbw->addQuotes( $dbw->timestamp() ) ],
1371  $fname
1372  );
1373  if ( $ids ) {
1374  $blockRestrictionStore = MediaWikiServices::getInstance()->getBlockRestrictionStore();
1375  $blockRestrictionStore->deleteByBlockId( $ids );
1376 
1377  $dbw->delete( 'ipblocks', [ 'ipb_id' => $ids ], $fname );
1378  }
1379  }
1380  ) );
1381  }
1382 
1403  public static function newFromTarget( $specificTarget, $vagueTarget = null, $fromMaster = false ) {
1404  list( $target, $type ) = self::parseTarget( $specificTarget );
1405  if ( $type == self::TYPE_ID || $type == self::TYPE_AUTO ) {
1406  return self::newFromID( $target );
1407 
1408  } elseif ( $target === null && $vagueTarget == '' ) {
1409  # We're not going to find anything useful here
1410  # Be aware that the == '' check is explicit, since empty values will be
1411  # passed by some callers (T31116)
1412  return null;
1413 
1414  } elseif ( in_array(
1415  $type,
1416  [ self::TYPE_USER, self::TYPE_IP, self::TYPE_RANGE, null ] )
1417  ) {
1418  $block = new Block();
1419  $block->fromMaster( $fromMaster );
1420 
1421  if ( $type !== null ) {
1422  $block->setTarget( $target );
1423  }
1424 
1425  if ( $block->newLoad( $vagueTarget ) ) {
1426  return $block;
1427  }
1428  }
1429  return null;
1430  }
1431 
1442  public static function getBlocksForIPList( array $ipChain, $isAnon, $fromMaster = false ) {
1443  if ( $ipChain === [] ) {
1444  return [];
1445  }
1446 
1447  $conds = [];
1448  $proxyLookup = MediaWikiServices::getInstance()->getProxyLookup();
1449  foreach ( array_unique( $ipChain ) as $ipaddr ) {
1450  # Discard invalid IP addresses. Since XFF can be spoofed and we do not
1451  # necessarily trust the header given to us, make sure that we are only
1452  # checking for blocks on well-formatted IP addresses (IPv4 and IPv6).
1453  # Do not treat private IP spaces as special as it may be desirable for wikis
1454  # to block those IP ranges in order to stop misbehaving proxies that spoof XFF.
1455  if ( !IP::isValid( $ipaddr ) ) {
1456  continue;
1457  }
1458  # Don't check trusted IPs (includes local squids which will be in every request)
1459  if ( $proxyLookup->isTrustedProxy( $ipaddr ) ) {
1460  continue;
1461  }
1462  # Check both the original IP (to check against single blocks), as well as build
1463  # the clause to check for rangeblocks for the given IP.
1464  $conds['ipb_address'][] = $ipaddr;
1465  $conds[] = self::getRangeCond( IP::toHex( $ipaddr ) );
1466  }
1467 
1468  if ( $conds === [] ) {
1469  return [];
1470  }
1471 
1472  if ( $fromMaster ) {
1473  $db = wfGetDB( DB_MASTER );
1474  } else {
1475  $db = wfGetDB( DB_REPLICA );
1476  }
1477  $conds = $db->makeList( $conds, LIST_OR );
1478  if ( !$isAnon ) {
1479  $conds = [ $conds, 'ipb_anon_only' => 0 ];
1480  }
1481  $blockQuery = self::getQueryInfo();
1482  $rows = $db->select(
1483  $blockQuery['tables'],
1484  array_merge( [ 'ipb_range_start', 'ipb_range_end' ], $blockQuery['fields'] ),
1485  $conds,
1486  __METHOD__,
1487  [],
1488  $blockQuery['joins']
1489  );
1490 
1491  $blocks = [];
1492  foreach ( $rows as $row ) {
1493  $block = self::newFromRow( $row );
1494  if ( !$block->isExpired() ) {
1495  $blocks[] = $block;
1496  }
1497  }
1498 
1499  return $blocks;
1500  }
1501 
1523  public static function chooseBlock( array $blocks, array $ipChain ) {
1524  if ( $blocks === [] ) {
1525  return null;
1526  } elseif ( count( $blocks ) == 1 ) {
1527  return $blocks[0];
1528  }
1529 
1530  // Sort hard blocks before soft ones and secondarily sort blocks
1531  // that disable account creation before those that don't.
1532  usort( $blocks, function ( Block $a, Block $b ) {
1533  $aWeight = (int)$a->isHardblock() . (int)$a->appliesToRight( 'createaccount' );
1534  $bWeight = (int)$b->isHardblock() . (int)$b->appliesToRight( 'createaccount' );
1535  return strcmp( $bWeight, $aWeight ); // highest weight first
1536  } );
1537 
1538  $blocksListExact = [
1539  'hard' => false,
1540  'disable_create' => false,
1541  'other' => false,
1542  'auto' => false
1543  ];
1544  $blocksListRange = [
1545  'hard' => false,
1546  'disable_create' => false,
1547  'other' => false,
1548  'auto' => false
1549  ];
1550  $ipChain = array_reverse( $ipChain );
1551 
1553  foreach ( $blocks as $block ) {
1554  // Stop searching if we have already have a "better" block. This
1555  // is why the order of the blocks matters
1556  if ( !$block->isHardblock() && $blocksListExact['hard'] ) {
1557  break;
1558  } elseif ( !$block->appliesToRight( 'createaccount' ) && $blocksListExact['disable_create'] ) {
1559  break;
1560  }
1561 
1562  foreach ( $ipChain as $checkip ) {
1563  $checkipHex = IP::toHex( $checkip );
1564  if ( (string)$block->getTarget() === $checkip ) {
1565  if ( $block->isHardblock() ) {
1566  $blocksListExact['hard'] = $blocksListExact['hard'] ?: $block;
1567  } elseif ( $block->appliesToRight( 'createaccount' ) ) {
1568  $blocksListExact['disable_create'] = $blocksListExact['disable_create'] ?: $block;
1569  } elseif ( $block->mAuto ) {
1570  $blocksListExact['auto'] = $blocksListExact['auto'] ?: $block;
1571  } else {
1572  $blocksListExact['other'] = $blocksListExact['other'] ?: $block;
1573  }
1574  // We found closest exact match in the ip list, so go to the next Block
1575  break;
1576  } elseif ( array_filter( $blocksListExact ) == []
1577  && $block->getRangeStart() <= $checkipHex
1578  && $block->getRangeEnd() >= $checkipHex
1579  ) {
1580  if ( $block->isHardblock() ) {
1581  $blocksListRange['hard'] = $blocksListRange['hard'] ?: $block;
1582  } elseif ( $block->appliesToRight( 'createaccount' ) ) {
1583  $blocksListRange['disable_create'] = $blocksListRange['disable_create'] ?: $block;
1584  } elseif ( $block->mAuto ) {
1585  $blocksListRange['auto'] = $blocksListRange['auto'] ?: $block;
1586  } else {
1587  $blocksListRange['other'] = $blocksListRange['other'] ?: $block;
1588  }
1589  break;
1590  }
1591  }
1592  }
1593 
1594  if ( array_filter( $blocksListExact ) == [] ) {
1595  $blocksList = &$blocksListRange;
1596  } else {
1597  $blocksList = &$blocksListExact;
1598  }
1599 
1600  $chosenBlock = null;
1601  if ( $blocksList['hard'] ) {
1602  $chosenBlock = $blocksList['hard'];
1603  } elseif ( $blocksList['disable_create'] ) {
1604  $chosenBlock = $blocksList['disable_create'];
1605  } elseif ( $blocksList['other'] ) {
1606  $chosenBlock = $blocksList['other'];
1607  } elseif ( $blocksList['auto'] ) {
1608  $chosenBlock = $blocksList['auto'];
1609  } else {
1610  throw new MWException( "Proxy block found, but couldn't be classified." );
1611  }
1612 
1613  return $chosenBlock;
1614  }
1615 
1625  public static function parseTarget( $target ) {
1626  # We may have been through this before
1627  if ( $target instanceof User ) {
1628  if ( IP::isValid( $target->getName() ) ) {
1629  return [ $target, self::TYPE_IP ];
1630  } else {
1631  return [ $target, self::TYPE_USER ];
1632  }
1633  } elseif ( $target === null ) {
1634  return [ null, null ];
1635  }
1636 
1637  $target = trim( $target );
1638 
1639  if ( IP::isValid( $target ) ) {
1640  # We can still create a User if it's an IP address, but we need to turn
1641  # off validation checking (which would exclude IP addresses)
1642  return [
1645  ];
1646 
1647  } elseif ( IP::isValidRange( $target ) ) {
1648  # Can't create a User from an IP range
1650  }
1651 
1652  # Consider the possibility that this is not a username at all
1653  # but actually an old subpage (T31797)
1654  if ( strpos( $target, '/' ) !== false ) {
1655  # An old subpage, drill down to the user behind it
1656  $target = explode( '/', $target )[0];
1657  }
1658 
1659  $userObj = User::newFromName( $target );
1660  if ( $userObj instanceof User ) {
1661  # Note that since numbers are valid usernames, a $target of "12345" will be
1662  # considered a User. If you want to pass a block ID, prepend a hash "#12345",
1663  # since hash characters are not valid in usernames or titles generally.
1664  return [ $userObj, self::TYPE_USER ];
1665 
1666  } elseif ( preg_match( '/^#\d+$/', $target ) ) {
1667  # Autoblock reference in the form "#12345"
1668  return [ substr( $target, 1 ), self::TYPE_AUTO ];
1669 
1670  } else {
1671  # WTF?
1672  return [ null, null ];
1673  }
1674  }
1675 
1682  public function getType() {
1683  return $this->mAuto
1684  ? self::TYPE_AUTO
1685  : $this->type;
1686  }
1687 
1695  public function getTargetAndType() {
1696  return [ $this->getTarget(), $this->getType() ];
1697  }
1698 
1705  public function getTarget() {
1706  return $this->target;
1707  }
1708 
1715  public function getExpiry() {
1716  return $this->mExpiry;
1717  }
1718 
1725  public function setExpiry( $expiry ) {
1726  $this->mExpiry = $expiry;
1727  }
1728 
1735  public function getTimestamp() {
1736  return $this->mTimestamp;
1737  }
1738 
1745  public function setTimestamp( $timestamp ) {
1746  $this->mTimestamp = $timestamp;
1747  }
1748 
1753  public function setTarget( $target ) {
1754  list( $this->target, $this->type ) = self::parseTarget( $target );
1755  }
1756 
1761  public function getBlocker() {
1762  return $this->blocker;
1763  }
1764 
1769  public function setBlocker( $user ) {
1770  if ( is_string( $user ) ) {
1771  $user = User::newFromName( $user, false );
1772  }
1773 
1774  if ( $user->isAnon() && User::isUsableName( $user->getName() ) ) {
1775  throw new InvalidArgumentException(
1776  'Blocker must be a local user or a name that cannot be a local user'
1777  );
1778  }
1779 
1780  $this->blocker = $user;
1781  }
1782 
1791  public function setCookie( WebResponse $response ) {
1792  // Calculate the default expiry time.
1793  $maxExpiryTime = wfTimestamp( TS_MW, wfTimestamp() + ( 24 * 60 * 60 ) );
1794 
1795  // Use the Block's expiry time only if it's less than the default.
1796  $expiryTime = $this->getExpiry();
1797  if ( $expiryTime === 'infinity' || $expiryTime > $maxExpiryTime ) {
1798  $expiryTime = $maxExpiryTime;
1799  }
1800 
1801  // Set the cookie. Reformat the MediaWiki datetime as a Unix timestamp for the cookie.
1802  $expiryValue = DateTime::createFromFormat( 'YmdHis', $expiryTime )->format( 'U' );
1803  $cookieOptions = [ 'httpOnly' => false ];
1804  $cookieValue = $this->getCookieValue();
1805  $response->setCookie( 'BlockID', $cookieValue, $expiryValue, $cookieOptions );
1806  }
1807 
1815  public static function clearCookie( WebResponse $response ) {
1816  $response->clearCookie( 'BlockID', [ 'httpOnly' => false ] );
1817  }
1818 
1828  public function getCookieValue() {
1829  $config = RequestContext::getMain()->getConfig();
1830  $id = $this->getId();
1831  $secretKey = $config->get( 'SecretKey' );
1832  if ( !$secretKey ) {
1833  // If there's no secret key, don't append a HMAC.
1834  return $id;
1835  }
1836  $hmac = MWCryptHash::hmac( $id, $secretKey, false );
1837  $cookieValue = $id . '!' . $hmac;
1838  return $cookieValue;
1839  }
1840 
1851  public static function getIdFromCookieValue( $cookieValue ) {
1852  // Extract the ID prefix from the cookie value (may be the whole value, if no bang found).
1853  $bangPos = strpos( $cookieValue, '!' );
1854  $id = ( $bangPos === false ) ? $cookieValue : substr( $cookieValue, 0, $bangPos );
1855  // Get the site-wide secret key.
1856  $config = RequestContext::getMain()->getConfig();
1857  $secretKey = $config->get( 'SecretKey' );
1858  if ( !$secretKey ) {
1859  // If there's no secret key, just use the ID as given.
1860  return $id;
1861  }
1862  $storedHmac = substr( $cookieValue, $bangPos + 1 );
1863  $calculatedHmac = MWCryptHash::hmac( $id, $secretKey, false );
1864  if ( $calculatedHmac === $storedHmac ) {
1865  return $id;
1866  } else {
1867  return null;
1868  }
1869  }
1870 
1879  $params = $this->getBlockErrorParams( $context );
1880 
1881  $msg = 'blockedtext';
1882  if ( $this->getSystemBlockType() !== null ) {
1883  $msg = 'systemblockedtext';
1884  } elseif ( $this->mAuto ) {
1885  $msg = 'autoblockedtext';
1886  } elseif ( !$this->isSitewide() ) {
1887  $msg = 'blockedtext-partial';
1888  }
1889 
1890  array_unshift( $params, $msg );
1891 
1892  return $params;
1893  }
1894 
1903  $blocker = $this->getBlocker();
1904  if ( $blocker instanceof User ) { // local user
1905  $blockerUserpage = $blocker->getUserPage();
1906  $link = "[[{$blockerUserpage->getPrefixedText()}|{$blockerUserpage->getText()}]]";
1907  } else { // foreign user
1908  $link = $blocker;
1909  }
1910 
1911  $reason = $this->getReason();
1912  if ( $reason == '' ) {
1913  $reason = $context->msg( 'blockednoreason' )->text();
1914  }
1915 
1916  /* $ip returns who *is* being blocked, $intended contains who was meant to be blocked.
1917  * This could be a username, an IP range, or a single IP. */
1918  $intended = $this->getTarget();
1920  $lang = $context->getLanguage();
1921 
1922  return [
1923  $link,
1924  $reason,
1925  $context->getRequest()->getIP(),
1926  $this->getByName(),
1927  $systemBlockType ?? $this->getId(),
1928  $lang->formatExpiry( $this->getExpiry() ),
1929  (string)$intended,
1930  $lang->userTimeAndDate( $this->getTimestamp(), $context->getUser() ),
1931  ];
1932  }
1933 
1943  public function getRestrictions() {
1944  if ( $this->restrictions === null ) {
1945  // If the block id has not been set, then do not attempt to load the
1946  // restrictions.
1947  if ( !$this->mId ) {
1948  return [];
1949  }
1950  $this->restrictions = $this->getBlockRestrictionStore()->loadByBlockId( $this->mId );
1951  }
1952 
1953  return $this->restrictions;
1954  }
1955 
1963  public function setRestrictions( array $restrictions ) {
1964  $this->restrictions = array_filter( $restrictions, function ( $restriction ) {
1965  return $restriction instanceof Restriction;
1966  } );
1967 
1968  return $this;
1969  }
1970 
1997  public function appliesToUsertalk( Title $usertalk = null ) {
1998  if ( !$usertalk ) {
1999  if ( $this->target instanceof User ) {
2000  $usertalk = $this->target->getTalkPage();
2001  } else {
2002  throw new InvalidArgumentException(
2003  '$usertalk must be provided if block target is not a user/IP'
2004  );
2005  }
2006  }
2007 
2008  if ( $usertalk->getNamespace() !== NS_USER_TALK ) {
2009  throw new InvalidArgumentException(
2010  '$usertalk must be a user talk page'
2011  );
2012  }
2013 
2014  if ( !$this->isSitewide() ) {
2015  if ( $this->appliesToPage( $usertalk->getArticleID() ) ) {
2016  return true;
2017  }
2018  if ( !$this->appliesToNamespace( NS_USER_TALK ) ) {
2019  return false;
2020  }
2021  }
2022 
2023  // This is a type of block which uses the ipb_allow_usertalk
2024  // flag. The flag can still be overridden by global configs.
2025  $config = RequestContext::getMain()->getConfig();
2026  if ( !$config->get( 'BlockAllowsUTEdit' ) ) {
2027  return true;
2028  }
2029  return !$this->isUsertalkEditAllowed();
2030  }
2031 
2043  public function appliesToTitle( Title $title ) {
2044  if ( $this->isSitewide() ) {
2045  return true;
2046  }
2047 
2048  $restrictions = $this->getRestrictions();
2049  foreach ( $restrictions as $restriction ) {
2050  if ( $restriction->matches( $title ) ) {
2051  return true;
2052  }
2053  }
2054 
2055  return false;
2056  }
2057 
2066  public function appliesToNamespace( $ns ) {
2067  if ( $this->isSitewide() ) {
2068  return true;
2069  }
2070 
2071  // Blocks do not apply to virtual namespaces.
2072  if ( $ns < 0 ) {
2073  return false;
2074  }
2075 
2076  $restriction = $this->findRestriction( NamespaceRestriction::TYPE, $ns );
2077 
2078  return (bool)$restriction;
2079  }
2080 
2094  public function appliesToPage( $pageId ) {
2095  if ( $this->isSitewide() ) {
2096  return true;
2097  }
2098 
2099  // If the pageId is not over zero, the block cannot apply to it.
2100  if ( $pageId <= 0 ) {
2101  return false;
2102  }
2103 
2104  $restriction = $this->findRestriction( PageRestriction::TYPE, $pageId );
2105 
2106  return (bool)$restriction;
2107  }
2108 
2116  private function findRestriction( $type, $value ) {
2117  $restrictions = $this->getRestrictions();
2118  foreach ( $restrictions as $restriction ) {
2119  if ( $restriction->getType() !== $type ) {
2120  continue;
2121  }
2122 
2123  if ( $restriction->getValue() === $value ) {
2124  return $restriction;
2125  }
2126  }
2127 
2128  return null;
2129  }
2130 
2138  public function shouldTrackWithCookie( $isIpUser ) {
2139  $config = RequestContext::getMain()->getConfig();
2140  switch ( $this->getType() ) {
2141  case self::TYPE_IP:
2142  case self::TYPE_RANGE:
2143  return $isIpUser && $config->get( 'CookieSetOnIpBlock' );
2144  case self::TYPE_USER:
2145  return !$isIpUser && $config->get( 'CookieSetOnAutoblock' ) && $this->isAutoblocking();
2146  default:
2147  return false;
2148  }
2149  }
2150 
2157  public function appliesToPasswordReset() {
2158  switch ( $this->getSystemBlockType() ) {
2159  case null:
2160  case 'global-block':
2161  return $this->isCreateAccountBlocked();
2162  case 'proxy':
2163  return true;
2164  case 'dnsbl':
2165  case 'wgSoftBlockRanges':
2166  return false;
2167  default:
2168  return true;
2169  }
2170  }
2171 
2178  return MediaWikiServices::getInstance()->getBlockRestrictionStore();
2179  }
2180 }
Block\appliesToPasswordReset
appliesToPasswordReset()
Check if the block prevents a user from resetting their password.
Definition: Block.php:2157
Block\prevents
prevents( $action, $x=null)
Get/set whether the Block prevents a given action.
Definition: Block.php:1277
$status
Status::newGood()` to allow deletion, and then `return false` from the hook function. Ensure you consume the 'ChangeTagAfterDelete' hook to carry out custom deletion actions. $tag:name of the tag $user:user initiating the action & $status:Status object. See above. 'ChangeTagsListActive':Allows you to nominate which of the tags your extension uses are in active use. & $tags:list of all active tags. Append to this array. 'ChangeTagsAfterUpdateTags':Called after tags have been updated with the ChangeTags::updateTags function. Params:$addedTags:tags effectively added in the update $removedTags:tags effectively removed in the update $prevTags:tags that were present prior to the update $rc_id:recentchanges table id $rev_id:revision table id $log_id:logging table id $params:tag params $rc:RecentChange being tagged when the tagging accompanies the action, or null $user:User who performed the tagging when the tagging is subsequent to the action, or null 'ChangeTagsAllowedAdd':Called when checking if a user can add tags to a change. & $allowedTags:List of all the tags the user is allowed to add. Any tags the user wants to add( $addTags) that are not in this array will cause it to fail. You may add or remove tags to this array as required. $addTags:List of tags user intends to add. $user:User who is adding the tags. 'ChangeUserGroups':Called before user groups are changed. $performer:The User who will perform the change $user:The User whose groups will be changed & $add:The groups that will be added & $remove:The groups that will be removed 'Collation::factory':Called if $wgCategoryCollation is an unknown collation. $collationName:Name of the collation in question & $collationObject:Null. Replace with a subclass of the Collation class that implements the collation given in $collationName. 'ConfirmEmailComplete':Called after a user 's email has been confirmed successfully. $user:user(object) whose email is being confirmed 'ContentAlterParserOutput':Modify parser output for a given content object. Called by Content::getParserOutput after parsing has finished. Can be used for changes that depend on the result of the parsing but have to be done before LinksUpdate is called(such as adding tracking categories based on the rendered HTML). $content:The Content to render $title:Title of the page, as context $parserOutput:ParserOutput to manipulate 'ContentGetParserOutput':Customize parser output for a given content object, called by AbstractContent::getParserOutput. May be used to override the normal model-specific rendering of page content. $content:The Content to render $title:Title of the page, as context $revId:The revision ID, as context $options:ParserOptions for rendering. To avoid confusing the parser cache, the output can only depend on parameters provided to this hook function, not on global state. $generateHtml:boolean, indicating whether full HTML should be generated. If false, generation of HTML may be skipped, but other information should still be present in the ParserOutput object. & $output:ParserOutput, to manipulate or replace 'ContentHandlerDefaultModelFor':Called when the default content model is determined for a given title. May be used to assign a different model for that title. $title:the Title in question & $model:the model name. Use with CONTENT_MODEL_XXX constants. 'ContentHandlerForModelID':Called when a ContentHandler is requested for a given content model name, but no entry for that model exists in $wgContentHandlers. Note:if your extension implements additional models via this hook, please use GetContentModels hook to make them known to core. $modeName:the requested content model name & $handler:set this to a ContentHandler object, if desired. 'ContentModelCanBeUsedOn':Called to determine whether that content model can be used on a given page. This is especially useful to prevent some content models to be used in some special location. $contentModel:ID of the content model in question $title:the Title in question. & $ok:Output parameter, whether it is OK to use $contentModel on $title. Handler functions that modify $ok should generally return false to prevent further hooks from further modifying $ok. 'ContribsPager::getQueryInfo':Before the contributions query is about to run & $pager:Pager object for contributions & $queryInfo:The query for the contribs Pager 'ContribsPager::reallyDoQuery':Called before really executing the query for My Contributions & $data:an array of results of all contribs queries $pager:The ContribsPager object hooked into $offset:Index offset, inclusive $limit:Exact query limit $descending:Query direction, false for ascending, true for descending 'ContributionsLineEnding':Called before a contributions HTML line is finished $page:SpecialPage object for contributions & $ret:the HTML line $row:the DB row for this line & $classes:the classes to add to the surrounding< li > & $attribs:associative array of other HTML attributes for the< li > element. Currently only data attributes reserved to MediaWiki are allowed(see Sanitizer::isReservedDataAttribute). 'ContributionsToolLinks':Change tool links above Special:Contributions $id:User identifier $title:User page title & $tools:Array of tool links $specialPage:SpecialPage instance for context and services. Can be either SpecialContributions or DeletedContributionsPage. Extensions should type hint against a generic SpecialPage though. 'ConvertContent':Called by AbstractContent::convert when a conversion to another content model is requested. Handler functions that modify $result should generally return false to disable further attempts at conversion. $content:The Content object to be converted. $toModel:The ID of the content model to convert to. $lossy:boolean indicating whether lossy conversion is allowed. & $result:Output parameter, in case the handler function wants to provide a converted Content object. Note that $result->getContentModel() must return $toModel. 'ContentSecurityPolicyDefaultSource':Modify the allowed CSP load sources. This affects all directives except for the script directive. If you want to add a script source, see ContentSecurityPolicyScriptSource hook. & $defaultSrc:Array of Content-Security-Policy allowed sources $policyConfig:Current configuration for the Content-Security-Policy header $mode:ContentSecurityPolicy::REPORT_ONLY_MODE or ContentSecurityPolicy::FULL_MODE depending on type of header 'ContentSecurityPolicyDirectives':Modify the content security policy directives. Use this only if ContentSecurityPolicyDefaultSource and ContentSecurityPolicyScriptSource do not meet your needs. & $directives:Array of CSP directives $policyConfig:Current configuration for the CSP header $mode:ContentSecurityPolicy::REPORT_ONLY_MODE or ContentSecurityPolicy::FULL_MODE depending on type of header 'ContentSecurityPolicyScriptSource':Modify the allowed CSP script sources. Note that you also have to use ContentSecurityPolicyDefaultSource if you want non-script sources to be loaded from whatever you add. & $scriptSrc:Array of CSP directives $policyConfig:Current configuration for the CSP header $mode:ContentSecurityPolicy::REPORT_ONLY_MODE or ContentSecurityPolicy::FULL_MODE depending on type of header 'CustomEditor':When invoking the page editor Return true to allow the normal editor to be used, or false if implementing a custom editor, e.g. for a special namespace, etc. $article:Article being edited $user:User performing the edit 'DatabaseOraclePostInit':Called after initialising an Oracle database $db:the DatabaseOracle object 'DeletedContribsPager::reallyDoQuery':Called before really executing the query for Special:DeletedContributions Similar to ContribsPager::reallyDoQuery & $data:an array of results of all contribs queries $pager:The DeletedContribsPager object hooked into $offset:Index offset, inclusive $limit:Exact query limit $descending:Query direction, false for ascending, true for descending 'DeletedContributionsLineEnding':Called before a DeletedContributions HTML line is finished. Similar to ContributionsLineEnding $page:SpecialPage object for DeletedContributions & $ret:the HTML line $row:the DB row for this line & $classes:the classes to add to the surrounding< li > & $attribs:associative array of other HTML attributes for the< li > element. Currently only data attributes reserved to MediaWiki are allowed(see Sanitizer::isReservedDataAttribute). 'DeleteUnknownPreferences':Called by the cleanupPreferences.php maintenance script to build a WHERE clause with which to delete preferences that are not known about. This hook is used by extensions that have dynamically-named preferences that should not be deleted in the usual cleanup process. For example, the Gadgets extension creates preferences prefixed with 'gadget-', and so anything with that prefix is excluded from the deletion. &where:An array that will be passed as the $cond parameter to IDatabase::select() to determine what will be deleted from the user_properties table. $db:The IDatabase object, useful for accessing $db->buildLike() etc. 'DifferenceEngineAfterLoadNewText':called in DifferenceEngine::loadNewText() after the new revision 's content has been loaded into the class member variable $differenceEngine->mNewContent but before returning true from this function. $differenceEngine:DifferenceEngine object 'DifferenceEngineLoadTextAfterNewContentIsLoaded':called in DifferenceEngine::loadText() after the new revision 's content has been loaded into the class member variable $differenceEngine->mNewContent but before checking if the variable 's value is null. This hook can be used to inject content into said class member variable. $differenceEngine:DifferenceEngine object 'DifferenceEngineMarkPatrolledLink':Allows extensions to change the "mark as patrolled" link which is shown both on the diff header as well as on the bottom of a page, usually wrapped in a span element which has class="patrollink". $differenceEngine:DifferenceEngine object & $markAsPatrolledLink:The "mark as patrolled" link HTML(string) $rcid:Recent change ID(rc_id) for this change(int) 'DifferenceEngineMarkPatrolledRCID':Allows extensions to possibly change the rcid parameter. For example the rcid might be set to zero due to the user being the same as the performer of the change but an extension might still want to show it under certain conditions. & $rcid:rc_id(int) of the change or 0 $differenceEngine:DifferenceEngine object $change:RecentChange object $user:User object representing the current user 'DifferenceEngineNewHeader':Allows extensions to change the $newHeader variable, which contains information about the new revision, such as the revision 's author, whether the revision was marked as a minor edit or not, etc. $differenceEngine:DifferenceEngine object & $newHeader:The string containing the various #mw-diff-otitle[1-5] divs, which include things like revision author info, revision comment, RevisionDelete link and more $formattedRevisionTools:Array containing revision tools, some of which may have been injected with the DiffRevisionTools hook $nextlink:String containing the link to the next revision(if any) $status
Definition: hooks.txt:1266
IP\toHex
static toHex( $ip)
Return a zero-padded upper case hexadecimal representation of an IP address.
Definition: IP.php:417
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:1146
Wikimedia\Rdbms\Database
Relational database abstraction object.
Definition: Database.php:48
Block\isCreateAccountBlocked
isCreateAccountBlocked( $x=null)
Get or set the flag indicating whether this block blocks the target from creating an account.
Definition: Block.php:1191
$user
return true to allow those checks to and false if checking is done & $user
Definition: hooks.txt:1476
User\newFromId
static newFromId( $id)
Static factory method for creation from a given user ID.
Definition: User.php:609
Block\getSystemBlockType
getSystemBlockType()
Get the system block type, if any.
Definition: Block.php:1127
Block\equals
equals(Block $block)
Check if two blocks are effectively equal.
Definition: Block.php:292
SCHEMA_COMPAT_READ_NEW
const SCHEMA_COMPAT_READ_NEW
Definition: Defines.php:287
Block\getHideName
getHideName()
Get whether the block hides the target's username.
Definition: Block.php:1108
Block\getType
getType()
Get the type of target for this particular block.
Definition: Block.php:1682
false
processing should stop and the error should be shown to the user * false
Definition: hooks.txt:187
Block\getReason
getReason()
Get the reason given for creating the block.
Definition: Block.php:1088
User\getId
getId()
Get the user's ID.
Definition: User.php:2425
Block\getCookieValue
getCookieValue()
Get the BlockID cookie's value for this block.
Definition: Block.php:1828
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
$context
do that in ParserLimitReportFormat instead use this to modify the parameters of the image all existing parser cache entries will be invalid To avoid you ll need to handle that somehow(e.g. with the RejectParserCacheValue hook) because MediaWiki won 't do it for you. & $defaults also a ContextSource after deleting those rows but within the same transaction you ll probably need to make sure the header is varied on and they can depend only on the ResourceLoaderContext $context
Definition: hooks.txt:2636
Block\clearCookie
static clearCookie(WebResponse $response)
Unset the 'BlockID' cookie.
Definition: Block.php:1815
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:456
Block\setReason
setReason( $reason)
Set the reason for creating the block.
Definition: Block.php:1098
Block\isExpired
isExpired()
Has the block expired?
Definition: Block.php:956
$lang
if(!isset( $args[0])) $lang
Definition: testCompression.php:33
Block\newFromID
static newFromID( $id)
Load a block from the block id.
Definition: Block.php:192
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:1633
Block\$isHardblock
bool $isHardblock
Definition: Block.php:81
AutoCommitUpdate
Deferrable Update for closure/callback updates that should use auto-commit mode.
Definition: AutoCommitUpdate.php:9
Block\TYPE_IP
const TYPE_IP
Definition: Block.php:97
captcha-old.count
count
Definition: captcha-old.py:249
Block\TYPE_RANGE
const TYPE_RANGE
Definition: Block.php:98
Block\getBy
getBy()
Get the user id of the blocking sysop.
Definition: Block.php:1043
Block\chooseBlock
static chooseBlock(array $blocks, array $ipChain)
From a list of multiple blocks, find the most exact and strongest Block.
Definition: Block.php:1523
$result
The index of the header message $result[1]=The index of the body text message $result[2 through n]=Parameters passed to body text message. Please note the header message cannot receive/use parameters. 'ImportHandleLogItemXMLTag':When parsing a XML tag in a log item. Return false to stop further processing of the tag $reader:XMLReader object $logInfo:Array of information 'ImportHandlePageXMLTag':When parsing a XML tag in a page. Return false to stop further processing of the tag $reader:XMLReader object & $pageInfo:Array of information 'ImportHandleRevisionXMLTag':When parsing a XML tag in a page revision. Return false to stop further processing of the tag $reader:XMLReader object $pageInfo:Array of page information $revisionInfo:Array of revision information 'ImportHandleToplevelXMLTag':When parsing a top level XML tag. Return false to stop further processing of the tag $reader:XMLReader object 'ImportHandleUnknownUser':When a user doesn 't exist locally, this hook is called to give extensions an opportunity to auto-create it. If the auto-creation is successful, return false. $name:User name 'ImportHandleUploadXMLTag':When parsing a XML tag in a file upload. Return false to stop further processing of the tag $reader:XMLReader object $revisionInfo:Array of information 'ImportLogInterwikiLink':Hook to change the interwiki link used in log entries and edit summaries for transwiki imports. & $fullInterwikiPrefix:Interwiki prefix, may contain colons. & $pageTitle:String that contains page title. 'ImportSources':Called when reading from the $wgImportSources configuration variable. Can be used to lazy-load the import sources list. & $importSources:The value of $wgImportSources. Modify as necessary. See the comment in DefaultSettings.php for the detail of how to structure this array. 'InfoAction':When building information to display on the action=info page. $context:IContextSource object & $pageInfo:Array of information 'InitializeArticleMaybeRedirect':MediaWiki check to see if title is a redirect. & $title:Title object for the current page & $request:WebRequest & $ignoreRedirect:boolean to skip redirect check & $target:Title/string of redirect target & $article:Article object 'InternalParseBeforeLinks':during Parser 's internalParse method before links but after nowiki/noinclude/includeonly/onlyinclude and other processings. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InternalParseBeforeSanitize':during Parser 's internalParse method just before the parser removes unwanted/dangerous HTML tags and after nowiki/noinclude/includeonly/onlyinclude and other processings. Ideal for syntax-extensions after template/parser function execution which respect nowiki and HTML-comments. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InterwikiLoadPrefix':When resolving if a given prefix is an interwiki or not. Return true without providing an interwiki to continue interwiki search. $prefix:interwiki prefix we are looking for. & $iwData:output array describing the interwiki with keys iw_url, iw_local, iw_trans and optionally iw_api and iw_wikiid. 'InvalidateEmailComplete':Called after a user 's email has been invalidated successfully. $user:user(object) whose email is being invalidated 'IRCLineURL':When constructing the URL to use in an IRC notification. Callee may modify $url and $query, URL will be constructed as $url . $query & $url:URL to index.php & $query:Query string $rc:RecentChange object that triggered url generation 'IsFileCacheable':Override the result of Article::isFileCacheable()(if true) & $article:article(object) being checked 'IsTrustedProxy':Override the result of IP::isTrustedProxy() & $ip:IP being check & $result:Change this value to override the result of IP::isTrustedProxy() 'IsUploadAllowedFromUrl':Override the result of UploadFromUrl::isAllowedUrl() $url:URL used to upload from & $allowed:Boolean indicating if uploading is allowed for given URL 'isValidEmailAddr':Override the result of Sanitizer::validateEmail(), for instance to return false if the domain name doesn 't match your organization. $addr:The e-mail address entered by the user & $result:Set this and return false to override the internal checks 'isValidPassword':Override the result of User::isValidPassword() $password:The password entered by the user & $result:Set this and return false to override the internal checks $user:User the password is being validated for 'Language::getMessagesFileName':$code:The language code or the language we 're looking for a messages file for & $file:The messages file path, you can override this to change the location. 'LanguageGetNamespaces':Provide custom ordering for namespaces or remove namespaces. Do not use this hook to add namespaces. Use CanonicalNamespaces for that. & $namespaces:Array of namespaces indexed by their numbers 'LanguageGetTranslatedLanguageNames':Provide translated language names. & $names:array of language code=> language name $code:language of the preferred translations 'LanguageLinks':Manipulate a page 's language links. This is called in various places to allow extensions to define the effective language links for a page. $title:The page 's Title. & $links:Array with elements of the form "language:title" in the order that they will be output. & $linkFlags:Associative array mapping prefixed links to arrays of flags. Currently unused, but planned to provide support for marking individual language links in the UI, e.g. for featured articles. 'LanguageSelector':Hook to change the language selector available on a page. $out:The output page. $cssClassName:CSS class name of the language selector. 'LinkBegin':DEPRECATED since 1.28! Use HtmlPageLinkRendererBegin instead. Used when generating internal and interwiki links in Linker::link(), before processing starts. Return false to skip default processing and return $ret. See documentation for Linker::link() for details on the expected meanings of parameters. $skin:the Skin object $target:the Title that the link is pointing to & $html:the contents that the< a > tag should have(raw HTML) $result
Definition: hooks.txt:1983
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition: GlobalFunctions.php:1912
$wgAutoblockExpiry
$wgAutoblockExpiry
Number of seconds before autoblock entries expire.
Definition: DefaultSettings.php:4967
Wikimedia\Rdbms\IDatabase\encodeExpiry
encodeExpiry( $expiry)
Encode an expiry time into the DBMS dependent format.
Block\update
update()
Update a block in the DB with new parameters.
Definition: Block.php:622
Block\getId
getId()
Get the block ID.
Definition: Block.php:1060
Block\setCookie
setCookie(WebResponse $response)
Set the 'BlockID' cookie to this block's ID and expiry time.
Definition: Block.php:1791
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:79
WebResponse\setCookie
setCookie( $name, $value, $expire=0, $options=[])
Set the browser cookie.
Definition: WebResponse.php:133
$params
$params
Definition: styleTest.css.php:44
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:1403
wfReadOnly
wfReadOnly()
Check whether the wiki is in read-only mode.
Definition: GlobalFunctions.php:1197
User\newFromName
static newFromName( $name, $validate='valid')
Static factory method for creation from username.
Definition: User.php:585
Block\isValid
isValid()
Is the block address valid (i.e.
Definition: Block.php:973
Block\initFromRow
initFromRow( $row)
Given a database row from the ipblocks table, initialize member variables.
Definition: Block.php:470
User\getUserPage
getUserPage()
Get this user's personal page title.
Definition: User.php:4550
Block\getRangeEnd
getRangeEnd()
Get the IP address at the end of the range in Hex form.
Definition: Block.php:1024
User\newFromAnyId
static newFromAnyId( $userId, $userName, $actorId)
Static factory method for creation from an ID, name, and/or actor ID.
Definition: User.php:676
$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:131
Block\getTimestamp
getTimestamp()
Get the timestamp indicating when the block was created.
Definition: Block.php:1735
$success
$success
Definition: NoLocalSettings.php:42
User
User
Definition: All_system_messages.txt:425
Block\$mParentBlockId
int $mParentBlockId
Definition: Block.php:48
Block\getExpiry
getExpiry()
Get the block expiry time.
Definition: Block.php:1715
Block\deleteIfExpired
deleteIfExpired()
Check if a block has expired.
Definition: Block.php:939
Block\getDatabaseArray
getDatabaseArray(IDatabase $dbw)
Get an array suitable for passing to $dbw->insert() or $dbw->update()
Definition: Block.php:685
Block\insert
insert( $dbw=null)
Insert a block into the block table.
Definition: Block.php:545
ActorMigration\newMigration
static newMigration()
Static constructor.
Definition: ActorMigration.php:111
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:43
$wgPutIPinRC
$wgPutIPinRC
Log IP addresses in the recentchanges table; can be accessed only by extensions (e....
Definition: DefaultSettings.php:5745
Wikimedia\Rdbms\IDatabase
Basic database interface for live and lazy-loaded relation database handles.
Definition: IDatabase.php:38
Block\getRedactedName
getRedactedName()
Get the block name, but with autoblocked IPs hidden as per standard privacy policy.
Definition: Block.php:1332
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:324
$dbr
$dbr
Definition: testCompression.php:50
Block\getBlockRestrictionStore
getBlockRestrictionStore()
Get a BlockRestrictionStore instance.
Definition: Block.php:2177
Block\$type
int $type
Block::TYPE_ constant.
Definition: Block.php:75
Block\setRestrictions
setRestrictions(array $restrictions)
Set Restrictions.
Definition: Block.php:1963
IP\isValidRange
static isValidRange( $ipRange)
Validate an IP range (valid address with a valid CIDR prefix).
Definition: IP.php:138
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:46
MWException
MediaWiki exception.
Definition: MWException.php:26
$title
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:925
wfDeprecated
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
Definition: GlobalFunctions.php:1078
Block\parseTarget
static parseTarget( $target)
From an existing Block, get the target and the type of target.
Definition: Block.php:1625
Block\$mBlockEmail
bool $mBlockEmail
Definition: Block.php:57
Block\isEmailBlocked
isEmailBlocked( $x=null)
Get or set the flag indicating whether this block blocks the target from sending emails.
Definition: Block.php:1204
Block\getRangeCond
static getRangeCond( $start, $end=null)
Get a set of SQL conditions which will select rangeblocks encompassing a given range.
Definition: Block.php:423
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:2636
Block\doAutoblock
doAutoblock( $autoblockIP)
Autoblocks the given IP, referring to this Block.
Definition: Block.php:858
Block\TYPE_ID
const TYPE_ID
Definition: Block.php:100
MediaWiki\Block\Restriction\Restriction
Definition: Restriction.php:25
Block\isWhitelistedFromAutoblocks
static isWhitelistedFromAutoblocks( $ip)
Checks whether a given IP is on the autoblock whitelist.
Definition: Block.php:812
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
$lines
$lines
Definition: router.php:61
Block\$allowUsertalk
bool $allowUsertalk
Definition: Block.php:60
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:650
wfTimestampNow
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
Definition: GlobalFunctions.php:1941
Block\appliesToTitle
appliesToTitle(Title $title)
Checks if a block applies to a particular title.
Definition: Block.php:2043
Block\isAutoblocking
isAutoblocking( $x=null)
Definition: Block.php:1159
Block\$isAutoblocking
bool $isAutoblocking
Definition: Block.php:84
DB_MASTER
const DB_MASTER
Definition: defines.php:26
array
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))
Block\$restrictions
Restriction[] $restrictions
Definition: Block.php:93
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:949
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:175
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\setTimestamp
setTimestamp( $timestamp)
Set the timestamp indicating when the block was created.
Definition: Block.php:1745
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:1442
null
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that When $user is not null
Definition: hooks.txt:780
$fname
if(defined( 'MW_SETUP_CALLBACK')) $fname
Customization point after all loading (constants, functions, classes, DefaultSettings,...
Definition: Setup.php:123
Block\getTargetAndType
getTargetAndType()
Get the target and target type for this particular Block.
Definition: Block.php:1695
$line
$line
Definition: cdb.php:59
NS_USER_TALK
const NS_USER_TALK
Definition: Defines.php:67
Block\doRetroactiveAutoblock
doRetroactiveAutoblock()
Retroactively autoblocks the last IP used by the user (if it is a user) blocked by this Block.
Definition: Block.php:736
$expiryTime
$expiryTime
Definition: opensearch_desc.php:41
Block\getIdFromCookieValue
static getIdFromCookieValue( $cookieValue)
Get the stored ID from the 'BlockID' cookie.
Definition: Block.php:1851
$value
$value
Definition: styleTest.css.php:49
Block\updateTimestamp
updateTimestamp()
Update the timestamp on autoblocks.
Definition: Block.php:981
Block\$systemBlockType
string null $systemBlockType
Definition: Block.php:87
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:513
Block\$mId
int $mId
Definition: Block.php:51
Block\getRestrictions
getRestrictions()
Get Restrictions.
Definition: Block.php:1943
Block\getBlocker
getBlocker()
Get the user who implemented this block.
Definition: Block.php:1761
Block\setBlocker
setBlocker( $user)
Set the user who implemented (or will implement) this block.
Definition: Block.php:1769
Block\$blocker
User $blocker
Definition: Block.php:78
$wgBlockDisablesLogin
$wgBlockDisablesLogin
If true, blocked users will not be allowed to login.
Definition: DefaultSettings.php:5009
Block\isSitewide
isSitewide( $x=null)
Indicates that the block is a sitewide block.
Definition: Block.php:1178
Block\fromMaster
fromMaster( $x=null)
Get/set a flag determining whether the master is used for reads.
Definition: Block.php:1137
Block\getQueryInfo
static getQueryInfo()
Return the tables, fields, and join conditions to be selected to create a new block object.
Definition: Block.php:260
Block\getTarget
getTarget()
Get the target for this particular Block.
Definition: Block.php:1705
Block\purgeExpired
static purgeExpired()
Purge expired blocks from the ipblocks table.
Definition: Block.php:1359
Block\appliesToUsertalk
appliesToUsertalk(Title $usertalk=null)
Determine whether the block allows the user to edit their own user talk page.
Definition: Block.php:1997
Block\TYPE_AUTO
const TYPE_AUTO
Definition: Block.php:99
RequestContext\getMain
static getMain()
Get the RequestContext object associated with the main request.
Definition: RequestContext.php:430
IP\isValid
static isValid( $ip)
Validate an IP address.
Definition: IP.php:111
Block\$isSitewide
bool $isSitewide
Definition: Block.php:90
plain
either a plain
Definition: hooks.txt:2046
$response
this hook is for auditing only $response
Definition: hooks.txt:780
IContextSource
Interface for objects which can provide a MediaWiki context on request.
Definition: IContextSource.php:53
MediaWiki\Block\Restriction\NamespaceRestriction
Definition: NamespaceRestriction.php:25
Block\TYPE_USER
const TYPE_USER
Definition: Block.php:96
text
This list may contain false positives That usually means there is additional text with links below the first Each row contains links to the first and second as well as the first line of the second redirect text
Definition: All_system_messages.txt:1267
Block\appliesToNamespace
appliesToNamespace( $ns)
Checks if a block applies to a particular namespace.
Definition: Block.php:2066
Block\appliesToRight
appliesToRight( $right)
Determine whether the Block prevents a given right.
Definition: Block.php:1231
IP\sanitizeIP
static sanitizeIP( $ip)
Convert an IP into a verbose, uppercase, normalized form.
Definition: IP.php:152
Title
Represents a title within MediaWiki.
Definition: Title.php:40
$wgBlockCIDRLimit
$wgBlockCIDRLimit
Limits on the possible sizes of range blocks.
Definition: DefaultSettings.php:4997
$cache
$cache
Definition: mcc.php:33
$rows
do that in ParserLimitReportFormat instead use this to modify the parameters of the image all existing parser cache entries will be invalid To avoid you ll need to handle that somehow(e.g. with the RejectParserCacheValue hook) because MediaWiki won 't do it for you. & $defaults also a ContextSource after deleting those rows but within the same transaction $rows
Definition: hooks.txt:2636
Block\$mAuto
bool $mAuto
Definition: Block.php:39
$options
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped & $options
Definition: hooks.txt:1985
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:216
MediaWiki\Block\Restriction\PageRestriction
Definition: PageRestriction.php:25
Block\$blockCreateAccount
bool $blockCreateAccount
Definition: Block.php:63
Block\$mHideName
bool $mHideName
Definition: Block.php:45
Block\$forcedTargetID
int $forcedTargetID
Hack for foreign blocking (CentralAuth)
Definition: Block.php:69
Block\$target
User string $target
Definition: Block.php:66
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:42
Block
Definition: Block.php:31
Block\shouldTrackWithCookie
shouldTrackWithCookie( $isIpUser)
Check if the block should be tracked with a cookie.
Definition: Block.php:2138
Block\setHideName
setHideName( $hideName)
Set whether ths block hides the target's username.
Definition: Block.php:1118
Wikimedia\Rdbms\IDatabase\selectFieldValues
selectFieldValues( $table, $var, $cond='', $fname=__METHOD__, $options=[], $join_conds=[])
A SELECT wrapper which returns a list of single field values from result rows.
Block\isUsertalkEditAllowed
isUsertalkEditAllowed( $x=null)
Get or set the flag indicating whether this block blocks the target from editing their own user talk ...
Definition: Block.php:1217
Block\getRangeStart
getRangeStart()
Get the IP address at the start of the range in Hex form.
Definition: Block.php:1005
$link
usually copyright or history_copyright This message must be in HTML not wikitext & $link
Definition: hooks.txt:3053
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:1985
Block\$mReason
string $mReason
Definition: Block.php:33
Block\getPermissionsError
getPermissionsError(IContextSource $context)
Get the key and parameters for the corresponding error message.
Definition: Block.php:1878
Block\getBlockErrorParams
getBlockErrorParams(IContextSource $context)
Get block information used in different block error messages.
Definition: Block.php:1902
Block\getByName
getByName()
Get the username of the blocking sysop.
Definition: Block.php:1052
Block\appliesToPage
appliesToPage( $pageId)
Checks if a block applies to a particular page.
Definition: Block.php:2094
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
User\isUsableName
static isUsableName( $name)
Usernames which fail to pass this function will be blocked from user login and new account registrati...
Definition: User.php:1042
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 use $formDescriptor instead 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
WebResponse
Allow programs to request this object from WebRequest::response() and handle all outputting (or lack ...
Definition: WebResponse.php:28
Block\setExpiry
setExpiry( $expiry)
Set the block expiry time.
Definition: Block.php:1725
CommentStore\getStore
static getStore()
Definition: CommentStore.php:130
Block\newFromRow
static newFromRow( $row)
Create a new Block object from a database row.
Definition: Block.php:505
User
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition: User.php:48
Hooks\run
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:200
Block\getAutoblockUpdateArray
getAutoblockUpdateArray(IDatabase $dbw)
Definition: Block.php:720
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
Block\findRestriction
findRestriction( $type, $value)
Find Restriction by type and value.
Definition: Block.php:2116
User\getName
getName()
Get the user name, or the IP of an anonymous user.
Definition: User.php:2452
Block\setId
setId( $blockId)
Set the block ID.
Definition: Block.php:1070
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:759
IP\sanitizeRange
static sanitizeRange( $range)
Gets rid of unneeded numbers in quad-dotted/octet IP strings For example, 127.111....
Definition: IP.php:725
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:1753
IContextSource\getLanguage
getLanguage()
Block\$mFromMaster
bool $mFromMaster
Definition: Block.php:54
MediaWiki\Block\BlockRestrictionStore
Definition: BlockRestrictionStore.php:33
Block\$mTimestamp
string $mTimestamp
Definition: Block.php:36
Block\getAutoblockExpiry
static getAutoblockExpiry( $timestamp)
Get a timestamp of the expiry for autoblocks.
Definition: Block.php:1350
$wgActorTableSchemaMigrationStage
int $wgActorTableSchemaMigrationStage
Actor table schema migration stage.
Definition: DefaultSettings.php:8979