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