文件上传类

jerry thinkphp 2015年11月18日 收藏
一直做自己的项目,用到用户头像上传,一些现成的类有些我要的功能实现不了
于是自己写了个
另一个稍作改动版本:针对多文件返回数组 http://www.thinkphp.cn/code/371.html
<?php
/**
 * FileUpload.class.php
 * @Description 多文件上传类
 * @author: yulipu
 * Time: 2013-10-3
 *        include "FileUpload.class.php";
 *      $up=new FileUpload(array('savepath'=>'./mytest/'));
 *      $up->uploadFile('userfile');  //userfile 为input框的name值 多文件时input 的name值要有中括号: name="userfile[]" 没有中括号只能上传第一个文件
 *      echo $up->getErrorMsg();  //得到错误信息
 *         
 * 基本功能有 都以参数形式传入构造函数
 *         指定上传文件格式 [array] allowtype 
 *         指定文件大小     [int] maxsize
 *         
 * 实例1 上传头像到指定目录 并以随即名保存 文件名长度为20(默认为20)
 *         $up = new FileUpload(array('savepath'=>'./avatar/', 'israndname'=>true, 'newfilenamelength'=>20));
 * 实例2 上传头像到指定目录 并且用用户id作为文件名 如上传 photo.png 保存为 2.png
 *         $up = new FileUpload(array('savepath'=>'./avatar/', 'israndname'=>false, 'givenfilename'=>2));
 * 实例3 上传头像到指定目录 在目录下以日期为单位建立子目录保存头像
 *         $up = new FileUpload(array('savepath'=>'./avatar/', 'subdirpattern'=>'Y/m' , 'israndname'=>false, 'givenfilename'=>2));
 *         以上生成目录为 './avatar/2013/10'
 */
class FileUpload {
    private $name = 'name';
    private $type = 'type';
    private $tmp_name = 'tmp_name';
    private $error = 'error';
    private $size = 'size';

    // 构造方法用到的字段
    private $savepath = '';  //指定上传文件保存的路径
    private $subdirpattern = '';  // 结合savepath使用 为空表示不添加子目录,不为空 比如 'Y/m' 表示 2011/01 那么保存路径就是 $savepath  . '/2011/01'
    private $allowtype = array('gif', 'jpg', 'png');
    private $maxsize = 204800; //Byte 200K
    private $israndname = true;  //是否随机重命名 true false不随机 使用原文件名
    private $givenfilename = '';  //使用给定的文件名 配合 israndname 使用
    private $ignoreemptyfile = true;  //是否忽略没有上传文件的文本域
    private $newfilenamelength = 20;
    
    // 本类用到的字段
    private $errorMessage = '';
    private $uploadFileArray = null;
    private $originalFileName = '';
    private $expandedName = '';
    public $newFileName = '';
    
    
    //1. 指定上传路径, 2,充许的类型, 3,限制大小, 4,是否使用随机文件名称
    //new FileUpload( array('savepath'=>'./uploads/', 'allowtype'=>array('txt','gif'), 'israndname'=>true) );
    public function __construct($args=array()) {
        foreach($args as $key => $value) {
            $key = strtolower($key);
            //查看用户参数中数组的下标是否和成员属性名相同
            //if(!in_array( $key, get_class_vars(get_class($this)) )) {
            //    continue;
            //}
            $this->setArgs($key, $value);
        }
    }
    
    private function setArgs($key, $value) {
        $this->$key = $value;
    }
    
    /**
     * 得到文件大小
     * @param int size 字节数
     */
    private function getFileSize($size) {
        $unit = 'Bytes';
        if($size < 1024) {
            return $size.$unit;
        } else if($size < pow(1024, 2)) {
            $unit = 'KB';
            $size = round($size / 1024, 2);
        } else if($size < pow(1024, 3)) {
            $unit = 'MB';
            $size = round($size / pow(1024, 2), 2);
        } else if($size < pow(1024, 4)) {
            $unit = 'GB';
            $size = round($size / pow(1024, 3), 2);
        } else {
            $unit = 'TB';
            $size = round($size / pow(1024, 4), 2);
        }
        
        return $size.$unit;
    }
    
