├── README.md ├── test.php └── upload.php /README.md: -------------------------------------------------------------------------------- 1 | Simple php upload class with file validation. 2 | ============================================= 3 | 4 | You need to install (or enable in php.ini) PHP "file info" extension. 5 | 6 | Link: http://us2.php.net/manual/en/fileinfo.installation.php 7 | 8 | ### **Quick start** 9 | 10 | ```php 11 | file($_FILES['test']); 18 | 19 | $results = $upload->upload(); 20 | 21 | var_dump($results); 22 | 23 | } 24 | ``` 25 | 26 | ### **Simple validation** 27 | 28 | ```php 29 | file($_FILES['test']); 37 | 38 | //set max. file size (in mb) 39 | $upload->set_max_file_size(1); 40 | 41 | //set allowed mime types 42 | $upload->set_allowed_mime_types(array('application/pdf')); 43 | 44 | $results = $upload->upload(); 45 | 46 | var_dump($results); 47 | } 48 | ``` 49 | 50 | ### **Callbacks** 51 | 52 | ```php 53 | file['original_filename']) > 5) { 61 | 62 | $object->set_error('File name is too long.'); 63 | 64 | } 65 | 66 | } 67 | 68 | } 69 | 70 | 71 | if (!empty($_FILES['test'])) { 72 | 73 | $upload = Upload::factory('important/files'); 74 | $upload->file($_FILES['test']); 75 | 76 | $validation = new validation; 77 | 78 | $upload->callbacks($validation, array('check_name_length')); 79 | 80 | $results = $upload->upload(); 81 | 82 | var_dump($results); 83 | 84 | } 85 | ``` 86 | 87 | ### **$result dump** 88 | 89 | ```php 90 | array 91 | 'status' => boolean false 92 | 'destination' => string 'important/files/' (length=16) 93 | 'size_in_bytes' => int 466028 94 | 'size_in_mb' => float 0.44 95 | 'mime' => string 'application/pdf' (length=15) 96 | 'original_filename' => string 'About Stacks.pdf' (length=16) 97 | 'tmp_name' => string '/private/var/tmp/phpXF2V7o' (length=26) 98 | 'post_data' => 99 | array 100 | 'name' => string 'About Stacks.pdf' (length=16) 101 | 'type' => string 'application/pdf' (length=15) 102 | 'tmp_name' => string '/private/var/tmp/phpXF2V7o' (length=26) 103 | 'error' => int 0 104 | 'size' => int 466028 105 | 'errors' => 106 | array 107 | 0 => string 'File name is too long.' (length=22) 108 | ``` 109 | 110 | --- 111 | 112 | ```php 113 | $upload->upload(); 114 | ``` 115 | 116 | is equivalent 117 | ```php 118 | if ($upload->check()) { 119 | $upload->save(); 120 | } 121 | $upload->get_state(); 122 | ``` 123 | 124 | --- 125 | Use this to get validation errors. 126 | 127 | ```php 128 | $upload->get_errors(); 129 | ``` 130 | 131 | --- 132 | 133 | When upload done you also get new filename and full path 134 | 135 | ```php 136 | 'filename' => string '091755cc57ee634186cd2655c3a0ec990c36f9161322940586' (length=50) 137 | 'full_path' => string 'important/files/091755cc57ee634186cd2655c3a0ec990c36f9161322940586' (length=66) 138 | ``` 139 | -------------------------------------------------------------------------------- /test.php: -------------------------------------------------------------------------------- 1 | file['original_filename']) > 5) { 10 | 11 | $object->set_error('File name is too long.'); 12 | 13 | } 14 | 15 | } 16 | 17 | } 18 | 19 | 20 | if (!empty($_FILES['test'])) { 21 | 22 | $upload = Upload::factory('important/files'); 23 | $upload->file($_FILES['test']); 24 | 25 | $validation = new validation; 26 | 27 | $upload->callbacks($validation, array('check_name_length')); 28 | 29 | $results = $upload->upload(); 30 | 31 | var_dump($results); 32 | 33 | } 34 | 35 | ?> 36 | 37 | 38 |
-------------------------------------------------------------------------------- /upload.php: -------------------------------------------------------------------------------- 1 | root = $root; 147 | 148 | } else { 149 | 150 | $this->root = $_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR; 151 | } 152 | 153 | // set & create destination path 154 | if (!$this->set_destination($destination)) { 155 | 156 | throw new Exception('Upload: Can\'t create destination. '.$this->root . $this->destination); 157 | 158 | } 159 | 160 | //create finfo object 161 | $this->finfo = new finfo(); 162 | 163 | } 164 | 165 | /** 166 | * Set target filename 167 | * 168 | * @param string $filename 169 | */ 170 | public function set_filename($filename) { 171 | 172 | $this->filename = $filename; 173 | 174 | } 175 | 176 | /** 177 | * Check & Save file 178 | * 179 | * Return data about current upload 180 | * 181 | * @return array 182 | */ 183 | public function upload($filename = false) { 184 | 185 | if( $filename ) { 186 | 187 | $this->set_filename($filename); 188 | 189 | } 190 | 191 | $this->set_filename($filename); 192 | 193 | if ($this->check()) { 194 | 195 | $this->save(); 196 | 197 | } 198 | 199 | // return state data 200 | return $this->get_state(); 201 | 202 | } 203 | 204 | 205 | /** 206 | * Save file on server 207 | * 208 | * Return state data 209 | * 210 | * @return array 211 | */ 212 | public function save() { 213 | 214 | $this->save_file(); 215 | 216 | return $this->get_state(); 217 | 218 | } 219 | 220 | 221 | /** 222 | * Validate file (execute callbacks) 223 | * 224 | * Returns TRUE if validation successful 225 | * 226 | * @return bool 227 | */ 228 | public function check() { 229 | 230 | //execute callbacks (check filesize, mime, also external callbacks 231 | $this->validate(); 232 | 233 | //add error messages 234 | $this->file['errors'] = $this->get_errors(); 235 | 236 | //change file validation status 237 | $this->file['status'] = empty($this->validation_errors); 238 | 239 | return $this->file['status']; 240 | 241 | } 242 | 243 | 244 | /** 245 | * Get current state data 246 | * 247 | * @return array 248 | */ 249 | public function get_state() { 250 | 251 | return $this->file; 252 | 253 | } 254 | 255 | 256 | /** 257 | * Save file on server 258 | */ 259 | protected function save_file() { 260 | 261 | //create & set new filename 262 | if(empty($this->filename)){ 263 | $this->create_new_filename(); 264 | } 265 | 266 | //set filename 267 | $this->file['filename'] = $this->filename; 268 | 269 | //set full path 270 | $this->file['full_path'] = $this->root . $this->destination . $this->filename; 271 | $this->file['path'] = $this->destination . $this->filename; 272 | 273 | $status = move_uploaded_file($this->tmp_name, $this->file['full_path']); 274 | 275 | //checks whether upload successful 276 | if (!$status) { 277 | throw new Exception('Upload: Can\'t upload file.'); 278 | } 279 | 280 | //done 281 | $this->file['status'] = true; 282 | 283 | } 284 | 285 | 286 | /** 287 | * Set data about file 288 | */ 289 | protected function set_file_data() { 290 | 291 | $file_size = $this->get_file_size(); 292 | 293 | $this->file = array( 294 | 'status' => false, 295 | 'destination' => $this->destination, 296 | 'size_in_bytes' => $file_size, 297 | 'size_in_mb' => $this->bytes_to_mb($file_size), 298 | 'mime' => $this->get_file_mime(), 299 | 'original_filename' => $this->file_post['name'], 300 | 'tmp_name' => $this->file_post['tmp_name'], 301 | 'post_data' => $this->file_post, 302 | ); 303 | 304 | } 305 | 306 | /** 307 | * Set validation error 308 | * 309 | * @param string $message 310 | */ 311 | public function set_error($message) { 312 | 313 | $this->validation_errors[] = $message; 314 | 315 | } 316 | 317 | 318 | /** 319 | * Return validation errors 320 | * 321 | * @return array 322 | */ 323 | public function get_errors() { 324 | 325 | return $this->validation_errors; 326 | 327 | } 328 | 329 | 330 | /** 331 | * Set external callback methods 332 | * 333 | * @param object $instance_of_callback_object 334 | * @param array $callback_methods 335 | */ 336 | public function callbacks($instance_of_callback_object, $callback_methods) { 337 | 338 | if (empty($instance_of_callback_object)) { 339 | 340 | throw new Exception('Upload: $instance_of_callback_object can\'t be empty.'); 341 | 342 | } 343 | 344 | if (!is_array($callback_methods)) { 345 | 346 | throw new Exception('Upload: $callback_methods data type need to be array.'); 347 | 348 | } 349 | 350 | $this->external_callback_object = $instance_of_callback_object; 351 | $this->external_callback_methods = $callback_methods; 352 | 353 | } 354 | 355 | 356 | /** 357 | * Execute callbacks 358 | */ 359 | protected function validate() { 360 | 361 | //get curent errors 362 | $errors = $this->get_errors(); 363 | 364 | if (empty($errors)) { 365 | 366 | //set data about current file 367 | $this->set_file_data(); 368 | 369 | //execute internal callbacks 370 | $this->execute_callbacks($this->callbacks, $this); 371 | 372 | //execute external callbacks 373 | $this->execute_callbacks($this->external_callback_methods, $this->external_callback_object); 374 | 375 | } 376 | 377 | } 378 | 379 | 380 | /** 381 | * Execute callbacks 382 | */ 383 | protected function execute_callbacks($callbacks, $object) { 384 | 385 | foreach($callbacks as $method) { 386 | 387 | $object->$method($this); 388 | 389 | } 390 | 391 | } 392 | 393 | 394 | /** 395 | * File mime type validation callback 396 | * 397 | * @param object $object 398 | */ 399 | protected function check_mime_type($object) { 400 | 401 | if (!empty($object->mimes)) { 402 | 403 | if (!in_array($object->file['mime'], $object->mimes)) { 404 | 405 | $object->set_error('Mime type not allowed.'); 406 | 407 | } 408 | 409 | } 410 | 411 | } 412 | 413 | 414 | /** 415 | * Set allowed mime types 416 | * 417 | * @param array $mimes 418 | */ 419 | public function set_allowed_mime_types($mimes) { 420 | 421 | $this->mimes = $mimes; 422 | 423 | //if mime types is set -> set callback 424 | $this->callbacks[] = 'check_mime_type'; 425 | 426 | } 427 | 428 | 429 | /** 430 | * File size validation callback 431 | * 432 | * @param object $object 433 | */ 434 | protected function check_file_size($object) { 435 | 436 | if (!empty($object->max_file_size)) { 437 | 438 | $file_size_in_mb = $this->bytes_to_mb($object->file['size_in_bytes']); 439 | 440 | if ($object->max_file_size <= $file_size_in_mb) { 441 | 442 | $object->set_error('File is too big.'); 443 | 444 | } 445 | 446 | } 447 | 448 | } 449 | 450 | 451 | /** 452 | * Set max. file size 453 | * 454 | * @param int $size 455 | */ 456 | public function set_max_file_size($size) { 457 | 458 | $this->max_file_size = $size; 459 | 460 | //if max file size is set -> set callback 461 | $this->callbacks[] = 'check_file_size'; 462 | 463 | } 464 | 465 | 466 | /** 467 | * Set File array to object 468 | * 469 | * @param array $file 470 | */ 471 | public function file($file) { 472 | 473 | $this->set_file_array($file); 474 | 475 | } 476 | 477 | 478 | /** 479 | * Set file array 480 | * 481 | * @param array $file 482 | */ 483 | protected function set_file_array($file) { 484 | 485 | //checks whether file array is valid 486 | if (!$this->check_file_array($file)) { 487 | 488 | //file not selected or some bigger problems (broken files array) 489 | $this->set_error('Please select file.'); 490 | 491 | } 492 | 493 | //set file data 494 | $this->file_post = $file; 495 | 496 | //set tmp path 497 | $this->tmp_name = $file['tmp_name']; 498 | 499 | } 500 | 501 | 502 | /** 503 | * Checks whether Files post array is valid 504 | * 505 | * @return bool 506 | */ 507 | protected function check_file_array($file) { 508 | 509 | return isset($file['error']) 510 | && !empty($file['name']) 511 | && !empty($file['type']) 512 | && !empty($file['tmp_name']) 513 | && !empty($file['size']); 514 | 515 | } 516 | 517 | 518 | /** 519 | * Get file mime type 520 | * 521 | * @return string 522 | */ 523 | protected function get_file_mime() { 524 | 525 | return $this->finfo->file($this->tmp_name, FILEINFO_MIME_TYPE); 526 | 527 | } 528 | 529 | 530 | /** 531 | * Get file size 532 | * 533 | * @return int 534 | */ 535 | protected function get_file_size() { 536 | 537 | return filesize($this->tmp_name); 538 | 539 | } 540 | 541 | 542 | /** 543 | * Set destination path (return TRUE on success) 544 | * 545 | * @param string $destination 546 | * @return bool 547 | */ 548 | protected function set_destination($destination) { 549 | 550 | $this->destination = $destination . DIRECTORY_SEPARATOR; 551 | 552 | return $this->destination_exist() ? TRUE : $this->create_destination(); 553 | 554 | } 555 | 556 | 557 | /** 558 | * Checks whether destination folder exists 559 | * 560 | * @return bool 561 | */ 562 | protected function destination_exist() { 563 | 564 | return is_writable($this->root . $this->destination); 565 | 566 | } 567 | 568 | 569 | /** 570 | * Create path to destination 571 | * 572 | * @param string $dir 573 | * @return bool 574 | */ 575 | protected function create_destination() { 576 | 577 | return mkdir($this->root . $this->destination, $this->default_permissions, true); 578 | 579 | } 580 | 581 | 582 | /** 583 | * Set unique filename 584 | * 585 | * @return string 586 | */ 587 | protected function create_new_filename() { 588 | 589 | $filename = sha1(mt_rand(1, 9999) . $this->destination . uniqid()) . time(); 590 | $this->set_filename($filename); 591 | 592 | } 593 | 594 | 595 | /** 596 | * Convert bytes to mb. 597 | * 598 | * @param int $bytes 599 | * @return int 600 | */ 601 | protected function bytes_to_mb($bytes) { 602 | 603 | return round(($bytes / 1048576), 2); 604 | 605 | } 606 | 607 | 608 | } // end of Upload 609 | --------------------------------------------------------------------------------