[ Index ]

PHP Cross Reference of MediaWiki-1.24.0

title

Body

[close]

/includes/specials/ -> SpecialBlock.php (source)

   1  <?php
   2  /**
   3   * Implements Special:Block
   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   * @ingroup SpecialPage
  22   */
  23  
  24  /**
  25   * A special page that allows users with 'block' right to block users from
  26   * editing pages and other actions
  27   *
  28   * @ingroup SpecialPage
  29   */
  30  class SpecialBlock extends FormSpecialPage {
  31      /** @var User User to be blocked, as passed either by parameter (url?wpTarget=Foo)
  32       * or as subpage (Special:Block/Foo) */
  33      protected $target;
  34  
  35      /** @var int Block::TYPE_ constant */
  36      protected $type;
  37  
  38      /** @var User|string The previous block target */
  39      protected $previousTarget;
  40  
  41      /** @var bool Whether the previous submission of the form asked for HideUser */
  42      protected $requestedHideUser;
  43  
  44      /** @var bool */
  45      protected $alreadyBlocked;
  46  
  47      /** @var array */
  48      protected $preErrors = array();
  49  
  50  	public function __construct() {
  51          parent::__construct( 'Block', 'block' );
  52      }
  53  
  54      /**
  55       * Checks that the user can unblock themselves if they are trying to do so
  56       *
  57       * @param User $user
  58       * @throws ErrorPageError
  59       */
  60  	protected function checkExecutePermissions( User $user ) {
  61          parent::checkExecutePermissions( $user );
  62  
  63          # bug 15810: blocked admins should have limited access here
  64          $status = self::checkUnblockSelf( $this->target, $user );
  65          if ( $status !== true ) {
  66              throw new ErrorPageError( 'badaccess', $status );
  67          }
  68      }
  69  
  70      /**
  71       * Handle some magic here
  72       *
  73       * @param string $par
  74       */
  75  	protected function setParameter( $par ) {
  76          # Extract variables from the request.  Try not to get into a situation where we
  77          # need to extract *every* variable from the form just for processing here, but
  78          # there are legitimate uses for some variables
  79          $request = $this->getRequest();
  80          list( $this->target, $this->type ) = self::getTargetAndType( $par, $request );
  81          if ( $this->target instanceof User ) {
  82              # Set the 'relevant user' in the skin, so it displays links like Contributions,
  83              # User logs, UserRights, etc.
  84              $this->getSkin()->setRelevantUser( $this->target );
  85          }
  86  
  87          list( $this->previousTarget, /*...*/ ) =
  88              Block::parseTarget( $request->getVal( 'wpPreviousTarget' ) );
  89          $this->requestedHideUser = $request->getBool( 'wpHideUser' );
  90      }
  91  
  92      /**
  93       * Customizes the HTMLForm a bit
  94       *
  95       * @param HTMLForm $form
  96       */
  97  	protected function alterForm( HTMLForm $form ) {
  98          $form->setWrapperLegendMsg( 'blockip-legend' );
  99          $form->setHeaderText( '' );
 100          $form->setSubmitCallback( array( __CLASS__, 'processUIForm' ) );
 101  
 102          $msg = $this->alreadyBlocked ? 'ipb-change-block' : 'ipbsubmit';
 103          $form->setSubmitTextMsg( $msg );
 104  
 105          # Don't need to do anything if the form has been posted
 106          if ( !$this->getRequest()->wasPosted() && $this->preErrors ) {
 107              $s = HTMLForm::formatErrors( $this->preErrors );
 108              if ( $s ) {
 109                  $form->addHeaderText( Html::rawElement(
 110                      'div',
 111                      array( 'class' => 'error' ),
 112                      $s
 113                  ) );
 114              }
 115          }
 116      }
 117  
 118      /**
 119       * Get the HTMLForm descriptor array for the block form
 120       * @return array
 121       */
 122  	protected function getFormFields() {
 123          global $wgBlockAllowsUTEdit;
 124  
 125          $user = $this->getUser();
 126  
 127          $suggestedDurations = self::getSuggestedDurations();
 128  
 129          $a = array(
 130              'Target' => array(
 131                  'type' => 'text',
 132                  'label-message' => 'ipaddressorusername',
 133                  'id' => 'mw-bi-target',
 134                  'size' => '45',
 135                  'autofocus' => true,
 136                  'required' => true,
 137                  'validation-callback' => array( __CLASS__, 'validateTargetField' ),
 138              ),
 139              'Expiry' => array(
 140                  'type' => !count( $suggestedDurations ) ? 'text' : 'selectorother',
 141                  'label-message' => 'ipbexpiry',
 142                  'required' => true,
 143                  'options' => $suggestedDurations,
 144                  'other' => $this->msg( 'ipbother' )->text(),
 145                  'default' => $this->msg( 'ipb-default-expiry' )->inContentLanguage()->text(),
 146              ),
 147              'Reason' => array(
 148                  'type' => 'selectandother',
 149                  'label-message' => 'ipbreason',
 150                  'options-message' => 'ipbreason-dropdown',
 151              ),
 152              'CreateAccount' => array(
 153                  'type' => 'check',
 154                  'label-message' => 'ipbcreateaccount',
 155                  'default' => true,
 156              ),
 157          );
 158  
 159          if ( self::canBlockEmail( $user ) ) {
 160              $a['DisableEmail'] = array(
 161                  'type' => 'check',
 162                  'label-message' => 'ipbemailban',
 163              );
 164          }
 165  
 166          if ( $wgBlockAllowsUTEdit ) {
 167              $a['DisableUTEdit'] = array(
 168                  'type' => 'check',
 169                  'label-message' => 'ipb-disableusertalk',
 170                  'default' => false,
 171              );
 172          }
 173  
 174          $a['AutoBlock'] = array(
 175              'type' => 'check',
 176              'label-message' => 'ipbenableautoblock',
 177              'default' => true,
 178          );
 179  
 180          # Allow some users to hide name from block log, blocklist and listusers
 181          if ( $user->isAllowed( 'hideuser' ) ) {
 182              $a['HideUser'] = array(
 183                  'type' => 'check',
 184                  'label-message' => 'ipbhidename',
 185                  'cssclass' => 'mw-block-hideuser',
 186              );
 187          }
 188  
 189          # Watchlist their user page? (Only if user is logged in)
 190          if ( $user->isLoggedIn() ) {
 191              $a['Watch'] = array(
 192                  'type' => 'check',
 193                  'label-message' => 'ipbwatchuser',
 194              );
 195          }
 196  
 197          $a['HardBlock'] = array(
 198              'type' => 'check',
 199              'label-message' => 'ipb-hardblock',
 200              'default' => false,
 201          );
 202  
 203          # This is basically a copy of the Target field, but the user can't change it, so we
 204          # can see if the warnings we maybe showed to the user before still apply
 205          $a['PreviousTarget'] = array(
 206              'type' => 'hidden',
 207              'default' => false,
 208          );
 209  
 210          # We'll turn this into a checkbox if we need to
 211          $a['Confirm'] = array(
 212              'type' => 'hidden',
 213              'default' => '',
 214              'label-message' => 'ipb-confirm',
 215          );
 216  
 217          $this->maybeAlterFormDefaults( $a );
 218  
 219          // Allow extensions to add more fields
 220          wfRunHooks( 'SpecialBlockModifyFormFields', array( $this, &$a ) );
 221  
 222          return $a;
 223      }
 224  
 225      /**
 226       * If the user has already been blocked with similar settings, load that block
 227       * and change the defaults for the form fields to match the existing settings.
 228       * @param array $fields HTMLForm descriptor array
 229       * @return bool Whether fields were altered (that is, whether the target is
 230       *     already blocked)
 231       */
 232  	protected function maybeAlterFormDefaults( &$fields ) {
 233          # This will be overwritten by request data
 234          $fields['Target']['default'] = (string)$this->target;
 235  
 236          # This won't be
 237          $fields['PreviousTarget']['default'] = (string)$this->target;
 238  
 239          $block = Block::newFromTarget( $this->target );
 240  
 241          if ( $block instanceof Block && !$block->mAuto # The block exists and isn't an autoblock
 242              && ( $this->type != Block::TYPE_RANGE # The block isn't a rangeblock
 243                  || $block->getTarget() == $this->target ) # or if it is, the range is what we're about to block
 244          ) {
 245              $fields['HardBlock']['default'] = $block->isHardblock();
 246              $fields['CreateAccount']['default'] = $block->prevents( 'createaccount' );
 247              $fields['AutoBlock']['default'] = $block->isAutoblocking();
 248  
 249              if ( isset( $fields['DisableEmail'] ) ) {
 250                  $fields['DisableEmail']['default'] = $block->prevents( 'sendemail' );
 251              }
 252  
 253              if ( isset( $fields['HideUser'] ) ) {
 254                  $fields['HideUser']['default'] = $block->mHideName;
 255              }
 256  
 257              if ( isset( $fields['DisableUTEdit'] ) ) {
 258                  $fields['DisableUTEdit']['default'] = $block->prevents( 'editownusertalk' );
 259              }
 260  
 261              // If the username was hidden (ipb_deleted == 1), don't show the reason
 262              // unless this user also has rights to hideuser: Bug 35839
 263              if ( !$block->mHideName || $this->getUser()->isAllowed( 'hideuser' ) ) {
 264                  $fields['Reason']['default'] = $block->mReason;
 265              } else {
 266                  $fields['Reason']['default'] = '';
 267              }
 268  
 269              if ( $this->getRequest()->wasPosted() ) {
 270                  # Ok, so we got a POST submission asking us to reblock a user.  So show the
 271                  # confirm checkbox; the user will only see it if they haven't previously
 272                  $fields['Confirm']['type'] = 'check';
 273              } else {
 274                  # We got a target, but it wasn't a POST request, so the user must have gone
 275                  # to a link like [[Special:Block/User]].  We don't need to show the checkbox
 276                  # as long as they go ahead and block *that* user
 277                  $fields['Confirm']['default'] = 1;
 278              }
 279  
 280              if ( $block->mExpiry == 'infinity' ) {
 281                  $fields['Expiry']['default'] = 'infinite';
 282              } else {
 283                  $fields['Expiry']['default'] = wfTimestamp( TS_RFC2822, $block->mExpiry );
 284              }
 285  
 286              $this->alreadyBlocked = true;
 287              $this->preErrors[] = array( 'ipb-needreblock', wfEscapeWikiText( (string)$block->getTarget() ) );
 288          }
 289  
 290          # We always need confirmation to do HideUser
 291          if ( $this->requestedHideUser ) {
 292              $fields['Confirm']['type'] = 'check';
 293              unset( $fields['Confirm']['default'] );
 294              $this->preErrors[] = array( 'ipb-confirmhideuser', 'ipb-confirmaction' );
 295          }
 296  
 297          # Or if the user is trying to block themselves
 298          if ( (string)$this->target === $this->getUser()->getName() ) {
 299              $fields['Confirm']['type'] = 'check';
 300              unset( $fields['Confirm']['default'] );
 301              $this->preErrors[] = array( 'ipb-blockingself', 'ipb-confirmaction' );
 302          }
 303      }
 304  
 305      /**
 306       * Add header elements like block log entries, etc.
 307       * @return string
 308       */
 309  	protected function preText() {
 310          $this->getOutput()->addModules( 'mediawiki.special.block' );
 311  
 312          $text = $this->msg( 'blockiptext' )->parse();
 313  
 314          $otherBlockMessages = array();
 315          if ( $this->target !== null ) {
 316              # Get other blocks, i.e. from GlobalBlocking or TorBlock extension
 317              wfRunHooks( 'OtherBlockLogLink', array( &$otherBlockMessages, $this->target ) );
 318  
 319              if ( count( $otherBlockMessages ) ) {
 320                  $s = Html::rawElement(
 321                      'h2',
 322                      array(),
 323                      $this->msg( 'ipb-otherblocks-header', count( $otherBlockMessages ) )->parse()
 324                  ) . "\n";
 325  
 326                  $list = '';
 327  
 328                  foreach ( $otherBlockMessages as $link ) {
 329                      $list .= Html::rawElement( 'li', array(), $link ) . "\n";
 330                  }
 331  
 332                  $s .= Html::rawElement(
 333                      'ul',
 334                      array( 'class' => 'mw-blockip-alreadyblocked' ),
 335                      $list
 336                  ) . "\n";
 337  
 338                  $text .= $s;
 339              }
 340          }
 341  
 342          return $text;
 343      }
 344  
 345      /**
 346       * Add footer elements to the form
 347       * @return string
 348       */
 349  	protected function postText() {
 350          $links = array();
 351  
 352          # Link to the user's contributions, if applicable
 353          if ( $this->target instanceof User ) {
 354              $contribsPage = SpecialPage::getTitleFor( 'Contributions', $this->target->getName() );
 355              $links[] = Linker::link(
 356                  $contribsPage,
 357                  $this->msg( 'ipb-blocklist-contribs', $this->target->getName() )->escaped()
 358              );
 359          }
 360  
 361          # Link to unblock the specified user, or to a blank unblock form
 362          if ( $this->target instanceof User ) {
 363              $message = $this->msg(
 364                  'ipb-unblock-addr',
 365                  wfEscapeWikiText( $this->target->getName() )
 366              )->parse();
 367              $list = SpecialPage::getTitleFor( 'Unblock', $this->target->getName() );
 368          } else {
 369              $message = $this->msg( 'ipb-unblock' )->parse();
 370              $list = SpecialPage::getTitleFor( 'Unblock' );
 371          }
 372          $links[] = Linker::linkKnown( $list, $message, array() );
 373  
 374          # Link to the block list
 375          $links[] = Linker::linkKnown(
 376              SpecialPage::getTitleFor( 'BlockList' ),
 377              $this->msg( 'ipb-blocklist' )->escaped()
 378          );
 379  
 380          $user = $this->getUser();
 381  
 382          # Link to edit the block dropdown reasons, if applicable
 383          if ( $user->isAllowed( 'editinterface' ) ) {
 384              $links[] = Linker::link(
 385                  Title::makeTitle( NS_MEDIAWIKI, 'Ipbreason-dropdown' ),
 386                  $this->msg( 'ipb-edit-dropdown' )->escaped(),
 387                  array(),
 388                  array( 'action' => 'edit' )
 389              );
 390          }
 391  
 392          $text = Html::rawElement(
 393              'p',
 394              array( 'class' => 'mw-ipb-conveniencelinks' ),
 395              $this->getLanguage()->pipeList( $links )
 396          );
 397  
 398          $userTitle = self::getTargetUserTitle( $this->target );
 399          if ( $userTitle ) {
 400              # Get relevant extracts from the block and suppression logs, if possible
 401              $out = '';
 402  
 403              LogEventsList::showLogExtract(
 404                  $out,
 405                  'block',
 406                  $userTitle,
 407                  '',
 408                  array(
 409                      'lim' => 10,
 410                      'msgKey' => array( 'blocklog-showlog', $userTitle->getText() ),
 411                      'showIfEmpty' => false
 412                  )
 413              );
 414              $text .= $out;
 415  
 416              # Add suppression block entries if allowed
 417              if ( $user->isAllowed( 'suppressionlog' ) ) {
 418                  LogEventsList::showLogExtract(
 419                      $out,
 420                      'suppress',
 421                      $userTitle,
 422                      '',
 423                      array(
 424                          'lim' => 10,
 425                          'conds' => array( 'log_action' => array( 'block', 'reblock', 'unblock' ) ),
 426                          'msgKey' => array( 'blocklog-showsuppresslog', $userTitle->getText() ),
 427                          'showIfEmpty' => false
 428                      )
 429                  );
 430  
 431                  $text .= $out;
 432              }
 433          }
 434  
 435          return $text;
 436      }
 437  
 438      /**
 439       * Get a user page target for things like logs.
 440       * This handles account and IP range targets.
 441       * @param User|string $target
 442       * @return Title|null
 443       */
 444  	protected static function getTargetUserTitle( $target ) {
 445          if ( $target instanceof User ) {
 446              return $target->getUserPage();
 447          } elseif ( IP::isIPAddress( $target ) ) {
 448              return Title::makeTitleSafe( NS_USER, $target );
 449          }
 450  
 451          return null;
 452      }
 453  
 454      /**
 455       * Determine the target of the block, and the type of target
 456       * @todo Should be in Block.php?
 457       * @param string $par Subpage parameter passed to setup, or data value from
 458       *     the HTMLForm
 459       * @param WebRequest $request Optionally try and get data from a request too
 460       * @return array( User|string|null, Block::TYPE_ constant|null )
 461       */
 462  	public static function getTargetAndType( $par, WebRequest $request = null ) {
 463          $i = 0;
 464          $target = null;
 465  
 466          while ( true ) {
 467              switch ( $i++ ) {
 468                  case 0:
 469                      # The HTMLForm will check wpTarget first and only if it doesn't get
 470                      # a value use the default, which will be generated from the options
 471                      # below; so this has to have a higher precedence here than $par, or
 472                      # we could end up with different values in $this->target and the HTMLForm!
 473                      if ( $request instanceof WebRequest ) {
 474                          $target = $request->getText( 'wpTarget', null );
 475                      }
 476                      break;
 477                  case 1:
 478                      $target = $par;
 479                      break;
 480                  case 2:
 481                      if ( $request instanceof WebRequest ) {
 482                          $target = $request->getText( 'ip', null );
 483                      }
 484                      break;
 485                  case 3:
 486                      # B/C @since 1.18
 487                      if ( $request instanceof WebRequest ) {
 488                          $target = $request->getText( 'wpBlockAddress', null );
 489                      }
 490                      break;
 491                  case 4:
 492                      break 2;
 493              }
 494  
 495              list( $target, $type ) = Block::parseTarget( $target );
 496  
 497              if ( $type !== null ) {
 498                  return array( $target, $type );
 499              }
 500          }
 501  
 502          return array( null, null );
 503      }
 504  
 505      /**
 506       * HTMLForm field validation-callback for Target field.
 507       * @since 1.18
 508       * @param string $value
 509       * @param array $alldata
 510       * @param HTMLForm $form
 511       * @return Message
 512       */
 513  	public static function validateTargetField( $value, $alldata, $form ) {
 514          $status = self::validateTarget( $value, $form->getUser() );
 515          if ( !$status->isOK() ) {
 516              $errors = $status->getErrorsArray();
 517  
 518              return call_user_func_array( array( $form, 'msg' ), $errors[0] );
 519          } else {
 520              return true;
 521          }
 522      }
 523  
 524      /**
 525       * Validate a block target.
 526       *
 527       * @since 1.21
 528       * @param string $value Block target to check
 529       * @param User $user Performer of the block
 530       * @return Status
 531       */
 532  	public static function validateTarget( $value, User $user ) {
 533          global $wgBlockCIDRLimit;
 534  
 535          /** @var User $target */
 536          list( $target, $type ) = self::getTargetAndType( $value );
 537          $status = Status::newGood( $target );
 538  
 539          if ( $type == Block::TYPE_USER ) {
 540              if ( $target->isAnon() ) {
 541                  $status->fatal(
 542                      'nosuchusershort',
 543                      wfEscapeWikiText( $target->getName() )
 544                  );
 545              }
 546  
 547              $unblockStatus = self::checkUnblockSelf( $target, $user );
 548              if ( $unblockStatus !== true ) {
 549                  $status->fatal( 'badaccess', $unblockStatus );
 550              }
 551          } elseif ( $type == Block::TYPE_RANGE ) {
 552              list( $ip, $range ) = explode( '/', $target, 2 );
 553  
 554              if (
 555                  ( IP::isIPv4( $ip ) && $wgBlockCIDRLimit['IPv4'] == 32 ) ||
 556                  ( IP::isIPv6( $ip ) && $wgBlockCIDRLimit['IPv6'] == 128 )
 557              ) {
 558                  // Range block effectively disabled
 559                  $status->fatal( 'range_block_disabled' );
 560              }
 561  
 562              if (
 563                  ( IP::isIPv4( $ip ) && $range > 32 ) ||
 564                  ( IP::isIPv6( $ip ) && $range > 128 )
 565              ) {
 566                  // Dodgy range
 567                  $status->fatal( 'ip_range_invalid' );
 568              }
 569  
 570              if ( IP::isIPv4( $ip ) && $range < $wgBlockCIDRLimit['IPv4'] ) {
 571                  $status->fatal( 'ip_range_toolarge', $wgBlockCIDRLimit['IPv4'] );
 572              }
 573  
 574              if ( IP::isIPv6( $ip ) && $range < $wgBlockCIDRLimit['IPv6'] ) {
 575                  $status->fatal( 'ip_range_toolarge', $wgBlockCIDRLimit['IPv6'] );
 576              }
 577          } elseif ( $type == Block::TYPE_IP ) {
 578              # All is well
 579          } else {
 580              $status->fatal( 'badipaddress' );
 581          }
 582  
 583          return $status;
 584      }
 585  
 586      /**
 587       * Submit callback for an HTMLForm object, will simply pass
 588       * @param array $data
 589       * @param HTMLForm $form
 590       * @return bool|string
 591       */
 592  	public static function processUIForm( array $data, HTMLForm $form ) {
 593          return self::processForm( $data, $form->getContext() );
 594      }
 595  
 596      /**
 597       * Given the form data, actually implement a block
 598       * @param array $data
 599       * @param IContextSource $context
 600       * @return bool|string
 601       */
 602  	public static function processForm( array $data, IContextSource $context ) {
 603          global $wgBlockAllowsUTEdit, $wgHideUserContribLimit, $wgContLang;
 604  
 605          $performer = $context->getUser();
 606  
 607          // Handled by field validator callback
 608          // self::validateTargetField( $data['Target'] );
 609  
 610          # This might have been a hidden field or a checkbox, so interesting data
 611          # can come from it
 612          $data['Confirm'] = !in_array( $data['Confirm'], array( '', '0', null, false ), true );
 613  
 614          /** @var User $target */
 615          list( $target, $type ) = self::getTargetAndType( $data['Target'] );
 616          if ( $type == Block::TYPE_USER ) {
 617              $user = $target;
 618              $target = $user->getName();
 619              $userId = $user->getId();
 620  
 621              # Give admins a heads-up before they go and block themselves.  Much messier
 622              # to do this for IPs, but it's pretty unlikely they'd ever get the 'block'
 623              # permission anyway, although the code does allow for it.
 624              # Note: Important to use $target instead of $data['Target']
 625              # since both $data['PreviousTarget'] and $target are normalized
 626              # but $data['target'] gets overriden by (non-normalized) request variable
 627              # from previous request.
 628              if ( $target === $performer->getName() &&
 629                  ( $data['PreviousTarget'] !== $target || !$data['Confirm'] )
 630              ) {
 631                  return array( 'ipb-blockingself', 'ipb-confirmaction' );
 632              }
 633          } elseif ( $type == Block::TYPE_RANGE ) {
 634              $userId = 0;
 635          } elseif ( $type == Block::TYPE_IP ) {
 636              $target = $target->getName();
 637              $userId = 0;
 638          } else {
 639              # This should have been caught in the form field validation
 640              return array( 'badipaddress' );
 641          }
 642  
 643          if ( ( strlen( $data['Expiry'] ) == 0 ) || ( strlen( $data['Expiry'] ) > 50 )
 644              || !self::parseExpiryInput( $data['Expiry'] )
 645          ) {
 646              return array( 'ipb_expiry_invalid' );
 647          }
 648  
 649          if ( !isset( $data['DisableEmail'] ) ) {
 650              $data['DisableEmail'] = false;
 651          }
 652  
 653          # If the user has done the form 'properly', they won't even have been given the
 654          # option to suppress-block unless they have the 'hideuser' permission
 655          if ( !isset( $data['HideUser'] ) ) {
 656              $data['HideUser'] = false;
 657          }
 658  
 659          if ( $data['HideUser'] ) {
 660              if ( !$performer->isAllowed( 'hideuser' ) ) {
 661                  # this codepath is unreachable except by a malicious user spoofing forms,
 662                  # or by race conditions (user has oversight and sysop, loads block form,
 663                  # and is de-oversighted before submission); so need to fail completely
 664                  # rather than just silently disable hiding
 665                  return array( 'badaccess-group0' );
 666              }
 667  
 668              # Recheck params here...
 669              if ( $type != Block::TYPE_USER ) {
 670                  $data['HideUser'] = false; # IP users should not be hidden
 671              } elseif ( !in_array( $data['Expiry'], array( 'infinite', 'infinity', 'indefinite' ) ) ) {
 672                  # Bad expiry.
 673                  return array( 'ipb_expiry_temp' );
 674              } elseif ( $wgHideUserContribLimit !== false
 675                  && $user->getEditCount() > $wgHideUserContribLimit
 676              ) {
 677                  # Typically, the user should have a handful of edits.
 678                  # Disallow hiding users with many edits for performance.
 679                  return array( array( 'ipb_hide_invalid',
 680                      Message::numParam( $wgHideUserContribLimit ) ) );
 681              } elseif ( !$data['Confirm'] ) {
 682                  return array( 'ipb-confirmhideuser', 'ipb-confirmaction' );
 683              }
 684          }
 685  
 686          # Create block object.
 687          $block = new Block();
 688          $block->setTarget( $target );
 689          $block->setBlocker( $performer );
 690          # Truncate reason for whole multibyte characters
 691          $block->mReason = $wgContLang->truncate( $data['Reason'][0], 255 );
 692          $block->mExpiry = self::parseExpiryInput( $data['Expiry'] );
 693          $block->prevents( 'createaccount', $data['CreateAccount'] );
 694          $block->prevents( 'editownusertalk', ( !$wgBlockAllowsUTEdit || $data['DisableUTEdit'] ) );
 695          $block->prevents( 'sendemail', $data['DisableEmail'] );
 696          $block->isHardblock( $data['HardBlock'] );
 697          $block->isAutoblocking( $data['AutoBlock'] );
 698          $block->mHideName = $data['HideUser'];
 699  
 700          $reason = array( 'hookaborted' );
 701          if ( !wfRunHooks( 'BlockIp', array( &$block, &$performer, &$reason ) ) ) {
 702              return $reason;
 703          }
 704  
 705          # Try to insert block. Is there a conflicting block?
 706          $status = $block->insert();
 707          if ( !$status ) {
 708              # Indicates whether the user is confirming the block and is aware of
 709              # the conflict (did not change the block target in the meantime)
 710              $blockNotConfirmed = !$data['Confirm'] || ( array_key_exists( 'PreviousTarget', $data )
 711                  && $data['PreviousTarget'] !== $target );
 712  
 713              # Special case for API - bug 32434
 714              $reblockNotAllowed = ( array_key_exists( 'Reblock', $data ) && !$data['Reblock'] );
 715  
 716              # Show form unless the user is already aware of this...
 717              if ( $blockNotConfirmed || $reblockNotAllowed ) {
 718                  return array( array( 'ipb_already_blocked', $block->getTarget() ) );
 719                  # Otherwise, try to update the block...
 720              } else {
 721                  # This returns direct blocks before autoblocks/rangeblocks, since we should
 722                  # be sure the user is blocked by now it should work for our purposes
 723                  $currentBlock = Block::newFromTarget( $target );
 724  
 725                  if ( $block->equals( $currentBlock ) ) {
 726                      return array( array( 'ipb_already_blocked', $block->getTarget() ) );
 727                  }
 728  
 729                  # If the name was hidden and the blocking user cannot hide
 730                  # names, then don't allow any block changes...
 731                  if ( $currentBlock->mHideName && !$performer->isAllowed( 'hideuser' ) ) {
 732                      return array( 'cant-see-hidden-user' );
 733                  }
 734  
 735                  $currentBlock->isHardblock( $block->isHardblock() );
 736                  $currentBlock->prevents( 'createaccount', $block->prevents( 'createaccount' ) );
 737                  $currentBlock->mExpiry = $block->mExpiry;
 738                  $currentBlock->isAutoblocking( $block->isAutoblocking() );
 739                  $currentBlock->mHideName = $block->mHideName;
 740                  $currentBlock->prevents( 'sendemail', $block->prevents( 'sendemail' ) );
 741                  $currentBlock->prevents( 'editownusertalk', $block->prevents( 'editownusertalk' ) );
 742                  $currentBlock->mReason = $block->mReason;
 743  
 744                  $status = $currentBlock->update();
 745  
 746                  $logaction = 'reblock';
 747  
 748                  # Unset _deleted fields if requested
 749                  if ( $currentBlock->mHideName && !$data['HideUser'] ) {
 750                      RevisionDeleteUser::unsuppressUserName( $target, $userId );
 751                  }
 752  
 753                  # If hiding/unhiding a name, this should go in the private logs
 754                  if ( (bool)$currentBlock->mHideName ) {
 755                      $data['HideUser'] = true;
 756                  }
 757              }
 758          } else {
 759              $logaction = 'block';
 760          }
 761  
 762          wfRunHooks( 'BlockIpComplete', array( $block, $performer ) );
 763  
 764          # Set *_deleted fields if requested
 765          if ( $data['HideUser'] ) {
 766              RevisionDeleteUser::suppressUserName( $target, $userId );
 767          }
 768  
 769          # Can't watch a rangeblock
 770          if ( $type != Block::TYPE_RANGE && $data['Watch'] ) {
 771              WatchAction::doWatch(
 772                  Title::makeTitle( NS_USER, $target ),
 773                  $performer,
 774                  WatchedItem::IGNORE_USER_RIGHTS
 775              );
 776          }
 777  
 778          # Block constructor sanitizes certain block options on insert
 779          $data['BlockEmail'] = $block->prevents( 'sendemail' );
 780          $data['AutoBlock'] = $block->isAutoblocking();
 781  
 782          # Prepare log parameters
 783          $logParams = array();
 784          $logParams[] = $data['Expiry'];
 785          $logParams[] = self::blockLogFlags( $data, $type );
 786  
 787          # Make log entry, if the name is hidden, put it in the oversight log
 788          $log_type = $data['HideUser'] ? 'suppress' : 'block';
 789          $log = new LogPage( $log_type );
 790          $log_id = $log->addEntry(
 791              $logaction,
 792              Title::makeTitle( NS_USER, $target ),
 793              $data['Reason'][0],
 794              $logParams,
 795              $performer
 796          );
 797          # Relate log ID to block IDs (bug 25763)
 798          $blockIds = array_merge( array( $status['id'] ), $status['autoIds'] );
 799          $log->addRelations( 'ipb_id', $blockIds, $log_id );
 800  
 801          # Report to the user
 802          return true;
 803      }
 804  
 805      /**
 806       * Get an array of suggested block durations from MediaWiki:Ipboptions
 807       * @todo FIXME: This uses a rather odd syntax for the options, should it be converted
 808       *     to the standard "**<duration>|<displayname>" format?
 809       * @param Language|null $lang The language to get the durations in, or null to use
 810       *     the wiki's content language
 811       * @return array
 812       */
 813  	public static function getSuggestedDurations( $lang = null ) {
 814          $a = array();
 815          $msg = $lang === null
 816              ? wfMessage( 'ipboptions' )->inContentLanguage()->text()
 817              : wfMessage( 'ipboptions' )->inLanguage( $lang )->text();
 818  
 819          if ( $msg == '-' ) {
 820              return array();
 821          }
 822  
 823          foreach ( explode( ',', $msg ) as $option ) {
 824              if ( strpos( $option, ':' ) === false ) {
 825                  $option = "$option:$option";
 826              }
 827  
 828              list( $show, $value ) = explode( ':', $option );
 829              $a[htmlspecialchars( $show )] = htmlspecialchars( $value );
 830          }
 831  
 832          return $a;
 833      }
 834  
 835      /**
 836       * Convert a submitted expiry time, which may be relative ("2 weeks", etc) or absolute
 837       * ("24 May 2034", etc), into an absolute timestamp we can put into the database.
 838       * @param string $expiry Whatever was typed into the form
 839       * @return string Timestamp or "infinity" string for the DB implementation
 840       */
 841  	public static function parseExpiryInput( $expiry ) {
 842          static $infinity;
 843          if ( $infinity == null ) {
 844              $infinity = wfGetDB( DB_SLAVE )->getInfinity();
 845          }
 846  
 847          if ( $expiry == 'infinite' || $expiry == 'indefinite' ) {
 848              $expiry = $infinity;
 849          } else {
 850              $expiry = strtotime( $expiry );
 851  
 852              if ( $expiry < 0 || $expiry === false ) {
 853                  return false;
 854              }
 855  
 856              $expiry = wfTimestamp( TS_MW, $expiry );
 857          }
 858  
 859          return $expiry;
 860      }
 861  
 862      /**
 863       * Can we do an email block?
 864       * @param User $user The sysop wanting to make a block
 865       * @return bool
 866       */
 867  	public static function canBlockEmail( $user ) {
 868          global $wgEnableUserEmail, $wgSysopEmailBans;
 869  
 870          return ( $wgEnableUserEmail && $wgSysopEmailBans && $user->isAllowed( 'blockemail' ) );
 871      }
 872  
 873      /**
 874       * bug 15810: blocked admins should not be able to block/unblock
 875       * others, and probably shouldn't be able to unblock themselves
 876       * either.
 877       * @param User|int|string $user
 878       * @param User $performer User doing the request
 879       * @return bool|string True or error message key
 880       */
 881  	public static function checkUnblockSelf( $user, User $performer ) {
 882          if ( is_int( $user ) ) {
 883              $user = User::newFromId( $user );
 884          } elseif ( is_string( $user ) ) {
 885              $user = User::newFromName( $user );
 886          }
 887  
 888          if ( $performer->isBlocked() ) {
 889              if ( $user instanceof User && $user->getId() == $performer->getId() ) {
 890                  # User is trying to unblock themselves
 891                  if ( $performer->isAllowed( 'unblockself' ) ) {
 892                      return true;
 893                      # User blocked themselves and is now trying to reverse it
 894                  } elseif ( $performer->blockedBy() === $performer->getName() ) {
 895                      return true;
 896                  } else {
 897                      return 'ipbnounblockself';
 898                  }
 899              } else {
 900                  # User is trying to block/unblock someone else
 901                  return 'ipbblocked';
 902              }
 903          } else {
 904              return true;
 905          }
 906      }
 907  
 908      /**
 909       * Return a comma-delimited list of "flags" to be passed to the log
 910       * reader for this block, to provide more information in the logs
 911       * @param array $data From HTMLForm data
 912       * @param int $type Block::TYPE_ constant (USER, RANGE, or IP)
 913       * @return string
 914       */
 915  	protected static function blockLogFlags( array $data, $type ) {
 916          global $wgBlockAllowsUTEdit;
 917          $flags = array();
 918  
 919          # when blocking a user the option 'anononly' is not available/has no effect
 920          # -> do not write this into log
 921          if ( !$data['HardBlock'] && $type != Block::TYPE_USER ) {
 922              // For grepping: message block-log-flags-anononly
 923              $flags[] = 'anononly';
 924          }
 925  
 926          if ( $data['CreateAccount'] ) {
 927              // For grepping: message block-log-flags-nocreate
 928              $flags[] = 'nocreate';
 929          }
 930  
 931          # Same as anononly, this is not displayed when blocking an IP address
 932          if ( !$data['AutoBlock'] && $type == Block::TYPE_USER ) {
 933              // For grepping: message block-log-flags-noautoblock
 934              $flags[] = 'noautoblock';
 935          }
 936  
 937          if ( $data['DisableEmail'] ) {
 938              // For grepping: message block-log-flags-noemail
 939              $flags[] = 'noemail';
 940          }
 941  
 942          if ( $wgBlockAllowsUTEdit && $data['DisableUTEdit'] ) {
 943              // For grepping: message block-log-flags-nousertalk
 944              $flags[] = 'nousertalk';
 945          }
 946  
 947          if ( $data['HideUser'] ) {
 948              // For grepping: message block-log-flags-hiddenname
 949              $flags[] = 'hiddenname';
 950          }
 951  
 952          return implode( ',', $flags );
 953      }
 954  
 955      /**
 956       * Process the form on POST submission.
 957       * @param array $data
 958       * @return bool|array True for success, false for didn't-try, array of errors on failure
 959       */
 960  	public function onSubmit( array $data ) {
 961          // This isn't used since we need that HTMLForm that's passed in the
 962          // second parameter. See alterForm for the real function
 963      }
 964  
 965      /**
 966       * Do something exciting on successful processing of the form, most likely to show a
 967       * confirmation message
 968       */
 969  	public function onSuccess() {
 970          $out = $this->getOutput();
 971          $out->setPageTitle( $this->msg( 'blockipsuccesssub' ) );
 972          $out->addWikiMsg( 'blockipsuccesstext', wfEscapeWikiText( $this->target ) );
 973      }
 974  
 975  	protected function getGroupName() {
 976          return 'users';
 977      }
 978  }


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