Suppress warnings
[lhc/web/wiklou.git] / includes / MimeMagic.php
index 2ef32c4..18fc9e7 100644 (file)
@@ -9,25 +9,43 @@
  * the file mime.types in the includes directory.
  */
 define('MM_WELL_KNOWN_MIME_TYPES',<<<END_STRING
  * the file mime.types in the includes directory.
  */
 define('MM_WELL_KNOWN_MIME_TYPES',<<<END_STRING
-application/ogg ogg ogm
+application/ogg ogx ogg ogm ogv oga spx
 application/pdf pdf
 application/pdf pdf
+application/vnd.oasis.opendocument.chart odc
+application/vnd.oasis.opendocument.chart-template otc
+application/vnd.oasis.opendocument.formula odf
+application/vnd.oasis.opendocument.formula-template otf
+application/vnd.oasis.opendocument.graphics odg
+application/vnd.oasis.opendocument.graphics-template otg
+application/vnd.oasis.opendocument.image odi
+application/vnd.oasis.opendocument.image-template oti
+application/vnd.oasis.opendocument.presentation odp
+application/vnd.oasis.opendocument.presentation-template otp
+application/vnd.oasis.opendocument.spreadsheet ods
+application/vnd.oasis.opendocument.spreadsheet-template ots
+application/vnd.oasis.opendocument.text odt
+application/vnd.oasis.opendocument.text-template ott
+application/vnd.oasis.opendocument.text-master otm
+application/vnd.oasis.opendocument.text-web oth
 application/x-javascript js
 application/x-shockwave-flash swf
 audio/midi mid midi kar
 audio/mpeg mpga mpa mp2 mp3
 audio/x-aiff aif aiff aifc
 audio/x-wav wav
 application/x-javascript js
 application/x-shockwave-flash swf
 audio/midi mid midi kar
 audio/mpeg mpga mpa mp2 mp3
 audio/x-aiff aif aiff aifc
 audio/x-wav wav
-audio/ogg ogg
+audio/ogg oga spx ogg
 image/x-bmp bmp
 image/gif gif
 image/jpeg jpeg jpg jpe
 image/png png
 image/x-bmp bmp
 image/gif gif
 image/jpeg jpeg jpg jpe
 image/png png
-image/svg+xml svg
+image/svg+xml image/svg svg
 image/tiff tiff tif
 image/tiff tiff tif
-image/vnd.djvu djvu
+image/vnd.djvu image/x.djvu image/x-djvu djvu
+image/x-portable-pixmap ppm
+image/x-xcf xcf
 text/plain txt
 text/html html htm
 text/plain txt
 text/html html htm
-video/ogg ogm ogg
+video/ogg ogv ogm ogg
 video/mpeg mpg mpeg
 END_STRING
 );
 video/mpeg mpg mpeg
 END_STRING
 );
