61 parent::__construct(
'Upload',
'upload' );
63 $services = MediaWikiServices::getInstance();
64 $repoGroup = $repoGroup ?? $services->getRepoGroup();
65 $this->localRepo = $repoGroup->getLocalRepo();
67 $this->nsInfo =
$nsInfo ?? $services->getNamespaceInfo();
125 $this->mRequest = $request = $this->
getRequest();
126 $this->mSourceType = $request->getVal(
'wpSourceType',
'file' );
127 $this->mUpload = UploadBase::createFromRequest( $request );
128 $this->mUploadClicked = $request->wasPosted()
129 && ( $request->getCheck(
'wpUpload' )
130 || $request->getCheck(
'wpUploadIgnoreWarning' ) );
133 $this->mDesiredDestName = $request->getText(
'wpDestFile' );
134 if ( !$this->mDesiredDestName && $request->getFileName(
'wpUploadFile' ) !== null ) {
135 $this->mDesiredDestName = $request->getFileName(
'wpUploadFile' );
137 $this->mLicense = $request->getText(
'wpLicense' );
139 $this->mDestWarningAck = $request->getText(
'wpDestFileWarningAck' );
140 $this->mIgnoreWarning = $request->getCheck(
'wpIgnoreWarning' )
141 || $request->getCheck(
'wpUploadIgnoreWarning' );
142 $this->mWatchthis = $request->getBool(
'wpWatchthis' ) && $this->
getUser()->isRegistered();
143 $this->mCopyrightStatus = $request->getText(
'wpUploadCopyStatus' );
144 $this->mCopyrightSource = $request->getText(
'wpUploadSource' );
146 $this->mForReUpload = $request->getBool(
'wpForReUpload' );
148 $commentDefault =
'';
149 $commentMsg = $this->
msg(
'upload-default-description' )->inContentLanguage();
150 if ( !$this->mForReUpload && !$commentMsg->isDisabled() ) {
151 $commentDefault = $commentMsg->plain();
153 $this->mComment = $request->getText(
'wpUploadDescription', $commentDefault );
155 $this->mCancelUpload = $request->getCheck(
'wpCancelUpload' )
156 || $request->getCheck(
'wpReUpload' );
159 $token = $request->getVal(
'wpEditToken' );
160 $this->mTokenOk = $this->
getUser()->matchEditToken( $token );
162 $this->uploadFormTextTop =
'';
163 $this->uploadFormTextAfterSummary =
'';
175 return UploadBase::isEnabled() && parent::userCanExecute( $user );
194 # Check uploading enabled
195 if ( !UploadBase::isEnabled() ) {
196 throw new ErrorPageError(
'uploaddisabled',
'uploaddisabledtext' );
203 $permissionRequired = UploadBase::isAllowed( $user );
204 if ( $permissionRequired !==
true ) {
209 if ( $user->isBlockedFromUpload() ) {
213 $this->getLanguage(),
214 $this->getRequest()->getIP()
219 if ( $user->isBlockedGlobally() ) {
221 $user->getGlobalBlock(),
223 $this->getLanguage(),
224 $this->getRequest()->getIP()
228 # Check whether we actually want to allow changing stuff
233 # Unsave the temporary file in case this was a cancelled upload
235 # Something went wrong, so unsaveUploadedFile showed a warning
239 # Process upload or show a form
241 $this->mTokenOk && !$this->mCancelUpload &&
242 ( $this->mUpload && $this->mUploadClicked )
246 # Backwards compatibility hook
247 if ( !$this->
getHookRunner()->onUploadForm_initial( $this ) ) {
248 wfDebug(
"Hook 'UploadForm:initial' broke output of the upload form" );
256 if ( $this->mUpload ) {
257 $this->mUpload->cleanupTempFile();
267 # Add links if file was previously deleted
268 if ( $this->mDesiredDestName ) {
287 protected function getUploadForm( $message =
'', $sessionKey =
'', $hideIgnoreWarning =
false ) {
294 'forreupload' => $this->mForReUpload,
295 'sessionkey' => $sessionKey,
296 'hideignorewarning' => $hideIgnoreWarning,
297 'destwarningack' => (
bool)$this->mDestWarningAck,
299 'description' => $this->mComment,
300 'texttop' => $this->uploadFormTextTop,
301 'textaftersummary' => $this->uploadFormTextAfterSummary,
302 'destfile' => $this->mDesiredDestName,
311 # Check the token, but only if necessary
313 !$this->mTokenOk && !$this->mCancelUpload &&
314 ( $this->mUpload && $this->mUploadClicked )
316 $form->addPreText( $this->
msg(
'session_fail_preview' )->parse() );
319 # Give a notice if the user is uploading a file that has been deleted or moved
320 # Note that this is independent from the message 'filewasdeleted'
321 $desiredTitleObj = Title::makeTitleSafe(
NS_FILE, $this->mDesiredDestName );
323 if ( $desiredTitleObj instanceof
Title && !$desiredTitleObj->
exists() ) {
324 LogEventsList::showLogExtract( $delNotice, [
'delete',
'move' ],
327 'conds' => [
'log_action != ' . $this->localRepo->getReplicaDB()->addQuotes(
'revision' ) ],
328 'showIfEmpty' =>
false,
329 'msgKey' => [
'upload-recreate-warning' ] ]
332 $form->addPreText( $delNotice );
335 $form->addPreText(
'<div id="uploadtext">' .
336 $this->
msg(
'uploadtext', [ $this->mDesiredDestName ] )->parseAsBlock() .
338 # Add upload error message
339 $form->addPreText( $message );
342 $uploadFooter = $this->
msg(
'uploadfooter' );
343 if ( !$uploadFooter->isDisabled() ) {
344 $form->addPostText(
'<div id="mw-upload-footer-message">'
345 . $uploadFooter->parseAsBlock() .
"</div>\n" );
355 $title = Title::makeTitleSafe(
NS_FILE, $this->mDesiredDestName );
359 $count =
$title->getDeletedEditsCount();
360 if ( $count > 0 && $this->
getAuthority()->isAllowed(
'deletedhistory' ) ) {
363 $this->msg(
'restorelink' )->numParams( $count )->text()
366 $this->
getAuthority()->isAllowed(
'delete' ) ?
'thisisdeleted' :
'viewdeleted'
367 )->rawParams( $restorelink )->parseAsBlock();
371 [
'id' =>
'contentSub2' ],
391 $stashStatus = $this->mUpload->tryStashFile( $this->
getUser() );
392 if ( $stashStatus->isGood() ) {
393 $sessionKey = $stashStatus->getValue()->getFileKey();
394 $uploadWarning =
'upload-tryagain';
397 $uploadWarning =
'upload-tryagain-nostash';
399 $message =
'<h2>' . $this->
msg(
'uploaderror' )->escaped() .
'</h2>' .
400 Html::errorBox( $message );
403 $form->setSubmitText( $this->
msg( $uploadWarning )->escaped() );
416 # If there are no warnings, or warnings we can ignore, return early.
417 # mDestWarningAck is set when some javascript has shown the warning
418 # to the user. mForReUpload is set when the user clicks the "upload a
420 if ( !$warnings || ( count( $warnings ) == 1
421 && isset( $warnings[
'exists'] )
422 && ( $this->mDestWarningAck || $this->mForReUpload ) )
427 $stashStatus = $this->mUpload->tryStashFile( $this->
getUser() );
428 if ( $stashStatus->isGood() ) {
429 $sessionKey = $stashStatus->getValue()->getFileKey();
430 $uploadWarning =
'uploadwarning-text';
433 $uploadWarning =
'uploadwarning-text-nostash';
437 $this->
getOutput()->addModuleStyles(
'mediawiki.special' );
440 $warningHtml =
'<h2>' . $this->
msg(
'uploadwarning' )->escaped() .
"</h2>\n"
441 .
'<div class="mw-destfile-warning"><ul>';
442 foreach ( $warnings as $warning =>
$args ) {
443 if ( $warning ==
'badfilename' ) {
444 $this->mDesiredDestName = Title::makeTitle(
NS_FILE,
$args )->getText();
446 if ( $warning ==
'exists' ) {
447 $msg =
"\t<li>" . self::getExistsWarning(
$args ) .
"</li>\n";
448 } elseif ( $warning ==
'no-change' ) {
450 $filename =
$file->getTitle()->getPrefixedText();
451 $msg =
"\t<li>" . $this->
msg(
'fileexists-no-change', $filename )->parse() .
"</li>\n";
452 } elseif ( $warning ==
'duplicate-version' ) {
454 $count = count(
$args );
455 $filename =
$file->getTitle()->getPrefixedText();
456 $message = $this->
msg(
'fileexists-duplicate-version' )
457 ->params( $filename )
458 ->numParams( $count );
459 $msg =
"\t<li>" . $message->parse() .
"</li>\n";
460 } elseif ( $warning ==
'was-deleted' ) {
461 # If the file existed before and was deleted, warn the user of this
465 $this->
msg(
'deletionlog' )->text(),
469 'page' => Title::makeTitle(
NS_FILE,
$args )->getPrefixedText(),
472 $msg =
"\t<li>" . $this->
msg(
'filewasdeleted' )->rawParams( $llink )->parse() .
"</li>\n";
473 } elseif ( $warning ==
'duplicate' ) {
475 } elseif ( $warning ==
'duplicate-archive' ) {
476 if (
$args ===
'' ) {
477 $msg =
"\t<li>" . $this->
msg(
'file-deleted-duplicate-notitle' )->parse()
480 $msg =
"\t<li>" . $this->
msg(
'file-deleted-duplicate',
481 Title::makeTitle(
NS_FILE,
$args )->getPrefixedText() )->parse()
485 if (
$args ===
true ) {
487 } elseif ( !is_array(
$args ) ) {
490 $msg =
"\t<li>" . $this->
msg( $warning,
$args )->parse() .
"</li>\n";
492 $warningHtml .= $msg;
494 $warningHtml .=
"</ul></div>\n";
495 $warningHtml .= $this->
msg( $uploadWarning )->parseAsBlock();
497 $form = $this->
getUploadForm( $warningHtml, $sessionKey,
true );
498 $form->setSubmitTextMsg(
'upload-tryagain' );
500 'name' =>
'wpUploadIgnoreWarning',
501 'value' => $this->
msg(
'ignorewarning' )->text()
504 'name' =>
'wpCancelUpload',
505 'value' => $this->
msg(
'reuploaddesc' )->text()
510 # Indicate that we showed a form
520 $message =
'<h2>' . $this->
msg(
'uploadwarning' )->escaped() .
'</h2>' .
521 Html::errorBox( $message );
531 $status = $this->mUpload->fetchFile();
532 if ( !$status->isOK() ) {
534 $status->getWikiText(
false,
false, $this->getLanguage() )
539 if ( !$this->
getHookRunner()->onUploadForm_BeforeProcessing( $this ) ) {
540 wfDebug(
"Hook 'UploadForm:BeforeProcessing' broke processing the file." );
550 $details = $this->mUpload->verifyUpload();
551 if ( $details[
'status'] != UploadBase::OK ) {
559 $permErrors = $this->mUpload->verifyTitlePermissions( $user );
560 if ( $permErrors !==
true ) {
561 $code = array_shift( $permErrors[0] );
567 $this->mLocalFile = $this->mUpload->getLocalFile();
570 if ( !$this->mIgnoreWarning ) {
571 $warnings = $this->mUpload->checkWarnings( $user );
578 if ( UploadBase::isThrottled( $user ) ) {
580 $this->
msg(
'actionthrottledtext' )->escaped()
586 if ( !$this->mForReUpload ) {
587 $pageText = self::getInitialPageText( $this->mComment, $this->mLicense,
588 $this->mCopyrightStatus, $this->mCopyrightSource, $this->
getConfig() );
593 $changeTags = $this->
getRequest()->getVal(
'wpChangeTags' );
594 if ( $changeTags ===
null || $changeTags ===
'' ) {
597 $changeTags = array_filter( array_map(
'trim', explode(
',', $changeTags ) ) );
602 $changeTags, $user );
603 if ( !$changeTagsStatus->isOK() ) {
605 $changeTagsStatus->getWikiText(
false,
false, $this->getLanguage() )
612 $status = $this->mUpload->performUpload(
620 if ( !$status->isGood() ) {
623 $status->getWikiText(
false,
false, $this->getLanguage() )
631 $this->mUploadSuccessful =
true;
633 $this->
getOutput()->redirect( $this->mLocalFile->getTitle()->getFullURL() );
648 if ( $config ===
null ) {
649 wfDebug( __METHOD__ .
' called without a Config instance passed to it' );
650 $config = MediaWikiServices::getInstance()->getMainConfig();
654 $forceUIMsgAsContentMsg = (array)$config->get(
'ForceUIMsgAsContentMsg' );
659 foreach ( [
'license-header',
'filedesc',
'filestatus',
'filesource' ] as $msgName ) {
660 if ( in_array( $msgName, $forceUIMsgAsContentMsg ) ) {
661 $msg[$msgName] =
"{{int:$msgName}}";
663 $msg[$msgName] =
wfMessage( $msgName )->inContentLanguage()->text();
668 if ( $license !==
'' ) {
669 $licenseText =
'== ' . $msg[
'license-header'] .
" ==\n{{" . $license .
"}}\n";
672 $pageText = $comment .
"\n";
673 $headerText =
'== ' . $msg[
'filedesc'] .
' ==';
674 if ( $comment !==
'' && strpos( $comment, $headerText ) ===
false ) {
676 $pageText = $headerText .
"\n" . $pageText;
679 if ( $config->get(
'UseCopyrightUpload' ) ) {
680 $pageText .=
'== ' . $msg[
'filestatus'] .
" ==\n" . $copyStatus .
"\n";
681 $pageText .= $licenseText;
682 $pageText .=
'== ' . $msg[
'filesource'] .
" ==\n" .
$source;
684 $pageText .= $licenseText;
688 Hooks::runner()->onUploadForm_getInitialPageText( $pageText, $msg, $config );
707 if ( $this->userOptionsLookup->getBoolOption( $user,
'watchdefault' ) ) {
712 $desiredTitleObj = Title::makeTitleSafe(
NS_FILE, $this->mDesiredDestName );
713 if ( $desiredTitleObj instanceof
Title &&
714 $this->watchlistManager->isWatched( $user, $desiredTitleObj ) ) {
719 $local = $this->localRepo->newFile( $this->mDesiredDestName );
720 if ( $local && $local->exists() ) {
726 return $this->userOptionsLookup->getBoolOption( $user,
'watchcreations' ) ||
727 $this->userOptionsLookup->getBoolOption( $user,
'watchuploads' );
738 switch ( $details[
'status'] ) {
740 case UploadBase::MIN_LENGTH_PARTNAME:
743 case UploadBase::ILLEGAL_FILENAME:
745 $details[
'filtered'] )->parse() );
747 case UploadBase::FILENAME_TOO_LONG:
750 case UploadBase::FILETYPE_MISSING:
753 case UploadBase::WINDOWS_NONASCII_FILENAME:
758 case UploadBase::EMPTY_FILE:
761 case UploadBase::FILE_TOO_LARGE:
764 case UploadBase::FILETYPE_BADTYPE:
765 $msg = $this->
msg(
'filetype-banned-type' );
766 if ( isset( $details[
'blacklistedExt'] ) ) {
767 $msg->params( $this->
getLanguage()->commaList( $details[
'blacklistedExt'] ) );
769 $msg->params( $details[
'finalExt'] );
771 $extensions = array_unique( $this->
getConfig()->
get(
'FileExtensions' ) );
772 $msg->params( $this->
getLanguage()->commaList( $extensions ),
773 count( $extensions ) );
778 if ( isset( $details[
'blacklistedExt'] ) ) {
779 $msg->params( count( $details[
'blacklistedExt'] ) );
786 case UploadBase::VERIFICATION_ERROR:
787 unset( $details[
'status'] );
788 $code = array_shift( $details[
'details'] );
791 case UploadBase::HOOK_ABORTED:
792 if ( is_array( $details[
'error'] ) ) { # allow hooks to
return error details in an array
793 $args = $details[
'error'];
794 $error = array_shift(
$args );
796 $error = $details[
'error'];
803 throw new MWException( __METHOD__ .
": Unknown value `{$details['status']}`" );
816 $success = $this->mUpload->unsaveUploadedFile();
819 $this->
msg(
'filedeleteerror' )
820 ->params( $this->mUpload->getTempPath() )
844 $file = $exists[
'file'];
845 $filename =
$file->getTitle()->getPrefixedText();
848 if ( $exists[
'warning'] ==
'exists' ) {
850 $warnMsg =
wfMessage(
'fileexists', $filename );
851 } elseif ( $exists[
'warning'] ==
'page-exists' ) {
853 $warnMsg =
wfMessage(
'filepageexists', $filename );
854 } elseif ( $exists[
'warning'] ==
'exists-normalized' ) {
855 $warnMsg =
wfMessage(
'fileexists-extension', $filename,
856 $exists[
'normalizedFile']->
getTitle()->getPrefixedText() );
857 } elseif ( $exists[
'warning'] ==
'thumb' ) {
859 $warnMsg =
wfMessage(
'fileexists-thumbnail-yes',
860 $exists[
'thumbFile']->
getTitle()->getPrefixedText(), $filename );
861 } elseif ( $exists[
'warning'] ==
'thumb-name' ) {
863 $name =
$file->getName();
864 $badPart = substr( $name, 0, strpos( $name,
'-' ) + 1 );
865 $warnMsg =
wfMessage(
'file-thumbnail-no', $badPart );
866 } elseif ( $exists[
'warning'] ==
'bad-prefix' ) {
867 $warnMsg =
wfMessage(
'filename-bad-prefix', $exists[
'prefix'] );
870 return $warnMsg ? $warnMsg->page(
$file->getTitle() )->parse() :
'';
883 $gallery = ImageGalleryBase::factory(
false, $this->
getContext() );
884 $gallery->setShowBytes(
false );
885 $gallery->setShowDimensions(
false );
886 foreach ( $dupes as
$file ) {
887 $gallery->add(
$file->getTitle() );
891 $this->
msg(
'file-exists-duplicate' )->numParams( count( $dupes ) )->parse() .
892 $gallery->toHTML() .
"</li>\n";
909 return $bitmapHandler->autoRotateEnabled();
WatchlistManager $watchlistManager
UserOptionsLookup $userOptionsLookup
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.
Generic handler for bitmap images.
An IContextSource implementation which will inherit context from another source but allow individual ...
An error page which can definitely be safely rendered using the OutputPage.
WebRequest clone which takes values from a provided array.
Class to represent a local file in the wiki's own database.
A repository that stores files in the local filesystem and registers them in the wiki's own database.
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.
Parent class for all special pages.
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,...
LinkRenderer null $linkRenderer
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.
showViewDeletedLinks()
Shows the "view X deleted revivions 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.
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.
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.
exists( $flags=0)
Check if page exists.
UploadBase and subclasses are the backend of MediaWiki's file uploads.
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,...
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form stripping il...
Interface for configuration instances.
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.