PageRenderTime 51ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/monica/monica/vendor/zendframework/zendframework/library/Zend/Validator/File/MimeType.php

https://bitbucket.org/alexandretaz/maniac_divers
PHP | 423 lines | 254 code | 47 blank | 122 comment | 42 complexity | e6f8950c243b2378cc2baf4768423a5e MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * Zend Framework (http://framework.zend.com/)
  4. *
  5. * @link http://github.com/zendframework/zf2 for the canonical source repository
  6. * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
  7. * @license http://framework.zend.com/license/new-bsd New BSD License
  8. */
  9. namespace Zend\Validator\File;
  10. use Traversable;
  11. use Zend\Stdlib\ArrayUtils;
  12. use Zend\Stdlib\ErrorHandler;
  13. use Zend\Validator\AbstractValidator;
  14. use Zend\Validator\Exception;
  15. /**
  16. * Validator for the mime type of a file
  17. */
  18. class MimeType extends AbstractValidator
  19. {
  20. /**#@+
  21. * @const Error type constants
  22. */
  23. const FALSE_TYPE = 'fileMimeTypeFalse';
  24. const NOT_DETECTED = 'fileMimeTypeNotDetected';
  25. const NOT_READABLE = 'fileMimeTypeNotReadable';
  26. /**#@-*/
  27. /**
  28. * @var array Error message templates
  29. */
  30. protected $messageTemplates = array(
  31. self::FALSE_TYPE => "File has an incorrect mimetype of '%type%'",
  32. self::NOT_DETECTED => "The mimetype could not be detected from the file",
  33. self::NOT_READABLE => "File is not readable or does not exist",
  34. );
  35. /**
  36. * @var array
  37. */
  38. protected $messageVariables = array(
  39. 'type' => 'type'
  40. );
  41. /**
  42. * @var string
  43. */
  44. protected $type;
  45. /**
  46. * Finfo object to use
  47. *
  48. * @var resource
  49. */
  50. protected $finfo;
  51. /**
  52. * If no environment variable 'MAGIC' is set, try and autodiscover it based on common locations
  53. * @var array
  54. */
  55. protected $magicFiles = array(
  56. '/usr/share/misc/magic',
  57. '/usr/share/misc/magic.mime',
  58. '/usr/share/misc/magic.mgc',
  59. '/usr/share/mime/magic',
  60. '/usr/share/mime/magic.mime',
  61. '/usr/share/mime/magic.mgc',
  62. '/usr/share/file/magic',
  63. '/usr/share/file/magic.mime',
  64. '/usr/share/file/magic.mgc',
  65. );
  66. /**
  67. * Options for this validator
  68. *
  69. * @var array
  70. */
  71. protected $options = array(
  72. 'enableHeaderCheck' => false, // Allow header check
  73. 'disableMagicFile' => false, // Disable usage of magicfile
  74. 'magicFile' => null, // Magicfile to use
  75. 'mimeType' => null, // Mimetype to allow
  76. );
  77. /**
  78. * Sets validator options
  79. *
  80. * Mimetype to accept
  81. * - NULL means default PHP usage by using the environment variable 'magic'
  82. * - FALSE means disabling searching for mimetype, should be used for PHP 5.3
  83. * - A string is the mimetype file to use
  84. *
  85. * @param string|array|Traversable $options
  86. */
  87. public function __construct($options = null)
  88. {
  89. if ($options instanceof Traversable) {
  90. $options = ArrayUtils::iteratorToArray($options);
  91. } elseif (is_string($options)) {
  92. $this->setMimeType($options);
  93. $options = array();
  94. }
  95. if (isset($options['magicFile'])) {
  96. $this->setMagicFile($options['magicFile']);
  97. unset($options['magicFile']);
  98. }
  99. if (isset($options['enableHeaderCheck'])) {
  100. $this->enableHeaderCheck($options['enableHeaderCheck']);
  101. unset($options['enableHeaderCheck']);
  102. }
  103. if (array_key_exists('mimeType', $options)) {
  104. $this->setMimeType($options['mimeType']);
  105. unset($options['mimeType']);
  106. }
  107. // Handle cases where mimetypes are interspersed with options, or
  108. // options are simply an array of mime types
  109. foreach (array_keys($options) as $key) {
  110. if (!is_int($key)) {
  111. continue;
  112. }
  113. $this->addMimeType($options[$key]);
  114. unset($options[$key]);
  115. }
  116. parent::__construct($options);
  117. }
  118. /**
  119. * Returns the actual set magicfile
  120. *
  121. * @return string
  122. */
  123. public function getMagicFile()
  124. {
  125. if (null === $this->options['magicFile']) {
  126. $magic = getenv('magic');
  127. if (!empty($magic)) {
  128. $this->setMagicFile($magic);
  129. if ($this->options['magicFile'] === null) {
  130. $this->options['magicFile'] = false;
  131. }
  132. return $this->options['magicFile'];
  133. }
  134. ErrorHandler::start();
  135. $safeMode = ini_get('safe_mode');
  136. ErrorHandler::stop();
  137. if (!($safeMode == 'On' || $safeMode === 1)) {
  138. foreach ($this->magicFiles as $file) {
  139. // suppressing errors which are thrown due to openbase_dir restrictions
  140. try {
  141. $this->setMagicFile($file);
  142. if ($this->options['magicFile'] !== null) {
  143. break;
  144. }
  145. } catch (Exception\ExceptionInterface $e) {
  146. // Intentionally, catch and fall through
  147. }
  148. }
  149. }
  150. if ($this->options['magicFile'] === null) {
  151. $this->options['magicFile'] = false;
  152. }
  153. }
  154. return $this->options['magicFile'];
  155. }
  156. /**
  157. * Sets the magicfile to use
  158. * if null, the MAGIC constant from php is used
  159. * if the MAGIC file is erroneous, no file will be set
  160. * if false, the default MAGIC file from PHP will be used
  161. *
  162. * @param string $file
  163. * @return MimeType Provides fluid interface
  164. * @throws Exception\RuntimeException When finfo can not read the magicfile
  165. * @throws Exception\InvalidArgumentException
  166. * @throws Exception\InvalidMagicMimeFileException
  167. */
  168. public function setMagicFile($file)
  169. {
  170. if ($file === false) {
  171. $this->options['magicFile'] = false;
  172. } elseif (empty($file)) {
  173. $this->options['magicFile'] = null;
  174. } elseif (!(class_exists('finfo', false))) {
  175. $this->options['magicFile'] = null;
  176. throw new Exception\RuntimeException('Magicfile can not be set; there is no finfo extension installed');
  177. } elseif (!is_file($file) || !is_readable($file)) {
  178. throw new Exception\InvalidArgumentException(sprintf(
  179. 'The given magicfile ("%s") could not be read',
  180. $file
  181. ));
  182. } else {
  183. $const = defined('FILEINFO_MIME_TYPE') ? FILEINFO_MIME_TYPE : FILEINFO_MIME;
  184. ErrorHandler::start(E_NOTICE|E_WARNING);
  185. $this->finfo = finfo_open($const, $file);
  186. $error = ErrorHandler::stop();
  187. if (empty($this->finfo)) {
  188. $this->finfo = null;
  189. throw new Exception\InvalidMagicMimeFileException(sprintf(
  190. 'The given magicfile ("%s") could not be used by ext/finfo',
  191. $file
  192. ), 0, $error);
  193. }
  194. $this->options['magicFile'] = $file;
  195. }
  196. return $this;
  197. }
  198. /**
  199. * Disables usage of MagicFile
  200. *
  201. * @param $disable boolean False disables usage of magic file
  202. * @return MimeType Provides fluid interface
  203. */
  204. public function disableMagicFile($disable)
  205. {
  206. $this->options['disableMagicFile'] = (bool) $disable;
  207. return $this;
  208. }
  209. /**
  210. * Is usage of MagicFile disabled?
  211. *
  212. * @return bool
  213. */
  214. public function isMagicFileDisabled()
  215. {
  216. return $this->options['disableMagicFile'];
  217. }
  218. /**
  219. * Returns the Header Check option
  220. *
  221. * @return bool
  222. */
  223. public function getHeaderCheck()
  224. {
  225. return $this->options['enableHeaderCheck'];
  226. }
  227. /**
  228. * Defines if the http header should be used
  229. * Note that this is unsafe and therefor the default value is false
  230. *
  231. * @param bool $headerCheck
  232. * @return MimeType Provides fluid interface
  233. */
  234. public function enableHeaderCheck($headerCheck = true)
  235. {
  236. $this->options['enableHeaderCheck'] = (bool) $headerCheck;
  237. return $this;
  238. }
  239. /**
  240. * Returns the set mimetypes
  241. *
  242. * @param bool $asArray Returns the values as array, when false a concatenated string is returned
  243. * @return string|array
  244. */
  245. public function getMimeType($asArray = false)
  246. {
  247. $asArray = (bool) $asArray;
  248. $mimetype = (string) $this->options['mimeType'];
  249. if ($asArray) {
  250. $mimetype = explode(',', $mimetype);
  251. }
  252. return $mimetype;
  253. }
  254. /**
  255. * Sets the mimetypes
  256. *
  257. * @param string|array $mimetype The mimetypes to validate
  258. * @return MimeType Provides a fluent interface
  259. */
  260. public function setMimeType($mimetype)
  261. {
  262. $this->options['mimeType'] = null;
  263. $this->addMimeType($mimetype);
  264. return $this;
  265. }
  266. /**
  267. * Adds the mimetypes
  268. *
  269. * @param string|array $mimetype The mimetypes to add for validation
  270. * @return MimeType Provides a fluent interface
  271. * @throws Exception\InvalidArgumentException
  272. */
  273. public function addMimeType($mimetype)
  274. {
  275. $mimetypes = $this->getMimeType(true);
  276. if (is_string($mimetype)) {
  277. $mimetype = explode(',', $mimetype);
  278. } elseif (!is_array($mimetype)) {
  279. throw new Exception\InvalidArgumentException("Invalid options to validator provided");
  280. }
  281. if (isset($mimetype['magicFile'])) {
  282. unset($mimetype['magicFile']);
  283. }
  284. foreach ($mimetype as $content) {
  285. if (empty($content) || !is_string($content)) {
  286. continue;
  287. }
  288. $mimetypes[] = trim($content);
  289. }
  290. $mimetypes = array_unique($mimetypes);
  291. // Sanity check to ensure no empty values
  292. foreach ($mimetypes as $key => $mt) {
  293. if (empty($mt)) {
  294. unset($mimetypes[$key]);
  295. }
  296. }
  297. $this->options['mimeType'] = implode(',', $mimetypes);
  298. return $this;
  299. }
  300. /**
  301. * Defined by Zend\Validator\ValidatorInterface
  302. *
  303. * Returns true if the mimetype of the file matches the given ones. Also parts
  304. * of mimetypes can be checked. If you give for example "image" all image
  305. * mime types will be accepted like "image/gif", "image/jpeg" and so on.
  306. *
  307. * @param string|array $value Real file to check for mimetype
  308. * @return bool
  309. */
  310. public function isValid($value)
  311. {
  312. if (is_array($value)) {
  313. if (!isset($value['tmp_name']) || !isset($value['name']) || !isset($value['type'])) {
  314. throw new Exception\InvalidArgumentException(
  315. 'Value array must be in $_FILES format'
  316. );
  317. }
  318. $file = $value['tmp_name'];
  319. $filename = $value['name'];
  320. $filetype = $value['type'];
  321. } else {
  322. $file = $value;
  323. $filename = basename($file);
  324. $filetype = null;
  325. }
  326. $this->setValue($filename);
  327. // Is file readable ?
  328. if (false === stream_resolve_include_path($file)) {
  329. $this->error(static::NOT_READABLE);
  330. return false;
  331. }
  332. $mimefile = $this->getMagicFile();
  333. if (class_exists('finfo', false)) {
  334. $const = defined('FILEINFO_MIME_TYPE') ? FILEINFO_MIME_TYPE : FILEINFO_MIME;
  335. if (!$this->isMagicFileDisabled() && (!empty($mimefile) && empty($this->finfo))) {
  336. ErrorHandler::start(E_NOTICE|E_WARNING);
  337. $this->finfo = finfo_open($const, $mimefile);
  338. ErrorHandler::stop();
  339. }
  340. if (empty($this->finfo)) {
  341. ErrorHandler::start(E_NOTICE|E_WARNING);
  342. $this->finfo = finfo_open($const);
  343. ErrorHandler::stop();
  344. }
  345. $this->type = null;
  346. if (!empty($this->finfo)) {
  347. $this->type = finfo_file($this->finfo, $file);
  348. }
  349. }
  350. if (empty($this->type) &&
  351. (function_exists('mime_content_type') && ini_get('mime_magic.magicfile'))) {
  352. $this->type = mime_content_type($file);
  353. }
  354. if (empty($this->type) && $this->getHeaderCheck()) {
  355. $this->type = $filetype;
  356. }
  357. if (empty($this->type)) {
  358. $this->error(static::NOT_DETECTED);
  359. return false;
  360. }
  361. $mimetype = $this->getMimeType(true);
  362. if (in_array($this->type, $mimetype)) {
  363. return true;
  364. }
  365. $types = explode('/', $this->type);
  366. $types = array_merge($types, explode('-', $this->type));
  367. $types = array_merge($types, explode(';', $this->type));
  368. foreach ($mimetype as $mime) {
  369. if (in_array($mime, $types)) {
  370. return true;
  371. }
  372. }
  373. $this->error(static::FALSE_TYPE);
  374. return false;
  375. }
  376. }