• Thinkphp-商城项目之oss文件上传及web端直传


    4.3头像上传

    一般商城网站都会把文件上传到第三方云,例如阿里云(oss),腾讯云(cos),当然如果公司有足够的实力,可以自己部署一台文件服务器,用于文件的保存。

    头像上传一般是用户在用户中心上传的,后台管理员可以编辑用户资料,其中就有头像上传,因此这个模块就先讲讲文件上传这个知识点。

    源码:https://gitee.com/myha/demo-shop

    4.3.1阿里云OSS

    首先打开官方文档https://help.aliyun.com/zh/oss/product-overview/?spm=a2c4g.11186623.0.0.625b6f1bjn1FsU。还是按照我们之前阅读文档的重点:概述、快速开始、提供的例子

    第一、购买服务

    https://help.aliyun.com/zh/oss/getting-started/console-quick-start?spm=a2c4g.11186623.0.0.4d425d6bcx5NWi根据文档这一章节的步骤来

    打开https://www.aliyun.com/product/oss?spm=a2c4g.11186623.J_4VYgf18xNlTAyFFbOuOQe.32.5e134425TurhoY,注册/登录阿里云账号

    在这里插入图片描述

    在这里插入图片描述

    购买成功后我们创建一个bucket,

    在这里插入图片描述

    4.3.2上传实现

    首先第一步就是安装

    composer require aliyuncs/oss-sdk-php
    
    • 1

    接下来就把它提供的代码示例抄下来修改即可:https://help.aliyun.com/zh/oss/developer-reference/simple-upload?spm=a2c4g.11186623.0.0.6c745d6bfD4WM5

    app->common->lib目录下新建oss->OSs.php

    
    // +----------------------------------------------------------------------
    // | OSS存储
    // +----------------------------------------------------------------------
    namespace app\common\lib\oss;
    
    use OSS\OssClient;
    use OSS\Core\OssException;
    use think\facade\Log;
    
    class Oss{
    
        //初始化oss客户端
        private static function createOssClient(){
            $accessKeyId = env('oss.access_key_id');
            $accessKeySecret = env('oss.access_key_secret');
            $endpoint = env('oss.endpoint');
            try {
                return new OssClient($accessKeyId, $accessKeySecret, $endpoint);
            } catch (OssException $e) {
                Log::error("初始化oss客户端异常:".$e->getMessage());
                serviceException();
            }
        }
        
        /**
         * 上传文件
         * @param  string     $object     目标文件
         * @param  string     $filePath    源文件
         */
        public static function uploadFile($object,$filePath){
            $bucket = env('oss.bucket');
            try {
                $ossClient = self::createOssClient();
                $result = $ossClient->uploadFile($bucket, $object, $filePath);
                return $result['info'];
            }catch (OssException $e) {
                Log::error("OSS上传文件失败:".$e->getMessage());
                serviceException();
            }
        }
    
        /**
         * 上传文件
         * @param  string     $object     目标文件
         * @param  string     $content    字符串
         */
        public static function putFile($object,$content){
            $bucket = env('oss.bucket');
            try {
                $ossClient = self::createOssClient();
                $result = $ossClient->putObject($bucket, $object, $content);
                return $result['info'];
            }catch (OssException $e) {
                Log::error("OSS上传文件失败:".$e->getMessage());
                serviceException();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    这里主要封装了两个上传方法,一个是上传文件,一个是把字符串的内容写到文件里并上传,这两种方式是很常用的,因此我这里就一并封装了。

    我们上传头像是上传图片,所有等下调用的是uploadFile()方法。

    这里需要注意的是

    $accessKeyId = env('oss.access_key_id');
    $accessKeySecret = env('oss.access_key_secret');
    $endpoint = env('oss.endpoint');
    // 这个我们之前创建的bucket
    $bucket = env('oss.bucket');
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这些配置在.env的值是怎么来的

    登录控制台,这里可以获取$accessKeyId$accessKeySecret

    在这里插入图片描述

    还是在控制台找到菜单Bucket 列表,找到刚才我们创建的bucket,然后点击它进去,之后访问概览

    在这里插入图片描述

    这里要注意一下,如果你们上线的代码是部署在阿里云的话,可以选择内网访问。

    在控制器app->admin->controller->User.php,新增如下方法

    //上传头像
    public function uploadAvatar(){
        $file = $this->request->file('file');
        $pathName = $file->getPathname();
        $originalName = $file->getOriginalExtension();
    
        $object = "avatar/".$file->hash('md5').".".$originalName;
        return success(Oss::uploadFile($object,$pathName));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    然后添加路由:app->admin->route->app.php

    //路由分组
    Route::group('user', function(){
        //导出
        Route::get('export','user/export');
        //上传头像
        Route::post('uploadAvatar','user/uploadAvatar');
    })->middleware(app\admin\middleware\Auth::class);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    最后我们测试一下接口

    在这里插入图片描述

    4.3.3客户端直传

    客户端直传指的是前端直接把文件上传到oss,就不通过后端服务了,客户端直传避免了业务服务器中转文件,提高了上传速度,节省了服务器资源 ,因此我们一般也是要求前端直传。

    文档:https://help.aliyun.com/zh/oss/use-cases/client-direct-transmission-overview?spm=a2c4g.11186623.0.0.40c97b93j8YYOR

    客户端直传,我们服务端唯一要做的是要提供一个临时密钥,因为$accessKeyId$accessKeySecret不能直接在前端配置,这东西绝对不能配置,因此我们在app->common->lib->oss->OSs.php后面添加一个获取临时密钥的方法

    //获取临时密钥
    public static function getTemKey(){
        $id = env('oss.access_key_id');
        $key = env('oss.access_key_secret');
        // $host的格式为 bucketname.endpoint,请替换为您的真实信息。
        $host = 'http://'.env('oss.bucket').env('oss.endpoint');
        // $callbackUrl为上传回调服务器的URL,请将下面的IP和Port配置为您自己的真实URL信息。
        $callbackUrl = '';
        $dir = 'test/';          // 用户上传文件时指定的前缀。
    
        $callback_param = array(
            'callbackUrl' => $callbackUrl,
            'callbackBody' => 'filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}',
            'callbackBodyType' => "application/x-www-form-urlencoded"
        );
        $callback_string = json_encode($callback_param);
    
        $base64_callback_body = base64_encode($callback_string);
        $now = time();
        $expire = 30;  //设置该policy超时时间是10s. 即这个policy过了这个有效时间,将不能访问。
        $end = $now + $expire;
        $expiration = str_replace('+00:00', '.000Z', gmdate('c', $now));;
    
    
        //最大文件大小.用户可以自己设置
        $condition = array(0 => 'content-length-range', 1 => 0, 2 => 1048576000);
        $conditions[] = $condition;
    
        // 表示用户上传的数据,必须是以$dir开始,不然上传会失败,这一步不是必须项,只是为了安全起见,防止用户通过policy上传到别人的目录。
        $start = array(0 => 'starts-with', 1 => '$key', 2 => $dir);
        $conditions[] = $start;
    
    
        $arr = array('expiration' => $expiration, 'conditions' => $conditions);
        $policy = json_encode($arr);
        $base64_policy = base64_encode($policy);
        $string_to_sign = $base64_policy;
        $signature = base64_encode(hash_hmac('sha1', $string_to_sign, $key, true));
    
        $response = array();
        $response['accessid'] = $id;
        $response['host'] = $host;
        $response['policy'] = $base64_policy;
        $response['signature'] = $signature;
        $response['expire'] = $end;
        $response['callback'] = $base64_callback_body;
        $response['dir'] = $dir;  // 这个参数是设置用户上传文件时指定的前缀。
        return $response;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    然后我们就可以在控制器中调用这个方法即可。

  • 相关阅读:
    docker 带端口映射启动是报错
    深度前馈网络(三)、隐藏单元
    面试官_vue的这些原理你了解吗_
    Java进阶——多线程相关,实际应用中的积累,持续更新
    基于springboot实现二次元商品购物系统项目【项目源码+论文说明】
    用C语言实现状态机设计模式
    Spring Boot Controller
    如何优雅构建自定义 Spring Boot 验证器,让你的代码更加丝滑!
    R语言将数据转化为DALEX包期望的格式、使用DALEX包的explain函数对多个h2o算法模型构建解释器进行解释分析、使用验证集数据构建模型解释器
    约瑟夫问题对应算法的实现(思路分析) [Java][数据结构]
  • 原文地址:https://blog.csdn.net/gzmyh/article/details/134517260