Completed
Branch master (939199)
by
unknown
39:35
created

includes/specials/SpecialImport.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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 $sourceName = false;
34
	private $interwiki = false;
35
	private $subproject;
36
	private $fullInterwikiPrefix;
37
	private $mapping = 'default';
38
	private $namespace;
39
	private $rootpage = '';
40
	private $frompage = '';
41
	private $logcomment = false;
42
	private $history = true;
43
	private $includeTemplates = false;
44
	private $pageLinkDepth;
45
	private $importSources;
46
47
	/**
48
	 * Constructor
49
	 */
50
	public function __construct() {
51
		parent::__construct( 'Import', 'import' );
52
	}
53
54
	public function doesWrites() {
55
		return true;
56
	}
57
58
	/**
59
	 * Execute
60
	 * @param string|null $par
61
	 * @throws PermissionsError
62
	 * @throws ReadOnlyError
63
	 */
64
	function execute( $par ) {
65
		$this->useTransactionalTimeLimit();
66
67
		$this->setHeaders();
68
		$this->outputHeader();
69
70
		$this->namespace = $this->getConfig()->get( 'ImportTargetNamespace' );
71
72
		$this->getOutput()->addModules( 'mediawiki.special.import' );
73
74
		$this->importSources = $this->getConfig()->get( 'ImportSources' );
75
		Hooks::run( 'ImportSources', [ &$this->importSources ] );
76
77
		$user = $this->getUser();
78
		if ( !$user->isAllowedAny( 'import', 'importupload' ) ) {
79
			throw new PermissionsError( 'import' );
80
		}
81
82
		# @todo Allow Title::getUserPermissionsErrors() to take an array
83
		# @todo FIXME: Title::checkSpecialsAndNSPermissions() has a very wierd expectation of what
84
		# getUserPermissionsErrors() might actually be used for, hence the 'ns-specialprotected'
85
		$errors = wfMergeErrorArrays(
86
			$this->getPageTitle()->getUserPermissionsErrors(
87
				'import', $user, true,
88
				[ 'ns-specialprotected', 'badaccess-group0', 'badaccess-groups' ]
89
			),
90
			$this->getPageTitle()->getUserPermissionsErrors(
91
				'importupload', $user, true,
92
				[ 'ns-specialprotected', 'badaccess-group0', 'badaccess-groups' ]
93
			)
94
		);
95
96
		if ( $errors ) {
97
			throw new PermissionsError( 'import', $errors );
98
		}
99
100
		$this->checkReadOnly();
101
102
		$request = $this->getRequest();
103
		if ( $request->wasPosted() && $request->getVal( 'action' ) == 'submit' ) {
104
			$this->doImport();
105
		}
106
		$this->showForm();
107
	}
108
109
	/**
110
	 * Do the actual import
111
	 */
