jenkins-bot has submitted this change and it was merged.

Change subject: Improve MIME detection in FileBackend
......................................................................


Improve MIME detection in FileBackend

The content type detector will now inspect the file contents
to better handle extensionless files.

Also dependency inject the callback and make the default one
use FileInfo.

Change-Id: Iad59bf6c6a416b706f976a4c425763fd30e2debb
---
M includes/filebackend/FileBackendGroup.php
M includes/filebackend/FileBackendStore.php
M tests/phpunit/includes/filebackend/FileBackendTest.php
3 files changed, 74 insertions(+), 6 deletions(-)

Approvals:
  Gilles: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/includes/filebackend/FileBackendGroup.php 
b/includes/filebackend/FileBackendGroup.php
index b6ddbad..c043106 100644
--- a/includes/filebackend/FileBackendGroup.php
+++ b/includes/filebackend/FileBackendGroup.php
@@ -166,6 +166,7 @@
                                ? FileJournal::factory( $config['fileJournal'], 
$name )
                                : FileJournal::factory( array( 'class' => 
'NullFileJournal' ), $name );
                        $config['wanCache'] = ObjectCache::getMainWANInstance();
+                       $config['mimeCallback'] = array( $this, 
'guessMimeInternal' );
 
                        $this->backends[$name]['instance'] = new $class( 
$config );
                }
@@ -203,4 +204,27 @@
 
                return null;
        }
+
+       /**
+        * @param string $storagePath
+        * @param string|null $content
+        * @param string|null $fsPath
+        * @return string
+        * @since 1.27
+        */
+       public function guessMimeInternal( $storagePath, $content, $fsPath ) {
+               $magic = MimeMagic::singleton();
+               // Trust the extension of the storage path (caller must 
validate)
+               $ext = FileBackend::extensionFromPath( $storagePath );
+               $type = $magic->guessTypesForExtension( $ext );
+               // For files without a valid extension (or one at all), inspect 
the contents
+               if ( !$type && $fsPath ) {
+                       $type = $magic->guessMimeType( $fsPath, false );
+               } elseif ( !$type && strlen( $content ) ) {
+                       $tmpFile = TempFSFile::factory( 'mime_' );
+                       file_put_contents( $tmpFile->getPath(), $content );
+                       $type = $magic->guessMimeType( $tmpFile->getPath(), 
false );
+               }
+               return $type ?: 'unknown/unknown';
+       }
 }
diff --git a/includes/filebackend/FileBackendStore.php 
b/includes/filebackend/FileBackendStore.php
index e5ce968..8113ec2 100644
--- a/includes/filebackend/FileBackendStore.php
+++ b/includes/filebackend/FileBackendStore.php
@@ -58,7 +58,7 @@
        /**
         * @see FileBackend::__construct()
         * Additional $config params include:
-        *   - wanCache     : WANOBjectCache object to use for persistent 
caching.
+        *   - wanCache     : WANObjectCache object to use for persistent 
caching.
         *   - mimeCallback : Callback that takes (storage path, content, file 
system path) and
         *                    returns the MIME type of the file or 
'unknown/unknown'. The file
         *                    system path parameter should be used if the 
content one is null.
@@ -69,10 +69,7 @@
                parent::__construct( $config );
                $this->mimeCallback = isset( $config['mimeCallback'] )
                        ? $config['mimeCallback']
-                       : function ( $storagePath, $content, $fsPath ) {
-                               // @todo handle the case of extension-less 
files using the contents
-                               return StreamFile::contentTypeFromPath( 
$storagePath ) ?: 'unknown/unknown';
-                       };
+                       : null;
                $this->memCache = WANObjectCache::newEmpty(); // disabled by 
default
                $this->cheapCache = new ProcessCacheLRU( self::CACHE_CHEAP_SIZE 
);
                $this->expensiveCache = new ProcessCacheLRU( 
self::CACHE_EXPENSIVE_SIZE );
@@ -1823,7 +1820,18 @@
         * @return string MIME type
         */
        protected function getContentType( $storagePath, $content, $fsPath ) {
-               return call_user_func_array( $this->mimeCallback, 
func_get_args() );
+               if ( $this->mimeCallback ) {
+                       return call_user_func_array( $this->mimeCallback, 
func_get_args() );
+               }
+
+               $mime = null;
+               if ( $fsPath !== null && function_exists( 'finfo_file' ) ) {
+                       $finfo = finfo_open( FILEINFO_MIME_TYPE );
+                       $mime = finfo_file( $finfo, $fsPath );
+                       finfo_close( $finfo );
+               }
+
+               return is_string( $mime ) ? $mime : 'unknown/unknown';
        }
 }
 
diff --git a/tests/phpunit/includes/filebackend/FileBackendTest.php 
b/tests/phpunit/includes/filebackend/FileBackendTest.php
index 0d15b75..09b3728 100644
--- a/tests/phpunit/includes/filebackend/FileBackendTest.php
+++ b/tests/phpunit/includes/filebackend/FileBackendTest.php
@@ -2397,6 +2397,42 @@
                        "Scoped unlocking of files succeeded with OK status 
($backendName)." );
        }
 
+       /**
+        * @dataProvider provider_testGetContentType
+        */
+       public function testGetContentType( $mimeCallback, $mimeFromString ) {
+               global $IP;
+
+               $be = TestingAccessWrapper::newFromObject( new 
MemoryFileBackend(
+                       array(
+                               'name' => 'testing',
+                               'class' => 'MemoryFileBackend',
+                               'wikiId' => 'meow',
+                               'mimeCallback' => $mimeCallback
+                       )
+               ) );
+
+               $dst = 'mwstore://testing/container/path/to/file_no_ext';
+               $src = "$IP/tests/phpunit/data/media/srgb.jpg";
+               $this->assertEquals( 'image/jpeg', $be->getContentType( $dst, 
null, $src ) );
+               $this->assertEquals(
+                       $mimeFromString ? 'image/jpeg' : 'unknown/unknown',
+                       $be->getContentType( $dst, file_get_contents( $src ), 
null ) );
+
+               $src = "$IP/tests/phpunit/data/media/Png-native-test.png";
+               $this->assertEquals( 'image/png', $be->getContentType( $dst, 
null, $src ) );
+               $this->assertEquals(
+                       $mimeFromString ? 'image/png' : 'unknown/unknown',
+                       $be->getContentType( $dst, file_get_contents( $src ), 
null ) );
+       }
+
+       public static function provider_testGetContentType() {
+               return array(
+                       array( null, false ),
+                       array( array( FileBackendGroup::singleton(), 
'guessMimeInternal' ), true )
+               );
+       }
+
        public function testReadAffinity() {
                $be = TestingAccessWrapper::newFromObject(
                        new FileBackendMultiWrite( array(

-- 
To view, visit https://gerrit.wikimedia.org/r/173241
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Iad59bf6c6a416b706f976a4c425763fd30e2debb
Gerrit-PatchSet: 6
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Aaron Schulz <asch...@wikimedia.org>
Gerrit-Reviewer: Aaron Schulz <asch...@wikimedia.org>
Gerrit-Reviewer: Brian Wolff <bawolff...@gmail.com>
Gerrit-Reviewer: Gilles <gdu...@wikimedia.org>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to