@@ -39,6 +57,22 @@ END_STRING
  */
 define('MM_WELL_KNOWN_MIME_INFO', <<<END_STRING
 application/pdf [OFFICE]
  */
 define('MM_WELL_KNOWN_MIME_INFO', <<<END_STRING
 application/pdf [OFFICE]
+application/vnd.oasis.opendocument.chart [OFFICE]
+application/vnd.oasis.opendocument.chart-template [OFFICE]
+application/vnd.oasis.opendocument.formula [OFFICE]
+application/vnd.oasis.opendocument.formula-template [OFFICE]
+application/vnd.oasis.opendocument.graphics [OFFICE]
+application/vnd.oasis.opendocument.graphics-template [OFFICE]
+application/vnd.oasis.opendocument.image [OFFICE]
+application/vnd.oasis.opendocument.image-template [OFFICE]
+application/vnd.oasis.opendocument.presentation [OFFICE]
+application/vnd.oasis.opendocument.presentation-template [OFFICE]
+application/vnd.oasis.opendocument.spreadsheet [OFFICE]
+application/vnd.oasis.opendocument.spreadsheet-template [OFFICE]
+application/vnd.oasis.opendocument.text [OFFICE]
+application/vnd.oasis.opendocument.text-template [OFFICE]
+application/vnd.oasis.opendocument.text-master [OFFICE]
+application/vnd.oasis.opendocument.text-web [OFFICE]
 text/javascript application/x-javascript [EXECUTABLE]
 application/x-shockwave-flash [MULTIMEDIA]
 audio/midi [AUDIO]
 text/javascript application/x-javascript [EXECUTABLE]
 application/x-shockwave-flash [MULTIMEDIA]
 audio/midi [AUDIO]
@@ -46,13 +80,15 @@ audio/x-aiff [AUDIO]
 audio/x-wav [AUDIO]
 audio/mp3 audio/mpeg [AUDIO]
 application/ogg audio/ogg video/ogg [MULTIMEDIA]
 audio/x-wav [AUDIO]
 audio/mp3 audio/mpeg [AUDIO]
 application/ogg audio/ogg video/ogg [MULTIMEDIA]
-image/x-bmp image/bmp [BITMAP]
+image/x-bmp image/x-ms-bmp image/bmp [BITMAP]
 image/gif [BITMAP]
 image/jpeg [BITMAP]
 image/png [BITMAP]
 image/gif [BITMAP]
 image/jpeg [BITMAP]
 image/png [BITMAP]
-image/svg image/svg+xml [DRAWING]
+image/svg+xml [DRAWING]
 image/tiff [BITMAP]
 image/vnd.djvu [BITMAP]
 image/tiff [BITMAP]
 image/vnd.djvu [BITMAP]
+image/x-xcf [BITMAP]
+image/x-portable-pixmap [BITMAP]
 text/plain [TEXT]
 text/html [TEXT]
 video/ogg [VIDEO]
 text/plain [TEXT]
 text/html [TEXT]
 video/ogg [VIDEO]
@@ -66,34 +102,39 @@ END_STRING
 global $wgLoadFileinfoExtension;
 
 if ($wgLoadFileinfoExtension) {
 global $wgLoadFileinfoExtension;
 
 if ($wgLoadFileinfoExtension) {
-       if(!extension_loaded('fileinfo')) dl('fileinfo.' . PHP_SHLIB_SUFFIX);
+       wfDl( 'fileinfo' );
 }
 
 }
 
-/** Implements functions related to mime types such as detection and mapping to
-* file extension,
-*
-* Instances of this class are stateles, there only needs to be one global instance
-* of MimeMagic. Please use MimeMagic::singleton() to get that instance.
-*/
+/**
+ * Implements functions related to mime types such as detection and mapping to
+ * file extension.
+ *
+ * Instances of this class are stateles, there only needs to be one global instance
+ * of MimeMagic. Please use MimeMagic::singleton() to get that instance.
+ */
 class MimeMagic {
 
        /**
        * Mapping of media types to arrays of mime types.
        * This is used by findMediaType and getMediaType, respectively
        */
 class MimeMagic {
 
        /**
        * Mapping of media types to arrays of mime types.
        * This is used by findMediaType and getMediaType, respectively
        */
-       var $mMediaTypes= NULL;
+       var $mMediaTypes= null;
 
        /** Map of mime type aliases
        */
 
        /** Map of mime type aliases
        */
-       var $mMimeTypeAliases= NULL;
+       var $mMimeTypeAliases= null;
 
        /** map of mime types to file extensions (as a space seprarated list)
        */
 
        /** map of mime types to file extensions (as a space seprarated list)
        */
-       var $mMimeToExt= NULL;
+       var $mMimeToExt= null;
 
        /** map of file extensions types to mime types (as a space seprarated list)
        */
 
        /** map of file extensions types to mime types (as a space seprarated list)
        */
-       var $mExtToMime= NULL;
+       var $mExtToMime= null;
+
+       /** IEContentAnalyzer instance
+        */
+       var $mIEAnalyzer;
 
        /** The singleton instance
         */
 
        /** The singleton instance
         */
@@ -108,56 +149,67 @@ class MimeMagic {
                *   --- load mime.types ---
                */
 
                *   --- load mime.types ---
                */
 
-               global $wgMimeTypeFile;
+               global $wgMimeTypeFile, $IP;
 
 
-               $types= MM_WELL_KNOWN_MIME_TYPES;
+               $types = MM_WELL_KNOWN_MIME_TYPES;
 
 
-               if ($wgMimeTypeFile) {
-                       if (is_file($wgMimeTypeFile) and is_readable($wgMimeTypeFile)) {
-                               wfDebug("MimeMagic::MimeMagic: loading mime types from $wgMimeTypeFile\n");
+               if ( $wgMimeTypeFile == 'includes/mime.types' ) {
+                       $wgMimeTypeFile = "$IP/$wgMimeTypeFile";
+               }
 
 
-                               $types.= "\n";
-                               $types.= file_get_contents($wgMimeTypeFile);
+               if ( $wgMimeTypeFile ) {
+                       if ( is_file( $wgMimeTypeFile ) and is_readable( $wgMimeTypeFile ) ) {
+                               wfDebug( __METHOD__.": loading mime types from $wgMimeTypeFile\n" );
+                               $types .= "\n";
+                               $types .= file_get_contents( $wgMimeTypeFile );
+                       } else {
+                               wfDebug( __METHOD__.": can't load mime types from $wgMimeTypeFile\n" );
                        }
                        }
-                       else wfDebug("MimeMagic::MimeMagic: can't load mime types from $wgMimeTypeFile\n");
+               } else {
+                       wfDebug( __METHOD__.": no mime types file defined, using build-ins only.\n" );
                }
                }
-               else wfDebug("MimeMagic::MimeMagic: no mime types file defined, using build-ins only.\n");
 
 
-               $types= str_replace(array("\r\n","\n\r","\n\n","\r\r","\r"),"\n",$types);
-               $types= str_replace("\t"," ",$types);
+               $types = str_replace( array( "\r\n", "\n\r", "\n\n", "\r\r", "\r" ), "\n", $types );
+               $types = str_replace( "\t", " ", $types );
 
 
-               $this->mMimeToExt= array();
-               $this->mToMime= array();
+               $this->mMimeToExt = array();
+               $this->mToMime = array();
 
 
-               $lines= explode("\n",$types);
-               foreach ($lines as $s) {
-                       $s= trim($s);
-                       if (empty($s)) continue;
-                       if (strpos($s,'#')===0) continue;
+               $lines = explode( "\n",$types );
+               foreach ( $lines as $s ) {
+                       $s = trim( $s );
+                       if ( empty( $s ) ) continue;
+                       if ( strpos( $s, '#' ) === 0 ) continue;
 
 
-                       $s= strtolower($s);
-                       $i= strpos($s,' ');
+                       $s = strtolower( $s );
+                       $i = strpos( $s, ' ' );
 
 
-                       if ($i===false) continue;
+                       if ( $i === false ) continue;
 
                        #print "processing MIME line $s<br>";
 
 
                        #print "processing MIME line $s<br>";
 
-                       $mime= substr($s,0,$i);
-                       $ext= trim(substr($s,$i+1));
+                       $mime = substr( $s, 0, $i );
+                       $ext = trim( substr($s, $i+1 ) );
 
 
-                       if (empty($ext)) continue;
+                       if ( empty( $ext ) ) continue;
 
 
-                       if ( !empty($this->mMimeToExt[$mime])) $this->mMimeToExt[$mime] .= ' '.$ext;
-                       else $this->mMimeToExt[$mime]= $ext;
+                       if ( !empty( $this->mMimeToExt[$mime] ) ) {
+                               $this->mMimeToExt[$mime] .= ' ' . $ext;
+                       } else {
+                               $this->mMimeToExt[$mime] = $ext;
+                       }
 
 
-                       $extensions= explode(' ',$ext);
+                       $extensions = explode( ' ', $ext );
 
 
-                       foreach ($extensions as $e) {
-                               $e= trim($e);
-                               if (empty($e)) continue;
+                       foreach ( $extensions as $e ) {
+                               $e = trim( $e );
+                               if ( empty( $e ) ) continue;
 
 
-                               if ( !empty($this->mExtToMime[$e])) $this->mExtToMime[$e] .= ' '.$mime;
-                               else $this->mExtToMime[$e]= $mime;
+                               if ( !empty( $this->mExtToMime[$e] ) ) {
+                                       $this->mExtToMime[$e] .= ' ' . $mime;
+                               } else {
+                                       $this->mExtToMime[$e] = $mime;
+                               }
                        }
                }
 
                        }
                }
 
@@ -166,62 +218,69 @@ class MimeMagic {
                */
 
                global $wgMimeInfoFile;
                */
 
                global $wgMimeInfoFile;
+               if ( $wgMimeInfoFile == 'includes/mime.info' ) {
+                       $wgMimeInfoFile = "$IP/$wgMimeInfoFile";
+               }
 
 
-               $info= MM_WELL_KNOWN_MIME_INFO;
-
-               if ($wgMimeInfoFile) {
-                       if (is_file($wgMimeInfoFile) and is_readable($wgMimeInfoFile)) {
-                               wfDebug("MimeMagic::MimeMagic: loading mime info from $wgMimeInfoFile\n");
+               $info = MM_WELL_KNOWN_MIME_INFO;
 
 
-                               $info.= "\n";
-                               $info.= file_get_contents($wgMimeInfoFile);
+               if ( $wgMimeInfoFile ) {
+                       if ( is_file( $wgMimeInfoFile ) and is_readable( $wgMimeInfoFile ) ) {
+                               wfDebug( __METHOD__.": loading mime info from $wgMimeInfoFile\n" );
+                               $info .= "\n";
+                               $info .= file_get_contents( $wgMimeInfoFile );
+                       } else {
+                               wfDebug(__METHOD__.": can't load mime info from $wgMimeInfoFile\n");
                        }
                        }
-                       else wfDebug("MimeMagic::MimeMagic: can't load mime info from $wgMimeInfoFile\n");
+               } else {
+                       wfDebug(__METHOD__.": no mime info file defined, using build-ins only.\n");
                }
                }
-               else wfDebug("MimeMagic::MimeMagic: no mime info file defined, using build-ins only.\n");
 
 
-               $info= str_replace(array("\r\n","\n\r","\n\n","\r\r","\r"),"\n",$info);
-               $info= str_replace("\t"," ",$info);
+               $info = str_replace( array( "\r\n", "\n\r", "\n\n", "\r\r", "\r" ), "\n", $info);
+               $info = str_replace( "\t", " ", $info );
 
 
-               $this->mMimeTypeAliases= array();
-               $this->mMediaTypes= array();
+               $this->mMimeTypeAliases = array();
+               $this->mMediaTypes = array();
 
 
-               $lines= explode("\n",$info);
-               foreach ($lines as $s) {
-                       $s= trim($s);
-                       if (empty($s)) continue;
-                       if (strpos($s,'#')===0) continue;
+               $lines = explode( "\n", $info );
+               foreach ( $lines as $s ) {
+                       $s = trim( $s );
+                       if ( empty( $s ) ) continue;
+                       if ( strpos( $s, '#' ) === 0 ) continue;
 
 
-                       $s= strtolower($s);
-                       $i= strpos($s,' ');
+                       $s = strtolower( $s );
+                       $i = strpos( $s, ' ' );
 
 
-                       if ($i===false) continue;
+                       if ( $i === false ) continue;
 
                        #print "processing MIME INFO line $s<br>";
 
 
                        #print "processing MIME INFO line $s<br>";
 
-                       $match= array();
-                       if (preg_match('!\[\s*(\w+)\s*\]!',$s,$match)) {
-                               $s= preg_replace('!\[\s*(\w+)\s*\]!','',$s);
-                               $mtype= trim(strtoupper($match[1]));
+                       $match = array();
+                       if ( preg_match( '!\[\s*(\w+)\s*\]!', $s, $match ) ) {
+                               $s = preg_replace( '!\[\s*(\w+)\s*\]!', '', $s );
+                               $mtype = trim( strtoupper( $match[1] ) );
+                       } else {
+                               $mtype = MEDIATYPE_UNKNOWN;
                        }
                        }
-                       else $mtype= MEDIATYPE_UNKNOWN;
 
 
-                       $m= explode(' ',$s);
+                       $m = explode( ' ', $s );
 
 
-                       if (!isset($this->mMediaTypes[$mtype])) $this->mMediaTypes[$mtype]= array();
+                       if ( !isset( $this->mMediaTypes[$mtype] ) ) {
+                               $this->mMediaTypes[$mtype] = array();
+                       }
 
 
-                       foreach ($m as $mime) {
-                               $mime= trim($mime);
-                               if (empty($mime)) continue;
+                       foreach ( $m as $mime ) {
+                               $mime = trim( $mime );
+                               if ( empty( $mime ) ) continue;
 
 
-                               $this->mMediaTypes[$mtype][]= $mime;
+                               $this->mMediaTypes[$mtype][] = $mime;
                        }
 
                        }
 
-                       if (sizeof($m)>1) {
-                               $main= $m[0];
-                               for ($i=1; $i<sizeof($m); $i+= 1) {
-                                       $mime= $m[$i];
-                                       $this->mMimeTypeAliases[$mime]= $main;
+                       if ( sizeof( $m ) > 1 ) {
+                               $main = $m[0];
+                               for ( $i=1; $i<sizeof($m); $i += 1 ) {
+                                       $mime = $m[$i];
+                                       $this->mMimeTypeAliases[$mime] = $main;
                                }
                        }
                }
                                }
                        }
                }
@@ -241,14 +300,14 @@ class MimeMagic {
        /** returns a list of file extensions for a given mime type
        * as a space separated string.
        */
        /** returns a list of file extensions for a given mime type
        * as a space separated string.
        */
-       function getExtensionsForType($mime) {
-               $mime= strtolower($mime);
+       function getExtensionsForType( $mime ) {
+               $mime = strtolower( $mime );
 
 
-               $r= @$this->mMimeToExt[$mime];
+               $r = @$this->mMimeToExt[$mime];
 
 
-               if (@!$r and isset($this->mMimeTypeAliases[$mime])) {
-                       $mime= $this->mMimeTypeAliases[$mime];
-                       $r= @$this->mMimeToExt[$mime];
+               if ( @!$r and isset( $this->mMimeTypeAliases[$mime] ) ) {
+                       $mime = $this->mMimeTypeAliases[$mime];
+                       $r = @$this->mMimeToExt[$mime];
                }
 
                return $r;
                }
 
                return $r;
@@ -257,22 +316,22 @@ class MimeMagic {
        /** returns a list of mime types for a given file extension
        * as a space separated string.
        */
        /** returns a list of mime types for a given file extension
        * as a space separated string.
        */
-       function getTypesForExtension($ext) {
-               $ext= strtolower($ext);
+       function getTypesForExtension( $ext ) {
+               $ext = strtolower( $ext );
 
 
-               $r= @$this->mExtToMime[$ext];
+               $r = isset( $this->mExtToMime[$ext] ) ? $this->mExtToMime[$ext] : null;
                return $r;
        }
 
        /** returns a single mime type for a given file extension.
        * This is always the first type from the list returned by getTypesForExtension($ext).
        */
                return $r;
        }
 
        /** returns a single mime type for a given file extension.
        * This is always the first type from the list returned by getTypesForExtension($ext).
        */
-       function guessTypesForExtension($ext) {
-               $m= $this->getTypesForExtension( $ext );
-               if( is_null($m) ) return NULL;
+       function guessTypesForExtension( $ext ) {
+               $m = $this->getTypesForExtension( $ext );
+               if ( is_null( $m ) ) return null;
 
 
-               $m= trim( $m );
-               $m= preg_replace('/\s.*$/','',$m);
+               $m = trim( $m );
+               $m = preg_replace( '/\s.*$/', '', $m );
 
                return $m;
        }
 
                return $m;
        }
@@ -282,17 +341,17 @@ class MimeMagic {
        * returns true if a match was found, NULL if the mime type is unknown,
        * and false if the mime type is known but no matches where found.
        */
        * returns true if a match was found, NULL if the mime type is unknown,
        * and false if the mime type is known but no matches where found.
        */
-       function isMatchingExtension($extension,$mime) {
-               $ext= $this->getExtensionsForType($mime);
+       function isMatchingExtension( $extension, $mime ) {
+               $ext = $this->getExtensionsForType( $mime );
 
 
-               if (!$ext) {
-                       return NULL;  //unknown
+               if ( !$ext ) {
+                       return null;  //unknown
                }
 
                }
 
-               $ext= explode(' ',$ext);
+               $ext = explode( ' ', $ext );
 
 
-               $extension= strtolower($extension);
-               if (in_array($extension,$ext)) {
+               $extension = strtolower( $extension );
+               if ( in_array( $extension, $ext ) ) {
                        return true;
                }
 
                        return true;
                }
 
@@ -330,10 +389,17 @@ class MimeMagic {
         */
        function isRecognizableExtension( $extension ) {
                static $types = array(
         */
        function isRecognizableExtension( $extension ) {
                static $types = array(
+                       // Types recognized by getimagesize()
                        'gif', 'jpeg', 'jpg', 'png', 'swf', 'psd',
                        'bmp', 'tiff', 'tif', 'jpc', 'jp2',
                        'jpx', 'jb2', 'swc', 'iff', 'wbmp',
                        'gif', 'jpeg', 'jpg', 'png', 'swf', 'psd',
                        'bmp', 'tiff', 'tif', 'jpc', 'jp2',
                        'jpx', 'jb2', 'swc', 'iff', 'wbmp',
-                       'xbm', 'djvu'
+                       'xbm',
+
+                       // Formats we recognize magic numbers for
+                       'djvu', 'ogx', 'ogg', 'ogv', 'oga', 'spx', 'mid', 'pdf', 'wmf', 'xcf',
+
+                       // XML formats we sure hope we recognize reliably
+                       'svg',
                );
                return in_array( strtolower( $extension ), $types );
        }
                );
                return in_array( strtolower( $extension ), $types );
        }
@@ -343,146 +409,255 @@ class MimeMagic {
        * but applies additional checks to determine some well known file formats that may be missed
        * or misinterpreter by the default mime detection (namely xml based formats like XHTML or SVG).
        *
        * but applies additional checks to determine some well known file formats that may be missed
        * or misinterpreter by the default mime detection (namely xml based formats like XHTML or SVG).
        *
-       * @param string $file The file to check
-       * @param bool $useExt switch for allowing to use the file extension to guess the mime type. true by default.
+       * @param $file String: the file to check
+       * @param $ext Mixed: the file extension, or true to extract it from the filename.
+       *             Set it to false to ignore the extension.
        *
        * @return string the mime type of $file
        */
        *
        * @return string the mime type of $file
        */
-       function guessMimeType( $file, $useExt=true ) {
-               $fname = 'MimeMagic::guessMimeType';
-               $mime= $this->detectMimeType($file,$useExt);
+       function guessMimeType( $file, $ext = true ) {
+               $mime = $this->doGuessMimeType( $file, $ext );
 
 
+               if( !$mime ) {
+                       wfDebug( __METHOD__.": internal type detection failed for $file (.$ext)...\n" );
+                       $mime = $this->detectMimeType( $file, $ext );
+               }
+
+               if ( isset( $this->mMimeTypeAliases[$mime] ) ) {
+                       $mime = $this->mMimeTypeAliases[$mime];
+               }
+
+               wfDebug(__METHOD__.": final mime type of $file: $mime\n");
+               return $mime;
+       }
+
+       function doGuessMimeType( $file, $ext = true ) {
                // Read a chunk of the file
                // Read a chunk of the file
+               wfSuppressWarnings();
                $f = fopen( $file, "rt" );
                $f = fopen( $file, "rt" );
+               wfRestoreWarnings();
                if( !$f ) return "unknown/unknown";
                $head = fread( $f, 1024 );
                if( !$f ) return "unknown/unknown";
                $head = fread( $f, 1024 );
+               fseek( $f, -65558, SEEK_END );
+               $tail = fread( $f, 65558 ); // 65558 = maximum size of a zip EOCDR
                fclose( $f );
 
                fclose( $f );
 
-               $sub4 =  substr( $head, 0, 4 );
-               if ( $sub4 == "\x01\x00\x09\x00" || $sub4 == "\xd7\xcd\xc6\x9a" ) {
-                       // WMF kill kill kill
-                       // Note that WMF may have a bare header, no magic number.
-                       // The former of the above two checks is theoretically prone to false positives
-                       $mime = "application/x-msmetafile";
-               }
-
-               if (strpos($mime,"text/")===0 || $mime==="application/xml") {
-
-                       $xml_type= NULL;
-                       $script_type= NULL;
+               // Hardcode a few magic number checks...
+               $headers = array(
+                       // Multimedia...
+                       'MThd'             => 'audio/midi',
+                       'OggS'             => 'application/ogg',
 
 
-                       /*
-                       * look for XML formats (XHTML and SVG)
-                       */
-                       if ($mime==="text/sgml" ||
-                           $mime==="text/plain" ||
-                           $mime==="text/html" ||
-                           $mime==="text/xml" ||
-                           $mime==="application/xml") {
-
-                               if (substr($head,0,5)=="<?xml") $xml_type= "ASCII";
-                               elseif (substr($head,0,8)=="\xef\xbb\xbf<?xml") $xml_type= "UTF-8";
-                               elseif (substr($head,0,10)=="\xfe\xff\x00<\x00?\x00x\x00m\x00l") $xml_type= "UTF-16BE";
-                               elseif (substr($head,0,10)=="\xff\xfe<\x00?\x00x\x00m\x00l\x00") $xml_type= "UTF-16LE";
-
-                               if ($xml_type) {
-                                       if ($xml_type!=="UTF-8" && $xml_type!=="ASCII") $head= iconv($xml_type,"ASCII//IGNORE",$head);
-
-                                       $match= array();
-                                       $doctype= "";
-                                       $tag= "";
-
-                                       if (preg_match('%<!DOCTYPE\s+[\w-]+\s+PUBLIC\s+["'."'".'"](.*?)["'."'".'"].*>%sim',$head,$match)) $doctype= $match[1];
-                                       if (preg_match('%<(\w+).*>%sim',$head,$match)) $tag= $match[1];
-
-                                       #print "<br>ANALYSING $file ($mime): doctype= $doctype; tag= $tag<br>";
+                       // Image formats...
+                       // Note that WMF may have a bare header, no magic number.
+                       "\x01\x00\x09\x00" => 'application/x-msmetafile', // Possibly prone to false positives?
+                       "\xd7\xcd\xc6\x9a" => 'application/x-msmetafile',
+                       '%PDF'             => 'application/pdf',
+                       'gimp xcf'         => 'image/x-xcf',
+
+                       // Some forbidden fruit...
+                       'MZ'               => 'application/octet-stream', // DOS/Windows executable
+                       "\xca\xfe\xba\xbe" => 'application/octet-stream', // Mach-O binary
+                       "\x7fELF"          => 'application/octet-stream', // ELF binary
+               );
 
 
-                                       if (strpos($doctype,"-//W3C//DTD SVG")===0) $mime= "image/svg";
-                                       elseif ($tag==="svg") $mime= "image/svg";
-                                       elseif (strpos($doctype,"-//W3C//DTD XHTML")===0) $mime= "text/html";
-                                       elseif ($tag==="html") $mime= "text/html";
-                               }
+               foreach( $headers as $magic => $candidate ) {
+                       if( strncmp( $head, $magic, strlen( $magic ) ) == 0 ) {
+                               wfDebug( __METHOD__ . ": magic header in $file recognized as $candidate\n" );
+                               return $candidate;
                        }
                        }
+               }
 
 
-                       /*
-                       * look for shell scripts
-                       */
-                       if (!$xml_type) {
-                               $script_type= NULL;
-
-                               #detect by shebang
-                               if (substr($head,0,2)=="#!") $script_type= "ASCII";
-                               elseif (substr($head,0,5)=="\xef\xbb\xbf#!") $script_type= "UTF-8";
-                               elseif (substr($head,0,7)=="\xfe\xff\x00#\x00!") $script_type= "UTF-16BE";
-                               elseif (substr($head,0,7)=="\xff\xfe#\x00!") $script_type= "UTF-16LE";
+               /*
+                * Look for PHP.  Check for this before HTML/XML...  Warning: this is a
+                * heuristic, and won't match a file with a lot of non-PHP before.  It
+                * will also match text files which could be PHP. :)
+                *
+                * FIXME: For this reason, the check is probably useless -- an attacker
+                * could almost certainly just pad the file with a lot of nonsense to
+                * circumvent the check in any case where it would be a security
+                * problem.  On the other hand, it causes harmful false positives (bug
+                * 16583).  The heuristic has been cut down to exclude three-character
+                * strings like "<? ", but should it be axed completely?
+                */
+               if( ( strpos( $head, '<?php' ) !== false ) ||
+
+                   ( strpos( $head, "<\x00?\x00p\x00h\x00p" ) !== false ) ||
+                   ( strpos( $head, "<\x00?\x00 " ) !== false ) ||
+                   ( strpos( $head, "<\x00?\x00\n" ) !== false ) ||
+                   ( strpos( $head, "<\x00?\x00\t" ) !== false ) ||
+                   ( strpos( $head, "<\x00?\x00=" ) !== false ) ) {
+
+                       wfDebug( __METHOD__ . ": recognized $file as application/x-php\n" );
+                       return "application/x-php";
+               }
 
 
-                               if ($script_type) {
-                                       if ($script_type!=="UTF-8" && $script_type!=="ASCII") $head= iconv($script_type,"ASCII//IGNORE",$head);
+               /*
+                * look for XML formats (XHTML and SVG)
+                */
+               $xml = new XmlTypeCheck( $file );
+               if( $xml->wellFormed ) {
+                       global $wgXMLMimeTypes;
+                       if( isset( $wgXMLMimeTypes[$xml->getRootElement()] ) ) {
+                               return $wgXMLMimeTypes[$xml->getRootElement()];
+                       } else {
+                               return 'application/xml';
+                       }
+               }
 
 
-                                       $match= array();
-                                       $prog= "";
+               /*
+                * look for shell scripts
+                */
+               $script_type = null;
+
+               # detect by shebang
+               if ( substr( $head, 0, 2) == "#!" ) {
+                       $script_type = "ASCII";
+               } elseif ( substr( $head, 0, 5) == "\xef\xbb\xbf#!" ) {
+                       $script_type = "UTF-8";
+               } elseif ( substr( $head, 0, 7) == "\xfe\xff\x00#\x00!" ) {
+                       $script_type = "UTF-16BE";
+               } elseif ( substr( $head, 0, 7 ) == "\xff\xfe#\x00!" ) {
+                       $script_type= "UTF-16LE";
+               }
 
 
-                                       if (preg_match('%/?([^\s]+/)(w+)%sim',$head,$match)) {
-                                               $script= $match[2]; // FIXME: $script variable not used; should this be "$prog = $match[2];" instead?
+               if ( $script_type ) {
+                       if ( $script_type !== "UTF-8" && $script_type !== "ASCII") {
+                               // Quick and dirty fold down to ASCII!
+                               $pack = array( 'UTF-16BE' => 'n*', 'UTF-16LE' => 'v*' );
+                               $chars = unpack( $pack[$script_type], substr( $head, 2 ) );
+                               $head = '';
+                               foreach( $chars as $codepoint ) {
+                                       if( $codepoint < 128 ) {
+                                               $head .= chr( $codepoint );
+                                       } else {
+                                               $head .= '?';
                                        }
                                        }
-
-                                       $mime= "application/x-$prog";
                                }
                        }
 
                                }
                        }
 
-                       /*
-                       * look for PHP
-                       */
-                       if( !$xml_type && !$script_type ) {
+                       $match = array();
 
 
-                               if( ( strpos( $head, '<?php' ) !== false ) ||
-                                   ( strpos( $head, '<? ' ) !== false ) ||
-                                   ( strpos( $head, "<?\n" ) !== false ) ||
-                                   ( strpos( $head, "<?\t" ) !== false ) ||
-                                   ( strpos( $head, "<?=" ) !== false ) ||
+                       if ( preg_match( '%/?([^\s]+/)(\w+)%', $head, $match ) ) {
+                               $mime = "application/x-{$match[2]}";
+                               wfDebug( __METHOD__.": shell script recognized as $mime\n" );
+                               return $mime;
+                       }
+               }
 
 
-                                   ( strpos( $head, "<\x00?\x00p\x00h\x00p" ) !== false ) ||
-                                   ( strpos( $head, "<\x00?\x00 " ) !== false ) ||
-                                   ( strpos( $head, "<\x00?\x00\n" ) !== false ) ||
-                                   ( strpos( $head, "<\x00?\x00\t" ) !== false ) ||
-                                   ( strpos( $head, "<\x00?\x00=" ) !== false ) ) {
+               // Check for ZIP (before getimagesize)
+               if ( strpos( $tail, "PK\x05\x06" ) !== false ) {
+                       wfDebug( __METHOD__.": ZIP header present at end of $file\n" );
+                       return $this->detectZipType( $head, $ext );
+               }
 
 
-                                       $mime= "application/x-php";
-                               }
-                       }
+               wfSuppressWarnings();
+               $gis = getimagesize( $file );
+               wfRestoreWarnings();
 
 
+               if( $gis && isset( $gis['mime'] ) ) {
+                       $mime = $gis['mime'];
+                       wfDebug( __METHOD__.": getimagesize detected $file as $mime\n" );
+                       return $mime;
                }
 
                }
 
-               if (isset($this->mMimeTypeAliases[$mime])) $mime= $this->mMimeTypeAliases[$mime];
+               // Also test DjVu
+               $deja = new DjVuImage( $file );
+               if( $deja->isValid() ) {
+                       wfDebug( __METHOD__.": detected $file as image/vnd.djvu\n" );
+                       return 'image/vnd.djvu';
+               }
 
 
-               wfDebug("$fname: final mime type of $file: $mime\n");
+               return false;
+       }
+       
+       /**
+        * Detect application-specific file type of a given ZIP file from its
+        * header data.  Currently works for OpenDocument types...
+        * If can't tell, returns 'application/zip'.
+        *
+        * @param $header String: some reasonably-sized chunk of file header
+        * @param $ext Mixed: the file extension, or true to extract it from the filename.
+        *             Set it to false to ignore the extension.
+        *
+        * @return string
+        */
+       function detectZipType( $header, $ext = false ) {
+               $mime = 'application/zip';
+               $opendocTypes = array(
+                       'chart-template',
+                       'chart',
+                       'formula-template',
+                       'formula',
+                       'graphics-template',
+                       'graphics',
+                       'image-template',
+                       'image',
+                       'presentation-template',
+                       'presentation',
+                       'spreadsheet-template',
+                       'spreadsheet',
+                       'text-template',
+                       'text-master',
+                       'text-web',
+                       'text' );
+
+               // http://lists.oasis-open.org/archives/office/200505/msg00006.html
+               $types = '(?:' . implode( '|', $opendocTypes ) . ')';
+               $opendocRegex = "/^mimetype(application\/vnd\.oasis\.opendocument\.$types)/";
+               wfDebug( __METHOD__.": $opendocRegex\n" );
+
+               $openxmlRegex = "/^\[Content_Types\].xml/";
+               
+               if( preg_match( $opendocRegex, substr( $header, 30 ), $matches ) ) {
+                       $mime = $matches[1];
+                       wfDebug( __METHOD__.": detected $mime from ZIP archive\n" );
+               } elseif( preg_match( $openxmlRegex, substr( $header, 30 ), $matches ) ) {
+                       $mime = "application/x-opc+zip";
+                       if( $ext !== true && $ext !== false ) {
+                               /** This is the mode used by getPropsFromPath
+                               * These mime's are stored in the database, where we don't really want
+                               * x-opc+zip, because we use it only for internal purposes
+                               */
+                               if( $this->isMatchingExtension( $ext, $mime) ) {
+                                       /* A known file extension for an OPC file,
+                                       * find the proper mime type for that file extension */
+                                       $mime = $this->guessTypesForExtension( $ext );
+                               } else {
+                                       $mime = 'application/zip';
+                               }
+                               
+                       }
+                       wfDebug( __METHOD__.": detected an Open Packaging Conventions archive: $mime\n" );
+               } else {
+                       wfDebug( __METHOD__.": unable to identify type of ZIP archive\n" );
+               }
                return $mime;
        }
 
        /** Internal mime type detection, please use guessMimeType() for application code instead.
        * Detection is done using an external program, if $wgMimeDetectorCommand is set.
        * Otherwise, the fileinfo extension and mime_content_type are tried (in this order), if they are available.
                return $mime;
        }
 
        /** Internal mime type detection, please use guessMimeType() for application code instead.
        * Detection is done using an external program, if $wgMimeDetectorCommand is set.
        * Otherwise, the fileinfo extension and mime_content_type are tried (in this order), if they are available.
-       * If the dections fails and $useExt is true, the mime type is guessed from the file extension, using guessTypesForExtension.
+       * If the dections fails and $ext is not false, the mime type is guessed from the file extension, using
+       * guessTypesForExtension.
        * If the mime type is still unknown, getimagesize is used to detect the mime type if the file is an image.
        * If no mime type can be determined, this function returns "unknown/unknown".
        *
        * If the mime type is still unknown, getimagesize is used to detect the mime type if the file is an image.
        * If no mime type can be determined, this function returns "unknown/unknown".
        *
-       * @param string $file The file to check
-       * @param bool $useExt switch for allowing to use the file extension to guess the mime type. true by default.
+       * @param $file String: the file to check
+       * @param $ext Mixed: the file extension, or true to extract it from the filename.
+       *             Set it to false to ignore the extension.
        *
        * @return string the mime type of $file
        * @access private
        */
        *
        * @return string the mime type of $file
        * @access private
        */
-       function detectMimeType( $file, $useExt=true ) {
-               $fname = 'MimeMagic::detectMimeType';
-
+       function detectMimeType( $file, $ext = true ) {
                global $wgMimeDetectorCommand;
 
                global $wgMimeDetectorCommand;
 
-               $m= NULL;
-               if ($wgMimeDetectorCommand) {
-                       $fn= wfEscapeShellArg($file);
-                       $m= `$wgMimeDetectorCommand $fn`;
-               }
-               else if (function_exists("finfo_open") && function_exists("finfo_file")) {
+               $m = null;
+               if ( $wgMimeDetectorCommand ) {
+                       $fn = wfEscapeShellArg( $file );
+                       $m = `$wgMimeDetectorCommand $fn`;
+               } elseif ( function_exists( "finfo_open" ) && function_exists( "finfo_file" ) ) {
 
                        # This required the fileinfo extension by PECL,
                        # see http://pecl.php.net/package/fileinfo
 
                        # This required the fileinfo extension by PECL,
                        # see http://pecl.php.net/package/fileinfo
@@ -497,13 +672,12 @@ class MimeMagic {
                        $mime_magic_resource = finfo_open(FILEINFO_MIME); /* return mime type ala mimetype extension */
 
                        if ($mime_magic_resource) {
                        $mime_magic_resource = finfo_open(FILEINFO_MIME); /* return mime type ala mimetype extension */
 
                        if ($mime_magic_resource) {
-                               $m= finfo_file($mime_magic_resource, $file);
-
-                               finfo_close($mime_magic_resource);
+                               $m = finfo_file( $mime_magic_resource, $file );
+                               finfo_close( $mime_magic_resource );
+                       } else {
+                               wfDebug( __METHOD__.": finfo_open failed on ".FILEINFO_MIME."!\n" );
                        }
                        }
-                       else wfDebug("$fname: finfo_open failed on ".FILEINFO_MIME."!\n");
-               }
-               else if (function_exists("mime_content_type")) {
+               } elseif ( function_exists( "mime_content_type" ) ) {
 
                        # NOTE: this function is available since PHP 4.3.0, but only if
                        # PHP was compiled with --with-mime-magic or, before 4.3.2, with --enable-mime-magic.
 
                        # NOTE: this function is available since PHP 4.3.0, but only if
                        # PHP was compiled with --with-mime-magic or, before 4.3.2, with --enable-mime-magic.
@@ -514,93 +688,44 @@ class MimeMagic {
                        # Also note that this has been DEPRECATED in favor of the fileinfo extension by PECL, see above.
                        # see http://www.php.net/manual/en/ref.mime-magic.php for details.
 
                        # Also note that this has been DEPRECATED in favor of the fileinfo extension by PECL, see above.
                        # see http://www.php.net/manual/en/ref.mime-magic.php for details.
 
-                       $m= mime_content_type($file);
-
-                       if ( $m == 'text/plain' ) {
-                               // mime_content_type sometimes considers DJVU files to be text/plain.
-                               $deja = new DjVuImage( $file );
-                               if( $deja->isValid() ) {
-                                       wfDebug("$fname: (re)detected $file as image/vnd.djvu\n");
-                                       $m = 'image/vnd.djvu';
-                               }
-                       }
-               }
-               else wfDebug("$fname: no magic mime detector found!\n");
-
-               if ($m) {
-                       #normalize
-                       $m= preg_replace('![;, ].*$!','',$m); #strip charset, etc
-                       $m= trim($m);
-                       $m= strtolower($m);
-
-                       if (strpos($m,'unknown')!==false) $m= NULL;
-                       else {
-                               wfDebug("$fname: magic mime type of $file: $m\n");
-                               return $m;
-                       }
+                       $m = mime_content_type($file);
+               } else {
+                       wfDebug( __METHOD__.": no magic mime detector found!\n" );
                }
 
                }
 
-               #if still not known, use getimagesize to find out the type of image
-               #TODO: skip things that do not have a well-known image extension? Would that be safe?
-               wfSuppressWarnings();
-               $gis = getimagesize( $file );
-               wfRestoreWarnings();
-
-               $notAnImage= false;
-
-               if ($gis && is_array($gis) && $gis[2]) {
-                       switch ($gis[2]) {
-                               case IMAGETYPE_GIF: $m= "image/gif"; break;
-                               case IMAGETYPE_JPEG: $m= "image/jpeg"; break;
-                               case IMAGETYPE_PNG: $m= "image/png"; break;
-                               case IMAGETYPE_SWF: $m= "application/x-shockwave-flash"; break;
-                               case IMAGETYPE_PSD: $m= "application/photoshop"; break;
-                               case IMAGETYPE_BMP: $m= "image/bmp"; break;
-                               case IMAGETYPE_TIFF_II: $m= "image/tiff"; break;
-                               case IMAGETYPE_TIFF_MM: $m= "image/tiff"; break;
-                               case IMAGETYPE_JPC: $m= "image"; break;
-                               case IMAGETYPE_JP2: $m= "image/jpeg2000"; break;
-                               case IMAGETYPE_JPX: $m= "image/jpeg2000"; break;
-                               case IMAGETYPE_JB2: $m= "image"; break;
-                               case IMAGETYPE_SWC: $m= "application/x-shockwave-flash"; break;
-                               case IMAGETYPE_IFF: $m= "image/vnd.xiff"; break;
-                               case IMAGETYPE_WBMP: $m= "image/vnd.wap.wbmp"; break;
-                               case IMAGETYPE_XBM: $m= "image/x-xbitmap"; break;
-                       }
+               if ( $m ) {
+                       # normalize
+                       $m = preg_replace( '![;, ].*$!', '', $m ); #strip charset, etc
+                       $m = trim( $m );
+                       $m = strtolower( $m );
 
 
-                       if ($m) {
-                               wfDebug("$fname: image mime type of $file: $m\n");
+                       if ( strpos( $m, 'unknown' ) !== false ) {
+                               $m = null;
+                       } else {
+                               wfDebug( __METHOD__.": magic mime type of $file: $m\n" );
                                return $m;
                        }
                                return $m;
                        }
-                       else $notAnImage= true;
-               } else {
-                       // Also test DjVu
-                       $deja = new DjVuImage( $file );
-                       if( $deja->isValid() ) {
-                               wfDebug("$fname: detected $file as image/vnd.djvu\n");
-                               return 'image/vnd.djvu';
-                       }
                }
 
                }
 
-               #if desired, look at extension as a fallback.
-               if ($useExt) {
+               # if desired, look at extension as a fallback.
+               if ( $ext === true ) {
                        $i = strrpos( $file, '.' );
                        $i = strrpos( $file, '.' );
-                       $e= strtolower( $i ? substr( $file, $i + 1 ) : '' );
-
-                       $m= $this->guessTypesForExtension($e);
-
-                       #TODO: if $notAnImage is set, do not trust the file extension if
-                       # the results is one of the image types that should have been recognized
-                       # by getimagesize
-
-                       if ($m) {
-                               wfDebug("$fname: extension mime type of $file: $m\n");
-                               return $m;
+                       $ext = strtolower( $i ? substr( $file, $i + 1 ) : '' );
+               }
+               if ( $ext ) {
+                       if( $this->isRecognizableExtension( $ext ) ) {
+                               wfDebug( __METHOD__. ": refusing to guess mime type for .$ext file, we should have recognized it\n" );
+                       } else {
+                               $m = $this->guessTypesForExtension( $ext );
+                               if ( $m ) {
+                                       wfDebug( __METHOD__.": extension mime type of $file: $m\n" );
+                                       return $m;
+                               }
                        }
                }
 
                #unknown type
                        }
                }
 
                #unknown type
-               wfDebug("$fname: failed to guess mime type for $file!\n");
+               wfDebug( __METHOD__.": failed to guess mime type for $file!\n" );
                return "unknown/unknown";
        }
 
                return "unknown/unknown";
        }
 
@@ -614,67 +739,67 @@ class MimeMagic {
        * @todo analyse file if need be
        * @todo look at multiple extension, separately and together.
        *
        * @todo analyse file if need be
        * @todo look at multiple extension, separately and together.
        *
-       * @param string $path full path to the image file, in case we have to look at the contents
+       * @param $path String: full path to the image file, in case we have to look at the contents
        *        (if null, only the mime type is used to determine the media type code).
        *        (if null, only the mime type is used to determine the media type code).
-       * @param string $mime mime type. If null it will be guessed using guessMimeType.
+       * @param $mime String: mime type. If null it will be guessed using guessMimeType.
        *
        * @return (int?string?) a value to be used with the MEDIATYPE_xxx constants.
        */
        *
        * @return (int?string?) a value to be used with the MEDIATYPE_xxx constants.
        */
-       function getMediaType($path=NULL,$mime=NULL) {
+       function getMediaType( $path = null, $mime = null ) {
                if( !$mime && !$path ) return MEDIATYPE_UNKNOWN;
 
                if( !$mime && !$path ) return MEDIATYPE_UNKNOWN;
 
-               #if mime type is unknown, guess it
-               if( !$mime ) $mime= $this->guessMimeType($path,false);
+               # If mime type is unknown, guess it
+               if( !$mime ) $mime = $this->guessMimeType( $path, false );
 
 
-               #special code for ogg - detect if it's video (theora),
-               #else label it as sound.
-               if( $mime=="application/ogg" && file_exists($path) ) {
+               # Special code for ogg - detect if it's video (theora),
+               # else label it as sound.
+               if( $mime == "application/ogg" && file_exists( $path ) ) {
 
                        // Read a chunk of the file
                        $f = fopen( $path, "rt" );
 
                        // Read a chunk of the file
                        $f = fopen( $path, "rt" );
-                       if( !$f ) return MEDIATYPE_UNKNOWN;
+                       if ( !$f ) return MEDIATYPE_UNKNOWN;
                        $head = fread( $f, 256 );
                        fclose( $f );
 
                        $head = fread( $f, 256 );
                        fclose( $f );
 
-                       $head= strtolower( $head );
+                       $head = strtolower( $head );
 
 
-                       #This is an UGLY HACK, file should be parsed correctly
-                       if( strpos($head,'theora')!==false ) return MEDIATYPE_VIDEO;
-                       elseif( strpos($head,'vorbis')!==false ) return MEDIATYPE_AUDIO;
-                       elseif( strpos($head,'flac')!==false ) return MEDIATYPE_AUDIO;
-                       elseif( strpos($head,'speex')!==false ) return MEDIATYPE_AUDIO;
+                       # This is an UGLY HACK, file should be parsed correctly
+                       if ( strpos( $head, 'theora' ) !== false ) return MEDIATYPE_VIDEO;
+                       elseif ( strpos( $head, 'vorbis' ) !== false ) return MEDIATYPE_AUDIO;
+                       elseif ( strpos( $head, 'flac' ) !== false ) return MEDIATYPE_AUDIO;
+                       elseif ( strpos( $head, 'speex' ) !== false ) return MEDIATYPE_AUDIO;
                        else return MEDIATYPE_MULTIMEDIA;
                }
 
                        else return MEDIATYPE_MULTIMEDIA;
                }
 
-               #check for entry for full mime type
+               # check for entry for full mime type
                if( $mime ) {
                if( $mime ) {
-                       $type= $this->findMediaType($mime);
-                       if( $type!==MEDIATYPE_UNKNOWN ) return $type;
+                       $type = $this->findMediaType( $mime );
+                       if( $type !== MEDIATYPE_UNKNOWN ) return $type;
                }
 
                }
 
-               #check for entry for file extension
-               $e= NULL;
-               if( $path ) {
+               # Check for entry for file extension
+               $e = null;
+               if ( $path ) {
                        $i = strrpos( $path, '.' );
                        $i = strrpos( $path, '.' );
-                       $e= strtolower( $i ? substr( $path, $i + 1 ) : '' );
+                       $e = strtolower( $i ? substr( $path, $i + 1 ) : '' );
 
 
-                       #TODO: look at multi-extension if this fails, parse from full path
+                       # TODO: look at multi-extension if this fails, parse from full path
 
 
-                       $type= $this->findMediaType('.'.$e);
-                       if( $type!==MEDIATYPE_UNKNOWN ) return $type;
+                       $type = $this->findMediaType( '.' . $e );
+                       if ( $type !== MEDIATYPE_UNKNOWN ) return $type;
                }
 
                }
 
-               #check major mime type
+               # Check major mime type
                if( $mime ) {
                if( $mime ) {
-                       $i= strpos($mime,'/');
+                       $i = strpos( $mime, '/' );
                        if( $i !== false ) {
                        if( $i !== false ) {
-                               $major= substr($mime,0,$i);
-                               $type= $this->findMediaType($major);
-                               if( $type!==MEDIATYPE_UNKNOWN ) return $type;
+                               $major = substr( $mime, 0, $i );
+                               $type = $this->findMediaType( $major );
+                               if( $type !== MEDIATYPE_UNKNOWN ) return $type;
                        }
                }
 
                        }
                }
 
-               if( !$type ) $type= MEDIATYPE_UNKNOWN;
+               if( !$type ) $type = MEDIATYPE_UNKNOWN;
 
                return $type;
        }
 
                return $type;
        }
@@ -686,30 +811,52 @@ class MimeMagic {
        * This funktion relies on the mapping defined by $this->mMediaTypes
        * @access private
        */
        * This funktion relies on the mapping defined by $this->mMediaTypes
        * @access private
        */
-       function findMediaType($extMime) {
-
-               if (strpos($extMime,'.')===0) { #if it's an extension, look up the mime types
-                       $m= $this->getTypesForExtension(substr($extMime,1));
-                       if (!$m) return MEDIATYPE_UNKNOWN;
+       function findMediaType( $extMime ) {
+               if ( strpos( $extMime, '.' ) === 0 ) { #if it's an extension, look up the mime types
+                       $m = $this->getTypesForExtension( substr( $extMime, 1 ) );
+                       if ( !$m ) return MEDIATYPE_UNKNOWN;
 
 
-                       $m= explode(' ',$m);
-               }
-               else { #normalize mime type
-                       if (isset($this->mMimeTypeAliases[$extMime])) {
-                               $extMime= $this->mMimeTypeAliases[$extMime];
+                       $m = explode( ' ', $m );
+               } else {
+                       # Normalize mime type
+                       if ( isset( $this->mMimeTypeAliases[$extMime] ) ) {
+                               $extMime = $this->mMimeTypeAliases[$extMime];
                        }
 
                        }
 
-                       $m= array($extMime);
+                       $m = array($extMime);
                }
 
                }
 
-               foreach ($m as $mime) {
-                       foreach ($this->mMediaTypes as $type => $codes) {
-                               if (in_array($mime,$codes,true)) return $type;
+               foreach ( $m as $mime ) {
+                       foreach ( $this->mMediaTypes as $type => $codes ) {
+                               if ( in_array($mime, $codes, true ) ) {
+                                       return $type;
+                               }
                        }
                }
 
                return MEDIATYPE_UNKNOWN;
        }
                        }
                }
 
                return MEDIATYPE_UNKNOWN;
        }
-}
 
 
-?>
+       /**
+        * Get the MIME types that various versions of Internet Explorer would 
+        * detect from a chunk of the content.
+        *
+        * @param $fileName String: the file name (unused at present)
+        * @param $chunk String: the first 256 bytes of the file
+        * @param $proposed String: the MIME type proposed by the server
+        */
+       public function getIEMimeTypes( $fileName, $chunk, $proposed ) {
+               $ca = $this->getIEContentAnalyzer();
+               return $ca->getRealMimesFromData( $fileName, $chunk, $proposed );
+       }
+
+       /**
+        * Get a cached instance of IEContentAnalyzer
+        */
+       protected function getIEContentAnalyzer() {
+               if ( is_null( $this->mIEAnalyzer ) ) {
+                       $this->mIEAnalyzer = new IEContentAnalyzer;
+               }
+               return $this->mIEAnalyzer;
+       }
+}