112
	private function doImport() {
113
		$isUpload = false;
114
		$request = $this->getRequest();
115
		$this->sourceName = $request->getVal( "source" );
116
117
		$this->logcomment = $request->getText( 'log-comment' );
118
		$this->pageLinkDepth = $this->getConfig()->get( 'ExportMaxLinkDepth' ) == 0
119
			? 0
120
			: $request->getIntOrNull( 'pagelink-depth' );
121
122
		$this->mapping = $request->getVal( 'mapping' );
123
		if ( $this->mapping === 'namespace' ) {
124
			$this->namespace = $request->getIntOrNull( 'namespace' );
125
		} elseif ( $this->mapping === 'subpage' ) {
126
			$this->rootpage = $request->getText( 'rootpage' );
127
		} else {
128
			$this->mapping = 'default';
129
		}
130
131
		$user = $this->getUser();
132
		if ( !$user->matchEditToken( $request->getVal( 'editToken' ) ) ) {
133
			$source = Status::newFatal( 'import-token-mismatch' );
134
		} elseif ( $this->sourceName === 'upload' ) {
135
			$isUpload = true;
136
			if ( $user->isAllowed( 'importupload' ) ) {
137
				$source = ImportStreamSource::newFromUpload( "xmlimport" );
138
			} else {
139
				throw new PermissionsError( 'importupload' );
140
			}
141
		} elseif ( $this->sourceName === 'interwiki' ) {
142
			if ( !$user->isAllowed( 'import' ) ) {
143
				throw new PermissionsError( 'import' );
144
			}
145
			$this->interwiki = $this->fullInterwikiPrefix = $request->getVal( 'interwiki' );
146
			// does this interwiki have subprojects?
147
			$hasSubprojects = array_key_exists( $this->interwiki, $this->importSources );
148
			if ( !$hasSubprojects && !in_array( $this->interwiki, $this->importSources ) ) {
149
				$source = Status::newFatal( "import-invalid-interwiki" );
150
			} else {
151
				if ( $hasSubprojects ) {
152
					$this->subproject = $request->getVal( 'subproject' );
153
					$this->fullInterwikiPrefix .= ':' . $request->getVal( 'subproject' );
154
				}
155
				if ( $hasSubprojects &&
156
					!in_array( $this->subproject, $this->importSources[$this->interwiki] )
157
				) {
158
					$source = Status::newFatal( "import-invalid-interwiki" );
159
				} else {
160
					$this->history = $request->getCheck( 'interwikiHistory' );
161
					$this->frompage = $request->getText( "frompage" );
162
					$this->includeTemplates = $request->getCheck( 'interwikiTemplates' );
163
					$source = ImportStreamSource::newFromInterwiki(
164
						$this->fullInterwikiPrefix,
165
						$this->frompage,
166
						$this->history,
167
						$this->includeTemplates,
168
						$this->pageLinkDepth );
169
				}
170
			}
171
		} else {
172
			$source = Status::newFatal( "importunknownsource" );
173
		}
174
175
		$out = $this->getOutput();
176
		if ( !$source->isGood() ) {
177
			$out->wrapWikiMsg(
178
				"<p class=\"error\">\n$1\n</p>",
179
				[ 'importfailed', $source->getWikiText() ]
180
			);
181
		} else {
182
			$importer = new WikiImporter( $source->value, $this->getConfig() );
183
			if ( !is_null( $this->namespace ) ) {
184
				$importer->setTargetNamespace( $this->namespace );
185
			} elseif ( !is_null( $this->rootpage ) ) {
186
				$statusRootPage = $importer->setTargetRootPage( $this->rootpage );
187
				if ( !$statusRootPage->isGood() ) {
188
					$out->wrapWikiMsg(
189
						"<p class=\"error\">\n$1\n</p>",
190
						[
191
							'import-options-wrong',
192
							$statusRootPage->getWikiText(),
193
							count( $statusRootPage->getErrorsArray() )
194
						]
195
					);
196
197
					return;
198
				}
199
			}
200
201
			$out->addWikiMsg( "importstart" );
202
203
			$reporter = new ImportReporter(
204
				$importer,
205
				$isUpload,
206
				$this->fullInterwikiPrefix,
207
				$this->logcomment
208
			);
209
			$reporter->setContext( $this->getContext() );
210
			$exception = false;
211
212
			$reporter->open();
213
			try {
214
				$importer->doImport();
215
			} catch ( Exception $e ) {
216
				$exception = $e;
217
			}
218
			$result = $reporter->close();
219
220
			if ( $exception ) {
221
				# No source or XML parse error
222
				$out->wrapWikiMsg(
223
					"<p class=\"error\">\n$1\n</p>",
224
					[ 'importfailed', $exception->getMessage() ]
225
				);
226
			} elseif ( !$result->isGood() ) {
227
				# Zero revisions
228
				$out->wrapWikiMsg(
229
					"<p class=\"error\">\n$1\n</p>",
230
					[ 'importfailed', $result->getWikiText() ]
231
				);
232
			} else {
233
				# Success!
234
				$out->addWikiMsg( 'importsuccess' );
235
			}
236
			$out->addHTML( '<hr />' );
237
		}
238
	}
