[ Index ]

PHP Cross Reference of MediaWiki-1.24.0

title

Body

[close]

/includes/ -> Block.php (source)

   1  <?php
   2  /**
   3   * Blocks and bans object
   4   *
   5   * This program is free software; you can redistribute it and/or modify
   6   * it under the terms of the GNU General Public License as published by
   7   * the Free Software Foundation; either version 2 of the License, or
   8   * (at your option) any later version.
   9   *
  10   * This program is distributed in the hope that it will be useful,
  11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13   * GNU General Public License for more details.
  14   *
  15   * You should have received a copy of the GNU General Public License along
  16   * with this program; if not, write to the Free Software Foundation, Inc.,
  17   * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18   * http://www.gnu.org/copyleft/gpl.html
  19   *
  20   * @file
  21   */
  22  class Block {
  23      /** @var string */
  24      public $mReason;
  25  
  26      /** @var bool|string */
  27      public $mTimestamp;
  28  
  29      /** @var int */
  30      public $mAuto;
  31  
  32      /** @var bool|string */
  33      public $mExpiry;
  34  
  35      public $mHideName;
  36  
  37      /** @var int */
  38      public $mParentBlockId;
  39  
  40      /** @var int */
  41      protected $mId;
  42  
  43      /** @var bool */
  44      protected $mFromMaster;
  45  
  46      /** @var bool */
  47      protected $mBlockEmail;
  48  
  49      /** @var bool */
  50      protected $mDisableUsertalk;
  51  
  52      /** @var bool */
  53      protected $mCreateAccount;
  54  
  55      /** @var User|string */
  56      protected $target;
  57  
  58      /** @var int Hack for foreign blocking (CentralAuth) */
  59      protected $forcedTargetID;
  60  
  61      /** @var int Block::TYPE_ constant. Can only be USER, IP or RANGE internally */
  62      protected $type;
  63  
  64      /** @var User */
  65      protected $blocker;
  66  
  67      /** @var bool */
  68      protected $isHardblock = true;
  69  
  70      /** @var bool */
  71      protected $isAutoblocking = true;
  72  
  73      # TYPE constants
  74      const TYPE_USER = 1;
  75      const TYPE_IP = 2;
  76      const TYPE_RANGE = 3;
  77      const TYPE_AUTO = 4;
  78      const TYPE_ID = 5;
  79  
  80      /**
  81       * @todo FIXME: Don't know what the best format to have for this constructor
  82       *   is, but fourteen optional parameters certainly isn't it.
  83       * @param string $address
  84       * @param int $user
  85       * @param int $by
  86       * @param string $reason
  87       * @param mixed $timestamp
  88       * @param int $auto
  89       * @param string $expiry
  90       * @param int $anonOnly
  91       * @param int $createAccount
  92       * @param int $enableAutoblock
  93       * @param int $hideName
  94       * @param int $blockEmail
  95       * @param int $allowUsertalk
  96       * @param string $byText
  97       */
  98  	function __construct( $address = '', $user = 0, $by = 0, $reason = '',
  99          $timestamp = 0, $auto = 0, $expiry = '', $anonOnly = 0, $createAccount = 0, $enableAutoblock = 0,
 100          $hideName = 0, $blockEmail = 0, $allowUsertalk = 0, $byText = ''
 101      ) {
 102          if ( $timestamp === 0 ) {
 103              $timestamp = wfTimestampNow();
 104          }
 105  
 106          if ( count( func_get_args() ) > 0 ) {
 107              # Soon... :D
 108              # wfDeprecated( __METHOD__ . " with arguments" );
 109          }
 110  
 111          $this->setTarget( $address );
 112          if ( $this->target instanceof User && $user ) {
 113              $this->forcedTargetID = $user; // needed for foreign users
 114          }
 115          if ( $by ) { // local user
 116              $this->setBlocker( User::newFromID( $by ) );
 117          } else { // foreign user
 118              $this->setBlocker( $byText );
 119          }
 120          $this->mReason = $reason;
 121          $this->mTimestamp = wfTimestamp( TS_MW, $timestamp );
 122          $this->mAuto = $auto;
 123          $this->isHardblock( !$anonOnly );
 124          $this->prevents( 'createaccount', $createAccount );
 125          if ( $expiry == 'infinity' || $expiry == wfGetDB( DB_SLAVE )->getInfinity() ) {
 126              $this->mExpiry = 'infinity';
 127          } else {
 128              $this->mExpiry = wfTimestamp( TS_MW, $expiry );
 129          }
 130          $this->isAutoblocking( $enableAutoblock );
 131          $this->mHideName = $hideName;
 132          $this->prevents( 'sendemail', $blockEmail );
 133          $this->prevents( 'editownusertalk', !$allowUsertalk );
 134  
 135          $this->mFromMaster = false;
 136      }
 137  
 138      /**
 139       * Load a blocked user from their block id.
 140       *
 141       * @param int $id Block id to search for
 142       * @return Block|null
 143       */
 144  	public static function newFromID( $id ) {
 145          $dbr = wfGetDB( DB_SLAVE );
 146          $res = $dbr->selectRow(
 147              'ipblocks',
 148              self::selectFields(),
 149              array( 'ipb_id' => $id ),
 150              __METHOD__
 151          );
 152          if ( $res ) {
 153              return self::newFromRow( $res );
 154          } else {
 155              return null;
 156          }
 157      }
 158  
 159      /**
 160       * Return the list of ipblocks fields that should be selected to create
 161       * a new block.
 162       * @return array
 163       */
 164  	public static function selectFields() {
 165          return array(
 166              'ipb_id',
 167              'ipb_address',
 168              'ipb_by',
 169              'ipb_by_text',
 170              'ipb_reason',
 171              'ipb_timestamp',
 172              'ipb_auto',
 173              'ipb_anon_only',
 174              'ipb_create_account',
 175              'ipb_enable_autoblock',
 176              'ipb_expiry',
 177              'ipb_deleted',
 178              'ipb_block_email',
 179              'ipb_allow_usertalk',
 180              'ipb_parent_block_id',
 181          );
 182      }
 183  
 184      /**
 185       * Check if two blocks are effectively equal.  Doesn't check irrelevant things like
 186       * the blocking user or the block timestamp, only things which affect the blocked user
 187       *
 188       * @param Block $block
 189       *
 190       * @return bool
 191       */
 192  	public function equals( Block $block ) {
 193          return (
 194              (string)$this->target == (string)$block->target
 195              && $this->type == $block->type
 196              && $this->mAuto == $block->mAuto
 197              && $this->isHardblock() == $block->isHardblock()
 198              && $this->prevents( 'createaccount' ) == $block->prevents( 'createaccount' )
 199              && $this->mExpiry == $block->mExpiry
 200              && $this->isAutoblocking() == $block->isAutoblocking()
 201              && $this->mHideName == $block->mHideName
 202              && $this->prevents( 'sendemail' ) == $block->prevents( 'sendemail' )
 203              && $this->prevents( 'editownusertalk' ) == $block->prevents( 'editownusertalk' )
 204              && $this->mReason == $block->mReason
 205          );
 206      }
 207  
 208      /**
 209       * Load a block from the database which affects the already-set $this->target:
 210       *     1) A block directly on the given user or IP
 211       *     2) A rangeblock encompassing the given IP (smallest first)
 212       *     3) An autoblock on the given IP
 213       * @param User|string $vagueTarget Also search for blocks affecting this target.  Doesn't
 214       *     make any sense to use TYPE_AUTO / TYPE_ID here. Leave blank to skip IP lookups.
 215       * @throws MWException
 216       * @return bool Whether a relevant block was found
 217       */
 218  	protected function newLoad( $vagueTarget = null ) {
 219          $db = wfGetDB( $this->mFromMaster ? DB_MASTER : DB_SLAVE );
 220  
 221          if ( $this->type !== null ) {
 222              $conds = array(
 223                  'ipb_address' => array( (string)$this->target ),
 224              );
 225          } else {
 226              $conds = array( 'ipb_address' => array() );
 227          }
 228  
 229          # Be aware that the != '' check is explicit, since empty values will be
 230          # passed by some callers (bug 29116)
 231          if ( $vagueTarget != '' ) {
 232              list( $target, $type ) = self::parseTarget( $vagueTarget );
 233              switch ( $type ) {
 234                  case self::TYPE_USER:
 235                      # Slightly weird, but who are we to argue?
 236                      $conds['ipb_address'][] = (string)$target;
 237                      break;
 238  
 239                  case self::TYPE_IP:
 240                      $conds['ipb_address'][] = (string)$target;
 241                      $conds[] = self::getRangeCond( IP::toHex( $target ) );
 242                      $conds = $db->makeList( $conds, LIST_OR );
 243                      break;
 244  
 245                  case self::TYPE_RANGE:
 246                      list( $start, $end ) = IP::parseRange( $target );
 247                      $conds['ipb_address'][] = (string)$target;
 248                      $conds[] = self::getRangeCond( $start, $end );
 249                      $conds = $db->makeList( $conds, LIST_OR );
 250                      break;
 251  
 252                  default:
 253                      throw new MWException( "Tried to load block with invalid type" );
 254              }
 255          }
 256  
 257          $res = $db->select( 'ipblocks', self::selectFields(), $conds, __METHOD__ );
 258  
 259          # This result could contain a block on the user, a block on the IP, and a russian-doll
 260          # set of rangeblocks.  We want to choose the most specific one, so keep a leader board.
 261          $bestRow = null;
 262  
 263          # Lower will be better
 264          $bestBlockScore = 100;
 265  
 266          # This is begging for $this = $bestBlock, but that's not allowed in PHP :(
 267          $bestBlockPreventsEdit = null;
 268  
 269          foreach ( $res as $row ) {
 270              $block = self::newFromRow( $row );
 271  
 272              # Don't use expired blocks
 273              if ( $block->deleteIfExpired() ) {
 274                  continue;
 275              }
 276  
 277              # Don't use anon only blocks on users
 278              if ( $this->type == self::TYPE_USER && !$block->isHardblock() ) {
 279                  continue;
 280              }
 281  
 282              if ( $block->getType() == self::TYPE_RANGE ) {
 283                  # This is the number of bits that are allowed to vary in the block, give
 284                  # or take some floating point errors
 285                  $end = wfBaseconvert( $block->getRangeEnd(), 16, 10 );
 286                  $start = wfBaseconvert( $block->getRangeStart(), 16, 10 );
 287                  $size = log( $end - $start + 1, 2 );
 288  
 289                  # This has the nice property that a /32 block is ranked equally with a
 290                  # single-IP block, which is exactly what it is...
 291                  $score = self::TYPE_RANGE - 1 + ( $size / 128 );
 292  
 293              } else {
 294                  $score = $block->getType();
 295              }
 296  
 297              if ( $score < $bestBlockScore ) {
 298                  $bestBlockScore = $score;
 299                  $bestRow = $row;
 300                  $bestBlockPreventsEdit = $block->prevents( 'edit' );
 301              }
 302          }
 303  
 304          if ( $bestRow !== null ) {
 305              $this->initFromRow( $bestRow );
 306              $this->prevents( 'edit', $bestBlockPreventsEdit );
 307              return true;
 308          } else {
 309              return false;
 310          }
 311      }
 312  
 313      /**
 314       * Get a set of SQL conditions which will select rangeblocks encompassing a given range
 315       * @param string $start Hexadecimal IP representation
 316       * @param string $end Hexadecimal IP representation, or null to use $start = $end
 317       * @return string
 318       */
 319  	public static function getRangeCond( $start, $end = null ) {
 320          if ( $end === null ) {
 321              $end = $start;
 322          }
 323          # Per bug 14634, we want to include relevant active rangeblocks; for
 324          # rangeblocks, we want to include larger ranges which enclose the given
 325          # range. We know that all blocks must be smaller than $wgBlockCIDRLimit,
 326          # so we can improve performance by filtering on a LIKE clause
 327          $chunk = self::getIpFragment( $start );
 328          $dbr = wfGetDB( DB_SLAVE );
 329          $like = $dbr->buildLike( $chunk, $dbr->anyString() );
 330  
 331          # Fairly hard to make a malicious SQL statement out of hex characters,
 332          # but stranger things have happened...
 333          $safeStart = $dbr->addQuotes( $start );
 334          $safeEnd = $dbr->addQuotes( $end );
 335  
 336          return $dbr->makeList(
 337              array(
 338                  "ipb_range_start $like",
 339                  "ipb_range_start <= $safeStart",
 340                  "ipb_range_end >= $safeEnd",
 341              ),
 342              LIST_AND
 343          );
 344      }
 345  
 346      /**
 347       * Get the component of an IP address which is certain to be the same between an IP
 348       * address and a rangeblock containing that IP address.
 349       * @param string $hex Hexadecimal IP representation
 350       * @return string
 351       */
 352  	protected static function getIpFragment( $hex ) {
 353          global $wgBlockCIDRLimit;
 354          if ( substr( $hex, 0, 3 ) == 'v6-' ) {
 355              return 'v6-' . substr( substr( $hex, 3 ), 0, floor( $wgBlockCIDRLimit['IPv6'] / 4 ) );
 356          } else {
 357              return substr( $hex, 0, floor( $wgBlockCIDRLimit['IPv4'] / 4 ) );
 358          }
 359      }
 360  
 361      /**
 362       * Given a database row from the ipblocks table, initialize
 363       * member variables
 364       * @param stdClass $row A row from the ipblocks table
 365       */
 366  	protected function initFromRow( $row ) {
 367          $this->setTarget( $row->ipb_address );
 368          if ( $row->ipb_by ) { // local user
 369              $this->setBlocker( User::newFromID( $row->ipb_by ) );
 370          } else { // foreign user
 371              $this->setBlocker( $row->ipb_by_text );
 372          }
 373  
 374          $this->mReason = $row->ipb_reason;
 375          $this->mTimestamp = wfTimestamp( TS_MW, $row->ipb_timestamp );
 376          $this->mAuto = $row->ipb_auto;
 377          $this->mHideName = $row->ipb_deleted;
 378          $this->mId = $row->ipb_id;
 379          $this->mParentBlockId = $row->ipb_parent_block_id;
 380  
 381          // I wish I didn't have to do this
 382          $db = wfGetDB( DB_SLAVE );
 383          if ( $row->ipb_expiry == $db->getInfinity() ) {
 384              $this->mExpiry = 'infinity';
 385          } else {
 386              $this->mExpiry = wfTimestamp( TS_MW, $row->ipb_expiry );
 387          }
 388  
 389          $this->isHardblock( !$row->ipb_anon_only );
 390          $this->isAutoblocking( $row->ipb_enable_autoblock );
 391  
 392          $this->prevents( 'createaccount', $row->ipb_create_account );
 393          $this->prevents( 'sendemail', $row->ipb_block_email );
 394          $this->prevents( 'editownusertalk', !$row->ipb_allow_usertalk );
 395      }
 396  
 397      /**
 398       * Create a new Block object from a database row
 399       * @param stdClass $row Row from the ipblocks table
 400       * @return Block
 401       */
 402  	public static function newFromRow( $row ) {
 403          $block = new Block;
 404          $block->initFromRow( $row );
 405          return $block;
 406      }
 407  
 408      /**
 409       * Delete the row from the IP blocks table.
 410       *
 411       * @throws MWException
 412       * @return bool
 413       */
 414  	public function delete() {
 415          if ( wfReadOnly() ) {
 416              return false;
 417          }
 418  
 419          if ( !$this->getId() ) {
 420              throw new MWException( "Block::delete() requires that the mId member be filled\n" );
 421          }
 422  
 423          $dbw = wfGetDB( DB_MASTER );
 424          $dbw->delete( 'ipblocks', array( 'ipb_parent_block_id' => $this->getId() ), __METHOD__ );
 425          $dbw->delete( 'ipblocks', array( 'ipb_id' => $this->getId() ), __METHOD__ );
 426  
 427          return $dbw->affectedRows() > 0;
 428      }
 429  
 430      /**
 431       * Insert a block into the block table. Will fail if there is a conflicting
 432       * block (same name and options) already in the database.
 433       *
 434       * @param DatabaseBase $dbw If you have one available
 435       * @return bool|array False on failure, assoc array on success:
 436       *    ('id' => block ID, 'autoIds' => array of autoblock IDs)
 437       */
 438  	public function insert( $dbw = null ) {
 439          wfDebug( "Block::insert; timestamp {$this->mTimestamp}\n" );
 440  
 441          if ( $dbw === null ) {
 442              $dbw = wfGetDB( DB_MASTER );
 443          }
 444  
 445          # Don't collide with expired blocks
 446          Block::purgeExpired();
 447  
 448          $row = $this->getDatabaseArray();
 449          $row['ipb_id'] = $dbw->nextSequenceValue( "ipblocks_ipb_id_seq" );
 450  
 451          $dbw->insert(
 452              'ipblocks',
 453              $row,
 454              __METHOD__,
 455              array( 'IGNORE' )
 456          );
 457          $affected = $dbw->affectedRows();
 458          $this->mId = $dbw->insertId();
 459  
 460          if ( $affected ) {
 461              $auto_ipd_ids = $this->doRetroactiveAutoblock();
 462              return array( 'id' => $this->mId, 'autoIds' => $auto_ipd_ids );
 463          }
 464  
 465          return false;
 466      }
 467  
 468      /**
 469       * Update a block in the DB with new parameters.
 470       * The ID field needs to be loaded first.
 471       *
 472       * @return bool|array False on failure, array on success:
 473       *   ('id' => block ID, 'autoIds' => array of autoblock IDs)
 474       */
 475  	public function update() {
 476          wfDebug( "Block::update; timestamp {$this->mTimestamp}\n" );
 477          $dbw = wfGetDB( DB_MASTER );
 478  
 479          $dbw->startAtomic( __METHOD__ );
 480  
 481          $dbw->update(
 482              'ipblocks',
 483              $this->getDatabaseArray( $dbw ),
 484              array( 'ipb_id' => $this->getId() ),
 485              __METHOD__
 486          );
 487  
 488          $affected = $dbw->affectedRows();
 489  
 490          if ( $this->isAutoblocking() ) {
 491              // update corresponding autoblock(s) (bug 48813)
 492              $dbw->update(
 493                  'ipblocks',
 494                  $this->getAutoblockUpdateArray(),
 495                  array( 'ipb_parent_block_id' => $this->getId() ),
 496                  __METHOD__
 497              );
 498          } else {
 499              // autoblock no longer required, delete corresponding autoblock(s)
 500              $dbw->delete(
 501                  'ipblocks',
 502                  array( 'ipb_parent_block_id' => $this->getId() ),
 503                  __METHOD__
 504              );
 505          }
 506  
 507          $dbw->endAtomic( __METHOD__ );
 508  
 509          if ( $affected ) {
 510              $auto_ipd_ids = $this->doRetroactiveAutoblock();
 511              return array( 'id' => $this->mId, 'autoIds' => $auto_ipd_ids );
 512          }
 513  
 514          return false;
 515      }
 516  
 517      /**
 518       * Get an array suitable for passing to $dbw->insert() or $dbw->update()
 519       * @param DatabaseBase $db
 520       * @return array
 521       */
 522  	protected function getDatabaseArray( $db = null ) {
 523          if ( !$db ) {
 524              $db = wfGetDB( DB_SLAVE );
 525          }
 526          $expiry = $db->encodeExpiry( $this->mExpiry );
 527  
 528          if ( $this->forcedTargetID ) {
 529              $uid = $this->forcedTargetID;
 530          } else {
 531              $uid = $this->target instanceof User ? $this->target->getID() : 0;
 532          }
 533  
 534          $a = array(
 535              'ipb_address'          => (string)$this->target,
 536              'ipb_user'             => $uid,
 537              'ipb_by'               => $this->getBy(),
 538              'ipb_by_text'          => $this->getByName(),
 539              'ipb_reason'           => $this->mReason,
 540              'ipb_timestamp'        => $db->timestamp( $this->mTimestamp ),
 541              'ipb_auto'             => $this->mAuto,
 542              'ipb_anon_only'        => !$this->isHardblock(),
 543              'ipb_create_account'   => $this->prevents( 'createaccount' ),
 544              'ipb_enable_autoblock' => $this->isAutoblocking(),
 545              'ipb_expiry'           => $expiry,
 546              'ipb_range_start'      => $this->getRangeStart(),
 547              'ipb_range_end'        => $this->getRangeEnd(),
 548              'ipb_deleted'          => intval( $this->mHideName ), // typecast required for SQLite
 549              'ipb_block_email'      => $this->prevents( 'sendemail' ),
 550              'ipb_allow_usertalk'   => !$this->prevents( 'editownusertalk' ),
 551              'ipb_parent_block_id'  => $this->mParentBlockId
 552          );
 553  
 554          return $a;
 555      }
 556  
 557      /**
 558       * @return array
 559       */
 560  	protected function getAutoblockUpdateArray() {
 561          return array(
 562              'ipb_by'               => $this->getBy(),
 563              'ipb_by_text'          => $this->getByName(),
 564              'ipb_reason'           => $this->mReason,
 565              'ipb_create_account'   => $this->prevents( 'createaccount' ),
 566              'ipb_deleted'          => (int)$this->mHideName, // typecast required for SQLite
 567              'ipb_allow_usertalk'   => !$this->prevents( 'editownusertalk' ),
 568          );
 569      }
 570  
 571      /**
 572       * Retroactively autoblocks the last IP used by the user (if it is a user)
 573       * blocked by this Block.
 574       *
 575       * @return array Block IDs of retroactive autoblocks made
 576       */
 577  	protected function doRetroactiveAutoblock() {
 578          $blockIds = array();
 579          # If autoblock is enabled, autoblock the LAST IP(s) used
 580          if ( $this->isAutoblocking() && $this->getType() == self::TYPE_USER ) {
 581              wfDebug( "Doing retroactive autoblocks for " . $this->getTarget() . "\n" );
 582  
 583              $continue = wfRunHooks(
 584                  'PerformRetroactiveAutoblock', array( $this, &$blockIds ) );
 585  
 586              if ( $continue ) {
 587                  self::defaultRetroactiveAutoblock( $this, $blockIds );
 588              }
 589          }
 590          return $blockIds;
 591      }
 592  
 593      /**
 594       * Retroactively autoblocks the last IP used by the user (if it is a user)
 595       * blocked by this Block. This will use the recentchanges table.
 596       *
 597       * @param Block $block
 598       * @param array &$blockIds
 599       */
 600  	protected static function defaultRetroactiveAutoblock( Block $block, array &$blockIds ) {
 601          global $wgPutIPinRC;
 602  
 603          // No IPs are in recentchanges table, so nothing to select
 604          if ( !$wgPutIPinRC ) {
 605              return;
 606          }
 607  
 608          $dbr = wfGetDB( DB_SLAVE );
 609  
 610          $options = array( 'ORDER BY' => 'rc_timestamp DESC' );
 611          $conds = array( 'rc_user_text' => (string)$block->getTarget() );
 612  
 613          // Just the last IP used.
 614          $options['LIMIT'] = 1;
 615  
 616          $res = $dbr->select( 'recentchanges', array( 'rc_ip' ), $conds,
 617              __METHOD__, $options );
 618  
 619          if ( !$res->numRows() ) {
 620              # No results, don't autoblock anything
 621              wfDebug( "No IP found to retroactively autoblock\n" );
 622          } else {
 623              foreach ( $res as $row ) {
 624                  if ( $row->rc_ip ) {
 625                      $id = $block->doAutoblock( $row->rc_ip );
 626                      if ( $id ) {
 627                          $blockIds[] = $id;
 628                      }
 629                  }
 630              }
 631          }
 632      }
 633  
 634      /**
 635       * Checks whether a given IP is on the autoblock whitelist.
 636       * TODO: this probably belongs somewhere else, but not sure where...
 637       *
 638       * @param string $ip The IP to check
 639       * @return bool
 640       */
 641  	public static function isWhitelistedFromAutoblocks( $ip ) {
 642          global $wgMemc;
 643  
 644          // Try to get the autoblock_whitelist from the cache, as it's faster
 645          // than getting the msg raw and explode()'ing it.
 646          $key = wfMemcKey( 'ipb', 'autoblock', 'whitelist' );
 647          $lines = $wgMemc->get( $key );
 648          if ( !$lines ) {
 649              $lines = explode( "\n", wfMessage( 'autoblock_whitelist' )->inContentLanguage()->plain() );
 650              $wgMemc->set( $key, $lines, 3600 * 24 );
 651          }
 652  
 653          wfDebug( "Checking the autoblock whitelist..\n" );
 654  
 655          foreach ( $lines as $line ) {
 656              # List items only
 657              if ( substr( $line, 0, 1 ) !== '*' ) {
 658                  continue;
 659              }
 660  
 661              $wlEntry = substr( $line, 1 );
 662              $wlEntry = trim( $wlEntry );
 663  
 664              wfDebug( "Checking $ip against $wlEntry..." );
 665  
 666              # Is the IP in this range?
 667              if ( IP::isInRange( $ip, $wlEntry ) ) {
 668                  wfDebug( " IP $ip matches $wlEntry, not autoblocking\n" );
 669                  return true;
 670              } else {
 671                  wfDebug( " No match\n" );
 672              }
 673          }
 674  
 675          return false;
 676      }
 677  
 678      /**
 679       * Autoblocks the given IP, referring to this Block.
 680       *
 681       * @param string $autoblockIP The IP to autoblock.
 682       * @return int|bool Block ID if an autoblock was inserted, false if not.
 683       */
 684  	public function doAutoblock( $autoblockIP ) {
 685          # If autoblocks are disabled, go away.
 686          if ( !$this->isAutoblocking() ) {
 687              return false;
 688          }
 689  
 690          # Check for presence on the autoblock whitelist.
 691          if ( self::isWhitelistedFromAutoblocks( $autoblockIP ) ) {
 692              return false;
 693          }
 694  
 695          # Allow hooks to cancel the autoblock.
 696          if ( !wfRunHooks( 'AbortAutoblock', array( $autoblockIP, &$this ) ) ) {
 697              wfDebug( "Autoblock aborted by hook.\n" );
 698              return false;
 699          }
 700  
 701          # It's okay to autoblock. Go ahead and insert/update the block...
 702  
 703          # Do not add a *new* block if the IP is already blocked.
 704          $ipblock = Block::newFromTarget( $autoblockIP );
 705          if ( $ipblock ) {
 706              # Check if the block is an autoblock and would exceed the user block
 707              # if renewed. If so, do nothing, otherwise prolong the block time...
 708              if ( $ipblock->mAuto && // @todo Why not compare $ipblock->mExpiry?
 709                  $this->mExpiry > Block::getAutoblockExpiry( $ipblock->mTimestamp )
 710              ) {
 711                  # Reset block timestamp to now and its expiry to
 712                  # $wgAutoblockExpiry in the future
 713                  $ipblock->updateTimestamp();
 714              }
 715              return false;
 716          }
 717  
 718          # Make a new block object with the desired properties.
 719          $autoblock = new Block;
 720          wfDebug( "Autoblocking {$this->getTarget()}@" . $autoblockIP . "\n" );
 721          $autoblock->setTarget( $autoblockIP );
 722          $autoblock->setBlocker( $this->getBlocker() );
 723          $autoblock->mReason = wfMessage( 'autoblocker', $this->getTarget(), $this->mReason )
 724              ->inContentLanguage()->plain();
 725          $timestamp = wfTimestampNow();
 726          $autoblock->mTimestamp = $timestamp;
 727          $autoblock->mAuto = 1;
 728          $autoblock->prevents( 'createaccount', $this->prevents( 'createaccount' ) );
 729          # Continue suppressing the name if needed
 730          $autoblock->mHideName = $this->mHideName;
 731          $autoblock->prevents( 'editownusertalk', $this->prevents( 'editownusertalk' ) );
 732          $autoblock->mParentBlockId = $this->mId;
 733  
 734          if ( $this->mExpiry == 'infinity' ) {
 735              # Original block was indefinite, start an autoblock now
 736              $autoblock->mExpiry = Block::getAutoblockExpiry( $timestamp );
 737          } else {
 738              # If the user is already blocked with an expiry date, we don't
 739              # want to pile on top of that.
 740              $autoblock->mExpiry = min( $this->mExpiry, Block::getAutoblockExpiry( $timestamp ) );
 741          }
 742  
 743          # Insert the block...
 744          $status = $autoblock->insert();
 745          return $status
 746              ? $status['id']
 747              : false;
 748      }
 749  
 750      /**
 751       * Check if a block has expired. Delete it if it is.
 752       * @return bool
 753       */
 754  	public function deleteIfExpired() {
 755          wfProfileIn( __METHOD__ );
 756  
 757          if ( $this->isExpired() ) {
 758              wfDebug( "Block::deleteIfExpired() -- deleting\n" );
 759              $this->delete();
 760              $retVal = true;
 761          } else {
 762              wfDebug( "Block::deleteIfExpired() -- not expired\n" );
 763              $retVal = false;
 764          }
 765  
 766          wfProfileOut( __METHOD__ );
 767          return $retVal;
 768      }
 769  
 770      /**
 771       * Has the block expired?
 772       * @return bool
 773       */
 774  	public function isExpired() {
 775          $timestamp = wfTimestampNow();
 776          wfDebug( "Block::isExpired() checking current " . $timestamp . " vs $this->mExpiry\n" );
 777  
 778          if ( !$this->mExpiry ) {
 779              return false;
 780          } else {
 781              return $timestamp > $this->mExpiry;
 782          }
 783      }
 784  
 785      /**
 786       * Is the block address valid (i.e. not a null string?)
 787       * @return bool
 788       */
 789  	public function isValid() {
 790          return $this->getTarget() != null;
 791      }
 792  
 793      /**
 794       * Update the timestamp on autoblocks.
 795       */
 796  	public function updateTimestamp() {
 797          if ( $this->mAuto ) {
 798              $this->mTimestamp = wfTimestamp();
 799              $this->mExpiry = Block::getAutoblockExpiry( $this->mTimestamp );
 800  
 801              $dbw = wfGetDB( DB_MASTER );
 802              $dbw->update( 'ipblocks',
 803                  array( /* SET */
 804                      'ipb_timestamp' => $dbw->timestamp( $this->mTimestamp ),
 805                      'ipb_expiry' => $dbw->timestamp( $this->mExpiry ),
 806                  ),
 807                  array( /* WHERE */
 808                      'ipb_address' => (string)$this->getTarget()
 809                  ),
 810                  __METHOD__
 811              );
 812          }
 813      }
 814  
 815      /**
 816       * Get the IP address at the start of the range in Hex form
 817       * @throws MWException
 818       * @return string IP in Hex form
 819       */
 820  	public function getRangeStart() {
 821          switch ( $this->type ) {
 822              case self::TYPE_USER:
 823                  return '';
 824              case self::TYPE_IP:
 825                  return IP::toHex( $this->target );
 826              case self::TYPE_RANGE:
 827                  list( $start, /*...*/ ) = IP::parseRange( $this->target );
 828                  return $start;
 829              default:
 830                  throw new MWException( "Block with invalid type" );
 831          }
 832      }
 833  
 834      /**
 835       * Get the IP address at the end of the range in Hex form
 836       * @throws MWException
 837       * @return string IP in Hex form
 838       */
 839  	public function getRangeEnd() {
 840          switch ( $this->type ) {
 841              case self::TYPE_USER:
 842                  return '';
 843              case self::TYPE_IP:
 844                  return IP::toHex( $this->target );
 845              case self::TYPE_RANGE:
 846                  list( /*...*/, $end ) = IP::parseRange( $this->target );
 847                  return $end;
 848              default:
 849                  throw new MWException( "Block with invalid type" );
 850          }
 851      }
 852  
 853      /**
 854       * Get the user id of the blocking sysop
 855       *
 856       * @return int (0 for foreign users)
 857       */
 858  	public function getBy() {
 859          $blocker = $this->getBlocker();
 860          return ( $blocker instanceof User )
 861              ? $blocker->getId()
 862              : 0;
 863      }
 864  
 865      /**
 866       * Get the username of the blocking sysop
 867       *
 868       * @return string
 869       */
 870  	public function getByName() {
 871          $blocker = $this->getBlocker();
 872          return ( $blocker instanceof User )
 873              ? $blocker->getName()
 874              : (string)$blocker; // username
 875      }
 876  
 877      /**
 878       * Get the block ID
 879       * @return int
 880       */
 881  	public function getId() {
 882          return $this->mId;
 883      }
 884  
 885      /**
 886       * Get/set a flag determining whether the master is used for reads
 887       *
 888       * @param bool $x
 889       * @return bool
 890       */
 891  	public function fromMaster( $x = null ) {
 892          return wfSetVar( $this->mFromMaster, $x );
 893      }
 894  
 895      /**
 896       * Get/set whether the Block is a hardblock (affects logged-in users on a given IP/range
 897       * @param bool $x
 898       * @return bool
 899       */
 900  	public function isHardblock( $x = null ) {
 901          wfSetVar( $this->isHardblock, $x );
 902  
 903          # You can't *not* hardblock a user
 904          return $this->getType() == self::TYPE_USER
 905              ? true
 906              : $this->isHardblock;
 907      }
 908  
 909  	public function isAutoblocking( $x = null ) {
 910          wfSetVar( $this->isAutoblocking, $x );
 911  
 912          # You can't put an autoblock on an IP or range as we don't have any history to
 913          # look over to get more IPs from
 914          return $this->getType() == self::TYPE_USER
 915              ? $this->isAutoblocking
 916              : false;
 917      }
 918  
 919      /**
 920       * Get/set whether the Block prevents a given action
 921       * @param string $action
 922       * @param bool $x
 923       * @return bool
 924       */
 925  	public function prevents( $action, $x = null ) {
 926          switch ( $action ) {
 927              case 'edit':
 928                  # For now... <evil laugh>
 929                  return true;
 930  
 931              case 'createaccount':
 932                  return wfSetVar( $this->mCreateAccount, $x );
 933  
 934              case 'sendemail':
 935                  return wfSetVar( $this->mBlockEmail, $x );
 936  
 937              case 'editownusertalk':
 938                  return wfSetVar( $this->mDisableUsertalk, $x );
 939  
 940              default:
 941                  return null;
 942          }
 943      }
 944  
 945      /**
 946       * Get the block name, but with autoblocked IPs hidden as per standard privacy policy
 947       * @return string Text is escaped
 948       */
 949  	public function getRedactedName() {
 950          if ( $this->mAuto ) {
 951              return Html::rawElement(
 952                  'span',
 953                  array( 'class' => 'mw-autoblockid' ),
 954                  wfMessage( 'autoblockid', $this->mId )
 955              );
 956          } else {
 957              return htmlspecialchars( $this->getTarget() );
 958          }
 959      }
 960  
 961      /**
 962       * Get a timestamp of the expiry for autoblocks
 963       *
 964       * @param string|int $timestamp
 965       * @return string
 966       */
 967  	public static function getAutoblockExpiry( $timestamp ) {
 968          global $wgAutoblockExpiry;
 969  
 970          return wfTimestamp( TS_MW, wfTimestamp( TS_UNIX, $timestamp ) + $wgAutoblockExpiry );
 971      }
 972  
 973      /**
 974       * Purge expired blocks from the ipblocks table
 975       */
 976  	public static function purgeExpired() {
 977          if ( wfReadOnly() ) {
 978              return;
 979          }
 980  
 981          $method = __METHOD__;
 982          $dbw = wfGetDB( DB_MASTER );
 983          $dbw->onTransactionIdle( function () use ( $dbw, $method ) {
 984              $dbw->delete( 'ipblocks',
 985                  array( 'ipb_expiry < ' . $dbw->addQuotes( $dbw->timestamp() ) ), $method );
 986          } );
 987      }
 988  
 989      /**
 990       * Given a target and the target's type, get an existing Block object if possible.
 991       * @param string|User|int $specificTarget A block target, which may be one of several types:
 992       *     * A user to block, in which case $target will be a User
 993       *     * An IP to block, in which case $target will be a User generated by using
 994       *       User::newFromName( $ip, false ) to turn off name validation
 995       *     * An IP range, in which case $target will be a String "123.123.123.123/18" etc
 996       *     * The ID of an existing block, in the format "#12345" (since pure numbers are valid
 997       *       usernames
 998       *     Calling this with a user, IP address or range will not select autoblocks, and will
 999       *     only select a block where the targets match exactly (so looking for blocks on
1000       *     1.2.3.4 will not select 1.2.0.0/16 or even 1.2.3.4/32)
1001       * @param string|User|int $vagueTarget As above, but we will search for *any* block which
1002       *     affects that target (so for an IP address, get ranges containing that IP; and also
1003       *     get any relevant autoblocks). Leave empty or blank to skip IP-based lookups.
1004       * @param bool $fromMaster Whether to use the DB_MASTER database
1005       * @return Block|null (null if no relevant block could be found).  The target and type
1006       *     of the returned Block will refer to the actual block which was found, which might
1007       *     not be the same as the target you gave if you used $vagueTarget!
1008       */
1009  	public static function newFromTarget( $specificTarget, $vagueTarget = null, $fromMaster = false ) {
1010  
1011          list( $target, $type ) = self::parseTarget( $specificTarget );
1012          if ( $type == Block::TYPE_ID || $type == Block::TYPE_AUTO ) {
1013              return Block::newFromID( $target );
1014  
1015          } elseif ( $target === null && $vagueTarget == '' ) {
1016              # We're not going to find anything useful here
1017              # Be aware that the == '' check is explicit, since empty values will be
1018              # passed by some callers (bug 29116)
1019              return null;
1020  
1021          } elseif ( in_array(
1022              $type,
1023              array( Block::TYPE_USER, Block::TYPE_IP, Block::TYPE_RANGE, null ) )
1024          ) {
1025              $block = new Block();
1026              $block->fromMaster( $fromMaster );
1027  
1028              if ( $type !== null ) {
1029                  $block->setTarget( $target );
1030              }
1031  
1032              if ( $block->newLoad( $vagueTarget ) ) {
1033                  return $block;
1034              }
1035          }
1036          return null;
1037      }
1038  
1039      /**
1040       * Get all blocks that match any IP from an array of IP addresses
1041       *
1042       * @param array $ipChain List of IPs (strings), usually retrieved from the
1043       *       X-Forwarded-For header of the request
1044       * @param bool $isAnon Exclude anonymous-only blocks if false
1045       * @param bool $fromMaster Whether to query the master or slave database
1046       * @return array Array of Blocks
1047       * @since 1.22
1048       */
1049  	public static function getBlocksForIPList( array $ipChain, $isAnon, $fromMaster = false ) {
1050          if ( !count( $ipChain ) ) {
1051              return array();
1052          }
1053  
1054          wfProfileIn( __METHOD__ );
1055          $conds = array();
1056          foreach ( array_unique( $ipChain ) as $ipaddr ) {
1057              # Discard invalid IP addresses. Since XFF can be spoofed and we do not
1058              # necessarily trust the header given to us, make sure that we are only
1059              # checking for blocks on well-formatted IP addresses (IPv4 and IPv6).
1060              # Do not treat private IP spaces as special as it may be desirable for wikis
1061              # to block those IP ranges in order to stop misbehaving proxies that spoof XFF.
1062              if ( !IP::isValid( $ipaddr ) ) {
1063                  continue;
1064              }
1065              # Don't check trusted IPs (includes local squids which will be in every request)
1066              if ( IP::isTrustedProxy( $ipaddr ) ) {
1067                  continue;
1068              }
1069              # Check both the original IP (to check against single blocks), as well as build
1070              # the clause to check for rangeblocks for the given IP.
1071              $conds['ipb_address'][] = $ipaddr;
1072              $conds[] = self::getRangeCond( IP::toHex( $ipaddr ) );
1073          }
1074  
1075          if ( !count( $conds ) ) {
1076              wfProfileOut( __METHOD__ );
1077              return array();
1078          }
1079  
1080          if ( $fromMaster ) {
1081              $db = wfGetDB( DB_MASTER );
1082          } else {
1083              $db = wfGetDB( DB_SLAVE );
1084          }
1085          $conds = $db->makeList( $conds, LIST_OR );
1086          if ( !$isAnon ) {
1087              $conds = array( $conds, 'ipb_anon_only' => 0 );
1088          }
1089          $selectFields = array_merge(
1090              array( 'ipb_range_start', 'ipb_range_end' ),
1091              Block::selectFields()
1092          );
1093          $rows = $db->select( 'ipblocks',
1094              $selectFields,
1095              $conds,
1096              __METHOD__
1097          );
1098  
1099          $blocks = array();
1100          foreach ( $rows as $row ) {
1101              $block = self::newFromRow( $row );
1102              if ( !$block->deleteIfExpired()  ) {
1103                  $blocks[] = $block;
1104              }
1105          }
1106  
1107          wfProfileOut( __METHOD__ );
1108          return $blocks;
1109      }
1110  
1111      /**
1112       * From a list of multiple blocks, find the most exact and strongest Block.
1113       * The logic for finding the "best" block is:
1114       *  - Blocks that match the block's target IP are preferred over ones in a range
1115       *  - Hardblocks are chosen over softblocks that prevent account creation
1116       *  - Softblocks that prevent account creation are chosen over other softblocks
1117       *  - Other softblocks are chosen over autoblocks
1118       *  - If there are multiple exact or range blocks at the same level, the one chosen
1119       *    is random
1120       *
1121       * @param array $blocks Array of blocks
1122       * @param array $ipChain List of IPs (strings). This is used to determine how "close"
1123       *       a block is to the server, and if a block matches exactly, or is in a range.
1124       *      The order is furthest from the server to nearest e.g., (Browser, proxy1, proxy2,
1125       *      local-squid, ...)
1126       * @return Block|null The "best" block from the list
1127       */
1128  	public static function chooseBlock( array $blocks, array $ipChain ) {
1129          if ( !count( $blocks ) ) {
1130              return null;
1131          } elseif ( count( $blocks ) == 1 ) {
1132              return $blocks[0];
1133          }
1134  
1135          wfProfileIn( __METHOD__ );
1136  
1137          // Sort hard blocks before soft ones and secondarily sort blocks
1138          // that disable account creation before those that don't.
1139          usort( $blocks, function ( Block $a, Block $b ) {
1140              $aWeight = (int)$a->isHardblock() . (int)$a->prevents( 'createaccount' );
1141              $bWeight = (int)$b->isHardblock() . (int)$b->prevents( 'createaccount' );
1142              return strcmp( $bWeight, $aWeight ); // highest weight first
1143          } );
1144  
1145          $blocksListExact = array(
1146              'hard' => false,
1147              'disable_create' => false,
1148              'other' => false,
1149              'auto' => false
1150          );
1151          $blocksListRange = array(
1152              'hard' => false,
1153              'disable_create' => false,
1154              'other' => false,
1155              'auto' => false
1156          );
1157          $ipChain = array_reverse( $ipChain );
1158  
1159          foreach ( $blocks as $block ) {
1160              // Stop searching if we have already have a "better" block. This
1161              // is why the order of the blocks matters
1162              if ( !$block->isHardblock() && $blocksListExact['hard'] ) {
1163                  break;
1164              } elseif ( !$block->prevents( 'createaccount' ) && $blocksListExact['disable_create'] ) {
1165                  break;
1166              }
1167  
1168              foreach ( $ipChain as $checkip ) {
1169                  $checkipHex = IP::toHex( $checkip );
1170                  if ( (string)$block->getTarget() === $checkip ) {
1171                      if ( $block->isHardblock() ) {
1172                          $blocksListExact['hard'] = $blocksListExact['hard'] ?: $block;
1173                      } elseif ( $block->prevents( 'createaccount' ) ) {
1174                          $blocksListExact['disable_create'] = $blocksListExact['disable_create'] ?: $block;
1175                      } elseif ( $block->mAuto ) {
1176                          $blocksListExact['auto'] = $blocksListExact['auto'] ?: $block;
1177                      } else {
1178                          $blocksListExact['other'] = $blocksListExact['other'] ?: $block;
1179                      }
1180                      // We found closest exact match in the ip list, so go to the next Block
1181                      break;
1182                  } elseif ( array_filter( $blocksListExact ) == array()
1183                      && $block->getRangeStart() <= $checkipHex
1184                      && $block->getRangeEnd() >= $checkipHex
1185                  ) {
1186                      if ( $block->isHardblock() ) {
1187                          $blocksListRange['hard'] = $blocksListRange['hard'] ?: $block;
1188                      } elseif ( $block->prevents( 'createaccount' ) ) {
1189                          $blocksListRange['disable_create'] = $blocksListRange['disable_create'] ?: $block;
1190                      } elseif ( $block->mAuto ) {
1191                          $blocksListRange['auto'] = $blocksListRange['auto'] ?: $block;
1192                      } else {
1193                          $blocksListRange['other'] = $blocksListRange['other'] ?: $block;
1194                      }
1195                      break;
1196                  }
1197              }
1198          }
1199  
1200          if ( array_filter( $blocksListExact ) == array() ) {
1201              $blocksList = &$blocksListRange;
1202          } else {
1203              $blocksList = &$blocksListExact;
1204          }
1205  
1206          $chosenBlock = null;
1207          if ( $blocksList['hard'] ) {
1208              $chosenBlock = $blocksList['hard'];
1209          } elseif ( $blocksList['disable_create'] ) {
1210              $chosenBlock = $blocksList['disable_create'];
1211          } elseif ( $blocksList['other'] ) {
1212              $chosenBlock = $blocksList['other'];
1213          } elseif ( $blocksList['auto'] ) {
1214              $chosenBlock = $blocksList['auto'];
1215          } else {
1216              wfProfileOut( __METHOD__ );
1217              throw new MWException( "Proxy block found, but couldn't be classified." );
1218          }
1219  
1220          wfProfileOut( __METHOD__ );
1221          return $chosenBlock;
1222      }
1223  
1224      /**
1225       * From an existing Block, get the target and the type of target.
1226       * Note that, except for null, it is always safe to treat the target
1227       * as a string; for User objects this will return User::__toString()
1228       * which in turn gives User::getName().
1229       *
1230       * @param string|int|User|null $target
1231       * @return array( User|String|null, Block::TYPE_ constant|null )
1232       */
1233  	public static function parseTarget( $target ) {
1234          # We may have been through this before
1235          if ( $target instanceof User ) {
1236              if ( IP::isValid( $target->getName() ) ) {
1237                  return array( $target, self::TYPE_IP );
1238              } else {
1239                  return array( $target, self::TYPE_USER );
1240              }
1241          } elseif ( $target === null ) {
1242              return array( null, null );
1243          }
1244  
1245          $target = trim( $target );
1246  
1247          if ( IP::isValid( $target ) ) {
1248              # We can still create a User if it's an IP address, but we need to turn
1249              # off validation checking (which would exclude IP addresses)
1250              return array(
1251                  User::newFromName( IP::sanitizeIP( $target ), false ),
1252                  Block::TYPE_IP
1253              );
1254  
1255          } elseif ( IP::isValidBlock( $target ) ) {
1256              # Can't create a User from an IP range
1257              return array( IP::sanitizeRange( $target ), Block::TYPE_RANGE );
1258          }
1259  
1260          # Consider the possibility that this is not a username at all
1261          # but actually an old subpage (bug #29797)
1262          if ( strpos( $target, '/' ) !== false ) {
1263              # An old subpage, drill down to the user behind it
1264              $parts = explode( '/', $target );
1265              $target = $parts[0];
1266          }
1267  
1268          $userObj = User::newFromName( $target );
1269          if ( $userObj instanceof User ) {
1270              # Note that since numbers are valid usernames, a $target of "12345" will be
1271              # considered a User.  If you want to pass a block ID, prepend a hash "#12345",
1272              # since hash characters are not valid in usernames or titles generally.
1273              return array( $userObj, Block::TYPE_USER );
1274  
1275          } elseif ( preg_match( '/^#\d+$/', $target ) ) {
1276              # Autoblock reference in the form "#12345"
1277              return array( substr( $target, 1 ), Block::TYPE_AUTO );
1278  
1279          } else {
1280              # WTF?
1281              return array( null, null );
1282          }
1283      }
1284  
1285      /**
1286       * Get the type of target for this particular block
1287       * @return int Block::TYPE_ constant, will never be TYPE_ID
1288       */
1289  	public function getType() {
1290          return $this->mAuto
1291              ? self::TYPE_AUTO
1292              : $this->type;
1293      }
1294  
1295      /**
1296       * Get the target and target type for this particular Block.  Note that for autoblocks,
1297       * this returns the unredacted name; frontend functions need to call $block->getRedactedName()
1298       * in this situation.
1299       * @return array( User|String, Block::TYPE_ constant )
1300       * @todo FIXME: This should be an integral part of the Block member variables
1301       */
1302  	public function getTargetAndType() {
1303          return array( $this->getTarget(), $this->getType() );
1304      }
1305  
1306      /**
1307       * Get the target for this particular Block.  Note that for autoblocks,
1308       * this returns the unredacted name; frontend functions need to call $block->getRedactedName()
1309       * in this situation.
1310       * @return User|string
1311       */
1312  	public function getTarget() {
1313          return $this->target;
1314      }
1315  
1316      /**
1317       * @since 1.19
1318       *
1319       * @return mixed|string
1320       */
1321  	public function getExpiry() {
1322          return $this->mExpiry;
1323      }
1324  
1325      /**
1326       * Set the target for this block, and update $this->type accordingly
1327       * @param mixed $target
1328       */
1329  	public function setTarget( $target ) {
1330          list( $this->target, $this->type ) = self::parseTarget( $target );
1331      }
1332  
1333      /**
1334       * Get the user who implemented this block
1335       * @return User|string Local User object or string for a foreign user
1336       */
1337  	public function getBlocker() {
1338          return $this->blocker;
1339      }
1340  
1341      /**
1342       * Set the user who implemented (or will implement) this block
1343       * @param User|string $user Local User object or username string for foreign users
1344       */
1345  	public function setBlocker( $user ) {
1346          $this->blocker = $user;
1347      }
1348  
1349      /**
1350       * Get the key and parameters for the corresponding error message.
1351       *
1352       * @since 1.22
1353       * @param IContextSource $context
1354       * @return array
1355       */
1356  	public function getPermissionsError( IContextSource $context ) {
1357          $blocker = $this->getBlocker();
1358          if ( $blocker instanceof User ) { // local user
1359              $blockerUserpage = $blocker->getUserPage();
1360              $link = "[[{$blockerUserpage->getPrefixedText()}|{$blockerUserpage->getText()}]]";
1361          } else { // foreign user
1362              $link = $blocker;
1363          }
1364  
1365          $reason = $this->mReason;
1366          if ( $reason == '' ) {
1367              $reason = $context->msg( 'blockednoreason' )->text();
1368          }
1369  
1370          /* $ip returns who *is* being blocked, $intended contains who was meant to be blocked.
1371           * This could be a username, an IP range, or a single IP. */
1372          $intended = $this->getTarget();
1373  
1374          $lang = $context->getLanguage();
1375          return array(
1376              $this->mAuto ? 'autoblockedtext' : 'blockedtext',
1377              $link,
1378              $reason,
1379              $context->getRequest()->getIP(),
1380              $this->getByName(),
1381              $this->getId(),
1382              $lang->formatExpiry( $this->mExpiry ),
1383              (string)$intended,
1384              $lang->userTimeAndDate( $this->mTimestamp, $context->getUser() ),
1385          );
1386      }
1387  }


Generated: Fri Nov 28 14:03:12 2014 Cross-referenced by PHPXref 0.7.1