宝塔面板开发腾讯云COS 插件

作者: print("") 分类: python,WEB前端 发布时间: 2018-09-17 10:19

最近忙于各种事情,都没有时间写博文了。今天上午抽空写了一篇垃圾文章。大佬勿喷。=。 =  

第一次玩这种大厂的API 确实最开始有点懵逼,然后公司CTO指导了一下,后面发现其实并不是很难

大概的思路就是登陆上传。登陆获取列表。新建。 遇到的一个坑就是返回的字典中的一个文件夹列表是一个列表。然后前端对接的时候用的数组合并

然后就是获取中出了问题。琢磨了一下就判断是是否为空。

SDK 参考地址:https://cloud.tencent.com/document/product/436/12269

API 参考地址:https://cloud.tencent.com/document/product/436/12270

具体的后端代码如下:

#!/usr/bin/python
# coding: utf-8
# -----------------------------
# 宝塔Linux面板网站备份工具 - 腾讯云
# -----------------------------
import sys, os
reload(sys)
sys.setdefaultencoding('utf-8')
os.chdir('/www/server/panel')
sys.path.append("class/")
import public, db, time,re,json
from qcloud_cos import CosConfig
from qcloud_cos import CosS3Client


# 腾讯云oss 的类
class txcos_main:
    __oss = None
    __bucket_path = None
    __error_count = 0
    __secret_id = 'None'
    __secret_key = 'None'
    __region = 'None'
    __Bucket = 'None'
    __error_msg = "ERROR: 无法连接腾讯云COS !"
    __setupPath = '/www/server/panel/plugin/txcos'
    '''
     __oss         : COS 客户端的对象
	__bucket_path : COS 的路径 例如:/   /data
	__error_count : 错误次数
	__secret_id  : 腾讯云COS 的secret_id 
	__secret_key : 腾讯云COS 的secret_key
	__region     : 腾讯云COS 的地区
	__Bucket     : COS 的Bucket
	__error_msg  : 错误次数
	__error_msg   : 错误信息
    '''

    def __init__(self):
        self.__conn()

    def set_cos(self):
        cfile = 'plugin/txcos/config.conf'
        fp = open(cfile, 'r')
        keys = fp.read().split('|')
        self.__secret_id = keys[0]
        self.__secret_key = keys[1]
        self.__region = keys[2]
        self.__Bucket = keys[3]
        self.__bucket_path = self.get_path(keys[4])
        try:
            config = CosConfig(Region=self.__region, SecretId=self.__secret_id, SecretKey=self.__secret_key, Token=None,Scheme='http', Timeout=1)
            self.__oss = CosS3Client(config)
        except:
            if self.__oss == None:
                time.sleep(1)
                self.__conn()
            return json.dumps(self.__error_msg)


    def __conn(self):
        if self.__oss: return;
        cfile = 'plugin/txcos/config.conf'
        if not os.path.exists(cfile): cfile = 'data/txcos.conf';
        if not os.path.exists(cfile): public.writeFile(cfile, '');
        fp = open(cfile, 'r')
        if not fp:
            print 'ERROR: 请检查atxcos.conf文件中是否有腾讯云secret_id相关信息!'
        keys = fp.read().split('|')
        if len(keys) < 4:
            keys = ['', '', '', '', '/']
        if len(keys) < 5: keys.append('/');

        self.__secret_id = keys[0]
        self.__secret_key = keys[1]
        self.__region = keys[2]
        self.__Bucket = keys[3]
        self.__bucket_path = self.get_path(keys[4])
        try:
            config = CosConfig(Region=self.__region, SecretId=self.__secret_id, SecretKey=self.__secret_key, Token=None,Scheme='http',Timeout=1)
            self.__oss = CosS3Client(config)
        except:
            if self.__oss==None:return json.dumps(self.__error_msg)

    def GetConfig(self, get):
        path = self.__setupPath + '/config.conf'
        if not os.path.exists(path):
            if os.path.exists('conf/atxcos.conf'): public.writeFile(path, public.readFile('conf/atxcos.conf'));
        if not os.path.exists(path): return ['', '', '', '', '/'];
        conf = public.readFile(path)
        if not conf: return ['', '', '', '', '/']
        result = conf.split('|')
        if len(result) < 5: result.append('/');
        return result

    def SetConfig(self, get):
        path = self.__setupPath + '/config.conf'
        conf = get.secret_id + '|' + get.secret_key + '|' + get.region + '|' + get.Bucket + '|' + get.bucket_path
        public.writeFile(path, conf)
        return public.returnMsg(True, '设置成功!')

    # 上传文件
    def upload_file(self, filename):
        self.set_cos()
        self.__conn()
        try:
            # 断点续传
            key = filename.split('/')[-1]
            print(key)
            key = self.__bucket_path + key
            print(key)
            # 短点续传
            response = self.__oss.upload_file(
                Bucket=self.__Bucket,
                Key=key,
                MAXThread=10,
                PartSize=5,
                LocalFilePath=filename)
        except:
            time.sleep(1)
            self.__error_count += 1
            if self.__error_count < 2:  # 重试2次
                self.sync_date()
                self.upload_file(filename)
            print self.__error_msg
            return None

    def create_dir(self, get):
        self.set_cos()
        self.__conn()
        path = self.get_path(get.path + get.dirname)
        filename = '/tmp/dirname.pl'
        public.writeFile(filename, '')
        response = self.__oss.put_object(
            Bucket=self.__Bucket,
            Body=b'',
            Key=path,
        )
        os.remove(filename)
        return public.returnMsg(True, '创建成功!')

    def get_list(self, get):
        self.__conn()
        try:
            data = []
            dir_list = []
            path = self.get_path(get.path)
            if 'Contents'  in self.__oss.list_objects(Bucket=self.__Bucket, MaxKeys=100, Delimiter='/', Prefix=path):
                for b in self.__oss.list_objects(Bucket=self.__Bucket, MaxKeys=100, Delimiter='/', Prefix=path)['Contents']:
                    tmp = {}
                    b['Key'] = b['Key'].replace(path, '')
                    if not b['Key']: continue
                    tmp['name'] = b['Key']
                    tmp['size'] = b['Size']
                    tmp['type'] = b['StorageClass']
                    tmp['download'] = self.download_file(path + b['Key'])
                    tmp['time'] = b['LastModified']
                    data.append(tmp)
            else:
                pass
            if 'CommonPrefixes' in self.__oss.list_objects(Bucket=self.__Bucket, MaxKeys=100, Delimiter='/', Prefix=path):
                for i in self.__oss.list_objects(Bucket=self.__Bucket, MaxKeys=100, Delimiter='/', Prefix=path)['CommonPrefixes']:
                    if not i['Prefix']: continue
                    dir_dir=i['Prefix'].split('/')[-2]+'/'
                    dir_list.append(dir_dir)
            else:
                pass
            mlist = {}
            mlist['path'] = get.path
            mlist['list'] = data
            mlist['dir'] = dir_list
            return mlist
        except:
            mlist = {}
            if self.__oss:
                mlist['status']=True
            else:
                mlist['status']=False
            mlist['path'] = get.path
            mlist['list'] = data
            mlist['dir'] = dir_list
            return mlist

    def sync_date(self):
        public.ExecShell("ntpdate 0.asia.pool.ntp.org")

    def download_file(self, filename, Expired=300):
        self.set_cos()
        self.__conn()
        try:
            response = self.__oss.get_presigned_download_url(
                Bucket=self.__Bucket,
                Key=filename
            )
            response = re.findall('([^?]*)?.*', response)[0]
            return response
        except:
            print self.__error_msg
            return None


    def get_path(self, path):
        if path == '/': path = '';
        if path[:1] == '/':
            path = path[1:]
            if path[-1:] != '/': path += '/';
        return path

    def delete_file(self, filename):
        self.set_cos()
        self.__conn()
        try:
            response = self.__oss.delete_object(
                Bucket=self.__Bucket,
                Key=filename
            )
            return response
        except Exception, ex:
            self.__error_count += 1
            if self.__error_count < 2:
                self.sync_date()
                self.delete_file(filename)
            print self.__error_msg
            return None

    # 删除文件
    def remove_file(self, get):
        self.set_cos()
        path = self.get_path(get.path)
        filename = path + get.filename
        self.delete_file(filename)
        return public.returnMsg(True, '删除文件成功!')

    # 备份网站
    def backupSite(self, name, count):
        self.set_cos()
        self.__conn();
        sql = db.Sql();
        path = sql.table('sites').where('name=?', (name,)).getField('path');
        startTime = time.time();
        if not path:
            endDate = time.strftime('%Y/%m/%d %X', time.localtime())
            log = "网站[" + name + "]不存在!"
            print "★[" + endDate + "] " + log
            print "----------------------------------------------------------------------------"
            return;

        backup_path = sql.table('config').where("id=?", (1,)).getField('backup_path') + '/site';
        if not os.path.exists(backup_path): public.ExecShell("mkdir -p " + backup_path);

        filename = backup_path + "/Web_" + name + "_" + time.strftime('%Y%m%d_%H%M%S', time.localtime()) + '.tar.gz'
        public.ExecShell("cd " + os.path.dirname(path) + " && tar zcvf '" + filename + "' '" + os.path.basename(
            path) + "' > /dev/null")
        endDate = time.strftime('%Y/%m/%d %X', time.localtime())

        if not os.path.exists(filename):
            log = "网站[" + name + "]备份失败!"
            print "★[" + endDate + "] " + log
            print "----------------------------------------------------------------------------"
            return;

        if self.__bucket_path != '': self.__bucket_path += name + '/';

        # 上传文件
        self.upload_file(filename);

        outTime = time.time() - startTime
        pid = sql.table('sites').where('name=?', (name,)).getField('id');
        sql.table('backup').add('type,name,pid,filename,addtime,size',
                                ('0', os.path.basename(filename), pid, 'alioss', endDate, os.path.getsize(filename)))
        log = "网站[" + name + "]已成功备份到阿里云OSS,用时[" + str(round(outTime, 2)) + "]秒";
        public.WriteLog('计划任务', log)
        print "★[" + endDate + "] " + log
        print "|---保留最新的[" + count + "]份备份"
        print "|---文件名:" + os.path.basename(filename)

        # 清理本地文件
        public.ExecShell("rm -f " + filename)

        # 清理多余备份
        backups = sql.table('backup').where('type=? and pid=?', ('0', pid)).field('id,name,filename').select();

        num = len(backups) - int(count)
        if num > 0:
            for backup in backups:
                if os.path.exists(backup['filename']):
                    public.ExecShell("rm -f " + backup['filename']);
                self.delete_file(self.__bucket_path + backup['name']);
                sql.table('backup').where('id=?', (backup['id'],)).delete();
                num -= 1;
                print "|---已清理过期备份文件:" + backup['name']
                if num < 1: break;
        return None
    # 备份数据库

    def backupDatabase(self, name, count):
        self.set_cos()
        self.__conn();
        sql = db.Sql();
        path = sql.table('databases').where('name=?', (name,)).getField('path');
        startTime = time.time();
        if not path:
            endDate = time.strftime('%Y/%m/%d %X', time.localtime())
            log = "数据库[" + name + "]不存在!"
            print("★[" + endDate + "] " + log)
            print("----------------------------------------------------------------------------")
            return;

        backup_path = sql.table('config').where("id=?", (1,)).getField('backup_path') + '/database';
        if not os.path.exists(backup_path): public.ExecShell("mkdir -p " + backup_path);

        filename = backup_path + "/Db_" + name + "_" + time.strftime('%Y%m%d_%H%M%S', time.localtime()) + ".sql.gz"

        import re
        mysql_root = sql.table('config').where("id=?", (1,)).getField('mysql_root')
        mycnf = public.readFile('/etc/my.cnf');
        rep = "\[mysqldump\]\nuser=root"
        sea = "[mysqldump]\n"
        subStr = sea + "user=root\npassword=" + mysql_root + "\n";
        mycnf = mycnf.replace(sea, subStr)
        if len(mycnf) > 100:
            public.writeFile('/etc/my.cnf', mycnf);

        public.ExecShell(
            "/www/server/mysql/bin/mysqldump --opt --default-character-set=utf8 " + name + " | gzip > " + filename)

        if not os.path.exists(filename):
            endDate = time.strftime('%Y/%m/%d %X', time.localtime())
            log = "数据库[" + name + "]备份失败!"
            print("★[" + endDate + "] " + log)
            print("----------------------------------------------------------------------------")
            return;

        mycnf = public.readFile('/etc/my.cnf');
        mycnf = mycnf.replace(subStr, sea)
        if len(mycnf) > 100:
            public.writeFile('/etc/my.cnf', mycnf);

        # 上传
        if self.__bucket_path != '': self.__bucket_path += 'database/' + name + '/';
        self.upload_file(filename);

        endDate = time.strftime('%Y/%m/%d %X', time.localtime())
        outTime = time.time() - startTime
        pid = sql.table('databases').where('name=?', (name,)).getField('id');

        sql.table('backup').add('type,name,pid,filename,addtime,size',
                                (1, os.path.basename(filename), pid, 'alioss', endDate, os.path.getsize(filename)))
        log = "数据库[" + name + "]已成功备份到腾讯云COS,用时[" + str(round(outTime, 2)) + "]秒";
        public.WriteLog('计划任务', log)
        print("★[" + endDate + "] " + log)
        print("|---保留最新的[" + count + "]份备份")
        print("|---文件名:" + os.path.basename(filename))

        # 清理本地文件
        public.ExecShell("rm -f " + filename)

        # 清理多余备份
        backups = sql.table('backup').where('type=? and pid=?', ('1', pid)).field('id,name,filename').select();

        num = len(backups) - int(count)
        if num > 0:
            for backup in backups:
                if os.path.exists(backup['filename']):
                    public.ExecShell("rm -f " + backup['filename']);

                self.delete_file(self.__bucket_path + backup['name']);
                sql.table('backup').where('id=?', (backup['id'],)).delete();
                num -= 1;
                print("|---已清理过期备份文件:" + backup['name'])
                if num < 1: break;
        return None

        # 备份指定目录
    def backupPath(self, path, count):
        self.set_cos()
        sql = db.Sql();
        startTime = time.time();
        name = os.path.basename(path)
        backup_path = sql.table('config').where("id=?", (1,)).getField('backup_path') + '/path';
        if not os.path.exists(backup_path): os.makedirs(backup_path);
        filename = backup_path + "/Path_" + name + "_" + time.strftime('%Y%m%d_%H%M%S', time.localtime()) + '.tar.gz'
        print(filename)
        os.system(
            "cd " + os.path.dirname(path) + " && tar zcvf '" + filename + "' '" + os.path.basename(path) + "' > /dev/null")

        endDate = time.strftime('%Y/%m/%d %X', time.localtime())
        if not os.path.exists(filename):
            log = u"目录[" + path + "]备份失败"
            print(u"★[" + endDate + "] " + log)
            print(u"----------------------------------------------------------------------------")
            return;

        # 上传文件
        if self.__bucket_path != '': self.__bucket_path += 'path/' + name + '/';
        self.upload_file(filename);
        outTime = time.time() - startTime
        sql.table('backup').add('type,name,pid,filename,addtime,size',
                                ('2', path, '0', filename, endDate, os.path.getsize(filename)))
        log = u"目录[" + path + "]备份成功,用时[" + str(round(outTime, 2)) + "]秒";
        public.WriteLog(u'计划任务', log)
        print(u"★[" + endDate + "] " + log)
        print(u"|---保留最新的[" + count + u"]份备份")
        print(u"|---文件名:" + filename)

        # 清理多余备份
        backups = sql.table('backup').where('type=? and pid=?', ('2', 0)).field('id,filename').select();

        # 清理本地文件
        if os.path.exists(filename): os.remove(filename)
        num = len(backups) - int(count)
        if num > 0:
            for backup in backups:
                if os.path.exists(backup['filename']): os.remove(backup['filename'])
                self.delete_file(self.__bucket_path + backup['filename']);
                sql.table('backup').where('id=?', (backup['id'],)).delete();
                num -= 1;
                print(u"|---已清理过期备份文件:" + backup['filename'])
                if num < 1: break;


    def backupSiteAll(self, save):
        self.set_cos()
        self.__conn()
        sites = public.M('sites').field('name').select()
        for site in sites:
            self.backupSite(site['name'], save)


    def backupDatabaseAll(self, save):
        self.set_cos()
        self.__conn()
        databases = public.M('databases').field('name').select()
        for database in databases:
            self.backupDatabase(database['name'], save)

    def set_cos(self):
        cfile = 'plugin/txcos/config.conf'
        fp = open(cfile, 'r')
        keys = fp.read().split('|')
        self.__secret_id = keys[0]
        self.__secret_key = keys[1]
        self.__region = keys[2]
        self.__Bucket = keys[3]
        self.__bucket_path = self.get_path(keys[4])
        try:
            config = CosConfig(Region=self.__region, SecretId=self.__secret_id, SecretKey=self.__secret_key, Token=None,Scheme='http', Timeout=1)
            self.__oss = CosS3Client(config)
        except:
            if self.__oss == None:
                time.sleep(1)
                self.__conn()
            return json.dumps(self.__error_msg)

    def get_lib(self):
        import json
        list={
            "name":"腾讯云COS",
            "type":"计划任务",
            "ps":"将网站或数据库打包备份到腾讯云COS对象存储空间,, <a class='link' href='https://portal.qiniu.com/signup?code=3liz7nbopjd5e' target='_blank'>点击申请</a>",
            "status":'false',
            "opt":"txcos",
            "module":"qcloud_cos",
            "script":"txcos",
            "help":"https://www.bt.cn/bbs/thread-17442-1-1.html",
            "SecretId":"SecretId|请输入SecretId|腾讯云COS的SecretId",
            "SecretKey":"SecretKey|请输入SecretKey|腾讯云COS  SecretKey",
            "region":"存储地区|请输入对象存储地区|例如 ap-chengdu",
            "Bucket":"存储名称|请输入绑定的存储名称",
            "check":["/usr/lib/python2.6/site-packages/qcloud_cos/cos_auth.py","/usr/lib/python2.7/site-packages/qcloud_cos/cos_auth.py"]
        }
        lib='/www/server/panel/data/libList.conf'
        lib_dic = json.loads(public.readFile(lib))
        for i in lib_dic:
            if list['name'] in i['name']:
                return True
            else:
                pass
        lib_dic.append(list)
        public.writeFile(lib, json.dumps(lib_dic))
        return lib_dic



