/framework/Mime/lib/Horde/Mime/Magic.php

https://github.com/ewandor/horde · PHP · 232 lines · 115 code · 26 blank · 91 comment · 24 complexity · ad3d82185c078c846b7aa5b57a8a0ad6 MD5 · raw file

  1. <?php
  2. /**
  3. * The Horde_Mime_Magic:: class provides an interface to determine a MIME type
  4. * for various content, if it provided with different levels of information.
  5. *
  6. * Copyright 1999-2012 Horde LLC (http://www.horde.org/)
  7. *
  8. * See the enclosed file COPYING for license information (LGPL). If you
  9. * did not receive this file, see http://www.horde.org/licenses/lgpl21.
  10. *
  11. * @author Anil Madhavapeddy <anil@recoil.org>
  12. * @author Michael Slusarz <slusarz@horde.org>
  13. * @category Horde
  14. * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
  15. * @package Mime
  16. */
  17. class Horde_Mime_Magic
  18. {
  19. /**
  20. * The MIME extension map.
  21. *
  22. * @var array
  23. */
  24. static protected $_map = null;
  25. /**
  26. * Returns a copy of the MIME extension map.
  27. *
  28. * @return array The MIME extension map.
  29. */
  30. static protected function _getMimeExtensionMap()
  31. {
  32. if (is_null(self::$_map)) {
  33. require dirname(__FILE__) . '/mime.mapping.php';
  34. self::$_map = $mime_extension_map;
  35. }
  36. return self::$_map;
  37. }
  38. /**
  39. * Attempt to convert a file extension to a MIME type, based
  40. * on the global Horde and application specific config files.
  41. *
  42. * If we cannot map the file extension to a specific type, then
  43. * we fall back to a custom MIME handler 'x-extension/$ext', which
  44. * can be used as a normal MIME type internally throughout Horde.
  45. *
  46. * @param string $ext The file extension to be mapped to a MIME type.
  47. *
  48. * @return string The MIME type of the file extension.
  49. */
  50. static public function extToMime($ext)
  51. {
  52. if (empty($ext)) {
  53. return 'application/octet-stream';
  54. }
  55. $ext = Horde_String::lower($ext);
  56. $map = self::_getMimeExtensionMap();
  57. $pos = 0;
  58. while (!isset($map[$ext])) {
  59. if (($pos = strpos($ext, '.')) === false) {
  60. break;
  61. }
  62. $ext = substr($ext, $pos + 1);
  63. }
  64. return isset($map[$ext])
  65. ? $map[$ext]
  66. : 'x-extension/' . $ext;
  67. }
  68. /**
  69. * Attempt to convert a filename to a MIME type, based on the global Horde
  70. * and application specific config files.
  71. *
  72. * @param string $filename The filename to be mapped to a MIME type.
  73. * @param boolean $unknown How should unknown extensions be handled? If
  74. * true, will return 'x-extension/*' types. If
  75. * false, will return 'application/octet-stream'.
  76. *
  77. * @return string The MIME type of the filename.
  78. */
  79. static public function filenameToMime($filename, $unknown = true)
  80. {
  81. $pos = strlen($filename) + 1;
  82. $type = '';
  83. $map = self::_getMimeExtensionMap();
  84. for ($i = 0; $i <= $map['__MAXPERIOD__']; ++$i) {
  85. $npos = strrpos(substr($filename, 0, $pos - 1), '.');
  86. if ($npos === false) {
  87. break;
  88. }
  89. $pos = $npos + 1;
  90. }
  91. $type = ($pos === false) ? '' : self::extToMime(substr($filename, $pos));
  92. return (empty($type) || (!$unknown && (strpos($type, 'x-extension') !== false)))
  93. ? 'application/octet-stream'
  94. : $type;
  95. }
  96. /**
  97. * Attempt to convert a MIME type to a file extension, based
  98. * on the global Horde and application specific config files.
  99. *
  100. * If we cannot map the type to a file extension, we return false.
  101. *
  102. * @param string $type The MIME type to be mapped to a file extension.
  103. *
  104. * @return string The file extension of the MIME type.
  105. */
  106. static public function mimeToExt($type)
  107. {
  108. if (empty($type)) {
  109. return false;
  110. }
  111. if (($key = array_search($type, self::_getMimeExtensionMap())) === false) {
  112. list($major, $minor) = explode('/', $type);
  113. if ($major == 'x-extension') {
  114. return $minor;
  115. }
  116. if (strpos($minor, 'x-') === 0) {
  117. return substr($minor, 2);
  118. }
  119. return false;
  120. }
  121. return $key;
  122. }
  123. /**
  124. * Attempt to determine the MIME type of an unknown file.
  125. *
  126. * @param string $path The path to the file to analyze.
  127. * @param string $magic_db Path to the mime magic database.
  128. * @param array $opts Additional options:
  129. * <pre>
  130. * 'nostrip' - (boolean) Don't strip parameter information from MIME
  131. * type string.
  132. * DEFAULT: false
  133. * </pre>
  134. *
  135. * @return mixed The MIME type of the file. Returns false if the file
  136. * type can not be determined.
  137. */
  138. static public function analyzeFile($path, $magic_db = null,
  139. $opts = array())
  140. {
  141. if (Horde_Util::extensionExists('fileinfo')) {
  142. $res = empty($magic_db)
  143. ? finfo_open(FILEINFO_MIME)
  144. : finfo_open(FILEINFO_MIME, $magic_db);
  145. if ($res) {
  146. $type = trim(finfo_file($res, $path));
  147. finfo_close($res);
  148. /* Remove any additional information. */
  149. if (empty($opts['nostrip'])) {
  150. foreach (array(';', ',', '\\0') as $separator) {
  151. if (($pos = strpos($type, $separator)) !== false) {
  152. $type = rtrim(substr($type, 0, $pos));
  153. }
  154. }
  155. if (preg_match('|^[a-z0-9]+/[.-a-z0-9]+$|i', $type)) {
  156. return $type;
  157. }
  158. } else {
  159. return $type;
  160. }
  161. }
  162. }
  163. return false;
  164. }
  165. /**
  166. * Attempt to determine the MIME type of an unknown byte stream.
  167. *
  168. * @param string $data The file data to analyze.
  169. * @param string $magic_db Path to the mime magic database.
  170. * @param array $opts Additional options:
  171. * <pre>
  172. * 'nostrip' - (boolean) Don't strip parameter information from MIME
  173. * type string.
  174. * DEFAULT: false
  175. * </pre>
  176. *
  177. * @return mixed The MIME type of the file. Returns false if the file
  178. * type can not be determined.
  179. */
  180. static public function analyzeData($data, $magic_db = null,
  181. $opts = array())
  182. {
  183. /* If the PHP Mimetype extension is available, use that. */
  184. if (Horde_Util::extensionExists('fileinfo')) {
  185. $res = empty($magic_db)
  186. ? @finfo_open(FILEINFO_MIME)
  187. : @finfo_open(FILEINFO_MIME, $magic_db);
  188. if (!$res) {
  189. return false;
  190. }
  191. $type = trim(finfo_buffer($res, $data));
  192. finfo_close($res);
  193. /* Remove any additional information. */
  194. if (empty($opts['nostrip'])) {
  195. if (($pos = strpos($type, ';')) !== false) {
  196. $type = rtrim(substr($type, 0, $pos));
  197. }
  198. if (($pos = strpos($type, ',')) !== false) {
  199. $type = rtrim(substr($type, 0, $pos));
  200. }
  201. }
  202. return $type;
  203. }
  204. return false;
  205. }
  206. }