diff options
-rw-r--r-- | lib/private/files/type/detection.php | 127 | ||||
-rw-r--r-- | lib/private/helper.php | 5 | ||||
-rw-r--r-- | lib/private/server.php | 18 | ||||
-rw-r--r-- | lib/public/files/imimetypedetector.php | 78 | ||||
-rw-r--r-- | lib/public/iservercontainer.php | 9 | ||||
-rw-r--r-- | tests/lib/files/type/detection.php | 97 |
6 files changed, 333 insertions, 1 deletions
diff --git a/lib/private/files/type/detection.php b/lib/private/files/type/detection.php index 3287375bc79..571062061df 100644 --- a/lib/private/files/type/detection.php +++ b/lib/private/files/type/detection.php @@ -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'; + } + } } diff --git a/lib/private/helper.php b/lib/private/helper.php index ed954f87630..09f0ba1da3c 100644 --- a/lib/private/helper.php +++ b/lib/private/helper.php @@ -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); diff --git a/lib/private/server.php b/lib/private/server.php index 53949b53df7..7aa331884b6 100644 --- a/lib/private/server.php +++ b/lib/private/server.php @@ -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'); + } } diff --git a/lib/public/files/imimetypedetector.php b/lib/public/files/imimetypedetector.php new file mode 100644 index 00000000000..79ed8a4fac9 --- /dev/null +++ b/lib/public/files/imimetypedetector.php @@ -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); +} diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index 95ee853d84c..f3165db33da 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -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(); } diff --git a/tests/lib/files/type/detection.php b/tests/lib/files/type/detection.php new file mode 100644 index 00000000000..1483839bf7f --- /dev/null +++ b/tests/lib/files/type/detection.php @@ -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); + } + +} |