Merge "Exclude redirects from Special:Fewestrevisions"
[lhc/web/wiklou.git] / includes / import / WikiRevision.php
1 <?php
2 /**
3 * MediaWiki page data importer.
4 *
5 * Copyright © 2003,2005 Brion Vibber <brion@pobox.com>
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 use MediaWiki\Logger\LoggerFactory;
27 use MediaWiki\MediaWikiServices;
28
29 /**
30 * Represents a revision, log entry or upload during the import process.
31 * This class sticks closely to the structure of the XML dump.
32 *
33 * @since 1.2
34 *
35 * @ingroup SpecialPage
36 */
37 class WikiRevision implements ImportableUploadRevision, ImportableOldRevision {
38
39 /**
40 * @since 1.2
41 * @var Title
42 */
43 public $title = null;
44
45 /**
46 * @since 1.6.4
47 * @var int
48 */
49 public $id = 0;
50
51 /**
52 * @since 1.2
53 * @var string
54 */
55 public $timestamp = "20010115000000";
56
57 /**
58 * @since 1.2
59 * @var string
60 */
61 public $user_text = "";
62
63 /**
64 * @since 1.27
65 * @var User
66 */
67 public $userObj = null;
68
69 /**
70 * @since 1.21
71 * @var string
72 */
73 public $model = null;
74
75 /**
76 * @since 1.21
77 * @var string
78 */
79 public $format = null;
80
81 /**
82 * @since 1.2
83 * @var string
84 */
85 public $text = "";
86
87 /**
88 * @since 1.12.2
89 * @var int
90 */
91 protected $size;
92
93 /**
94 * @since 1.21
95 * @var Content
96 */
97 public $content = null;
98
99 /**
100 * @since 1.24
101 * @var ContentHandler
102 */
103 protected $contentHandler = null;
104
105 /**
106 * @since 1.2.6
107 * @var string
108 */
109 public $comment = "";
110
111 /**
112 * @since 1.5.7
113 * @var bool
114 */
115 public $minor = false;
116
117 /**
118 * @since 1.12.2
119 * @var string
120 */
121 public $type = "";
122
123 /**
124 * @since 1.12.2
125 * @var string
126 */
127 public $action = "";
128
129 /**
130 * @since 1.12.2
131 * @var string
132 */
133 public $params = "";
134
135 /**
136 * @since 1.17
137 * @var string
138 */
139 public $fileSrc = '';
140
141 /**
142 * @since 1.17
143 * @var bool|string
144 */
145 public $sha1base36 = false;
146
147 /**
148 * @since 1.17
149 * @var string
150 */
151 public $archiveName = '';
152
153 /**
154 * @since 1.12.2
155 */
156 protected $filename;
157
158 /**
159 * @since 1.12.2
160 * @var string|null
161 */
162 protected $src = null;
163
164 /**
165 * @since 1.18
166 * @var bool
167 * @todo Unused?
168 */
169 public $isTemp = false;
170
171 /**
172 * @since 1.18
173 * @deprecated 1.29 use Wikirevision::isTempSrc()
174 * First written to in 43d5d3b682cc1733ad01a837d11af4a402d57e6a
175 * Actually introduced in 52cd34acf590e5be946b7885ffdc13a157c1c6cf
176 */
177 public $fileIsTemp;
178
179 /** @var bool */
180 private $mNoUpdates = false;
181
182 /** @var Config $config */
183 private $config;
184
185 public function __construct( Config $config ) {
186 $this->config = $config;
187 }
188
189 /**
190 * @since 1.7 taking a Title object (string before)
191 * @param Title $title
192 * @throws MWException
193 */
194 public function setTitle( $title ) {
195 if ( is_object( $title ) ) {
196 $this->title = $title;
197 } elseif ( is_null( $title ) ) {
198 throw new MWException( "WikiRevision given a null title in import. "
199 . "You may need to adjust \$wgLegalTitleChars." );
200 } else {
201 throw new MWException( "WikiRevision given non-object title in import." );
202 }
203 }
204
205 /**
206 * @since 1.6.4
207 * @param int $id
208 */
209 public function setID( $id ) {
210 $this->id = $id;
211 }
212
213 /**
214 * @since 1.2
215 * @param string $ts
216 */
217 public function setTimestamp( $ts ) {
218 # 2003-08-05T18:30:02Z
219 $this->timestamp = wfTimestamp( TS_MW, $ts );
220 }
221
222 /**
223 * @since 1.2
224 * @param string $user
225 */
226 public function setUsername( $user ) {
227 $this->user_text = $user;
228 }
229
230 /**
231 * @since 1.27
232 * @param User $user
233 */
234 public function setUserObj( $user ) {
235 $this->userObj = $user;
236 }
237
238 /**
239 * @since 1.2
240 * @param string $ip
241 */
242 public function setUserIP( $ip ) {
243 $this->user_text = $ip;
244 }
245
246 /**
247 * @since 1.21
248 * @param string $model
249 */
250 public function setModel( $model ) {
251 $this->model = $model;
252 }
253
254 /**
255 * @since 1.21
256 * @param string $format
257 */
258 public function setFormat( $format ) {
259 $this->format = $format;
260 }
261
262 /**
263 * @since 1.2
264 * @param string $text
265 */
266 public function setText( $text ) {
267 $this->text = $text;
268 }
269
270 /**
271 * @since 1.2.6
272 * @param string $text
273 */
274 public function setComment( $text ) {
275 $this->comment = $text;
276 }
277
278 /**
279 * @since 1.5.7
280 * @param bool $minor
281 */
282 public function setMinor( $minor ) {
283 $this->minor = (bool)$minor;
284 }
285
286 /**
287 * @since 1.12.2
288 * @param string|null $src
289 */
290 public function setSrc( $src ) {
291 $this->src = $src;
292 }
293
294 /**
295 * @since 1.17
296 * @param string $src
297 * @param bool $isTemp
298 */
299 public function setFileSrc( $src, $isTemp ) {
300 $this->fileSrc = $src;
301 $this->fileIsTemp = $isTemp;
302 $this->isTemp = $isTemp;
303 }
304
305 /**
306 * @since 1.17
307 * @param string $sha1base36
308 */
309 public function setSha1Base36( $sha1base36 ) {
310 $this->sha1base36 = $sha1base36;
311 }
312
313 /**
314 * @since 1.12.2
315 * @param string $filename
316 */
317 public function setFilename( $filename ) {
318 $this->filename = $filename;
319 }
320
321 /**
322 * @since 1.17
323 * @param string $archiveName
324 */
325 public function setArchiveName( $archiveName ) {
326 $this->archiveName = $archiveName;
327 }
328
329 /**
330 * @since 1.12.2
331 * @param int $size
332 */
333 public function setSize( $size ) {
334 $this->size = intval( $size );
335 }
336
337 /**
338 * @since 1.12.2
339 * @param string $type
340 */
341 public function setType( $type ) {
342 $this->type = $type;
343 }
344
345 /**
346 * @since 1.12.2
347 * @param string $action
348 */
349 public function setAction( $action ) {
350 $this->action = $action;
351 }
352
353 /**
354 * @since 1.12.2
355 * @param array $params
356 */
357 public function setParams( $params ) {
358 $this->params = $params;
359 }
360
361 /**
362 * @since 1.18
363 * @param bool $noupdates
364 */
365 public function setNoUpdates( $noupdates ) {
366 $this->mNoUpdates = $noupdates;
367 }
368
369 /**
370 * @since 1.2
371 * @return Title
372 */
373 public function getTitle() {
374 return $this->title;
375 }
376
377 /**
378 * @since 1.6.4
379 * @return int
380 */
381 public function getID() {
382 return $this->id;
383 }
384
385 /**
386 * @since 1.2
387 * @return string
388 */
389 public function getTimestamp() {
390 return $this->timestamp;
391 }
392
393 /**
394 * @since 1.2
395 * @return string
396 */
397 public function getUser() {
398 return $this->user_text;
399 }
400
401 /**
402 * @since 1.27
403 * @return User
404 */
405 public function getUserObj() {
406 return $this->userObj;
407 }
408
409 /**
410 * @since 1.2
411 * @return string
412 */
413 public function getText() {
414 return $this->text;
415 }
416
417 /**
418 * @since 1.24
419 * @return ContentHandler
420 */
421 public function getContentHandler() {
422 if ( is_null( $this->contentHandler ) ) {
423 $this->contentHandler = ContentHandler::getForModelID( $this->getModel() );
424 }
425
426 return $this->contentHandler;
427 }
428
429 /**
430 * @since 1.21
431 * @return Content
432 */
433 public function getContent() {
434 if ( is_null( $this->content ) ) {
435 $handler = $this->getContentHandler();
436 $this->content = $handler->unserializeContent( $this->text, $this->getFormat() );
437 }
438
439 return $this->content;
440 }
441
442 /**
443 * @since 1.21
444 * @return string
445 */
446 public function getModel() {
447 if ( is_null( $this->model ) ) {
448 $this->model = $this->getTitle()->getContentModel();
449 }
450
451 return $this->model;
452 }
453
454 /**
455 * @since 1.21
456 * @return string
457 */
458 public function getFormat() {
459 if ( is_null( $this->format ) ) {
460 $this->format = $this->getContentHandler()->getDefaultFormat();
461 }
462
463 return $this->format;
464 }
465
466 /**
467 * @since 1.2.6
468 * @return string
469 */
470 public function getComment() {
471 return $this->comment;
472 }
473
474 /**
475 * @since 1.5.7
476 * @return bool
477 */
478 public function getMinor() {
479 return $this->minor;
480 }
481
482 /**
483 * @since 1.12.2
484 * @return string|null
485 */
486 public function getSrc() {
487 return $this->src;
488 }
489
490 /**
491 * @since 1.17
492 * @return bool|string
493 */
494 public function getSha1() {
495 if ( $this->sha1base36 ) {
496 return Wikimedia\base_convert( $this->sha1base36, 36, 16 );
497 }
498 return false;
499 }
500
501 /**
502 * @since 1.31
503 * @return bool|string
504 */
505 public function getSha1Base36() {
506 if ( $this->sha1base36 ) {
507 return $this->sha1base36;
508 }
509 return false;
510 }
511
512 /**
513 * @since 1.17
514 * @return string
515 */
516 public function getFileSrc() {
517 return $this->fileSrc;
518 }
519
520 /**
521 * @since 1.17
522 * @return bool
523 */
524 public function isTempSrc() {
525 return $this->isTemp;
526 }
527
528 /**
529 * @since 1.12.2
530 * @return mixed
531 */
532 public function getFilename() {
533 return $this->filename;
534 }
535
536 /**
537 * @since 1.17
538 * @return string
539 */
540 public function getArchiveName() {
541 return $this->archiveName;
542 }
543
544 /**
545 * @since 1.12.2
546 * @return mixed
547 */
548 public function getSize() {
549 return $this->size;
550 }
551
552 /**
553 * @since 1.12.2
554 * @return string
555 */
556 public function getType() {
557 return $this->type;
558 }
559
560 /**
561 * @since 1.12.2
562 * @return string
563 */
564 public function getAction() {
565 return $this->action;
566 }
567
568 /**
569 * @since 1.12.2
570 * @return string
571 */
572 public function getParams() {
573 return $this->params;
574 }
575
576 /**
577 * @since 1.4.1
578 * @deprecated in 1.31. Use OldRevisionImporter::import
579 * @return bool
580 */
581 public function importOldRevision() {
582 if ( $this->mNoUpdates ) {
583 $importer = MediaWikiServices::getInstance()->getWikiRevisionOldRevisionImporterNoUpdates();
584 } else {
585 $importer = MediaWikiServices::getInstance()->getWikiRevisionOldRevisionImporter();
586 }
587 return $importer->import( $this );
588 }
589
590 /**
591 * @since 1.12.2
592 * @return bool
593 */
594 public function importLogItem() {
595 $dbw = wfGetDB( DB_MASTER );
596
597 $user = $this->getUserObj() ?: User::newFromName( $this->getUser(), false );
598
599 # @todo FIXME: This will not record autoblocks
600 if ( !$this->getTitle() ) {
601 wfDebug( __METHOD__ . ": skipping invalid {$this->type}/{$this->action} log time, timestamp " .
602 $this->timestamp . "\n" );
603 return false;
604 }
605 # Check if it exists already
606 // @todo FIXME: Use original log ID (better for backups)
607 $prior = $dbw->selectField( 'logging', '1',
608 [ 'log_type' => $this->getType(),
609 'log_action' => $this->getAction(),
610 'log_timestamp' => $dbw->timestamp( $this->timestamp ),
611 'log_namespace' => $this->getTitle()->getNamespace(),
612 'log_title' => $this->getTitle()->getDBkey(),
613 'log_params' => $this->params ],
614 __METHOD__
615 );
616 // @todo FIXME: This could fail slightly for multiple matches :P
617 if ( $prior ) {
618 wfDebug( __METHOD__
619 . ": skipping existing item for Log:{$this->type}/{$this->action}, timestamp "
620 . $this->timestamp . "\n" );
621 return false;
622 }
623 $data = [
624 'log_type' => $this->type,
625 'log_action' => $this->action,
626 'log_timestamp' => $dbw->timestamp( $this->timestamp ),
627 'log_namespace' => $this->getTitle()->getNamespace(),
628 'log_title' => $this->getTitle()->getDBkey(),
629 'log_params' => $this->params
630 ] + CommentStore::getStore()->insert( $dbw, 'log_comment', $this->getComment() )
631 + ActorMigration::newMigration()->getInsertValues( $dbw, 'log_user', $user );
632 $dbw->insert( 'logging', $data, __METHOD__ );
633
634 return true;
635 }
636
637 /**
638 * @since 1.12.2
639 * @deprecated in 1.31. Use UploadRevisionImporter::import
640 * @return bool
641 */
642 public function importUpload() {
643 $importer = MediaWikiServices::getInstance()->getWikiRevisionUploadImporter();
644 $statusValue = $importer->import( $this );
645 return $statusValue->isGood();
646 }
647
648 /**
649 * @since 1.12.2
650 * @deprecated in 1.31. No replacement
651 * @return bool|string
652 */
653 public function downloadSource() {
654 $importer = new ImportableUploadRevisionImporter(
655 $this->config->get( 'EnableUploads' ),
656 LoggerFactory::getInstance( 'UploadRevisionImporter' )
657 );
658 return $importer->downloadSource( $this );
659 }
660
661 }