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