Details
-
Type:
Improvement
-
Status:
Resolved
-
Priority:
Major
-
Resolution: Won't Fix
-
Affects Version/s: 1.10.3
-
Fix Version/s: 1.10.4
-
Component/s: Zend_Validate
-
Labels:None
Description
I would like to propose an improvement to Zend_Validate_File_MimeType as the current method of setting the magic files seems over-complicated and doesn't work on all distributions. On my Mac and on several other Linux distributions, the mime type for images is returned as 'application/octet-stream'.
I first noticed the issue on my Mac OS X 10.5.X (Leopard) running Zend Server w/PHP 5.3.1. If I replaced my /usr/share/file/magic* files with those from Mac OS X 10.6.X (Snow Leopard), the problem went away. My Ubuntu instance with PHP 5.2.10 or 5.3.2 worked fine as it has updated libmagic1 package. However, our production systems use RHEL with compiled PHP 5.2.13 or 5.3.2, but the libmagic files there seem very outdated, causing the validator to fail for Images.
Moreover, Zend_Validate_File_MimeType doesn't allow you to use the finfo_open function with the second parameter set to the default of NULL. All distributions I've tried seem to work when the magic file is not specified.
The patch below changes Zend_Validate_File_MimeType to work more like Zend_File_Transfer_Adapter_Abstract...it doesn't have any complex logic to automatically find a magic file, if the user sets one, it uses it. Otherwise, it does finfo_open w/o specifying a magic file:
<?php /** * Zend Framework * * LICENSE * * This source file is subject to the new BSD license that is bundled * with this package in the file LICENSE.txt. * It is also available through the world-wide-web at this URL: * http://framework.zend.com/license/new-bsd * If you did not receive a copy of the license and are unable to * obtain it through the world-wide-web, please send an email * to license@zend.com so we can send you a copy immediately. * * @category Zend * @package Zend_Validate * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License * @version $Id: MimeType.php 21472 2010-03-11 22:16:55Z thomas $ */ /** * @see Zend_Validate_Abstract */ require_once 'Zend/Validate/Abstract.php'; /** * Validator for the mime type of a file * * @category Zend * @package Zend_Validate * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Zend_Validate_File_MimeType extends Zend_Validate_Abstract { /**#@+ * @const Error type constants */ const FALSE_TYPE = 'fileMimeTypeFalse'; const NOT_DETECTED = 'fileMimeTypeNotDetected'; const NOT_READABLE = 'fileMimeTypeNotReadable'; /**#@-*/ /** * @var array Error message templates */ protected $_messageTemplates = array( self::FALSE_TYPE => "File '%value%' has a false mimetype of '%type%'", self::NOT_DETECTED => "The mimetype of file '%value%' could not be detected", self::NOT_READABLE => "File '%value%' can not be read", ); /** * @var array */ protected $_messageVariables = array( 'type' => '_type' ); /** * @var string */ protected $_type; /** * Mimetypes * * If null, there is no mimetype * * @var string|null */ protected $_mimetype; /** * Magicfile to use * * @var string|null */ protected $_magicfile; /** * Option to allow header check * * @var boolean */ protected $_headerCheck = false; /** * Sets validator options * * Mimetype to accept * * @param string|array $mimetype MimeType * @return void */ public function __construct($mimetype) { if ($mimetype instanceof Zend_Config) { $mimetype = $mimetype->toArray(); } elseif (is_string($mimetype)) { $mimetype = explode(',', $mimetype); } elseif (!is_array($mimetype)) { require_once 'Zend/Validate/Exception.php'; throw new Zend_Validate_Exception("Invalid options to validator provided"); } if (isset($mimetype['magicfile'])) { $this->setMagicFile($mimetype['magicfile']); unset($mimetype['magicfile']); } if (isset($mimetype['headerCheck'])) { $this->enableHeaderCheck($mimetype['headerCheck']); unset($mimetype['headerCheck']); } $this->setMimeType($mimetype); } /** * Returns the actual set magicfile * * @return string */ public function getMagicFile() { return $this->_magicfile; } /** * Sets the magicfile to use * if null, the MAGIC constant from php is used * if the MAGIC file is errorous, no file will be set * * @param string $file * @throws Zend_Validate_Exception When finfo can not read the magicfile * @return Zend_Validate_File_MimeType Provides fluid interface */ public function setMagicFile($file) { if (isset($file)) { $this->_magicfile = (string)$file; } return $this; } /** * Returns the Header Check option * * @return boolean */ public function getHeaderCheck() { return $this->_headerCheck; } /** * Defines if the http header should be used * Note that this is unsave and therefor the default value is false * * @param boolean $checkHeader * @return Zend_Validate_File_MimeType Provides fluid interface */ public function enableHeaderCheck($headerCheck = true) { $this->_headerCheck = (boolean) $headerCheck; return $this; } /** * Returns the set mimetypes * * @param boolean $asArray Returns the values as array, when false an concated string is returned * @return string|array */ public function getMimeType($asArray = false) { $asArray = (bool) $asArray; $mimetype = (string) $this->_mimetype; if ($asArray) { $mimetype = explode(',', $mimetype); } return $mimetype; } /** * Sets the mimetypes * * @param string|array $mimetype The mimetypes to validate * @return Zend_Validate_File_Extension Provides a fluent interface */ public function setMimeType($mimetype) { $this->_mimetype = null; $this->addMimeType($mimetype); return $this; } /** * Adds the mimetypes * * @param string|array $mimetype The mimetypes to add for validation * @return Zend_Validate_File_Extension Provides a fluent interface */ public function addMimeType($mimetype) { $mimetypes = $this->getMimeType(true); if (is_string($mimetype)) { $mimetype = explode(',', $mimetype); } elseif (!is_array($mimetype)) { require_once 'Zend/Validate/Exception.php'; throw new Zend_Validate_Exception("Invalid options to validator provided"); } if (isset($mimetype['magicfile'])) { unset($mimetype['magicfile']); } foreach ($mimetype as $content) { if (empty($content) || !is_string($content)) { continue; } $mimetypes[] = trim($content); } $mimetypes = array_unique($mimetypes); // Sanity check to ensure no empty values foreach ($mimetypes as $key => $mt) { if (empty($mt)) { unset($mimetypes[$key]); } } $this->_mimetype = implode(',', $mimetypes); return $this; } /** * Defined by Zend_Validate_Interface * * Returns true if the mimetype of the file matches the given ones. Also parts * of mimetypes can be checked. If you give for example "image" all image * mime types will be accepted like "image/gif", "image/jpeg" and so on. * * @param string $value Real file to check for mimetype * @param array $file File data from Zend_File_Transfer * @return boolean */ public function isValid($value, $file = null) { if ($file === null) { $file = array( 'type' => null, 'name' => $value ); } // Is file readable ? require_once 'Zend/Loader.php'; if (!Zend_Loader::isReadable($value)) { return $this->_throw($file, self::NOT_READABLE); } if (class_exists('finfo', false)) { $const = defined('FILEINFO_MIME_TYPE') ? FILEINFO_MIME_TYPE : FILEINFO_MIME; if (!empty($this->_magicfile)) { $finfo = @finfo_open($const, $this->_magicfile); } if (empty($finfo)) { $finfo = @finfo_open($const); } if ($finfo !== false) { $this->_type = finfo_file($finfo, $value); } unset($finfo); } if (empty($this->_type) && (function_exists('mime_content_type') && ini_get('mime_magic.magicfile'))) { $this->_type = mime_content_type($value); } if (empty($this->_type) && $this->_headerCheck) { $this->_type = $file['type']; } if (empty($this->_type)) { return $this->_throw($file, self::NOT_DETECTED); } $mimetype = $this->getMimeType(true); if (in_array($this->_type, $mimetype)) { return true; } $types = explode('/', $this->_type); $types = array_merge($types, explode('-', $this->_type)); $types = array_merge($types, explode(';', $this->_type)); foreach($mimetype as $mime) { if (in_array($mime, $types)) { return true; } } return $this->_throw($file, self::FALSE_TYPE); } /** * Throws an error of the given type * * @param string $file * @param string $errorType * @return false */ protected function _throw($file, $errorType) { $this->_value = $file['name']; $this->_error($errorType); return false; } }
Issue Links
| This issue is related to: | ||||
| ZF-10461 | CLONE - Zend_Validate_File_MimeType overrides default PHP fileinfo behavior |
|
|
|
According to documentation and API you could simply set the option
"magicfile" to FALSE
which leads to finfo_open to be called without the magicfile parameter.
And there ARE distributions which are delivered with a broken finfo implementation. That was the original reason why we implemented this feature.