[ Index ] |
PHP Cross Reference of MediaWiki-1.24.0 |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 14:03:12 2014 | Cross-referenced by PHPXref 0.7.1 |