    /**
     * 得到一个数组的键组成的数组
     */
    private function myArray_keys(& $arr) {
        $returnArr = array();
        foreach($arr as $key => $val) {
            $returnArr[] = $key;
        }
        
        return $returnArr;
    }
/* 没排序时
Array
(
    [f1] => Array
        (
            [name] => Array
                (
                    [0] => Winter.jpg
                )
            // 凡是加了[] 这里的name格式就成了数组 这是才能支持多文件
            // 凡是不加[] 这里的name格式就是字符串 也就是只能上传第一个文件
            
            [type] => Array
                (
                    [0] => image/jpeg
                )

            [tmp_name] => Array
                (
                    [0] => C:\WINDOWS\TEMP\php38D.tmp
                )

            [error] => Array
                (
                    [0] => 0
                )

            [size] => Array
                (
                    [0] => 105542
                )

        )

)
*/
    
    /**
     * 重新排列上传文件
     * $uploadFileArray 上传的文件的数组
     */
    private function reSortFile(& $uploadFileArray) {
        // input name没有[] 时是字符串
        // 有[] 时是数组
        $multiFlag = is_array($uploadFileArray[$this->name]) ? true : false;
        $file_arr = array();
        
        $file_num = $multiFlag ? count($uploadFileArray[$this->name]) : 1;  //计算上传的文件数
        $file_keys = $this->myArray_keys($uploadFileArray);  //得到数组,包含了name type error tmp_name size
        
        for($i=0; $i<$file_num; $i++) {
            foreach($file_keys as $value) {
                $file_arr[$i][$value] = $multiFlag ? $uploadFileArray[$value][$i] : $uploadFileArray[$value];
            }
        }
        
        return $file_arr;
    }
    
    /**
     * 错误报告 
     * $errorno 错误号
     */
    private function setErrorMsg($errorno){
        $msg = "上传文件<font color='red'> {$this->originalFileName} </font>时出错: ";
        switch($errorno){
            case 1:
            case 2:
                $msg .= '文件过大,无法上传';  //配置文件中的大小
            case 3:
                $msg .= '文件只被部分上传'; break;
            case -1:
                $msg .= '不充许的文件类型'; break;
            case -2:
                $msg .= '文件过大,上传文件不能超过'.$this->getFileSize($this->maxsize); break;
            case -3: 
                $msg .= '上传失败'; break;
            case -4:
                $msg .= '建立存放上传文件目录失败,请重新指定上传目录'; break;
            case -5:
                $msg .= '必须指定上传文件的路径'; break;
            case -6:
                $msg .= '不是上传的文件'; break;
            default: $msg .=  "未知错误";
        }
        return $msg.'<br>';
    }
    
    /**
     * 检查有没有指定上传路径
     */
    private function emptySavePath() {
        if(empty($this->savepath)) {
            $this->errorMessage .= $this->setErrorMsg(-5);
            return true;
        }
        return false;
    }
    
    /**
     * 得到扩展名
     * $fileName 文件名
     */
    private function getExpandedName() {
        $pos = strrpos($this->originalFileName, '.');
        return substr($this->originalFileName, $pos+1);
    }
    
    /**
     * 检查文件扩展名是够合法
     */
    private function isLegalExpandedName() {
        if(in_array($this->expandedName, $this->allowtype)) {
            return true;
        }
        $this->errorMessage .= $this->setErrorMsg(-1);
        
        return false;
    }
    
    /**
     * 检查上传的文件有没有错误
     * $i 第几个文件
     */
    private function hasError($i) {
        $errorno = $this->uploadFileArray[$i][$this->error];
        if(0 == $errorno) {
            return 0; //文件正常
        } else if(4 == $errorno) {
            return 4;  //没有上传文件
        }
        $this->errorMessage .= $this->setErrorMsg($errorno);
        
        return 99;  //文件有错误
    }
    
    /**
     * 检查文件大小
     * $i 第几个文件
     */
    private function isLegalSize($i) {
        $fileSize = $this->uploadFileArray[$i][$this->size];
        if($fileSize <= $this->maxsize) {
            return true;
        }
        $this->errorMessage .= $this->setErrorMsg(-2);
        return false;
    }
    
