MediaWiki  master
SpecialUpload.php
Go to the documentation of this file.
1 <?php
29 
36 class SpecialUpload extends SpecialPage {
37 
39  private $localRepo;
40 
43 
45  private $nsInfo;
46 
49 
56  public function __construct(
57  RepoGroup $repoGroup = null,
59  NamespaceInfo $nsInfo = null,
61  ) {
62  parent::__construct( 'Upload', 'upload' );
63  // This class is extended and therefor fallback to global state - T265300
64  $services = MediaWikiServices::getInstance();
65  $repoGroup = $repoGroup ?? $services->getRepoGroup();
66  $this->localRepo = $repoGroup->getLocalRepo();
67  $this->userOptionsLookup = $userOptionsLookup ?? $services->getUserOptionsLookup();
68  $this->nsInfo = $nsInfo ?? $services->getNamespaceInfo();
69  $this->watchlistManager = $watchlistManager ?? $services->getWatchlistManager();
70  }
71 
72  public function doesWrites() {
73  return true;
74  }
75 
79  public $mRequest;
80  public $mSourceType;
81 
83  public $mUpload;
84 
86  public $mLocalFile;
88 
93  public $mComment;
94  public $mLicense;
95 
99  public $mWatchthis;
102 
106 
109 
112  public $mTokenOk;
113 
115  public $mUploadSuccessful = false;
116 
121 
125  protected function loadRequest() {
126  $this->mRequest = $request = $this->getRequest();
127  $this->mSourceType = $request->getVal( 'wpSourceType', 'file' );
128  $this->mUpload = UploadBase::createFromRequest( $request );
129  $this->mUploadClicked = $request->wasPosted()
130  && ( $request->getCheck( 'wpUpload' )
131  || $request->getCheck( 'wpUploadIgnoreWarning' ) );
132 
133  // Guess the desired name from the filename if not provided
134  $this->mDesiredDestName = $request->getText( 'wpDestFile' );
135  if ( !$this->mDesiredDestName && $request->getFileName( 'wpUploadFile' ) !== null ) {
136  $this->mDesiredDestName = $request->getFileName( 'wpUploadFile' );
137  }
138  $this->mLicense = $request->getText( 'wpLicense' );
139 
140  $this->mDestWarningAck = $request->getText( 'wpDestFileWarningAck' );
141  $this->mIgnoreWarning = $request->getCheck( 'wpIgnoreWarning' )
142  || $request->getCheck( 'wpUploadIgnoreWarning' );
143  $this->mWatchthis = $request->getBool( 'wpWatchthis' ) && $this->getUser()->isRegistered();
144  $this->mCopyrightStatus = $request->getText( 'wpUploadCopyStatus' );
145  $this->mCopyrightSource = $request->getText( 'wpUploadSource' );
146 
147  $this->mForReUpload = $request->getBool( 'wpForReUpload' ); // updating a file
148 
149  $commentDefault = '';
150  $commentMsg = $this->msg( 'upload-default-description' )->inContentLanguage();
151  if ( !$this->mForReUpload && !$commentMsg->isDisabled() ) {
152  $commentDefault = $commentMsg->plain();
153  }
154  $this->mComment = $request->getText( 'wpUploadDescription', $commentDefault );
155 
156  $this->mCancelUpload = $request->getCheck( 'wpCancelUpload' )
157  || $request->getCheck( 'wpReUpload' ); // b/w compat
158 
159  // If it was posted check for the token (no remote POST'ing with user credentials)
160  $token = $request->getVal( 'wpEditToken' );
161  $this->mTokenOk = $this->getUser()->matchEditToken( $token );
162 
163  $this->uploadFormTextTop = '';
164  $this->uploadFormTextAfterSummary = '';
165  }
166 
175  public function userCanExecute( User $user ) {
176  return UploadBase::isEnabled() && parent::userCanExecute( $user );
177  }
178 
189  public function execute( $par ) {
190  $this->useTransactionalTimeLimit();
191 
192  $this->setHeaders();
193  $this->outputHeader();
194 
195  # Check uploading enabled
196  if ( !UploadBase::isEnabled() ) {
197  throw new ErrorPageError( 'uploaddisabled', 'uploaddisabledtext' );
198  }
199 
200  $this->addHelpLink( 'Help:Managing files' );
201 
202  # Check permissions
203  $user = $this->getUser();
204  $permissionRequired = UploadBase::isAllowed( $user );
205  if ( $permissionRequired !== true ) {
206  throw new PermissionsError( $permissionRequired );
207  }
208 
209  # Check blocks
210  if ( $user->isBlockedFromUpload() ) {
211  throw new UserBlockedError(
212  // @phan-suppress-next-line PhanTypeMismatchArgumentNullable Block is checked and not null
213  $user->getBlock(),
214  $user,
215  $this->getLanguage(),
216  $this->getRequest()->getIP()
217  );
218  }
219 
220  // Global blocks
221  if ( $user->isBlockedGlobally() ) {
222  throw new UserBlockedError(
223  $user->getGlobalBlock(),
224  $user,
225  $this->getLanguage(),
226  $this->getRequest()->getIP()
227  );
228  }
229 
230  # Check whether we actually want to allow changing stuff
231  $this->checkReadOnly();
232 
233  $this->loadRequest();
234 
235  # Unsave the temporary file in case this was a cancelled upload
236  if ( $this->mCancelUpload && !$this->unsaveUploadedFile() ) {
237  # Something went wrong, so unsaveUploadedFile showed a warning
238  return;
239  }
240 
241  # Process upload or show a form
242  if (
243  $this->mTokenOk && !$this->mCancelUpload &&
244  ( $this->mUpload && $this->mUploadClicked )
245  ) {
246  $this->processUpload();
247  } else {
248  # Backwards compatibility hook
249  if ( !$this->getHookRunner()->onUploadForm_initial( $this ) ) {
250  wfDebug( "Hook 'UploadForm:initial' broke output of the upload form" );
251 
252  return;
253  }
254  $this->showUploadForm( $this->getUploadForm() );
255  }
256 
257  # Cleanup
258  if ( $this->mUpload ) {
259  $this->mUpload->cleanupTempFile();
260  }
261  }
262 
268  protected function showUploadForm( $form ) {
269  # Add links if file was previously deleted
270  if ( $this->mDesiredDestName ) {
271  $this->showViewDeletedLinks();
272  }
273 
274  if ( $form instanceof HTMLForm ) {
275  $form->show();
276  } else {
277  $this->getOutput()->addHTML( $form );
278  }
279  }
280 
289  protected function getUploadForm( $message = '', $sessionKey = '', $hideIgnoreWarning = false ) {
290  # Initialize form
291  $form = new UploadForm(
292  [
293  'watch' => $this->getWatchCheck(),
294  'forreupload' => $this->mForReUpload,
295  'sessionkey' => $sessionKey,
296  'hideignorewarning' => $hideIgnoreWarning,
297  'destwarningack' => (bool)$this->mDestWarningAck,
298 
299  'description' => $this->mComment,
300  'texttop' => $this->uploadFormTextTop,
301  'textaftersummary' => $this->uploadFormTextAfterSummary,
302  'destfile' => $this->mDesiredDestName,
303  ],
304  $this->getContext(),
305  $this->getLinkRenderer(),
306  $this->localRepo,
307  $this->getContentLanguage(),
308  $this->nsInfo
309  );
310  $form->setTitle( $this->getPageTitle() ); // Remove subpage
311 
312  # Check the token, but only if necessary
313  if (
314  !$this->mTokenOk && !$this->mCancelUpload &&
315  ( $this->mUpload && $this->mUploadClicked )
316  ) {
317  $form->addPreText( $this->msg( 'session_fail_preview' )->parse() );
318  }
319 
320  # Give a notice if the user is uploading a file that has been deleted or moved
321  # Note that this is independent from the message 'filewasdeleted'
322  $desiredTitleObj = Title::makeTitleSafe( NS_FILE, $this->mDesiredDestName );
323  $delNotice = ''; // empty by default
324  if ( $desiredTitleObj instanceof Title && !$desiredTitleObj->exists() ) {
325  LogEventsList::showLogExtract( $delNotice, [ 'delete', 'move' ],
326  $desiredTitleObj,
327  '', [ 'lim' => 10,
328  'conds' => [ 'log_action != ' . $this->localRepo->getReplicaDB()->addQuotes( 'revision' ) ],
329  'showIfEmpty' => false,
330  'msgKey' => [ 'upload-recreate-warning' ] ]
331  );
332  }
333  $form->addPreText( $delNotice );
334 
335  # Add text to form
336  $form->addPreText( '<div id="uploadtext">' .
337  $this->msg( 'uploadtext', [ $this->mDesiredDestName ] )->parseAsBlock() .
338  '</div>' );
339  # Add upload error message
340  $form->addPreText( $message );
341 
342  # Add footer to form
343  $uploadFooter = $this->msg( 'uploadfooter' );
344  if ( !$uploadFooter->isDisabled() ) {
345  $form->addPostText( '<div id="mw-upload-footer-message">'
346  . $uploadFooter->parseAsBlock() . "</div>\n" );
347  }
348 
349  return $form;
350  }
351 
355  protected function showViewDeletedLinks() {
356  $title = Title::makeTitleSafe( NS_FILE, $this->mDesiredDestName );
357  $user = $this->getUser();
358  // Show a subtitle link to deleted revisions (to sysops et al only)
359  if ( $title instanceof Title ) {
360  $count = $title->getDeletedEditsCount();
361  if ( $count > 0 && $this->getAuthority()->isAllowed( 'deletedhistory' ) ) {
362  $restorelink = $this->getLinkRenderer()->makeKnownLink(
363  SpecialPage::getTitleFor( 'Undelete', $title->getPrefixedText() ),
364  $this->msg( 'restorelink' )->numParams( $count )->text()
365  );
366  $link = $this->msg(
367  $this->getAuthority()->isAllowed( 'delete' ) ? 'thisisdeleted' : 'viewdeleted'
368  )->rawParams( $restorelink )->parseAsBlock();
369  $this->getOutput()->addHTML(
371  'div',
372  [ 'id' => 'contentSub2' ],
373  $link
374  )
375  );
376  }
377  }
378  }
379 
391  protected function showRecoverableUploadError( $message ) {
392  $stashStatus = $this->mUpload->tryStashFile( $this->getUser() );
393  if ( $stashStatus->isGood() ) {
394  $sessionKey = $stashStatus->getValue()->getFileKey();
395  $uploadWarning = 'upload-tryagain';
396  } else {
397  $sessionKey = null;
398  $uploadWarning = 'upload-tryagain-nostash';
399  }
400  $message = '<h2>' . $this->msg( 'uploaderror' )->escaped() . '</h2>' .
401  Html::errorBox( $message );
402 
403  $form = $this->getUploadForm( $message, $sessionKey );
404  $form->setSubmitText( $this->msg( $uploadWarning )->escaped() );
405  $this->showUploadForm( $form );
406  }
407 
416  protected function showUploadWarning( $warnings ) {
417  # If there are no warnings, or warnings we can ignore, return early.
418  # mDestWarningAck is set when some javascript has shown the warning
419  # to the user. mForReUpload is set when the user clicks the "upload a
420  # new version" link.
421  if ( !$warnings || ( count( $warnings ) == 1
422  && isset( $warnings['exists'] )
423  && ( $this->mDestWarningAck || $this->mForReUpload ) )
424  ) {
425  return false;
426  }
427 
428  $stashStatus = $this->mUpload->tryStashFile( $this->getUser() );
429  if ( $stashStatus->isGood() ) {
430  $sessionKey = $stashStatus->getValue()->getFileKey();
431  $uploadWarning = 'uploadwarning-text';
432  } else {
433  $sessionKey = null;
434  $uploadWarning = 'uploadwarning-text-nostash';
435  }
436 
437  // Add styles for the warning, reused from the live preview
438  $this->getOutput()->addModuleStyles( 'mediawiki.special' );
439 
440  $linkRenderer = $this->getLinkRenderer();
441  $warningHtml = '<h2>' . $this->msg( 'uploadwarning' )->escaped() . "</h2>\n"
442  . '<div class="mw-destfile-warning"><ul>';
443  foreach ( $warnings as $warning => $args ) {
444  if ( $warning == 'badfilename' ) {
445  $this->mDesiredDestName = Title::makeTitle( NS_FILE, $args )->getText();
446  }
447  if ( $warning == 'exists' ) {
448  $msg = "\t<li>" . self::getExistsWarning( $args ) . "</li>\n";
449  } elseif ( $warning == 'no-change' ) {
450  $file = $args;
451  $filename = $file->getTitle()->getPrefixedText();
452  $msg = "\t<li>" . $this->msg( 'fileexists-no-change', $filename )->parse() . "</li>\n";
453  } elseif ( $warning == 'duplicate-version' ) {
454  $file = $args[0];
455  $count = count( $args );
456  $filename = $file->getTitle()->getPrefixedText();
457  $message = $this->msg( 'fileexists-duplicate-version' )
458  ->params( $filename )
459  ->numParams( $count );
460  $msg = "\t<li>" . $message->parse() . "</li>\n";
461  } elseif ( $warning == 'was-deleted' ) {
462  # If the file existed before and was deleted, warn the user of this
463  $ltitle = SpecialPage::getTitleFor( 'Log' );
464  $llink = $linkRenderer->makeKnownLink(
465  $ltitle,
466  $this->msg( 'deletionlog' )->text(),
467  [],
468  [
469  'type' => 'delete',
470  'page' => Title::makeTitle( NS_FILE, $args )->getPrefixedText(),
471  ]
472  );
473  $msg = "\t<li>" . $this->msg( 'filewasdeleted' )->rawParams( $llink )->parse() . "</li>\n";
474  } elseif ( $warning == 'duplicate' ) {
475  $msg = $this->getDupeWarning( $args );
476  } elseif ( $warning == 'duplicate-archive' ) {
477  if ( $args === '' ) {
478  $msg = "\t<li>" . $this->msg( 'file-deleted-duplicate-notitle' )->parse()
479  . "</li>\n";
480  } else {
481  $msg = "\t<li>" . $this->msg( 'file-deleted-duplicate',
482  Title::makeTitle( NS_FILE, $args )->getPrefixedText() )->parse()
483  . "</li>\n";
484  }
485  } else {
486  if ( $args === true ) {
487  $args = [];
488  } elseif ( !is_array( $args ) ) {
489  $args = [ $args ];
490  }
491  $msg = "\t<li>" . $this->msg( $warning, $args )->parse() . "</li>\n";
492  }
493  $warningHtml .= $msg;
494  }
495  $warningHtml .= "</ul></div>\n";
496  $warningHtml .= $this->msg( $uploadWarning )->parseAsBlock();
497 
498  $form = $this->getUploadForm( $warningHtml, $sessionKey, /* $hideIgnoreWarning */ true );
499  $form->setSubmitTextMsg( 'upload-tryagain' );
500  $form->addButton( [
501  'name' => 'wpUploadIgnoreWarning',
502  'value' => $this->msg( 'ignorewarning' )->text()
503  ] );
504  $form->addButton( [
505  'name' => 'wpCancelUpload',
506  'value' => $this->msg( 'reuploaddesc' )->text()
507  ] );
508 
509  $this->showUploadForm( $form );
510 
511  # Indicate that we showed a form
512  return true;
513  }
514 
520  protected function showUploadError( $message ) {
521  $message = '<h2>' . $this->msg( 'uploadwarning' )->escaped() . '</h2>' .
522  Html::errorBox( $message );
523  $this->showUploadForm( $this->getUploadForm( $message ) );
524  }
525 
530  protected function processUpload() {
531  // Fetch the file if required
532  $status = $this->mUpload->fetchFile();
533  if ( !$status->isOK() ) {
534  $this->showUploadError( $this->getOutput()->parseAsInterface(
535  $status->getWikiText( false, false, $this->getLanguage() )
536  ) );
537 
538  return;
539  }
540  if ( !$this->getHookRunner()->onUploadForm_BeforeProcessing( $this ) ) {
541  wfDebug( "Hook 'UploadForm:BeforeProcessing' broke processing the file." );
542  // This code path is deprecated. If you want to break upload processing
543  // do so by hooking into the appropriate hooks in UploadBase::verifyUpload
544  // and UploadBase::verifyFile.
545  // If you use this hook to break uploading, the user will be returned
546  // an empty form with no error message whatsoever.
547  return;
548  }
549 
550  // Upload verification
551  $details = $this->mUpload->verifyUpload();
552  if ( $details['status'] != UploadBase::OK ) {
553  $this->processVerificationError( $details );
554 
555  return;
556  }
557 
558  // Verify permissions for this title
559  $user = $this->getUser();
560  $permErrors = $this->mUpload->verifyTitlePermissions( $user );
561  if ( $permErrors !== true ) {
562  $code = array_shift( $permErrors[0] );
563  $this->showRecoverableUploadError( $this->msg( $code, $permErrors[0] )->parse() );
564 
565  return;
566  }
567 
568  $this->mLocalFile = $this->mUpload->getLocalFile();
569 
570  // Check warnings if necessary
571  if ( !$this->mIgnoreWarning ) {
572  $warnings = $this->mUpload->checkWarnings( $user );
573  if ( $this->showUploadWarning( $warnings ) ) {
574  return;
575  }
576  }
577 
578  // This is as late as we can throttle, after expected issues have been handled
579  if ( UploadBase::isThrottled( $user ) ) {
581  $this->msg( 'actionthrottledtext' )->escaped()
582  );
583  return;
584  }
585 
586  // Get the page text if this is not a reupload
587  if ( !$this->mForReUpload ) {
588  $pageText = self::getInitialPageText( $this->mComment, $this->mLicense,
589  $this->mCopyrightStatus, $this->mCopyrightSource, $this->getConfig() );
590  } else {
591  $pageText = false;
592  }
593 
594  $changeTags = $this->getRequest()->getVal( 'wpChangeTags' );
595  if ( $changeTags === null || $changeTags === '' ) {
596  $changeTags = [];
597  } else {
598  $changeTags = array_filter( array_map( 'trim', explode( ',', $changeTags ) ) );
599  }
600 
601  if ( $changeTags ) {
602  $changeTagsStatus = ChangeTags::canAddTagsAccompanyingChange(
603  $changeTags, $user );
604  if ( !$changeTagsStatus->isOK() ) {
605  $this->showUploadError( $this->getOutput()->parseAsInterface(
606  $changeTagsStatus->getWikiText( false, false, $this->getLanguage() )
607  ) );
608 
609  return;
610  }
611  }
612 
613  $status = $this->mUpload->performUpload(
614  $this->mComment,
615  $pageText,
616  $this->mWatchthis,
617  $user,
618  $changeTags
619  );
620 
621  if ( !$status->isGood() ) {
623  $this->getOutput()->parseAsInterface(
624  $status->getWikiText( false, false, $this->getLanguage() )
625  )
626  );
627 
628  return;
629  }
630 
631  // Success, redirect to description page
632  $this->mUploadSuccessful = true;
633  $this->getHookRunner()->onSpecialUploadComplete( $this );
634  $this->getOutput()->redirect( $this->mLocalFile->getTitle()->getFullURL() );
635  }
636 
646  public static function getInitialPageText( $comment = '', $license = '',
647  $copyStatus = '', $source = '', Config $config = null
648  ) {
649  if ( $config === null ) {
650  wfDebug( __METHOD__ . ' called without a Config instance passed to it' );
651  $config = MediaWikiServices::getInstance()->getMainConfig();
652  }
653 
654  $msg = [];
655  $forceUIMsgAsContentMsg = (array)$config->get( MainConfigNames::ForceUIMsgAsContentMsg );
656  /* These messages are transcluded into the actual text of the description page.
657  * Thus, forcing them as content messages makes the upload to produce an int: template
658  * instead of hardcoding it there in the uploader language.
659  */
660  foreach ( [ 'license-header', 'filedesc', 'filestatus', 'filesource' ] as $msgName ) {
661  if ( in_array( $msgName, $forceUIMsgAsContentMsg ) ) {
662  $msg[$msgName] = "{{int:$msgName}}";
663  } else {
664  $msg[$msgName] = wfMessage( $msgName )->inContentLanguage()->text();
665  }
666  }
667 
668  $licenseText = '';
669  if ( $license !== '' ) {
670  $licenseText = '== ' . $msg['license-header'] . " ==\n{{" . $license . "}}\n";
671  }
672 
673  $pageText = $comment . "\n";
674  $headerText = '== ' . $msg['filedesc'] . ' ==';
675  if ( $comment !== '' && strpos( $comment, $headerText ) === false ) {
676  // prepend header to page text unless it's already there (or there is no content)
677  $pageText = $headerText . "\n" . $pageText;
678  }
679 
680  if ( $config->get( MainConfigNames::UseCopyrightUpload ) ) {
681  $pageText .= '== ' . $msg['filestatus'] . " ==\n" . $copyStatus . "\n";
682  $pageText .= $licenseText;
683  $pageText .= '== ' . $msg['filesource'] . " ==\n" . $source;
684  } else {
685  $pageText .= $licenseText;
686  }
687 
688  // allow extensions to modify the content
689  Hooks::runner()->onUploadForm_getInitialPageText( $pageText, $msg, $config );
690 
691  return $pageText;
692  }
693 
706  protected function getWatchCheck() {
707  $user = $this->getUser();
708  if ( $this->userOptionsLookup->getBoolOption( $user, 'watchdefault' ) ) {
709  // Watch all edits!
710  return true;
711  }
712 
713  $desiredTitleObj = Title::makeTitleSafe( NS_FILE, $this->mDesiredDestName );
714  if ( $desiredTitleObj instanceof Title &&
715  $this->watchlistManager->isWatched( $user, $desiredTitleObj ) ) {
716  // Already watched, don't change that
717  return true;
718  }
719 
720  $local = $this->localRepo->newFile( $this->mDesiredDestName );
721  if ( $local && $local->exists() ) {
722  // We're uploading a new version of an existing file.
723  // No creation, so don't watch it if we're not already.
724  return false;
725  } else {
726  // New page should get watched if that's our option.
727  return $this->userOptionsLookup->getBoolOption( $user, 'watchcreations' ) ||
728  $this->userOptionsLookup->getBoolOption( $user, 'watchuploads' );
729  }
730  }
731 
738  protected function processVerificationError( $details ) {
739  switch ( $details['status'] ) {
742  $this->showRecoverableUploadError( $this->msg( 'minlength1' )->escaped() );
743  break;
745  $this->showRecoverableUploadError( $this->msg( 'illegalfilename',
746  $details['filtered'] )->parse() );
747  break;
749  $this->showRecoverableUploadError( $this->msg( 'filename-toolong' )->escaped() );
750  break;
752  $this->showRecoverableUploadError( $this->msg( 'filetype-missing' )->parse() );
753  break;
755  $this->showRecoverableUploadError( $this->msg( 'windows-nonascii-filename' )->parse() );
756  break;
757 
760  $this->showUploadError( $this->msg( 'emptyfile' )->escaped() );
761  break;
763  $this->showUploadError( $this->msg( 'largefileserver' )->escaped() );
764  break;
766  $msg = $this->msg( 'filetype-banned-type' );
767  if ( isset( $details['blacklistedExt'] ) ) {
768  $msg->params( $this->getLanguage()->commaList( $details['blacklistedExt'] ) );
769  } else {
770  $msg->params( $details['finalExt'] );
771  }
772  $extensions =
773  array_unique( $this->getConfig()->get( MainConfigNames::FileExtensions ) );
774  $msg->params( $this->getLanguage()->commaList( $extensions ),
775  count( $extensions ) );
776 
777  // Add PLURAL support for the first parameter. This results
778  // in a bit unlogical parameter sequence, but does not break
779  // old translations
780  if ( isset( $details['blacklistedExt'] ) ) {
781  $msg->params( count( $details['blacklistedExt'] ) );
782  } else {
783  $msg->params( 1 );
784  }
785 
786  $this->showUploadError( $msg->parse() );
787  break;
789  unset( $details['status'] );
790  $code = array_shift( $details['details'] );
791  $this->showUploadError( $this->msg( $code, $details['details'] )->parse() );
792  break;
794  if ( is_array( $details['error'] ) ) { # allow hooks to return error details in an array
795  $args = $details['error'];
796  $error = array_shift( $args );
797  } else {
798  $error = $details['error'];
799  $args = null;
800  }
801 
802  $this->showUploadError( $this->msg( $error, $args )->parse() );
803  break;
804  default:
805  throw new MWException( __METHOD__ . ": Unknown value `{$details['status']}`" );
806  }
807  }
808 
814  protected function unsaveUploadedFile() {
815  if ( !( $this->mUpload instanceof UploadFromStash ) ) {
816  return true;
817  }
818  $success = $this->mUpload->unsaveUploadedFile();
819  if ( !$success ) {
820  $this->getOutput()->showFatalError(
821  $this->msg( 'filedeleteerror' )
822  ->params( $this->mUpload->getTempPath() )
823  ->escaped()
824  );
825 
826  return false;
827  } else {
828  return true;
829  }
830  }
831 
841  public static function getExistsWarning( $exists ) {
842  if ( !$exists ) {
843  return '';
844  }
845 
846  $file = $exists['file'];
847  $filename = $file->getTitle()->getPrefixedText();
848  $warnMsg = null;
849 
850  if ( $exists['warning'] == 'exists' ) {
851  // Exact match
852  $warnMsg = wfMessage( 'fileexists', $filename );
853  } elseif ( $exists['warning'] == 'page-exists' ) {
854  // Page exists but file does not
855  $warnMsg = wfMessage( 'filepageexists', $filename );
856  } elseif ( $exists['warning'] == 'exists-normalized' ) {
857  $warnMsg = wfMessage( 'fileexists-extension', $filename,
858  $exists['normalizedFile']->getTitle()->getPrefixedText() );
859  } elseif ( $exists['warning'] == 'thumb' ) {
860  // Swapped argument order compared with other messages for backwards compatibility
861  $warnMsg = wfMessage( 'fileexists-thumbnail-yes',
862  $exists['thumbFile']->getTitle()->getPrefixedText(), $filename );
863  } elseif ( $exists['warning'] == 'thumb-name' ) {
864  // Image w/o '180px-' does not exists, but we do not like these filenames
865  $name = $file->getName();
866  $badPart = substr( $name, 0, strpos( $name, '-' ) + 1 );
867  $warnMsg = wfMessage( 'file-thumbnail-no', $badPart );
868  } elseif ( $exists['warning'] == 'bad-prefix' ) {
869  $warnMsg = wfMessage( 'filename-bad-prefix', $exists['prefix'] );
870  }
871 
872  return $warnMsg ? $warnMsg->page( $file->getTitle() )->parse() : '';
873  }
874 
880  public function getDupeWarning( $dupes ) {
881  if ( !$dupes ) {
882  return '';
883  }
884 
885  $gallery = ImageGalleryBase::factory( false, $this->getContext() );
886  $gallery->setShowBytes( false );
887  $gallery->setShowDimensions( false );
888  foreach ( $dupes as $file ) {
889  $gallery->add( $file->getTitle() );
890  }
891 
892  return '<li>' .
893  $this->msg( 'file-exists-duplicate' )->numParams( count( $dupes ) )->parse() .
894  $gallery->toHTML() . "</li>\n";
895  }
896 
897  protected function getGroupName() {
898  return 'media';
899  }
900 
909  public static function rotationEnabled() {
910  $bitmapHandler = new BitmapHandler();
911  return $bitmapHandler->autoRotateEnabled();
912  }
913 }
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:625
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:150
static runner()
Get a HookRunner instance for calling hooks using the new interfaces.
Definition: Hooks.php:173
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition: Html.php:214
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.
MediaWiki exception.
Definition: MWException.php:29
A class containing constants representing the names of configuration variables.
Service locator for MediaWiki core services.
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.
LinkRenderer null $linkRenderer
Definition: SpecialPage.php:81
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getAuthority()
Shortcut to get the Authority executing this instance.
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
showViewDeletedLinks()
Shows the "view X deleted revisions link"".
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.
LocalRepo $localRepo
string $uploadFormTextAfterSummary
Raw html injection point for hooks not using HTMLForm.
$mDestWarningAck
Hidden variables.
UserOptionsLookup $userOptionsLookup
getDupeWarning( $dupes)
Construct a warning and a gallery from an array of duplicate files.
showUploadForm( $form)
Show the main upload form.
WatchlistManager $watchlistManager
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.
NamespaceInfo $nsInfo
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:49
exists( $flags=0)
Check if page exists.
Definition: Title.php:3469
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:664
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:638
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:29
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:68
Interface for configuration instances.
Definition: Config.php:30
if( $line===false) $args
Definition: mcc.php:124
$source
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
Definition: router.php:42