MediaWiki  REL1_22
SpecialImport.php
Go to the documentation of this file.
00001 <?php
00032 class SpecialImport extends SpecialPage {
00033     private $interwiki = false;
00034     private $namespace;
00035     private $rootpage = '';
00036     private $frompage = '';
00037     private $logcomment = false;
00038     private $history = true;
00039     private $includeTemplates = false;
00040     private $pageLinkDepth;
00041 
00045     public function __construct() {
00046         parent::__construct( 'Import', 'import' );
00047         global $wgImportTargetNamespace;
00048         $this->namespace = $wgImportTargetNamespace;
00049     }
00050 
00054     function execute( $par ) {
00055         $this->setHeaders();
00056         $this->outputHeader();
00057 
00058         $user = $this->getUser();
00059         if ( !$user->isAllowedAny( 'import', 'importupload' ) ) {
00060             throw new PermissionsError( 'import' );
00061         }
00062 
00063         # @todo Allow Title::getUserPermissionsErrors() to take an array
00064         # @todo FIXME: Title::checkSpecialsAndNSPermissions() has a very wierd expectation of what
00065         # getUserPermissionsErrors() might actually be used for, hence the 'ns-specialprotected'
00066         $errors = wfMergeErrorArrays(
00067             $this->getTitle()->getUserPermissionsErrors(
00068                 'import', $user, true,
00069                 array( 'ns-specialprotected', 'badaccess-group0', 'badaccess-groups' )
00070             ),
00071             $this->getTitle()->getUserPermissionsErrors(
00072                 'importupload', $user, true,
00073                 array( 'ns-specialprotected', 'badaccess-group0', 'badaccess-groups' )
00074             )
00075         );
00076 
00077         if ( $errors ) {
00078             throw new PermissionsError( 'import', $errors );
00079         }
00080 
00081         $this->checkReadOnly();
00082 
00083         $request = $this->getRequest();
00084         if ( $request->wasPosted() && $request->getVal( 'action' ) == 'submit' ) {
00085             $this->doImport();
00086         }
00087         $this->showForm();
00088     }
00089 
00093     private function doImport() {
00094         global $wgImportSources, $wgExportMaxLinkDepth;
00095 
00096         $isUpload = false;
00097         $request = $this->getRequest();
00098         $this->namespace = $request->getIntOrNull( 'namespace' );
00099         $sourceName = $request->getVal( "source" );
00100 
00101         $this->logcomment = $request->getText( 'log-comment' );
00102         $this->pageLinkDepth = $wgExportMaxLinkDepth == 0 ? 0 : $request->getIntOrNull( 'pagelink-depth' );
00103         $this->rootpage = $request->getText( 'rootpage' );
00104 
00105         $user = $this->getUser();
00106         if ( !$user->matchEditToken( $request->getVal( 'editToken' ) ) ) {
00107             $source = Status::newFatal( 'import-token-mismatch' );
00108         } elseif ( $sourceName == 'upload' ) {
00109             $isUpload = true;
00110             if ( $user->isAllowed( 'importupload' ) ) {
00111                 $source = ImportStreamSource::newFromUpload( "xmlimport" );
00112             } else {
00113                 throw new PermissionsError( 'importupload' );
00114             }
00115         } elseif ( $sourceName == "interwiki" ) {
00116             if ( !$user->isAllowed( 'import' ) ) {
00117                 throw new PermissionsError( 'import' );
00118             }
00119             $this->interwiki = $request->getVal( 'interwiki' );
00120             if ( !in_array( $this->interwiki, $wgImportSources ) ) {
00121                 $source = Status::newFatal( "import-invalid-interwiki" );
00122             } else {
00123                 $this->history = $request->getCheck( 'interwikiHistory' );
00124                 $this->frompage = $request->getText( "frompage" );
00125                 $this->includeTemplates = $request->getCheck( 'interwikiTemplates' );
00126                 $source = ImportStreamSource::newFromInterwiki(
00127                     $this->interwiki,
00128                     $this->frompage,
00129                     $this->history,
00130                     $this->includeTemplates,
00131                     $this->pageLinkDepth );
00132             }
00133         } else {
00134             $source = Status::newFatal( "importunknownsource" );
00135         }
00136 
00137         $out = $this->getOutput();
00138         if ( !$source->isGood() ) {
00139             $out->wrapWikiMsg(
00140                 "<p class=\"error\">\n$1\n</p>",
00141                 array( 'importfailed', $source->getWikiText() )
00142             );
00143         } else {
00144             $importer = new WikiImporter( $source->value );
00145             if ( !is_null( $this->namespace ) ) {
00146                 $importer->setTargetNamespace( $this->namespace );
00147             }
00148             if ( !is_null( $this->rootpage ) ) {
00149                 $statusRootPage = $importer->setTargetRootPage( $this->rootpage );
00150                 if ( !$statusRootPage->isGood() ) {
00151                     $out->wrapWikiMsg(
00152                         "<p class=\"error\">\n$1\n</p>",
00153                         array(
00154                             'import-options-wrong',
00155                             $statusRootPage->getWikiText(),
00156                             count( $statusRootPage->getErrorsArray() )
00157                         )
00158                     );
00159 
00160                     return;
00161                 }
00162             }
00163 
00164             $out->addWikiMsg( "importstart" );
00165 
00166             $reporter = new ImportReporter(
00167                 $importer,
00168                 $isUpload,
00169                 $this->interwiki,
00170                 $this->logcomment
00171             );
00172             $reporter->setContext( $this->getContext() );
00173             $exception = false;
00174 
00175             $reporter->open();
00176             try {
00177                 $importer->doImport();
00178             } catch ( MWException $e ) {
00179                 $exception = $e;
00180             }
00181             $result = $reporter->close();
00182 
00183             if ( $exception ) {
00184                 # No source or XML parse error
00185                 $out->wrapWikiMsg(
00186                     "<p class=\"error\">\n$1\n</p>",
00187                     array( 'importfailed', $exception->getMessage() )
00188                 );
00189             } elseif ( !$result->isGood() ) {
00190                 # Zero revisions
00191                 $out->wrapWikiMsg(
00192                     "<p class=\"error\">\n$1\n</p>",
00193                     array( 'importfailed', $result->getWikiText() )
00194                 );
00195             } else {
00196                 # Success!
00197                 $out->addWikiMsg( 'importsuccess' );
00198             }
00199             $out->addHTML( '<hr />' );
00200         }
00201     }
00202 
00203     private function showForm() {
00204         global $wgImportSources, $wgExportMaxLinkDepth;
00205 
00206         $action = $this->getTitle()->getLocalURL( array( 'action' => 'submit' ) );
00207         $user = $this->getUser();
00208         $out = $this->getOutput();
00209 
00210         if ( $user->isAllowed( 'importupload' ) ) {
00211             $out->addHTML(
00212                 Xml::fieldset( $this->msg( 'import-upload' )->text() ) .
00213                     Xml::openElement(
00214                         'form',
00215                         array(
00216                             'enctype' => 'multipart/form-data',
00217                             'method' => 'post',
00218                             'action' => $action,
00219                             'id' => 'mw-import-upload-form'
00220                         )
00221                     ) .
00222                     $this->msg( 'importtext' )->parseAsBlock() .
00223                     Html::hidden( 'action', 'submit' ) .
00224                     Html::hidden( 'source', 'upload' ) .
00225                     Xml::openElement( 'table', array( 'id' => 'mw-import-table-upload' ) ) .
00226                     "<tr>
00227                     <td class='mw-label'>" .
00228                     Xml::label( $this->msg( 'import-upload-filename' )->text(), 'xmlimport' ) .
00229                     "</td>
00230                     <td class='mw-input'>" .
00231                     Html::input( 'xmlimport', '', 'file', array( 'id' => 'xmlimport' ) ) . ' ' .
00232                     "</td>
00233                 </tr>
00234                 <tr>
00235                     <td class='mw-label'>" .
00236                     Xml::label( $this->msg( 'import-comment' )->text(), 'mw-import-comment' ) .
00237                     "</td>
00238                     <td class='mw-input'>" .
00239                     Xml::input( 'log-comment', 50, '',
00240                         array( 'id' => 'mw-import-comment', 'type' => 'text' ) ) . ' ' .
00241                     "</td>
00242                 </tr>
00243                 <tr>
00244                     <td class='mw-label'>" .
00245                     Xml::label( $this->msg( 'import-interwiki-rootpage' )->text(), 'mw-interwiki-rootpage-upload' ) .
00246                     "</td>
00247                     <td class='mw-input'>" .
00248                     Xml::input( 'rootpage', 50, $this->rootpage,
00249                         array( 'id' => 'mw-interwiki-rootpage-upload', 'type' => 'text' ) ) . ' ' .
00250                     "</td>
00251                 </tr>
00252                 <tr>
00253                     <td></td>
00254                     <td class='mw-submit'>" .
00255                     Xml::submitButton( $this->msg( 'uploadbtn' )->text() ) .
00256                     "</td>
00257                 </tr>" .
00258                     Xml::closeElement( 'table' ) .
00259                     Html::hidden( 'editToken', $user->getEditToken() ) .
00260                     Xml::closeElement( 'form' ) .
00261                     Xml::closeElement( 'fieldset' )
00262             );
00263         } else {
00264             if ( empty( $wgImportSources ) ) {
00265                 $out->addWikiMsg( 'importnosources' );
00266             }
00267         }
00268 
00269         if ( $user->isAllowed( 'import' ) && !empty( $wgImportSources ) ) {
00270             # Show input field for import depth only if $wgExportMaxLinkDepth > 0
00271             $importDepth = '';
00272             if ( $wgExportMaxLinkDepth > 0 ) {
00273                 $importDepth = "<tr>
00274                             <td class='mw-label'>" .
00275                     $this->msg( 'export-pagelinks' )->parse() .
00276                     "</td>
00277                             <td class='mw-input'>" .
00278                     Xml::input( 'pagelink-depth', 3, 0 ) .
00279                     "</td>
00280                 </tr>";
00281             }
00282 
00283             $out->addHTML(
00284                 Xml::fieldset( $this->msg( 'importinterwiki' )->text() ) .
00285                     Xml::openElement(
00286                         'form',
00287                         array(
00288                             'method' => 'post',
00289                             'action' => $action,
00290                             'id' => 'mw-import-interwiki-form'
00291                         )
00292                     ) .
00293                     $this->msg( 'import-interwiki-text' )->parseAsBlock() .
00294                     Html::hidden( 'action', 'submit' ) .
00295                     Html::hidden( 'source', 'interwiki' ) .
00296                     Html::hidden( 'editToken', $user->getEditToken() ) .
00297                     Xml::openElement( 'table', array( 'id' => 'mw-import-table-interwiki' ) ) .
00298                     "<tr>
00299                     <td class='mw-label'>" .
00300                     Xml::label( $this->msg( 'import-interwiki-source' )->text(), 'interwiki' ) .
00301                     "</td>
00302                     <td class='mw-input'>" .
00303                     Xml::openElement(
00304                         'select',
00305                         array( 'name' => 'interwiki', 'id' => 'interwiki' )
00306                     )
00307             );
00308 
00309             foreach ( $wgImportSources as $prefix ) {
00310                 $selected = ( $this->interwiki === $prefix ) ? ' selected="selected"' : '';
00311                 $out->addHTML( Xml::option( $prefix, $prefix, $selected ) );
00312             }
00313 
00314             $out->addHTML(
00315                 Xml::closeElement( 'select' ) .
00316                     Xml::input( 'frompage', 50, $this->frompage, array( 'id' => 'frompage' ) ) .
00317                     "</td>
00318                 </tr>
00319                 <tr>
00320                     <td>
00321                     </td>
00322                     <td class='mw-input'>" .
00323                     Xml::checkLabel(
00324                         $this->msg( 'import-interwiki-history' )->text(),
00325                         'interwikiHistory',
00326                         'interwikiHistory',
00327                         $this->history
00328                     ) .
00329                     "</td>
00330                 </tr>
00331                 <tr>
00332                     <td>
00333                     </td>
00334                     <td class='mw-input'>" .
00335                     Xml::checkLabel(
00336                         $this->msg( 'import-interwiki-templates' )->text(),
00337                         'interwikiTemplates',
00338                         'interwikiTemplates',
00339                         $this->includeTemplates
00340                     ) .
00341                     "</td>
00342                 </tr>
00343                 $importDepth
00344                 <tr>
00345                     <td class='mw-label'>" .
00346                     Xml::label( $this->msg( 'import-interwiki-namespace' )->text(), 'namespace' ) .
00347                     "</td>
00348                     <td class='mw-input'>" .
00349                     Html::namespaceSelector(
00350                         array(
00351                             'selected' => $this->namespace,
00352                             'all' => '',
00353                         ), array(
00354                             'name' => 'namespace',
00355                             'id' => 'namespace',
00356                             'class' => 'namespaceselector',
00357                         )
00358                     ) .
00359                     "</td>
00360                 </tr>
00361                 <tr>
00362                     <td class='mw-label'>" .
00363                     Xml::label( $this->msg( 'import-comment' )->text(), 'mw-interwiki-comment' ) .
00364                     "</td>
00365                     <td class='mw-input'>" .
00366                     Xml::input( 'log-comment', 50, '',
00367                         array( 'id' => 'mw-interwiki-comment', 'type' => 'text' ) ) . ' ' .
00368                     "</td>
00369                 </tr>
00370                 <tr>
00371                     <td class='mw-label'>" .
00372                     Xml::label(
00373                         $this->msg( 'import-interwiki-rootpage' )->text(),
00374                         'mw-interwiki-rootpage-interwiki'
00375                     ) .
00376                     "</td>
00377                     <td class='mw-input'>" .
00378                     Xml::input( 'rootpage', 50, $this->rootpage,
00379                         array( 'id' => 'mw-interwiki-rootpage-interwiki', 'type' => 'text' ) ) . ' ' .
00380                     "</td>
00381                 </tr>
00382                 <tr>
00383                     <td>
00384                     </td>
00385                     <td class='mw-submit'>" .
00386                     Xml::submitButton(
00387                         $this->msg( 'import-interwiki-submit' )->text(),
00388                         Linker::tooltipAndAccesskeyAttribs( 'import' )
00389                     ) .
00390                     "</td>
00391                 </tr>" .
00392                     Xml::closeElement( 'table' ) .
00393                     Xml::closeElement( 'form' ) .
00394                     Xml::closeElement( 'fieldset' )
00395             );
00396         }
00397     }
00398 
00399     protected function getGroupName() {
00400         return 'pagetools';
00401     }
00402 }
00403 
00408 class ImportReporter extends ContextSource {
00409     private $reason = false;
00410     private $mOriginalLogCallback = null;
00411     private $mOriginalPageOutCallback = null;
00412     private $mLogItemCount = 0;
00413 
00414 
00421     function __construct( $importer, $upload, $interwiki, $reason = false ) {
00422         $this->mOriginalPageOutCallback =
00423             $importer->setPageOutCallback( array( $this, 'reportPage' ) );
00424         $this->mOriginalLogCallback =
00425             $importer->setLogItemCallback( array( $this, 'reportLogItem' ) );
00426         $importer->setNoticeCallback( array( $this, 'reportNotice' ) );
00427         $this->mPageCount = 0;
00428         $this->mIsUpload = $upload;
00429         $this->mInterwiki = $interwiki;
00430         $this->reason = $reason;
00431     }
00432 
00433     function open() {
00434         $this->getOutput()->addHTML( "<ul>\n" );
00435     }
00436 
00437     function reportNotice( $msg, array $params ) {
00438         $this->getOutput()->addHTML( Html::element( 'li', array(), $this->msg( $msg, $params )->text() ) );
00439     }
00440 
00441     function reportLogItem( /* ... */ ) {
00442         $this->mLogItemCount++;
00443         if ( is_callable( $this->mOriginalLogCallback ) ) {
00444             call_user_func_array( $this->mOriginalLogCallback, func_get_args() );
00445         }
00446     }
00447 
00456     function reportPage( $title, $origTitle, $revisionCount, $successCount, $pageInfo ) {
00457         $args = func_get_args();
00458         call_user_func_array( $this->mOriginalPageOutCallback, $args );
00459 
00460         if ( $title === null ) {
00461             # Invalid or non-importable title; a notice is already displayed
00462             return;
00463         }
00464 
00465         $this->mPageCount++;
00466 
00467         if ( $successCount > 0 ) {
00468             $this->getOutput()->addHTML(
00469                 "<li>" . Linker::linkKnown( $title ) . " " .
00470                     $this->msg( 'import-revision-count' )->numParams( $successCount )->escaped() .
00471                     "</li>\n"
00472             );
00473 
00474             $log = new LogPage( 'import' );
00475             if ( $this->mIsUpload ) {
00476                 $detail = $this->msg( 'import-logentry-upload-detail' )->numParams(
00477                     $successCount )->inContentLanguage()->text();
00478                 if ( $this->reason ) {
00479                     $detail .= $this->msg( 'colon-separator' )->inContentLanguage()->text() . $this->reason;
00480                 }
00481                 $log->addEntry( 'upload', $title, $detail, array(), $this->getUser() );
00482             } else {
00483                 $interwiki = '[[:' . $this->mInterwiki . ':' .
00484                     $origTitle->getPrefixedText() . ']]';
00485                 $detail = $this->msg( 'import-logentry-interwiki-detail' )->numParams(
00486                     $successCount )->params( $interwiki )->inContentLanguage()->text();
00487                 if ( $this->reason ) {
00488                     $detail .= $this->msg( 'colon-separator' )->inContentLanguage()->text() . $this->reason;
00489                 }
00490                 $log->addEntry( 'interwiki', $title, $detail, array(), $this->getUser() );
00491             }
00492 
00493             $comment = $detail; // quick
00494             $dbw = wfGetDB( DB_MASTER );
00495             $latest = $title->getLatestRevID();
00496             $nullRevision = Revision::newNullRevision( $dbw, $title->getArticleID(), $comment, true );
00497             if ( !is_null( $nullRevision ) ) {
00498                 $nullRevision->insertOn( $dbw );
00499                 $page = WikiPage::factory( $title );
00500                 # Update page record
00501                 $page->updateRevisionOn( $dbw, $nullRevision );
00502                 wfRunHooks( 'NewRevisionFromEditComplete', array( $page, $nullRevision, $latest, $this->getUser() ) );
00503             }
00504         } else {
00505             $this->getOutput()->addHTML( "<li>" . Linker::linkKnown( $title ) . " " .
00506                 $this->msg( 'import-nonewrevisions' )->escaped() . "</li>\n" );
00507         }
00508     }
00509 
00510     function close() {
00511         $out = $this->getOutput();
00512         if ( $this->mLogItemCount > 0 ) {
00513             $msg = $this->msg( 'imported-log-entries' )->numParams( $this->mLogItemCount )->parse();
00514             $out->addHTML( Xml::tags( 'li', null, $msg ) );
00515         } elseif ( $this->mPageCount == 0 && $this->mLogItemCount == 0 ) {
00516             $out->addHTML( "</ul>\n" );
00517 
00518             return Status::newFatal( 'importnopages' );
00519         }
00520         $out->addHTML( "</ul>\n" );
00521 
00522         return Status::newGood( $this->mPageCount );
00523     }
00524 }