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