(bug 26130) Revert changes to WebStart.php in r72349, which turn out to have been...
[lhc/web/wiklou.git] / includes / MimeMagic.php
index 813db38..7d7fedd 100644 (file)
@@ -402,6 +402,7 @@ class MimeMagic {
                        // Formats we recognize magic numbers for
                        'djvu', 'ogx', 'ogg', 'ogv', 'oga', 'spx',
                        'mid', 'pdf', 'wmf', 'xcf', 'webm', 'mkv', 'mka',
+                       'webp',
 
                        // XML formats we sure hope we recognize reliably
                        'svg',
@@ -409,18 +410,73 @@ class MimeMagic {
                return in_array( strtolower( $extension ), $types );
        }
 
+       /** improves a mime type using the file extension. Some file formats are very generic,
+       * so their mime type is not very meaningful. A more useful mime type can be derived 
+       * by looking at the file extension. Typically, this method would be called on the 
+       * result of guessMimeType().
+       * 
+       * Currently, this method does the following:
+       *
+       * If $mime is "unknown/unknown" and isRecognizableExtension( $ext ) returns false,
+       * return the result of guessTypesForExtension($ext). 
+       *
+       * If $mime is "application/x-opc+zip" and isMatchingExtension( $ext, $mime )
+       * gives true, return the result of guessTypesForExtension($ext). 
+       *
+       * @param $mime String: the mime type, typically guessed from a file's content.
+       * @param $ext String: the file extension, as taken from the file name
+       *
+       * @return string the mime type
+       */
+       function improveTypeFromExtension( $mime, $ext ) {
+               if ( $mime === "unknown/unknown" ) {
+                       if( $this->isRecognizableExtension( $ext ) ) {
+                               wfDebug( __METHOD__. ": refusing to guess mime type for .$ext file, " .
+                                       "we should have recognized it\n" );
+                       } else {
+                               /* Not something we can detect, so simply 
+                               * trust the file extension */
+                               $mime = $this->guessTypesForExtension( $ext );
+                       }
+               }
+               else if ( $mime === "application/x-opc+zip" ) {
+                       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 {
+                               wfDebug( __METHOD__. ": refusing to guess better type for $mime file, " . 
+                                       ".$ext is not a known OPC extension.\n" );
+                               $mime = "application/zip";
+                       }
+               }
+
+               if ( isset( $this->mMimeTypeAliases[$mime] ) ) {
+                       $mime = $this->mMimeTypeAliases[$mime];
+               }
+
+               wfDebug(__METHOD__.": improved mime type for .$ext: $mime\n");
+               return $mime;
+       }
 
        /** mime type detection. This uses detectMimeType to detect the mime type of the file,
        * 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).
+       * or misinterpreter by the default mime detection (namely XML based formats like XHTML or SVG,
+       * as well as ZIP based formats like OPC/ODF files).
        *
        * @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.
+       * @param $ext Mixed: the file extension, or true (default) to extract it from the filename.
+       *             Set it to false to ignore the extension. DEPRECATED! Set to false, use 
+       *             improveTypeFromExtension($mime, $ext) later to improve mime type.
        *
        * @return string the mime type of $file
        */
        function guessMimeType( $file, $ext = true ) {
+               if( $ext ) { # TODO: make $ext default to false. Or better, remove it.
+                       wfDebug( __METHOD__.": WARNING: use of the \$ext parameter is deprecated. " .
+                               "Use improveTypeFromExtension(\$mime, \$ext) instead.\n" );
+               }
+
                $mime = $this->doGuessMimeType( $file, $ext );
 
                if( !$mime ) {
@@ -432,11 +488,11 @@ class MimeMagic {
                        $mime = $this->mMimeTypeAliases[$mime];
                }
 
-               wfDebug(__METHOD__.": final mime type of $file: $mime\n");
+               wfDebug(__METHOD__.": guessed mime type of $file: $mime\n");
                return $mime;
        }
 
-       function doGuessMimeType( $file, $ext = true ) {
+       private function doGuessMimeType( $file, $ext ) { # TODO: remove $ext param
                // Read a chunk of the file
                wfSuppressWarnings();
                $f = fopen( $file, "rt" );
@@ -447,6 +503,8 @@ class MimeMagic {
                $tail = fread( $f, 65558 ); // 65558 = maximum size of a zip EOCDR
                fclose( $f );
 
+               wfDebug( __METHOD__ . ": analyzing head and tail of $file for magic numbers.\n" );
+
                // Hardcode a few magic number checks...
                $headers = array(
                        // Multimedia...
@@ -491,6 +549,12 @@ class MimeMagic {
                        return "unknown/unknown";
                }
 
+               /* Look for WebP */
+               if( strncmp( $head, "RIFF", 4 ) == 0 && strncmp( substr( $head, 8, 8), "WEBPVP8 ", 8 ) == 0 ) {
+                       wfDebug( __METHOD__ . ": recognized file as image/webp\n" );
+                       return "image/webp";
+               }
+
                /*
                 * 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
@@ -602,11 +666,17 @@ class MimeMagic {
         * @param $header String: some reasonably-sized chunk of file header
         * @param $tail   String: the tail of the file
         * @param $ext Mixed: the file extension, or true to extract it from the filename.
-        *             Set it to false to ignore the extension.
+        *             Set it to false (default) to ignore the extension. DEPRECATED! Set to false, 
+        *             use improveTypeFromExtension($mime, $ext) later to improve mime type.
         *
         * @return string
         */
        function detectZipType( $header, $tail = null, $ext = false ) {
+               if( $ext ) { # TODO: remove $ext param
+                       wfDebug( __METHOD__.": WARNING: use of the \$ext parameter is deprecated. " .
+                               "Use improveTypeFromExtension(\$mime, \$ext) instead.\n" );
+               }
+
                $mime = 'application/zip';
                $opendocTypes = array(
                        'chart-template',
@@ -637,7 +707,8 @@ class MimeMagic {
                        wfDebug( __METHOD__.": detected $mime from ZIP archive\n" );
                } elseif( preg_match( $openxmlRegex, substr( $header, 30 ) ) ) {
                        $mime = "application/x-opc+zip";
-                       if( $ext !== true && $ext !== false ) {
+                       # TODO: remove the block below, as soon as improveTypeFromExtension is used everywhere 
+                       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
@@ -695,15 +766,20 @@ class MimeMagic {
        * If no mime type can be determined, this function returns "unknown/unknown".
        *
        * @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.
+       * @param $ext Mixed: the file extension, or true (default) to extract it from the filename.
+       *             Set it to false to ignore the extension. DEPRECATED! Set to false, use 
+       *             improveTypeFromExtension($mime, $ext) later to improve mime type.
        *
        * @return string the mime type of $file
        * @access private
        */
-       function detectMimeType( $file, $ext = true ) {
+       private function detectMimeType( $file, $ext = true ) {
                global $wgMimeDetectorCommand;
 
+               if( $ext ) { # TODO:  make $ext default to false. Or better, remove it.
+                       wfDebug( __METHOD__.": WARNING: use of the \$ext parameter is deprecated. Use improveTypeFromExtension(\$mime, \$ext) instead.\n" );
+               }
+
                $m = null;
                if ( $wgMimeDetectorCommand ) {
                        $fn = wfEscapeShellArg( $file );
@@ -829,7 +905,6 @@ class MimeMagic {
                }
 
                # Check for entry for file extension
-               $e = null;
                if ( $path ) {
                        $i = strrpos( $path, '.' );
                        $e = strtolower( $i ? substr( $path, $i + 1 ) : '' );