    /**
     * 检查所给出的文件是否是通过HTTP POST上传的
     * $i 第几个文件
     */
    private function isUploadedFile($i) {
        $tmpName = $this->uploadFileArray[$i][$this->tmp_name];
        if(is_uploaded_file($tmpName)) {
            return true;
        }
        $this->errorMessage .= $this->setErrorMsg(-6);
        return false;
    }
    
    /**
     * 得到新文件名(如果用户指定不用新文件名则使用旧文件名)
     *
     */
    private function initNewFileName() {
        $str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $chars = $this->originalFileName;  // 有后缀 .jpg
        if($this->israndname) {
            $chars = '';
            for($i=0; $i<$this->newfilenamelength-8; $i++) {
                $chars .= substr($str, mt_rand(0, strlen($str)-1), 1);
            }
            $chars .= date('Ymd', time());
            $chars = $chars . '.' . $this->expandedName;
        } else {
            // 给定了使用指定的名字
            if('' != $this->givenfilename) {
                $chars = $this->givenfilename . '.' . $this->expandedName;
            }
        }
        
        return $chars;
    }
    
    /**
     * 复制文件到指定地方
     * $i 第几个文件
     */
    private function copyFile($i) {
        $this->newFileName = $this->initNewFileName();
        
        if(is_dir($this->savepath)) {
            @move_uploaded_file($this->uploadFileArray[$i][$this->tmp_name], $this->savepath.$this->newFileName);
        } else {
            die('上传目录创建失败');
        }
    }
    
    /**
     * 检查是否有空文件
     */
    private function chkEmptyFile(& $arr) {
        $flag = 1;
        for($i = 0; $i < count($arr); $i++) {
            if(intval($arr[$i][$this->error]) == 4) {
                $flag = 4;
                break;
            }
        }
        
        return $flag;
    }
    
    /**
     * 初始化上传文件夹
     */
    private function initSavePath() {
        $this->savepath = rtrim($this->savepath, '/') . '/';
        !empty($this->subdirpattern) && $this->savepath = $this->savepath . date($this->subdirpattern, time()) . '/';
        
        $tmpSavePath = rtrim($this->savepath, '/');
        if(!is_dir($tmpSavePath)) {
            $dirs = explode('/', $tmpSavePath);
            $realDir = '';
            for($i = 0; $i < count($dirs); $i++) {
                if($dirs[$i] == '') continue;
                if($dirs[$i] == '.') {
                    $realDir .= './';
                } else {
                    $realDir = $realDir . $dirs[$i] . '/';
                }
                
                if(!is_dir($realDir))
                    mkdir($realDir);
            }
        }
    }
    
    /**
     * 开始上传文件方法
     */
    private function startUpload() {
        for($i=0; $i<count($this->uploadFileArray); $i++) {
            if(0 === $this->hasError($i)) {
                $this->originalFileName = $this->uploadFileArray[$i][$this->name];  // aa.jpg
                $this->expandedName = $this->getExpandedName();
                if($this->isLegalExpandedName()) {
                    if($this->isLegalSize($i)) {
                        //if($this->isUploadedFile($i)) {
                            $this->copyFile($i);
                        //}
                    }
                }
            }
        }
    }
    
    /**
     * 上传文件 入口
     * $fileField input框的name属性值
     */
    public function uploadFile($fileField) {
        //检查上传路径
        if(true === $this->emptySavePath()) {
            return false;
        }
        
        if(0 !== count($_FILES)) {
            //重新排列上传文件
            $this->uploadFileArray = $this->reSortFile($_FILES[$fileField]);
            
            //开始上传文件
            if( !$this->ignoreemptyfile && 4 == $this->chkEmptyFile($this->uploadFileArray) ) {
                die('强制全部上传模式');
                
            } else {
                $this->initSavePath();  // 初始化上传路径
                $this->startUpload();
            }
        }
    }
     
    /**
     * de到错误信息 
     */     
    public function getErrorMsg() {
        return $this->errorMessage;
    }
    
    public function getUploadFileName() {
        return $this->savepath . $this->newFileName;
    }
}

?>

附件FileUpload.class.php.rar ( 3.81 KB 下载:77 次 )