mRequest = $request;
}
protected function initForm() {
global $wgRequest, $wgUser;
if ( is_null( $this->mRequest ) ) {
$request = $wgRequest;
} else {
$request = $this->mRequest;
}
// Guess the desired name from the filename if not provided
$this->mDesiredDestName = $request->getText( 'wpDestFile' );
if( !$this->mDesiredDestName )
$this->mDesiredDestName = $request->getText( 'wpUploadFile' );
$this->mForReUpload = $request->getBool( 'wpForReUpload' ); // updating a file
$this->mIgnoreWarning = $request->getCheck( 'wpIgnoreWarning' );
$this->mComment = $request->getText( 'wpUploadDescription' );
if( !$request->wasPosted() ) {
# GET requests just give the main form; no data except destination
# filename and description
return;
}
# Placeholders for text injection by hooks (empty per default)
$this->uploadFormTextTop = "";
$this->uploadFormTextAfterSummary = "";
$this->mUploadClicked = $request->getCheck( 'wpUpload' );
$this->mLicense = $request->getText( 'wpLicense' );
$this->mCopyrightStatus = $request->getText( 'wpUploadCopyStatus' );
$this->mCopyrightSource = $request->getText( 'wpUploadSource' );
$this->mWatchthis = $request->getBool( 'wpWatchthis' );
$this->mSourceType = $request->getVal( 'wpSourceType', 'file' );
$this->mDestWarningAck = $request->getText( 'wpDestFileWarningAck' );
$this->mReUpload = $request->getCheck( 'wpReUpload' ); // retrying upload
$this->mAction = $request->getVal( 'action' );
$this->mUpload = UploadBase::createFromRequest( $request );
// If it was posted check for the token (no remote POST'ing with user credentials)
$token = $request->getVal( 'wpEditToken' );
if( $this->mSourceType == 'file' && $token == null ) {
// Skip token check for file uploads as that can't be faked via JS...
// Some client-side tools don't expect to need to send wpEditToken
// with their submissions, as that's new in 1.16.
$this->mTokenOk = true;
} else {
$this->mTokenOk = $wgUser->matchEditToken( $token );
}
}
public function userCanExecute( $user ) {
return UploadBase::isEnabled() && parent::userCanExecute( $user );
}
/**
* Start doing stuff
* @access public
*/
function execute( $par ) {
global $wgUser, $wgOut, $wgRequest;
$this->setHeaders();
$this->outputHeader();
$this->initForm();
# Check uploading enabled
if( !UploadBase::isEnabled() ) {
$wgOut->showErrorPage( 'uploaddisabled', 'uploaddisabledtext' );
return;
}
# Check permissions
global $wgGroupPermissions;
if( !$wgUser->isAllowed( 'upload' ) ) {
if( !$wgUser->isLoggedIn() && ( $wgGroupPermissions['user']['upload']
|| $wgGroupPermissions['autoconfirmed']['upload'] ) ) {
// Custom message if logged-in users without any special rights can upload
$wgOut->showErrorPage( 'uploadnologin', 'uploadnologintext' );
} else {
$wgOut->permissionRequired( 'upload' );
}
return;
}
# Check blocks
if( $wgUser->isBlocked() ) {
$wgOut->blockedPage();
return;
}
if( wfReadOnly() ) {
$wgOut->readOnlyPage();
return;
}
//check token if uploading or reUploading
if( !$this->mTokenOk && !$this->mReUpload && ($this->mUpload && (
'submit' == $this->mAction || $this->mUploadClicked ) ) )
{
$this->mainUploadForm ( wfMsgExt( 'session_fail_preview', 'parseinline' ) );
return ;
}
if( $this->mReUpload && $this->mUpload) {
// User choose to cancel upload
if( !$this->mUpload->unsaveUploadedFile() ) {
return;
}
# Because it is probably checked and shouldn't be
$this->mIgnoreWarning = false;
$this->mainUploadForm();
} elseif( $this->mUpload && (
'submit' == $this->mAction ||
$this->mUploadClicked
) ) {
$this->processUpload();
} else {
$this->mainUploadForm();
}
if( $this->mUpload )
$this->mUpload->cleanupTempFile();
}
/**
* Do the upload
* Checks are made in SpecialUpload::execute()
*
* FIXME this should really use the standard Status class (instead of associative array)
* FIXME would be nice if we refactored this into the upload api.
* (the special upload page is not the only response point that needs clean localized error msgs)
*
* @access private
*/
function processUpload() {
global $wgOut, $wgFileExtensions, $wgLang;
$details = $this->internalProcessUpload();
switch( $details['status'] ) {
case UploadBase::SUCCESS:
$wgOut->redirect( $this->mLocalFile->getTitle()->getFullURL() );
break;
case UploadBase::BEFORE_PROCESSING:
$this->uploadError( $details['error'] );
break;
case UploadBase::LARGE_FILE_SERVER:
$this->mainUploadForm( wfMsgHtml( 'largefileserver' ) );
break;
case UploadBase::EMPTY_FILE:
$this->mainUploadForm( wfMsgHtml( 'emptyfile' ) );
break;
case UploadBase::MIN_LENGTH_PARTNAME:
$this->mainUploadForm( wfMsgHtml( 'minlength1' ) );
break;
case UploadBase::ILLEGAL_FILENAME:
$this->uploadError( wfMsgExt( 'illegalfilename',
'parseinline', $details['filtered'] ) );
break;
case UploadBase::PROTECTED_PAGE:
$wgOut->showPermissionsErrorPage( $details['permissionserrors'] );
break;
case UploadBase::OVERWRITE_EXISTING_FILE:
$this->uploadError( wfMsgExt( $details['overwrite'],
'parseinline' ) );
break;
case UploadBase::FILETYPE_MISSING:
$this->uploadError( wfMsgExt( 'filetype-missing', array ( 'parseinline' ) ) );
break;
case UploadBase::FILETYPE_BADTYPE:
$finalExt = $details['finalExt'];
$this->uploadError(
wfMsgExt( 'filetype-banned-type',
array( 'parseinline' ),
htmlspecialchars( $finalExt ),
implode(
wfMsgExt( 'comma-separator', array( 'escapenoentities' ) ),
$wgFileExtensions
),
$wgLang->formatNum( count( $wgFileExtensions ) )
)
);
break;
case UploadBase::VERIFICATION_ERROR:
unset( $details['status'] );
$code = array_shift( $details['details'] );
$this->uploadError( wfMsgExt( $code, 'parseinline', $details['details'] ) );
break;
case UploadBase::UPLOAD_VERIFICATION_ERROR:
$error = $details['error'];
$this->uploadError( wfMsgExt( $error, 'parseinline' ) );
break;
case UploadBase::UPLOAD_WARNING:
unset( $details['status'] );
$this->uploadWarning( $details );
break;
case UploadBase::INTERNAL_ERROR:
$status = $details['internal'];
$this->showError( $wgOut->parse( $status->getWikiText() ) );
break;
default:
throw new MWException( __METHOD__ . ": Unknown value `{$details['status']}`" );
}
}
/**
* Really do the upload
* Checks are made in SpecialUpload::execute()
*
* @param array $resultDetails contains result-specific dict of additional values
*
* @access private
*/
function internalProcessUpload() {
global $wgUser;
if( !wfRunHooks( 'UploadForm:BeforeProcessing', array( &$this ) ) )
{
wfDebug( "Hook 'UploadForm:BeforeProcessing' broke processing the file.\n" );
return array( 'status' => UploadBase::BEFORE_PROCESSING );
}
/**
* If the image is protected, non-sysop users won't be able
* to modify it by uploading a new revision.
*/
$permErrors = $this->mUpload->verifyPermissions( $wgUser );
if( $permErrors !== true ) {
return array( 'status' => UploadBase::PROTECTED_PAGE, 'permissionserrors' => $permErrors );
}
// Fetch the file if required
$status = $this->mUpload->fetchFile();
if( !$status->isOK() ) {
return array( 'status' => UploadBase::BEFORE_PROCESSING, 'error'=> $status->getWikiText() );
}
// Check whether this is a sane upload
$result = $this->mUpload->verifyUpload();
if( $result['status'] != UploadBase::OK )
return $result;
$this->mLocalFile = $this->mUpload->getLocalFile();
if( !$this->mIgnoreWarning ) {
$warnings = $this->mUpload->checkWarnings();
if( count( $warnings ) ) {
$warnings['status'] = UploadBase::UPLOAD_WARNING;
return $warnings;
}
}
/**
* Try actually saving the thing...
* It will show an error form on failure. No it will not.
*/
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, $wgUser );
if ( !$status->isGood() ) {
return array( 'status' => UploadBase::INTERNAL_ERROR, 'internal' => $status );
} else {
// Success, redirect to description page
wfRunHooks( 'SpecialUploadComplete', array( &$this ) );
return UploadBase::SUCCESS;
}
}
/**
* Formats a result of UploadBase::getExistsWarning as HTML
* This check is static and can be done pre-upload via AJAX
*
* @param array $exists The result of UploadBase::getExistsWarning
* @return string Empty string if there is no warning or an HTML fragment
* consisting of one or more
elements if there is a warning.
*/
public static function getExistsWarning( $exists ) {
global $wgUser, $wgContLang;
if ( !$exists )
return '';
$file = $exists['file'];
$filename = $file->getTitle()->getPrefixedText();
$warning = array();
$sk = $wgUser->getSkin();
if( $exists['warning'] == 'exists' ) {
// Exact match
$warning[] = '
';
} elseif ( $exists['warning'] == 'was-deleted' ) {
# If the file existed before and was deleted, warn the user of this
$ltitle = SpecialPage::getTitleFor( 'Log' );
$llink = $sk->linkKnown(
$ltitle,
wfMsgHtml( 'deletionlog' ),
array(),
array(
'type' => 'delete',
'page' => $filename
)
);
$warning[] = '
' . wfMsgWikiHtml( 'filewasdeleted', $llink ) . '
';
}
return implode( "\n", $warning );
}
/**
* Get a list of warnings
*
* @param string local filename, e.g. 'file exists', 'non-descriptive filename'
* @return array list of warning messages
*/
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 = ' ';
if ( $file ) {
$exists = UploadBase::getExistsWarning( $file );
$warning = self::getExistsWarning( $exists );
// FIXME: We probably also want the prefix blacklist and the wasdeleted check here
if ( $warning !== '' ) {
$s = "
$warning
";
}
}
return $s;
}
/**
* Render a preview of a given license for the AJAX preview on upload
*
* @param string $license
* @return string
*/
public static function ajaxGetLicensePreview( $license ) {
global $wgParser, $wgUser;
$text = '{{' . $license . '}}';
$title = Title::makeTitle( NS_FILE, 'Sample.jpg' );
$options = ParserOptions::newFromUser( $wgUser );
// Expand subst: first, then live templates...
$text = $wgParser->preSaveTransform( $text, $title, $wgUser, $options );
$output = $wgParser->parse( $text, $title, $options );
return $output->getText();
}
/**
* Construct the human readable warning message from an array of duplicate files
*/
public static function getDupeWarning( $dupes ) {
if( $dupes ) {
global $wgOut;
$msg = "";
foreach( $dupes as $file ) {
$title = $file->getTitle();
$msg .= $title->getPrefixedText() .
"|" . $title->getText() . "\n";
}
$msg .= "";
return "
\n";
} else {
return '';
}
}
/**
* Remove a temporarily kept file stashed by saveTempUploadedFile().
* @access private
* @return success
*/
function unsaveUploadedFile() {
global $wgOut;
$success = $this->mUpload->unsaveUploadedFile();
if ( ! $success ) {
$wgOut->showFileDeleteError( $this->mUpload->getTempPath() );
return false;
} else {
return true;
}
}
/* Interface code starts below this line *
* -------------------------------------------------------------- */
/**
* @param string $error as HTML
* @access private
*/
function uploadError( $error ) {
global $wgOut;
$wgOut->addHTML( '
' . wfMsgHtml( 'uploadwarning' ) . "
\n" );
$wgOut->addHTML( '' . $error . '' );
}
/**
* There's something wrong with this file, not enough to reject it
* totally but we require manual intervention to save it for real.
* Stash it away, then present a form asking to confirm or cancel.
*
* @param string $warning as HTML
* @access private
*/
function uploadWarning( $warnings ) {
global $wgOut, $wgUser;
global $wgUseCopyrightUpload;
$this->mSessionKey = $this->mUpload->stashSession();
if( $this->mSessionKey === false ) {
# Couldn't save file; an error has been displayed so let's go.
return;
}
$sk = $wgUser->getSkin();
$wgOut->addHTML( '
' . wfMsgHtml( 'uploadwarning' ) . "
\n" );
$wgOut->addHTML( '
' );
foreach( $warnings as $warning => $args ) {
$msg = null;
if( $warning == 'exists' ) {
//we should not have produced this warning if the user already acknowledged the destination warning
//at any rate I don't see why we should hid this warning if mDestWarningAck has been checked
//(it produces an empty warning page when no other warnings are fired)
//if ( !$this->mDestWarningAck )
$msg = self::getExistsWarning( $args );
} elseif( $warning == 'duplicate' ) {
$msg = $this->getDupeWarning( $args );
} elseif( $warning == 'duplicate-archive' ) {
$titleText = Title::makeTitle( NS_FILE, $args )->getPrefixedText();
$msg = Xml::tags( 'li', null, wfMsgExt( 'file-deleted-duplicate', array( 'parseinline' ), array( $titleText ) ) );
} else {
if( is_bool( $args ) )
$args = array();
elseif( !is_array( $args ) )
$args = array( $args );
$msg = "\t
\n" );
# Print a list of allowed file extensions, if so configured. We ignore
# MIME type here, it's incomprehensible to most people and too long.
global $wgCheckFileExtensions, $wgStrictFileExtensions,
$wgFileExtensions, $wgFileBlacklist;
$allowedExtensions = '';
if( $wgCheckFileExtensions ) {
if( $wgStrictFileExtensions ) {
# Everything not permitted is banned
$extensionsList =
'
\n";
}
} else {
# Everything is permitted.
$extensionsList = '';
}
# Get the maximum file size from php.ini as $wgMaxUploadSize works for uploads from URL via CURL only
# See http://www.php.net/manual/en/ini.core.php#ini.upload-max-filesize for possible values of upload_max_filesize
$val = wfShorthandToInteger( ini_get( 'upload_max_filesize' ) );
$maxUploadSize = '