39 parent::__construct(
'Upload',
'upload' );
95 $this->mRequest = $request = $this->
getRequest();
96 $this->mSourceType = $request->getVal(
'wpSourceType',
'file' );
97 $this->mUpload = UploadBase::createFromRequest( $request );
98 $this->mUploadClicked = $request->wasPosted()
99 && ( $request->getCheck(
'wpUpload' )
100 || $request->getCheck(
'wpUploadIgnoreWarning' ) );
103 $this->mDesiredDestName = $request->getText(
'wpDestFile' );
104 if ( !$this->mDesiredDestName && $request->getFileName(
'wpUploadFile' ) !== null ) {
105 $this->mDesiredDestName = $request->getFileName(
'wpUploadFile' );
107 $this->mLicense = $request->getText(
'wpLicense' );
109 $this->mDestWarningAck = $request->getText(
'wpDestFileWarningAck' );
110 $this->mIgnoreWarning = $request->getCheck(
'wpIgnoreWarning' )
111 || $request->getCheck(
'wpUploadIgnoreWarning' );
112 $this->mWatchthis = $request->getBool(
'wpWatchthis' ) && $this->
getUser()->isLoggedIn();
113 $this->mCopyrightStatus = $request->getText(
'wpUploadCopyStatus' );
114 $this->mCopyrightSource = $request->getText(
'wpUploadSource' );
116 $this->mForReUpload = $request->getBool(
'wpForReUpload' );
118 $commentDefault =
'';
119 $commentMsg = $this->
msg(
'upload-default-description' )->inContentLanguage();
120 if ( !$this->mForReUpload && !$commentMsg->isDisabled() ) {
121 $commentDefault = $commentMsg->plain();
123 $this->mComment = $request->getText(
'wpUploadDescription', $commentDefault );
125 $this->mCancelUpload = $request->getCheck(
'wpCancelUpload' )
126 || $request->getCheck(
'wpReUpload' );
129 $token = $request->getVal(
'wpEditToken' );
130 $this->mTokenOk = $this->
getUser()->matchEditToken( $token );
132 $this->uploadFormTextTop =
'';
133 $this->uploadFormTextAfterSummary =
'';
145 return UploadBase::isEnabled() && parent::userCanExecute( $user );
164 # Check uploading enabled
165 if ( !UploadBase::isEnabled() ) {
166 throw new ErrorPageError(
'uploaddisabled',
'uploaddisabledtext' );
173 $permissionRequired = UploadBase::isAllowed( $user );
174 if ( $permissionRequired !==
true ) {
179 if ( $user->isBlockedFromUpload() ) {
184 if ( $user->isBlockedGlobally() ) {
188 # Check whether we actually want to allow changing stuff
193 # Unsave the temporary file in case this was a cancelled upload
195 # Something went wrong, so unsaveUploadedFile showed a warning
199 # Process upload or show a form
201 $this->mTokenOk && !$this->mCancelUpload &&
202 ( $this->mUpload && $this->mUploadClicked )
206 # Backwards compatibility hook
209 if ( !
Hooks::run(
'UploadForm:initial', [ &$upload ] ) ) {
210 wfDebug(
"Hook 'UploadForm:initial' broke output of the upload form\n" );
218 if ( $this->mUpload ) {
219 $this->mUpload->cleanupTempFile();
229 # Add links if file was previously deleted
230 if ( $this->mDesiredDestName ) {
249 protected function getUploadForm( $message =
'', $sessionKey =
'', $hideIgnoreWarning =
false ) {
255 'forreupload' => $this->mForReUpload,
256 'sessionkey' => $sessionKey,
257 'hideignorewarning' => $hideIgnoreWarning,
258 'destwarningack' => (
bool)$this->mDestWarningAck,
260 'description' => $this->mComment,
261 'texttop' => $this->uploadFormTextTop,
262 'textaftersummary' => $this->uploadFormTextAfterSummary,
263 'destfile' => $this->mDesiredDestName,
266 # Check the token, but only if necessary
268 !$this->mTokenOk && !$this->mCancelUpload &&
269 ( $this->mUpload && $this->mUploadClicked )
271 $form->addPreText( $this->
msg(
'session_fail_preview' )->parse() );
274 # Give a notice if the user is uploading a file that has been deleted or moved
275 # Note that this is independent from the message 'filewasdeleted'
278 if ( $desiredTitleObj instanceof
Title && !$desiredTitleObj->
exists() ) {
284 'conds' => [
'log_action != ' .
$dbr->addQuotes(
'revision' ) ],
285 'showIfEmpty' =>
false,
286 'msgKey' => [
'upload-recreate-warning' ] ]
289 $form->addPreText( $delNotice );
292 $form->addPreText(
'<div id="uploadtext">' .
293 $this->
msg(
'uploadtext', [ $this->mDesiredDestName ] )->parseAsBlock() .
295 # Add upload error message
296 $form->addPreText( $message );
299 $uploadFooter = $this->
msg(
'uploadfooter' );
300 if ( !$uploadFooter->isDisabled() ) {
301 $form->addPostText(
'<div id="mw-upload-footer-message">'
302 . $uploadFooter->parseAsBlock() .
"</div>\n" );
314 $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
317 $count =
$title->isDeleted();
318 if ( $count > 0 && $permissionManager->userHasRight( $user,
'deletedhistory' ) ) {
321 $this->
msg(
'restorelink' )->numParams( $count )->text()
324 $permissionManager->userHasRight( $user,
'delete' ) ?
'thisisdeleted' :
'viewdeleted'
325 )->rawParams( $restorelink )->parseAsBlock();
329 [
'id' =>
'contentSub2' ],
349 $stashStatus = $this->mUpload->tryStashFile( $this->
getUser() );
350 if ( $stashStatus->isGood() ) {
351 $sessionKey = $stashStatus->getValue()->getFileKey();
352 $uploadWarning =
'upload-tryagain';
355 $uploadWarning =
'upload-tryagain-nostash';
357 $message =
'<h2>' . $this->
msg(
'uploaderror' )->escaped() .
"</h2>\n" .
358 '<div class="error">' . $message .
"</div>\n";
361 $form->setSubmitText( $this->
msg( $uploadWarning )->escaped() );
374 # If there are no warnings, or warnings we can ignore, return early.
375 # mDestWarningAck is set when some javascript has shown the warning
376 # to the user. mForReUpload is set when the user clicks the "upload a
378 if ( !$warnings || ( count( $warnings ) == 1
379 && isset( $warnings[
'exists'] )
380 && ( $this->mDestWarningAck || $this->mForReUpload ) )
385 $stashStatus = $this->mUpload->tryStashFile( $this->
getUser() );
386 if ( $stashStatus->isGood() ) {
387 $sessionKey = $stashStatus->getValue()->getFileKey();
388 $uploadWarning =
'uploadwarning-text';
391 $uploadWarning =
'uploadwarning-text-nostash';
395 $this->
getOutput()->addModuleStyles(
'mediawiki.special' );
398 $warningHtml =
'<h2>' . $this->
msg(
'uploadwarning' )->escaped() .
"</h2>\n"
399 .
'<div class="mw-destfile-warning"><ul>';
400 foreach ( $warnings as $warning =>
$args ) {
401 if ( $warning ==
'badfilename' ) {
404 if ( $warning ==
'exists' ) {
406 } elseif ( $warning ==
'no-change' ) {
408 $filename =
$file->getTitle()->getPrefixedText();
409 $msg =
"\t<li>" . $this->
msg(
'fileexists-no-change', $filename )->parse() .
"</li>\n";
410 } elseif ( $warning ==
'duplicate-version' ) {
412 $count = count(
$args );
413 $filename =
$file->getTitle()->getPrefixedText();
414 $message = $this->
msg(
'fileexists-duplicate-version' )
415 ->params( $filename )
416 ->numParams( $count );
417 $msg =
"\t<li>" . $message->parse() .
"</li>\n";
418 } elseif ( $warning ==
'was-deleted' ) {
419 # If the file existed before and was deleted, warn the user of this
423 $this->
msg(
'deletionlog' )->text(),
430 $msg =
"\t<li>" . $this->
msg(
'filewasdeleted' )->rawParams( $llink )->parse() .
"</li>\n";
431 } elseif ( $warning ==
'duplicate' ) {
433 } elseif ( $warning ==
'duplicate-archive' ) {
434 if (
$args ===
'' ) {
435 $msg =
"\t<li>" . $this->
msg(
'file-deleted-duplicate-notitle' )->parse()
438 $msg =
"\t<li>" . $this->
msg(
'file-deleted-duplicate',
443 if (
$args ===
true ) {
445 } elseif ( !is_array(
$args ) ) {
448 $msg =
"\t<li>" . $this->
msg( $warning,
$args )->parse() .
"</li>\n";
450 $warningHtml .= $msg;
452 $warningHtml .=
"</ul></div>\n";
453 $warningHtml .= $this->
msg( $uploadWarning )->parseAsBlock();
455 $form = $this->
getUploadForm( $warningHtml, $sessionKey,
true );
456 $form->setSubmitText( $this->
msg(
'upload-tryagain' )->text() );
458 'name' =>
'wpUploadIgnoreWarning',
459 'value' => $this->
msg(
'ignorewarning' )->text()
462 'name' =>
'wpCancelUpload',
463 'value' => $this->
msg(
'reuploaddesc' )->text()
468 # Indicate that we showed a form
478 $message =
'<h2>' . $this->
msg(
'uploadwarning' )->escaped() .
"</h2>\n" .
479 '<div class="error">' . $message .
"</div>\n";
489 $status = $this->mUpload->fetchFile();
492 $status->getWikiText(
false,
false, $this->getLanguage() )
499 if ( !
Hooks::run(
'UploadForm:BeforeProcessing', [ &$upload ] ) ) {
500 wfDebug(
"Hook 'UploadForm:BeforeProcessing' broke processing the file.\n" );
510 $details = $this->mUpload->verifyUpload();
511 if ( $details[
'status'] != UploadBase::OK ) {
518 $permErrors = $this->mUpload->verifyTitlePermissions( $this->
getUser() );
519 if ( $permErrors !==
true ) {
520 $code = array_shift( $permErrors[0] );
526 $this->mLocalFile = $this->mUpload->getLocalFile();
529 if ( !$this->mIgnoreWarning ) {
530 $warnings = $this->mUpload->checkWarnings();
537 if ( UploadBase::isThrottled( $this->
getUser() ) ) {
539 $this->
msg(
'actionthrottledtext' )->escaped()
545 if ( !$this->mForReUpload ) {
547 $this->mCopyrightStatus, $this->mCopyrightSource, $this->
getConfig() );
552 $changeTags = $this->
getRequest()->getVal(
'wpChangeTags' );
553 if ( is_null( $changeTags ) || $changeTags ===
'' ) {
556 $changeTags = array_filter( array_map(
'trim', explode(
',', $changeTags ) ) );
561 $changeTags, $this->
getUser() );
562 if ( !$changeTagsStatus->isOK() ) {
564 $changeTagsStatus->getWikiText(
false,
false, $this->getLanguage() )
571 $status = $this->mUpload->performUpload(
582 $status->getWikiText(
false,
false, $this->getLanguage() )
590 $this->mUploadSuccessful =
true;
593 Hooks::run(
'SpecialUploadComplete', [ &$upload ] );
594 $this->
getOutput()->redirect( $this->mLocalFile->getTitle()->getFullURL() );
609 if ( $config ===
null ) {
610 wfDebug( __METHOD__ .
' called without a Config instance passed to it' );
611 $config = MediaWikiServices::getInstance()->getMainConfig();
615 $forceUIMsgAsContentMsg = (array)$config->get(
'ForceUIMsgAsContentMsg' );
620 foreach ( [
'license-header',
'filedesc',
'filestatus',
'filesource' ] as $msgName ) {
621 if ( in_array( $msgName, $forceUIMsgAsContentMsg ) ) {
622 $msg[$msgName] =
"{{int:$msgName}}";
624 $msg[$msgName] =
wfMessage( $msgName )->inContentLanguage()->text();
629 if ( $license !==
'' ) {
630 $licenseText =
'== ' . $msg[
'license-header'] .
" ==\n{{" . $license .
"}}\n";
633 $pageText = $comment .
"\n";
634 $headerText =
'== ' . $msg[
'filedesc'] .
' ==';
635 if ( $comment !==
'' && strpos( $comment, $headerText ) ===
false ) {
637 $pageText = $headerText .
"\n" . $pageText;
640 if ( $config->get(
'UseCopyrightUpload' ) ) {
641 $pageText .=
'== ' . $msg[
'filestatus'] .
" ==\n" . $copyStatus .
"\n";
642 $pageText .= $licenseText;
643 $pageText .=
'== ' . $msg[
'filesource'] .
" ==\n" .
$source;
645 $pageText .= $licenseText;
649 Hooks::run(
'UploadForm:getInitialPageText', [ &$pageText, $msg, $config ] );
667 if ( $this->
getUser()->getOption(
'watchdefault' ) ) {
673 if ( $desiredTitleObj instanceof
Title && $this->
getUser()->isWatched( $desiredTitleObj ) ) {
678 $local = MediaWikiServices::getInstance()->getRepoGroup()->getLocalRepo()
679 ->newFile( $this->mDesiredDestName );
680 if ( $local && $local->exists() ) {
686 return $this->
getUser()->getOption(
'watchcreations' ) ||
687 $this->
getUser()->getOption(
'watchuploads' );
698 switch ( $details[
'status'] ) {
700 case UploadBase::MIN_LENGTH_PARTNAME:
703 case UploadBase::ILLEGAL_FILENAME:
705 $details[
'filtered'] )->parse() );
707 case UploadBase::FILENAME_TOO_LONG:
710 case UploadBase::FILETYPE_MISSING:
713 case UploadBase::WINDOWS_NONASCII_FILENAME:
718 case UploadBase::EMPTY_FILE:
721 case UploadBase::FILE_TOO_LARGE:
724 case UploadBase::FILETYPE_BADTYPE:
725 $msg = $this->
msg(
'filetype-banned-type' );
726 if ( isset( $details[
'blacklistedExt'] ) ) {
727 $msg->params( $this->
getLanguage()->commaList( $details[
'blacklistedExt'] ) );
729 $msg->params( $details[
'finalExt'] );
731 $extensions = array_unique( $this->
getConfig()->
get(
'FileExtensions' ) );
732 $msg->params( $this->
getLanguage()->commaList( $extensions ),
733 count( $extensions ) );
738 if ( isset( $details[
'blacklistedExt'] ) ) {
739 $msg->params( count( $details[
'blacklistedExt'] ) );
746 case UploadBase::VERIFICATION_ERROR:
747 unset( $details[
'status'] );
748 $code = array_shift( $details[
'details'] );
751 case UploadBase::HOOK_ABORTED:
752 if ( is_array( $details[
'error'] ) ) { # allow hooks to
return error details in an array
753 $args = $details[
'error'];
754 $error = array_shift(
$args );
756 $error = $details[
'error'];
763 throw new MWException( __METHOD__ .
": Unknown value `{$details['status']}`" );
776 $success = $this->mUpload->unsaveUploadedFile();
779 $this->
msg(
'filedeleteerror' )
780 ->params( $this->mUpload->getTempPath() )
804 $file = $exists[
'file'];
805 $filename =
$file->getTitle()->getPrefixedText();
808 if ( $exists[
'warning'] ==
'exists' ) {
810 $warnMsg =
wfMessage(
'fileexists', $filename );
811 } elseif ( $exists[
'warning'] ==
'page-exists' ) {
813 $warnMsg =
wfMessage(
'filepageexists', $filename );
814 } elseif ( $exists[
'warning'] ==
'exists-normalized' ) {
815 $warnMsg =
wfMessage(
'fileexists-extension', $filename,
816 $exists[
'normalizedFile']->
getTitle()->getPrefixedText() );
817 } elseif ( $exists[
'warning'] ==
'thumb' ) {
819 $warnMsg =
wfMessage(
'fileexists-thumbnail-yes',
820 $exists[
'thumbFile']->
getTitle()->getPrefixedText(), $filename );
821 } elseif ( $exists[
'warning'] ==
'thumb-name' ) {
823 $name =
$file->getName();
824 $badPart = substr( $name, 0, strpos( $name,
'-' ) + 1 );
825 $warnMsg =
wfMessage(
'file-thumbnail-no', $badPart );
826 } elseif ( $exists[
'warning'] ==
'bad-prefix' ) {
827 $warnMsg =
wfMessage(
'filename-bad-prefix', $exists[
'prefix'] );
830 return $warnMsg ? $warnMsg->title(
$file->getTitle() )->parse() :
'';
844 $gallery->setShowBytes(
false );
845 $gallery->setShowDimensions(
false );
846 foreach ( $dupes as
$file ) {
847 $gallery->add(
$file->getTitle() );
851 $this->
msg(
'file-exists-duplicate' )->numParams( count( $dupes ) )->parse() .
852 $gallery->toHTML() .
"</li>\n";
869 return $bitmapHandler->autoRotateEnabled();