mirror of
https://github.com/nextcloud/server.git
synced 2026-06-09 00:32:29 -04:00
Added mimetype detector
* Copied unit tests from old functions
This commit is contained in:
parent
4edfadac96
commit
6db6689740
6 changed files with 333 additions and 1 deletions
|
|
@ -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';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
78
lib/public/files/imimetypedetector.php
Normal file
78
lib/public/files/imimetypedetector.php
Normal 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);
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
97
tests/lib/files/type/detection.php
Normal file
97
tests/lib/files/type/detection.php
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in a new issue