239
240
	private function getMappingFormPart( $sourceName ) {
241
		$isSameSourceAsBefore = ( $this->sourceName === $sourceName );
242
		$defaultNamespace = $this->getConfig()->get( 'ImportTargetNamespace' );
243
		return "<tr>
244
					<td>
245
					</td>
246
					<td class='mw-input'>" .
247
					Xml::radioLabel(
248
						$this->msg( 'import-mapping-default' )->text(),
249
						'mapping',
250
						'default',
251
						// mw-import-mapping-interwiki-default, mw-import-mapping-upload-default
252
						"mw-import-mapping-$sourceName-default",
253
						( $isSameSourceAsBefore ?
254
							( $this->mapping === 'default' ) :
255
							is_null( $defaultNamespace ) )
256
					) .
257
					"</td>
258
				</tr>
259
				<tr>
260
					<td>
261
					</td>
262
					<td class='mw-input'>" .
263
					Xml::radioLabel(
264
						$this->msg( 'import-mapping-namespace' )->text(),
265
						'mapping',
266
						'namespace',
267
						// mw-import-mapping-interwiki-namespace, mw-import-mapping-upload-namespace
268
						"mw-import-mapping-$sourceName-namespace",
269
						( $isSameSourceAsBefore ?
270
							( $this->mapping === 'namespace' ) :
271
							!is_null( $defaultNamespace ) )
272
					) . ' ' .
273
					Html::namespaceSelector(
274
						[
275
							'selected' => ( $isSameSourceAsBefore ?
276
								$this->namespace :
277
								( $defaultNamespace || '' ) ),
278
						], [
279
							'name' => "namespace",
280
							// mw-import-namespace-interwiki, mw-import-namespace-upload
281
							'id' => "mw-import-namespace-$sourceName",
282
							'class' => 'namespaceselector',
283
						]
284
					) .
285
					"</td>
286
				</tr>
287
				<tr>
288
					<td>
289
					</td>
290
					<td class='mw-input'>" .
291
					Xml::radioLabel(
292
						$this->msg( 'import-mapping-subpage' )->text(),
293
						'mapping',
294
						'subpage',
295
						// mw-import-mapping-interwiki-subpage, mw-import-mapping-upload-subpage
296
						"mw-import-mapping-$sourceName-subpage",
297
						( $isSameSourceAsBefore ? ( $this->mapping === 'subpage' ) : '' )
298
					) . ' ' .
299
					Xml::input( 'rootpage', 50,
300
						( $isSameSourceAsBefore ? $this->rootpage : '' ),
301
						[
302
							// Should be "mw-import-rootpage-...", but we keep this inaccurate
303
							// ID for legacy reasons
304
							// mw-interwiki-rootpage-interwiki, mw-interwiki-rootpage-upload
305
							'id' => "mw-interwiki-rootpage-$sourceName",
306
							'type' => 'text'
307
						]
308
					) . ' ' .
309
					"</td>
310
				</tr>";
311
	}
