<?php
 use TCMS\TException;
 class FileUpload {
 public $overideFile = true;
 public $dateDir = false;
 public $filters = false;
 public $maxFileSize = 0;
 private $inputName = null;
 private $uploadDir = null;
 private $newFileName = null;
 private $fullFileName = null;
 private $errorMsg = [ 'not_found' => 'Input name {0} không tồn tại', 'empty' => 'Vui lòng chọn file', 'in_valid' => 'Đuôi file không hợp lệ', 'max_size' => 'Dung lượng file quá lớn, dung lượng tối đa là {0}', 'ini_size' => 'Dung lượng file vượt quá cấu hình trong php', 'cant_write' => 'Không có quyền upload file vào thư mục {0}', 'error' => 'Upload file thất bại' ];
 public function __construct($inputName, $uploadDir) {
 $this->inputName = $inputName;
 $this->uploadDir = $uploadDir;
 if(!$this->uploadDir || !trim($this->uploadDir)) {
 throw new TException("Vui lòng truyền upload dir cho file upload", 500);
 }
 $this->uploadDir = trim($this->uploadDir);
 }
 public function getFileName() {
 return $this->newFileName;
 }
 public function getFullFileName() {
 return $this->fullFileName;
 }
 public function setErrorMessage(array $errorMsg) {
 if($errorMsg) {
 array_merge($this->errorMsg, $errorMsg);
 }
 }
 public function save($fileName = null) {
 if(empty($_FILES[$this->inputName])) {
 throw new TException($this->errorMsg['not_found'], 500);
 }
 $this->createUploadDir();
 $files = $_FILES[$this->inputName];
 if(is_string($files['name'])) {
 if($this->uploadFile($fileName, $files)) return $this->getFileName();
 return false;
 }
 $this->newFileName = [];
 $this->fullFileName = [];
 foreach($files['name'] as $k => $file) {
 $this->uploadFiles($fileName, $files, $k);
 }
 return $this->getFileName();
 }
 private function uploadFile($fileName, $file) {
 if($this->isValid($file)) {
 if(!$fileName) {
 $fileName = $file['name'];
 }
 else {
 if($fileName instanceof \DateTime) {
 $fileName = $fileName->format('dmY_His') . '_' . rand() . '.' . $this->getExtFile($file['name']);
 }
 }
 if(!$this->overideFile) {
 $oFileName = $this->getOnlyFileName($fileName);
 $extFile = $this->getExtFile($fileName);
 $fileName = $this->createNewFileName($oFileName, $extFile, 0);
 }
 if(move_uploaded_file($file["tmp_name"], $this->uploadDir . $fileName)) {
 $this->newFileName = $fileName;
 $this->fullFileName = asset('/' . $fileName);
 return true;
 }
 else {
 throw new TException($this->errorMsg['error'], 500);
 }
 }
 return false;
 }
 private function uploadFiles($fileName, $file, $index) {
 $fInfo = [ 'name' => $file['name'][$index], 'type' => $file['type'][$index], 'size' => $file['size'][$index], 'error' => $file['error'][$index], 'tmp_name' => $file['tmp_name'][$index], ];
 if($this->isValid($fInfo)) {
 if(!$fileName) {
 $fileName = $fInfo['name'];
 }
 else {
 if($fileName instanceof \DateTime) {
 $fileName = $fileName->format('dmY_His') . '_' . rand() . '.' . $this->getExtFile($fInfo['name']);
 }
 }
 if(!$this->overideFile) {
 $oFileName = $this->getOnlyFileName($fileName);
 $extFile = $this->getExtFile($fileName);
 $fileName = $this->createNewFileName($oFileName, $extFile, 0);
 }
 if(move_uploaded_file($fInfo["tmp_name"], $this->uploadDir . $fileName)) {
 $this->newFileName[] = $fileName;
 $this->fullFileName[] = asset('/' . $this->uploadDir . '/' . $fileName);
 return true;
 }
 else {
 throw new TException($this->errorMsg['error'], 500);
 }
 }
 return false;
 }
 private function createUploadDir() {
 if($this->dateDir !== false) {
 if($this->dateDir === true) {
 $this->dateDir = 'd_m_Y';
 }
 $dt = new \DateTime();
 $this->uploadDir .= '/' . $dt->format($this->dateDir);
 }
 $exp = explode('/', $this->uploadDir);
 if(count($exp) == 1) {
 $exp = explode('\\', $this->uploadDir);
 }
 if(count($exp) == 1) {
 $this->uploadDir = ROOT_PATH . 'public' . DIRECTORY_SEPARATOR . $exp[0];
 if(!file_exists($this->uploadDir) || !is_dir($this->uploadDir)) {
 mkdir($this->uploadDir);
 }
 $this->uploadDir .= DIRECTORY_SEPARATOR;
 }
 else {
 $this->uploadDir = ROOT_PATH . 'public';
 foreach($exp as $v) {
 $this->uploadDir .= DIRECTORY_SEPARATOR . $v;
 if(!file_exists($this->uploadDir) || !is_dir($this->uploadDir)) {
 mkdir($this->uploadDir);
 }
 }
 $this->uploadDir .= DIRECTORY_SEPARATOR;
 }
 }
 private function isValid($file) {
 $errorCode = $file['error'];
 switch($errorCode) {
 case UPLOAD_ERR_OK: if($this->maxFileSize !== 0) {
 if($file['size'] > $this->maxFileSize) {
 throw new TException($this->errorMsg['max_size'], 500);
 }
 }
 if($this->filters) {
 if(!$this->filterFile($file)) {
 throw new TException($this->errorMsg['in_valid'], 500);
 }
 }
 return true;
 break;
 case UPLOAD_ERR_NO_FILE: throw new TException($this->errorMsg['empty'], 500);
 break;
 case UPLOAD_ERR_INI_SIZE: throw new TException($this->errorMsg['ini_size'], 500);
 break;
 case UPLOAD_ERR_FORM_SIZE: throw new TException($this->errorMsg['ini_size'], 500);
 break;
 case UPLOAD_ERR_CANT_WRITE: throw new TException($this->errorMsg['cant_write'], 500);
 break;
 case UPLOAD_ERR_NO_TMP_DIR: throw new TException($this->errorMsg['cant_write'], 500);
 break;
 case UPLOAD_ERR_EXTENSION: throw new TException('EXTENSION: ' . $this->errorMsg['error'], 500);
 break;
 default: throw new TException('ERROR: ' . $this->errorMsg['error'], 500);
 break;
 }
 }
 private function filterFile($file) {
 $exp = explode('|', $this->filters);
 if(!$exp) {
 return true;
 }
 $fileName = $file['name'];
 $type = $file['type'];
 $extFile = $this->getExtFile($fileName);
 foreach($exp as $v) {
 $e = trim($v);
 if(!$e || strlen($e) < 2) {
 continue;
 }
 $f = substr($e, 0, 2);
 if($f == "*.") {
 if(substr($e, 2) == $extFile) {
 return true;
 }
 continue;
 }
 if($e == $type) {
 return true;
 }
 }
 return false;
 }
 private function getExtFile($fileName) {
 return pathinfo($fileName, PATHINFO_EXTENSION);
 }
 private function createNewFileName($fileName, $extFile, $index) {
 $fName = $index === 0 ? $fileName : ($fileName . '(' . $index . ')');
 $fName .= '.' . $extFile;
 if(file_exists($this->uploadDir . $fName)) {
 return $this->createNewFileName($fileName, $extFile, $index + 1);
 }
 return $fName;
 }
 private function getOnlyFileName($fileName) {
 return pathinfo($fileName, PATHINFO_FILENAME);
 }
 }
 