Extension:UploadCheck/Code

From Linux Web Expert

The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

UploadCheck.php

<?PHP
/*
 * ***** BEGIN LICENSE BLOCK *****
 * This file is part of UploadCheck.
 * Copyright © 20013 Martin Strecker. All rights reserved.
 *
 * UploadCheck is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * UploadCheck is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details. (http://www.gnu.org/licenses/)
 *
 * ***** END LICENSE BLOCK *****
 *
 * UploadCheck is a tool for MediaWiki.
 */

if ( !defined( 'MEDIAWIKI' ) ) {
        die( 'This is not a valid entry point to MediaWiki.' );
}

$wgExtensionCredits['specialpage'] [] = array (
'path' => __FILE__,
'name' => 'UploadCheck',
'author' => 'Martin Strecker',
'descriptionmsg' => 'uploadcheck_desc',
'version' => 1.0,
'url' => 'https://www.mediawiki.org/wiki/Extension:UploadCheck',
);

$dir = dirname(__FILE__) . '/';

$wgAutoloadClasses['SpecialUploadCheck'] = $dir . 'SpecialUploadCheck.php';
$wgExtensionMessagesFiles['UploadCheck'] = $dir . 'UploadCheck.i18n.php';
$wgSpecialPages['UploadCheck'] = 'SpecialUploadCheck';

UploadCheck.i18n.php

<?PHP
/*
 * ***** BEGIN LICENSE BLOCK *****
 * This file is part of UploadCheck.
 * Copyright © 2013 Martin Strecker. All rights reserved.
 *
 * UploadCheck is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * UploadCheck is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details. (http://www.gnu.org/licenses/)
 *
 * ***** END LICENSE BLOCK *****
 *
 * UploadCheck is a tool for MediaWiki.
 */

$message = array();

/* English
 * @author Martin Strecker
 */
$messages['en'] = array('uploadcheck' => 'Upload file',
                        'uploadcheck_desc' => 'Checks if the fields "Description" and "License" are filled when uploading a file',
                        'uploadcheck_comment' => 'Please write a Comment.',
                        'uploadcheck_license' => 'Please choose a License.'
);

/* German
* @author Martin Strecker
*/
$messages['de'] = array('uploadcheck' => 'Datei hochladen',
                        'uploadcheck_desc' => 'Prüft, ob die Felder "Beschreibung" und "Lizenz" beim Hochladen einer Datei ausgefüllt wurden',
                        'uploadcheck_comment' => 'Bitte geben Sie eine Beschreibung ein.',
                        'uploadcheck_license' => 'Bitte geben Sie eine Lizenz ein.'
);

SpecialUploadCheck.php

<?php
/*
 * ***** BEGIN LICENSE BLOCK *****
 * This file is part of UploadCheck.
 * Copyright © 2013 Martin Strecker. All rights reserved.
 *
 * UploadCheck is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * UploadCheck is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details. (http://www.gnu.org/licenses/)
 *
 * ***** END LICENSE BLOCK *****
 *
 * UploadCheck is a tool for MediaWiki.
 */

class SpecialUploadCheck extends SpecialPage {
        function __construct() {
                parent::__construct('UploadCheck');
        }

	/** Misc variables **/
	public $mRequest;			// The WebRequest or FauxRequest this form is supposed to handle
	public $mSourceType;

	/**
	 * @var UploadBase
	 */
	public $mUpload;

	/**
	 * @var LocalFile
	 */
	public $mLocalFile;
	public $mUploadClicked;

	/** User input variables from the "description" section **/
	public $mDesiredDestName;	// The requested target file name
	public $mComment;
	public $mLicense;

	/** User input variables from the root section **/
	public $mIgnoreWarning;
	public $mWatchThis;
	public $mCopyrightStatus;
	public $mCopyrightSource;

	/** Hidden variables **/
	public $mDestWarningAck;
	public $mForReUpload;		// The user followed an "overwrite this file" link
	public $mCancelUpload;		// The user clicked "Cancel and return to upload form" button
	public $mTokenOk;
	public $mUploadSuccessful = false;	// Subclasses can use this to determine whether a file was uploaded

	/** Text injection points for hooks not using HTMLForm **/
	public $uploadFormTextTop;
	public $uploadFormTextAfterSummary;

	public $mWatchthis;

	/**
	 * Initialize instance variables from request and create an Upload handler
	 */

