You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
235 lines
7.2 KiB
235 lines
7.2 KiB
<?php
|
|
/**
|
|
* Copyright 1999-2017 Horde LLC (http://www.horde.org/)
|
|
*
|
|
* See the enclosed file COPYING for license information (LGPL). If you
|
|
* did not receive this file, see http://www.horde.org/licenses/lgpl21.
|
|
*
|
|
* @category Horde
|
|
* @copyright 1999-2017 Horde LLC
|
|
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
|
|
* @package Mime
|
|
*/
|
|
|
|
/**
|
|
* Utilities to determine MIME content-types of unknown content.
|
|
*
|
|
* @author Anil Madhavapeddy <anil@recoil.org>
|
|
* @author Michael Slusarz <slusarz@horde.org>
|
|
* @category Horde
|
|
* @copyright 1999-2017 Horde LLC
|
|
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
|
|
* @package Mime
|
|
*/
|
|
class Horde_Mime_Magic
|
|
{
|
|
/**
|
|
* The MIME extension map.
|
|
*
|
|
* @var array
|
|
*/
|
|
protected static $_map = null;
|
|
|
|
/**
|
|
* Returns a copy of the MIME extension map.
|
|
*
|
|
* @return array The MIME extension map.
|
|
*/
|
|
protected static function _getMimeExtensionMap()
|
|
{
|
|
if (is_null(self::$_map)) {
|
|
require __DIR__ . '/mime.mapping.php';
|
|
self::$_map = $mime_extension_map;
|
|
}
|
|
|
|
return self::$_map;
|
|
}
|
|
|
|
/**
|
|
* Attempt to convert a file extension to a MIME type, based
|
|
* on the global Horde and application specific config files.
|
|
*
|
|
* If we cannot map the file extension to a specific type, then
|
|
* we fall back to a custom MIME handler 'x-extension/$ext', which
|
|
* can be used as a normal MIME type internally throughout Horde.
|
|
*
|
|
* @param string $ext The file extension to be mapped to a MIME type.
|
|
*
|
|
* @return string The MIME type of the file extension.
|
|
*/
|
|
public static function extToMime($ext)
|
|
{
|
|
if (empty($ext)) {
|
|
return 'application/octet-stream';
|
|
}
|
|
|
|
$ext = Horde_String::lower($ext);
|
|
$map = self::_getMimeExtensionMap();
|
|
$pos = 0;
|
|
|
|
while (!isset($map[$ext])) {
|
|
if (($pos = strpos($ext, '.')) === false) {
|
|
break;
|
|
}
|
|
$ext = substr($ext, $pos + 1);
|
|
}
|
|
|
|
return isset($map[$ext])
|
|
? $map[$ext]
|
|
: 'x-extension/' . $ext;
|
|
}
|
|
|
|
/**
|
|
* Attempt to convert a filename to a MIME type, based on the global Horde
|
|
* and application specific config files.
|
|
*
|
|
* @param string $filename The filename to be mapped to a MIME type.
|
|
* @param boolean $unknown How should unknown extensions be handled? If
|
|
* true, will return 'x-extension/*' types. If
|
|
* false, will return 'application/octet-stream'.
|
|
*
|
|
* @return string The MIME type of the filename.
|
|
*/
|
|
public static function filenameToMime($filename, $unknown = true)
|
|
{
|
|
$pos = strlen($filename) + 1;
|
|
$type = '';
|
|
|
|
$map = self::_getMimeExtensionMap();
|
|
for ($i = 0; $i <= $map['__MAXPERIOD__']; ++$i) {
|
|
$npos = strrpos(substr($filename, 0, $pos - 1), '.');
|
|
if ($npos === false) {
|
|
break;
|
|
}
|
|
$pos = $npos + 1;
|
|
}
|
|
|
|
$type = ($pos === false) ? '' : self::extToMime(substr($filename, $pos));
|
|
|
|
return (empty($type) || (!$unknown && (strpos($type, 'x-extension') !== false)))
|
|
? 'application/octet-stream'
|
|
: $type;
|
|
}
|
|
|
|
/**
|
|
* Attempt to convert a MIME type to a file extension, based
|
|
* on the global Horde and application specific config files.
|
|
*
|
|
* If we cannot map the type to a file extension, we return false.
|
|
*
|
|
* @param string $type The MIME type to be mapped to a file extension.
|
|
*
|
|
* @return string The file extension of the MIME type.
|
|
*/
|
|
public static function mimeToExt($type)
|
|
{
|
|
if (empty($type)) {
|
|
return false;
|
|
}
|
|
|
|
if (($key = array_search($type, self::_getMimeExtensionMap())) === false) {
|
|
list($major, $minor) = explode('/', $type);
|
|
if ($major == 'x-extension') {
|
|
return $minor;
|
|
}
|
|
if (strpos($minor, 'x-') === 0) {
|
|
return substr($minor, 2);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
return $key;
|
|
}
|
|
|
|
/**
|
|
* Attempt to determine the MIME type of an unknown file.
|
|
*
|
|
* @param string $path The path to the file to analyze.
|
|
* @param string $magic_db Path to the mime magic database.
|
|
* @param array $opts Additional options:
|
|
* - nostrip: (boolean) Don't strip parameter information from MIME
|
|
* type string.
|
|
* DEFAULT: false
|
|
*
|
|
* @return mixed The MIME type of the file. Returns false if the file
|
|
* type can not be determined.
|
|
*/
|
|
public static function analyzeFile($path, $magic_db = null,
|
|
$opts = array())
|
|
{
|
|
if (Horde_Util::extensionExists('fileinfo')) {
|
|
$res = empty($magic_db)
|
|
? finfo_open(FILEINFO_MIME)
|
|
: finfo_open(FILEINFO_MIME, $magic_db);
|
|
|
|
if ($res) {
|
|
$type = trim(finfo_file($res, $path));
|
|
finfo_close($res);
|
|
|
|
/* Remove any additional information. */
|
|
if (empty($opts['nostrip'])) {
|
|
foreach (array(';', ',', '\\0') as $separator) {
|
|
if (($pos = strpos($type, $separator)) !== false) {
|
|
$type = rtrim(substr($type, 0, $pos));
|
|
}
|
|
}
|
|
|
|
if (preg_match('|^[a-z0-9]+/[.-a-z0-9]+$|i', $type)) {
|
|
return $type;
|
|
}
|
|
} else {
|
|
return $type;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Attempt to determine the MIME type of an unknown byte stream.
|
|
*
|
|
* @param string $data The file data to analyze.
|
|
* @param string $magic_db Path to the mime magic database.
|
|
* @param array $opts Additional options:
|
|
* - nostrip: (boolean) Don't strip parameter information from MIME
|
|
* type string.
|
|
* DEFAULT: false
|
|
*
|
|
* @return mixed The MIME type of the file. Returns false if the file
|
|
* type can not be determined.
|
|
*/
|
|
public static function analyzeData($data, $magic_db = null,
|
|
$opts = array())
|
|
{
|
|
/* If the PHP Mimetype extension is available, use that. */
|
|
if (Horde_Util::extensionExists('fileinfo')) {
|
|
$res = empty($magic_db)
|
|
? @finfo_open(FILEINFO_MIME)
|
|
: @finfo_open(FILEINFO_MIME, $magic_db);
|
|
|
|
if (!$res) {
|
|
return false;
|
|
}
|
|
|
|
$type = trim(finfo_buffer($res, $data));
|
|
finfo_close($res);
|
|
|
|
/* Remove any additional information. */
|
|
if (empty($opts['nostrip'])) {
|
|
if (($pos = strpos($type, ';')) !== false) {
|
|
$type = rtrim(substr($type, 0, $pos));
|
|
}
|
|
|
|
if (($pos = strpos($type, ',')) !== false) {
|
|
$type = rtrim(substr($type, 0, $pos));
|
|
}
|
|
}
|
|
|
|
return $type;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|