if __name__ == "__main__":
    import json

    data = None
    q = txcos_main()
    type = sys.argv[1]
    if type == 'site':
        if sys.argv[2] == 'ALL':
            q.set_cos()
            q.backupSiteAll(sys.argv[3])
        else:
            q.set_cos()
            q.backupSite(sys.argv[2], sys.argv[3])
        exit()
    elif type == 'database':
        if sys.argv[2] == 'ALL':
            q.set_cos()
            q.backupDatabaseAll(sys.argv[3])
        else:
            q.set_cos()
            q.backupDatabase(sys.argv[2], sys.argv[3])
        exit()
    elif type == 'path':
        q.set_cos()
        q.backupPath(sys.argv[2], sys.argv[3])
    elif type == 'upload':
        q.set_cos()
        data = q.upload_file(sys.argv[2]);
    elif type == 'download':
        data = q.download_file(sys.argv[2]);
    elif type == 'get':
        data = q.get_files(sys.argv[2]);
    elif type == 'list':
        q.set_cos()
        data = q.get_list();
    elif type == 'delete_file':
        data = q.delete_file(sys.argv[2]);
    elif type == 'lib':
        data = q.get_lib()
    else:
        data = 'ERROR: 参数不正确!'
    print(json.dumps(data))

前端代码其实就是抄袭了一波阿里云的COS 的前段代码,如下

