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-2015 Zend Technologies USA Inc. (http://www.zend.com) 7 * @license http://framework.zend.com/license/new-bsd New BSD License 8 */ 9 10namespace Zend\Validator\File; 11 12use Zend\Validator\AbstractValidator; 13use Zend\Validator\Exception; 14 15/** 16 * Validator for counting all given files 17 * 18 */ 19class Count extends AbstractValidator 20{ 21 /**#@+ 22 * @const string Error constants 23 */ 24 const TOO_MANY = 'fileCountTooMany'; 25 const TOO_FEW = 'fileCountTooFew'; 26 /**#@-*/ 27 28 /** 29 * @var array Error message templates 30 */ 31 protected $messageTemplates = array( 32 self::TOO_MANY => "Too many files, maximum '%max%' are allowed but '%count%' are given", 33 self::TOO_FEW => "Too few files, minimum '%min%' are expected but '%count%' are given", 34 ); 35 36 /** 37 * @var array Error message template variables 38 */ 39 protected $messageVariables = array( 40 'min' => array('options' => 'min'), 41 'max' => array('options' => 'max'), 42 'count' => 'count' 43 ); 44 45 /** 46 * Actual filecount 47 * 48 * @var int 49 */ 50 protected $count; 51 52 /** 53 * Internal file array 54 * @var array 55 */ 56 protected $files; 57 58 /** 59 * Options for this validator 60 * 61 * @var array 62 */ 63 protected $options = array( 64 'min' => null, // Minimum file count, if null there is no minimum file count 65 'max' => null, // Maximum file count, if null there is no maximum file count 66 ); 67 68 /** 69 * Sets validator options 70 * 71 * Min limits the file count, when used with max=null it is the maximum file count 72 * It also accepts an array with the keys 'min' and 'max' 73 * 74 * If $options is an integer, it will be used as maximum file count 75 * As Array is accepts the following keys: 76 * 'min': Minimum filecount 77 * 'max': Maximum filecount 78 * 79 * @param int|array|\Traversable $options Options for the adapter 80 */ 81 public function __construct($options = null) 82 { 83 if (is_string($options) || is_numeric($options)) { 84 $options = array('max' => $options); 85 } 86 87 if (1 < func_num_args()) { 88 $options['min'] = func_get_arg(0); 89 $options['max'] = func_get_arg(1); 90 } 91 92 parent::__construct($options); 93 } 94 95 /** 96 * Returns the minimum file count 97 * 98 * @return int 99 */ 100 public function getMin() 101 { 102 return $this->options['min']; 103 } 104 105 /** 106 * Sets the minimum file count 107 * 108 * @param int|array $min The minimum file count 109 * @return Count Provides a fluent interface 110 * @throws Exception\InvalidArgumentException When min is greater than max 111 */ 112 public function setMin($min) 113 { 114 if (is_array($min) and isset($min['min'])) { 115 $min = $min['min']; 116 } 117 118 if (!is_string($min) and !is_numeric($min)) { 119 throw new Exception\InvalidArgumentException('Invalid options to validator provided'); 120 } 121 122 $min = (int) $min; 123 if (($this->getMax() !== null) && ($min > $this->getMax())) { 124 throw new Exception\InvalidArgumentException( 125 "The minimum must be less than or equal to the maximum file count, but {$min} > {$this->getMax()}" 126 ); 127 } 128 129 $this->options['min'] = $min; 130 return $this; 131 } 132 133 /** 134 * Returns the maximum file count 135 * 136 * @return int 137 */ 138 public function getMax() 139 { 140 return $this->options['max']; 141 } 142 143 /** 144 * Sets the maximum file count 145 * 146 * @param int|array $max The maximum file count 147 * @return Count Provides a fluent interface 148 * @throws Exception\InvalidArgumentException When max is smaller than min 149 */ 150 public function setMax($max) 151 { 152 if (is_array($max) and isset($max['max'])) { 153 $max = $max['max']; 154 } 155 156 if (!is_string($max) and !is_numeric($max)) { 157 throw new Exception\InvalidArgumentException('Invalid options to validator provided'); 158 } 159 160 $max = (int) $max; 161 if (($this->getMin() !== null) && ($max < $this->getMin())) { 162 throw new Exception\InvalidArgumentException( 163 "The maximum must be greater than or equal to the minimum file count, but {$max} < {$this->getMin()}" 164 ); 165 } 166 167 $this->options['max'] = $max; 168 return $this; 169 } 170 171 /** 172 * Adds a file for validation 173 * 174 * @param string|array $file 175 * @return Count 176 */ 177 public function addFile($file) 178 { 179 if (is_string($file)) { 180 $file = array($file); 181 } 182 183 if (is_array($file)) { 184 foreach ($file as $name) { 185 if (!isset($this->files[$name]) && !empty($name)) { 186 $this->files[$name] = $name; 187 } 188 } 189 } 190 191 return $this; 192 } 193 194 /** 195 * Returns true if and only if the file count of all checked files is at least min and 196 * not bigger than max (when max is not null). Attention: When checking with set min you 197 * must give all files with the first call, otherwise you will get a false. 198 * 199 * @param string|array $value Filenames to check for count 200 * @param array $file File data from \Zend\File\Transfer\Transfer 201 * @return bool 202 */ 203 public function isValid($value, $file = null) 204 { 205 if (($file !== null) && !array_key_exists('destination', $file)) { 206 $file['destination'] = dirname($value); 207 } 208 209 if (($file !== null) && array_key_exists('tmp_name', $file)) { 210 $value = $file['destination'] . DIRECTORY_SEPARATOR . $file['name']; 211 } 212 213 if (($file === null) || !empty($file['tmp_name'])) { 214 $this->addFile($value); 215 } 216 217 $this->count = count($this->files); 218 if (($this->getMax() !== null) && ($this->count > $this->getMax())) { 219 return $this->throwError($file, self::TOO_MANY); 220 } 221 222 if (($this->getMin() !== null) && ($this->count < $this->getMin())) { 223 return $this->throwError($file, self::TOO_FEW); 224 } 225 226 return true; 227 } 228 229 /** 230 * Throws an error of the given type 231 * 232 * @param string $file 233 * @param string $errorType 234 * @return false 235 */ 236 protected function throwError($file, $errorType) 237 { 238 if ($file !== null) { 239 if (is_array($file)) { 240 if (array_key_exists('name', $file)) { 241 $this->value = $file['name']; 242 } 243 } elseif (is_string($file)) { 244 $this->value = $file; 245 } 246 } 247 248 $this->error($errorType); 249 return false; 250 } 251} 252