	protected function loadRequest() {
		$this->mRequest = $request = $this->getRequest();
		$this->mSourceType        = $request->getVal( 'wpSourceType', 'file' );
		$this->mUpload            = UploadBase::createFromRequest( $request );
		$this->mUploadClicked     = $request->wasPosted()
			&& ( $request->getCheck( 'wpUpload' )
				|| $request->getCheck( 'wpUploadIgnoreWarning' ) );

		// Guess the desired name from the filename if not provided
		$this->mDesiredDestName   = $request->getText( 'wpDestFile' );
		if( !$this->mDesiredDestName && $request->getFileName( 'wpUploadFile' ) !== null ) {
			$this->mDesiredDestName = $request->getFileName( 'wpUploadFile' );
		}
		$this->mComment           = $request->getText( 'wpUploadDescription' );
		$this->mLicense           = $request->getText( 'wpLicense' );


		$this->mDestWarningAck    = $request->getText( 'wpDestFileWarningAck' );
		$this->mIgnoreWarning     = $request->getCheck( 'wpIgnoreWarning' )
			|| $request->getCheck( 'wpUploadIgnoreWarning' );
		$this->mWatchthis         = $request->getBool( 'wpWatchthis' ) && $this->getUser()->isLoggedIn();
		$this->mCopyrightStatus   = $request->getText( 'wpUploadCopyStatus' );
		$this->mCopyrightSource   = $request->getText( 'wpUploadSource' );


		$this->mForReUpload       = $request->getBool( 'wpForReUpload' ); // updating a file
		$this->mCancelUpload      = $request->getCheck( 'wpCancelUpload' )
								 || $request->getCheck( 'wpReUpload' ); // b/w compat

		// If it was posted check for the token (no remote POST'ing with user credentials)
		$token = $request->getVal( 'wpEditToken' );
		$this->mTokenOk = $this->getUser()->matchEditToken( $token );

		$this->uploadFormTextTop = '';
		$this->uploadFormTextAfterSummary = '';
	}

	/**
	 * This page can be shown if uploading is enabled.
	 * Handle permission checking elsewhere in order to be able to show
	 * custom error messages.
	 *
	 * @param $user User object
	 * @return Boolean
	 */
	public function userCanExecute( User $user ) {
		return UploadBase::isEnabled() && parent::userCanExecute( $user );
	}

	/**
	 * Special page entry point
	 */
	public function execute( $par ) {
		$this->setHeaders();
		$this->outputHeader();

		# Check uploading enabled
		if( !UploadBase::isEnabled() ) {
			throw new ErrorPageError( 'uploaddisabled', 'uploaddisabledtext' );
		}

		# Check permissions
		$user = $this->getUser();
		$permissionRequired = UploadBase::isAllowed( $user );
		if( $permissionRequired !== true ) {
			throw new PermissionsError( $permissionRequired );
		}

		# Check blocks
		if( $user->isBlocked() ) {
			throw new UserBlockedError( $user->mBlock );
		}

		# Check whether we actually want to allow changing stuff
		$this->checkReadOnly();

		$this->loadRequest();

		# Unsave the temporary file in case this was a cancelled upload
		if ( $this->mCancelUpload ) {
			if ( !$this->unsaveUploadedFile() ) {
				# Something went wrong, so unsaveUploadedFile showed a warning
				return;
			}
		}

		# Process upload or show a form
		if (
			$this->mTokenOk && !$this->mCancelUpload &&
			( $this->mUpload && $this->mUploadClicked )
		) {
			$this->processUpload();
		} else {
			# Backwards compatibility hook
			if( !wfRunHooks( 'UploadForm:initial', array( &$this ) ) ) {
				wfDebug( "Hook 'UploadForm:initial' broke output of the upload form" );
				return;
			}
			$this->showUploadForm( $this->getUploadForm() );
		}

		# Cleanup
		if ( $this->mUpload ) {
			$this->mUpload->cleanupTempFile();
		}
	}

	/**
	 * Show the main upload form
	 *
	 * @param $form Mixed: an HTMLForm instance or HTML string to show
	 */
	protected function showUploadForm( $form ) {
		# Add links if file was previously deleted
		if ( $this->mDesiredDestName ) {
			$this->showViewDeletedLinks();
		}

		if ( $form instanceof HTMLForm ) {
			$form->show();
		} else {
			$this->getOutput()->addHTML( $form );
		}

	}