<style>
.upyunCon {
    height: 628px;
}
.up-place{
    height: 62px;
    border-bottom:1px solid #ddd;
}
.up-place .btn{
    border-radius: 0;
}
.up-place .place-input{
    background-color: #f3f3f3;
    border: 1px solid #ccc;
    height: 30px;
    line-height: 28px;
    overflow: hidden;
    margin: 1px 0 0 -1px;
    width: 340px;
}
.place-input ul {
    display: inline-block;
    position: relative;
    width: auto;
}
.place-input ul li {
    background: url("/static/img/ico/ico-ltr.png") no-repeat right center;
    float: left;
    padding-left: 10px;
    padding-right: 18px;
}
.place-input ul li a {
    height: 28px;
    cursor: pointer;
    display: inline-block;
}
.upyunlist{
    height:516px;
    overflow:auto;
}
.up-bottom {
    background-color: #fafafa;
    border-top: 1px solid #eee;
    bottom: 0;
    position: absolute;
    width: 100%;
}
.up-use{
    line-height:50px
}
.list-list .cursor span{
    line-height:30px;
}
.btn-title{
    margin-top:1px
}
</style>
<div class="upyunCon"></div>
<script type="javascript/text">
    function upyun(path){
        var loadT = layer.msg('正在获取文件列表...',{icon:16,time:0,shade: [0.3, '#000']});
        $.post('/plugin?action=a&s=get_list&name=txcos',{path:path},function(mlist){
            layer.close(loadT);
            if(mlist.status === false){
                upyunApi();
                return;
            }
            var listBody = ''
            var listFiles = ''
            var arry = mlist.dir.concat(mlist.list);
			console.log(arry);
            for(var i=0;i<arry.length;i++){
                if(arry[i].type == null){
                    listBody += '<tr><td class="cursor" onclick="upyun(\''+(path+'/'+arry[i]).replace('//','/')+'\')"><span class="ico ico-folder"></span><span>'+arry[i]+'</span></td><td>-</td><td>-</td><td class="text-right"><a class="btlink" onclick="DelUpFile(\''+arry[i]+'\')">删除</a></td></tr>'
                }else{
                    listFiles += '<tr><td class="cursor"><span class="ico ico-file"></span><span>'+arry[i].name+'</span></td><td>'+ToSize(arry[i].size)+'</td><td>'+getLocalTime(arry[i].time)+'</td><td class="text-right"><a target="_blank" href="'+arry[i].download+'" class="btlink">下载</a> | <a class="btlink" onclick="DelUpFile(\''+arry[i].name+'\')">删除</a></td></tr>'
                }
            }
            listBody += listFiles;
            
            var pathLi='';
            var tmp = path.split('/')
            var pathname = '';
            var n = 0;
            for(var i=0;i<tmp.length;i++){
                if(n > 0 && tmp[i] == '') continue;
                var dirname = tmp[i];
                if(dirname == '') {
                    dirname = '根目录';
                    n++;
                }
                pathname += '/' + tmp[i];
                pathname = pathname.replace('//','/');
                pathLi += '<li><a title="'+ pathname +'" onclick="upyun(\''+pathname+'\')">'+dirname+'</a></li>';
            }
            var um = 1;
            if(tmp[tmp.length-1] == '') um = 2;
            var backPath = tmp.slice(0,tmp.length-um).join('/') || '/';
            var con='<div class="up-place pd15">\
                        <button id="backBtn" class="btn btn-default btn-sm glyphicon glyphicon-arrow-left pull-left" title="后退" onClick="upyun(\''+backPath+'\')"></button>\
                        <input id="myPath" style="display:none;" type="text" value="'+path+'">\
                        <input type="file" style="display:none;" id="Upupload" multiple="multiple">\
                        <div class="place-input pull-left"><div style="width:1400px;height:28px"><ul>'+pathLi+'</ul></div></div>\
                        <button class="refreshBtn btn btn-default btn-sm glyphicon glyphicon-refresh pull-left mr20" title="刷新" onclick="upyun(\''+path+'\')" style="margin-left:-1px;"></button>\
                        <button class="btn btn-default btn-sm pull-right btn-title" onclick="upyunApi()">帐户设置</button>\
                        <!--<button class="btn btn-default btn-sm pull-right mr20 btn-title" onclick="UploadUp()">上传</button> -->\
                        <button class="btn btn-default btn-sm pull-right mr20 btn-title" onclick="CreateDir()">新建文件夹</button>\
                    </div><div class="upyunlist pd15">\
                    <div class="divtable" style="margin-bottom:15px">\
                        <table class="table table-hover">\
                            <thead><tr><th>名称</th><th>大小</th><th>更新时间</th><th class="text-right">操作</th></tr></thead>\
                            <tbody class="list-list">'+listBody+'</tbody>\
                        </table>\
                    </div>\
                </div>';
        
            $(".upyunCon").html(con);
            upPathLeft();
            
        });
    }
    //计算当前目录偏移
    function upPathLeft(){
        var UlWidth = $(".place-input ul").width();
        var SpanPathWidth = $(".place-input").width() - 20;
        var Ml = UlWidth - SpanPathWidth;
        if(UlWidth > SpanPathWidth ){
            $(".place-input ul").css("left",-Ml)
        }
        else{
            $(".place-input ul").css("left",0)
        }
    }
    //上传文件
    function UploadUp(){
        $("#Upupload").on("change", function () {
            var files = $("#Upupload")[0].files;
            AllUploadTo(files,0,'');
         });
        
        $("#Upupload").click();
    }
    var loadTup = null;
    var n = 0;
    function AllUploadTo(files,successCount,errorMsg){
        var path = $("#myPath").val();
        if(files.length == successCount) {
            layer.close(loadTup);
            upyun(path);
            setTimeout(function(){layer.msg('成功上传['+successCount+']个文件!',{icon:1,time:5000});},1000);
            return;
        }
        
        if(!$(".upyun_name").html()){
            loadTup = layer.msg('正在上传 >> <a class="upyun_name">' + files[successCount].name + '</a>...',{icon:16,time:0,shade: [0.3, '#000']});
        }else{
            $(".upyun_name").text(files[successCount].name);
        }
        $.post('/plugin?action=a&name=upyun&s=GetSgin',{filename:path + '/' +files[successCount].name},function(token){
            var formData = new FormData();
            formData.append("policy", token[0]);
            formData.append("authorization", token[1]);
            formData.append("file", files[successCount]);
            $.ajax({
                url : "https://v0.api.upyun.com/" + token[2],
                type : "POST",
                data : formData,
                processData : false,
                contentType : false,
                beforeSend: function (request) {
                    request.setRequestHeader("authorization", token[1]);
                },
                success : function(data) {
                    data = eval('('+data+')');
                    n++;
                    successCount++;
                    if(n > 4){
                        upyun(path);
                        n = 0;
                    }
                    setTimeout(function(){
                        AllUploadTo(files,successCount,errorMsg);
                    },200);
                    
                },
                error : function(responseStr) {
                    layer.msg('上传失败2!',{icon:2});
                    console.log(responseStr);
                    successCount++;
                    setTimeout(function(){
                        AllUploadTo(files,successCount,errorMsg);
                    },200);
                }
            });
         });
    }
    
    function CreateDir(){
        var i = layer.open({
                type: 1,
                area: "400px",
                title: "创建目录",
                closeBtn: 2,
                shift: 5,
                shadeClose: false,
                content:'<div class="bingfa mtb15">\
                            <p>\
                                <span class="span_tit">目录名称:</span>\
                                <input style="width: 200px;" type="text" name="newPath" value="">\
                            </p>\
                            <div class="submit-btn">\
                                <button type="button" class="btn btn-danger btn-sm bt-cancel">取消</button>\
                                <button class="btn btn-success btn-sm createDir" onclick="CreateUpDir()">确定</button>\
                            </div>\
                        </div>'
        });
        $(".bt-cancel,.createDir").click(function(){
            layer.close(i);
        });
        
        $("input[name='newPath']").focus().keyup(function(e){
            if(e.keyCode == 13) $(".createDir").click();
        });
    }
    
    //创建目录
    function CreateUpDir(name){
        name = $("input[name='newPath']").val();
        if(name == ''){
            layer.msg('目录名称不能为空!',{icon:2});
            return;
        }
        var path = $("#myPath").val()
        var dirname = name;
        var loadT = layer.msg('正在创建目录['+dirname+']...',{icon:16,time:0,shade: [0.3, '#000']});
        $.post('/plugin?action=a&s=create_dir&name=txcos',{path:path,dirname:dirname},function(rdata){
            layer.close(loadT);
            layer.msg(rdata.msg,{icon:rdata.status?1:2});
            if(rdata.status) upyun(path);
        });
    }
    
    //删除文件
    function DelUpFile(name){
        SafeMessage('删除文件','删除后将无法恢复,真的要删除['+name+']吗?',function(){
            var path = $("#myPath").val()
            var loadT = layer.msg('正在删除文件['+name+']...',{icon:16,time:0,shade: [0.3, '#000']});
            $.post('/plugin?action=a&s=remove_file&name=txcos',{path:path,filename:name},function(rdata){
                layer.close(loadT);
                layer.msg(rdata.msg,{icon:rdata.status?1:2});
                if(rdata.status) upyun(path);
            });
        });
    }
    
    var i = null;
    //设置API
    function upyunApi(){
        $.get('/plugin?action=a&name=txcos&s=GetConfig',function(token){
            if(!token) return;
            var apicon = '<div class="zun-form-new bingfa">\
                            <p>\
                                <span class="span_tit">secret_id:</span>\
                                <input placeholder="请输入secret_id" style="width: 300px;" type="text" name="secret_id" value="'+token[0]+'">  *腾讯云COS  secret_id <a href="https://www.bt.cn/bbs/thread-17442-1-1.html" style="color:green" target="_blank"> [帮助]</a>\
                            </p>\
                            <p>\
                                <span class="span_tit">secret_key:</span>\
                                <input placeholder="请输入secret_key" style="width: 300px;" type="text" name="secret_key" value="'+token[1]+'">  *腾讯云COS  secret_key\
                            </p>\
                            <p>\
                                <span class="span_tit">region:</span>\
                                <input placeholder="请输入region名称" style="width: 300px;" type="text" name="region" value="'+token[2]+'">   *腾讯云COS  region\
                            </p>\
                            <p>\
                                <span class="span_tit">Bucket:</span>\
                                <input placeholder="请输入Bucket域名" style="width: 300px;" type="text" name="Bucket" value="'+token[3]+'">   *腾讯云COS  Bucket\
                            </p>\
                            <p>\
                                <span class="span_tit">保存路径:</span>\
                                <input placeholder="请输入保存路径" style="width: 300px;" type="text" name="bucket_path" value="'+token[4]+'">   *备份文件保存路径\
                            </p>\
                            <div class="submit-btn">\
                                <button type="button" class="btn btn-danger btn-sm btn-title bt-cancel">取消</button>\
                                <button class="btn btn-success btn-sm btn-title" onclick="SetUpyunApi()">保存</button>\
                            </div>\
                        </div>';
            
            i = layer.open({
                    type: 1,
                    area: "700px",
                    title: "腾讯云 COS 设置",
                    closeBtn: 2,
                    shift: 5,
                    shadeClose: false,
                    content:apicon
                });
                $(".bt-cancel").click(function(){
                    layer.close(i)
                });
        });
    }
    
    //提交API
    function SetUpyunApi(){
        var data = {
            secret_id:$("input[name='secret_id']").val(),
            secret_key:$("input[name='secret_key']").val(),
            region:$("input[name='region']").val(),
            Bucket:$("input[name='Bucket']").val(),
            bucket_path:$("input[name='bucket_path']").val()
        }
        var loadT = layer.msg('正在校验...',{icon:16,time:0,shade: [0.3, '#000']});
        $.post('/plugin?action=a&s=SetConfig&name=txcos',data,function(rdata){
            layer.close(loadT);
            layer.msg(rdata.msg,{icon:rdata.status?1:2});
            if(rdata.status) {
                layer.close(i);
                upyun('/');
            }
        });
    }
    
    upyun('/');
    $('.layui-layer-page').css('height','670px');
