diff options
author | Roeland Jago Douma <rullzer@users.noreply.github.com> | 2019-12-12 11:19:55 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-12-12 11:19:55 +0100 |
commit | c6e51924c8615166c2533f83ecc6399d9cc56cbd (patch) | |
tree | 4628e29811b1b3b5831df2b18cafedbc2e7ee86b /lib/private/Files | |
parent | 4f60609f83fde059e6f831c1b17b481e6604ce24 (diff) | |
parent | 4356c91ffd16f54a7bc67b7c62ef4f1110b29e9f (diff) | |
download | nextcloud-server-c6e51924c8615166c2533f83ecc6399d9cc56cbd.tar.gz nextcloud-server-c6e51924c8615166c2533f83ecc6399d9cc56cbd.zip |
Merge pull request #18236 from nextcloud/bugfix/noid/always-detect-mimetype-by-content-in-workflows
Allow to detect mimetype by content
Diffstat (limited to 'lib/private/Files')
-rw-r--r-- | lib/private/Files/Type/Detection.php | 150 |
1 files changed, 90 insertions, 60 deletions
diff --git a/lib/private/Files/Type/Detection.php b/lib/private/Files/Type/Detection.php index 8505f59bacc..530020fe4b9 100644 --- a/lib/private/Files/Type/Detection.php +++ b/lib/private/Files/Type/Detection.php @@ -1,4 +1,5 @@ <?php +declare(strict_types=1); /** * @copyright Copyright (c) 2016, ownCloud, Inc. * @@ -77,8 +78,8 @@ class Detection implements IMimeTypeDetector { */ public function __construct(IURLGenerator $urlGenerator, ILogger $logger, - $customConfigDir, - $defaultConfigDir) { + string $customConfigDir, + string $defaultConfigDir) { $this->urlGenerator = $urlGenerator; $this->logger = $logger; $this->customConfigDir = $customConfigDir; @@ -96,9 +97,9 @@ class Detection implements IMimeTypeDetector { * @param string $mimetype * @param string|null $secureMimeType */ - public function registerType($extension, - $mimetype, - $secureMimeType = null) { + public function registerType(string $extension, + string $mimetype, + ?string $secureMimeType = null): void { $this->mimetypes[$extension] = array($mimetype, $secureMimeType); $this->secureMimeTypes[$mimetype] = $secureMimeType ?: $mimetype; } @@ -112,12 +113,12 @@ class Detection implements IMimeTypeDetector { * * @param array $types */ - public function registerTypeArray($types) { + public function registerTypeArray(array $types): void { $this->mimetypes = array_merge($this->mimetypes, $types); // Update the alternative mimetypes to avoid having to look them up each time. foreach ($this->mimetypes as $mimeType) { - $this->secureMimeTypes[$mimeType[0]] = isset($mimeType[1]) ? $mimeType[1]: $mimeType[0]; + $this->secureMimeTypes[$mimeType[0]] = $mimeType[1] ?? $mimeType[0]; } } @@ -136,7 +137,7 @@ class Detection implements IMimeTypeDetector { /** * Add the mimetype aliases if they are not yet present */ - private function loadAliases() { + private function loadAliases(): void { if (!empty($this->mimeTypeAlias)) { return; } @@ -148,12 +149,12 @@ class Detection implements IMimeTypeDetector { /** * @return string[] */ - public function getAllAliases() { + public function getAllAliases(): array { $this->loadAliases(); return $this->mimeTypeAlias; } - public function getOnlyDefaultAliases() { + public function getOnlyDefaultAliases(): array { $this->loadMappings(); $this->mimeTypeAlias = json_decode(file_get_contents($this->defaultConfigDir . '/mimetypealiases.dist.json'), true); return $this->mimeTypeAlias; @@ -162,7 +163,7 @@ class Detection implements IMimeTypeDetector { /** * Add mimetype mappings if they are not yet present */ - private function loadMappings() { + private function loadMappings(): void { if (!empty($this->mimetypes)) { return; } @@ -176,7 +177,7 @@ class Detection implements IMimeTypeDetector { /** * @return array */ - public function getAllMappings() { + public function getAllMappings(): array { $this->loadMappings(); return $this->mimetypes; } @@ -187,7 +188,7 @@ class Detection implements IMimeTypeDetector { * @param string $path * @return string */ - public function detectPath($path) { + public function detectPath($path): string { $this->loadMappings(); $fileName = basename($path); @@ -199,68 +200,100 @@ class Detection implements IMimeTypeDetector { if (strpos($fileName, '.') > 0) { // remove versioning extension: name.v1508946057 and transfer extension: name.ocTransferId2057600214.part - $fileName = preg_replace('!((\.v\d+)|((.ocTransferId\d+)?.part))$!', '', $fileName); + $fileName = preg_replace('!((\.v\d+)|((\.ocTransferId\d+)?\.part))$!', '', $fileName); //try to guess the type by the file extension - $extension = strtolower(strrchr($fileName, '.')); - $extension = substr($extension, 1); //remove leading . - return (isset($this->mimetypes[$extension]) && isset($this->mimetypes[$extension][0])) - ? $this->mimetypes[$extension][0] - : 'application/octet-stream'; - } else { - return 'application/octet-stream'; + $extension = strrchr($fileName, '.'); + if ($extension !== false) { + $extension = strtolower($extension); + $extension = substr($extension, 1); //remove leading . + return $this->mimetypes[$extension][0] ?? 'application/octet-stream'; + } } + + return 'application/octet-stream'; } /** - * detect mimetype based on both filename and content - * + * detect mimetype only based on the content of file * @param string $path * @return string + * @since 18.0.0 */ - public function detect($path) { + public function detectContent(string $path): string { $this->loadMappings(); if (@is_dir($path)) { // directories are easy - return "httpd/unix-directory"; + return 'httpd/unix-directory'; } - $mimeType = $this->detectPath($path); - - if ($mimeType === 'application/octet-stream' and function_exists('finfo_open') - and function_exists('finfo_file') and $finfo = finfo_open(FILEINFO_MIME) - ) { - $info = @strtolower(finfo_file($finfo, $path)); + if (function_exists('finfo_open') + && function_exists('finfo_file') + && $finfo = finfo_open(FILEINFO_MIME)) { + $info = @finfo_file($finfo, $path); finfo_close($finfo); if ($info) { + $info = strtolower($info); $mimeType = strpos($info, ';') !== false ? substr($info, 0, strpos($info, ';')) : $info; - return empty($mimeType) ? 'application/octet-stream' : $mimeType; + $mimeType = $this->getSecureMimeType($mimeType); + if ($mimeType !== 'application/octet-stream') { + return $mimeType; + } } + } + if (strpos($path, '://') !== false && strpos($path, 'file://') === 0) { + // Is the file wrapped in a stream? + return 'application/octet-stream'; } - $isWrapped = (strpos($path, '://') !== false) and (substr($path, 0, 7) === 'file://'); - if (!$isWrapped and $mimeType === 'application/octet-stream' && function_exists("mime_content_type")) { + + if (function_exists('mime_content_type')) { // use mime magic extension if available $mimeType = mime_content_type($path); + if ($mimeType !== false) { + $mimeType = $this->getSecureMimeType($mimeType); + if ($mimeType !== 'application/octet-stream') { + return $mimeType; + } + } } - if (!$isWrapped and $mimeType === 'application/octet-stream' && \OC_Helper::canExecute("file")) { + + if (\OC_Helper::canExecute('file')) { // it looks like we have a 'file' command, // lets see if it does have mime support $path = escapeshellarg($path); - $fp = popen("file -b --mime-type $path 2>/dev/null", "r"); - $reply = fgets($fp); + $fp = popen("test -f $path && file -b --mime-type $path", 'r'); + $mimeType = fgets($fp); pclose($fp); - //trim the newline - $mimeType = trim($reply); - - if (empty($mimeType)) { - $mimeType = 'application/octet-stream'; + if ($mimeType !== false) { + //trim the newline + $mimeType = trim($mimeType); + $mimeType = $this->getSecureMimeType($mimeType); + if ($mimeType !== 'application/octet-stream') { + return $mimeType; + } } } - return $mimeType; + return 'application/octet-stream'; + } + + /** + * detect mimetype based on both filename and content + * + * @param string $path + * @return string + */ + public function detect($path): string { + $mimeType = $this->detectPath($path); + + if ($mimeType !== 'application/octet-stream') { + return $mimeType; + } + + return $this->detectContent($path); } /** @@ -269,20 +302,20 @@ class Detection implements IMimeTypeDetector { * @param string $data * @return string */ - public function detectString($data) { - if (function_exists('finfo_open') and function_exists('finfo_file')) { + public function detectString($data): string { + if (function_exists('finfo_open') && function_exists('finfo_file')) { $finfo = finfo_open(FILEINFO_MIME); $info = finfo_buffer($finfo, $data); return strpos($info, ';') !== false ? substr($info, 0, strpos($info, ';')) : $info; - } else { - $tmpFile = \OC::$server->getTempManager()->getTemporaryFile(); - $fh = fopen($tmpFile, 'wb'); - fwrite($fh, $data, 8024); - fclose($fh); - $mime = $this->detect($tmpFile); - unset($tmpFile); - return $mime; } + + $tmpFile = \OC::$server->getTempManager()->getTemporaryFile(); + $fh = fopen($tmpFile, 'wb'); + fwrite($fh, $data, 8024); + fclose($fh); + $mime = $this->detect($tmpFile); + unset($tmpFile); + return $mime; } /** @@ -291,12 +324,10 @@ class Detection implements IMimeTypeDetector { * @param string $mimeType * @return string */ - public function getSecureMimeType($mimeType) { + public function getSecureMimeType($mimeType): string { $this->loadMappings(); - return isset($this->secureMimeTypes[$mimeType]) - ? $this->secureMimeTypes[$mimeType] - : 'application/octet-stream'; + return $this->secureMimeTypes[$mimeType] ?? 'application/octet-stream'; } /** @@ -304,7 +335,7 @@ class Detection implements IMimeTypeDetector { * @param string $mimetype the MIME type * @return string the url */ - public function mimeTypeIcon($mimetype) { + public function mimeTypeIcon($mimetype): string { $this->loadAliases(); while (isset($this->mimeTypeAlias[$mimetype])) { @@ -315,8 +346,7 @@ class Detection implements IMimeTypeDetector { } // Replace slash and backslash with a minus - $icon = str_replace('/', '-', $mimetype); - $icon = str_replace('\\', '-', $icon); + $icon = str_replace(['/', '\\'], '-', $mimetype); // Is it a dir? if ($mimetype === 'dir') { |