MediaWiki  REL1_19
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 $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 
00104                 $user = $this->getUser();
00105                 if ( !$user->matchEditToken( $request->getVal( 'editToken' ) ) ) {
00106                         $source = Status::newFatal( 'import-token-mismatch' );
00107                 } elseif ( $sourceName == 'upload' ) {
00108                         $isUpload = true;
00109                         if( $user->isAllowed( 'importupload' ) ) {
00110                                 $source = ImportStreamSource::newFromUpload( "xmlimport" );
00111                         } else {
00112                                 throw new PermissionsError( 'importupload' );
00113                         }
00114                 } elseif ( $sourceName == "interwiki" ) {
00115                         if( !$user->isAllowed( 'import' ) ){
00116                                 throw new PermissionsError( 'import' );
00117                         }
00118                         $this->interwiki = $request->getVal( 'interwiki' );
00119                         if ( !in_array( $this->interwiki, $wgImportSources ) ) {
00120                                 $source = Status::newFatal( "import-invalid-interwiki" );
00121                         } else {
00122                                 $this->history = $request->getCheck( 'interwikiHistory' );
00123                                 $this->frompage = $request->getText( "frompage" );
00124                                 $this->includeTemplates = $request->getCheck( 'interwikiTemplates' );
00125                                 $source = ImportStreamSource::newFromInterwiki(
00126                                         $this->interwiki,
00127                                         $this->frompage,
00128                                         $this->history,
00129                                         $this->includeTemplates,
00130                                         $this->pageLinkDepth );
00131                         }
00132                 } else {
00133                         $source = Status::newFatal( "importunknownsource" );
00134                 }
00135 
00136                 $out = $this->getOutput();
00137                 if( !$source->isGood() ) {
00138                         $out->wrapWikiMsg( "<p class=\"error\">\n$1\n</p>", array( 'importfailed', $source->getWikiText() ) );
00139                 } else {
00140                         $out->addWikiMsg( "importstart" );
00141 
00142                         $importer = new WikiImporter( $source->value );
00143                         if( !is_null( $this->namespace ) ) {
00144                                 $importer->setTargetNamespace( $this->namespace );
00145                         }
00146                         $reporter = new ImportReporter( $importer, $isUpload, $this->interwiki , $this->logcomment);
00147                         $reporter->setContext( $this->getContext() );
00148                         $exception = false;
00149 
00150                         $reporter->open();
00151                         try {
00152                                 $importer->doImport();
00153                         } catch ( MWException $e ) {
00154                                 $exception = $e;
00155                         }
00156                         $result = $reporter->close();
00157 
00158                         if ( $exception ) {
00159                                 # No source or XML parse error
00160                                 $out->wrapWikiMsg( "<p class=\"error\">\n$1\n</p>", array( 'importfailed', $exception->getMessage() ) );
00161                         } elseif( !$result->isGood() ) {
00162                                 # Zero revisions
00163                                 $out->wrapWikiMsg( "<p class=\"error\">\n$1\n</p>", array( 'importfailed', $result->getWikiText() ) );
00164                         } else {
00165                                 # Success!
00166                                 $out->addWikiMsg( 'importsuccess' );
00167                         }
00168                         $out->addHTML( '<hr />' );
00169                 }
00170         }
00171 
00172         private function showForm() {
00173                 global $wgImportSources, $wgExportMaxLinkDepth;
00174 
00175                 $action = $this->getTitle()->getLocalUrl( array( 'action' => 'submit' ) );
00176                 $user = $this->getUser();
00177                 $out = $this->getOutput();
00178 
00179                 if( $user->isAllowed( 'importupload' ) ) {
00180                         $out->addWikiMsg( "importtext" );
00181                         $out->addHTML(
00182                                 Xml::fieldset( wfMsg( 'import-upload' ) ).
00183                                 Xml::openElement( 'form', array( 'enctype' => 'multipart/form-data', 'method' => 'post',
00184                                         'action' => $action, 'id' => 'mw-import-upload-form' ) ) .
00185                                 Html::hidden( 'action', 'submit' ) .
00186                                 Html::hidden( 'source', 'upload' ) .
00187                                 Xml::openElement( 'table', array( 'id' => 'mw-import-table' ) ) .
00188 
00189                                 "<tr>
00190                                         <td class='mw-label'>" .
00191                                                 Xml::label( wfMsg( 'import-upload-filename' ), 'xmlimport' ) .
00192                                         "</td>
00193                                         <td class='mw-input'>" .
00194                                                 Xml::input( 'xmlimport', 50, '', array( 'type' => 'file' ) ) . ' ' .
00195                                         "</td>
00196                                 </tr>
00197                                 <tr>
00198                                         <td class='mw-label'>" .
00199                                                 Xml::label( wfMsg( 'import-comment' ), 'mw-import-comment' ) .
00200                                         "</td>
00201                                         <td class='mw-input'>" .
00202                                                 Xml::input( 'log-comment', 50, '',
00203                                                         array( 'id' => 'mw-import-comment', 'type' => 'text' ) ) . ' ' .
00204                                         "</td>
00205                                 </tr>
00206                                 <tr>
00207                                         <td></td>
00208                                         <td class='mw-submit'>" .
00209                                                 Xml::submitButton( wfMsg( 'uploadbtn' ) ) .
00210                                         "</td>
00211                                 </tr>" .
00212                                 Xml::closeElement( 'table' ).
00213                                 Html::hidden( 'editToken', $user->getEditToken() ) .
00214                                 Xml::closeElement( 'form' ) .
00215                                 Xml::closeElement( 'fieldset' )
00216                         );
00217                 } else {
00218                         if( empty( $wgImportSources ) ) {
00219                                 $out->addWikiMsg( 'importnosources' );
00220                         }
00221                 }
00222 
00223                 if( $user->isAllowed( 'import' ) && !empty( $wgImportSources ) ) {
00224                         # Show input field for import depth only if $wgExportMaxLinkDepth > 0
00225                         $importDepth = '';
00226                         if( $wgExportMaxLinkDepth > 0 ) {
00227                                 $importDepth = "<tr>
00228                                                         <td class='mw-label'>" .
00229                                                                 wfMsgExt( 'export-pagelinks', 'parseinline' ) .
00230                                                         "</td>
00231                                                         <td class='mw-input'>" .
00232                                                                 Xml::input( 'pagelink-depth', 3, 0 ) .
00233                                                         "</td>
00234                                                 </tr>";
00235                         }
00236 
00237                         $out->addHTML(
00238                                 Xml::fieldset(  wfMsg( 'importinterwiki' ) ) .
00239                                 Xml::openElement( 'form', array( 'method' => 'post', 'action' => $action, 'id' => 'mw-import-interwiki-form' ) ) .
00240                                 wfMsgExt( 'import-interwiki-text', array( 'parse' ) ) .
00241                                 Html::hidden( 'action', 'submit' ) .
00242                                 Html::hidden( 'source', 'interwiki' ) .
00243                                 Html::hidden( 'editToken', $user->getEditToken() ) .
00244                                 Xml::openElement( 'table', array( 'id' => 'mw-import-table' ) ) .
00245                                 "<tr>
00246                                         <td class='mw-label'>" .
00247                                                 Xml::label( wfMsg( 'import-interwiki-source' ), 'interwiki' ) .
00248                                         "</td>
00249                                         <td class='mw-input'>" .
00250                                                 Xml::openElement( 'select', array( 'name' => 'interwiki' ) )
00251                         );
00252                         foreach( $wgImportSources as $prefix ) {
00253                                 $selected = ( $this->interwiki === $prefix ) ? ' selected="selected"' : '';
00254                                 $out->addHTML( Xml::option( $prefix, $prefix, $selected ) );
00255                         }
00256 
00257                         $out->addHTML(
00258                                                 Xml::closeElement( 'select' ) .
00259                                                 Xml::input( 'frompage', 50, $this->frompage ) .
00260                                         "</td>
00261                                 </tr>
00262                                 <tr>
00263                                         <td>
00264                                         </td>
00265                                         <td class='mw-input'>" .
00266                                                 Xml::checkLabel( wfMsg( 'import-interwiki-history' ), 'interwikiHistory', 'interwikiHistory', $this->history ) .
00267                                         "</td>
00268                                 </tr>
00269                                 <tr>
00270                                         <td>
00271                                         </td>
00272                                         <td class='mw-input'>" .
00273                                                 Xml::checkLabel( wfMsg( 'import-interwiki-templates' ), 'interwikiTemplates', 'interwikiTemplates', $this->includeTemplates ) .
00274                                         "</td>
00275                                 </tr>
00276                                 $importDepth
00277                                 <tr>
00278                                         <td class='mw-label'>" .
00279                                                 Xml::label( wfMsg( 'import-interwiki-namespace' ), 'namespace' ) .
00280                                         "</td>
00281                                         <td class='mw-input'>" .
00282                                                 Xml::namespaceSelector( $this->namespace, '' ) .
00283                                         "</td>
00284                                 </tr>
00285                                 <tr>
00286                                         <td class='mw-label'>" .
00287                                                 Xml::label( wfMsg( 'import-comment' ), 'mw-interwiki-comment' ) .
00288                                         "</td>
00289                                         <td class='mw-input'>" .
00290                                                 Xml::input( 'log-comment', 50, '',
00291                                                         array( 'id' => 'mw-interwiki-comment', 'type' => 'text' ) ) . ' ' .
00292                                         "</td>
00293                                 </tr>
00294                                 <tr>
00295                                         <td>
00296                                         </td>
00297                                         <td class='mw-submit'>" .
00298                                                 Xml::submitButton( wfMsg( 'import-interwiki-submit' ), Linker::tooltipAndAccesskeyAttribs( 'import' ) ) .
00299                                         "</td>
00300                                 </tr>" .
00301                                 Xml::closeElement( 'table' ).
00302                                 Xml::closeElement( 'form' ) .
00303                                 Xml::closeElement( 'fieldset' )
00304                         );
00305                 }
00306         }
00307 }
00308 
00313 class ImportReporter extends ContextSource {
00314         private $reason=false;
00315         private $mOriginalLogCallback = null;
00316         private $mOriginalPageOutCallback = null;
00317         private $mLogItemCount = 0;
00318 
00319         function __construct( $importer, $upload, $interwiki , $reason=false ) {
00320                 $this->mOriginalPageOutCallback =
00321                                 $importer->setPageOutCallback( array( $this, 'reportPage' ) );
00322                 $this->mOriginalLogCallback =
00323                         $importer->setLogItemCallback( array( $this, 'reportLogItem' ) );
00324                 $importer->setNoticeCallback( array( $this, 'reportNotice' ) );
00325                 $this->mPageCount = 0;
00326                 $this->mIsUpload = $upload;
00327                 $this->mInterwiki = $interwiki;
00328                 $this->reason = $reason;
00329         }
00330 
00331         function open() {
00332                 $this->getOutput()->addHTML( "<ul>\n" );
00333         }
00334 
00335         function reportNotice( $msg, array $params ) {
00336                 $this->getOutput()->addHTML( Html::element( 'li', array(), $this->msg( $msg, $params )->text() ) );
00337         }
00338 
00339         function reportLogItem( /* ... */ ) {
00340                 $this->mLogItemCount++;
00341                 if ( is_callable( $this->mOriginalLogCallback ) ) {
00342                         call_user_func_array( $this->mOriginalLogCallback, func_get_args() );
00343                 }
00344         }
00345 
00354         function reportPage( $title, $origTitle, $revisionCount, $successCount, $pageInfo ) {
00355                 global $wgContLang;
00356 
00357                 $args = func_get_args();
00358                 call_user_func_array( $this->mOriginalPageOutCallback, $args );
00359 
00360                 if ( $title === null ) {
00361                         # Invalid or non-importable title; a notice is already displayed
00362                         return;
00363                 }
00364 
00365                 $this->mPageCount++;
00366 
00367                 $localCount = $this->getLanguage()->formatNum( $successCount );
00368                 $contentCount = $wgContLang->formatNum( $successCount );
00369 
00370                 if( $successCount > 0 ) {
00371                         $this->getOutput()->addHTML( "<li>" . Linker::linkKnown( $title ) . " " .
00372                                 wfMsgExt( 'import-revision-count', array( 'parsemag', 'escape' ), $localCount ) .
00373                                 "</li>\n"
00374                         );
00375 
00376                         $log = new LogPage( 'import' );
00377                         if( $this->mIsUpload ) {
00378                                 $detail = wfMsgExt( 'import-logentry-upload-detail', array( 'content', 'parsemag' ),
00379                                         $contentCount );
00380                                 if ( $this->reason ) {
00381                                         $detail .=  wfMsgForContent( 'colon-separator' ) . $this->reason;
00382                                 }
00383                                 $log->addEntry( 'upload', $title, $detail );
00384                         } else {
00385                                 $interwiki = '[[:' . $this->mInterwiki . ':' .
00386                                         $origTitle->getPrefixedText() . ']]';
00387                                 $detail = wfMsgExt( 'import-logentry-interwiki-detail', array( 'content', 'parsemag' ),
00388                                         $contentCount, $interwiki );
00389                                 if ( $this->reason ) {
00390                                         $detail .=  wfMsgForContent( 'colon-separator' ) . $this->reason;
00391                                 }
00392                                 $log->addEntry( 'interwiki', $title, $detail );
00393                         }
00394 
00395                         $comment = $detail; // quick
00396                         $dbw = wfGetDB( DB_MASTER );
00397                         $latest = $title->getLatestRevID();
00398                         $nullRevision = Revision::newNullRevision( $dbw, $title->getArticleId(), $comment, true );
00399                         if (!is_null($nullRevision)) {
00400                                 $nullRevision->insertOn( $dbw );
00401                                 $page = WikiPage::factory( $title );
00402                                 # Update page record
00403                                 $page->updateRevisionOn( $dbw, $nullRevision );
00404                                 wfRunHooks( 'NewRevisionFromEditComplete', array( $page, $nullRevision, $latest, $this->getUser() ) );
00405                         }
00406                 } else {
00407                         $this->getOutput()->addHTML( "<li>" . Linker::linkKnown( $title ) . " " .
00408                                 wfMsgHtml( 'import-nonewrevisions' ) . "</li>\n" );
00409                 }
00410         }
00411 
00412         function close() {
00413                 $out = $this->getOutput();
00414                 if ( $this->mLogItemCount > 0 ) {
00415                         $msg = wfMsgExt( 'imported-log-entries', 'parseinline',
00416                                                 $this->getLanguage()->formatNum( $this->mLogItemCount ) );
00417                         $out->addHTML( Xml::tags( 'li', null, $msg ) );
00418                 } elseif( $this->mPageCount == 0 && $this->mLogItemCount == 0 ) {
00419                         $out->addHTML( "</ul>\n" );
00420                         return Status::newFatal( 'importnopages' );
00421                 }
00422                 $out->addHTML( "</ul>\n" );
00423 
00424                 return Status::newGood( $this->mPageCount );
00425         }
00426 }