MediaWiki  master
Block.php
Go to the documentation of this file.
00001 <?php
00022 class Block {
00023         /* public*/ var $mReason, $mTimestamp, $mAuto, $mExpiry, $mHideName;
00024 
00025         protected
00026                 $mId,
00027                 $mFromMaster,
00028 
00029                 $mBlockEmail,
00030                 $mDisableUsertalk,
00031                 $mCreateAccount,
00032                 $mParentBlockId;
00033 
00035         protected $target;
00036 
00037         // @var Integer Hack for foreign blocking (CentralAuth)
00038         protected $forcedTargetID;
00039 
00041         protected $type;
00042 
00044         protected $blocker;
00045 
00047         protected $isHardblock = true;
00048 
00050         protected $isAutoblocking = true;
00051 
00052         # TYPE constants
00053         const TYPE_USER = 1;
00054         const TYPE_IP = 2;
00055         const TYPE_RANGE = 3;
00056         const TYPE_AUTO = 4;
00057         const TYPE_ID = 5;
00058 
00064         function __construct( $address = '', $user = 0, $by = 0, $reason = '',
00065                 $timestamp = 0, $auto = 0, $expiry = '', $anonOnly = 0, $createAccount = 0, $enableAutoblock = 0,
00066                 $hideName = 0, $blockEmail = 0, $allowUsertalk = 0, $byText = '' )
00067         {
00068                 if( $timestamp === 0 ){
00069                         $timestamp = wfTimestampNow();
00070                 }
00071 
00072                 if( count( func_get_args() ) > 0 ){
00073                         # Soon... :D
00074                         # wfDeprecated( __METHOD__ . " with arguments" );
00075                 }
00076 
00077                 $this->setTarget( $address );
00078                 if ( $this->target instanceof User && $user ) {
00079                         $this->forcedTargetID = $user; // needed for foreign users
00080                 }
00081                 if ( $by ) { // local user
00082                         $this->setBlocker( User::newFromID( $by ) );
00083                 } else { // foreign user
00084                         $this->setBlocker( $byText );
00085                 }
00086                 $this->mReason = $reason;
00087                 $this->mTimestamp = wfTimestamp( TS_MW, $timestamp );
00088                 $this->mAuto = $auto;
00089                 $this->isHardblock( !$anonOnly );
00090                 $this->prevents( 'createaccount', $createAccount );
00091                 if ( $expiry == 'infinity' || $expiry == wfGetDB( DB_SLAVE )->getInfinity() ) {
00092                         $this->mExpiry = 'infinity';
00093                 } else {
00094                         $this->mExpiry = wfTimestamp( TS_MW, $expiry );
00095                 }
00096                 $this->isAutoblocking( $enableAutoblock );
00097                 $this->mHideName = $hideName;
00098                 $this->prevents( 'sendemail', $blockEmail );
00099                 $this->prevents( 'editownusertalk', !$allowUsertalk );
00100 
00101                 $this->mFromMaster = false;
00102         }
00103 
00114         public static function newFromDB( $address, $user = 0 ) {
00115                 wfDeprecated( __METHOD__, '1.18' );
00116                 return self::newFromTarget( User::whoIs( $user ), $address );
00117         }
00118 
00125         public static function newFromID( $id ) {
00126                 $dbr = wfGetDB( DB_SLAVE );
00127                 $res = $dbr->selectRow(
00128                         'ipblocks',
00129                         self::selectFields(),
00130                         array( 'ipb_id' => $id ),
00131                         __METHOD__
00132                 );
00133                 if ( $res ) {
00134                         return self::newFromRow( $res );
00135                 } else {
00136                         return null;
00137                 }
00138         }
00139 
00145         public static function selectFields() {
00146                 return array(
00147                         'ipb_id',
00148                         'ipb_address',
00149                         'ipb_by',
00150                         'ipb_by_text',
00151                         'ipb_reason',
00152                         'ipb_timestamp',
00153                         'ipb_auto',
00154                         'ipb_anon_only',
00155                         'ipb_create_account',
00156                         'ipb_enable_autoblock',
00157                         'ipb_expiry',
00158                         'ipb_deleted',
00159                         'ipb_block_email',
00160                         'ipb_allow_usertalk',
00161                         'ipb_parent_block_id',
00162                 );
00163         }
00164 
00173         public function equals( Block $block ) {
00174                 return (
00175                         (string)$this->target == (string)$block->target
00176                         && $this->type == $block->type
00177                         && $this->mAuto == $block->mAuto
00178                         && $this->isHardblock() == $block->isHardblock()
00179                         && $this->prevents( 'createaccount' ) == $block->prevents( 'createaccount' )
00180                         && $this->mExpiry == $block->mExpiry
00181                         && $this->isAutoblocking() == $block->isAutoblocking()
00182                         && $this->mHideName == $block->mHideName
00183                         && $this->prevents( 'sendemail' ) == $block->prevents( 'sendemail' )
00184                         && $this->prevents( 'editownusertalk' ) == $block->prevents( 'editownusertalk' )
00185                         && $this->mReason == $block->mReason
00186                 );
00187         }
00188 
00194         public function clear() {
00195                 wfDeprecated( __METHOD__, '1.18' );
00196                 # Noop
00197         }
00198 
00207         public function load( $address = '', $user = 0 ) {
00208                 wfDeprecated( __METHOD__, '1.18' );
00209                 if( $user ){
00210                         $username = User::whoIs( $user );
00211                         $block = self::newFromTarget( $username, $address );
00212                 } else {
00213                         $block = self::newFromTarget( null, $address );
00214                 }
00215 
00216                 if( $block instanceof Block ){
00217                         # This is mildly evil, but hey, it's B/C :D
00218                         foreach( $block as $variable => $value ){
00219                                 $this->$variable = $value;
00220                         }
00221                         return true;
00222                 } else {
00223                         return false;
00224                 }
00225         }
00226 
00237         protected function newLoad( $vagueTarget = null ) {
00238                 $db = wfGetDB( $this->mFromMaster ? DB_MASTER : DB_SLAVE );
00239 
00240                 if( $this->type !== null ){
00241                         $conds = array(
00242                                 'ipb_address' => array( (string)$this->target ),
00243                         );
00244                 } else {
00245                         $conds = array( 'ipb_address' => array() );
00246                 }
00247 
00248                 # Be aware that the != '' check is explicit, since empty values will be
00249                 # passed by some callers (bug 29116)
00250                 if( $vagueTarget != ''){
00251                         list( $target, $type ) = self::parseTarget( $vagueTarget );
00252                         switch( $type ) {
00253                                 case self::TYPE_USER:
00254                                         # Slightly wierd, but who are we to argue?
00255                                         $conds['ipb_address'][] = (string)$target;
00256                                         break;
00257 
00258                                 case self::TYPE_IP:
00259                                         $conds['ipb_address'][] = (string)$target;
00260                                         $conds[] = self::getRangeCond( IP::toHex( $target ) );
00261                                         $conds = $db->makeList( $conds, LIST_OR );
00262                                         break;
00263 
00264                                 case self::TYPE_RANGE:
00265                                         list( $start, $end ) = IP::parseRange( $target );
00266                                         $conds['ipb_address'][] = (string)$target;
00267                                         $conds[] = self::getRangeCond( $start, $end );
00268                                         $conds = $db->makeList( $conds, LIST_OR );
00269                                         break;
00270 
00271                                 default:
00272                                         throw new MWException( "Tried to load block with invalid type" );
00273                         }
00274                 }
00275 
00276                 $res = $db->select( 'ipblocks', self::selectFields(), $conds, __METHOD__ );
00277 
00278                 # This result could contain a block on the user, a block on the IP, and a russian-doll
00279                 # set of rangeblocks.  We want to choose the most specific one, so keep a leader board.
00280                 $bestRow = null;
00281 
00282                 # Lower will be better
00283                 $bestBlockScore = 100;
00284 
00285                 # This is begging for $this = $bestBlock, but that's not allowed in PHP :(
00286                 $bestBlockPreventsEdit = null;
00287 
00288                 foreach( $res as $row ){
00289                         $block = self::newFromRow( $row );
00290 
00291                         # Don't use expired blocks
00292                         if( $block->deleteIfExpired() ){
00293                                 continue;
00294                         }
00295 
00296                         # Don't use anon only blocks on users
00297                         if( $this->type == self::TYPE_USER && !$block->isHardblock() ){
00298                                 continue;
00299                         }
00300 
00301                         if( $block->getType() == self::TYPE_RANGE ){
00302                                 # This is the number of bits that are allowed to vary in the block, give
00303                                 # or take some floating point errors
00304                                 $end = wfBaseconvert( $block->getRangeEnd(), 16, 10 );
00305                                 $start = wfBaseconvert( $block->getRangeStart(), 16, 10 );
00306                                 $size = log( $end - $start + 1, 2 );
00307 
00308                                 # This has the nice property that a /32 block is ranked equally with a
00309                                 # single-IP block, which is exactly what it is...
00310                                 $score = self::TYPE_RANGE  - 1 + ( $size / 128 );
00311 
00312                         } else {
00313                                 $score = $block->getType();
00314                         }
00315 
00316                         if( $score < $bestBlockScore ){
00317                                 $bestBlockScore = $score;
00318                                 $bestRow = $row;
00319                                 $bestBlockPreventsEdit = $block->prevents( 'edit' );
00320                         }
00321                 }
00322 
00323                 if( $bestRow !== null ){
00324                         $this->initFromRow( $bestRow );
00325                         $this->prevents( 'edit', $bestBlockPreventsEdit );
00326                         return true;
00327                 } else {
00328                         return false;
00329                 }
00330         }
00331 
00338         public static function getRangeCond( $start, $end = null ) {
00339                 if ( $end === null ) {
00340                         $end = $start;
00341                 }
00342                 # Per bug 14634, we want to include relevant active rangeblocks; for
00343                 # rangeblocks, we want to include larger ranges which enclose the given
00344                 # range. We know that all blocks must be smaller than $wgBlockCIDRLimit,
00345                 # so we can improve performance by filtering on a LIKE clause
00346                 $chunk = self::getIpFragment( $start );
00347                 $dbr = wfGetDB( DB_SLAVE );
00348                 $like = $dbr->buildLike( $chunk, $dbr->anyString() );
00349 
00350                 # Fairly hard to make a malicious SQL statement out of hex characters,
00351                 # but stranger things have happened...
00352                 $safeStart = $dbr->addQuotes( $start );
00353                 $safeEnd = $dbr->addQuotes( $end );
00354 
00355                 return $dbr->makeList(
00356                         array(
00357                                 "ipb_range_start $like",
00358                                 "ipb_range_start <= $safeStart",
00359                                 "ipb_range_end >= $safeEnd",
00360                         ),
00361                         LIST_AND
00362                 );
00363         }
00364 
00371         protected static function getIpFragment( $hex ) {
00372                 global $wgBlockCIDRLimit;
00373                 if ( substr( $hex, 0, 3 ) == 'v6-' ) {
00374                         return 'v6-' . substr( substr( $hex, 3 ), 0,  floor( $wgBlockCIDRLimit['IPv6'] / 4 ) );
00375                 } else {
00376                         return substr( $hex, 0,  floor( $wgBlockCIDRLimit['IPv4'] / 4 ) );
00377                 }
00378         }
00379 
00385         protected function initFromRow( $row ) {
00386                 $this->setTarget( $row->ipb_address );
00387                 if ( $row->ipb_by ) { // local user
00388                         $this->setBlocker( User::newFromID( $row->ipb_by ) );
00389                 } else { // foreign user
00390                         $this->setBlocker( $row->ipb_by_text );
00391                 }
00392 
00393                 $this->mReason = $row->ipb_reason;
00394                 $this->mTimestamp = wfTimestamp( TS_MW, $row->ipb_timestamp );
00395                 $this->mAuto = $row->ipb_auto;
00396                 $this->mHideName = $row->ipb_deleted;
00397                 $this->mId = $row->ipb_id;
00398                 $this->mParentBlockId = $row->ipb_parent_block_id;
00399 
00400                 // I wish I didn't have to do this
00401                 $db = wfGetDB( DB_SLAVE );
00402                 if ( $row->ipb_expiry == $db->getInfinity() ) {
00403                         $this->mExpiry = 'infinity';
00404                 } else {
00405                         $this->mExpiry = wfTimestamp( TS_MW, $row->ipb_expiry );
00406                 }
00407 
00408                 $this->isHardblock( !$row->ipb_anon_only );
00409                 $this->isAutoblocking( $row->ipb_enable_autoblock );
00410 
00411                 $this->prevents( 'createaccount', $row->ipb_create_account );
00412                 $this->prevents( 'sendemail', $row->ipb_block_email );
00413                 $this->prevents( 'editownusertalk', !$row->ipb_allow_usertalk );
00414         }
00415 
00421         public static function newFromRow( $row ){
00422                 $block = new Block;
00423                 $block->initFromRow( $row );
00424                 return $block;
00425         }
00426 
00433         public function delete() {
00434                 if ( wfReadOnly() ) {
00435                         return false;
00436                 }
00437 
00438                 if ( !$this->getId() ) {
00439                         throw new MWException( "Block::delete() requires that the mId member be filled\n" );
00440                 }
00441 
00442                 $dbw = wfGetDB( DB_MASTER );
00443                 $dbw->delete( 'ipblocks', array( 'ipb_parent_block_id' => $this->getId() ), __METHOD__ );
00444                 $dbw->delete( 'ipblocks', array( 'ipb_id' => $this->getId() ), __METHOD__ );
00445 
00446                 return $dbw->affectedRows() > 0;
00447         }
00448 
00457         public function insert( $dbw = null ) {
00458                 wfDebug( "Block::insert; timestamp {$this->mTimestamp}\n" );
00459 
00460                 if ( $dbw === null ) {
00461                         $dbw = wfGetDB( DB_MASTER );
00462                 }
00463 
00464                 # Don't collide with expired blocks
00465                 Block::purgeExpired();
00466 
00467                 $row = $this->getDatabaseArray();
00468                 $row['ipb_id'] = $dbw->nextSequenceValue("ipblocks_ipb_id_seq");
00469 
00470                 $dbw->insert(
00471                         'ipblocks',
00472                         $row,
00473                         __METHOD__,
00474                         array( 'IGNORE' )
00475                 );
00476                 $affected = $dbw->affectedRows();
00477                 $this->mId = $dbw->insertId();
00478 
00479                 if ( $affected ) {
00480                         $auto_ipd_ids = $this->doRetroactiveAutoblock();
00481                         return array( 'id' => $this->mId, 'autoIds' => $auto_ipd_ids );
00482                 }
00483 
00484                 return false;
00485         }
00486 
00494         public function update() {
00495                 wfDebug( "Block::update; timestamp {$this->mTimestamp}\n" );
00496                 $dbw = wfGetDB( DB_MASTER );
00497 
00498                 $dbw->update(
00499                         'ipblocks',
00500                         $this->getDatabaseArray( $dbw ),
00501                         array( 'ipb_id' => $this->getId() ),
00502                         __METHOD__
00503                 );
00504 
00505                 return $dbw->affectedRows();
00506         }
00507 
00513         protected function getDatabaseArray( $db = null ){
00514                 if( !$db ){
00515                         $db = wfGetDB( DB_SLAVE );
00516                 }
00517                 $expiry = $db->encodeExpiry( $this->mExpiry );
00518 
00519                 if ( $this->forcedTargetID ) {
00520                         $uid = $this->forcedTargetID;
00521                 } else {
00522                         $uid = $this->target instanceof User ? $this->target->getID() : 0;
00523                 }
00524 
00525                 $a = array(
00526                         'ipb_address'          => (string)$this->target,
00527                         'ipb_user'             => $uid,
00528                         'ipb_by'               => $this->getBy(),
00529                         'ipb_by_text'          => $this->getByName(),
00530                         'ipb_reason'           => $this->mReason,
00531                         'ipb_timestamp'        => $db->timestamp( $this->mTimestamp ),
00532                         'ipb_auto'             => $this->mAuto,
00533                         'ipb_anon_only'        => !$this->isHardblock(),
00534                         'ipb_create_account'   => $this->prevents( 'createaccount' ),
00535                         'ipb_enable_autoblock' => $this->isAutoblocking(),
00536                         'ipb_expiry'           => $expiry,
00537                         'ipb_range_start'      => $this->getRangeStart(),
00538                         'ipb_range_end'        => $this->getRangeEnd(),
00539                         'ipb_deleted'          => intval( $this->mHideName ), // typecast required for SQLite
00540                         'ipb_block_email'      => $this->prevents( 'sendemail' ),
00541                         'ipb_allow_usertalk'   => !$this->prevents( 'editownusertalk' ),
00542                         'ipb_parent_block_id'  => $this->mParentBlockId
00543                 );
00544 
00545                 return $a;
00546         }
00547 
00554         protected function doRetroactiveAutoblock() {
00555                 $blockIds = array();
00556                 # If autoblock is enabled, autoblock the LAST IP(s) used
00557                 if ( $this->isAutoblocking() && $this->getType() == self::TYPE_USER ) {
00558                         wfDebug( "Doing retroactive autoblocks for " . $this->getTarget() . "\n" );
00559 
00560                         $continue = wfRunHooks(
00561                                 'PerformRetroactiveAutoblock', array( $this, &$blockIds ) );
00562 
00563                         if ( $continue ) {
00564                                 self::defaultRetroactiveAutoblock( $this, $blockIds );
00565                         }
00566                 }
00567                 return $blockIds;
00568         }
00569 
00578         protected static function defaultRetroactiveAutoblock( Block $block, array &$blockIds ) {
00579                 $dbr = wfGetDB( DB_SLAVE );
00580 
00581                 $options = array( 'ORDER BY' => 'rc_timestamp DESC' );
00582                 $conds = array( 'rc_user_text' => (string)$block->getTarget() );
00583 
00584                 // Just the last IP used.
00585                 $options['LIMIT'] = 1;
00586 
00587                 $res = $dbr->select( 'recentchanges', array( 'rc_ip' ), $conds,
00588                         __METHOD__ ,  $options );
00589 
00590                 if ( !$dbr->numRows( $res ) ) {
00591                         # No results, don't autoblock anything
00592                         wfDebug( "No IP found to retroactively autoblock\n" );
00593                 } else {
00594                         foreach ( $res as $row ) {
00595                                 if ( $row->rc_ip ) {
00596                                         $id = $block->doAutoblock( $row->rc_ip );
00597                                         if ( $id ) $blockIds[] = $id;
00598                                 }
00599                         }
00600                 }
00601         }
00602 
00610         public static function isWhitelistedFromAutoblocks( $ip ) {
00611                 global $wgMemc;
00612 
00613                 // Try to get the autoblock_whitelist from the cache, as it's faster
00614                 // than getting the msg raw and explode()'ing it.
00615                 $key = wfMemcKey( 'ipb', 'autoblock', 'whitelist' );
00616                 $lines = $wgMemc->get( $key );
00617                 if ( !$lines ) {
00618                         $lines = explode( "\n", wfMessage( 'autoblock_whitelist' )->inContentLanguage()->plain() );
00619                         $wgMemc->set( $key, $lines, 3600 * 24 );
00620                 }
00621 
00622                 wfDebug( "Checking the autoblock whitelist..\n" );
00623 
00624                 foreach ( $lines as $line ) {
00625                         # List items only
00626                         if ( substr( $line, 0, 1 ) !== '*' ) {
00627                                 continue;
00628                         }
00629 
00630                         $wlEntry = substr( $line, 1 );
00631                         $wlEntry = trim( $wlEntry );
00632 
00633                         wfDebug( "Checking $ip against $wlEntry..." );
00634 
00635                         # Is the IP in this range?
00636                         if ( IP::isInRange( $ip, $wlEntry ) ) {
00637                                 wfDebug( " IP $ip matches $wlEntry, not autoblocking\n" );
00638                                 return true;
00639                         } else {
00640                                 wfDebug( " No match\n" );
00641                         }
00642                 }
00643 
00644                 return false;
00645         }
00646 
00653         public function doAutoblock( $autoblockIP ) {
00654                 # If autoblocks are disabled, go away.
00655                 if ( !$this->isAutoblocking() ) {
00656                         return false;
00657                 }
00658 
00659                 # Check for presence on the autoblock whitelist.
00660                 if ( self::isWhitelistedFromAutoblocks( $autoblockIP ) ) {
00661                         return false;
00662                 }
00663 
00664                 # Allow hooks to cancel the autoblock.
00665                 if ( !wfRunHooks( 'AbortAutoblock', array( $autoblockIP, &$this ) ) ) {
00666                         wfDebug( "Autoblock aborted by hook.\n" );
00667                         return false;
00668                 }
00669 
00670                 # It's okay to autoblock. Go ahead and insert/update the block...
00671 
00672                 # Do not add a *new* block if the IP is already blocked.
00673                 $ipblock = Block::newFromTarget( $autoblockIP );
00674                 if ( $ipblock ) {
00675                         # Check if the block is an autoblock and would exceed the user block
00676                         # if renewed. If so, do nothing, otherwise prolong the block time...
00677                         if ( $ipblock->mAuto && // @TODO: why not compare $ipblock->mExpiry?
00678                                 $this->mExpiry > Block::getAutoblockExpiry( $ipblock->mTimestamp )
00679                         ) {
00680                                 # Reset block timestamp to now and its expiry to
00681                                 # $wgAutoblockExpiry in the future
00682                                 $ipblock->updateTimestamp();
00683                         }
00684                         return false;
00685                 }
00686 
00687                 # Make a new block object with the desired properties.
00688                 $autoblock = new Block;
00689                 wfDebug( "Autoblocking {$this->getTarget()}@" . $autoblockIP . "\n" );
00690                 $autoblock->setTarget( $autoblockIP );
00691                 $autoblock->setBlocker( $this->getBlocker() );
00692                 $autoblock->mReason = wfMessage( 'autoblocker', $this->getTarget(), $this->mReason )->inContentLanguage()->text();
00693                 $timestamp = wfTimestampNow();
00694                 $autoblock->mTimestamp = $timestamp;
00695                 $autoblock->mAuto = 1;
00696                 $autoblock->prevents( 'createaccount', $this->prevents( 'createaccount' ) );
00697                 # Continue suppressing the name if needed
00698                 $autoblock->mHideName = $this->mHideName;
00699                 $autoblock->prevents( 'editownusertalk', $this->prevents( 'editownusertalk' ) );
00700                 $autoblock->mParentBlockId = $this->mId;
00701 
00702                 if ( $this->mExpiry == 'infinity' ) {
00703                         # Original block was indefinite, start an autoblock now
00704                         $autoblock->mExpiry = Block::getAutoblockExpiry( $timestamp );
00705                 } else {
00706                         # If the user is already blocked with an expiry date, we don't
00707                         # want to pile on top of that.
00708                         $autoblock->mExpiry = min( $this->mExpiry, Block::getAutoblockExpiry( $timestamp ) );
00709                 }
00710 
00711                 # Insert the block...
00712                 $status = $autoblock->insert();
00713                 return $status
00714                         ? $status['id']
00715                         : false;
00716         }
00717 
00722         public function deleteIfExpired() {
00723                 wfProfileIn( __METHOD__ );
00724 
00725                 if ( $this->isExpired() ) {
00726                         wfDebug( "Block::deleteIfExpired() -- deleting\n" );
00727                         $this->delete();
00728                         $retVal = true;
00729                 } else {
00730                         wfDebug( "Block::deleteIfExpired() -- not expired\n" );
00731                         $retVal = false;
00732                 }
00733 
00734                 wfProfileOut( __METHOD__ );
00735                 return $retVal;
00736         }
00737 
00742         public function isExpired() {
00743                 $timestamp = wfTimestampNow();
00744                 wfDebug( "Block::isExpired() checking current " . $timestamp . " vs $this->mExpiry\n" );
00745 
00746                 if ( !$this->mExpiry ) {
00747                         return false;
00748                 } else {
00749                         return $timestamp > $this->mExpiry;
00750                 }
00751         }
00752 
00757         public function isValid() {
00758                 return $this->getTarget() != null;
00759         }
00760 
00764         public function updateTimestamp() {
00765                 if ( $this->mAuto ) {
00766                         $this->mTimestamp = wfTimestamp();
00767                         $this->mExpiry = Block::getAutoblockExpiry( $this->mTimestamp );
00768 
00769                         $dbw = wfGetDB( DB_MASTER );
00770                         $dbw->update( 'ipblocks',
00771                                 array( /* SET */
00772                                         'ipb_timestamp' => $dbw->timestamp( $this->mTimestamp ),
00773                                         'ipb_expiry' => $dbw->timestamp( $this->mExpiry ),
00774                                 ),
00775                                 array( /* WHERE */
00776                                         'ipb_address' => (string)$this->getTarget()
00777                                 ),
00778                                 __METHOD__
00779                         );
00780                 }
00781         }
00782 
00788         public function getRangeStart() {
00789                 switch( $this->type ) {
00790                         case self::TYPE_USER:
00791                                 return '';
00792                         case self::TYPE_IP:
00793                                 return IP::toHex( $this->target );
00794                         case self::TYPE_RANGE:
00795                                 list( $start, /*...*/ ) = IP::parseRange( $this->target );
00796                                 return $start;
00797                         default: throw new MWException( "Block with invalid type" );
00798                 }
00799         }
00800 
00806         public function getRangeEnd() {
00807                 switch( $this->type ) {
00808                         case self::TYPE_USER:
00809                                 return '';
00810                         case self::TYPE_IP:
00811                                 return IP::toHex( $this->target );
00812                         case self::TYPE_RANGE:
00813                                 list( /*...*/, $end ) = IP::parseRange( $this->target );
00814                                 return $end;
00815                         default: throw new MWException( "Block with invalid type" );
00816                 }
00817         }
00818 
00824         public function getBy() {
00825                 $blocker = $this->getBlocker();
00826                 return ( $blocker instanceof User )
00827                         ? $blocker->getId()
00828                         : 0;
00829         }
00830 
00836         public function getByName() {
00837                 $blocker = $this->getBlocker();
00838                 return ( $blocker instanceof User )
00839                         ? $blocker->getName()
00840                         : (string)$blocker; // username
00841         }
00842 
00847         public function getId() {
00848                 return $this->mId;
00849         }
00850 
00857         public function forUpdate( $x = null ) {
00858                 wfDeprecated( __METHOD__, '1.18' );
00859                 # noop
00860         }
00861 
00868         public function fromMaster( $x = null ) {
00869                 return wfSetVar( $this->mFromMaster, $x );
00870         }
00871 
00877         public function isHardblock( $x = null ) {
00878                 wfSetVar( $this->isHardblock, $x );
00879 
00880                 # You can't *not* hardblock a user
00881                 return $this->getType() == self::TYPE_USER
00882                         ? true
00883                         : $this->isHardblock;
00884         }
00885 
00886         public function isAutoblocking( $x = null ) {
00887                 wfSetVar( $this->isAutoblocking, $x );
00888 
00889                 # You can't put an autoblock on an IP or range as we don't have any history to
00890                 # look over to get more IPs from
00891                 return $this->getType() == self::TYPE_USER
00892                         ? $this->isAutoblocking
00893                         : false;
00894         }
00895 
00902         public function prevents( $action, $x = null ) {
00903                 switch( $action ) {
00904                         case 'edit':
00905                                 # For now... <evil laugh>
00906                                 return true;
00907 
00908                         case 'createaccount':
00909                                 return wfSetVar( $this->mCreateAccount, $x );
00910 
00911                         case 'sendemail':
00912                                 return wfSetVar( $this->mBlockEmail, $x );
00913 
00914                         case 'editownusertalk':
00915                                 return wfSetVar( $this->mDisableUsertalk, $x );
00916 
00917                         default:
00918                                 return null;
00919                 }
00920         }
00921 
00926         public function getRedactedName() {
00927                 if ( $this->mAuto ) {
00928                         return Html::rawElement(
00929                                 'span',
00930                                 array( 'class' => 'mw-autoblockid' ),
00931                                 wfMessage( 'autoblockid', $this->mId )
00932                         );
00933                 } else {
00934                         return htmlspecialchars( $this->getTarget() );
00935                 }
00936         }
00937 
00946         public static function encodeExpiry( $expiry, $db ) {
00947                 wfDeprecated( __METHOD__, '1.18' );
00948                 return $db->encodeExpiry( $expiry );
00949         }
00950 
00959         public static function decodeExpiry( $expiry, $timestampType = TS_MW ) {
00960                 wfDeprecated( __METHOD__, '1.18' );
00961                 global $wgContLang;
00962                 return $wgContLang->formatExpiry( $expiry, $timestampType );
00963         }
00964 
00971         public static function getAutoblockExpiry( $timestamp ) {
00972                 global $wgAutoblockExpiry;
00973 
00974                 return wfTimestamp( TS_MW, wfTimestamp( TS_UNIX, $timestamp ) + $wgAutoblockExpiry );
00975         }
00976 
00984         public static function normaliseRange( $range ) {
00985                 wfDeprecated( __METHOD__, '1.18' );
00986                 return IP::sanitizeRange( $range );
00987         }
00988 
00992         public static function purgeExpired() {
00993                 $dbw = wfGetDB( DB_MASTER );
00994                 $dbw->delete( 'ipblocks',
00995                         array( 'ipb_expiry < ' . $dbw->addQuotes( $dbw->timestamp() ) ), __METHOD__ );
00996         }
00997 
01004         public static function infinity() {
01005                 wfDeprecated( __METHOD__, '1.18' );
01006                 return wfGetDB( DB_SLAVE )->getInfinity();
01007         }
01008 
01016         public static function parseExpiryInput( $expiry ) {
01017                 wfDeprecated( __METHOD__, '1.18' );
01018                 return SpecialBlock::parseExpiryInput( $expiry );
01019         }
01020 
01041         public static function newFromTarget( $specificTarget, $vagueTarget = null, $fromMaster = false ) {
01042 
01043                 list( $target, $type ) = self::parseTarget( $specificTarget );
01044                 if( $type == Block::TYPE_ID || $type == Block::TYPE_AUTO ){
01045                         return Block::newFromID( $target );
01046 
01047                 } elseif( $target === null && $vagueTarget == '' ){
01048                         # We're not going to find anything useful here
01049                         # Be aware that the == '' check is explicit, since empty values will be
01050                         # passed by some callers (bug 29116)
01051                         return null;
01052 
01053                 } elseif( in_array( $type, array( Block::TYPE_USER, Block::TYPE_IP, Block::TYPE_RANGE ) ) ) {
01054                         $block = new Block();
01055                         $block->fromMaster( $fromMaster );
01056 
01057                         if( $type !== null ){
01058                                 $block->setTarget( $target );
01059                         }
01060 
01061                         if( $block->newLoad( $vagueTarget ) ){
01062                                 return $block;
01063                         }
01064                 }
01065                 return null;
01066         }
01067 
01076         public static function parseTarget( $target ) {
01077                 # We may have been through this before
01078                 if( $target instanceof User ){
01079                         if( IP::isValid( $target->getName() ) ){
01080                                 return array( $target, self::TYPE_IP );
01081                         } else {
01082                                 return array( $target, self::TYPE_USER );
01083                         }
01084                 } elseif( $target === null ){
01085                         return array( null, null );
01086                 }
01087 
01088                 $target = trim( $target );
01089 
01090                 if ( IP::isValid( $target ) ) {
01091                         # We can still create a User if it's an IP address, but we need to turn
01092                         # off validation checking (which would exclude IP addresses)
01093                         return array(
01094                                 User::newFromName( IP::sanitizeIP( $target ), false ),
01095                                 Block::TYPE_IP
01096                         );
01097 
01098                 } elseif ( IP::isValidBlock( $target ) ) {
01099                         # Can't create a User from an IP range
01100                         return array( IP::sanitizeRange( $target ), Block::TYPE_RANGE );
01101                 }
01102 
01103                 # Consider the possibility that this is not a username at all
01104                 # but actually an old subpage (bug #29797)
01105                 if( strpos( $target, '/' ) !== false ){
01106                         # An old subpage, drill down to the user behind it
01107                         $parts = explode( '/', $target );
01108                         $target = $parts[0];
01109                 }
01110 
01111                 $userObj = User::newFromName( $target );
01112                 if ( $userObj instanceof User ) {
01113                         # Note that since numbers are valid usernames, a $target of "12345" will be
01114                         # considered a User.  If you want to pass a block ID, prepend a hash "#12345",
01115                         # since hash characters are not valid in usernames or titles generally.
01116                         return array( $userObj, Block::TYPE_USER );
01117 
01118                 } elseif ( preg_match( '/^#\d+$/', $target ) ) {
01119                         # Autoblock reference in the form "#12345"
01120                         return array( substr( $target, 1 ), Block::TYPE_AUTO );
01121 
01122                 } else {
01123                         # WTF?
01124                         return array( null, null );
01125                 }
01126         }
01127 
01132         public function getType() {
01133                 return $this->mAuto
01134                         ? self::TYPE_AUTO
01135                         : $this->type;
01136         }
01137 
01145         public function getTargetAndType() {
01146                 return array( $this->getTarget(), $this->getType() );
01147         }
01148 
01155         public function getTarget() {
01156                 return $this->target;
01157         }
01158 
01164         public function getExpiry() {
01165                 return $this->mExpiry;
01166         }
01167 
01172         public function setTarget( $target ){
01173                 list( $this->target, $this->type ) = self::parseTarget( $target );
01174         }
01175 
01180         public function getBlocker(){
01181                 return $this->blocker;
01182         }
01183 
01188         public function setBlocker( $user ){
01189                 $this->blocker = $user;
01190         }
01191 }