分享一个关于TP6的上传文件类Upload.php - 风之涯技术博客

标签搜索

分享一个关于TP6的上传文件类Upload.php

小峰
2022年08月31日 / 7 评论 / 836 阅读 / 正在检测是否收录...
广告

废话不多说,直接上代码

  • 首先修改config文件下的filesystem.php文件

    <?php
    
    return [
      // 默认磁盘
      'default' => env('filesystem.driver', 'local'),
      // 磁盘列表
      'disks'   => [
          'local'  => [
              'type' => 'local',
              'root' => app()->getRuntimePath() . 'storage',
          ],
          'public' => [
              // 磁盘类型
              'type'       => 'local',
              // 磁盘路径
              'root'       => './upload',//app()->getRootPath() . 'public/upload', //这里修改成我这样即可,当然你可以自己定义你的路径
              // 磁盘路径对应的外部URL路径
              'url'        => '/upload',
              // 可见性
              'visibility' => '',//public
          ],
          // 更多的磁盘配置信息
      ],
      //以下完全是自定义,定义你的上传文件路径,自定义即可
      'filetype'  =>  [
          0   =>  'other',            //其他(未知)文件或图片
          1   =>  'images',           //图片
          2   =>  'images/logo',      //网站logo
          3   =>  'images/favicon',   //网站favicon
          4   =>  'images/avatar',    //用户头像
          5   =>  'images/article',   //文章配图
          6   =>  'images/source',    //资源配图
          7   =>  'images/carousel',  //轮播配图
          8   =>  'images/product',   //产品图片
          9   =>  'images/notice',    //通知图片
          10  =>  'images/sys',       //系统产生的图片
          11  =>  'images/chat',      //聊天图片
          12  =>  'images/liveroom',  //直播间头像
          13  =>  'images/book',      //书籍封面
          30  =>  'file',             //文件
          34  =>  'file/article',     //文章里面的文件
          35  =>  'file/source',      //资源文件
          37  =>  'file/product',     //产品文件
          38  =>  'file/notice',      //通知里面文件
          39  =>  'file/sys',         //系统产生的文件
          40  =>  'file/chat',        //聊天文件
      ]
    ];
  • upload.php
首先命名空间还是要定义的,我这里写在公共文件夹common里面了,app>commen>model 下
<?php
namespace app\common\model;
这里引用到Filesystem类,和think下的file的类(如果需要对图片作一些处理,需要自己改进引用到image类,需要自己安装tp下的image包)
use think\facade\Filesystem;
use think\File;
use think\Image; //自选
开始创建Upload类吧
class Upload{
    //初始化一些参数
    protected $field   ='file'; //请求字段
    protected $maxsize ='5*1024*1024';//最大上传大小5M
    protected $ext     ='';//限制上传后缀
    protected $rule    ='';//命名规则,md5/date/sha1 3种存储方式,默认以date方式
    protected $rename  =true;//是否重命名,默认true
    protected $type    =0;//默认上传目录
    protected $url     ='';//'/upload';
    protected $path    ='';//'./upload';
    protected $typepath='';//上传创建的路径
    protected $ischeck =false;//默认需要校验
    protected $config  =[];
    protected $validate='';
总得对初始化的参数做一些处理吧
    /**
     * Upload constructor.
     * @param $options
     */
    function __construct($options){
        $this->config=[
            'field'     =>  !empty($options['field'])?$options['field']:$this->field,
            'maxsize'   =>  !empty($options['maxsize'])?$options['maxsize']:$this->maxsize,
            'ext'       =>  !empty($options['ext'])?$options['ext']:$this->ext,
            'rule'      =>  !empty($options['rule'])?($options['rule']=='date'?'':$options['rule']):$this->rule,
            'rename'    =>  $options['rename']==false?$options['rename']:$this->rename,
            'type'      =>  $options['type']!=(null || '')?$options['type']:$this->type,
            'ischeck'   =>  !empty($options['ischeck'])?$options['ischeck']:$this->ischeck,
        ];//集中配置app()->config->get('filesystem.disks.public.url')
        $this->validate='filesize:'.$this->config['maxsize'].'|fileExt:'.$this->config['ext'];//集中验证规则
        $this->path=app()->config->get('filesystem.disks.public.root').'/'.$this->actdir($this->config['type']);
        $this->typepath=$this->actdir($this->config['type']);
        $this->url=app()->config->get('filesystem.disks.public.url').'/'.$this->actdir($this->config['type']);
    }
根据类型去创建对应的文件目录吧
    /**
     * @上传文件获取上传目录
     * @param int $type 0=公共文件目录,1=商品分类图标,2=商品图片,3=文章分类图标,4=文章封面图、插图,
     * 5=活动图片,6=会员头像存储,7=系统用户头像存储,8=评论、回复图片,9=广告图片,10=公告图片,11=消息图片,
     * 12=轮播图片,13=品牌图标,16=商品视频,17=活动(宣传)视频,18=文章视频,99=其他未知类型文件
     * @return string
     */
    private function actdir($type=0){
        // 这些类型在最上面的filesystem.php里面定义后去获取即可
//        $arr=[
//            0   =>  'other',            //其他(未知)文件或图片
//            1   =>  'images',           //图片
//            2   =>  'images/logo',      //网站logo
//            3   =>  'images/favicon',   //网站favicon
//            4   =>  'images/avatar',    //用户头像
//            5   =>  'images/article',   //文章配图
//            6   =>  'images/source',    //资源配图
//            7   =>  'images/carousel',  //轮播配图
//            8   =>  'images/product',   //产品图片
//            9   =>  'images/notice',    //通知图片
//            10  =>  'images/sys',       //系统产生的图片
//            11  =>  'images/chat',      //聊天图片
//            30  =>  'file',             //文件
//            34  =>  'file/article',     //文章里面的文件
//            35  =>  'file/source',      //资源文件
//            37  =>  'file/product',     //产品文件
//            38  =>  'file/notice',      //通知里面文件
//            39  =>  'file/sys',         //系统产生的文件
//            40  =>  'file/chat',        //聊天文件
//        ];
        $arr=app()->config->get('filesystem.filetype'); //获取初始定义的目录
        return $arr[$type];
    }
开始上传,也就是需要开始对上传的图片进行处理的地方了
    /**
     * @上传入口
     */
    public function uploadfile(){
        $files = request()->file($this->config['field']); //获取文件
        //判断存储目录是否存在,不存在则生成
        if(!file_exists($this->path)){
            mkdir($this->path,0777,true);//生成含有下级目录
        }
        if(is_array($files)){
            return self::handlemultfile($files);
        }else{
            return self::handleonlyfile($files);
        }
    }
handlemultfile多文件上传入口
    /**
     * @多文件上传
     * @param $files
     */
    private function handlemultfile($files){
        foreach($files as $file){
            return self::handleonlyfile($file);
        }
    }
handleonlyfile单文件上传入口
    /**
     * @单文件上传
     * @param $file
     */
    private function handleonlyfile($file){
        $fileSystem=new Filesystem();
        $oldname=$file->getOriginalName();//['name']; //获取原名称
        if($this->config['ischeck']) { //1.验证文件
            try{
                validate([$this->config['field']=>$this->validate])->check($file);
            }catch (\think\exception\ValidateException $e){
                return self::_error($e->getMessage());
            }
        }
        if($this->config['rename']) {//2.会按照规则重命名
            $info = $fileSystem::disk('public')->putFile( $this->typepath, $file, $this->config['rule']);
        }else{ //3.不会重命名,且不会覆盖
            $info = $fileSystem::disk('public')->putFileAs( $this->typepath.'/'.date('Ymd'), $file, $oldname);
        }
        if($info){ //$info是一个文件的路径
            $filepath=app()->config->get('filesystem.disks.public.root').'/'.$info;
            $fileNew=new File($filepath);
            $ext=$fileNew->extension();//获取文件后缀
            $fileName=$fileNew->getFilename();
            //处理商品图片文件
            if(in_array($ext,['png','jpg','jpeg','gif','tif','pic','ico','webp','pcx','bmp']) && $this->config['type']==8){
                self::thumbimg($filepath); //处理商品图片(type=8)
            }
            //存入数据库,返回id值
            return self::saveToBase($filepath);
        }else{
            return self::_error('上传出错,联系管理员');
        }
    }
获取文件后缀
    /**
    * 获取文件后缀,这个作法是不科学的,请使用原生的file的获取文件后缀
    **/
    private function getNameAndExt($filename){
        $arr=explode('.',$filename);
        return $arr;
    }
简单处理比如商品图片(此处只是示例,有需要的自己扩展) 这里需要引用Image包扩展
   /**
     * php裁剪图像
     * @param $filename
     */
    private function cropimg($filepath){
        $fileNew=new File($filepath);
        $fileNewPath=str_replace($fileNew->getFilename(),'',$filepath);
        $width=300;$height=300;$pwidth=100;$pheight=30;
        $image = Image::open($filepath);
        $arr=self::getNameAndExt($fileNew->getFilename());
        $newfilename=$arr[0].'_'.$width.'_'.$height.'.'.$arr[1];
        if($image->crop($width,$height,$pwidth,$pheight)->save($fileNewPath.$newfilename)){
            return true;
        }
        return false;
    }
    /**
     * php生成略缩图
     * @param $filename
     */
    private function thumbimg($filepath){
        $width=300;$height=300;
        $image= Image::open($filepath);
        $fileNew=new File($filepath);
        $arr=self::getNameAndExt($fileNew->getFilename());
        $newfilename1=$arr[0].'_'.$width.'_'.$height.'.'.$arr[1];
        $newfilename2=$arr[0].'_'.($width/6).'_'.($height/6).'.'.$arr[1];
        $newfilename3=$arr[0].'_'.($width/3).'_'.($height/3).'.'.$arr[1];
        $newfilename4=$arr[0].'_'.($width/2).'_'.($height/2).'.'.$arr[1];
        $image->thumb($width,$height)->save($this->path.'/'.date('Ymd').'/'.$newfilename1);
        $image->thumb($width/6,$height/6)->save($this->path.'/'.date('Ymd').'/'.$newfilename2);
        $image->thumb($width/3,$height/3)->save($this->path.'/'.date('Ymd').'/'.$newfilename3);
        $image->thumb($width/2,$height/2)->save($this->path.'/'.date('Ymd').'/'.$newfilename4);
    }
res方法是一个公共方法,在common.php里面自行创建
function res($code=0,$msg='',$data=null,$count=0){
    return json([
        'code'   =>  $code,
        'msg'    =>  $msg,
        'data'   =>  $data,
        'count'  =>  $count
    ]);
}
成功返回
失败返回
   /**
     * @成功返回
     * @param $data
     * @return \think\response\Json
     */
    private function _success($data){
        return res(0,'上传成功',$data,1);
    }

