1: <?php
  2:   3:   4:   5:   6:   7: 
  8: 
  9: namespace Wei;
 10: 
 11: use Wei\Validator\File as FileValidator;
 12: use Wei\Validator\Image;
 13: 
 14:  15:  16:  17:  18:  19: 
 20: class Upload extends Image
 21: {
 22:      23:  24:  25:  26: 
 27:     protected $postSizeMessage = 'No file uploaded or the total file size is too large, allowed maximum size is %postMaxSize%';
 28: 
 29:      30:  31: 
 32:     protected $noFileMessage = 'No file uploaded, please select a file to upload';
 33: 
 34:     protected $formLimitMessage = '%name% is larger than the MAX_FILE_SIZE value in the HTML form';
 35: 
 36:     protected $partialMessage = '%name% was partial uploaded, please try again';
 37: 
 38:     protected $noTmpDirMessage = 'The temporary upload directory is missing';
 39: 
 40:     protected $cantWriteMessage = 'Cannot write %name% to disk';
 41: 
 42:     protected $extensionMessage = 'File upload stopped by extension';
 43: 
 44:     protected $notUploadedFileMessage = 'No file uploaded';
 45: 
 46:     protected $cantMoveMessage = 'Cannot move uploaded file';
 47: 
 48:      49:  50:  51:  52: 
 53:     protected $name = 'file';
 54: 
 55:      56:  57:  58:  59:  60: 
 61:     protected $field;
 62: 
 63:      64:  65:  66:  67: 
 68:     protected $dir = 'uploads';
 69: 
 70:      71:  72:  73:  74: 
 75:     protected $fileName;
 76: 
 77:      78:  79:  80:  81:  82:  83:  84:  85:  86:  87: 
 88:     protected $isImage = false;
 89: 
 90:      91:  92:  93:  94:  95: 
 96:     protected $overwrite = false;
 97: 
 98:      99: 100: 101: 102: 
103:     protected $unitTest = false;
104: 
105:     106: 107: 108: 109: 
110:     protected $postMaxSize;
111: 
112:     113: 114: 115: 116: 
117:     public function __construct(array $options = array())
118:     {
119:         parent::__construct($options + array(
120:             'dir' => $this->dir
121:         ));
122:     }
123: 
124:     125: 126: 127: 128: 129: 130: 
131:     public function __invoke($field = null, $options = array())
132:     {
133:         
134:         if (is_string($field)) {
135:             $this->storeOption('field', $field);
136:             $options && $this->storeOption($options);
137:         
138:         } elseif (is_array($field)) {
139:             $field && $this->storeOption($field);
140:         }
141: 
142:         
143:         parent::reset();
144: 
145:         $uploadedFiles = $this->request->getParameterReference('file');
146: 
147:         
148:         if (!$this->field) {
149:             $this->field = key($uploadedFiles);
150:         }
151: 
152:         
153:         if (!isset($uploadedFiles[$this->field])) {
154:             $post = $this->request->getParameterReference('post');
155:             if (empty($uploadedFiles) && empty($post)) {
156:                 $error = 'postSize';
157:                 
158:                 $this->postMaxSize = $this->getIniSize('post_max_size');
159:             } else {
160:                 $error = 'noFile';
161:             }
162:             $this->addError($error);
163:             return false;
164:         }
165: 
166:         $uploadedFile = $uploadedFiles[$this->field];
167: 
168:         169: 170: 
171:         if ($uploadedFile['error'] !== UPLOAD_ERR_OK) {
172:             switch ($uploadedFile['error']) {
173:                 
174:                 case UPLOAD_ERR_INI_SIZE :
175:                     $this->sizeString = $this->fromBytes($uploadedFile['size']);
176:                     $this->maxSizeString = $this->getIniSize('upload_max_filesize');
177:                     $this->addError('maxSize');
178:                     break;
179: 
180:                 
181:                 case UPLOAD_ERR_FORM_SIZE :
182:                     $this->addError('formLimit');
183:                     break;
184: 
185:                 
186:                 
187:                 case UPLOAD_ERR_PARTIAL :
188:                     $this->addError('partial');
189:                     break;
190: 
191:                 
192:                 case UPLOAD_ERR_NO_TMP_DIR :
193:                     $this->addError('noTmpDir');
194:                     break;
195: 
196:                 
197:                 case UPLOAD_ERR_CANT_WRITE :
198:                     $this->addError('cantWrite');
199:                     break;
200: 
201:                 
202:                 case UPLOAD_ERR_EXTENSION :
203:                     $this->addError('extension');
204:                     break;
205: 
206:                 
207:                 case UPLOAD_ERR_NO_FILE :
208:                 default :
209:                     $this->addError('noFile');
210:             }
211:             return false;
212:         }
213: 
214:         if (!$this->isUploadedFile($uploadedFile['tmp_name'])) {
215:             $this->addError('notUploadedFile');
216:             return false;
217:         }
218: 
219:         
220:         if ($this->isImage || $this->maxWidth || $this->maxHeight || $this->minWidth || $this->minHeight) {
221:             $result = parent::doValidate($uploadedFile);
222:         } else {
223:             $result = FileValidator::doValidate($uploadedFile);
224:         }
225:         if (false === $result) {
226:             return false;
227:         }
228: 
229:         return $this->saveFile($uploadedFile);
230:     }
231: 
232:     233: 234: 235: 236: 237: 
238:     protected function saveFile($uploadedFile)
239:     {
240:         $ext = $this->getExt();
241:         $fullExt = $ext ? '.' . $ext : '';
242: 
243:         if ($this->fileName) {
244:             $fileName = $this->fileName;
245:         } else {
246:             $fileName = substr($uploadedFile['name'], 0, strlen($uploadedFile['name']) - strlen($fullExt));
247:         }
248: 
249:         $this->file = $this->dir . '/' . $fileName . $fullExt;
250:         if (!$this->overwrite) {
251:             $i = 1;
252:             while(is_file($this->file)) {
253:                 $this->file = $this->dir . '/' . $fileName . '-' . $i . $fullExt;
254:                 $i++;
255:             }
256:         }
257: 
258:         if (!$this->moveUploadedFile($uploadedFile['tmp_name'], $this->file)) {
259:             $this->addError('cantMove');
260:             return false;
261:         }
262: 
263:         return true;
264:     }
265: 
266:     267: 268: 269: 270: 
271:     public function getFile()
272:     {
273:         return $this->file;
274:     }
275: 
276: 
277:     278: 279: 280: 281: 282: 
283:     public function setDir($dir)
284:     {
285:         $dir = rtrim($dir, '/');
286:         if (!is_dir($dir)) {
287:             mkdir($dir, 0700, true);
288:         }
289:         $this->dir = $dir;
290: 
291:         return $this;
292:     }
293: 
294:     295: 296: 297: 298: 
299:     public function getDir()
300:     {
301:         return $this->dir;
302:     }
303: 
304:     305: 306: 307: 308: 309: 310: 
311:     protected function getIniSize($name)
312:     {
313:         $size = ini_get($name);
314:         return is_numeric($size) ? $this->fromBytes($size) : $size;
315:     }
316: 
317:     318: 319: 320: 321: 322: 323: 
324:     protected function isUploadedFile($file)
325:     {
326:         return $this->unitTest ? is_file($file) : is_uploaded_file($file);
327:     }
328: 
329:     330: 331: 332: 333: 334: 335: 336: 
337:     protected function moveUploadedFile($from, $to)
338:     {
339:         return $this->unitTest ? copy($from, $to) : @move_uploaded_file($from, $to);
340:     }
341: }
342: