Don't force edit encoding when LanguageEo.php is loaded; defer until $wgContLang...
[lhc/web/wiklou.git] / includes / SpecialUpload.php
index 1e3d40c..a5b32f0 100644 (file)
@@ -31,8 +31,8 @@ class UploadForm {
        var $mUploadAffirm, $mUploadFile, $mUploadDescription, $mIgnoreWarning;
        var $mUploadSaveName, $mUploadTempName, $mUploadSize, $mUploadOldVersion;
        var $mUploadCopyStatus, $mUploadSource, $mReUpload, $mAction, $mUpload;
-       var $mOname, $mSessionKey;
-       /**#@- */
+       var $mOname, $mSessionKey, $mStashed;
+       /**#@-*/
 
        /**
         * Constructor : initialise object
@@ -69,6 +69,7 @@ class UploadForm {
                        $this->mUploadTempName   = $data['mUploadTempName'];
                        $this->mUploadSize       = $data['mUploadSize'];
                        $this->mOname            = $data['mOname'];
+                       $this->mStashed          = true;
                } else {
                        /**
                         *Check for a newly uploaded file.
@@ -77,6 +78,7 @@ class UploadForm {
                        $this->mUploadSize     = $request->getFileSize( 'wpUploadFile' );
                        $this->mOname          = $request->getFileName( 'wpUploadFile' );
                        $this->mSessionKey     = false;
+                       $this->mStashed        = false;
                }
        }
 
@@ -95,7 +97,7 @@ class UploadForm {
                }
                
                /** Various rights checks */
-               if( ( $wgUser->getID() == 0 )
+               if( ( $wgUser->isAnon() )
                         OR $wgUser->isBlocked() ) {
                        $wgOut->errorpage( 'uploadnologin', 'uploadnologintext' );
                        return;
@@ -156,14 +158,18 @@ class UploadForm {
                # Chop off any directories in the given filename
                $basename = basename( $this->mOname );
 
-               if( preg_match( '/^(.*)\.([^.]*)$/', $basename, $matches ) ) {
-                       $partname = $matches[1];
-                       $ext      = $matches[2];
+               /**
+                * We'll want to blacklist against *any* 'extension', and use
+                * only the final one for the whitelist.
+                */
+               list( $partname, $ext ) = $this->splitExtensions( $basename );
+               if( count( $ext ) ) {
+                       $finalExt = $ext[count( $ext ) - 1];
                } else {
-                   $partname = $basename;
-                   $ext = '';
+                       $finalExt = '';
                }
-
+               $fullExt = implode( '.', $ext );
+               
                if ( strlen( $partname ) < 3 ) {
                        $this->mainUploadForm( wfMsg( 'minlength' ) );
                        return;
@@ -192,9 +198,10 @@ class UploadForm {
                /* Don't allow users to override the blacklist */
                global $wgStrictFileExtensions;
                global $wgFileExtensions, $wgFileBlacklist;
-               if( $this->checkFileExtension( $ext, $wgFileBlacklist ) ||
-                       ($wgStrictFileExtensions && !$this->checkFileExtension( $ext, $wgFileExtensions ) ) ) {
-                       return $this->uploadError( wfMsg( 'badfiletype', htmlspecialchars( $ext ) ) );
+               if( $this->checkFileExtensionList( $ext, $wgFileBlacklist ) ||
+                       ($wgStrictFileExtensions &&
+                               !$this->checkFileExtension( $finalExt, $wgFileExtensions ) ) ) {
+                       return $this->uploadError( wfMsg( 'badfiletype', htmlspecialchars( $fullExt ) ) );
                }
                
                /**
@@ -202,7 +209,7 @@ class UploadForm {
                 * type but it's corrupt or data of the wrong type, we should
                 * probably not accept it.
                 */
-               if( !$this->verify( $this->mUploadTempName, $ext ) ) {
+               if( !$this->mStashed && !$this->verify( $this->mUploadTempName, $finalExt ) ) {
                        return $this->uploadError( wfMsg( 'uploadcorrupt' ) );
                }
                
@@ -217,8 +224,8 @@ class UploadForm {
        
                        global $wgCheckFileExtensions;
                        if ( $wgCheckFileExtensions ) {
-                               if ( ! $this->checkFileExtension( $ext, $wgFileExtensions ) ) {
-                                       $warning .= '<li>'.wfMsg( 'badfiletype', htmlspecialchars( $ext ) ).'</li>';
+                               if ( ! $this->checkFileExtension( $finalExt, $wgFileExtensions ) ) {
+                                       $warning .= '<li>'.wfMsg( 'badfiletype', htmlspecialchars( $fullExt ) ).'</li>';
                                }
                        }
        
@@ -263,6 +270,10 @@ class UploadForm {
                                        $this->mUploadDescription,
                                        $this->mUploadCopyStatus,
                                        $this->mUploadSource );
+
+                       /* refresh image metadata cache */
+                       new Image( $this->mUploadSaveName, true );
+
                        $this->showSuccess();
                }
        }
@@ -386,7 +397,7 @@ class UploadForm {
                
                $sk = $wgUser->getSkin();
                $ilink = $sk->makeMediaLink( $this->mUploadSaveName, Image::wfImageUrl( $this->mUploadSaveName ) );
-               $dname = $wgContLang->getNsText( Namespace::getImage() ) . ':'.$this->mUploadSaveName;
+               $dname = $wgContLang->getNsText( NS_IMAGE ) . ':'.$this->mUploadSaveName;
                $dlink = $sk->makeKnownLink( $dname, $dname );
 
                $wgOut->addHTML( '<h2>' . wfMsg( 'successfulupload' ) . "</h2>\n" );
@@ -426,7 +437,7 @@ class UploadForm {
 
                $sub = wfMsg( 'uploadwarning' );
                $wgOut->addHTML( "<h2>{$sub}</h2>\n" );
-               $wgOut->addHTML( "<ul class='warning'>{$warning}</ul><br/>\n" );
+               $wgOut->addHTML( "<ul class='warning'>{$warning}</ul><br />\n" );
 
                $save = wfMsg( 'savefile' );
                $reupload = wfMsg( 'reupload' );
@@ -534,6 +545,20 @@ class UploadForm {
        
        /* -------------------------------------------------------------- */
 
+       /**
+        * Split a file into a base name and all dot-delimited 'extensions'
+        * on the end. Some web server configurations will fall back to
+        * earlier pseudo-'extensions' to determine type and execute
+        * scripts, so the blacklist needs to check them all.
+        *
+        * @return array
+        */
+       function splitExtensions( $filename ) {
+               $bits = explode( '.', $filename );
+               $basename = array_shift( $bits );
+               return array( $basename, $bits );
+       }
+       
        /**
         * Perform case-insensitive match against a list of file extensions.
         * Returns true if the extension is in the list.
@@ -546,6 +571,23 @@ class UploadForm {
                return in_array( strtolower( $ext ), $list );
        }
 
+       /**
+        * Perform case-insensitive match against a list of file extensions.
+        * Returns true if any of the extensions are in the list.
+        *
+        * @param array $ext
+        * @param array $list
+        * @return bool
+        */
+       function checkFileExtensionList( $ext, $list ) {
+               foreach( $ext as $e ) {
+                       if( in_array( strtolower( $e ), $list ) ) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+       
        /**
         * Returns false if the file is of a known type but can't be recognized,
         * indicating a corrupt file.
@@ -557,7 +599,8 @@ class UploadForm {
         * @return bool
         */
        function verify( $tmpfile, $extension ) {
-               if( $this->triggersIEbug( $tmpfile ) ) {
+               if( $this->triggersIEbug( $tmpfile ) ||
+                   $this->triggersSafariBug( $tmpfile ) ) {
                        return false;
                }
                
@@ -643,10 +686,47 @@ class UploadForm {
         */
        function triggersIEbug( $filename ) {
                $file = fopen( $filename, 'rb' );
-               $chunk = strtolower( fread( $file, 200 ) );
+               $chunk = strtolower( fread( $file, 256 ) );
+               fclose( $file );
+               
+               $tags = array(
+                       '<body',
+                       '<head',
+                       '<html',
+                       '<img',
+                       '<pre',
+                       '<script',
+                       '<table',
+                       '<title' );
+               foreach( $tags as $tag ) {
+                       if( false !== strpos( $chunk, $tag ) ) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+       /**
+        * Apple's Safari browser performs some unsafe file type autodetection
+        * which can cause legitimate files to be interpreted as HTML if the
+        * web server is not correctly configured to send the right content-type
+        * (or if you're really uploading plain text and octet streams!)
+        *
+        * Returns true if Safari would mistake the given file for HTML
+        * when served with a generic content-type.
+        *
+        * @param string $filename
+        * @return bool
+        */
+       function triggersSafariBug( $filename ) {
+               $file = fopen( $filename, 'rb' );
+               $chunk = strtolower( fread( $file, 1024 ) );
                fclose( $file );
                
-               $tags = array( '<html', '<head', '<body', '<script' );
+               $tags = array(
+                       '<html',
+                       '<script',
+                       '<title' );
                foreach( $tags as $tag ) {
                        if( false !== strpos( $chunk, $tag ) ) {
                                return true;
@@ -654,5 +734,6 @@ class UploadForm {
                }
                return false;
        }
+       
 }
 ?>