	/**
	 * Get an UploadForm instance with title and text properly set.
	 *
	 * @param $message String: HTML string to add to the form
	 * @param $sessionKey String: session key in case this is a stashed upload
	 * @param $hideIgnoreWarning Boolean: whether to hide "ignore warning" check box
	 * @return UploadForm
	 */

	protected function getUploadForm( $message = '', $sessionKey = '', $hideIgnoreWarning = true ) {
		//Gets the variable $hideWarning from LocalSettings.php to check if the user can ignore the warnings.
		global $hideWarning;
		$hideIgnoreWarning = $hideWarning;
		# Initialize form
		$form = new UploadForm( array(
			'watch' => $this->getWatchCheck(),
			'forreupload' => $this->mForReUpload,
			'sessionkey' => $sessionKey,
			'hideignorewarning' => $hideIgnoreWarning,
			'destwarningack' => (bool)$this->mDestWarningAck,

			'description' => $this->mComment,
			'texttop' => $this->uploadFormTextTop,
			'textaftersummary' => $this->uploadFormTextAfterSummary,
			'destfile' => $this->mDesiredDestName,
		), $this->getContext() );
		$form->setTitle( $this->getTitle() );

		# Check the token, but only if necessary
		if(
			!$this->mTokenOk && !$this->mCancelUpload &&
			( $this->mUpload && $this->mUploadClicked )
		) {
			$form->addPreText( wfMsgExt( 'session_fail_preview', 'parseinline' ) );
		}

		# Give a notice if the user is uploading a file that has been deleted or moved
		# Note that this is independent from the message 'filewasdeleted' that requires JS
		$desiredTitleObj = Title::makeTitleSafe( NS_FILE, $this->mDesiredDestName );
		$delNotice = ''; // empty by default
		if ( $desiredTitleObj instanceof Title && !$desiredTitleObj->exists() ) {
			LogEventsList::showLogExtract( $delNotice, array( 'delete', 'move' ),
				$desiredTitleObj,
				'', array( 'lim' => 10,
					   'conds' => array( "log_action != 'revision'" ),
					   'showIfEmpty' => false,
					   'msgKey' => array( 'upload-recreate-warning' ) )
			);
		}
		$form->addPreText( $delNotice );

		# Add text to form
		$form->addPreText( '<div id="uploadtext">' .
			wfMsgExt( 'uploadtext', 'parse', array( $this->mDesiredDestName ) ) .
			'</div>' );
		# Add upload error message
		$form->addPreText( $message );

		# Add footer to form
		$uploadFooter = wfMessage( 'uploadfooter' );
		if ( !$uploadFooter->isDisabled() ) {
			$form->addPostText( '<div id="mw-upload-footer-message">'
				. $this->getOutput()->parse( $uploadFooter->plain() ) . "</div>\n" );
		}

		return $form;
	}

	/**
	 * Shows the "view X deleted revivions link""
	 */
	protected function showViewDeletedLinks() {
		$title = Title::makeTitleSafe( NS_FILE, $this->mDesiredDestName );
		$user = $this->getUser();
		// Show a subtitle link to deleted revisions (to sysops et al only)
		if( $title instanceof Title ) {
			$count = $title->isDeleted();
			if ( $count > 0 && $user->isAllowed( 'deletedhistory' ) ) {
				$link = wfMsgExt(
					$user->isAllowed( 'delete' ) ? 'thisisdeleted' : 'viewdeleted',
					array( 'parse', 'replaceafter' ),
					Linker::linkKnown(
						SpecialPage::getTitleFor( 'Undelete', $title->getPrefixedText() ),
						wfMsgExt( 'restorelink', array( 'parsemag', 'escape' ), $count )
					)
				);
				$this->getOutput()->addHTML( "<div id=\"contentSub2\">{$link}</div>" );
			}
		}
	}

