43 private $userOptionsLookup;
49 private $watchlistManager;
63 parent::__construct(
'Upload',
'upload' );
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();
127 $this->mRequest = $request = $this->
getRequest();
128 $this->mSourceType = $request->getVal(
'wpSourceType',
'file' );
130 $this->mUploadClicked = $request->wasPosted()
131 && ( $request->getCheck(
'wpUpload' )
132 || $request->getCheck(
'wpUploadIgnoreWarning' ) );
135 $this->mDesiredDestName = $request->getText(
'wpDestFile' );
136 if ( !$this->mDesiredDestName && $request->getFileName(
'wpUploadFile' ) !== null ) {
137 $this->mDesiredDestName = $request->getFileName(
'wpUploadFile' );
139 $this->mLicense = $request->getText(
'wpLicense' );
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' );
148 $this->mForReUpload = $request->getBool(
'wpForReUpload' );
150 $commentDefault =
'';
151 $commentMsg = $this->
msg(
'upload-default-description' )->inContentLanguage();
152 if ( !$this->mForReUpload && !$commentMsg->isDisabled() ) {
153 $commentDefault = $commentMsg->plain();
155 $this->mComment = $request->getText(
'wpUploadDescription', $commentDefault );
157 $this->mCancelUpload = $request->getCheck(
'wpCancelUpload' )
158 || $request->getCheck(
'wpReUpload' );
161 $token = $request->getVal(
'wpEditToken' );
162 $this->mTokenOk = $this->
getUser()->matchEditToken( $token );
164 $this->uploadFormTextTop =
'';
165 $this->uploadFormTextAfterSummary =
'';
189 # Check uploading enabled
191 throw new ErrorPageError(
'uploaddisabled',
'uploaddisabledtext' );
199 if ( $permissionRequired !==
true ) {
204 if ( $user->isBlockedFromUpload() ) {
209 $this->getLanguage(),
210 $this->getRequest()->getIP()
214 # Check whether we actually want to allow changing stuff
219 # Unsave the temporary file in case this was a cancelled upload
221 # Something went wrong, so unsaveUploadedFile showed a warning
225 # Process upload or show a form
227 $this->mTokenOk && !$this->mCancelUpload &&
228 ( $this->mUpload && $this->mUploadClicked )
232 # Backwards compatibility hook
233 if ( !$this->
getHookRunner()->onUploadForm_initial( $this ) ) {
234 wfDebug(
"Hook 'UploadForm:initial' broke output of the upload form" );
242 if ( $this->mUpload ) {
243 $this->mUpload->cleanupTempFile();
268 protected function getUploadForm( $message =
'', $sessionKey =
'', $hideIgnoreWarning =
false ) {
273 'forreupload' => $this->mForReUpload,
274 'sessionkey' => $sessionKey,
275 'hideignorewarning' => $hideIgnoreWarning,
276 'destwarningack' => (
bool)$this->mDestWarningAck,
278 'description' => $this->mComment,
279 'texttop' => $this->uploadFormTextTop,
280 'textaftersummary' => $this->uploadFormTextAfterSummary,
281 'destfile' => $this->mDesiredDestName,
292 # Check the token, but only if necessary
294 !$this->mTokenOk && !$this->mCancelUpload &&
295 ( $this->mUpload && $this->mUploadClicked )
297 $form->addPreText( $this->
msg(
'session_fail_preview' )->parse() );
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'
304 if ( $desiredTitleObj instanceof
Title && !$desiredTitleObj->
exists() ) {
308 'conds' => [
'log_action != ' . $this->localRepo->getReplicaDB()->addQuotes(
'revision' ) ],
309 'showIfEmpty' =>
false,
310 'msgKey' => [
'upload-recreate-warning' ] ]
313 $form->addPreText( $delNotice );
316 $form->addPreText(
'<div id="uploadtext">' .
317 $this->
msg(
'uploadtext', [ $this->mDesiredDestName ] )->parseAsBlock() .
319 # Add upload error message
320 $form->addPreText( $message );
323 $uploadFooter = $this->
msg(
'uploadfooter' );
324 if ( !$uploadFooter->isDisabled() ) {
325 $form->addPostText(
'<div id="mw-upload-footer-message">'
326 . $uploadFooter->parseAsBlock() .
"</div>\n" );
344 $stashStatus = $this->mUpload->tryStashFile( $this->
getUser() );
345 if ( $stashStatus->isGood() ) {
346 $sessionKey = $stashStatus->getValue()->getFileKey();
347 $uploadWarning =
'upload-tryagain';
350 $uploadWarning =
'upload-tryagain-nostash';
352 $message =
'<h2>' . $this->
msg(
'uploaderror' )->escaped() .
'</h2>' .
356 $form->setSubmitText( $this->
msg( $uploadWarning )->escaped() );
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
373 if ( !$warnings || ( count( $warnings ) == 1
374 && isset( $warnings[
'exists'] )
375 && ( $this->mDestWarningAck || $this->mForReUpload ) )
380 $stashStatus = $this->mUpload->tryStashFile( $this->
getUser() );
381 if ( $stashStatus->isGood() ) {
382 $sessionKey = $stashStatus->getValue()->getFileKey();
383 $uploadWarning =
'uploadwarning-text';
386 $uploadWarning =
'uploadwarning-text-nostash';
390 $this->
getOutput()->addModuleStyles(
'mediawiki.special' );
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' ) {
399 if ( $warning ==
'exists' ) {
401 } elseif ( $warning ==
'no-change' ) {
403 $filename =
$file->getTitle()->getPrefixedText();
404 $msg =
"\t<li>" . $this->
msg(
'fileexists-no-change', $filename )->parse() .
"</li>\n";
405 } elseif ( $warning ==
'duplicate-version' ) {
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
416 $llink = $linkRenderer->makeKnownLink(
418 $this->
msg(
'deletionlog' )->text(),
425 $msg =
"\t<li>" . $this->
msg(
'filewasdeleted' )->rawParams( $llink )->parse() .
"</li>\n";
426 } elseif ( $warning ==
'duplicate' ) {
428 } elseif ( $warning ==
'duplicate-archive' ) {
429 if ( $args ===
'' ) {
430 $msg =
"\t<li>" . $this->
msg(
'file-deleted-duplicate-notitle' )->parse()
433 $msg =
"\t<li>" . $this->
msg(
'file-deleted-duplicate',
438 if ( $args ===
true ) {
440 } elseif ( !is_array( $args ) ) {
443 $msg =
"\t<li>" . $this->
msg( $warning, $args )->parse() .
"</li>\n";
445 $warningHtml .= $msg;
447 $warningHtml .=
"</ul></div>\n";
448 $warningHtml .= $this->
msg( $uploadWarning )->parseAsBlock();
450 $form = $this->
getUploadForm( $warningHtml, $sessionKey,
true );
451 $form->setSubmitTextMsg(
'upload-tryagain' );
453 'name' =>
'wpUploadIgnoreWarning',
454 'value' => $this->
msg(
'ignorewarning' )->text()
457 'name' =>
'wpCancelUpload',
458 'value' => $this->
msg(
'reuploaddesc' )->text()
463 # Indicate that we showed a form
473 $message =
'<h2>' . $this->
msg(
'uploadwarning' )->escaped() .
'</h2>' .
484 $status = $this->mUpload->fetchFile();
485 if ( !$status->isOK() ) {
487 $status->getWikiText(
false,
false, $this->getLanguage() )
492 if ( !$this->
getHookRunner()->onUploadForm_BeforeProcessing( $this ) ) {
493 wfDebug(
"Hook 'UploadForm:BeforeProcessing' broke processing the file." );
503 $details = $this->mUpload->verifyUpload();
512 $permErrors = $this->mUpload->verifyTitlePermissions( $user );
513 if ( $permErrors !==
true ) {
514 $code = array_shift( $permErrors[0] );
520 $this->mLocalFile = $this->mUpload->getLocalFile();
523 if ( !$this->mIgnoreWarning ) {
524 $warnings = $this->mUpload->checkWarnings( $user );
533 $this->
msg(
'actionthrottledtext' )->escaped()
539 if ( !$this->mForReUpload ) {
541 $this->mCopyrightStatus, $this->mCopyrightSource, $this->
getConfig() );
546 $changeTags = $this->
getRequest()->getVal(
'wpChangeTags' );
547 if ( $changeTags ===
null || $changeTags ===
'' ) {
550 $changeTags = array_filter( array_map(
'trim', explode(
',', $changeTags ) ) );
555 $changeTags, $user );
556 if ( !$changeTagsStatus->isOK() ) {
558 $changeTagsStatus->getWikiText(
false,
false, $this->getLanguage() )
565 $status = $this->mUpload->performUpload(
573 if ( !$status->isGood() ) {
576 $status->getWikiText(
false,
false, $this->getLanguage() )
584 $this->mUploadSuccessful =
true;
586 $this->
getOutput()->redirect( $this->mLocalFile->getTitle()->getFullURL() );
601 if ( $config ===
null ) {
602 wfDebug( __METHOD__ .
' called without a Config instance passed to it' );
603 $config = MediaWikiServices::getInstance()->getMainConfig();
607 $forceUIMsgAsContentMsg = (array)$config->get( MainConfigNames::ForceUIMsgAsContentMsg );
612 foreach ( [
'license-header',
'filedesc',
'filestatus',
'filesource' ] as $msgName ) {
613 if ( in_array( $msgName, $forceUIMsgAsContentMsg ) ) {
614 $msg[$msgName] =
"{{int:$msgName}}";
616 $msg[$msgName] =
wfMessage( $msgName )->inContentLanguage()->text();
621 if ( $license !==
'' ) {
622 $licenseText =
'== ' . $msg[
'license-header'] .
" ==\n{{" . $license .
"}}\n";
625 $pageText = $comment .
"\n";
626 $headerText =
'== ' . $msg[
'filedesc'] .
' ==';
627 if ( $comment !==
'' && !str_contains( $comment, $headerText ) ) {
629 $pageText = $headerText .
"\n" . $pageText;
632 if ( $config->get( MainConfigNames::UseCopyrightUpload ) ) {
633 $pageText .=
'== ' . $msg[
'filestatus'] .
" ==\n" . $copyStatus .
"\n";
634 $pageText .= $licenseText;
635 $pageText .=
'== ' . $msg[
'filesource'] .
" ==\n" .
$source;
637 $pageText .= $licenseText;
641 Hooks::runner()->onUploadForm_getInitialPageText( $pageText, $msg, $config );
660 if ( $this->userOptionsLookup->getBoolOption( $user,
'watchdefault' ) ) {
666 if ( $desiredTitleObj instanceof
Title &&
667 $this->watchlistManager->isWatched( $user, $desiredTitleObj ) ) {
672 $local = $this->localRepo->newFile( $this->mDesiredDestName );
673 if ( $local && $local->exists() ) {
679 return $this->userOptionsLookup->getBoolOption( $user,
'watchcreations' ) ||
680 $this->userOptionsLookup->getBoolOption( $user,
'watchuploads' );
690 switch ( $details[
'status'] ) {
697 $details[
'filtered'] )->parse() );
717 $msg = $this->
msg(
'filetype-banned-type' );
718 if ( isset( $details[
'blacklistedExt'] ) ) {
719 $msg->params( $this->
getLanguage()->commaList( $details[
'blacklistedExt'] ) );
721 $msg->params( $details[
'finalExt'] );
724 array_unique( $this->
getConfig()->
get( MainConfigNames::FileExtensions ) );
725 $msg->params( $this->
getLanguage()->commaList( $extensions ),
726 count( $extensions ) );
731 if ( isset( $details[
'blacklistedExt'] ) ) {
732 $msg->params( count( $details[
'blacklistedExt'] ) );
740 unset( $details[
'status'] );
741 $code = array_shift( $details[
'details'] );
745 if ( is_array( $details[
'error'] ) ) { # allow hooks to
return error details in an array
746 $args = $details[
'error'];
747 $error = array_shift( $args );
749 $error = $details[
'error'];
756 throw new UnexpectedValueException( __METHOD__ .
": Unknown value `{$details['status']}`" );
769 $success = $this->mUpload->unsaveUploadedFile();
772 $this->
msg(
'filedeleteerror' )
773 ->params( $this->mUpload->getTempPath() )
797 $file = $exists[
'file'];
798 $filename =
$file->getTitle()->getPrefixedText();
801 if ( $exists[
'warning'] ==
'exists' ) {
803 $warnMsg =
wfMessage(
'fileexists', $filename );
804 } elseif ( $exists[
'warning'] ==
'page-exists' ) {
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' ) {
812 $warnMsg =
wfMessage(
'fileexists-thumbnail-yes',
813 $exists[
'thumbFile']->
getTitle()->getPrefixedText(), $filename );
814 } elseif ( $exists[
'warning'] ==
'thumb-name' ) {
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'] );
823 return $warnMsg ? $warnMsg->page(
$file->getTitle() )->parse() :
'';
837 $gallery->setShowBytes(
false );
838 $gallery->setShowDimensions(
false );
839 foreach ( $dupes as
$file ) {
840 $gallery->add(
$file->getTitle() );
844 $this->
msg(
'file-exists-duplicate' )->numParams( count( $dupes ) )->parse() .
845 $gallery->toHTML() .
"</li>\n";
862 return $bitmapHandler->autoRotateEnabled();
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 error page which can definitely be safely rendered using the OutputPage.
static runner()
Get a HookRunner instance for calling hooks using the new interfaces.
static errorBox( $html, $heading='', $className='')
Return an error box.
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.
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,...
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.
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.
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.
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
static createFromRequest(&$request, $type=null)
Create a form of UploadBase depending on wpSourceType and initializes it.
static isEnabled()
Returns true if uploads are enabled.
static isAllowed(Authority $performer)
Returns true if the user can use this upload module or else a string identifying the missing permissi...
const WINDOWS_NONASCII_FILENAME
static isThrottled( $user)
Returns true if the user has surpassed the upload rate limit, false otherwise.
const MIN_LENGTH_PARTNAME
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,...
Interface for configuration instances.
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.