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