+ /**
+ * Update a block in the DB with new parameters.
+ * The ID field needs to be loaded first.
+ */
+ public function update() {
+ wfDebug( "Block::update; timestamp {$this->mTimestamp}\n" );
+ $dbw = wfGetDB( DB_MASTER );
+
+ $this->validateBlockParams();
+
+ $dbw->update(
+ 'ipblocks',
+ array(
+ 'ipb_user' => $this->mUser,
+ 'ipb_by' => $this->mBy,
+ 'ipb_by_text' => $this->mByName,
+ 'ipb_reason' => $this->mReason,
+ 'ipb_timestamp' => $dbw->timestamp( $this->mTimestamp ),
+ 'ipb_auto' => $this->mAuto,
+ 'ipb_anon_only' => $this->mAnonOnly,
+ 'ipb_create_account' => $this->mCreateAccount,
+ 'ipb_enable_autoblock' => $this->mEnableAutoblock,
+ 'ipb_expiry' => $dbw->encodeExpiry( $this->mExpiry ),
+ 'ipb_range_start' => $this->mRangeStart,
+ 'ipb_range_end' => $this->mRangeEnd,
+ 'ipb_deleted' => $this->mHideName,
+ 'ipb_block_email' => $this->mBlockEmail,
+ 'ipb_allow_usertalk' => $this->mAllowUsertalk
+ ),
+ array( 'ipb_id' => $this->mId ),
+ 'Block::update'
+ );
+
+ return $dbw->affectedRows();
+ }
+
+ /**
+ * Make sure all the proper members are set to sane values
+ * before adding/updating a block
+ */
+ protected function validateBlockParams() {
+ # Unset ipb_anon_only for user blocks, makes no sense
+ if ( $this->mUser ) {
+ $this->mAnonOnly = 0;
+ }
+
+ # Unset ipb_enable_autoblock for IP blocks, makes no sense
+ if ( !$this->mUser ) {
+ $this->mEnableAutoblock = 0;
+ }
+
+ # bug 18860: non-anon-only IP blocks should be allowed to block email
+ if ( !$this->mUser && $this->mAnonOnly ) {
+ $this->mBlockEmail = 0;
+ }
+
+ if ( !$this->mByName ) {
+ if ( $this->mBy ) {
+ $this->mByName = User::whoIs( $this->mBy );
+ } else {
+ global $wgUser;
+ $this->mByName = $wgUser->getName();
+ }
+ }
+ }
+
+ /**
+ * Retroactively autoblocks the last IP used by the user (if it is a user)
+ * blocked by this Block.
+ *
+ * @return Boolean: whether or not a retroactive autoblock was made.
+ */
+ protected function doRetroactiveAutoblock() {
+ $dbr = wfGetDB( DB_SLAVE );
+ # If autoblock is enabled, autoblock the LAST IP used
+ # - stolen shamelessly from CheckUser_body.php
+
+ if ( $this->mEnableAutoblock && $this->mUser ) {
+ wfDebug( "Doing retroactive autoblocks for " . $this->mAddress . "\n" );
+
+ $options = array( 'ORDER BY' => 'rc_timestamp DESC' );
+ $conds = array( 'rc_user_text' => $this->mAddress );
+
+ if ( $this->mAngryAutoblock ) {
+ // Block any IP used in the last 7 days. Up to five IPs.
+ $conds[] = 'rc_timestamp < ' . $dbr->addQuotes( $dbr->timestamp( time() - ( 7 * 86400 ) ) );
+ $options['LIMIT'] = 5;
+ } else {
+ // Just the last IP used.
+ $options['LIMIT'] = 1;
+ }
+
+ $res = $dbr->select( 'recentchanges', array( 'rc_ip' ), $conds,
+ __METHOD__ , $options );
+
+ if ( !$dbr->numRows( $res ) ) {
+ # No results, don't autoblock anything
+ wfDebug( "No IP found to retroactively autoblock\n" );
+ } else {
+ foreach ( $res as $row ) {
+ if ( $row->rc_ip ) {
+ $this->doAutoblock( $row->rc_ip );
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks whether a given IP is on the autoblock whitelist.
+ *
+ * @param $ip String: The IP to check
+ * @return Boolean
+ */
+ public static function isWhitelistedFromAutoblocks( $ip ) {
+ global $wgMemc;
+
+ // Try to get the autoblock_whitelist from the cache, as it's faster
+ // than getting the msg raw and explode()'ing it.
+ $key = wfMemcKey( 'ipb', 'autoblock', 'whitelist' );
+ $lines = $wgMemc->get( $key );
+ if ( !$lines ) {
+ $lines = explode( "\n", wfMsgForContentNoTrans( 'autoblock_whitelist' ) );
+ $wgMemc->set( $key, $lines, 3600 * 24 );
+ }
+
+ wfDebug( "Checking the autoblock whitelist..\n" );
+
+ foreach ( $lines as $line ) {
+ # List items only
+ if ( substr( $line, 0, 1 ) !== '*' ) {
+ continue;
+ }
+
+ $wlEntry = substr( $line, 1 );
+ $wlEntry = trim( $wlEntry );
+
+ wfDebug( "Checking $ip against $wlEntry..." );
+
+ # Is the IP in this range?
+ if ( IP::isInRange( $ip, $wlEntry ) ) {
+ wfDebug( " IP $ip matches $wlEntry, not autoblocking\n" );
+ return true;
+ } else {
+ wfDebug( " No match\n" );
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Autoblocks the given IP, referring to this Block.
+ *
+ * @param $autoblockIP String: the IP to autoblock.
+ * @param $justInserted Boolean: the main block was just inserted
+ * @return Boolean: whether or not an autoblock was inserted.
+ */
+ public function doAutoblock( $autoblockIP, $justInserted = false ) {
+ # If autoblocks are disabled, go away.
+ if ( !$this->mEnableAutoblock ) {
+ return;
+ }
+
+ # Check for presence on the autoblock whitelist
+ if ( Block::isWhitelistedFromAutoblocks( $autoblockIP ) ) {
+ return;
+ }
+
+ # # Allow hooks to cancel the autoblock.
+ if ( !wfRunHooks( 'AbortAutoblock', array( $autoblockIP, &$this ) ) ) {
+ wfDebug( "Autoblock aborted by hook.\n" );
+ return false;
+ }
+
+ # It's okay to autoblock. Go ahead and create/insert the block.
+
+ $ipblock = Block::newFromDB( $autoblockIP );
+ if ( $ipblock ) {
+ # If the user is already blocked. Then check if the autoblock would
+ # exceed the user block. If it would exceed, then do nothing, else
+ # prolong block time
+ if ( $this->mExpiry &&
+ ( $this->mExpiry < Block::getAutoblockExpiry( $ipblock->mTimestamp ) )
+ ) {
+ return;
+ }
+
+ # Just update the timestamp
+ if ( !$justInserted ) {
+ $ipblock->updateTimestamp();
+ }
+
+ return;
+ } else {
+ $ipblock = new Block;
+ }
+
+ # Make a new block object with the desired properties
+ wfDebug( "Autoblocking {$this->mAddress}@" . $autoblockIP . "\n" );
+ $ipblock->mAddress = $autoblockIP;
+ $ipblock->mUser = 0;
+ $ipblock->mBy = $this->mBy;
+ $ipblock->mByName = $this->mByName;
+ $ipblock->mReason = wfMsgForContent( 'autoblocker', $this->mAddress, $this->mReason );
+ $ipblock->mTimestamp = wfTimestampNow();
+ $ipblock->mAuto = 1;
+ $ipblock->mCreateAccount = $this->mCreateAccount;
+ # Continue suppressing the name if needed
+ $ipblock->mHideName = $this->mHideName;
+ $ipblock->mAllowUsertalk = $this->mAllowUsertalk;
+
+ # If the user is already blocked with an expiry date, we don't
+ # want to pile on top of that!
+ if ( $this->mExpiry ) {
+ $ipblock->mExpiry = min( $this->mExpiry, Block::getAutoblockExpiry( $this->mTimestamp ) );
+ } else {
+ $ipblock->mExpiry = Block::getAutoblockExpiry( $this->mTimestamp );
+ }
+
+ # Insert it
+ return $ipblock->insert();
+ }
+
+ /**
+ * Check if a block has expired. Delete it if it is.
+ * @return Boolean
+ */
+ public function deleteIfExpired() {
+ wfProfileIn( __METHOD__ );
+