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