PageRenderTime 123ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/common/lib/Yii/validators/CFileValidator.php

https://bitbucket.org/haichau59/manga
PHP | 304 lines | 131 code | 11 blank | 162 comment | 45 complexity | 0b023f0ed8c21f7c480efb5a82c7c678 MD5 | raw file
  1. <?php
  2. /**
  3. * CFileValidator class file.
  4. *
  5. * @author Qiang Xue <qiang.xue@gmail.com>
  6. * @link http://www.yiiframework.com/
  7. * @copyright Copyright &copy; 2008-2011 Yii Software LLC
  8. * @license http://www.yiiframework.com/license/
  9. */
  10. /**
  11. * CFileValidator verifies if an attribute is receiving a valid uploaded file.
  12. *
  13. * It uses the model class and attribute name to retrieve the information
  14. * about the uploaded file. It then checks if a file is uploaded successfully,
  15. * if the file size is within the limit and if the file type is allowed.
  16. *
  17. * This validator will attempt to fetch uploaded data if attribute is not
  18. * previously set. Please note that this cannot be done if input is tabular:
  19. * <pre>
  20. * foreach($models as $i=>$model)
  21. * $model->attribute = CUploadedFile::getInstance($model, "[$i]attribute");
  22. * </pre>
  23. * Please note that you must use {@link CUploadedFile::getInstances} for multiple
  24. * file uploads.
  25. *
  26. * When using CFileValidator with an active record, the following code is often used:
  27. * <pre>
  28. * if($model->save())
  29. * {
  30. * // single upload
  31. * $model->attribute->saveAs($path);
  32. * // multiple upload
  33. * foreach($model->attribute as $file)
  34. * $file->saveAs($path);
  35. * }
  36. * </pre>
  37. *
  38. * You can use {@link CFileValidator} to validate the file attribute.
  39. *
  40. * In addition to the {@link message} property for setting a custom error message,
  41. * CFileValidator has a few custom error messages you can set that correspond to different
  42. * validation scenarios. When the file is too large, you may use the {@link tooLarge} property
  43. * to define a custom error message. Similarly for {@link tooSmall}, {@link wrongType} and
  44. * {@link tooMany}. The messages may contain additional placeholders that will be replaced
  45. * with the actual content. In addition to the "{attribute}" placeholder, recognized by all
  46. * validators (see {@link CValidator}), CFileValidator allows for the following placeholders
  47. * to be specified:
  48. * <ul>
  49. * <li>{file}: replaced with the name of the file.</li>
  50. * <li>{limit}: when using {@link tooLarge}, replaced with {@link maxSize};
  51. * when using {@link tooSmall}, replaced with {@link minSize}; and when using {@link tooMany}
  52. * replaced with {@link maxFiles}.</li>
  53. * <li>{extensions}: when using {@link wrongType}, it will be replaced with the allowed extensions.</li>
  54. * </ul>
  55. *
  56. * @author Qiang Xue <qiang.xue@gmail.com>
  57. * @version $Id$
  58. * @package system.validators
  59. * @since 1.0
  60. */
  61. class CFileValidator extends CValidator
  62. {
  63. /**
  64. * @var boolean whether the attribute requires a file to be uploaded or not.
  65. * Defaults to false, meaning a file is required to be uploaded.
  66. */
  67. public $allowEmpty=false;
  68. /**
  69. * @var mixed a list of file name extensions that are allowed to be uploaded.
  70. * This can be either an array or a string consisting of file extension names
  71. * separated by space or comma (e.g. "gif, jpg").
  72. * Extension names are case-insensitive. Defaults to null, meaning all file name
  73. * extensions are allowed.
  74. */
  75. public $types;
  76. /**
  77. * @var mixed a list of MIME-types of the file that are allowed to be uploaded.
  78. * This can be either an array or a string consisting of MIME-types separated
  79. * by space or comma (e.g. "image/gif, image/jpeg"). MIME-types are
  80. * case-insensitive. Defaults to null, meaning all MIME-types are allowed.
  81. * In order to use this property fileinfo PECL extension should be installed.
  82. * @since 1.1.11
  83. */
  84. public $mimeTypes;
  85. /**
  86. * @var integer the minimum number of bytes required for the uploaded file.
  87. * Defaults to null, meaning no limit.
  88. * @see tooSmall
  89. */
  90. public $minSize;
  91. /**
  92. * @var integer the maximum number of bytes required for the uploaded file.
  93. * Defaults to null, meaning no limit.
  94. * Note, the size limit is also affected by 'upload_max_filesize' INI setting
  95. * and the 'MAX_FILE_SIZE' hidden field value.
  96. * @see tooLarge
  97. */
  98. public $maxSize;
  99. /**
  100. * @var string the error message used when the uploaded file is too large.
  101. * @see maxSize
  102. */
  103. public $tooLarge;
  104. /**
  105. * @var string the error message used when the uploaded file is too small.
  106. * @see minSize
  107. */
  108. public $tooSmall;
  109. /**
  110. * @var string the error message used when the uploaded file has an extension name
  111. * that is not listed among {@link types}.
  112. */
  113. public $wrongType;
  114. /**
  115. * @var string the error message used when the uploaded file has a MIME-type
  116. * that is not listed among {@link mimeTypes}. In order to use this property
  117. * fileinfo PECL extension should be installed.
  118. * @since 1.1.11
  119. */
  120. public $wrongMimeType;
  121. /**
  122. * @var integer the maximum file count the given attribute can hold.
  123. * It defaults to 1, meaning single file upload. By defining a higher number,
  124. * multiple uploads become possible.
  125. */
  126. public $maxFiles=1;
  127. /**
  128. * @var string the error message used if the count of multiple uploads exceeds
  129. * limit.
  130. */
  131. public $tooMany;
  132. /**
  133. * @var boolean whether attributes listed with this validator should be considered safe for massive assignment.
  134. * For this validator it defaults to false.
  135. * @since 1.1.12
  136. */
  137. public $safe=false;
  138. /**
  139. * Set the attribute and then validates using {@link validateFile}.
  140. * If there is any error, the error message is added to the object.
  141. * @param CModel $object the object being validated
  142. * @param string $attribute the attribute being validated
  143. */
  144. protected function validateAttribute($object, $attribute)
  145. {
  146. if($this->maxFiles > 1)
  147. {
  148. $files=$object->$attribute;
  149. if(!is_array($files) || !isset($files[0]) || !$files[0] instanceof CUploadedFile)
  150. $files = CUploadedFile::getInstances($object, $attribute);
  151. if(array()===$files)
  152. return $this->emptyAttribute($object, $attribute);
  153. if(count($files) > $this->maxFiles)
  154. {
  155. $message=$this->tooMany!==null?$this->tooMany : Yii::t('yii', '{attribute} cannot accept more than {limit} files.');
  156. $this->addError($object, $attribute, $message, array('{attribute}'=>$attribute, '{limit}'=>$this->maxFiles));
  157. }
  158. else
  159. foreach($files as $file)
  160. $this->validateFile($object, $attribute, $file);
  161. }
  162. else
  163. {
  164. $file = $object->$attribute;
  165. if(!$file instanceof CUploadedFile)
  166. {
  167. $file = CUploadedFile::getInstance($object, $attribute);
  168. if(null===$file)
  169. return $this->emptyAttribute($object, $attribute);
  170. }
  171. $this->validateFile($object, $attribute, $file);
  172. }
  173. }
  174. /**
  175. * Internally validates a file object.
  176. * @param CModel $object the object being validated
  177. * @param string $attribute the attribute being validated
  178. * @param CUploadedFile $file uploaded file passed to check against a set of rules
  179. */
  180. protected function validateFile($object, $attribute, $file)
  181. {
  182. if(null===$file || ($error=$file->getError())==UPLOAD_ERR_NO_FILE)
  183. return $this->emptyAttribute($object, $attribute);
  184. else if($error==UPLOAD_ERR_INI_SIZE || $error==UPLOAD_ERR_FORM_SIZE || $this->maxSize!==null && $file->getSize()>$this->maxSize)
  185. {
  186. $message=$this->tooLarge!==null?$this->tooLarge : Yii::t('yii','The file "{file}" is too large. Its size cannot exceed {limit} bytes.');
  187. $this->addError($object,$attribute,$message,array('{file}'=>$file->getName(), '{limit}'=>$this->getSizeLimit()));
  188. }
  189. else if($error==UPLOAD_ERR_PARTIAL)
  190. throw new CException(Yii::t('yii','The file "{file}" was only partially uploaded.',array('{file}'=>$file->getName())));
  191. else if($error==UPLOAD_ERR_NO_TMP_DIR)
  192. throw new CException(Yii::t('yii','Missing the temporary folder to store the uploaded file "{file}".',array('{file}'=>$file->getName())));
  193. else if($error==UPLOAD_ERR_CANT_WRITE)
  194. throw new CException(Yii::t('yii','Failed to write the uploaded file "{file}" to disk.',array('{file}'=>$file->getName())));
  195. else if(defined('UPLOAD_ERR_EXTENSION') && $error==UPLOAD_ERR_EXTENSION) // available for PHP 5.2.0 or above
  196. throw new CException(Yii::t('yii','File upload was stopped by extension.'));
  197. if($this->minSize!==null && $file->getSize()<$this->minSize)
  198. {
  199. $message=$this->tooSmall!==null?$this->tooSmall : Yii::t('yii','The file "{file}" is too small. Its size cannot be smaller than {limit} bytes.');
  200. $this->addError($object,$attribute,$message,array('{file}'=>$file->getName(), '{limit}'=>$this->minSize));
  201. }
  202. if($this->types!==null)
  203. {
  204. if(is_string($this->types))
  205. $types=preg_split('/[\s,]+/',strtolower($this->types),-1,PREG_SPLIT_NO_EMPTY);
  206. else
  207. $types=$this->types;
  208. if(!in_array(strtolower($file->getExtensionName()),$types))
  209. {
  210. $message=$this->wrongType!==null?$this->wrongType : Yii::t('yii','The file "{file}" cannot be uploaded. Only files with these extensions are allowed: {extensions}.');
  211. $this->addError($object,$attribute,$message,array('{file}'=>$file->getName(), '{extensions}'=>implode(', ',$types)));
  212. }
  213. }
  214. if($this->mimeTypes!==null)
  215. {
  216. if(function_exists('finfo_open'))
  217. {
  218. $mimeType=false;
  219. if($info=finfo_open(defined('FILEINFO_MIME_TYPE') ? FILEINFO_MIME_TYPE : FILEINFO_MIME))
  220. $mimeType=finfo_file($info,$file->getTempName());
  221. }
  222. else if(function_exists('mime_content_type'))
  223. $mimeType=mime_content_type($file->getTempName());
  224. else
  225. throw new CException(Yii::t('yii','In order to use MIME-type validation provided by CFileValidator fileinfo PECL extension should be installed.'));
  226. if(is_string($this->mimeTypes))
  227. $mimeTypes=preg_split('/[\s,]+/',strtolower($this->mimeTypes),-1,PREG_SPLIT_NO_EMPTY);
  228. else
  229. $mimeTypes=$this->mimeTypes;
  230. if($mimeType===false || !in_array(strtolower($mimeType),$mimeTypes))
  231. {
  232. $message=$this->wrongMimeType!==null?$this->wrongMimeType : Yii::t('yii','The file "{file}" cannot be uploaded. Only files of these MIME-types are allowed: {mimeTypes}.');
  233. $this->addError($object,$attribute,$message,array('{file}'=>$file->getName(), '{mimeTypes}'=>implode(', ',$mimeTypes)));
  234. }
  235. }
  236. }
  237. /**
  238. * Raises an error to inform end user about blank attribute.
  239. * @param CModel $object the object being validated
  240. * @param string $attribute the attribute being validated
  241. */
  242. protected function emptyAttribute($object, $attribute)
  243. {
  244. if(!$this->allowEmpty)
  245. {
  246. $message=$this->message!==null?$this->message : Yii::t('yii','{attribute} cannot be blank.');
  247. $this->addError($object,$attribute,$message);
  248. }
  249. }
  250. /**
  251. * Returns the maximum size allowed for uploaded files.
  252. * This is determined based on three factors:
  253. * <ul>
  254. * <li>'upload_max_filesize' in php.ini</li>
  255. * <li>'MAX_FILE_SIZE' hidden field</li>
  256. * <li>{@link maxSize}</li>
  257. * </ul>
  258. *
  259. * @return integer the size limit for uploaded files.
  260. */
  261. protected function getSizeLimit()
  262. {
  263. $limit=ini_get('upload_max_filesize');
  264. $limit=$this->sizeToBytes($limit);
  265. if($this->maxSize!==null && $limit>0 && $this->maxSize<$limit)
  266. $limit=$this->maxSize;
  267. if(isset($_POST['MAX_FILE_SIZE']) && $_POST['MAX_FILE_SIZE']>0 && $_POST['MAX_FILE_SIZE']<$limit)
  268. $limit=$_POST['MAX_FILE_SIZE'];
  269. return $limit;
  270. }
  271. /**
  272. * Converts php.ini style size to bytes. Examples of size strings are: 150, 1g, 500k, 5M (size suffix
  273. * is case insensitive). If you pass here the number with a fractional part, then everything after
  274. * the decimal point will be ignored (php.ini values common behavior). For example 1.5G value would be
  275. * treated as 1G and 1073741824 number will be returned as a result. This method is public
  276. * (was private before) since 1.1.11.
  277. *
  278. * @param string $sizeStr the size string to convert.
  279. * @return integer the byte count in the given size string.
  280. * @since 1.1.11
  281. */
  282. public function sizeToBytes($sizeStr)
  283. {
  284. // get the latest character
  285. switch (strtolower(substr($sizeStr, -1)))
  286. {
  287. case 'm': return (int)$sizeStr * 1048576; // 1024 * 1024
  288. case 'k': return (int)$sizeStr * 1024; // 1024
  289. case 'g': return (int)$sizeStr * 1073741824; // 1024 * 1024 * 1024
  290. default: return (int)$sizeStr; // do nothing
  291. }
  292. }
  293. }