MediaWiki master
UploadForm.php
Go to the documentation of this file.
1<?php
32use Wikimedia\RequestTimeout\TimeoutException;
33
37class UploadForm extends HTMLForm {
38 protected $mWatch;
39 protected $mForReUpload;
40 protected $mSessionKey;
43 protected $mDestFile;
44
45 protected $mComment;
47 protected $mTextTop;
50
51 protected $mSourceIds;
52
53 protected $mMaxFileSize = [];
54
56 protected $mMaxUploadSize = [];
57
58 private LocalRepo $localRepo;
59 private Language $contentLanguage;
60 private NamespaceInfo $nsInfo;
61 private HookRunner $hookRunner;
62
72 public function __construct(
73 array $options = [],
74 IContextSource $context = null,
75 LinkRenderer $linkRenderer = null,
76 LocalRepo $localRepo = null,
77 Language $contentLanguage = null,
78 NamespaceInfo $nsInfo = null,
79 HookContainer $hookContainer = null
80 ) {
81 if ( $context instanceof IContextSource ) {
82 $this->setContext( $context );
83 }
84
85 $services = MediaWikiServices::getInstance();
86 if ( !$linkRenderer ) {
87 $linkRenderer = $services->getLinkRenderer();
88 }
89 if ( !$localRepo ) {
90 $localRepo = $services->getRepoGroup()->getLocalRepo();
91 }
92 if ( !$contentLanguage ) {
93 $contentLanguage = $services->getContentLanguage();
94 }
95 if ( !$nsInfo ) {
96 $nsInfo = $services->getNamespaceInfo();
97 }
98 $this->localRepo = $localRepo;
99 $this->contentLanguage = $contentLanguage;
100 $this->nsInfo = $nsInfo;
101 $this->hookRunner = new HookRunner( $hookContainer ?? $services->getHookContainer() );
102
103 $this->mWatch = !empty( $options['watch'] );
104 $this->mForReUpload = !empty( $options['forreupload'] );
105 $this->mSessionKey = $options['sessionkey'] ?? '';
106 $this->mHideIgnoreWarning = !empty( $options['hideignorewarning'] );
107 $this->mDestWarningAck = !empty( $options['destwarningack'] );
108 $this->mDestFile = $options['destfile'] ?? '';
109
110 $this->mComment = $options['description'] ?? '';
111
112 $this->mTextTop = $options['texttop'] ?? '';
113
114 $this->mTextAfterSummary = $options['textaftersummary'] ?? '';
115
116 $sourceDescriptor = $this->getSourceSection();
117 $descriptor = $sourceDescriptor
118 + $this->getDescriptionSection()
119 + $this->getOptionsSection();
120
121 $this->hookRunner->onUploadFormInitDescriptor( $descriptor );
122 parent::__construct( $descriptor, $this->getContext(), 'upload' );
123
124 # Add a link to edit MediaWiki:Licenses
125 if ( $this->getAuthority()->isAllowed( 'editinterface' ) ) {
126 $this->getOutput()->addModuleStyles( 'mediawiki.special' );
127 $licensesLink = $linkRenderer->makeKnownLink(
128 $this->msg( 'licenses' )->inContentLanguage()->getTitle(),
129 $this->msg( 'licenses-edit' )->text(),
130 [],
131 [ 'action' => 'edit' ]
132 );
133 $editLicenses = '<p class="mw-upload-editlicenses">' . $licensesLink . '</p>';
134 $this->addFooterText( $editLicenses, 'description' );
135 }
136
137 # Set some form properties
138 $this->setSubmitTextMsg( 'uploadbtn' );
139 $this->setSubmitName( 'wpUpload' );
140 # Used message keys: 'accesskey-upload', 'tooltip-upload'
141 $this->setSubmitTooltip( 'upload' );
142 $this->setId( 'mw-upload-form' );
143
144 # Build a list of IDs for javascript insertion
145 $this->mSourceIds = [];
146 foreach ( $sourceDescriptor as $field ) {
147 if ( !empty( $field['id'] ) ) {
148 $this->mSourceIds[] = $field['id'];
149 }
150 }
151 }
152
159 protected function getSourceSection() {
160 if ( $this->mSessionKey ) {
161 return [
162 'SessionKey' => [
163 'type' => 'hidden',
164 'default' => $this->mSessionKey,
165 ],
166 'SourceType' => [
167 'type' => 'hidden',
168 'default' => 'Stash',
169 ],
170 ];
171 }
172
173 $canUploadByUrl = UploadFromUrl::isEnabled()
174 && ( UploadFromUrl::isAllowed( $this->getAuthority() ) === true )
175 && $this->getConfig()->get( MainConfigNames::CopyUploadsFromSpecialUpload );
176 $radio = $canUploadByUrl;
177 $selectedSourceType = strtolower( $this->getRequest()->getText( 'wpSourceType', 'File' ) );
178
179 $descriptor = [];
180 if ( $this->mTextTop ) {
181 $descriptor['UploadFormTextTop'] = [
182 'type' => 'info',
183 'section' => 'source',
184 'default' => $this->mTextTop,
185 'raw' => true,
186 ];
187 }
188
189 $this->mMaxUploadSize['file'] = min(
190 UploadBase::getMaxUploadSize( 'file' ),
191 UploadBase::getMaxPhpUploadSize()
192 );
193
194 $help = $this->msg( 'upload-maxfilesize' )->sizeParams( $this->mMaxUploadSize['file'] )->parse();
195
196 // If the user can also upload by URL, there are 2 different file size limits.
197 // This extra message helps stress which limit corresponds to what.
198 if ( $canUploadByUrl ) {
199 $help .= $this->msg( 'word-separator' )->escaped();
200 $help .= $this->msg( 'upload_source_file' )->parse();
201 }
202
203 $descriptor['UploadFile'] = [
204 'class' => UploadSourceField::class,
205 'section' => 'source',
206 'type' => 'file',
207 'id' => 'wpUploadFile',
208 'radio-id' => 'wpSourceTypeFile',
209 'label-message' => 'sourcefilename',
210 'upload-type' => 'File',
211 'radio' => &$radio,
212 'help' => $help,
213 'checked' => $selectedSourceType == 'file',
214 ];
215
216 if ( $canUploadByUrl ) {
217 $this->mMaxUploadSize['url'] = UploadBase::getMaxUploadSize( 'url' );
218 $descriptor['UploadFileURL'] = [
219 'class' => UploadSourceField::class,
220 'section' => 'source',
221 'id' => 'wpUploadFileURL',
222 'radio-id' => 'wpSourceTypeurl',
223 'label-message' => 'sourceurl',
224 'upload-type' => 'url',
225 'radio' => &$radio,
226 'help' => $this->msg( 'upload-maxfilesize' )->sizeParams( $this->mMaxUploadSize['url'] )->parse() .
227 $this->msg( 'word-separator' )->escaped() .
228 $this->msg( 'upload_source_url' )->parse(),
229 'checked' => $selectedSourceType == 'url',
230 ];
231 }
232 $this->hookRunner->onUploadFormSourceDescriptors(
233 $descriptor, $radio, $selectedSourceType );
234
235 $descriptor['Extensions'] = [
236 'type' => 'info',
237 'section' => 'source',
238 'default' => $this->getExtensionsMessage(),
239 'raw' => true,
240 ];
241
242 return $descriptor;
243 }
244
250 protected function getExtensionsMessage() {
251 # Print a list of allowed file extensions, if so configured. We ignore
252 # MIME type here, it's incomprehensible to most people and too long.
253 $config = $this->getConfig();
254
255 if ( $config->get( MainConfigNames::CheckFileExtensions ) ) {
256 $fileExtensions = array_unique( $config->get( MainConfigNames::FileExtensions ) );
257 if ( $config->get( MainConfigNames::StrictFileExtensions ) ) {
258 # Everything not permitted is banned
259 $extensionsList =
260 '<div id="mw-upload-permitted">' .
261 $this->msg( 'upload-permitted' )
262 ->params( $this->getLanguage()->commaList( $fileExtensions ) )
263 ->numParams( count( $fileExtensions ) )
264 ->parseAsBlock() .
265 "</div>\n";
266 } else {
267 # We have to list both preferred and prohibited
268 $prohibitedExtensions =
269 array_unique( $config->get( MainConfigNames::ProhibitedFileExtensions ) );
270 $extensionsList =
271 '<div id="mw-upload-preferred">' .
272 $this->msg( 'upload-preferred' )
273 ->params( $this->getLanguage()->commaList( $fileExtensions ) )
274 ->numParams( count( $fileExtensions ) )
275 ->parseAsBlock() .
276 "</div>\n" .
277 '<div id="mw-upload-prohibited">' .
278 $this->msg( 'upload-prohibited' )
279 ->params( $this->getLanguage()->commaList( $prohibitedExtensions ) )
280 ->numParams( count( $prohibitedExtensions ) )
281 ->parseAsBlock() .
282 "</div>\n";
283 }
284 } else {
285 # Everything is permitted.
286 $extensionsList = '';
287 }
288
289 return $extensionsList;
290 }
291
298 protected function getDescriptionSection() {
299 $config = $this->getConfig();
300 if ( $this->mSessionKey ) {
301 $stash = $this->localRepo->getUploadStash( $this->getUser() );
302 try {
303 $file = $stash->getFile( $this->mSessionKey );
304 } catch ( TimeoutException $e ) {
305 throw $e;
306 } catch ( Exception $e ) {
307 $file = null;
308 }
309 if ( $file ) {
310 $mto = $file->transform( [ 'width' => 120 ] );
311 if ( $mto ) {
312 $this->addHeaderText(
313 '<div class="thumb t' .
314 $this->contentLanguage->alignEnd() . '">' .
315 Html::element( 'img', [
316 'src' => $mto->getUrl(),
317 'class' => 'thumbimage',
318 ] ) . '</div>', 'description' );
319 }
320 }
321 }
322
323 $descriptor = [
324 'DestFile' => [
325 'type' => 'text',
326 'section' => 'description',
327 'id' => 'wpDestFile',
328 'label-message' => 'destfilename',
329 'size' => 60,
330 'default' => $this->mDestFile,
331 # @todo FIXME: Hack to work around poor handling of the 'default' option in HTMLForm
332 'nodata' => strval( $this->mDestFile ) !== '',
333 ],
334 'UploadDescription' => [
335 'type' => $this->mForReUpload
336 ? 'text'
337 : 'textarea',
338 'section' => 'description',
339 'id' => 'wpUploadDescription',
340 'label-message' => $this->mForReUpload
341 ? 'filereuploadsummary'
342 : 'fileuploadsummary',
343 'default' => $this->mComment,
344 ]
345 ];
346 if ( $this->mTextAfterSummary ) {
347 $descriptor['UploadFormTextAfterSummary'] = [
348 'type' => 'info',
349 'section' => 'description',
350 'default' => $this->mTextAfterSummary,
351 'raw' => true,
352 ];
353 }
354
355 $descriptor += [
356 'EditTools' => [
357 'type' => 'edittools',
358 'section' => 'description',
359 'message' => 'edittools-upload',
360 ]
361 ];
362
363 if ( $this->mForReUpload ) {
364 $descriptor['DestFile']['readonly'] = true;
365 $descriptor['UploadDescription']['size'] = 60;
366 } else {
367 $descriptor['License'] = [
368 'type' => 'select',
369 'class' => Licenses::class,
370 'section' => 'description',
371 'id' => 'wpLicense',
372 'label-message' => 'license',
373 ];
374 $descriptor['UploadDescription']['rows'] = 8;
375 }
376
377 if ( $config->get( MainConfigNames::UseCopyrightUpload ) ) {
378 $descriptor['UploadCopyStatus'] = [
379 'type' => 'text',
380 'section' => 'description',
381 'id' => 'wpUploadCopyStatus',
382 'label-message' => 'filestatus',
383 ];
384 $descriptor['UploadSource'] = [
385 'type' => 'text',
386 'section' => 'description',
387 'id' => 'wpUploadSource',
388 'label-message' => 'filesource',
389 ];
390 }
391
392 return $descriptor;
393 }
394
401 protected function getOptionsSection() {
402 $user = $this->getUser();
403 if ( $user->isRegistered() ) {
404 $descriptor = [
405 'Watchthis' => [
406 'type' => 'check',
407 'id' => 'wpWatchthis',
408 'label-message' => 'watchthisupload',
409 'section' => 'options',
410 'default' => $this->mWatch,
411 ]
412 ];
413 }
414 if ( !$this->mHideIgnoreWarning ) {
415 $descriptor['IgnoreWarning'] = [
416 'type' => 'check',
417 'id' => 'wpIgnoreWarning',
418 'label-message' => 'ignorewarnings',
419 'section' => 'options',
420 ];
421 }
422
423 $descriptor['DestFileWarningAck'] = [
424 'type' => 'hidden',
425 'id' => 'wpDestFileWarningAck',
426 'default' => $this->mDestWarningAck ? '1' : '',
427 ];
428
429 if ( $this->mForReUpload ) {
430 $descriptor['ForReUpload'] = [
431 'type' => 'hidden',
432 'id' => 'wpForReUpload',
433 'default' => '1',
434 ];
435 }
436
437 return $descriptor;
438 }
439
444 public function show() {
445 $this->addUploadJS();
446 return parent::show();
447 }
448
452 protected function addUploadJS() {
453 $config = $this->getConfig();
454
455 $this->mMaxUploadSize['*'] = UploadBase::getMaxUploadSize();
456
457 $scriptVars = [
458 'wgAjaxLicensePreview' => $config->get( MainConfigNames::AjaxLicensePreview ),
459 'wgUploadAutoFill' => !$this->mForReUpload &&
460 // If we received mDestFile from the request, don't autofill
461 // the wpDestFile textbox
462 $this->mDestFile === '',
463 'wgUploadSourceIds' => $this->mSourceIds,
464 'wgCheckFileExtensions' => $config->get( MainConfigNames::CheckFileExtensions ),
465 'wgStrictFileExtensions' => $config->get( MainConfigNames::StrictFileExtensions ),
466 'wgFileExtensions' =>
467 array_values( array_unique( $config->get( MainConfigNames::FileExtensions ) ) ),
468 'wgMaxUploadSize' => $this->mMaxUploadSize,
469 'wgFileCanRotate' => SpecialUpload::rotationEnabled(),
470 ];
471
472 $out = $this->getOutput();
473 $out->addJsConfigVars( $scriptVars );
474
475 $out->addModules( [
476 'mediawiki.special.upload', // Extras for thumbnail and license preview.
477 ] );
478 }
479
485 public function trySubmit() {
486 return false;
487 }
488}
getUser()
getRequest()
getAuthority()
getContext()
Base class for language-specific code.
Definition Language.php:63
Local repository that stores files in the local filesystem and registers them in the wiki's own datab...
Definition LocalRepo.php:49
setContext(IContextSource $context)
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition HTMLForm.php:206
addFooterText( $msg, $section=null)
Add footer text, inside the form.
addHeaderText( $msg, $section=null)
Add HTML to the header, inside the form.
Definition HTMLForm.php:994
setSubmitTextMsg( $msg)
Set the text for the submit button to a message.
This class provides an implementation of the core hook interfaces, forwarding hook calls to HookConta...
This class is a collection of static functions that serve two purposes:
Definition Html.php:56
Class that generates HTML for internal links.
A class containing constants representing the names of configuration variables.
Service locator for MediaWiki core services.
Form for handling uploads and special page.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition Status.php:54
This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of them ba...
Sub class of HTMLForm that provides the form section of SpecialUpload.
string $mTextAfterSummary
raw html
show()
Add the upload JS and show the form.
trySubmit()
Empty function; submission is handled elsewhere.
getDescriptionSection()
Get the descriptor of the fieldset that contains the file description input.
getOptionsSection()
Get the descriptor of the fieldset that contains the upload options, such as "watch this file".
addUploadJS()
Add upload JS to the OutputPage.
__construct(array $options=[], IContextSource $context=null, LinkRenderer $linkRenderer=null, LocalRepo $localRepo=null, Language $contentLanguage=null, NamespaceInfo $nsInfo=null, HookContainer $hookContainer=null)
getSourceSection()
Get the descriptor of the fieldset that contains the file source selection.
string $mTextTop
raw html
getExtensionsMessage()
Get the messages indicating which extensions are preferred and prohibited.
array $mMaxUploadSize
static isAllowed(Authority $performer)
Checks if the user is allowed to use the upload-by-URL feature.
static isEnabled()
Checks if the upload from URL feature is enabled.
Interface for objects which can provide a MediaWiki context on request.