[ Index ]

PHP Cross Reference of MediaWiki-1.24.0

title

Body

[close]

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

   1  <?php
   2  /**
   3   * Implements Special:Import
   4   *
   5   * Copyright © 2003,2005 Brion Vibber <[email protected]>
   6   * https://www.mediawiki.org/
   7   *
   8   * This program is free software; you can redistribute it and/or modify
   9   * it under the terms of the GNU General Public License as published by
  10   * the Free Software Foundation; either version 2 of the License, or
  11   * (at your option) any later version.
  12   *
  13   * This program is distributed in the hope that it will be useful,
  14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16   * GNU General Public License for more details.
  17   *
  18   * You should have received a copy of the GNU General Public License along
  19   * with this program; if not, write to the Free Software Foundation, Inc.,
  20   * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  21   * http://www.gnu.org/copyleft/gpl.html
  22   *
  23   * @file
  24   * @ingroup SpecialPage
  25   */
  26  
  27  /**
  28   * MediaWiki page data importer
  29   *
  30   * @ingroup SpecialPage
  31   */
  32  class SpecialImport extends SpecialPage {
  33      private $interwiki = false;
  34      private $subproject;
  35      private $fullInterwikiPrefix;
  36      private $namespace;
  37      private $rootpage = '';
  38      private $frompage = '';
  39      private $logcomment = false;
  40      private $history = true;
  41      private $includeTemplates = false;
  42      private $pageLinkDepth;
  43  
  44      /**
  45       * Constructor
  46       */
  47  	public function __construct() {
  48          parent::__construct( 'Import', 'import' );
  49          $this->namespace = $this->getConfig()->get( 'ImportTargetNamespace' );
  50      }
  51  
  52      /**
  53       * Execute
  54       * @param string|null $par
  55       */
  56  	function execute( $par ) {
  57          $this->setHeaders();
  58          $this->outputHeader();
  59  
  60          $this->getOutput()->addModules( 'mediawiki.special.import' );
  61  
  62          $user = $this->getUser();
  63          if ( !$user->isAllowedAny( 'import', 'importupload' ) ) {
  64              throw new PermissionsError( 'import' );
  65          }
  66  
  67          # @todo Allow Title::getUserPermissionsErrors() to take an array
  68          # @todo FIXME: Title::checkSpecialsAndNSPermissions() has a very wierd expectation of what
  69          # getUserPermissionsErrors() might actually be used for, hence the 'ns-specialprotected'
  70          $errors = wfMergeErrorArrays(
  71              $this->getPageTitle()->getUserPermissionsErrors(
  72                  'import', $user, true,
  73                  array( 'ns-specialprotected', 'badaccess-group0', 'badaccess-groups' )
  74              ),
  75              $this->getPageTitle()->getUserPermissionsErrors(
  76                  'importupload', $user, true,
  77                  array( 'ns-specialprotected', 'badaccess-group0', 'badaccess-groups' )
  78              )
  79          );
  80  
  81          if ( $errors ) {
  82              throw new PermissionsError( 'import', $errors );
  83          }
  84  
  85          $this->checkReadOnly();
  86  
  87          $request = $this->getRequest();
  88          if ( $request->wasPosted() && $request->getVal( 'action' ) == 'submit' ) {
  89              $this->doImport();
  90          }
  91          $this->showForm();
  92      }
  93  
  94      /**
  95       * Do the actual import
  96       */
  97  	private function doImport() {
  98          $isUpload = false;
  99          $request = $this->getRequest();
 100          $this->namespace = $request->getIntOrNull( 'namespace' );
 101          $sourceName = $request->getVal( "source" );
 102  
 103          $this->logcomment = $request->getText( 'log-comment' );
 104          $this->pageLinkDepth = $this->getConfig()->get( 'ExportMaxLinkDepth' ) == 0
 105              ? 0
 106              : $request->getIntOrNull( 'pagelink-depth' );
 107          $this->rootpage = $request->getText( 'rootpage' );
 108  
 109          $user = $this->getUser();
 110          if ( !$user->matchEditToken( $request->getVal( 'editToken' ) ) ) {
 111              $source = Status::newFatal( 'import-token-mismatch' );
 112          } elseif ( $sourceName == 'upload' ) {
 113              $isUpload = true;
 114              if ( $user->isAllowed( 'importupload' ) ) {
 115                  $source = ImportStreamSource::newFromUpload( "xmlimport" );
 116              } else {
 117                  throw new PermissionsError( 'importupload' );
 118              }
 119          } elseif ( $sourceName == "interwiki" ) {
 120              if ( !$user->isAllowed( 'import' ) ) {
 121                  throw new PermissionsError( 'import' );
 122              }
 123              $this->interwiki = $this->fullInterwikiPrefix = $request->getVal( 'interwiki' );
 124              // does this interwiki have subprojects?
 125              $importSources = $this->getConfig()->get( 'ImportSources' );
 126              $hasSubprojects = array_key_exists( $this->interwiki, $importSources );
 127              if ( !$hasSubprojects && !in_array( $this->interwiki, $importSources ) ) {
 128                  $source = Status::newFatal( "import-invalid-interwiki" );
 129              } else {
 130                  if ( $hasSubprojects ) {
 131                      $this->subproject = $request->getVal( 'subproject' );
 132                      $this->fullInterwikiPrefix .= ':' . $request->getVal( 'subproject' );
 133                  }
 134                  if ( $hasSubprojects && !in_array( $this->subproject, $importSources[$this->interwiki] ) ) {
 135                      $source = Status::newFatal( "import-invalid-interwiki" );
 136                  } else {
 137                      $this->history = $request->getCheck( 'interwikiHistory' );
 138                      $this->frompage = $request->getText( "frompage" );
 139                      $this->includeTemplates = $request->getCheck( 'interwikiTemplates' );
 140                      $source = ImportStreamSource::newFromInterwiki(
 141                          $this->fullInterwikiPrefix,
 142                          $this->frompage,
 143                          $this->history,
 144                          $this->includeTemplates,
 145                          $this->pageLinkDepth );
 146                  }
 147              }
 148          } else {
 149              $source = Status::newFatal( "importunknownsource" );
 150          }
 151  
 152          $out = $this->getOutput();
 153          if ( !$source->isGood() ) {
 154              $out->wrapWikiMsg(
 155                  "<p class=\"error\">\n$1\n</p>",
 156                  array( 'importfailed', $source->getWikiText() )
 157              );
 158          } else {
 159              $importer = new WikiImporter( $source->value );
 160              if ( !is_null( $this->namespace ) ) {
 161                  $importer->setTargetNamespace( $this->namespace );
 162              }
 163              if ( !is_null( $this->rootpage ) ) {
 164                  $statusRootPage = $importer->setTargetRootPage( $this->rootpage );
 165                  if ( !$statusRootPage->isGood() ) {
 166                      $out->wrapWikiMsg(
 167                          "<p class=\"error\">\n$1\n</p>",
 168                          array(
 169                              'import-options-wrong',
 170                              $statusRootPage->getWikiText(),
 171                              count( $statusRootPage->getErrorsArray() )
 172                          )
 173                      );
 174  
 175                      return;
 176                  }
 177              }
 178  
 179              $out->addWikiMsg( "importstart" );
 180  
 181              $reporter = new ImportReporter(
 182                  $importer,
 183                  $isUpload,
 184                  $this->fullInterwikiPrefix,
 185                  $this->logcomment
 186              );
 187              $reporter->setContext( $this->getContext() );
 188              $exception = false;
 189  
 190              $reporter->open();
 191              try {
 192                  $importer->doImport();
 193              } catch ( MWException $e ) {
 194                  $exception = $e;
 195              }
 196              $result = $reporter->close();
 197  
 198              if ( $exception ) {
 199                  # No source or XML parse error
 200                  $out->wrapWikiMsg(
 201                      "<p class=\"error\">\n$1\n</p>",
 202                      array( 'importfailed', $exception->getMessage() )
 203                  );
 204              } elseif ( !$result->isGood() ) {
 205                  # Zero revisions
 206                  $out->wrapWikiMsg(
 207                      "<p class=\"error\">\n$1\n</p>",
 208                      array( 'importfailed', $result->getWikiText() )
 209                  );
 210              } else {
 211                  # Success!
 212                  $out->addWikiMsg( 'importsuccess' );
 213              }
 214              $out->addHTML( '<hr />' );
 215          }
 216      }
 217  
 218  	private function showForm() {
 219          $action = $this->getPageTitle()->getLocalURL( array( 'action' => 'submit' ) );
 220          $user = $this->getUser();
 221          $out = $this->getOutput();
 222          $importSources = $this->getConfig()->get( 'ImportSources' );
 223  
 224          if ( $user->isAllowed( 'importupload' ) ) {
 225              $out->addHTML(
 226                  Xml::fieldset( $this->msg( 'import-upload' )->text() ) .
 227                      Xml::openElement(
 228                          'form',
 229                          array(
 230                              'enctype' => 'multipart/form-data',
 231                              'method' => 'post',
 232                              'action' => $action,
 233                              'id' => 'mw-import-upload-form'
 234                          )
 235                      ) .
 236                      $this->msg( 'importtext' )->parseAsBlock() .
 237                      Html::hidden( 'action', 'submit' ) .
 238                      Html::hidden( 'source', 'upload' ) .
 239                      Xml::openElement( 'table', array( 'id' => 'mw-import-table-upload' ) ) .
 240                      "<tr>
 241                      <td class='mw-label'>" .
 242                      Xml::label( $this->msg( 'import-upload-filename' )->text(), 'xmlimport' ) .
 243                      "</td>
 244                      <td class='mw-input'>" .
 245                      Html::input( 'xmlimport', '', 'file', array( 'id' => 'xmlimport' ) ) . ' ' .
 246                      "</td>
 247                  </tr>
 248                  <tr>
 249                      <td class='mw-label'>" .
 250                      Xml::label( $this->msg( 'import-comment' )->text(), 'mw-import-comment' ) .
 251                      "</td>
 252                      <td class='mw-input'>" .
 253                      Xml::input( 'log-comment', 50, '',
 254                          array( 'id' => 'mw-import-comment', 'type' => 'text' ) ) . ' ' .
 255                      "</td>
 256                  </tr>
 257                  <tr>
 258                      <td class='mw-label'>" .
 259                      Xml::label(
 260                          $this->msg( 'import-interwiki-rootpage' )->text(),
 261                          'mw-interwiki-rootpage-upload'
 262                      ) .
 263                      "</td>
 264                      <td class='mw-input'>" .
 265                      Xml::input( 'rootpage', 50, $this->rootpage,
 266                          array( 'id' => 'mw-interwiki-rootpage-upload', 'type' => 'text' ) ) . ' ' .
 267                      "</td>
 268                  </tr>
 269                  <tr>
 270                      <td></td>
 271                      <td class='mw-submit'>" .
 272                      Xml::submitButton( $this->msg( 'uploadbtn' )->text() ) .
 273                      "</td>
 274                  </tr>" .
 275                      Xml::closeElement( 'table' ) .
 276                      Html::hidden( 'editToken', $user->getEditToken() ) .
 277                      Xml::closeElement( 'form' ) .
 278                      Xml::closeElement( 'fieldset' )
 279              );
 280          } else {
 281              if ( empty( $importSources ) ) {
 282                  $out->addWikiMsg( 'importnosources' );
 283              }
 284          }
 285  
 286          if ( $user->isAllowed( 'import' ) && !empty( $importSources ) ) {
 287              # Show input field for import depth only if $wgExportMaxLinkDepth > 0
 288              $importDepth = '';
 289              if ( $this->getConfig()->get( 'ExportMaxLinkDepth' ) > 0 ) {
 290                  $importDepth = "<tr>
 291                              <td class='mw-label'>" .
 292                      $this->msg( 'export-pagelinks' )->parse() .
 293                      "</td>
 294                              <td class='mw-input'>" .
 295                      Xml::input( 'pagelink-depth', 3, 0 ) .
 296                      "</td>
 297                  </tr>";
 298              }
 299  
 300              $out->addHTML(
 301                  Xml::fieldset( $this->msg( 'importinterwiki' )->text() ) .
 302                      Xml::openElement(
 303                          'form',
 304                          array(
 305                              'method' => 'post',
 306                              'action' => $action,
 307                              'id' => 'mw-import-interwiki-form'
 308                          )
 309                      ) .
 310                      $this->msg( 'import-interwiki-text' )->parseAsBlock() .
 311                      Html::hidden( 'action', 'submit' ) .
 312                      Html::hidden( 'source', 'interwiki' ) .
 313                      Html::hidden( 'editToken', $user->getEditToken() ) .
 314                      Xml::openElement( 'table', array( 'id' => 'mw-import-table-interwiki' ) ) .
 315                      "<tr>
 316                      <td class='mw-label'>" .
 317                      Xml::label( $this->msg( 'import-interwiki-sourcewiki' )->text(), 'interwiki' ) .
 318                      "</td>
 319                      <td class='mw-input'>" .
 320                      Xml::openElement(
 321                          'select',
 322                          array( 'name' => 'interwiki', 'id' => 'interwiki' )
 323                      )
 324              );
 325  
 326              $needSubprojectField = false;
 327              foreach ( $importSources as $key => $value ) {
 328                  if ( is_int( $key ) ) {
 329                      $key = $value;
 330                  } elseif ( $value !== $key ) {
 331                      $needSubprojectField = true;
 332                  }
 333  
 334                  $attribs = array(
 335                      'value' => $key,
 336                  );
 337                  if ( is_array( $value ) ) {
 338                      $attribs['data-subprojects'] = implode( ' ', $value );
 339                  }
 340                  if ( $this->interwiki === $key ) {
 341                      $attribs['selected'] = 'selected';
 342                  }
 343                  $out->addHTML( Html::element( 'option', $attribs, $key ) );
 344              }
 345  
 346              $out->addHTML(
 347                  Xml::closeElement( 'select' )
 348              );
 349  
 350              if ( $needSubprojectField ) {
 351                  $out->addHTML(
 352                      Xml::openElement(
 353                          'select',
 354                          array( 'name' => 'subproject', 'id' => 'subproject' )
 355                      )
 356                  );
 357  
 358                  $subprojectsToAdd = array();
 359                  foreach ( $importSources as $key => $value ) {
 360                      if ( is_array( $value ) ) {
 361                          $subprojectsToAdd = array_merge( $subprojectsToAdd, $value );
 362                      }
 363                  }
 364                  $subprojectsToAdd = array_unique( $subprojectsToAdd );
 365                  sort( $subprojectsToAdd );
 366                  foreach ( $subprojectsToAdd as $subproject ) {
 367                      $out->addHTML( Xml::option( $subproject, $subproject, $this->subproject === $subproject ) );
 368                  }
 369  
 370                  $out->addHTML(
 371                      Xml::closeElement( 'select' )
 372                  );
 373              }
 374  
 375              $out->addHTML(
 376                      "</td>
 377                  </tr>
 378                  <tr>
 379                      <td class='mw-label'>" .
 380                      Xml::label( $this->msg( 'import-interwiki-sourcepage' )->text(), 'frompage' ) .
 381                      "</td>
 382                      <td class='mw-input'>" .
 383                      Xml::input( 'frompage', 50, $this->frompage, array( 'id' => 'frompage' ) ) .
 384                      "</td>
 385                  </tr>
 386                  <tr>
 387                      <td>
 388                      </td>
 389                      <td class='mw-input'>" .
 390                      Xml::checkLabel(
 391                          $this->msg( 'import-interwiki-history' )->text(),
 392                          'interwikiHistory',
 393                          'interwikiHistory',
 394                          $this->history
 395                      ) .
 396                      "</td>
 397                  </tr>
 398                  <tr>
 399                      <td>
 400                      </td>
 401                      <td class='mw-input'>" .
 402                      Xml::checkLabel(
 403                          $this->msg( 'import-interwiki-templates' )->text(),
 404                          'interwikiTemplates',
 405                          'interwikiTemplates',
 406                          $this->includeTemplates
 407                      ) .
 408                      "</td>
 409                  </tr>
 410                  $importDepth
 411                  <tr>
 412                      <td class='mw-label'>" .
 413                      Xml::label( $this->msg( 'import-interwiki-namespace' )->text(), 'namespace' ) .
 414                      "</td>
 415                      <td class='mw-input'>" .
 416                      Html::namespaceSelector(
 417                          array(
 418                              'selected' => $this->namespace,
 419                              'all' => '',
 420                          ), array(
 421                              'name' => 'namespace',
 422                              'id' => 'namespace',
 423                              'class' => 'namespaceselector',
 424                          )
 425                      ) .
 426                      "</td>
 427                  </tr>
 428                  <tr>
 429                      <td class='mw-label'>" .
 430                      Xml::label( $this->msg( 'import-comment' )->text(), 'mw-interwiki-comment' ) .
 431                      "</td>
 432                      <td class='mw-input'>" .
 433                      Xml::input( 'log-comment', 50, '',
 434                          array( 'id' => 'mw-interwiki-comment', 'type' => 'text' ) ) . ' ' .
 435                      "</td>
 436                  </tr>
 437                  <tr>
 438                      <td class='mw-label'>" .
 439                      Xml::label(
 440                          $this->msg( 'import-interwiki-rootpage' )->text(),
 441                          'mw-interwiki-rootpage-interwiki'
 442                      ) .
 443                      "</td>
 444                      <td class='mw-input'>" .
 445                      Xml::input( 'rootpage', 50, $this->rootpage,
 446                          array( 'id' => 'mw-interwiki-rootpage-interwiki', 'type' => 'text' ) ) . ' ' .
 447                      "</td>
 448                  </tr>
 449                  <tr>
 450                      <td>
 451                      </td>
 452                      <td class='mw-submit'>" .
 453                      Xml::submitButton(
 454                          $this->msg( 'import-interwiki-submit' )->text(),
 455                          Linker::tooltipAndAccesskeyAttribs( 'import' )
 456                      ) .
 457                      "</td>
 458                  </tr>" .
 459                      Xml::closeElement( 'table' ) .
 460                      Xml::closeElement( 'form' ) .
 461                      Xml::closeElement( 'fieldset' )
 462              );
 463          }
 464      }
 465  
 466  	protected function getGroupName() {
 467          return 'pagetools';
 468      }
 469  }
 470  
 471  /**
 472   * Reporting callback
 473   * @ingroup SpecialPage
 474   */
 475  class ImportReporter extends ContextSource {
 476      private $reason = false;
 477      private $mOriginalLogCallback = null;
 478      private $mOriginalPageOutCallback = null;
 479      private $mLogItemCount = 0;
 480  
 481      /**
 482       * @param WikiImporter $importer
 483       * @param bool $upload
 484       * @param string $interwiki
 485       * @param string|bool $reason
 486       */
 487  	function __construct( $importer, $upload, $interwiki, $reason = false ) {
 488          $this->mOriginalPageOutCallback =
 489              $importer->setPageOutCallback( array( $this, 'reportPage' ) );
 490          $this->mOriginalLogCallback =
 491              $importer->setLogItemCallback( array( $this, 'reportLogItem' ) );
 492          $importer->setNoticeCallback( array( $this, 'reportNotice' ) );
 493          $this->mPageCount = 0;
 494          $this->mIsUpload = $upload;
 495          $this->mInterwiki = $interwiki;
 496          $this->reason = $reason;
 497      }
 498  
 499  	function open() {
 500          $this->getOutput()->addHTML( "<ul>\n" );
 501      }
 502  
 503  	function reportNotice( $msg, array $params ) {
 504          $this->getOutput()->addHTML(
 505              Html::element( 'li', array(), $this->msg( $msg, $params )->text() )
 506          );
 507      }
 508  
 509  	function reportLogItem( /* ... */ ) {
 510          $this->mLogItemCount++;
 511          if ( is_callable( $this->mOriginalLogCallback ) ) {
 512              call_user_func_array( $this->mOriginalLogCallback, func_get_args() );
 513          }
 514      }
 515  
 516      /**
 517       * @param Title $title
 518       * @param Title $origTitle
 519       * @param int $revisionCount
 520       * @param int $successCount
 521       * @param array $pageInfo
 522       * @return void
 523       */
 524  	function reportPage( $title, $origTitle, $revisionCount, $successCount, $pageInfo ) {
 525          $args = func_get_args();
 526          call_user_func_array( $this->mOriginalPageOutCallback, $args );
 527  
 528          if ( $title === null ) {
 529              # Invalid or non-importable title; a notice is already displayed
 530              return;
 531          }
 532  
 533          $this->mPageCount++;
 534  
 535          if ( $successCount > 0 ) {
 536              $this->getOutput()->addHTML(
 537                  "<li>" . Linker::linkKnown( $title ) . " " .
 538                      $this->msg( 'import-revision-count' )->numParams( $successCount )->escaped() .
 539                      "</li>\n"
 540              );
 541  
 542              $log = new LogPage( 'import' );
 543              if ( $this->mIsUpload ) {
 544                  $detail = $this->msg( 'import-logentry-upload-detail' )->numParams(
 545                      $successCount )->inContentLanguage()->text();
 546                  if ( $this->reason ) {
 547                      $detail .= $this->msg( 'colon-separator' )->inContentLanguage()->text()
 548                          . $this->reason;
 549                  }
 550                  $log->addEntry( 'upload', $title, $detail, array(), $this->getUser() );
 551              } else {
 552                  $interwiki = '[[:' . $this->mInterwiki . ':' .
 553                      $origTitle->getPrefixedText() . ']]';
 554                  $detail = $this->msg( 'import-logentry-interwiki-detail' )->numParams(
 555                      $successCount )->params( $interwiki )->inContentLanguage()->text();
 556                  if ( $this->reason ) {
 557                      $detail .= $this->msg( 'colon-separator' )->inContentLanguage()->text()
 558                          . $this->reason;
 559                  }
 560                  $log->addEntry( 'interwiki', $title, $detail, array(), $this->getUser() );
 561              }
 562  
 563              $comment = $detail; // quick
 564              $dbw = wfGetDB( DB_MASTER );
 565              $latest = $title->getLatestRevID();
 566              $nullRevision = Revision::newNullRevision(
 567                  $dbw,
 568                  $title->getArticleID(),
 569                  $comment,
 570                  true,
 571                  $this->getUser()
 572              );
 573  
 574              if ( !is_null( $nullRevision ) ) {
 575                  $nullRevision->insertOn( $dbw );
 576                  $page = WikiPage::factory( $title );
 577                  # Update page record
 578                  $page->updateRevisionOn( $dbw, $nullRevision );
 579                  wfRunHooks(
 580                      'NewRevisionFromEditComplete',
 581                      array( $page, $nullRevision, $latest, $this->getUser() )
 582                  );
 583              }
 584          } else {
 585              $this->getOutput()->addHTML( "<li>" . Linker::linkKnown( $title ) . " " .
 586                  $this->msg( 'import-nonewrevisions' )->escaped() . "</li>\n" );
 587          }
 588      }
 589  
 590  	function close() {
 591          $out = $this->getOutput();
 592          if ( $this->mLogItemCount > 0 ) {
 593              $msg = $this->msg( 'imported-log-entries' )->numParams( $this->mLogItemCount )->parse();
 594              $out->addHTML( Xml::tags( 'li', null, $msg ) );
 595          } elseif ( $this->mPageCount == 0 && $this->mLogItemCount == 0 ) {
 596              $out->addHTML( "</ul>\n" );
 597  
 598              return Status::newFatal( 'importnopages' );
 599          }
 600          $out->addHTML( "</ul>\n" );
 601  
 602          return Status::newGood( $this->mPageCount );
 603      }
 604  }


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