	/**
	 * Stashes the upload and shows the main upload form.
	 *
	 * Note: only errors that can be handled by changing the name or
	 * description should be redirected here. It should be assumed that the
	 * file itself is sane and has passed UploadBase::verifyFile. This
	 * essentially means that UploadBase::VERIFICATION_ERROR and
	 * UploadBase::EMPTY_FILE should not be passed here.
	 *
	 * @param $message String: HTML message to be passed to mainUploadForm
	 */
	protected function showRecoverableUploadError( $message ) {
		$sessionKey = $this->mUpload->stashSession();
		$message = '<h2>' . wfMsgHtml( 'uploaderror' ) . "</h2>\n" .
			'<div class="error">' . $message . "</div>\n";

		$form = $this->getUploadForm( $message, $sessionKey );
		$form->setSubmitText( wfMsg( 'upload-tryagain' ) );
		$this->showUploadForm( $form );
	}
	/**
	 * Stashes the upload, shows the main form, but adds an "continue anyway button".
	 * Also checks whether there are actually warnings to display.
	 *
	 * @param $warnings Array
	 * @return boolean true if warnings were displayed, false if there are no
	 * 	warnings and the should continue processing like there was no warning
	 */
	protected function showUploadWarning( $warnings ) {
		# If there are no warnings, or warnings we can ignore, return early.
		# mDestWarningAck is set when some javascript has shown the warning
		# to the user. mForReUpload is set when the user clicks the "upload a
		# new version" link.
		if ( !$warnings || ( count( $warnings ) == 1 &&
			isset( $warnings['exists'] ) &&
			( $this->mDestWarningAck || $this->mForReUpload ) ) )
		{
			return false;
		}

		$sessionKey = $this->mUpload->stashSession();

		$warningHtml = '<h2>' . wfMsgHtml( 'uploadwarning' ) . "</h2>\n"
			. '<ul class="warning">';
		foreach( $warnings as $warning => $args ) {
			if( $warning == 'exists' ) {
				$msg = "\t<li>" . self::getExistsWarning( $args ) . "</li>\n";
			} elseif( $warning == 'duplicate' ) {
				$msg = self::getDupeWarning( $args );
			} elseif( $warning == 'duplicate-archive' ) {
				$msg = "\t<li>" . wfMsgExt( 'file-deleted-duplicate', 'parseinline',
						array( Title::makeTitle( NS_FILE, $args )->getPrefixedText() ) )
					. "</li>\n";


//Edit
//These are the actions for the new warnings.

			} elseif($warning == 'LiCo') {
				$msg = "<li>" . wfMessage('uploadcheck_license') . "</li>";
				$msg .= "<li>" . wfMessage('uploadcheck_comment') . "</li>";
			} elseif($warning == 'License'){
				$msg = "<li>" . wfMessage('uploadcheck_license') . "</li>";
			} elseif($warning == 'Comment'){
				$msg = "<li>" . wfMessage('uploadcheck_comment') . "</li>";
			
//End Edit


			} else {
				if ( $args === true ) {
					$args = array();
				} elseif ( !is_array( $args ) ) {
					$args = array( $args );
				}
				$msg = "\t<li>" . wfMsgExt( $warning, 'parseinline', $args ) . "</li>\n";
			}

			$warningHtml .= $msg;
		}


		$warningHtml .= "</ul>\n";
		$warningHtml .= wfMsgExt( 'uploadwarning-text', 'parse' );

		$form = $this->getUploadForm( $warningHtml, $sessionKey, /* $hideIgnoreWarning */ true );
		$form->setSubmitText( wfMsg( 'upload-tryagain' ) );
		//Check if the user can ignore the warnings.
		global $hideWarning;
		if($hideWarning == false){
			$form->addButton( 'wpUploadIgnoreWarning', wfMsg( 'ignorewarning' ) );
		}
		$form->addButton( 'wpCancelUpload', wfMsg( 'reuploaddesc' ) );


		$this->showUploadForm( $form );

		# Indicate that we showed a form
		return true;
	}

	/**
	 * Show the upload form with error message, but do not stash the file.
	 *
	 * @param $message string HTML string
	 */
	protected function showUploadError( $message ) {
		$message = '<h2>' . wfMsgHtml( 'uploadwarning' ) . "</h2>\n" .
			'<div class="error">' . $message . "
                         </div>\n";
		$this->showUploadForm( $this->getUploadForm( $message ) );
	}