</script>

腾讯云COS 的使用方法1. 设置COS的各种信息
 
首先找到
secret_id
secret_key
进入腾讯云的管理界面

还有一个是region 这个是地区:

最后一个是

Bucket就是你的

存储桶名称
我这里是[url=]adasaasd-1252040336[/url]
[url=]可以如下设置[/url]
[url=]  [/url]
[url=]保存之后就可以看到你的存储下面的东西了[/url]
[url=]  [/url]
稍后会在计划任务中添加腾讯云COS 的存储 方式






备份完之后可以查看一下

然后查看到了有备份文件

这个插件还不算太完善。比如备份到指定的目录。默认是根目录。腾讯云的对象存储有点恶心。

直接访问的话是一个文件下载。不过对于图片啥的,还是可以预览的。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

4条评论
  • 厦门SEO

    2018年9月19日 下午7:53

    博主您没发现你截图演示的是备份网站、而结果图里只有sql备份呀!没看到有网站备份呢?
    我亲测腾讯cos配置完可以连接上,但是备份就出现报错!不信博主可以备份一个网站试试,查看日志就会显示错误!
    我感觉博主是不是直接拿宝塔阿里云oss插件源码改的?因为报错的时候提示的文本是阿里云。
    望作者能即时修复插件bug,毕竟已经更新到市场了,嘻嘻~

    1. print("")

      2018年9月19日 下午8:01

      那个报错会传输第二次的。报错的可能是第一次连接失败导致的。你在用计划任务传完之后看看。
      因为我在测试中。有遇到过你这个事情。那个那个就是拿的阿里云oss改的。因为相差不大。
      你也可以直接用命令行的方式备份。因为留了方式。可以备份整个目录。path 的方式 。

      1. 星夜的蓝天

        2018年9月24日 上午10:32

        有显示备份成功,但是去储存桶里看还是没有,已经很多次了。

  • 小白

    2018年11月24日 下午12:55

    安装完配置好后,计划任务里并没有备份到腾讯云的选项,怎么回事儿?

发表评论

电子邮件地址不会被公开。 必填项已用*标注