/*
 *文件名为FileUpload.class.php
 *将与文件上传相关的成员属性和成员方法声明在一起
 */
    class FileUpload{
            private $filePath;                                  //保存上传文件将被保存的目的路径
            private $fileField;                                 //保存从$_FILES[$fileField]中获取上传文件信息
            private $originName;                           //保存上传文件的源文件明年
            private $tmpFileName;                       //保存上传文件的临时文件名
            private $fileType;                                //保存上传文件的类型
            private $fileSize;                                  //保存上传文件的大小
            private $newFileName;                       //保存上传文件的新文件名
            //用于保存上传文件允许的文件类型(保存文件后缀名数组)
            private $allowType = array('txt','html','php','js','css','jpg','gif','png','doc','swf','rar','zip');
            private $maxSize = 1000000000;          //允许文件上传的最大长度,默认为1MB
            private $isUserDefName = false;          //文件上传后,是否采用用户自定文件名
            private $userDefName;                         //保存用户自定义的上传文件mingc
            private $isRandName = false;              //上传文件是否使用随机文件名称
            private $randName;                             //保存系统随机命名的上传文件名称
            private $errorNum = 0;                        //保存系统自定义的错误号,默认值为0
            private $isCoverModer = true;            //上传文件是否覆盖原有的文件,默认值为TRUE
            
            /*
             * 构造方法,创建上传文件对象时为部分成员属性列表赋初值
             * 参数options:提供一个数组,数组下标为成员属性名称,元素值为属性设置的值
             */
            function __construct($options=array()){
                                $this->setOptions($options);                    //调用内容方法为上传文件的属性列表赋值
            }
            
            /*
             * 在对象外部调用该法处理上传文件
             * 参数filefield提供全局变量数组$_FILES是的第二维数组
             * 返回值 如果文件上传成功返回TRUE,如果失败则返回FALSE
             */
            function uploadFile($filefield){
                            $this->setOption('errorNum',0);                    //为错误位设置初值
                            $this->setOption('fileField',$filefield);          //通过参数设置成员属性fileField的值
                            $this->setFiles();                                             //调用成员方法设置文件信息
                            $this->checkValid();                                        //判断上传文件是否有效
                            $this->checkFilePath();                                   //检查保存上传文件的路径是否正确
                            $this->setNewFileName();                              //将上传文件设置为新文件名
                            if($this->errorNum <0)                                   //检查上传文件是否出错
                                return $this->errorNum;                            //如果出错退出函数并返回错误号 
                            return $this->copyFile();                                 //将上传文件移动到指定位置  
            }
            
            /*
             * 为成员属性列表赋初值
             *  参数options:提供一个数组,数组下标为成员属性名称,元素值为属性设置的值
             */
            
            private function setOptions($options = array()){
                        foreach($options as $key => $val){//遍历参数数组
                            //检查数组的下标是否和成员属性同名
                            if(!in_array($key, array('filePath','fileField','originName','allowType','maxSize','isUserDefName','userDefName','isRandName','randName'))){
                                continue;//如果数组中没有正确的下标则退出循环
                            }
                            $this->setOption($key,$val);//将数组中的值赋给对应数组下标的成员属性
                        }
            }
            
            /*
             * 从$_FILES数组中取值,赋给对应的成员属性
             */
            private function setFiles(){
                if($this->getFileErrorFromFILES()!=0){//检查上传文件是否出现错误
                    $this->setOption('errorNum',-1);//如果有错误则设置错误标号为-1
                    return $this->errorNum;                //退出函数不向下执行
                }
                //调用对象内部函数为保存上传文件源名的成员属性赋值
                $this->setOption('originName',$this->getFileNameFromFILES());
                
                //保存上传文件临时文件名的成员属性赋值
                $this->setOption('tmpFileName',$this->getTmpFileNameFromFILES());
                
                //类型
                $this->setOption('fileType',$this->getFileTypeFromFILES());
                
                //大小
                $this->setOption('fileSize',$this->getFileSizeFromFILES());                
            }
            
            /*
             *为指定的成员属性赋值
             *参数key:提供保存成员属性名的变量
             *参数val:提供将要为成员属性赋的值
             */
            private function setOpiton($key,$val){
                    $this->$key = $val; //为成员属性赋值
            }
            
            /*
             * 为上传文件设置新的文件名称
             */
            private function setNewFileName(){
                //如果不允许随机文件名并且不允许用户自定义文件名,则新文件件名为上传文件源名
                if($this->isRandName==false && $this->isUserDefName==false){
                    $this->setOption('newFileName', $this->originName);
                }elseif($this->isRandName==ture && $this->isUserDefName==false){
                    $this->setOption('newFileName',$this->proRandName().'.'.$this->fileType);
                }elseif($this->isRandName==false && $this->isUserDefName==true){
                    $this->setOption('newFileName',$this->userDefName);
                }else{
                    $this->setOption('errorNum',-4);//以上条件都不成立 设置错误为-4
                }
            }
            
            /*
             * 检查上传是否有效
             */
            private function checkValid(){
                $this->checkFileSize();//检查上传文件大小是否超出范围
                $this->checkFileType();//检查上传文件类型是否为允许的类型
            }
            
            /*
             * 检查上传文件类型是否为允许的类型
             */
            private function checkFileType(){
                if(!in_array($this->fileType, $this->allowType)){
                    $this->setOption('errorNum',-2);
                        return $this->errorNum;
                }
            }

            /*
             * 检查上传文件大小是否超出范围
             */
            private function checkFileSize(){
                if($this->fileSize > $this->maxSize){
                    $this->setOption('errorNum',-3);
                    return $this->errorNum;
                }
            }
            
            /*
             * 检查保存上传文件的路径是否有效
             */
            private function checkFilePath(){
               if(!file_exists($this->filePath)){
                    if($this->isCoverModer){
                            $this->makePath();
                    }else{
                            $this->setOption('errorNum',-6);
                    }
                }
            }
            
            /*
             * 随机产生上传文件的新文件名称
             */
            private function  proRandName(){
                $tmpStr = 'abcdefghijklmnopqrstuvwxyz0123456789';
                $str = "";
                $len =strlen($tmpStr);
                for($i=0;$i<8;$i++){
                    $num = rand(0,$len);
                    $str .=$tmpStr[$num];                    
                }
                return $str;
            }
            
            /*
             * 创建保存上传文件的路径
             */
            private function makePath(){
                if(!@mkdir($this->filePath,0755)){
                    $this->setOption('errorNum',-7);
                }
            }
            
            /*
             * 将上传文件从临时目录中复制到指定的新位置
             */
            private function copyFile(){
                $filePath = $this->filePath;
                
                if($filePath[strlen($filePath)-1] != '/'){
                    $filePath .='/';
                }
                
                $filePath .= $this->newFileName;
                if(!@move_uploaded_file($this->tmpFileName, $filePath)){
                    $this->setOption('errorNum',-5);
                }
                return $this->errorNum;                
            }
            
            /*
             * 从全局变量数组$_FILES中获取上传文件的错误标号
             */
            private function getFileErrorFromFILES(){
                return $this->filedField['error'];
            }
            
            /*
             * 获取文件的后缀名
             */
            private function getFileTypeFromFILES(){
                $str =$this->fileField['name'];
                $aryStr = split("./", $str);
                $ret = strtolower($aryStr[count($aryStr)-1]);
                return $ret;
            }
            
            /*
             * 从全局变量数组$_FILES中获取上传文件的名称
             */
            private  function getFileNameFromFILES(){
                return $this->fileField['name'];
            }
            
            /*
             * 获取临时文件名称
             */
            private  function getTmpFileNameFromFILES(){
                return $this->fileField['tmp_name'];
            }
            
            /*
             *获取文件大小
             */
            private function getFileSizeFromFILES(){
                return $this->fileField['size'];
            }
            
            /*
             * 根据错误标号返回对应的错误信息
             */
            public function getErrorMsg(){
                $str ="上传文件出错:";
                switch ($this->errorNum){
                    case -1:
                        $str .= "未知错误";
                        break;
                    case -2:
                        $str .= "未允许类型";
                        break;           
                    case -3:
                        $str .= "文件过大";
                        break;
                    case -4:
                        $str .= "产生文件名出错";
                        break;
                    case -5:
                        $str .= "上传失败";
                        break;
                    case -6:
                        $str .= "目录不存在";
                        break;
                    case -7:
                        $str .= "建立目录失败";
                        break;
                }
                return $str;
            }                 
    }