Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 82
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
ImportableUploadRevisionImporter
0.00% covered (danger)
0.00%
0 / 81
0.00% covered (danger)
0.00%
0 / 5
420
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setNullRevisionCreation
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 newNotOkStatus
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 import
0.00% covered (danger)
0.00%
0 / 58
0.00% covered (danger)
0.00%
0 / 1
182
 downloadSource
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2
3namespace MediaWiki\Import;
4
5use MediaWiki\FileRepo\File\OldLocalFile;
6use MediaWiki\MediaWikiServices;
7use MediaWiki\User\User;
8use Psr\Log\LoggerInterface;
9use StatusValue;
10use Wikimedia\FileBackend\FSFile\TempFSFile;
11use Wikimedia\Rdbms\IDBAccessObject;
12
13/**
14 * @since 1.31
15 */
16class ImportableUploadRevisionImporter implements UploadRevisionImporter {
17
18    private bool $shouldCreateNullRevision = true;
19
20    public function __construct(
21        private readonly bool $enableUploads,
22        private readonly LoggerInterface $logger,
23    ) {
24    }
25
26    /**
27     * Setting this to false will deactivate the creation of a dummy revision as part of the upload
28     * process logging in LocalFile::recordUpload3, see T193621
29     *
30     * @param bool $shouldCreateNullRevision
31     */
32    public function setNullRevisionCreation( $shouldCreateNullRevision ) {
33        $this->shouldCreateNullRevision = $shouldCreateNullRevision;
34    }
35
36    /**
37     * @return StatusValue
38     */
39    private function newNotOkStatus() {
40        $statusValue = new StatusValue();
41        $statusValue->setOK( false );
42        return $statusValue;
43    }
44
45    /** @inheritDoc */
46    public function import( ImportableUploadRevision $importableRevision ) {
47        # Construct a file
48        $archiveName = $importableRevision->getArchiveName();
49        $localRepo = MediaWikiServices::getInstance()->getRepoGroup()->getLocalRepo();
50        if ( $archiveName ) {
51            $this->logger->debug( __METHOD__ . ": Importing archived file as $archiveName" );
52            $file = OldLocalFile::newFromArchiveName( $importableRevision->getTitle(),
53                $localRepo, $archiveName );
54        } else {
55            $file = $localRepo->newFile( $importableRevision->getTitle() );
56            $file->load( IDBAccessObject::READ_LATEST );
57            $this->logger->debug( __METHOD__ . ': Importing new file as ' . $file->getName() );
58            if ( $file->exists() && $file->getTimestamp() > $importableRevision->getTimestamp() ) {
59                $archiveName = $importableRevision->getTimestamp() . '!' . $file->getName();
60                $file = OldLocalFile::newFromArchiveName( $importableRevision->getTitle(),
61                    $localRepo, $archiveName );
62                $this->logger->debug( __METHOD__ . ": File already exists; importing as $archiveName" );
63            }
64        }
65        if ( !$file ) {
66            $this->logger->debug( __METHOD__ . ': Bad file for ' . $importableRevision->getTitle() );
67            return $this->newNotOkStatus();
68        }
69
70        # Get the file source or download if necessary
71        $source = $importableRevision->getFileSrc();
72        $autoDeleteSource = $importableRevision->isTempSrc();
73        if ( $source === '' ) {
74            $source = $this->downloadSource( $importableRevision );
75            $autoDeleteSource = true;
76        }
77        if ( $source === '' ) {
78            $this->logger->debug( __METHOD__ . ": Could not fetch remote file." );
79            return $this->newNotOkStatus();
80        }
81
82        $tmpFile = new TempFSFile( $source );
83        if ( $autoDeleteSource ) {
84            $tmpFile->autocollect();
85        }
86
87        $sha1File = ltrim( sha1_file( $source ), '0' );
88        $sha1 = $importableRevision->getSha1();
89        if ( $sha1 && ( $sha1 !== $sha1File ) ) {
90            $this->logger->debug( __METHOD__ . ": Corrupt file $source." );
91            return $this->newNotOkStatus();
92        }
93
94        $user = $importableRevision->getUserObj()
95            ?: User::newFromName( $importableRevision->getUser(), false );
96
97        # Do the actual upload
98        if ( $file instanceof OldLocalFile ) {
99            $status = $file->uploadOld(
100                $source,
101                $importableRevision->getTimestamp(),
102                $importableRevision->getComment(),
103                $user
104            );
105        } else {
106            $flags = 0;
107            $status = $file->upload(
108                $source,
109                $importableRevision->getComment(),
110                $importableRevision->getComment(),
111                $flags,
112                false,
113                $importableRevision->getTimestamp(),
114                $user,
115                [],
116                $this->shouldCreateNullRevision
117            );
118        }
119
120        if ( $status->isGood() ) {
121            $this->logger->debug( __METHOD__ . ": Successful" );
122        } else {
123            $this->logger->debug( __METHOD__ . ': failed: ' . $status->getHTML() );
124        }
125
126        return $status;
127    }
128
129    /**
130     * @param ImportableUploadRevision $wikiRevision
131     *
132     * @return string|false
133     */
134    private function downloadSource( ImportableUploadRevision $wikiRevision ) {
135        if ( !$this->enableUploads ) {
136            return false;
137        }
138
139        $tempo = tempnam( wfTempDir(), 'download' );
140        $f = fopen( $tempo, 'wb' );
141        if ( !$f ) {
142            $this->logger->debug( "IMPORT: couldn't write to temp file $tempo" );
143            return false;
144        }
145
146        // @todo FIXME!
147        $src = $wikiRevision->getSrc();
148        $data = MediaWikiServices::getInstance()->getHttpRequestFactory()->
149            get( $src, [], __METHOD__ );
150        if ( !$data ) {
151            $this->logger->debug( "IMPORT: couldn't fetch source $src" );
152            fclose( $f );
153            unlink( $tempo );
154            return false;
155        }
156
157        fwrite( $f, $data );
158        fclose( $f );
159
160        return $tempo;
161    }
162
163}
164
165/** @deprecated class alias since 1.46 */
166class_alias( ImportableUploadRevisionImporter::class, 'ImportableUploadRevisionImporter' );