	/**
	 * Do the upload.
	 * Checks are made in SpecialUpload::execute()
	 */
	protected function processUpload() {
		// Fetch the file if required
		$status = $this->mUpload->fetchFile();
		if( !$status->isOK() ) {
			$this->showUploadError( $this->getOutput()->parse( $status->getWikiText() ) );
			return;
		}

		if( !wfRunHooks( 'UploadForm:BeforeProcessing', array( &$this ) ) ) {
			wfDebug( "Hook 'UploadForm:BeforeProcessing' broke processing the file.\n" );
			// This code path is deprecated. If you want to break upload processing
			// do so by hooking into the appropriate hooks in UploadBase::verifyUpload
			// and UploadBase::verifyFile.
			// If you use this hook to break uploading, the user will be returned
			// an empty form with no error message whatsoever.
			return;
		}

		// Upload verification
		$details = $this->mUpload->verifyUpload();
		if ( $details['status'] != UploadBase::OK ) {
			$this->processVerificationError( $details );
			return;
		}

		// Verify permissions for this title
		$permErrors = $this->mUpload->verifyTitlePermissions( $this->getUser() );
		if( $permErrors !== true ) {
			$code = array_shift( $permErrors[0] );
			$this->showRecoverableUploadError( wfMsgExt( $code,
					'parseinline', $permErrors[0] ) );
			return;
		}

		$this->mLocalFile = $this->mUpload->getLocalFile();
		

		// Check warnings if necessary
		if( !$this->mIgnoreWarning ) {
			$warnings = $this->mUpload->checkWarnings();
//Edit
/*
Here is the creation of the new warnings. If you want to add a new warning you just need the name of the field you want to check.
For example "$this->mLicense".
Don't forget to add an action for your warning further above.
*/

			if($this->mComment == '' && $this->mLicense == ''){
				$warnings['LiCo'] = true;
			}
			elseif($this->mComment == ''){
				$warnings['Comment'] = true;
			}
			elseif($this->mLicense == ''){
				$warnings['License'] = true;
			}

//End Edit
			if( $this->showUploadWarning( $warnings ) ) {
				return;
			}
		}

		// Get the page text if this is not a reupload
		if( !$this->mForReUpload ) {
			$pageText = self::getInitialPageText( $this->mComment, $this->mLicense,
				$this->mCopyrightStatus, $this->mCopyrightSource );
		} else {
			$pageText = false;
		}
		$status = $this->mUpload->performUpload( $this->mComment, $pageText, $this->mWatchthis, $this->getUser() );
		if ( !$status->isGood() ) {
			$this->showUploadError( $this->getOutput()->parse( $status->getWikiText() ) );
			return;
		}

		// Success, redirect to description page
		$this->mUploadSuccessful = true;
		wfRunHooks( 'SpecialUploadComplete', array( &$this ) );
		$this->getOutput()->redirect( $this->mLocalFile->getTitle()->getFullURL() );
	}

	/**
	 * Get the initial image page text based on a comment and optional file status information
	 * @param $comment string
	 * @param $license string
	 * @param $copyStatus string
	 * @param $source string
	 * @return string
	 */
	public static function getInitialPageText( $comment = '', $license = '', $copyStatus = '', $source = '' ) {
		global $wgUseCopyrightUpload, $wgForceUIMsgAsContentMsg;
		$wgForceUIMsgAsContentMsg = (array) $wgForceUIMsgAsContentMsg;

		$msg = array();
		/* These messages are transcluded into the actual text of the description page.
		 * Thus, forcing them as content messages makes the upload to produce an int: template
		 * instead of hardcoding it there in the uploader language.
		 */
		foreach( array( 'license-header', 'filedesc', 'filestatus', 'filesource' ) as $msgName ) {
			if ( in_array( $msgName, $wgForceUIMsgAsContentMsg ) ) {
				$msg[$msgName] = "{{int:$msgName}}";
			} else {
				$msg[$msgName] = wfMsgForContent( $msgName );
			}
		}

		if ( $wgUseCopyrightUpload ) {
			$licensetxt = '';
			if ( $license != '' ) {
				$licensetxt = '== ' . $msg[ 'license-header' ] . " ==\n" . '{{' . $license . '}}' . "\n";
			}
			$pageText = '== ' . $msg[ 'filedesc' ] . " ==\n" . $comment . "\n" .
				'== ' . $msg[ 'filestatus' ] . " ==\n" . $copyStatus . "\n" .
				"$licensetxt" .
				'== ' . $msg[ 'filesource' ] . " ==\n" . $source;
		} else {
			if ( $license != '' ) {
				$filedesc = $comment == '' ? '' : '== ' . $msg[ 'filedesc' ] . " ==\n" . $comment . "\n";
					$pageText = $filedesc .
					'== ' . $msg[ 'license-header' ] . " ==\n" . '{{' . $license . '}}' . "\n";
			} else {
				$pageText = $comment;
			}
		}
		return $pageText;
	}