312
313
	private function showForm() {
314
		$action = $this->getPageTitle()->getLocalURL( [ 'action' => 'submit' ] );
315
		$user = $this->getUser();
316
		$out = $this->getOutput();
317
		$this->addHelpLink( '//meta.wikimedia.org/wiki/Special:MyLanguage/Help:Import', true );
318
319
		if ( $user->isAllowed( 'importupload' ) ) {
320
			$mappingSelection = $this->getMappingFormPart( 'upload' );
321
			$out->addHTML(
322
				Xml::fieldset( $this->msg( 'import-upload' )->text() ) .
323
					Xml::openElement(
324
						'form',
325
						[
326
							'enctype' => 'multipart/form-data',
327
							'method' => 'post',
328
							'action' => $action,
329
							'id' => 'mw-import-upload-form'
330
						]
331
					) .
332
					$this->msg( 'importtext' )->parseAsBlock() .
333
					Html::hidden( 'action', 'submit' ) .
334
					Html::hidden( 'source', 'upload' ) .
335
					Xml::openElement( 'table', [ 'id' => 'mw-import-table-upload' ] ) .
336
					"<tr>
337
					<td class='mw-label'>" .
338
					Xml::label( $this->msg( 'import-upload-filename' )->text(), 'xmlimport' ) .
339
					"</td>
340
					<td class='mw-input'>" .
341
					Html::input( 'xmlimport', '', 'file', [ 'id' => 'xmlimport' ] ) . ' ' .
342
					"</td>
343
				</tr>
344
				<tr>
345
					<td class='mw-label'>" .
346
					Xml::label( $this->msg( 'import-comment' )->text(), 'mw-import-comment' ) .
347
					"</td>
348
					<td class='mw-input'>" .
349
					Xml::input( 'log-comment', 50,
350
						( $this->sourceName === 'upload' ? $this->logcomment : '' ),
351
						[ 'id' => 'mw-import-comment', 'type' => 'text' ] ) . ' ' .
352
					"</td>
353
				</tr>
354
				$mappingSelection
355
				<tr>
356
					<td></td>
357
					<td class='mw-submit'>" .
358
					Xml::submitButton( $this->msg( 'uploadbtn' )->text() ) .
359
					"</td>
360
				</tr>" .
361
					Xml::closeElement( 'table' ) .
362
					Html::hidden( 'editToken', $user->getEditToken() ) .
363
					Xml::closeElement( 'form' ) .
364
					Xml::closeElement( 'fieldset' )
365
			);
366
		} else {
367
			if ( empty( $this->importSources ) ) {
368
				$out->addWikiMsg( 'importnosources' );
369
			}
370
		}
371
372
		if ( $user->isAllowed( 'import' ) && !empty( $this->importSources ) ) {
373
			# Show input field for import depth only if $wgExportMaxLinkDepth > 0
374
			$importDepth = '';
375
			if ( $this->getConfig()->get( 'ExportMaxLinkDepth' ) > 0 ) {
376
				$importDepth = "<tr>
377
							<td class='mw-label'>" .
378
					$this->msg( 'export-pagelinks' )->parse() .
379
					"</td>
380
							<td class='mw-input'>" .
381
					Xml::input( 'pagelink-depth', 3, 0 ) .
382
					"</td>
383
				</tr>";
384
			}
385
			$mappingSelection = $this->getMappingFormPart( 'interwiki' );
386
387
			$out->addHTML(
388
				Xml::fieldset( $this->msg( 'importinterwiki' )->text() ) .
389
					Xml::openElement(
390
						'form',
391
						[
392
							'method' => 'post',
393
							'action' => $action,
394
							'id' => 'mw-import-interwiki-form'
395
						]
396
					) .
397
					$this->msg( 'import-interwiki-text' )->parseAsBlock() .
398
					Html::hidden( 'action', 'submit' ) .
399
					Html::hidden( 'source', 'interwiki' ) .
400
					Html::hidden( 'editToken', $user->getEditToken() ) .
401
					Xml::openElement( 'table', [ 'id' => 'mw-import-table-interwiki' ] ) .
402
					"<tr>
403
					<td class='mw-label'>" .
404
					Xml::label( $this->msg( 'import-interwiki-sourcewiki' )->text(), 'interwiki' ) .
405
					"</td>
406
					<td class='mw-input'>" .
407
					Xml::openElement(
408
						'select',
409
						[ 'name' => 'interwiki', 'id' => 'interwiki' ]
410
					)
411
			);
412
413
			$needSubprojectField = false;
414
			foreach ( $this->importSources as $key => $value ) {
415
				if ( is_int( $key ) ) {
416
					$key = $value;
417
				} elseif ( $value !== $key ) {
418
					$needSubprojectField = true;
419
				}
420
421
				$attribs = [
422
					'value' => $key,
423
				];
424
				if ( is_array( $value ) ) {
425
					$attribs['data-subprojects'] = implode( ' ', $value );
426
				}
427
				if ( $this->interwiki === $key ) {
428
					$attribs['selected'] = 'selected';
429
				}
430
				$out->addHTML( Html::element( 'option', $attribs, $key ) );
431
			}
432
433
			$out->addHTML(
434
				Xml::closeElement( 'select' )
435
			);
436
437
			if ( $needSubprojectField ) {
438
				$out->addHTML(
439
					Xml::openElement(
440
						'select',
441
						[ 'name' => 'subproject', 'id' => 'subproject' ]
442
					)
443
				);
444
445
				$subprojectsToAdd = [];
446
				foreach ( $this->importSources as $key => $value ) {
447
					if ( is_array( $value ) ) {
448
						$subprojectsToAdd = array_merge( $subprojectsToAdd, $value );
449
					}
450
				}
451
				$subprojectsToAdd = array_unique( $subprojectsToAdd );
452
				sort( $subprojectsToAdd );
453
				foreach ( $subprojectsToAdd as $subproject ) {
454
					$out->addHTML( Xml::option( $subproject, $subproject, $this->subproject === $subproject ) );
455
				}
456
457
				$out->addHTML(
458
					Xml::closeElement( 'select' )
459
				);
460
			}
461
462
			$out->addHTML(
463
					"</td>
464
				</tr>
465
				<tr>
466
					<td class='mw-label'>" .
467
					Xml::label( $this->msg( 'import-interwiki-sourcepage' )->text(), 'frompage' ) .
468
					"</td>
469
					<td class='mw-input'>" .
470
					Xml::input( 'frompage', 50, $this->frompage, [ 'id' => 'frompage' ] ) .
471
					"</td>
472
				</tr>
473
				<tr>
474
					<td>
475
					</td>
476
					<td class='mw-input'>" .
477
					Xml::checkLabel(
478
						$this->msg( 'import-interwiki-history' )->text(),
479
						'interwikiHistory',
480
						'interwikiHistory',
481
						$this->history
482
					) .
483
					"</td>
484
				</tr>
485
				<tr>
486
					<td>
487
					</td>
488
					<td class='mw-input'>" .
489
					Xml::checkLabel(
490
						$this->msg( 'import-interwiki-templates' )->text(),
491
						'interwikiTemplates',
492
						'interwikiTemplates',
493
						$this->includeTemplates
494
					) .
495
					"</td>
496
				</tr>
497
				$importDepth
498
				<tr>
499
					<td class='mw-label'>" .
500
					Xml::label( $this->msg( 'import-comment' )->text(), 'mw-interwiki-comment' ) .
501
					"</td>
502
					<td class='mw-input'>" .
503
					Xml::input( 'log-comment', 50,
504
						( $this->sourceName === 'interwiki' ? $this->logcomment : '' ),
505
						[ 'id' => 'mw-interwiki-comment', 'type' => 'text' ] ) . ' ' .
506
					"</td>
507
				</tr>
508
				$mappingSelection
509
				<tr>
510
					<td>
511
					</td>
512
					<td class='mw-submit'>" .
513
					Xml::submitButton(
514
						$this->msg( 'import-interwiki-submit' )->text(),
515
						Linker::tooltipAndAccesskeyAttribs( 'import' )
516
					) .
517
					"</td>
518
				</tr>" .
519
					Xml::closeElement( 'table' ) .
520
					Xml::closeElement( 'form' ) .
521
					Xml::closeElement( 'fieldset' )
522
			);
523
		}
524
	}
