找回密码
 立即注册
搜索
查看: 482|回复: 0

[js/jquery基础] javascript/js上传文件到oss

  [复制链接]
发表于 2023-2-23 14:42 | 显示全部楼层 |阅读模式

单纯的javascript/js上传文件到oss会直接泄漏相应的key/secret等重要信息,所以上传时要先请求下PHP,然后拿着对应的信息就可以直接上传到OSS了。

第1步:上传表单:

<tr><td style="text-align:right;">上传mp3封面:</td><td style="text-align:left;">
 
  <span class="imgs"></span>
  <span class="imgs_file_btn">
  <input type="file" name="file_conver" class="myfile layui-btn layui-btn-primary" value="" >
  </span>
 
 </td></tr>

第2步:
引入我们写好的js文件:
<script src="{$Think.BASE_SITE_ROOT}/static/oss_jq.js?time=1557452966" charset="utf-8"></script>
oss_jq.js内容如下:
;(function ($) {
    $.fn.extend({
        uploadUtil: function uploadUtil(options) {
            var that = this;
            $(this).on('change', function (e) {
                var file = e.target.files[0];
                var tokenUrl = options.tokenUrl;
                var filePrefix = options.filePrefix;
                var match = options.match;
                var callback = options.callback;
                var bucket = options.bucket;
                if (!bucket) {
                    bucket = 'mymall';//桶
                }
                // 只选择图片文件
                if (match) {
                    if (!file.type.match(match)) {
                        return false;
                    }
                }
                $.get(tokenUrl, { prefix: filePrefix, bucket: bucket }, function (res) {
                    var ossData = new FormData();
                    var realFilename = file.type.split('/');
                    ossData.append('OSSAccessKeyId', res.accessid);
                    ossData.append('policy', res.policy);
                    ossData.append('Signature', res.signature);
                    ossData.append('key', res.dir);
                    ossData.append('success_action_status', 201); // 指定返回的状态码
                    ossData.append('file', file, filePrefix + res.timestamp + '.' + realFilename[1]);
                    $.ajax({
                        url: res.host,
                        data: ossData,
                        dataType: 'xml',
                        processData: false,
                        contentType: false,
                        type: 'POST',
                        context: that
                    }).done(function (data) {
                        // 返回的上传信息
                        if ($(data).find('PostResponse')) {
                            var resq = $(data).find('PostResponse');
                            var nameKey = $(e.target).attr('id');
                            that[0].value = '';
                            $('img[name="' + nameKey + '"]').attr('src', resq.find('Location').text()).show();
                            $('input[name="' + nameKey + '"]').val(resq.find('Key').text());
                            if (callback) {
                                callback.apply(this, [res.host, resq.find('Key').text()]);
                            }
                        }
                    });
                }, 'json');
            });
        }
    });
})(jQuery);

第3步:调用上面的JS写好的方法:
        //图片上传
    $('input[name="file_conver"]').uploadUtil({
        tokenUrl: '/api/oss_token/getToken',//获取oss信息
        filePrefix: 'music/{$day}/',//目录前缀,可以自定义
        match: 'image.*',//上传要匹配的文件类型
        callback: function (imgHost, imgStr) {
            let arr = imgStr.split('/');
            let html = '<img src="' + imgHost + imgStr + '">' +
                '<input type="hidden" name="image" value="' + imgHost + imgStr + '">';//将上传后的图片显示出来并将值放到隐藏域
            $('.imgs').html(html);
            $('.imgs_file_btn').hide();
        }
    });

第4步:/api/oss_token/getToken取出key/secret代码:
<?php
 
namespace app\api\controller;
 
 
use think\Controller;
 
class OssToken extends Controller
{
    public function getToken()
    {
        $bucket = request()->get('bucket');
        $bucket = empty($bucket) ? 'mymall' : $bucket;
        //自行设置AccessKey和相应Bucket的外网域名
 
        $id = 'OSS后台的id';
        $key = 'OSS后台的key';
        // h5下去除协议名称,由前端自行决定采用协议的类型
        $host = '//'.$bucket.'.阿里云OSS给我们的域名/';
 
        $prefix = request()->get('prefix');
        $prefixs = explode('/', $prefix);
        array_pop($prefixs);
 
        $now = time();
        $expire = 10; //设置该policy超时时间是10s. 即这个policy过了这个有效时间,将不能访问
        $end = $now + $expire;
        $expiration = $this->gmt_iso8601($end);
 
        //文件大小范围.用户可以自己设置
        $condition = array('content-length-range', 0, 1048576000);
 
        //设置用户上传指定的前缀
        $dir = 'home/' . implode('/', $prefixs) . '/';
        //用户上传数据的位置匹配,这一步不是必须项,只是为了安全起见,防止用户通过policy上传到别人的目录
        $start = array('starts-with', '$key', $dir);
 
        //设置bucket
        $bucket = array('eq', '$bucket', $bucket);
 
        $conditions = array($bucket, $condition, $start);
 
 
        $arr = array('expiration'=>$expiration,'conditions'=>$conditions);
        //echo json_encode($arr);
        //return;
        $policy = json_encode($arr);
        $base64_policy = base64_encode($policy);
        $signature = base64_encode(hash_hmac('sha1', $base64_policy, $key, true));
 
        $response = array(
            'accessid' => $id,
            'host' => $host,
            'policy' => $base64_policy,
            'signature' => $signature,
            'expire' => $end,
            'timestamp' => date('YmdHis') . mt_rand(10000, 99999),
            'dir' => $dir.'${filename}'
        );
        header('Content-Type: application/json;charset=utf-8');
        echo json_encode($response);
        exit;
    }
 
    function gmt_iso8601($time) {
        $dtStr = date("c", $time);
        $mydatetime = new \DateTime($dtStr);
        $expiration = $mydatetime->format(\DateTime::ISO8601);
        $pos = strpos($expiration, '+');
        $expiration = substr($expiration, 0, $pos);
        return $expiration."Z";
    }
}

第5步:大功告成。注意:由于是在H5/pc上的代码,返回的文件地址是//开头的协议文件地址,传到PHP后台时,要处理下。不然APP无法识别。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|学习笔记

GMT+8, 2025-4-3 10:35 , Processed in 0.017654 second(s), 13 queries , APCu On.

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表