1 class FileUpload { 2 /** 3 * 文件上传类 4 * @author lhm 5 * for example 6 * $up=new FileUpload(array('israndname'=>true, 7 * 'allowType'=>array('txt', 'doc', 'php', 'gif','jpg'), 8 * 'filepath'=>'./uploads/', 9 * 'maxSize'=>2000000)); 10 * $up->uploadFile('pic');//pic 为文件输入框name值 11 */ 12 private $filepath; //指定上传文件保存的路径 13 private $allowtype=array('gif', 'jpg', 'png', 'jpeg'); //充许上传文件的类型 14 private $maxsize=2000000; //允上传文件的最大长度 2M 15 private $israndname=true; //是否随机重命名, true false不随机,使用原文件名 16 private $originName; //源文件名称 17 private $tmpFileName; //临时文件名 18 private $fileType; //文件类型 19 private $fileSize; //文件大小 20 private $newFileName; //新文件名 21 private $errorNum=0; //错误号 22 private $errorMess=''; //用来提供错误报告 23 24 25 /** 26 * 用于上传文件初始化 27 * 用户可以不用按位置传参数,后面参数给值不用将前几个参数也提供值 28 */ 29 function __construct($options = array()){ 30 $allowOption = array('filepath','allowtype','maxsize','israndname'); 31 foreach($options as $key=>$val){ 32 $key = strtolower($key); 33 //查看用户参数中数组的下标是否和成员属性名相同 34 //if(!in_array($key,get_class_vars(get_class($this)))){ 35 if(!in_array($key, $allowOption)){ 36 $this->setOption('errorNum', 5); 37 $this->errorMess = $this->getError(); 38 continue 1; 39 } 40 $this->setOption($key, $val); 41 } 42 } 43 44 /** 45 * 46 * 用来检查文件上传路径 47 * @access private 48 * @return bool 49 */ 50 private function checkFilePath(){ 51 if(empty($this->filepath)) { 52 $this->setOption('errorNum', -5); 53 return false; 54 } 55 56 if(!file_exists($this->filepath) || !is_writable($this->filepath)){ 57 if(!@mkdir($this->filepath, 0755)){ 58 $this->setOption('errorNum', -4); 59 return false; 60 } 61 } 62 return true; 63 } 64 /** 65 * 66 * 用来检查文件上传的大小 67 * @access private 68 * @return bool 69 */ 70 private function checkFileSize() { 71 if($this->fileSize > $this->maxsize){ 72 $this->setOPtion('errorNum', -2); 73 return false; 74 }else{ 75 return true; 76 } 77 } 78 /** 79 * 80 * 用于检查文件上传类型 81 * @access private 82 * @return bool 83 */ 84 private function checkFileType() { 85 if(in_array(strtolower($this->fileType), $this->allowtype)) { 86 return true; 87 }else{ 88 $this->setOption('errorNum', -1); 89 return false; 90 } 91 } 92 /** 93 * 94 * 检查文件真实上传数量,如果文件名为空,则删除对应元素值 95 * @access private 96 * @param array $name 97 * @param array $tmpName 98 * @param array $size 99 * @param array $error 100 * @param array $fileField 101 */ 102 private function checkFileNum($name, $tmpName, $size, $error, $fileField){ 103 $continue = true; 104 for($i=0; $i < count($name); $i++){ 105 if ($name[$i] === ''){ 106 $name = $this->deleteArrayElement($name, $i);//线性删除 107 $tmpName = $this->deleteArrayElement($tmpName, $i); 108 $size = $this->deleteArrayElement($size, $i); 109 $error = $this->deleteArrayElement($error, $i); 110 $continue = false; 111 break 1; 112 } 113 } 114 if ($continue === false){ 115 $this->checkFileNum($name, $tmpName, $size, $error, $fileField);//递归 116 }else { 117 //将空空元素删除后重新赋给$_FILES 118 $_FILES[$fileField]['name'] = $name; 119 $_FILES[$fileField]['tmp_name'] = $tmpName; 120 $_FILES[$fileField]['size'] = $size; 121 $_FILES[$fileField]['error'] = $error; 122 } 123 124 } 125 /** 126 * 127 * 设置上传后的文件名称 128 * @access private 129 */ 130 private function setNewFileName(){ 131 if($this->israndname){ 132 $this->setOption('newFileName', $this->setRandName());//系统随机名 133 } else { 134 $this->setOption('newFileName', $this->originName);//沿用文件旧名 135 } 136 } 137 /** 138 * 139 * 设置随机文件名称 140 * @access private 141 * @return string 142 */ 143 private function setRandName(){ 144 $fileName = date("YmdHis").rand(100,999); 145 return $fileName.'.'.$this->fileType; 146 } 147 /** 148 * 149 * 自动生成属性并赋值 150 * @param string $key 151 * @param string $val 152 */ 153 private function setOption($key, $val){ 154 $this->$key=$val; 155 } 156 /** 157 * 158 * 用于上传文件 159 * @param string $fileField 160 */ 161 public function uploadFile($fileField){ 162 $return=true; 163 //检查初始化是否出错 164 if ($this->errorNum != 0){ 165 $this->errorMess = $this->getError(); 166 return false; 167 } 168 //检查文件上传路径 169 if(!$this->checkFilePath()){ 170 $this->errorMess = $this->getError(); 171 return false; 172 } 173 174 $this->checkFileNum($_FILES[$fileField]['name'],$_FILES[$fileField]['tmp_name'], 175 $_FILES[$fileField]['size'],$_FILES[$fileField]['error'], 176 $fileField); 177 $name = $_FILES[$fileField]['name']; 178 $tmpName = $_FILES[$fileField]['tmp_name']; 179 $size = $_FILES[$fileField]['size']; 180 $error = $_FILES[$fileField]['error']; 181 //print_r($name); 182 if(is_Array($name)){ 183 $errors = array(); 184 $count = count($name); 185 for($i=0; $i < $count; $i++){ 186 if($this->setFiles($name[$i], $tmpName[$i], $size[$i], $error[$i])){ 187 if(!$this->checkFileSize() || !$this->checkFileType()){ 188 $errors[] = $this->getError(); 189 $return=false; 190 } 191 }else{ 192 $error[] = $this->getError(); 193 $return = false; 194 } 195 196 if(!$return) 197 $this->setFiles(); 198 } 199 200 if($return){ 201 $fileNames = array(); 202 for($i = 0; $i < $count; $i++){ 203 if($this->setFiles($name[$i], $tmpName[$i], $size[$i], $error[$i])){ 204 $this->setNewFileName(); 205 if(!$this->copyFile()){ 206 $errors = $this->getError(); 207 $return = false; 208 }else{ 209 $fileNames[] = $this->newFileName; 210 } 211 } 212 } 213 214 $this->newFileName = $fileNames; 215 } 216 $this->errorMess = $errors; 217 }else{ 218 if($this->setFiles($name, $tmpName, $size, $error)){ 219 if($this->checkFileSize() && $this->checkFileType()){ 220 $this->setNewFileName(); 221 222 if($this->copyFile()){ 223 return true; 224 }else{ 225 $return = false; 226 } 227 228 }else{ 229 $return = false; 230 } 231 }else{ 232 $return = false; 233 } 234 235 if(!$return) 236 $this->errorMess = $this->getError(); 237 } 238 return $return; 239 } 240 /** 241 * 242 * 将临时文件移动到正式路径 243 * @access private 244 * @return bool 245 */ 246 private function copyFile(){ 247 if(!$this->errorNum){ 248 $filepath = rtrim($this->filepath, '/').'/'; 249 $filepath .= $this->newFileName; 250 251 if(@move_uploaded_file($this->tmpFileName, $filepath)) { 252 return true; 253 }else{ 254 $this->setOption('errorNum', -3); 255 return false; 256 } 257 258 }else{ 259 return false; 260 } 261 } 262 /** 263 * 设置文件属性的值 264 */ 265 private function setFiles($name = '', $tmpName = '', $size = 0, $error = 0){ 266 267 $this->setOption('errorNum', $error); 268 269 if($error){ 270 return false; 271 } 272 273 $this->setOption('originName', $name); 274 $this->setOption('tmpFileName', $tmpName); 275 $arrStr=explode('.', $name); 276 $this->setOption('fileType', strtolower($arrStr[count($arrStr)-1])); 277 $this->setOption('fileSize', $size); 278 279 return true; 280 } 281 /** 282 * 283 * 线性删除 284 * @access private 285 * @param array $array 286 * @param int $i 287 * @return array; 288 */ 289 private function deleteArrayElement($array , $i) { 290 $count = count($array); 291 for ($j = $i; $j < $count; $j ++){ 292 $array[$j] = $array [$j+1]; 293 } 294 array_pop ($array); 295 return $array ; 296 } 297 /** 298 * 299 * 用于获取上传后文件的文件名 300 * @access public 301 * @return string 302 */ 303 public function getNewFileName(){ 304 return $this->newFileName; 305 } 306 /** 307 * 308 * 获取上传错误信息 309 * @access private 310 * @return string 311 */ 312 private function getError(){ 313 $str='上传文件<font color="red">'.$this->originName.'</font>时出错:'; 314 315 switch($this->errorNum){ 316 case 5: $str .= '初始化参数出错'; 317 break; 318 case 4: $str .= '没有文件被上传'; 319 break; 320 case 3: $str .= '文件只被部分上传'; 321 break; 322 case 2: $str .= '上传文件超过了HTML表单中MAX_FILE_SIZE选项指定的值'; 323 break; 324 case 1: $str .= '上传文件超过了php.ini 中upload_max_filesize选项的值'; 325 break; 326 case -1: $str .= '末充许的类型'; 327 break; 328 case -2: $str .= '文件过大,上传文件不能超过'.$this->maxSize.'个字节'; 329 break; 330 case -3: $str .= '上传失败'; 331 break; 332 case -4: $str .= '建立存放上传文件目录失败,请重新指定上传目录'; 333 break; 334 case -5: $str .= '必须指定上传文件的路径'; 335 break; 336 default: $str .= '末知错误'; 337 } 338 339 return $str.'<br>'; 340 } 341 /** 342 * 343 * 查看错误报告 344 * @access public 345 * @return string 346 */ 347 public function getErrorMsg() { 348 return $this->errorMess; 349 } 350 }