diff options
Diffstat (limited to 'includes/upload/UploadBase.php')
-rw-r--r-- | includes/upload/UploadBase.php | 161 |
1 files changed, 82 insertions, 79 deletions
diff --git a/includes/upload/UploadBase.php b/includes/upload/UploadBase.php index 14959c26..6da8250b 100644 --- a/includes/upload/UploadBase.php +++ b/includes/upload/UploadBase.php @@ -69,8 +69,6 @@ abstract class UploadBase { const WINDOWS_NONASCII_FILENAME = 13; const FILENAME_TOO_LONG = 14; - const SESSION_STATUS_KEY = 'wsUploadStatusData'; - /** * @param int $error * @return string @@ -152,7 +150,7 @@ abstract class UploadBase { // Give hooks the chance to handle this request $className = null; - wfRunHooks( 'UploadCreateFromRequest', array( $type, &$className ) ); + Hooks::run( 'UploadCreateFromRequest', array( $type, &$className ) ); if ( is_null( $className ) ) { $className = 'UploadFrom' . $type; wfDebug( __METHOD__ . ": class name: $className\n" ); @@ -263,7 +261,6 @@ abstract class UploadBase { * @return string|bool The real path if it was a virtual URL Returns false on failure */ function getRealPath( $srcPath ) { - wfProfileIn( __METHOD__ ); $repo = RepoGroup::singleton()->getLocalRepo(); if ( $repo->isVirtualUrl( $srcPath ) ) { /** @todo Just make uploads work with storage paths UploadFromStash @@ -277,7 +274,6 @@ abstract class UploadBase { } else { $path = $srcPath; } - wfProfileOut( __METHOD__ ); return $path; } @@ -287,13 +283,11 @@ abstract class UploadBase { * @return mixed Const self::OK or else an array with error information */ public function verifyUpload() { - wfProfileIn( __METHOD__ ); /** * If there was no filename or a zero size given, give up quick. */ if ( $this->isEmptyFile() ) { - wfProfileOut( __METHOD__ ); return array( 'status' => self::EMPTY_FILE ); } @@ -303,7 +297,6 @@ abstract class UploadBase { */ $maxSize = self::getMaxUploadSize( $this->getSourceType() ); if ( $this->mFileSize > $maxSize ) { - wfProfileOut( __METHOD__ ); return array( 'status' => self::FILE_TOO_LARGE, @@ -318,7 +311,6 @@ abstract class UploadBase { */ $verification = $this->verifyFile(); if ( $verification !== true ) { - wfProfileOut( __METHOD__ ); return array( 'status' => self::VERIFICATION_ERROR, @@ -331,22 +323,18 @@ abstract class UploadBase { */ $result = $this->validateName(); if ( $result !== true ) { - wfProfileOut( __METHOD__ ); return $result; } $error = ''; - if ( !wfRunHooks( 'UploadVerification', + if ( !Hooks::run( 'UploadVerification', array( $this->mDestName, $this->mTempPath, &$error ) ) ) { - wfProfileOut( __METHOD__ ); return array( 'status' => self::HOOK_ABORTED, 'error' => $error ); } - wfProfileOut( __METHOD__ ); - return array( 'status' => self::OK ); } @@ -388,12 +376,10 @@ abstract class UploadBase { */ protected function verifyMimeType( $mime ) { global $wgVerifyMimeType; - wfProfileIn( __METHOD__ ); if ( $wgVerifyMimeType ) { wfDebug( "mime: <$mime> extension: <{$this->mFinalExtension}>\n" ); global $wgMimeTypeBlacklist; if ( $this->checkFileExtension( $mime, $wgMimeTypeBlacklist ) ) { - wfProfileOut( __METHOD__ ); return array( 'filetype-badmime', $mime ); } @@ -408,15 +394,12 @@ abstract class UploadBase { $ieTypes = $magic->getIEMimeTypes( $this->mTempPath, $chunk, $extMime ); foreach ( $ieTypes as $ieType ) { if ( $this->checkFileExtension( $ieType, $wgMimeTypeBlacklist ) ) { - wfProfileOut( __METHOD__ ); return array( 'filetype-bad-ie-mime', $ieType ); } } } - wfProfileOut( __METHOD__ ); - return true; } @@ -426,12 +409,10 @@ abstract class UploadBase { * @return mixed True of the file is verified, array otherwise. */ protected function verifyFile() { - global $wgVerifyMimeType; - wfProfileIn( __METHOD__ ); + global $wgVerifyMimeType, $wgDisableUploadScriptChecks; $status = $this->verifyPartialFile(); if ( $status !== true ) { - wfProfileOut( __METHOD__ ); return $status; } @@ -442,32 +423,39 @@ abstract class UploadBase { if ( $wgVerifyMimeType ) { # XXX: Missing extension will be caught by validateName() via getTitle() if ( $this->mFinalExtension != '' && !$this->verifyExtension( $mime, $this->mFinalExtension ) ) { - wfProfileOut( __METHOD__ ); return array( 'filetype-mime-mismatch', $this->mFinalExtension, $mime ); } } + # check for htmlish code and javascript + if ( !$wgDisableUploadScriptChecks ) { + if ( $this->mFinalExtension == 'svg' || $mime == 'image/svg+xml' ) { + $svgStatus = $this->detectScriptInSvg( $this->mTempPath, false ); + if ( $svgStatus !== false ) { + + return $svgStatus; + } + } + } + $handler = MediaHandler::getHandler( $mime ); if ( $handler ) { $handlerStatus = $handler->verifyUpload( $this->mTempPath ); if ( !$handlerStatus->isOK() ) { $errors = $handlerStatus->getErrorsArray(); - wfProfileOut( __METHOD__ ); return reset( $errors ); } } - wfRunHooks( 'UploadVerifyFile', array( $this, $mime, &$status ) ); + Hooks::run( 'UploadVerifyFile', array( $this, $mime, &$status ) ); if ( $status !== true ) { - wfProfileOut( __METHOD__ ); return $status; } wfDebug( __METHOD__ . ": all clear; passing.\n" ); - wfProfileOut( __METHOD__ ); return true; } @@ -482,7 +470,6 @@ abstract class UploadBase { */ protected function verifyPartialFile() { global $wgAllowJavaUploads, $wgDisableUploadScriptChecks; - wfProfileIn( __METHOD__ ); # getTitle() sets some internal parameters like $this->mFinalExtension $this->getTitle(); @@ -493,7 +480,6 @@ abstract class UploadBase { $mime = $this->mFileProps['file-mime']; $status = $this->verifyMimeType( $mime ); if ( $status !== true ) { - wfProfileOut( __METHOD__ ); return $status; } @@ -501,14 +487,12 @@ abstract class UploadBase { # check for htmlish code and javascript if ( !$wgDisableUploadScriptChecks ) { if ( self::detectScript( $this->mTempPath, $mime, $this->mFinalExtension ) ) { - wfProfileOut( __METHOD__ ); return array( 'uploadscripted' ); } if ( $this->mFinalExtension == 'svg' || $mime == 'image/svg+xml' ) { - $svgStatus = $this->detectScriptInSvg( $this->mTempPath ); + $svgStatus = $this->detectScriptInSvg( $this->mTempPath, true ); if ( $svgStatus !== false ) { - wfProfileOut( __METHOD__ ); return $svgStatus; } @@ -525,13 +509,11 @@ abstract class UploadBase { $errors = $zipStatus->getErrorsArray(); $error = reset( $errors ); if ( $error[0] !== 'zip-wrong-format' ) { - wfProfileOut( __METHOD__ ); return $error; } } if ( $this->mJavaDetected ) { - wfProfileOut( __METHOD__ ); return array( 'uploadjava' ); } @@ -540,13 +522,10 @@ abstract class UploadBase { # Scan the uploaded file for viruses $virus = $this->detectVirus( $this->mTempPath ); if ( $virus ) { - wfProfileOut( __METHOD__ ); return array( 'uploadvirus', $virus ); } - wfProfileOut( __METHOD__ ); - return true; } @@ -639,11 +618,11 @@ abstract class UploadBase { */ public function checkWarnings() { global $wgLang; - wfProfileIn( __METHOD__ ); $warnings = array(); $localFile = $this->getLocalFile(); + $localFile->load( File::READ_LATEST ); $filename = $localFile->getName(); /** @@ -699,17 +678,15 @@ abstract class UploadBase { } // Check dupes against archives - $archivedImage = new ArchivedFile( null, 0, "{$hash}.{$this->mFinalExtension}" ); - if ( $archivedImage->getID() > 0 ) { - if ( $archivedImage->userCan( File::DELETED_FILE ) ) { - $warnings['duplicate-archive'] = $archivedImage->getName(); + $archivedFile = new ArchivedFile( null, 0, '', $hash ); + if ( $archivedFile->getID() > 0 ) { + if ( $archivedFile->userCan( File::DELETED_FILE ) ) { + $warnings['duplicate-archive'] = $archivedFile->getName(); } else { $warnings['duplicate-archive'] = ''; } } - wfProfileOut( __METHOD__ ); - return $warnings; } @@ -725,7 +702,7 @@ abstract class UploadBase { * @return Status Indicating the whether the upload succeeded. */ public function performUpload( $comment, $pageText, $watch, $user ) { - wfProfileIn( __METHOD__ ); + $this->getLocalFile()->load( File::READ_LATEST ); $status = $this->getLocalFile()->upload( $this->mTempPath, @@ -745,15 +722,44 @@ abstract class UploadBase { WatchedItem::IGNORE_USER_RIGHTS ); } - wfRunHooks( 'UploadComplete', array( &$this ) ); - } + Hooks::run( 'UploadComplete', array( &$this ) ); - wfProfileOut( __METHOD__ ); + $this->postProcessUpload(); + } return $status; } /** + * Perform extra steps after a successful upload. + * + * @since 1.25 + */ + public function postProcessUpload() { + global $wgUploadThumbnailRenderMap; + + $jobs = array(); + + $sizes = $wgUploadThumbnailRenderMap; + rsort( $sizes ); + + $file = $this->getLocalFile(); + + foreach ( $sizes as $size ) { + if ( $file->isVectorized() + || $file->getWidth() > $size ) { + $jobs[] = new ThumbnailRenderJob( $file->getTitle(), array( + 'transformParams' => array( 'width' => $size ), + ) ); + } + } + + if ( $jobs ) { + JobQueueGroup::singleton()->push( $jobs ); + } + } + + /** * Returns the title of the file to be uploaded. Sets mTitleError in case * the name was illegal. * @@ -911,14 +917,11 @@ abstract class UploadBase { */ public function stashFile( User $user = null ) { // was stashSessionFile - wfProfileIn( __METHOD__ ); $stash = RepoGroup::singleton()->getLocalRepo()->getUploadStash( $user ); $file = $stash->stashFile( $this->mTempPath, $this->getSourceType() ); $this->mLocalFile = $file; - wfProfileOut( __METHOD__ ); - return $file; } @@ -1058,7 +1061,6 @@ abstract class UploadBase { */ public static function detectScript( $file, $mime, $extension ) { global $wgAllowTitlesInSVG; - wfProfileIn( __METHOD__ ); # ugly hack: for text files, always look at the entire file. # For binary field, just check the first K. @@ -1074,7 +1076,6 @@ abstract class UploadBase { $chunk = strtolower( $chunk ); if ( !$chunk ) { - wfProfileOut( __METHOD__ ); return false; } @@ -1099,7 +1100,6 @@ abstract class UploadBase { # check for HTML doctype if ( preg_match( "/<!DOCTYPE *X?HTML/i", $chunk ) ) { - wfProfileOut( __METHOD__ ); return true; } @@ -1108,7 +1108,6 @@ abstract class UploadBase { // PHP/expat will interpret the given encoding in the xml declaration (bug 47304) if ( $extension == 'svg' || strpos( $mime, 'image/svg' ) === 0 ) { if ( self::checkXMLEncodingMissmatch( $file ) ) { - wfProfileOut( __METHOD__ ); return true; } @@ -1147,7 +1146,6 @@ abstract class UploadBase { foreach ( $tags as $tag ) { if ( false !== strpos( $chunk, $tag ) ) { wfDebug( __METHOD__ . ": found something that may make it be mistaken for html: $tag\n" ); - wfProfileOut( __METHOD__ ); return true; } @@ -1163,7 +1161,6 @@ abstract class UploadBase { # look for script-types if ( preg_match( '!type\s*=\s*[\'"]?\s*(?:\w*/)?(?:ecma|java)!sim', $chunk ) ) { wfDebug( __METHOD__ . ": found script types\n" ); - wfProfileOut( __METHOD__ ); return true; } @@ -1171,7 +1168,6 @@ abstract class UploadBase { # look for html-style script-urls if ( preg_match( '!(?:href|src|data)\s*=\s*[\'"]?\s*(?:ecma|java)script:!sim', $chunk ) ) { wfDebug( __METHOD__ . ": found html-style script urls\n" ); - wfProfileOut( __METHOD__ ); return true; } @@ -1179,13 +1175,11 @@ abstract class UploadBase { # look for css-style script-urls if ( preg_match( '!url\s*\(\s*[\'"]?\s*(?:ecma|java)script:!sim', $chunk ) ) { wfDebug( __METHOD__ . ": found css-style script urls\n" ); - wfProfileOut( __METHOD__ ); return true; } wfDebug( __METHOD__ . ": no scripts found\n" ); - wfProfileOut( __METHOD__ ); return false; } @@ -1252,9 +1246,10 @@ abstract class UploadBase { /** * @param string $filename + * @param bool $partial * @return mixed False of the file is verified (does not contain scripts), array otherwise. */ - protected function detectScriptInSvg( $filename ) { + protected function detectScriptInSvg( $filename, $partial ) { $this->mSVGNSError = false; $check = new XmlTypeCheck( $filename, @@ -1264,7 +1259,8 @@ abstract class UploadBase { ); if ( $check->wellFormed !== true ) { // Invalid xml (bug 58553) - return array( 'uploadinvalidxml' ); + // But only when non-partial (bug 65724) + return $partial ? false : array( 'uploadinvalidxml' ); } elseif ( $check->filterMatch ) { if ( $this->mSVGNSError ) { return array( 'uploadscriptednamespace', $this->mSVGNSError ); @@ -1602,11 +1598,9 @@ abstract class UploadBase { */ public static function detectVirus( $file ) { global $wgAntivirus, $wgAntivirusSetup, $wgAntivirusRequired, $wgOut; - wfProfileIn( __METHOD__ ); if ( !$wgAntivirus ) { wfDebug( __METHOD__ . ": virus scanner disabled\n" ); - wfProfileOut( __METHOD__ ); return null; } @@ -1615,7 +1609,6 @@ abstract class UploadBase { wfDebug( __METHOD__ . ": unknown virus scanner: $wgAntivirus\n" ); $wgOut->wrapWikiMsg( "<div class=\"error\">\n$1\n</div>", array( 'virus-badscanner', $wgAntivirus ) ); - wfProfileOut( __METHOD__ ); return wfMessage( 'virus-unknownscanner' )->text() . " $wgAntivirus"; } @@ -1689,8 +1682,6 @@ abstract class UploadBase { wfDebug( __METHOD__ . ": FOUND VIRUS! scanner feedback: $output \n" ); } - wfProfileOut( __METHOD__ ); - return $output; } @@ -1705,6 +1696,7 @@ abstract class UploadBase { private function checkOverwrite( $user ) { // First check whether the local file can be overwritten $file = $this->getLocalFile(); + $file->load( File::READ_LATEST ); if ( $file->exists() ) { if ( !self::userCanReUpload( $user, $file ) ) { return array( 'fileexists-forbidden', $file->getName() ); @@ -1716,7 +1708,7 @@ abstract class UploadBase { /* Check shared conflicts: if the local file does not exist, but * wfFindFile finds a file, it exists in a shared repository. */ - $file = wfFindFile( $this->getTitle() ); + $file = wfFindFile( $this->getTitle(), array( 'latest' => true ) ); if ( $file && !$user->isAllowed( 'reupload-shared' ) ) { return array( 'fileexists-shared-forbidden', $file->getName() ); } @@ -1745,6 +1737,8 @@ abstract class UploadBase { return false; } + $img->load( File::READ_LATEST ); + return $user->getId() == $img->getUser( 'id' ); } @@ -1950,29 +1944,38 @@ abstract class UploadBase { } /** - * Get the current status of a chunked upload (used for polling). - * The status will be read from the *current* user session. + * Get the current status of a chunked upload (used for polling) + * + * The value will be read from cache. + * + * @param User $user * @param string $statusKey * @return Status[]|bool */ - public static function getSessionStatus( $statusKey ) { - return isset( $_SESSION[self::SESSION_STATUS_KEY][$statusKey] ) - ? $_SESSION[self::SESSION_STATUS_KEY][$statusKey] - : false; + public static function getSessionStatus( User $user, $statusKey ) { + $key = wfMemcKey( 'uploadstatus', $user->getId() ?: md5( $user->getName() ), $statusKey ); + + return wfGetCache( CACHE_ANYTHING )->get( $key ); } /** - * Set the current status of a chunked upload (used for polling). - * The status will be stored in the *current* user session. + * Set the current status of a chunked upload (used for polling) + * + * The value will be set in cache for 1 day + * + * @param User $user * @param string $statusKey * @param array|bool $value * @return void */ - public static function setSessionStatus( $statusKey, $value ) { + public static function setSessionStatus( User $user, $statusKey, $value ) { + $key = wfMemcKey( 'uploadstatus', $user->getId() ?: md5( $user->getName() ), $statusKey ); + + $cache = wfGetCache( CACHE_ANYTHING ); if ( $value === false ) { - unset( $_SESSION[self::SESSION_STATUS_KEY][$statusKey] ); + $cache->delete( $key ); } else { - $_SESSION[self::SESSION_STATUS_KEY][$statusKey] = $value; + $cache->set( $key, $value, 86400 ); } } } |