MediaWiki  master
SpecialUpload.php
Go to the documentation of this file.
1 <?php
30 
37 class SpecialUpload extends SpecialPage {
38 
40  private $localRepo;
41 
43  private $userOptionsLookup;
44 
46  private $nsInfo;
47 
49  private $watchlistManager;
50 
57  public function __construct(
58  RepoGroup $repoGroup = null,
59  UserOptionsLookup $userOptionsLookup = null,
60  NamespaceInfo $nsInfo = null,
61  WatchlistManager $watchlistManager = null
62  ) {
63  parent::__construct( 'Upload', 'upload' );
64  // This class is extended and therefor fallback to global state - T265300
65  $services = MediaWikiServices::getInstance();
66  $repoGroup ??= $services->getRepoGroup();
67  $this->localRepo = $repoGroup->getLocalRepo();
68  $this->userOptionsLookup = $userOptionsLookup ?? $services->getUserOptionsLookup();
69  $this->nsInfo = $nsInfo ?? $services->getNamespaceInfo();
70  $this->watchlistManager = $watchlistManager ?? $services->getWatchlistManager();
71  }
72 
73  public function doesWrites() {
74  return true;
75  }
76 
80  public $mRequest;
81  public $mSourceType;
82 
84  public $mUpload;
85 
87  public $mLocalFile;
89 
94  public $mComment;
95  public $mLicense;
96 
100  public $mWatchthis;
103 
107 
110 
113  public $mTokenOk;
114 
116  public $mUploadSuccessful = false;
117 
122 
126  protected function loadRequest() {
127  $this->mRequest = $request = $this->getRequest();
128  $this->mSourceType = $request->getVal( 'wpSourceType', 'file' );
129  $this->mUpload = UploadBase::createFromRequest( $request );
130  $this->mUploadClicked = $request->wasPosted()
131  && ( $request->getCheck( 'wpUpload' )
132  || $request->getCheck( 'wpUploadIgnoreWarning' ) );
133 
134  // Guess the desired name from the filename if not provided
135  $this->mDesiredDestName = $request->getText( 'wpDestFile' );
136  if ( !$this->mDesiredDestName && $request->getFileName( 'wpUploadFile' ) !== null ) {
137  $this->mDesiredDestName = $request->getFileName( 'wpUploadFile' );
138  }
139  $this->mLicense = $request->getText( 'wpLicense' );
140 
141  $this->mDestWarningAck = $request->getText( 'wpDestFileWarningAck' );
142  $this->mIgnoreWarning = $request->getCheck( 'wpIgnoreWarning' )
143  || $request->getCheck( 'wpUploadIgnoreWarning' );
144  $this->mWatchthis = $request->getBool( 'wpWatchthis' ) && $this->getUser()->isRegistered();
145  $this->mCopyrightStatus = $request->getText( 'wpUploadCopyStatus' );
146  $this->mCopyrightSource = $request->getText( 'wpUploadSource' );
147 
148  $this->mForReUpload = $request->getBool( 'wpForReUpload' ); // updating a file
149 
150  $commentDefault = '';
151  $commentMsg = $this->msg( 'upload-default-description' )->inContentLanguage();
152  if ( !$this->mForReUpload && !$commentMsg->isDisabled() ) {
153  $commentDefault = $commentMsg->plain();
154  }
155  $this->mComment = $request->getText( 'wpUploadDescription', $commentDefault );
156 
157  $this->mCancelUpload = $request->getCheck( 'wpCancelUpload' )
158  || $request->getCheck( 'wpReUpload' ); // b/w compat
159 
160  // If it was posted check for the token (no remote POST'ing with user credentials)
161  $token = $request->getVal( 'wpEditToken' );
162  $this->mTokenOk = $this->getUser()->matchEditToken( $token );
163 
164  $this->uploadFormTextTop = '';
165  $this->uploadFormTextAfterSummary = '';
166  }
167 
176  public function userCanExecute( User $user ) {
177  return UploadBase::isEnabled() && parent::userCanExecute( $user );
178  }
179 
183  public function execute( $par ) {
184  $this->useTransactionalTimeLimit();
185 
186  $this->setHeaders();
187  $this->outputHeader();
188 
189  # Check uploading enabled
190  if ( !UploadBase::isEnabled() ) {
191  throw new ErrorPageError( 'uploaddisabled', 'uploaddisabledtext' );
192  }
193 
194  $this->addHelpLink( 'Help:Managing files' );
195 
196  # Check permissions
197  $user = $this->getUser();
198  $permissionRequired = UploadBase::isAllowed( $user );
199  if ( $permissionRequired !== true ) {
200  throw new PermissionsError( $permissionRequired );
201  }
202 
203  # Check blocks
204  if ( $user->isBlockedFromUpload() ) {
205  throw new UserBlockedError(
206  // @phan-suppress-next-line PhanTypeMismatchArgumentNullable Block is checked and not null
207  $user->getBlock(),
208  $user,
209  $this->getLanguage(),
210  $this->getRequest()->getIP()
211  );
212  }
213 
214  # Check whether we actually want to allow changing stuff
215  $this->checkReadOnly();
216 
217  $this->loadRequest();
218 
219  # Unsave the temporary file in case this was a cancelled upload
220  if ( $this->mCancelUpload && !$this->unsaveUploadedFile() ) {
221  # Something went wrong, so unsaveUploadedFile showed a warning
222  return;
223  }
224 
225  # Process upload or show a form
226  if (
227  $this->mTokenOk && !$this->mCancelUpload &&
228  ( $this->mUpload && $this->mUploadClicked )
229  ) {
230  $this->processUpload();
231  } else {
232  # Backwards compatibility hook
233  if ( !$this->getHookRunner()->onUploadForm_initial( $this ) ) {
234  wfDebug( "Hook 'UploadForm:initial' broke output of the upload form" );
235 
236  return;
237  }
238  $this->showUploadForm( $this->getUploadForm() );
239  }
240 
241  # Cleanup
242  if ( $this->mUpload ) {
243  $this->mUpload->cleanupTempFile();
244  }
245  }
246 
252  protected function showUploadForm( $form ) {
253  if ( $form instanceof HTMLForm ) {
254  $form->show();
255  } else {
256  $this->getOutput()->addHTML( $form );
257  }
258  }
259 
268  protected function getUploadForm( $message = '', $sessionKey = '', $hideIgnoreWarning = false ) {
269  # Initialize form
270  $form = new UploadForm(
271  [
272  'watch' => $this->getWatchCheck(),
273  'forreupload' => $this->mForReUpload,
274  'sessionkey' => $sessionKey,
275  'hideignorewarning' => $hideIgnoreWarning,
276  'destwarningack' => (bool)$this->mDestWarningAck,
277 
278  'description' => $this->mComment,
279  'texttop' => $this->uploadFormTextTop,
280  'textaftersummary' => $this->uploadFormTextAfterSummary,
281  'destfile' => $this->mDesiredDestName,
282  ],
283  $this->getContext(),
284  $this->getLinkRenderer(),
285  $this->localRepo,
286  $this->getContentLanguage(),
287  $this->nsInfo,
288  $this->getHookContainer()
289  );
290  $form->setTitle( $this->getPageTitle() ); // Remove subpage
291 
292  # Check the token, but only if necessary
293  if (
294  !$this->mTokenOk && !$this->mCancelUpload &&
295  ( $this->mUpload && $this->mUploadClicked )
296  ) {
297  $form->addPreText( $this->msg( 'session_fail_preview' )->parse() );
298  }
299 
300  # Give a notice if the user is uploading a file that has been deleted or moved
301  # Note that this is independent from the message 'filewasdeleted'
302  $desiredTitleObj = Title::makeTitleSafe( NS_FILE, $this->mDesiredDestName );
303  $delNotice = ''; // empty by default
304  if ( $desiredTitleObj instanceof Title && !$desiredTitleObj->exists() ) {
305  LogEventsList::showLogExtract( $delNotice, [ 'delete', 'move' ],
306  $desiredTitleObj,
307  '', [ 'lim' => 10,
308  'conds' => [ 'log_action != ' . $this->localRepo->getReplicaDB()->addQuotes( 'revision' ) ],
309  'showIfEmpty' => false,
310  'msgKey' => [ 'upload-recreate-warning' ] ]
311  );
312  }
313  $form->addPreText( $delNotice );
314 
315  # Add text to form
316  $form->addPreText( '<div id="uploadtext">' .
317  $this->msg( 'uploadtext', [ $this->mDesiredDestName ] )->parseAsBlock() .
318  '</div>' );
319  # Add upload error message
320  $form->addPreText( $message );
321 
322  # Add footer to form
323  $uploadFooter = $this->msg( 'uploadfooter' );
324  if ( !$uploadFooter->isDisabled() ) {
325  $form->addPostText( '<div id="mw-upload-footer-message">'
326  . $uploadFooter->parseAsBlock() . "</div>\n" );
327  }
328 
329  return $form;
330  }
331 
343  protected function showRecoverableUploadError( $message ) {
344  $stashStatus = $this->mUpload->tryStashFile( $this->getUser() );
345  if ( $stashStatus->isGood() ) {
346  $sessionKey = $stashStatus->getValue()->getFileKey();
347  $uploadWarning = 'upload-tryagain';
348  } else {
349  $sessionKey = null;
350  $uploadWarning = 'upload-tryagain-nostash';
351  }
352  $message = '<h2>' . $this->msg( 'uploaderror' )->escaped() . '</h2>' .
353  Html::errorBox( $message );
354 
355  $form = $this->getUploadForm( $message, $sessionKey );
356  $form->setSubmitText( $this->msg( $uploadWarning )->escaped() );
357  $this->showUploadForm( $form );
358  }
359 
368  protected function showUploadWarning( $warnings ) {
369  # If there are no warnings, or warnings we can ignore, return early.
370  # mDestWarningAck is set when some javascript has shown the warning
371  # to the user. mForReUpload is set when the user clicks the "upload a
372  # new version" link.
373  if ( !$warnings || ( count( $warnings ) == 1
374  && isset( $warnings['exists'] )
375  && ( $this->mDestWarningAck || $this->mForReUpload ) )
376  ) {
377  return false;
378  }
379 
380  $stashStatus = $this->mUpload->tryStashFile( $this->getUser() );
381  if ( $stashStatus->isGood() ) {
382  $sessionKey = $stashStatus->getValue()->getFileKey();
383  $uploadWarning = 'uploadwarning-text';
384  } else {
385  $sessionKey = null;
386  $uploadWarning = 'uploadwarning-text-nostash';
387  }
388 
389  // Add styles for the warning, reused from the live preview
390  $this->getOutput()->addModuleStyles( 'mediawiki.special' );
391 
392  $linkRenderer = $this->getLinkRenderer();
393  $warningHtml = '<h2>' . $this->msg( 'uploadwarning' )->escaped() . "</h2>\n"
394  . '<div class="mw-destfile-warning"><ul>';
395  foreach ( $warnings as $warning => $args ) {
396  if ( $warning == 'badfilename' ) {
397  $this->mDesiredDestName = Title::makeTitle( NS_FILE, $args )->getText();
398  }
399  if ( $warning == 'exists' ) {
400  $msg = "\t<li>" . self::getExistsWarning( $args ) . "</li>\n";
401  } elseif ( $warning == 'no-change' ) {
402  $file = $args;
403  $filename = $file->getTitle()->getPrefixedText();
404  $msg = "\t<li>" . $this->msg( 'fileexists-no-change', $filename )->parse() . "</li>\n";
405  } elseif ( $warning == 'duplicate-version' ) {
406  $file = $args[0];
407  $count = count( $args );
408  $filename = $file->getTitle()->getPrefixedText();
409  $message = $this->msg( 'fileexists-duplicate-version' )
410  ->params( $filename )
411  ->numParams( $count );
412  $msg = "\t<li>" . $message->parse() . "</li>\n";
413  } elseif ( $warning == 'was-deleted' ) {
414  # If the file existed before and was deleted, warn the user of this
415  $ltitle = SpecialPage::getTitleFor( 'Log' );
416  $llink = $linkRenderer->makeKnownLink(
417  $ltitle,
418  $this->msg( 'deletionlog' )->text(),
419  [],
420  [
421  'type' => 'delete',
422  'page' => Title::makeTitle( NS_FILE, $args )->getPrefixedText(),
423  ]
424  );
425  $msg = "\t<li>" . $this->msg( 'filewasdeleted' )->rawParams( $llink )->parse() . "</li>\n";
426  } elseif ( $warning == 'duplicate' ) {
427  $msg = $this->getDupeWarning( $args );
428  } elseif ( $warning == 'duplicate-archive' ) {
429  if ( $args === '' ) {
430  $msg = "\t<li>" . $this->msg( 'file-deleted-duplicate-notitle' )->parse()
431  . "</li>\n";
432  } else {
433  $msg = "\t<li>" . $this->msg( 'file-deleted-duplicate',
434  Title::makeTitle( NS_FILE, $args )->getPrefixedText() )->parse()
435  . "</li>\n";
436  }
437  } else {
438  if ( $args === true ) {
439  $args = [];
440  } elseif ( !is_array( $args ) ) {
441  $args = [ $args ];
442  }
443  $msg = "\t<li>" . $this->msg( $warning, $args )->parse() . "</li>\n";
444  }
445  $warningHtml .= $msg;
446  }
447  $warningHtml .= "</ul></div>\n";
448  $warningHtml .= $this->msg( $uploadWarning )->parseAsBlock();
449 
450  $form = $this->getUploadForm( $warningHtml, $sessionKey, /* $hideIgnoreWarning */ true );
451  $form->setSubmitTextMsg( 'upload-tryagain' );
452  $form->addButton( [
453  'name' => 'wpUploadIgnoreWarning',
454  'value' => $this->msg( 'ignorewarning' )->text()
455  ] );
456  $form->addButton( [
457  'name' => 'wpCancelUpload',
458  'value' => $this->msg( 'reuploaddesc' )->text()
459  ] );
460 
461  $this->showUploadForm( $form );
462 
463  # Indicate that we showed a form
464  return true;
465  }
466 
472  protected function showUploadError( $message ) {
473  $message = '<h2>' . $this->msg( 'uploadwarning' )->escaped() . '</h2>' .
474  Html::errorBox( $message );
475  $this->showUploadForm( $this->getUploadForm( $message ) );
476  }
477 
482  protected function processUpload() {
483  // Fetch the file if required
484  $status = $this->mUpload->fetchFile();
485  if ( !$status->isOK() ) {
486  $this->showUploadError( $this->getOutput()->parseAsInterface(
487  $status->getWikiText( false, false, $this->getLanguage() )
488  ) );
489 
490  return;
491  }
492  if ( !$this->getHookRunner()->onUploadForm_BeforeProcessing( $this ) ) {
493  wfDebug( "Hook 'UploadForm:BeforeProcessing' broke processing the file." );
494  // This code path is deprecated. If you want to break upload processing
495  // do so by hooking into the appropriate hooks in UploadBase::verifyUpload
496  // and UploadBase::verifyFile.
497  // If you use this hook to break uploading, the user will be returned
498  // an empty form with no error message whatsoever.
499  return;
500  }
501 
502  // Upload verification
503  $details = $this->mUpload->verifyUpload();
504  if ( $details['status'] != UploadBase::OK ) {
505  $this->processVerificationError( $details );
506 
507  return;
508  }
509 
510  // Verify permissions for this title
511  $user = $this->getUser();
512  $permErrors = $this->mUpload->verifyTitlePermissions( $user );
513  if ( $permErrors !== true ) {
514  $code = array_shift( $permErrors[0] );
515  $this->showRecoverableUploadError( $this->msg( $code, $permErrors[0] )->parse() );
516 
517  return;
518  }
519 
520  $this->mLocalFile = $this->mUpload->getLocalFile();
521 
522  // Check warnings if necessary
523  if ( !$this->mIgnoreWarning ) {
524  $warnings = $this->mUpload->checkWarnings( $user );
525  if ( $this->showUploadWarning( $warnings ) ) {
526  return;
527  }
528  }
529 
530  // This is as late as we can throttle, after expected issues have been handled
531  if ( UploadBase::isThrottled( $user ) ) {
533  $this->msg( 'actionthrottledtext' )->escaped()
534  );
535  return;
536  }
537 
538  // Get the page text if this is not a reupload
539  if ( !$this->mForReUpload ) {
540  $pageText = self::getInitialPageText( $this->mComment, $this->mLicense,
541  $this->mCopyrightStatus, $this->mCopyrightSource, $this->getConfig() );
542  } else {
543  $pageText = false;
544  }
545 
546  $changeTags = $this->getRequest()->getVal( 'wpChangeTags' );
547  if ( $changeTags === null || $changeTags === '' ) {
548  $changeTags = [];
549  } else {
550  $changeTags = array_filter( array_map( 'trim', explode( ',', $changeTags ) ) );
551  }
552 
553  if ( $changeTags ) {
554  $changeTagsStatus = ChangeTags::canAddTagsAccompanyingChange(
555  $changeTags, $user );
556  if ( !$changeTagsStatus->isOK() ) {
557  $this->showUploadError( $this->getOutput()->parseAsInterface(
558  $changeTagsStatus->getWikiText( false, false, $this->getLanguage() )
559  ) );
560 
561  return;
562  }
563  }
564 
565  $status = $this->mUpload->performUpload(
566  $this->mComment,
567  $pageText,
568  $this->mWatchthis,
569  $user,
570  $changeTags
571  );
572 
573  if ( !$status->isGood() ) {
575  $this->getOutput()->parseAsInterface(
576  $status->getWikiText( false, false, $this->getLanguage() )
577  )
578  );
579 
580  return;
581  }
582 
583  // Success, redirect to description page
584  $this->mUploadSuccessful = true;
585  $this->getHookRunner()->onSpecialUploadComplete( $this );
586  $this->getOutput()->redirect( $this->mLocalFile->getTitle()->getFullURL() );
587  }
588 
598  public static function getInitialPageText( $comment = '', $license = '',
599  $copyStatus = '', $source = '', Config $config = null
600  ) {
601  if ( $config === null ) {
602  wfDebug( __METHOD__ . ' called without a Config instance passed to it' );
603  $config = MediaWikiServices::getInstance()->getMainConfig();
604  }
605 
606  $msg = [];
607  $forceUIMsgAsContentMsg = (array)$config->get( MainConfigNames::ForceUIMsgAsContentMsg );
608  /* These messages are transcluded into the actual text of the description page.
609  * Thus, forcing them as content messages makes the upload to produce an int: template
610  * instead of hardcoding it there in the uploader language.
611  */
612  foreach ( [ 'license-header', 'filedesc', 'filestatus', 'filesource' ] as $msgName ) {
613  if ( in_array( $msgName, $forceUIMsgAsContentMsg ) ) {
614  $msg[$msgName] = "{{int:$msgName}}";
615  } else {
616  $msg[$msgName] = wfMessage( $msgName )->inContentLanguage()->text();
617  }
618  }
619 
620  $licenseText = '';
621  if ( $license !== '' ) {
622  $licenseText = '== ' . $msg['license-header'] . " ==\n{{" . $license . "}}\n";
623  }
624 
625  $pageText = $comment . "\n";
626  $headerText = '== ' . $msg['filedesc'] . ' ==';
627  if ( $comment !== '' && !str_contains( $comment, $headerText ) ) {
628  // prepend header to page text unless it's already there (or there is no content)
629  $pageText = $headerText . "\n" . $pageText;
630  }
631 
632  if ( $config->get( MainConfigNames::UseCopyrightUpload ) ) {
633  $pageText .= '== ' . $msg['filestatus'] . " ==\n" . $copyStatus . "\n";
634  $pageText .= $licenseText;
635  $pageText .= '== ' . $msg['filesource'] . " ==\n" . $source;
636  } else {
637  $pageText .= $licenseText;
638  }
639 
640  // allow extensions to modify the content
641  Hooks::runner()->onUploadForm_getInitialPageText( $pageText, $msg, $config );
642 
643  return $pageText;
644  }
645 
658  protected function getWatchCheck() {
659  $user = $this->getUser();
660  if ( $this->userOptionsLookup->getBoolOption( $user, 'watchdefault' ) ) {
661  // Watch all edits!
662  return true;
663  }
664 
665  $desiredTitleObj = Title::makeTitleSafe( NS_FILE, $this->mDesiredDestName );
666  if ( $desiredTitleObj instanceof Title &&
667  $this->watchlistManager->isWatched( $user, $desiredTitleObj ) ) {
668  // Already watched, don't change that
669  return true;
670  }
671 
672  $local = $this->localRepo->newFile( $this->mDesiredDestName );
673  if ( $local && $local->exists() ) {
674  // We're uploading a new version of an existing file.
675  // No creation, so don't watch it if we're not already.
676  return false;
677  } else {
678  // New page should get watched if that's our option.
679  return $this->userOptionsLookup->getBoolOption( $user, 'watchcreations' ) ||
680  $this->userOptionsLookup->getBoolOption( $user, 'watchuploads' );
681  }
682  }
683 
689  protected function processVerificationError( $details ) {
690  switch ( $details['status'] ) {
693  $this->showRecoverableUploadError( $this->msg( 'minlength1' )->escaped() );
694  break;
696  $this->showRecoverableUploadError( $this->msg( 'illegalfilename',
697  $details['filtered'] )->parse() );
698  break;
700  $this->showRecoverableUploadError( $this->msg( 'filename-toolong' )->escaped() );
701  break;
703  $this->showRecoverableUploadError( $this->msg( 'filetype-missing' )->parse() );
704  break;
706  $this->showRecoverableUploadError( $this->msg( 'windows-nonascii-filename' )->parse() );
707  break;
708 
711  $this->showUploadError( $this->msg( 'emptyfile' )->escaped() );
712  break;
714  $this->showUploadError( $this->msg( 'largefileserver' )->escaped() );
715  break;
717  $msg = $this->msg( 'filetype-banned-type' );
718  if ( isset( $details['blacklistedExt'] ) ) {
719  $msg->params( $this->getLanguage()->commaList( $details['blacklistedExt'] ) );
720  } else {
721  $msg->params( $details['finalExt'] );
722  }
723  $extensions =
724  array_unique( $this->getConfig()->get( MainConfigNames::FileExtensions ) );
725  $msg->params( $this->getLanguage()->commaList( $extensions ),
726  count( $extensions ) );
727 
728  // Add PLURAL support for the first parameter. This results
729  // in a bit unlogical parameter sequence, but does not break
730  // old translations
731  if ( isset( $details['blacklistedExt'] ) ) {
732  $msg->params( count( $details['blacklistedExt'] ) );
733  } else {
734  $msg->params( 1 );
735  }
736 
737  $this->showUploadError( $msg->parse() );
738  break;
740  unset( $details['status'] );
741  $code = array_shift( $details['details'] );
742  $this->showUploadError( $this->msg( $code, $details['details'] )->parse() );
743  break;
745  if ( is_array( $details['error'] ) ) { # allow hooks to return error details in an array
746  $args = $details['error'];
747  $error = array_shift( $args );
748  } else {
749  $error = $details['error'];
750  $args = null;
751  }
752 
753  $this->showUploadError( $this->msg( $error, $args )->parse() );
754  break;
755  default:
756  throw new UnexpectedValueException( __METHOD__ . ": Unknown value `{$details['status']}`" );
757  }
758  }
759 
765  protected function unsaveUploadedFile() {
766  if ( !( $this->mUpload instanceof UploadFromStash ) ) {
767  return true;
768  }
769  $success = $this->mUpload->unsaveUploadedFile();
770  if ( !$success ) {
771  $this->getOutput()->showFatalError(
772  $this->msg( 'filedeleteerror' )
773  ->params( $this->mUpload->getTempPath() )
774  ->escaped()
775  );
776 
777  return false;
778  } else {
779  return true;
780  }
781  }
782 
792  public static function getExistsWarning( $exists ) {
793  if ( !$exists ) {
794  return '';
795  }
796 
797  $file = $exists['file'];
798  $filename = $file->getTitle()->getPrefixedText();
799  $warnMsg = null;
800 
801  if ( $exists['warning'] == 'exists' ) {
802  // Exact match
803  $warnMsg = wfMessage( 'fileexists', $filename );
804  } elseif ( $exists['warning'] == 'page-exists' ) {
805  // Page exists but file does not
806  $warnMsg = wfMessage( 'filepageexists', $filename );
807  } elseif ( $exists['warning'] == 'exists-normalized' ) {
808  $warnMsg = wfMessage( 'fileexists-extension', $filename,
809  $exists['normalizedFile']->getTitle()->getPrefixedText() );
810  } elseif ( $exists['warning'] == 'thumb' ) {
811  // Swapped argument order compared with other messages for backwards compatibility
812  $warnMsg = wfMessage( 'fileexists-thumbnail-yes',
813  $exists['thumbFile']->getTitle()->getPrefixedText(), $filename );
814  } elseif ( $exists['warning'] == 'thumb-name' ) {
815  // Image w/o '180px-' does not exists, but we do not like these filenames
816  $name = $file->getName();
817  $badPart = substr( $name, 0, strpos( $name, '-' ) + 1 );
818  $warnMsg = wfMessage( 'file-thumbnail-no', $badPart );
819  } elseif ( $exists['warning'] == 'bad-prefix' ) {
820  $warnMsg = wfMessage( 'filename-bad-prefix', $exists['prefix'] );
821  }
822 
823  return $warnMsg ? $warnMsg->page( $file->getTitle() )->parse() : '';
824  }
825 
831  public function getDupeWarning( $dupes ) {
832  if ( !$dupes ) {
833  return '';
834  }
835 
836  $gallery = ImageGalleryBase::factory( false, $this->getContext() );
837  $gallery->setShowBytes( false );
838  $gallery->setShowDimensions( false );
839  foreach ( $dupes as $file ) {
840  $gallery->add( $file->getTitle() );
841  }
842 
843  return '<li>' .
844  $this->msg( 'file-exists-duplicate' )->numParams( count( $dupes ) )->parse() .
845  $gallery->toHTML() . "</li>\n";
846  }
847 
848  protected function getGroupName() {
849  return 'media';
850  }
851 
860  public static function rotationEnabled() {
861  $bitmapHandler = new BitmapHandler();
862  return $bitmapHandler->autoRotateEnabled();
863  }
864 }
const NS_FILE
Definition: Defines.php:70
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
$success
Generic handler for bitmap images.
static canAddTagsAccompanyingChange(array $tags, Authority $performer=null, $checkBlock=true)
Is it OK to allow the user to apply all the specified tags at the same time as they edit/make the cha...
Definition: ChangeTags.php:635
An error page which can definitely be safely rendered using the OutputPage.
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition: HTMLForm.php:151
static runner()
Get a HookRunner instance for calling hooks using the new interfaces.
Definition: Hooks.php:173
static errorBox( $html, $heading='', $className='')
Return an error box.
Definition: Html.php:788
static factory( $mode=false, IContextSource $context=null)
Get a new image gallery.
static showLogExtract(&$out, $types=[], $page='', $user='', $param=[])
Show log extract.
A class containing constants representing the names of configuration variables.
Service locator for MediaWiki core services.
WebRequest clone which takes values from a provided array.
Definition: FauxRequest.php:42
Provides access to user options.
This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of them ba...
Show an error when a user tries to do something they do not have the necessary permissions for.
Prioritized list of file repositories.
Definition: RepoGroup.php:29
Parent class for all special pages.
Definition: SpecialPage.php:44
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages Per default the message key is the canonical name o...
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
getOutput()
Get the OutputPage being used for this instance.
getUser()
Shortcut to get the User executing this instance.
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
getContext()
Gets the context this SpecialPage is executed in.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getConfig()
Shortcut to get main config object.
getRequest()
Get the WebRequest being used for this instance.
checkReadOnly()
If the wiki is currently in readonly mode, throws a ReadOnlyError.
getPageTitle( $subpage=false)
Get a self-referential title object.
useTransactionalTimeLimit()
Call wfTransactionalTimeLimit() if this request was POSTed.
getLanguage()
Shortcut to get user's language.
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
getContentLanguage()
Shortcut to get content language.
Form for handling uploads and special page.
processVerificationError( $details)
Provides output to the user for a result of UploadBase::verifyUpload.
UploadBase $mUpload
getWatchCheck()
See if we should check the 'watch this page' checkbox on the form based on the user's preferences and...
loadRequest()
Initialize instance variables from request and create an Upload handler.
static getInitialPageText( $comment='', $license='', $copyStatus='', $source='', Config $config=null)
Get the initial image page text based on a comment and optional file status information.
showUploadWarning( $warnings)
Stashes the upload, shows the main form, but adds a "continue anyway button".
bool $mCancelUpload
The user clicked "Cancel and return to upload form" button.
unsaveUploadedFile()
Remove a temporarily kept file stashed by saveTempUploadedFile().
userCanExecute(User $user)
This page can be shown if uploading is enabled.
static getExistsWarning( $exists)
Functions for formatting warnings.
string $mDesiredDestName
User input variables from the "description" section.
showRecoverableUploadError( $message)
Stashes the upload and shows the main upload form.
string $uploadFormTextAfterSummary
Raw html injection point for hooks not using HTMLForm.
$mDestWarningAck
Hidden variables.
getDupeWarning( $dupes)
Construct a warning and a gallery from an array of duplicate files.
showUploadForm( $form)
Show the main upload form.
WebRequest FauxRequest $mRequest
Misc variables.
processUpload()
Do the upload.
bool $mUploadSuccessful
Subclasses can use this to determine whether a file was uploaded.
LocalFile $mLocalFile
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
getUploadForm( $message='', $sessionKey='', $hideIgnoreWarning=false)
Get an UploadForm instance with title and text properly set.
doesWrites()
Indicates whether this special page may perform database writes.
string $uploadFormTextTop
Raw html injection point for hooks not using HTMLForm.
bool $mForReUpload
The user followed an "overwrite this file" link.
$mIgnoreWarning
User input variables from the root section.
showUploadError( $message)
Show the upload form with error message, but do not stash the file.
static rotationEnabled()
Should we rotate images in the preview on Special:Upload.
__construct(RepoGroup $repoGroup=null, UserOptionsLookup $userOptionsLookup=null, NamespaceInfo $nsInfo=null, WatchlistManager $watchlistManager=null)
Represents a title within MediaWiki.
Definition: Title.php:52
exists( $flags=0)
Check if page exists.
Definition: Title.php:3491
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:667
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:641
const EMPTY_FILE
Definition: UploadBase.php:107
static createFromRequest(&$request, $type=null)
Create a form of UploadBase depending on wpSourceType and initializes it.
Definition: UploadBase.php:190
const FILETYPE_MISSING
Definition: UploadBase.php:111
static isEnabled()
Returns true if uploads are enabled.
Definition: UploadBase.php:146
const HOOK_ABORTED
Definition: UploadBase.php:114
const VERIFICATION_ERROR
Definition: UploadBase.php:113
static isAllowed(Authority $performer)
Returns true if the user can use this upload module or else a string identifying the missing permissi...
Definition: UploadBase.php:160
const WINDOWS_NONASCII_FILENAME
Definition: UploadBase.php:116
const FILETYPE_BADTYPE
Definition: UploadBase.php:112
const FILE_TOO_LARGE
Definition: UploadBase.php:115
static isThrottled( $user)
Returns true if the user has surpassed the upload rate limit, false otherwise.
Definition: UploadBase.php:176
const ILLEGAL_FILENAME
Definition: UploadBase.php:109
const MIN_LENGTH_PARTNAME
Definition: UploadBase.php:108
const FILENAME_TOO_LONG
Definition: UploadBase.php:117
Sub class of HTMLForm that provides the form section of SpecialUpload.
Definition: UploadForm.php:31
Implements uploading from previously stored file.
Show an error when the user tries to do something whilst blocked.
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition: User.php:70
Interface for configuration instances.
Definition: Config.php:30
$source
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
Definition: router.php:42