525
526
	protected function getGroupName() {
527
		return 'pagetools';
528
	}
529
}
530
531
/**
532
 * Reporting callback
533
 * @ingroup SpecialPage
534
 */
535
class ImportReporter extends ContextSource {
536
	private $reason = false;
537
	private $mOriginalLogCallback = null;
538
	private $mOriginalPageOutCallback = null;
539
	private $mLogItemCount = 0;
540
541
	/**
542
	 * @param WikiImporter $importer
543
	 * @param bool $upload
544
	 * @param string $interwiki
545
	 * @param string|bool $reason
546
	 */
547
	function __construct( $importer, $upload, $interwiki, $reason = false ) {
548
		$this->mOriginalPageOutCallback =
549
			$importer->setPageOutCallback( [ $this, 'reportPage' ] );
550
		$this->mOriginalLogCallback =
551
			$importer->setLogItemCallback( [ $this, 'reportLogItem' ] );
552
		$importer->setNoticeCallback( [ $this, 'reportNotice' ] );
553
		$this->mPageCount = 0;
554
		$this->mIsUpload = $upload;
555
		$this->mInterwiki = $interwiki;
556
		$this->reason = $reason;
0 ignored issues
show
Documentation Bug introduced by
It seems like $reason can also be of type string. However, the property $reason is declared as type boolean. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
557
	}
558
559
	function open() {
560
		$this->getOutput()->addHTML( "<ul>\n" );
561
	}
562
563
	function reportNotice( $msg, array $params ) {
564
		$this->getOutput()->addHTML(
565
			Html::element( 'li', [], $this->msg( $msg, $params )->text() )
566
		);
567
	}
568
569
	function reportLogItem( /* ... */ ) {
570
		$this->mLogItemCount++;
571
		if ( is_callable( $this->mOriginalLogCallback ) ) {
572
			call_user_func_array( $this->mOriginalLogCallback, func_get_args() );
573
		}
574
	}
575
576
	/**
577
	 * @param Title $title
578
	 * @param ForeignTitle $foreignTitle
579
	 * @param int $revisionCount
580
	 * @param int $successCount
581
	 * @param array $pageInfo
582
	 * @return void
583
	 */
584
	public function reportPage( $title, $foreignTitle, $revisionCount,
585
			$successCount, $pageInfo ) {
586
		$args = func_get_args();
587
		call_user_func_array( $this->mOriginalPageOutCallback, $args );
588
589
		if ( $title === null ) {
590
			# Invalid or non-importable title; a notice is already displayed
591
			return;
592
		}
593
594
		$this->mPageCount++;
595
596
		if ( $successCount > 0 ) {
597
			// <bdi> prevents jumbling of the versions count
598
			// in RTL wikis in case the page title is LTR
599
			$this->getOutput()->addHTML(
600
				"<li>" . Linker::linkKnown( $title ) . " " .
601
					"<bdi>" .
602
					$this->msg( 'import-revision-count' )->numParams( $successCount )->escaped() .
603
					"</bdi>" .
604
					"</li>\n"
605
			);
606
607
			$logParams = [ '4:number:count' => $successCount ];
608
			if ( $this->mIsUpload ) {
609
				$detail = $this->msg( 'import-logentry-upload-detail' )->numParams(
610
					$successCount )->inContentLanguage()->text();
611
				$action = 'upload';
612
			} else {
613
				$pageTitle = $foreignTitle->getFullText();
614
				$fullInterwikiPrefix = $this->mInterwiki;
615
				Hooks::run( 'ImportLogInterwikiLink', [ &$fullInterwikiPrefix, &$pageTitle ] );
616
617
				$interwikiTitleStr = $fullInterwikiPrefix . ':' . $pageTitle;
618
				$interwiki = '[[:' . $interwikiTitleStr . ']]';
619
				$detail = $this->msg( 'import-logentry-interwiki-detail' )->numParams(
620
					$successCount )->params( $interwiki )->inContentLanguage()->text();
621
				$action = 'interwiki';
622
				$logParams['5:title-link:interwiki'] = $interwikiTitleStr;
623
			}
624
			if ( $this->reason ) {
625
				$detail .= $this->msg( 'colon-separator' )->inContentLanguage()->text()
626
					. $this->reason;
627
			}
628
629
			$logEntry = new ManualLogEntry( 'import', $action );
630
			$logEntry->setTarget( $title );
631
			$logEntry->setComment( $this->reason );
632
			$logEntry->setPerformer( $this->getUser() );
633
			$logEntry->setParameters( $logParams );
634
			$logid = $logEntry->insert();
635
			$logEntry->publish( $logid );
636
637
			$comment = $detail; // quick
638
			$dbw = wfGetDB( DB_MASTER );
639
			$latest = $title->getLatestRevID();
640
			$nullRevision = Revision::newNullRevision(
641
				$dbw,
642
				$title->getArticleID(),
643
				$comment,
644
				true,
645
				$this->getUser()
646
			);
647
648
			if ( !is_null( $nullRevision ) ) {
649
				$nullRevision->insertOn( $dbw );
650
				$page = WikiPage::factory( $title );
651
				# Update page record
652
				$page->updateRevisionOn( $dbw, $nullRevision );
653
				Hooks::run(
654
					'NewRevisionFromEditComplete',
655
					[ $page, $nullRevision, $latest, $this->getUser() ]
656
				);
657
			}
658
		} else {
659
			$this->getOutput()->addHTML( "<li>" . Linker::linkKnown( $title ) . " " .
660
				$this->msg( 'import-nonewrevisions' )->escaped() . "</li>\n" );
661
		}
662
	}
663
664
	function close() {
665
		$out = $this->getOutput();
666
		if ( $this->mLogItemCount > 0 ) {
667
			$msg = $this->msg( 'imported-log-entries' )->numParams( $this->mLogItemCount )->parse();
668
			$out->addHTML( Xml::tags( 'li', null, $msg ) );
669
		} elseif ( $this->mPageCount == 0 && $this->mLogItemCount == 0 ) {
670
			$out->addHTML( "</ul>\n" );
671
672
			return Status::newFatal( 'importnopages' );
673
		}
674
		$out->addHTML( "</ul>\n" );
675
676
		return Status::newGood( $this->mPageCount );
677
	}
678
}
679