	/**
	 * See if we should check the 'watch this page' checkbox on the form
	 * based on the user's preferences and whether we're being asked
	 * to create a new file or update an existing one.
	 *
	 * In the case where 'watch edits' is off but 'watch creations' is on,
	 * we'll leave the box unchecked.
	 *
	 * Note that the page target can be changed *on the form*, so our check
	 * state can get out of sync.
	 * @return Bool|String
	 */
	protected function getWatchCheck() {
		if( $this->getUser()->getOption( 'watchdefault' ) ) {
			// Watch all edits!
			return true;
		}

		$local = wfLocalFile( $this->mDesiredDestName );
		if( $local && $local->exists() ) {
			// We're uploading a new version of an existing file.
			// No creation, so don't watch it if we're not already.
			return $local->getTitle()->userIsWatching();
		} else {
			// New page should get watched if that's our option.
			return $this->getUser()->getOption( 'watchcreations' );
		}
	}


	/**
	 * Provides output to the user for a result of UploadBase::verifyUpload
	 *
	 * @param $details Array: result of UploadBase::verifyUpload
	 */
	protected function processVerificationError( $details ) {
		global $wgFileExtensions;

		switch( $details['status'] ) {

			/** Statuses that only require name changing **/
			case UploadBase::MIN_LENGTH_PARTNAME:
				$this->showRecoverableUploadError( wfMsgHtml( 'minlength1' ) );
				break;
			case UploadBase::ILLEGAL_FILENAME:
				$this->showRecoverableUploadError( wfMsgExt( 'illegalfilename',
					'parseinline', $details['filtered'] ) );
				break;
			case UploadBase::FILENAME_TOO_LONG:
				$this->showRecoverableUploadError( wfMsgHtml( 'filename-toolong' ) );
				break;
			case UploadBase::FILETYPE_MISSING:
				$this->showRecoverableUploadError( wfMsgExt( 'filetype-missing',
					'parseinline' ) );
				break;
			case UploadBase::WINDOWS_NONASCII_FILENAME:
				$this->showRecoverableUploadError( wfMsgExt( 'windows-nonascii-filename',
					'parseinline' ) );
				break;

			/** Statuses that require reuploading **/
			case UploadBase::EMPTY_FILE:
				$this->showUploadError( wfMsgHtml( 'emptyfile' ) );
				break;
			case UploadBase::FILE_TOO_LARGE:
				$this->showUploadError( wfMsgHtml( 'largefileserver' ) );
				break;
			case UploadBase::FILETYPE_BADTYPE:
				$msg = wfMessage( 'filetype-banned-type' );
				if ( isset( $details['blacklistedExt'] ) ) {
					$msg->params( $this->getLanguage()->commaList( $details['blacklistedExt'] ) );
				} else {
					$msg->params( $details['finalExt'] );
				}
				$msg->params( $this->getLanguage()->commaList( $wgFileExtensions ),
					count( $wgFileExtensions ) );

				// Add PLURAL support for the first parameter. This results
				// in a bit unlogical parameter sequence, but does not break
				// old translations
				if ( isset( $details['blacklistedExt'] ) ) {
					$msg->params( count( $details['blacklistedExt'] ) );
				} else {
					$msg->params( 1 );
				}

				$this->showUploadError( $msg->parse() );
				break;
			case UploadBase::VERIFICATION_ERROR:
				unset( $details['status'] );
				$code = array_shift( $details['details'] );
				$this->showUploadError( wfMsgExt( $code, 'parseinline', $details['details'] ) );
				break;
			case UploadBase::HOOK_ABORTED:
				if ( is_array( $details['error'] ) ) { # allow hooks to return error details in an array
					$args = $details['error'];
					$error = array_shift( $args );
				} else {
					$error = $details['error'];
					$args = null;
				}

				$this->showUploadError( wfMsgExt( $error, 'parseinline', $args ) );
				break;
			default:
				throw new MWException( __METHOD__ . ": Unknown value `{$details['status']}`" );
		}
	}

