Added mimetype detector

* Copied unit tests from old functions
This commit is contained in:
Roeland Jago Douma 2015-04-09 15:19:57 +02:00
parent 4edfadac96
commit 6db6689740
6 changed files with 333 additions and 1 deletions

View file

@ -4,6 +4,7 @@
* @author Jens-Christian Fischer <jens-christian.fischer@switch.ch>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Tanghus <thomas@tanghus.net>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
@ -25,6 +26,8 @@
namespace OC\Files\Type;
use OCP\Files\IMimeTypeDetector;
/**
* Class Detection
*
@ -32,10 +35,85 @@ namespace OC\Files\Type;
*
* @package OC\Files\Type
*/
class Detection {
class Detection implements IMimeTypeDetector {
protected $mimetypes = array();
protected $secureMimeTypes = array();
protected $mimetypeIcons = [];
/** @var string[] */
protected $mimeTypeAlias = [
'application/octet-stream' => 'file', // use file icon as fallback
'application/illustrator' => 'image/vector',
'application/postscript' => 'image/vector',
'image/svg+xml' => 'image/vector',
'application/coreldraw' => 'image',
'application/x-gimp' => 'image',
'application/x-photoshop' => 'image',
'application/x-dcraw' => 'image',
'application/font-sfnt' => 'font',
'application/x-font' => 'font',
'application/font-woff' => 'font',
'application/vnd.ms-fontobject' => 'font',
'application/json' => 'text/code',
'application/x-perl' => 'text/code',
'application/x-php' => 'text/code',
'text/x-shellscript' => 'text/code',
'application/yaml' => 'text/code',
'application/xml' => 'text/html',
'text/css' => 'text/code',
'application/x-tex' => 'text',
'application/x-compressed' => 'package/x-generic',
'application/x-7z-compressed' => 'package/x-generic',
'application/x-deb' => 'package/x-generic',
'application/x-gzip' => 'package/x-generic',
'application/x-rar-compressed' => 'package/x-generic',
'application/x-tar' => 'package/x-generic',
'application/vnd.android.package-archive' => 'package/x-generic',
'application/zip' => 'package/x-generic',
'application/msword' => 'x-office/document',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'x-office/document',
'application/vnd.openxmlformats-officedocument.wordprocessingml.template' => 'x-office/document',
'application/vnd.ms-word.document.macroEnabled.12' => 'x-office/document',
'application/vnd.ms-word.template.macroEnabled.12' => 'x-office/document',
'application/vnd.oasis.opendocument.text' => 'x-office/document',
'application/vnd.oasis.opendocument.text-template' => 'x-office/document',
'application/vnd.oasis.opendocument.text-web' => 'x-office/document',
'application/vnd.oasis.opendocument.text-master' => 'x-office/document',
'application/mspowerpoint' => 'x-office/presentation',
'application/vnd.ms-powerpoint' => 'x-office/presentation',
'application/vnd.openxmlformats-officedocument.presentationml.presentation' => 'x-office/presentation',
'application/vnd.openxmlformats-officedocument.presentationml.template' => 'x-office/presentation',
'application/vnd.openxmlformats-officedocument.presentationml.slideshow' => 'x-office/presentation',
'application/vnd.ms-powerpoint.addin.macroEnabled.12' => 'x-office/presentation',
'application/vnd.ms-powerpoint.presentation.macroEnabled.12' => 'x-office/presentation',
'application/vnd.ms-powerpoint.template.macroEnabled.12' => 'x-office/presentation',
'application/vnd.ms-powerpoint.slideshow.macroEnabled.12' => 'x-office/presentation',
'application/vnd.oasis.opendocument.presentation' => 'x-office/presentation',
'application/vnd.oasis.opendocument.presentation-template' => 'x-office/presentation',
'application/msexcel' => 'x-office/spreadsheet',
'application/vnd.ms-excel' => 'x-office/spreadsheet',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'x-office/spreadsheet',
'application/vnd.openxmlformats-officedocument.spreadsheetml.template' => 'x-office/spreadsheet',
'application/vnd.ms-excel.sheet.macroEnabled.12' => 'x-office/spreadsheet',
'application/vnd.ms-excel.template.macroEnabled.12' => 'x-office/spreadsheet',
'application/vnd.ms-excel.addin.macroEnabled.12' => 'x-office/spreadsheet',
'application/vnd.ms-excel.sheet.binary.macroEnabled.12' => 'x-office/spreadsheet',
'application/vnd.oasis.opendocument.spreadsheet' => 'x-office/spreadsheet',
'application/vnd.oasis.opendocument.spreadsheet-template' => 'x-office/spreadsheet',
'text/csv' => 'x-office/spreadsheet',
'application/msaccess' => 'database',
];
/**
* Add an extension -> mimetype mapping
*
@ -170,4 +248,51 @@ class Detection {
? $this->secureMimeTypes[$mimeType]
: 'application/octet-stream';
}
/**
* Get path to the icon of a file type
* @param string $mimeType the MIME type
* @return string the url
*/
public function mimeTypeIcon($mimetype) {
if (isset($this->mimeTypeAlias[$mimetype])) {
$mimetype = $this->mimeTypeAlias[$mimetype];
}
if (isset($this->mimetypeIcons[$mimetype])) {
return $this->mimetypeIcons[$mimetype];
}
// Replace slash and backslash with a minus
$icon = str_replace('/', '-', $mimetype);
$icon = str_replace('\\', '-', $icon);
// Is it a dir?
if ($mimetype === 'dir') {
$this->mimetypeIcons[$mimetype] = OC::$WEBROOT . '/core/img/filetypes/folder.png';
return OC::$WEBROOT . '/core/img/filetypes/folder.png';
}
if ($mimetype === 'dir-shared') {
$this->mimetypeIcons[$mimetype] = OC::$WEBROOT . '/core/img/filetypes/folder-shared.png';
return OC::$WEBROOT . '/core/img/filetypes/folder-shared.png';
}
if ($mimetype === 'dir-external') {
$this->mimetypeIcons[$mimetype] = OC::$WEBROOT . '/core/img/filetypes/folder-external.png';
return OC::$WEBROOT . '/core/img/filetypes/folder-external.png';
}
// Icon exists?
if (file_exists(OC::$SERVERROOT . '/core/img/filetypes/' . $icon . '.png')) {
$this->mimetypeIcons[$mimetype] = OC::$WEBROOT . '/core/img/filetypes/' . $icon . '.png';
return OC::$WEBROOT . '/core/img/filetypes/' . $icon . '.png';
}
// Try only the first part of the filetype
$mimePart = substr($icon, 0, strpos($icon, '-'));
if (file_exists(OC::$SERVERROOT . '/core/img/filetypes/' . $mimePart . '.png')) {
$this->mimetypeIcons[$mimetype] = OC::$WEBROOT . '/core/img/filetypes/' . $mimePart . '.png';
return OC::$WEBROOT . '/core/img/filetypes/' . $mimePart . '.png';
} else {
$this->mimetypeIcons[$mimetype] = OC::$WEBROOT . '/core/img/filetypes/file.png';
return OC::$WEBROOT . '/core/img/filetypes/file.png';
}
}
}

View file

@ -183,6 +183,7 @@ class OC_Helper {
* @return string the url
*
* Returns the path to the image of this file type.
* @deprecated Use \OC::$server->getMimeTypeDetector()->mimeTypeIcon($mimetype)
*/
public static function mimetypeIcon($mimetype) {
@ -465,6 +466,7 @@ class OC_Helper {
*
* @param string $path
* @return string
* @deprecated Use \OC::$server->getMimeTypeDetector()->detectPath($path)
*/
static public function getFileNameMimeType($path) {
return self::getMimetypeDetector()->detectPath($path);
@ -476,6 +478,7 @@ class OC_Helper {
* @param string $path
* @return string
* does NOT work for ownClouds filesystem, use OC_FileSystem::getMimeType instead
* @deprecated Use \OC::$server->getMimeTypeDetector()->detect($path)
*/
static function getMimeType($path) {
return self::getMimetypeDetector()->detect($path);
@ -486,6 +489,7 @@ class OC_Helper {
*
* @param string $mimeType
* @return string
* @deprecated Use \OC::$server->getMimeTypeDetector()->getSecureMimeType($mimeType)
*/
static function getSecureMimeType($mimeType) {
return self::getMimetypeDetector()->getSecureMimeType($mimeType);
@ -496,6 +500,7 @@ class OC_Helper {
*
* @param string $data
* @return string
* @deprecated Use \OC::$server->getMimeTypeDetector->detectString($data)
*/
static function getStringMimeType($data) {
return self::getMimetypeDetector()->detectString($data);

View file

@ -12,6 +12,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
* @author Robin McCorkell <rmccorkell@karoshi.org.uk>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Sander <brantje@gmail.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
@ -58,6 +59,7 @@ use OC\Security\SecureRandom;
use OC\Security\TrustedDomainHelper;
use OC\Tagging\TagMapper;
use OCP\IServerContainer;
use OC\Files\Type\Detection;
/**
* Class Server
@ -443,6 +445,13 @@ class Server extends SimpleContainer implements IServerContainer {
$this->registerService('MountManager', function () {
return new \OC\Files\Mount\Manager();
});
$this->registerService('MimeTypeDetector', function(Server $c) {
$mimeTypeDetector = new Detection();
$dist = file_get_contents(\OC::$configDir . '/mimetypemapping.dist.json');
$mimetypemapping = get_object_vars(json_decode($dist));
$mimeTypeDetector->registerTypeArray($mimetypemapping);
return $mimeTypeDetector;
});
}
/**
@ -930,4 +939,13 @@ class Server extends SimpleContainer implements IServerContainer {
function getMountManager() {
return $this->query('MountManager');
}
/*
* Get the MimeTypeDetector
*
* @return \OCP\Files\IMimeTypeDetector
*/
public function getMimeTypeDetector() {
return $this->query('MimeTypeDetector');
}
}

View file

@ -0,0 +1,78 @@
<?php
/**
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
// use OCP namespace for all classes that are considered public.
// This means that they should be used by apps instead of the internal ownCloud classes
namespace OCP\Files;
/**
* Interface IMimeTypeDetector
* @package OCP\Files
* @since 8.2.0
*
* Interface to handle mimetypes (detection and icon retrieval)
**/
interface IMimeTypeDetector {
/**
* detect mimetype only based on filename, content of file is not used
* @param string $path
* @return string
* @since 8.2.0
**/
public function detectPath($path);
/**
* detect mimetype based on both filename and content
*
* @param string $path
* @return string
* @since 8.2.0
*/
public function detect($path);
/**
* Get a secure mimetype that won't expose potential XSS.
*
* @param string $mimeType
* @return string
* @since 8.2.0
*/
public function getSecureMimeType($mimeType);
/**
* detect mimetype based on the content of a string
*
* @param string $data
* @return string
* @since 8.2.0
*/
public function detectString($data);
/**
* Get path to the icon of a file type
* @param string $mimeType the MIME type
* @return string the url
* @since 8.2.0
*/
public function mimeTypeIcon($mimeType);
}

View file

@ -9,6 +9,7 @@
* @author Lukas Reschke <lukas@owncloud.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Thomas Tanghus <thomas@tanghus.net>
*
@ -429,4 +430,12 @@ interface IServerContainer {
* @since 8.2.0
*/
public function getMountManager();
/**
* Get the MimeTypeDetector
*
* @return \OCP\Files\IMimeTypeDetector
* @since 8.2.0
*/
public function getMimeTypeDetector();
}

View file

@ -0,0 +1,97 @@
<?php
/**
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OC\Files\Type;
use \OC\Files\Type\Detection;
class DetectionTest extends \Test\TestCase {
public function testDetect() {
$detection = new Detection();
$dir = \OC::$SERVERROOT.'/tests/data';
$result = $detection->detect($dir."/");
$expected = 'httpd/unix-directory';
$this->assertEquals($expected, $result);
$result = $detection->detect($dir."/data.tar.gz");
$expected = 'application/x-gzip';
$this->assertEquals($expected, $result);
$result = $detection->detect($dir."/data.zip");
$expected = 'application/zip';
$this->assertEquals($expected, $result);
$result = $detection->detect($dir."/testimagelarge.svg");
$expected = 'image/svg+xml';
$this->assertEquals($expected, $result);
$result = $detection->detect($dir."/testimage.png");
$expected = 'image/png';
$this->assertEquals($expected, $result);
}
public function testGetSecureMimeType() {
$detection = new Detection();
$dist = file_get_contents(\OC::$configDir . '/mimetypemapping.dist.json');
$mimetypemapping = get_object_vars(json_decode($dist));
$detection->registerTypeArray($mimetypemapping);
$result = $detection->getSecureMimeType('image/svg+xml');
$expected = 'text/plain';
$this->assertEquals($expected, $result);
$result = $detection->getSecureMimeType('image/png');
$expected = 'image/png';
$this->assertEquals($expected, $result);
}
public function testDetectPath() {
$detection = new Detection();
$dist = file_get_contents(\OC::$configDir . '/mimetypemapping.dist.json');
$mimetypemapping = get_object_vars(json_decode($dist));
$detection->registerTypeArray($mimetypemapping);
$this->assertEquals('text/plain', $detection->detectPath('foo.txt'));
$this->assertEquals('image/png', $detection->detectPath('foo.png'));
$this->assertEquals('image/png', $detection->detectPath('foo.bar.png'));
$this->assertEquals('application/octet-stream', $detection->detectPath('.png'));
$this->assertEquals('application/octet-stream', $detection->detectPath('foo'));
$this->assertEquals('application/octet-stream', $detection->detectPath(''));
}
public function testDetectString() {
if (\OC_Util::runningOnWindows()) {
$this->markTestSkipped('[Windows] Strings have mimetype application/octet-stream on Windows');
}
$detection = new Detection();
$dist = file_get_contents(\OC::$configDir . '/mimetypemapping.dist.json');
$mimetypemapping = get_object_vars(json_decode($dist));
$detection->registerTypeArray($mimetypemapping);
$result = $detection->detectString("/data/data.tar.gz");
$expected = 'text/plain; charset=us-ascii';
$this->assertEquals($expected, $result);
}
}