    /**
     * @失败返回
     * @param $msg
     * @return \think\response\Json
     */
    private function _error($msg){
        return res(1,$msg);
    }
存入数据库或OSS之类的在此处扩展,需要自己引入数据库model

CREATE TABLE `XX_files` (
  `id` char(32) NOT NULL COMMENT '图片ID',
  `filename` varchar(50) DEFAULT '' COMMENT '图片名称',
  `ext` varchar(20) DEFAULT '' COMMENT '扩展名',
  `size` int(10) DEFAULT '0' COMMENT '文件大小',
  `url` varchar(255) DEFAULT '' COMMENT '绝对请求地址',
  `path` varchar(255) DEFAULT '' COMMENT '物理地址',
  `type` tinyint(3) DEFAULT '0' COMMENT '图片分类',
  `cattype` varchar(20) DEFAULT 'Local' COMMENT '存储引擎,本地,xx云等',
  `addtime` datetime DEFAULT NULL COMMENT '创建时间',
  `isdel` smallint(12) unsigned DEFAULT '0' COMMENT '删除标志0=默认1=删除',
  `jsondata` text COMMENT '存入的JSON字符串',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE KEY `id` (`id`) USING BTREE,
  KEY `isdel` (`isdel`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='全部文件表';
   private function saveToBase($filepath){
       //如果需要存入OSS,这里需要自己扩展自己的代码
       //扩展代码
       //扩展代码,然后再进行存储存入后的路径
        $saveName=self::dir_replace($filepath);
        $fileNew=new File($filepath);
        $db=new Files(); //我这里叫files表,作演示
        $data=[
            'id'        =>  md5($fileNew->getFilename()),
            'filename'  =>  $fileNew->getFilename(),
            'ext'       =>  $fileNew->extension(),
            'size'      =>  filesize($filepath),
            'url'       =>  ltrim($saveName,'.'), //去掉左边第一个.
            'path'      =>  $saveName,
            'type'      =>  $this->config['type'],
            'cattype'   =>  'Local',//Local是存入本地的意思
            'addtime'   =>  toDate(),
        ];
        $data['jsondata']=json_encode($data,JSON_UNESCAPED_SLASHES);
        if($db->addData($data)){
            return $this->_success(json_encode($data,JSON_UNESCAPED_SLASHES));
        }else{
            return $this->_success(json_encode([
                'id'        =>  $data['filename'],
                'filename'  =>  $data['filename'],
                'ext'       =>  $data['ext'],
                'size'      =>  $data['size'],
                'url'       =>  $data['url'],
                'type'      =>  $this->config['type'],
                'path'      =>  $data['path'],
            ],JSON_UNESCAPED_SLASHES));
        }
    }
辅助方法 - 转换路径,便于在win和linux都能用
    /**
     * 替换相应的字符
     * @param string $path 路径
     * @return string
     */
    public function dir_replace($path){
        return str_replace('//','/',str_replace('\\','/',$path));
    }
base64位图片上传
    /**
     * 上传blob流文件
     * @param $imgfile
     * @param int $typeid
     * @return \think\response\Json
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function upload_avatar($imgfile,$mode=1){
        //接收
        $img=$imgfile;
        //文件夹日期
        $ymd = date("Ymd",time());
        //图片路径地址
        $fullpath = $this->path.'/'.$ymd;
        if(!is_dir($fullpath)){
            mkdir($fullpath,0777,true);
        }
        $types = empty($types)? array('jpg', 'gif', 'png', 'jpeg', 'ico'):$types;

        $img = str_replace(array('_','-'), array('/','+'), $img);

        $b64img = substr($img, 0,100);
        if(preg_match('/^(data:\s*image\/(\w+);base64,)/', $b64img, $matches)) {
            $ext = $matches[2];
            if (!in_array($ext, $types)) {
                return res(1,'文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。');
            }
            $img = str_replace($matches[1], '', $img);
            $img = base64_decode($img);
            $photo = '/' . md5(date('YmdHis') . rand(1000, 9999)) . '.' . $ext;
            file_put_contents($fullpath . $photo, $img);//写入图片
            //存入到数据库
            //$fileurl=$this->url.'/'.$ymd.$photo;//图片路径+文件ming
            $filepath = $this->path.'/'.$ymd.$photo;
            if($mode==1){
              return self::saveToBase($filepath);//存入数据库
            }
            //其他操作等
            // $data=[
            //     'id'        =>  md5($photo),
            //     'filename'  =>  $photo,
            //     'ext'       =>  $ext,
            //     'size'      =>  filesize($this->path.'/'.$ymd.$photo),
            //     'url'       =>  $this->url.'/'.$ymd.$photo,
            //     'path'      =>  $this->path.'/'.$ymd.$photo,
            //     'type'      =>  $this->config['type'],
            //     'cattype'   =>  'Local',//
            //     'addtime'   =>  toDate(),
            // ];
            // $data['jsondata']=json_encode($data,JSON_UNESCAPED_SLASHES);
            // $db=new Files();
            // if($db->addData($data)){
            //     return $this->_success(json_encode($data,JSON_UNESCAPED_SLASHES));
            // }else{
            //     return $this->_error('头像保存失败');
            // }
        }else{
            return $this->_error('您上传的头像已丢失,请重新上传!');
        }
    }
完整代码

自此,整个上传类就结束,如果有小伙伴发现问题,请及时反馈给我,大家相互学习。有任何疑问,评论区见。

1

评论 (11)

QQ
昵称
邮箱
取消
  1. 头像
    114222556
    Windows 10 . Google Chrome . 广东省深圳市

    kk

    回复
  2. 头像
    蛮强盗
    Windows 10 . FireFox . 广西

    写的很详细,辛苦了

    回复
    1. 头像
      小峰 作者
      Windows 10 . Google Chrome . 北京市丰台区
      @ 蛮强盗

      QQ

      回复
    2. 头像
      深情演绎
      Windows 10 . FireFox . 广西

      很好,学习了

      回复
      1. 头像
        小峰 作者
        Windows 10 . Google Chrome . 北京市丰台区
        @ 深情演绎

        QQ

        回复
      2. 头像
        脏兮兮
        Windows 10 . Google Chrome . 湖北省武汉市武昌区

        看看tp的

        回复
        1. 头像
          小峰 作者
          Windows 10 . Google Chrome . 北京市丰台区
          @ 脏兮兮

          QQ

          回复
        2. 头像
          星城哈哈
          Windows 10 . Google Chrome . 湖南省长沙市

          看一看

          回复
          1. 头像
            小峰 作者
            Windows 10 . Google Chrome . 北京市丰台区
            @ 星城哈哈

            QQ

            回复
          2. 头像
            谀而不迂
            Windows 10 . QQ Browser . 贵州省黔南州都匀市

            看看

            回复
            1. 头像
              小峰 作者
              Windows 10 . Google Chrome . 北京市丰台区
              @ 谀而不迂

              欢迎QQ

              回复