	/**
	 * Remove a temporarily kept file stashed by saveTempUploadedFile().
	 *
	 * @return Boolean: success
	 */
	protected function unsaveUploadedFile() {
		if ( !( $this->mUpload instanceof UploadFromStash ) ) {
			return true;
		}
		$success = $this->mUpload->unsaveUploadedFile();
		if ( !$success ) {
			$this->getOutput()->showFileDeleteError( $this->mUpload->getTempPath() );
			return false;
		} else {
			return true;
		}
	}

	/*** Functions for formatting warnings ***/

	/**
	 * Formats a result of UploadBase::getExistsWarning as HTML
	 * This check is static and can be done pre-upload via AJAX
	 *
	 * @param $exists Array: the result of UploadBase::getExistsWarning
	 * @return String: empty string if there is no warning or an HTML fragment
	 */
	public static function getExistsWarning( $exists ) {
		if ( !$exists ) {
			return '';
		}

		$file = $exists['file'];
		$filename = $file->getTitle()->getPrefixedText();
		$warning = '';

		if( $exists['warning'] == 'exists' ) {
			// Exact match
			$warning = wfMsgExt( 'fileexists', 'parseinline', $filename );
		} elseif( $exists['warning'] == 'page-exists' ) {
			// Page exists but file does not
			$warning = wfMsgExt( 'filepageexists', 'parseinline', $filename );
		} elseif ( $exists['warning'] == 'exists-normalized' ) {
			$warning = wfMsgExt( 'fileexists-extension', 'parseinline', $filename,
				$exists['normalizedFile']->getTitle()->getPrefixedText() );
		} elseif ( $exists['warning'] == 'thumb' ) {
			// Swapped argument order compared with other messages for backwards compatibility
			$warning = wfMsgExt( 'fileexists-thumbnail-yes', 'parseinline',
				$exists['thumbFile']->getTitle()->getPrefixedText(), $filename );
		} elseif ( $exists['warning'] == 'thumb-name' ) {
			// Image w/o '180px-' does not exists, but we do not like these filenames
			$name = $file->getName();
			$badPart = substr( $name, 0, strpos( $name, '-' ) + 1 );
			$warning = wfMsgExt( 'file-thumbnail-no', 'parseinline', $badPart );
		} elseif ( $exists['warning'] == 'bad-prefix' ) {
			$warning = wfMsgExt( 'filename-bad-prefix', 'parseinline', $exists['prefix'] );
		} elseif ( $exists['warning'] == 'was-deleted' ) {
			# If the file existed before and was deleted, warn the user of this
			$ltitle = SpecialPage::getTitleFor( 'Log' );
			$llink = Linker::linkKnown(
				$ltitle,
				wfMsgHtml( 'deletionlog' ),
				array(),
				array(
					'type' => 'delete',
					'page' => $filename
				)
			);
			$warning = wfMsgExt( 'filewasdeleted', array( 'parse', 'replaceafter' ), $llink );
		}
		return $warning;
	}

	/**
	 * Get a list of warnings
	 *
	 * @param $filename String: local filename, e.g. 'file exists', 'non-descriptive filename'
	 * @return Array: list of warning messages
	 */
	public static function ajaxGetExistsWarning( $filename ) {
		$file = wfFindFile( $filename );
		if( !$file ) {
			// Force local file so we have an object to do further checks against
			// if there isn't an exact match...
			$file = wfLocalFile( $filename );
		}
		$s = '&#160;';
		if ( $file ) {
			$exists = UploadBase::getExistsWarning( $file );
			$warning = self::getExistsWarning( $exists );
			if ( $warning !== '' ) {
				$s = "<div>$warning</div>";
			}
		}
		return $s;
	}

	/**
	 * Construct a warning and a gallery from an array of duplicate files.
	 * @param $dupes array
	 * @return string
	 */
	public static function getDupeWarning( $dupes ) {
		global $wgOut;
		if( $dupes ) {
			$msg = '<gallery>';
			foreach( $dupes as $file ) {
				$title = $file->getTitle();
				$msg .= $title->getPrefixedText() .
					'|' . $title->getText() . "\n";
			}
			$msg .= '</gallery>';
			return '<li>' .
				wfMsgExt( 'file-exists-duplicate', array( 'parse' ), count( $dupes ) ) .
				$wgOut->parse( $msg ) .
				"</li>\n";
		} else {
			return '';
		}
	}
}