Ver código fonte

增加腾讯云支持,测试中。。。

Anyon 4 anos atrás
pai
commit
5e39c5b530

+ 10 - 27
app/admin/controller/Config.php

@@ -19,6 +19,9 @@ use think\admin\Controller;
 use think\admin\service\AdminService;
 use think\admin\service\ModuleService;
 use think\admin\service\SystemService;
+use think\admin\storage\AliossStorage;
+use think\admin\storage\QiniuStorage;
+use think\admin\storage\TxcosStorage;
 
 /**
  * 系统参数配置
@@ -35,33 +38,6 @@ class Config extends Controller
     protected $table = 'SystemConfig';
 
     /**
-     * 阿里数据中心
-     * @var array
-     */
-    protected $points = [
-        'oss-cn-hangzhou.aliyuncs.com'    => '华东 1(杭州)',
-        'oss-cn-shanghai.aliyuncs.com'    => '华东 2(上海)',
-        'oss-cn-qingdao.aliyuncs.com'     => '华北 1(青岛)',
-        'oss-cn-beijing.aliyuncs.com'     => '华北 2(北京)',
-        'oss-cn-zhangjiakou.aliyuncs.com' => '华北 3(张家口)',
-        'oss-cn-huhehaote.aliyuncs.com'   => '华北 5(呼和浩特)',
-        'oss-cn-shenzhen.aliyuncs.com'    => '华南 1(深圳)',
-        'oss-cn-chengdu.aliyuncs.com'     => '西南 1(成都)',
-        'oss-cn-hongkong.aliyuncs.com'    => '中国(香港)',
-        'oss-us-west-1.aliyuncs.com'      => '美国西部 1(硅谷)',
-        'oss-us-east-1.aliyuncs.com'      => '美国东部 1(弗吉尼亚)',
-        'oss-ap-southeast-1.aliyuncs.com' => '亚太东南 1(新加坡)',
-        'oss-ap-southeast-2.aliyuncs.com' => '亚太东南 2(悉尼)',
-        'oss-ap-southeast-3.aliyuncs.com' => '亚太东南 3(吉隆坡)',
-        'oss-ap-southeast-5.aliyuncs.com' => '亚太东南 5(雅加达)',
-        'oss-ap-northeast-1.aliyuncs.com' => '亚太东北 1(日本)',
-        'oss-ap-south-1.aliyuncs.com'     => '亚太南部 1(孟买)',
-        'oss-eu-central-1.aliyuncs.com'   => '欧洲中部 1(法兰克福)',
-        'oss-eu-west-1.aliyuncs.com'      => '英国(伦敦)',
-        'oss-me-east-1.aliyuncs.com'      => '中东东部 1(迪拜)',
-    ];
-
-    /**
      * 系统参数配置
      * @auth true
      * @menu true
@@ -114,6 +90,13 @@ class Config extends Controller
         $this->_applyFormToken();
         if ($this->request->isGet()) {
             $this->type = input('type', 'local');
+            if ($this->type === 'alioss') {
+                $this->points = AliossStorage::region();
+            } elseif ($this->type === 'txcos') {
+                $this->points = TxcosStorage::region();
+            } elseif ($this->type === 'qiniu') {
+                $this->points = QiniuStorage::region();
+            }
             $this->fetch("storage-{$this->type}");
         } else {
             $post = $this->request->post();

+ 11 - 1
app/admin/controller/api/Upload.php

@@ -20,6 +20,7 @@ use think\admin\Storage;
 use think\admin\storage\AliossStorage;
 use think\admin\storage\LocalStorage;
 use think\admin\storage\QiniuStorage;
+use think\admin\storage\TxcosStorage;
 
 /**
  * 文件上传接口
@@ -76,6 +77,15 @@ class Upload extends Controller
             $data['signature'] = $token['signature'];
             $data['OSSAccessKeyId'] = $token['keyid'];
             $data['server'] = AliossStorage::instance()->upload();
+        } elseif ('txcos' === $data['uptype']) {
+            $token = TxcosStorage::instance()->buildUploadToken($data['xkey'], 3600, $this->name);
+            $data['url'] = $token['siteurl'];
+            $data['q-ak'] = $token['q-ak'];
+            $data['policy'] = $token['policy'];
+            $data['q-key-time'] = $token['q-key-time'];
+            $data['q-signature'] = $token['d-signature'];
+            $data['q-sign-algorithm'] = $token['q-sign-algorithm'];
+            $data['server'] = TxcosStorage::instance()->upload();
         }
         $this->success('获取授权参数', $data, 404);
     }
@@ -139,7 +149,7 @@ class Upload extends Controller
     private function getType()
     {
         $this->uptype = strtolower(input('uptype', ''));
-        if (!in_array($this->uptype, ['local', 'qiniu', 'alioss'])) {
+        if (!in_array($this->uptype, ['local', 'qiniu', 'alioss', 'txcos'])) {
             $this->uptype = strtolower(sysconf('storage.type'));
         }
         return strtolower($this->uptype);

+ 8 - 0
app/admin/view/api/upload.js

@@ -39,6 +39,14 @@ define(['md5'], function (SparkMD5, allowMime) {
                                         option.uploader.config.data.OSSAccessKeyId = ret.data.OSSAccessKeyId;
                                         option.uploader.config.data.success_action_status = 200;
                                         option.uploader.config.data['Content-Disposition'] = 'inline;filename=' + encodeURIComponent(file.name);
+                                    } else if (ret.data.uptype === 'txcos') {
+                                        option.uploader.config.data.policy = ret.data.policy;
+                                        option.uploader.config.data['q-ak'] = ret.data['q-ak'];
+                                        option.uploader.config.data['q-key-time'] = ret.data['q-key-time'];
+                                        option.uploader.config.data['q-signature'] = ret.data['q-signature'];
+                                        option.uploader.config.data['q-sign-algorithm'] = ret.data['q-sign-algorithm'];
+                                        option.uploader.config.data.success_action_status = 200;
+                                        option.uploader.config.data['Content-Disposition'] = 'inline;filename=' + encodeURIComponent(file.name);
                                     }
                                     object.upload(file.index, file);
                                 } else if (parseInt(ret.code) === 200) {

+ 2 - 1
app/admin/view/config/index.html

@@ -39,7 +39,7 @@
     </div>
     <div class="layui-card-body">
         <div class="layui-btn-group shadow-mini nowrap">
-            {foreach ['local' => '本地服务器存储','qiniu' => '七牛云对象存储','alioss' => '阿里云OSS存储'] as $k => $v} {if sysconf('storage.type') eq $k}
+            {foreach ['local' => '本地服务器存储','qiniu' => '七牛云对象存储','alioss' => '阿里云OSS存储','txcos' => '腾讯云COS存储'] as $k => $v} {if sysconf('storage.type') eq $k}
             {if auth('storage')}<a data-title="配置{$v}" data-modal="{:url('storage')}?type={$k}" class="layui-btn layui-btn-sm layui-btn-active">{$v}</a>{else}<a class="layui-btn layui-btn-sm layui-btn-active">{$v}</a>{/if}
             {else}
             {if auth('storage')}<a data-title="配置{$v}" data-modal="{:url('storage')}?type={$k}" class="layui-btn layui-btn-sm layui-btn-primary">{$v}</a>{else}<a class="layui-btn layui-btn-sm layui-btn-primary">{$v}</a>{/if}
@@ -49,6 +49,7 @@
             <p><b>本地服务器存储</b>:文件直接上传到本地服务器的 `static/upload` 目录,不支持大文件上传,占用服务器磁盘空间,访问时消耗服务器带宽流量。</p>
             <p><b>七牛云对象存储</b>:文件直接上传到七牛云存储空间,支持大文件上传,不占用服务器空间及服务器带宽流量,支持 CDN 加速访问,访问量大时推荐使用。</p>
             <p><b>阿里云OSS存储</b>:文件直接上传到阿里云 OSS 存储空间,支持大文件上传,不占用服务器空间及服务器带宽流量,支持 CDN 加速访问,访问量大时推荐使用。</p>
+            <p><b>腾讯云COS存储</b>:文件直接上传到腾讯云 COS 存储空间,支持大文件上传,不占用服务器空间及服务器带宽流量,支持 CDN 加速访问,访问量大时推荐使用。</p>
         </div>
     </div>
 </div>

+ 1 - 0
app/admin/view/config/storage-0.html

@@ -3,6 +3,7 @@
         <span class="color-green font-w7">链接类型</span><br><span class="nowrap color-desc">LinkType</span>
     </label>
     <div class="layui-input-block">
+        {if !sysconf('storage.link_type')}{php}sysconf('storage.link_type','none');{/php}{/if}
         {foreach ['none'=>'简洁链接','full'=>'完整链接'] as $k=>$v}
         <label class="think-radio notselect">
             {if sysconf('storage.link_type') eq $k}

+ 9 - 8
app/admin/view/config/storage-alioss.html

@@ -13,16 +13,17 @@
                 <span class="color-green font-w7">访问协议</span><br><span class="nowrap color-desc">Protocol</span>
             </label>
             <div class="layui-input-block">
-                {foreach ['http','https','auto'] as $protocol}
+                {if !sysconf('storage.alioss_http_protocol')}{php}sysconf('storage.alioss_http_protocol','http');{/php}{/if}
+                {foreach ['http'=>'HTTP','https'=>'HTTPS','auto'=>"AUTO"] as $protocol=>$remark}
                 <label class="think-radio">
                     {if sysconf('storage.alioss_http_protocol') eq $protocol}
-                    <input checked type="radio" name="storage.alioss_http_protocol" value="{$protocol}" lay-ignore> {$protocol}
+                    <input checked type="radio" name="storage.alioss_http_protocol" value="{$protocol}" lay-ignore> {$remark}
                     {else}
-                    <input type="radio" name="storage.alioss_http_protocol" value="{$protocol}" lay-ignore> {$protocol}
+                    <input type="radio" name="storage.alioss_http_protocol" value="{$protocol}" lay-ignore> {$remark}
                     {/if}
                 </label>
                 {/foreach}
-                <p class="help-block">阿里云OSS存储访问协议,其中 https 需要配置证书才能使用(auto 为相对协议)</p>
+                <p class="help-block">阿里云OSS存储访问协议,其中 HTTPS 需要配置证书才能使用(AUTO 为相对协议)</p>
             </div>
         </div>
 
@@ -34,9 +35,9 @@
                 <select class="layui-select" name="storage.alioss_point" lay-search>
                     {foreach $points as $point => $title}
                     {if sysconf('storage.alioss_point') eq $point}
-                    <option selected value="{$point}">{$title} {$point}</option>
+                    <option selected value="{$point}">{$title} {$point}</option>
                     {else}
-                    <option value="{$point}">{$title} {$point}</option>
+                    <option value="{$point}">{$title} {$point}</option>
                     {/if}{/foreach}
                 </select>
                 <p class="help-block">阿里云OSS存储空间所在区域,需要严格对应储存所在区域才能上传文件</p>
@@ -49,7 +50,7 @@
             </label>
             <div class="layui-input-block">
                 <input id="storage.alioss_bucket" type="text" name="storage.alioss_bucket" required value="{:sysconf('storage.alioss_bucket')}" placeholder="请输入阿里云OSS存储 Bucket (空间名称)" class="layui-input">
-                <p class="help-block">填写OSS存储空间名称,如:think-admin-oss(需要是全区唯一的值,不存在时会自动创建)</p>
+                <p class="help-block">填写阿里云OSS存储空间名称,如:think-admin-oss(需要是全区唯一的值,不存在时会自动创建)</p>
             </div>
         </div>
 
@@ -59,7 +60,7 @@
             </label>
             <div class="layui-input-block">
                 <input id="storage.alioss_http_domain" type="text" name="storage.alioss_http_domain" required value="{:sysconf('storage.alioss_http_domain')}" placeholder="请输入阿里云OSS存储 Domain (访问域名)" class="layui-input">
-                <p class="help-block">填写OSS存储外部访问域名,如:static.ctolog.com</p>
+                <p class="help-block">填写阿里云OSS存储外部访问域名,如:static.ctolog.com</p>
             </div>
         </div>
 

+ 6 - 5
app/admin/view/config/storage-local.html

@@ -13,16 +13,17 @@
                 <span class="color-green font-w7">访问协议</span><br><span class="nowrap color-desc">Protocol</span>
             </label>
             <div class="layui-input-block">
-                {foreach ['follow','http','https','path','auto'] as $pro}
+                {if !sysconf('storage.local_http_protocol')}{php}sysconf('storage.local_http_protocol','http');{/php}{/if}
+                {foreach ['follow'=>'FOLLOW','http'=>'HTTP','https'=>'HTTPS','path'=>'PATH','auto'=>'AUTO'] as $protocol=>$remark}
                 <label class="think-radio">
-                    {if sysconf('storage.local_http_protocol') eq $pro}
-                    <input checked type="radio" name="storage.local_http_protocol" value="{$pro}" lay-ignore> {$pro}
+                    {if sysconf('storage.local_http_protocol') eq $protocol}
+                    <input checked type="radio" name="storage.local_http_protocol" value="{$protocol}" lay-ignore> {$remark}
                     {else}
-                    <input type="radio" name="storage.local_http_protocol" value="{$pro}" lay-ignore> {$pro}
+                    <input type="radio" name="storage.local_http_protocol" value="{$protocol}" lay-ignore> {$remark}
                     {/if}
                 </label>
                 {/foreach}
-                <p class="help-block">本地服务器访问协议,其中 https 需要配置证书才能使用(follow 为跟随系统,path 为文件路径,auto 为相对协议)</p>
+                <p class="help-block">本地存储访问协议,其中 HTTPS 需要配置证书才能使用( FOLLOW 跟随系统,PATH 文件路径,AUTO 相对协议 )</p>
             </div>
         </div>
 

+ 6 - 5
app/admin/view/config/storage-qiniu.html

@@ -13,16 +13,17 @@
                 <span class="color-green font-w7">访问协议</span><br><span class="nowrap color-desc">Protocol</span>
             </label>
             <div class="layui-input-block">
-                {foreach ['http','https','auto'] as $pro}
+                {if !sysconf('storage.qiniu_http_protocol')}{php}sysconf('storage.qiniu_http_protocol','http');{/php}{/if}
+                {foreach ['http'=>'HTTP','https'=>'HTTPS','auto'=>"AUTO"] as $protocol=>$remark}
                 <label class="think-radio">
-                    {if sysconf('storage.qiniu_http_protocol') eq $pro}
-                    <input checked type="radio" name="storage.qiniu_http_protocol" value="{$pro}" lay-ignore> {$pro}
+                    {if sysconf('storage.qiniu_http_protocol') eq $protocol}
+                    <input checked type="radio" name="storage.qiniu_http_protocol" value="{$protocol}" lay-ignore> {$remark}
                     {else}
-                    <input type="radio" name="storage.qiniu_http_protocol" value="{$pro}" lay-ignore> {$pro}
+                    <input type="radio" name="storage.qiniu_http_protocol" value="{$protocol}" lay-ignore> {$remark}
                     {/if}
                 </label>
                 {/foreach}
-                <p class="help-block">七牛云存储访问协议,其中 https 需要配置证书才能使用(auto 为相对协议)</p>
+                <p class="help-block">七牛云存储访问协议,其中 HTTPS 需要配置证书才能使用( AUTO 为相对协议 )</p>
             </div>
         </div>
 

+ 108 - 0
app/admin/view/config/storage-txcos.html

@@ -0,0 +1,108 @@
+<form onsubmit="return false" data-auto="true" action="{:request()->url()}" method="post" class='layui-form layui-card' autocomplete="off">
+    <div class="layui-card-body padding-top-20">
+
+        <div class="color-text margin-left-40 margin-bottom-20 layui-code text-center layui-bg-gray layui-hide" style="border-left-width:1px">
+            <p class="margin-bottom-5 font-w7">文件将上传到腾讯云 COS 存储,需要配置 COS 公开访问及跨域策略</p>
+            <p>直传需要配置跨域规则,设置来源为 *,允许 Methods 为 POST,允许 Headers 为 *</p>
+        </div>
+
+        {include file='config/storage-0'}
+
+        <div class="layui-form-item">
+            <label class="layui-form-label label-required">
+                <span class="color-green font-w7">访问协议</span><br><span class="nowrap color-desc">Protocol</span>
+            </label>
+            <div class="layui-input-block">
+                {if !sysconf('storage.txcos_http_protocol')}{php}sysconf('storage.txcos_http_protocol','http');{/php}{/if}
+                {foreach ['http'=>'HTTP','https'=>'HTTPS','auto'=>"AUTO"] as $protocol=>$remark}
+                <label class="think-radio">
+                    {if sysconf('storage.txcos_http_protocol') eq $protocol}
+                    <input checked type="radio" name="storage.txcos_http_protocol" value="{$protocol}" lay-ignore> {$remark}
+                    {else}
+                    <input type="radio" name="storage.txcos_http_protocol" value="{$protocol}" lay-ignore> {$remark}
+                    {/if}
+                </label>
+                {/foreach}
+                <p class="help-block">腾讯云COS存储访问协议,其中 HTTPS 需要配置证书才能使用( AUTO 为相对协议 )</p>
+            </div>
+        </div>
+
+        <div class="layui-form-item">
+            <label class="layui-form-label">
+                <span class="color-green font-w7">存储区域</span><br><span class="nowrap color-desc label-required">Region</span>
+            </label>
+            <div class="layui-input-block">
+                <select class="layui-select" name="storage.txcos_point" lay-search>
+                    {foreach $points as $point => $title}
+                    {if sysconf('storage.txcos_point') eq $point}
+                    <option selected value="{$point}">{$title}( {$point} )</option>
+                    {else}
+                    <option value="{$point}">{$title}( {$point} )</option>
+                    {/if}{/foreach}
+                </select>
+                <p class="help-block">腾讯云COS存储空间所在区域,需要严格对应储存所在区域才能上传文件</p>
+            </div>
+        </div>
+
+        <div class="layui-form-item">
+            <label class="layui-form-label" for="storage.txcos_bucket">
+                <span class="color-green font-w7">空间名称</span><br><span class="nowrap color-desc">Bucket</span>
+            </label>
+            <div class="layui-input-block">
+                <input id="storage.txcos_bucket" type="text" name="storage.txcos_bucket" required value="{:sysconf('storage.txcos_bucket')}" placeholder="请输入腾讯云COS存储 Bucket" class="layui-input">
+                <p class="help-block">填写腾讯云COS存储空间名称,如:think-admin-cos</p>
+            </div>
+        </div>
+
+        <div class="layui-form-item">
+            <label class="layui-form-label" for="storage.txcos_http_domain">
+                <span class="color-green font-w7">访问域名</span><br><span class="nowrap color-desc">Domain</span>
+            </label>
+            <div class="layui-input-block">
+                <input id="storage.txcos_http_domain" type="text" name="storage.txcos_http_domain" required value="{:sysconf('storage.txcos_http_domain')}" placeholder="请输入腾讯云COS存储 Domain" class="layui-input">
+                <p class="help-block">填写腾讯云COS存储外部访问域名,如:static.ctolog.com</p>
+            </div>
+        </div>
+
+        <div class="layui-form-item">
+            <label class="layui-form-label" for="storage.txcos_appid">
+                <span class="color-green font-w7">账号编号</span><br><span class="nowrap color-desc">APPID</span>
+            </label>
+            <div class="layui-input-block">
+                <input id="storage.txcos_appid" type="text" name="storage.txcos_appid" required value="{:sysconf('storage.txcos_appid')}" placeholder="请输入腾讯云主账号 APPID" class="layui-input">
+                <p class="help-block">可以在 [ 腾讯云 > 个人中心 ] 获取到主账号的 APPID</p>
+            </div>
+        </div>
+
+        <div class="layui-form-item">
+            <label class="layui-form-label" for="storage.txcos_access_key">
+                <span class="color-green font-w7">访问密钥</span><br><span class="nowrap color-desc">AccessKey</span>
+            </label>
+            <div class="layui-input-block">
+                <input id="storage.txcos_access_key" type="text" name="storage.txcos_access_key" required value="{:sysconf('storage.txcos_access_key')}" placeholder="请输入腾讯云COS存储 AccessKey" class="layui-input">
+                <p class="help-block">可以在 [ 腾讯云 > 个人中心 ] 设置并获取到访问密钥</p>
+            </div>
+        </div>
+
+        <div class="layui-form-item">
+            <label class="layui-form-label" for="storage.txcos_secret_key">
+                <span class="color-green font-w7">安全密钥</span><br><span class="nowrap color-desc">SecretKey</span>
+            </label>
+            <div class="layui-input-block">
+                <input id="storage.txcos_secret_key" type="text" name="storage.txcos_secret_key" required value="{:sysconf('storage.txcos_secret_key')}" maxlength="43" placeholder="请输入腾讯云COS存储 SecretKey" class="layui-input">
+                <p class="help-block">可以在 [ 腾讯云 > 个人中心 ] 设置并获取到安全密钥</p>
+            </div>
+        </div>
+
+        <div class="hr-line-dashed margin-left-40"></div>
+        <input type="hidden" name="storage.type" value="txcos">
+
+        <div class="layui-form-item text-center padding-left-40">
+            <button class="layui-btn" type="submit">保存配置</button>
+            <button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消修改吗?" data-close>取消修改</button>
+        </div>
+
+        <script>form.render()</script>
+
+    </div>
+</form>

+ 4 - 4
vendor/composer/installed.json

@@ -893,12 +893,12 @@
         "source": {
             "type": "git",
             "url": "https://github.com/zoujingli/ThinkLibrary.git",
-            "reference": "213b606ab9906914296f475324538b93c18406dd"
+            "reference": "be1ddab224ab14d814ae120eebfb53b25808bbfa"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/zoujingli/ThinkLibrary/zipball/213b606ab9906914296f475324538b93c18406dd",
-            "reference": "213b606ab9906914296f475324538b93c18406dd",
+            "url": "https://api.github.com/repos/zoujingli/ThinkLibrary/zipball/be1ddab224ab14d814ae120eebfb53b25808bbfa",
+            "reference": "be1ddab224ab14d814ae120eebfb53b25808bbfa",
             "shasum": "",
             "mirrors": [
                 {
@@ -915,7 +915,7 @@
             "ext-mbstring": "*",
             "topthink/framework": "^6.0"
         },
-        "time": "2020-10-15T01:37:16+00:00",
+        "time": "2020-10-15T03:06:04+00:00",
         "type": "library",
         "extra": {
             "think": {

+ 1 - 1
vendor/services.php

@@ -1,5 +1,5 @@
 <?php 
-// This file is automatically generated at:2020-10-15 09:55:40
+// This file is automatically generated at:2020-10-15 11:40:03
 declare (strict_types = 1);
 return array (
   0 => 'think\\admin\\Library',

+ 33 - 3
vendor/zoujingli/think-library/src/storage/AliossStorage.php

@@ -201,8 +201,8 @@ class AliossStorage extends Storage
      */
     public function upload(): string
     {
-        $http = $this->app->request->isSsl() ? 'https' : 'http';
-        return "{$http}://{$this->bucket}.{$this->point}";
+        $protocol = $this->app->request->isSsl() ? 'https' : 'http';
+        return "{$protocol}://{$this->bucket}.{$this->point}";
     }
 
     /**
@@ -219,8 +219,8 @@ class AliossStorage extends Storage
                 'conditions' => [['content-length-range', 0, 1048576000]],
                 'expiration' => date('Y-m-d\TH:i:s.000\Z', time() + $expires),
             ])),
-            'siteurl' => $this->url($name, false, $attname),
             'keyid'   => $this->accessKey,
+            'siteurl' => $this->url($name, false, $attname),
         ];
         $data['signature'] = base64_encode(hash_hmac('sha1', $data['policy'], $this->secretKey, true));
         return $data;
@@ -254,4 +254,34 @@ class AliossStorage extends Storage
         return array_values($header);
     }
 
+    /**
+     * 阿里云OSS存储区域
+     * @return array
+     */
+    public static function region()
+    {
+        return [
+            'oss-cn-hangzhou.aliyuncs.com'    => '华东 1(杭州)',
+            'oss-cn-shanghai.aliyuncs.com'    => '华东 2(上海)',
+            'oss-cn-qingdao.aliyuncs.com'     => '华北 1(青岛)',
+            'oss-cn-beijing.aliyuncs.com'     => '华北 2(北京)',
+            'oss-cn-zhangjiakou.aliyuncs.com' => '华北 3(张家口)',
+            'oss-cn-huhehaote.aliyuncs.com'   => '华北 5(呼和浩特)',
+            'oss-cn-shenzhen.aliyuncs.com'    => '华南 1(深圳)',
+            'oss-cn-chengdu.aliyuncs.com'     => '西南 1(成都)',
+            'oss-cn-hongkong.aliyuncs.com'    => '中国(香港)',
+            'oss-us-west-1.aliyuncs.com'      => '美国西部 1(硅谷)',
+            'oss-us-east-1.aliyuncs.com'      => '美国东部 1(弗吉尼亚)',
+            'oss-ap-southeast-1.aliyuncs.com' => '亚太东南 1(新加坡)',
+            'oss-ap-southeast-2.aliyuncs.com' => '亚太东南 2(悉尼)',
+            'oss-ap-southeast-3.aliyuncs.com' => '亚太东南 3(吉隆坡)',
+            'oss-ap-southeast-5.aliyuncs.com' => '亚太东南 5(雅加达)',
+            'oss-ap-northeast-1.aliyuncs.com' => '亚太东北 1(日本)',
+            'oss-ap-south-1.aliyuncs.com'     => '亚太南部 1(孟买)',
+            'oss-eu-central-1.aliyuncs.com'   => '欧洲中部 1(法兰克福)',
+            'oss-eu-west-1.aliyuncs.com'      => '英国(伦敦)',
+            'oss-me-east-1.aliyuncs.com'      => '中东东部 1(迪拜)',
+        ];
+    }
+
 }

+ 15 - 0
vendor/zoujingli/think-library/src/storage/QiniuStorage.php

@@ -232,4 +232,19 @@ class QiniuStorage extends Storage
         $sign = hash_hmac('sha1', "/{$type}/{$entry}\n", $this->secretKey, true);
         return [$entry, "{$this->accessKey}:{$this->safeBase64($sign)}"];
     }
+
+    /**
+     * 七牛云对象存储区域
+     * @return array
+     */
+    public static function region()
+    {
+        return [
+            'up.qiniup.com'     => '华东',
+            'up-z1.qiniup.com'  => '华北',
+            'up-z2.qiniup.com'  => '华南',
+            'up-na0.qiniup.com' => '北美',
+            'up-as0.qiniup.com' => '东南亚',
+        ];
+    }
 }

+ 56 - 25
vendor/zoujingli/think-library/src/storage/TxcosStorage.php

@@ -21,6 +21,12 @@ class TxcosStorage extends Storage
     private $point;
 
     /**
+     * 账号 AppID
+     * @var string
+     */
+    private $appid;
+
+    /**
      * 存储空间名称
      * @var string
      */
@@ -48,6 +54,7 @@ class TxcosStorage extends Storage
     protected function initialize()
     {
         // 读取配置文件
+        $this->appid = sysconf('storage.txcos_appid');
         $this->point = sysconf('storage.txcos_point');
         $this->bucket = sysconf('storage.txcos_bucket');
         $this->secretId = sysconf('storage.txcos_secret_id');
@@ -92,11 +99,11 @@ class TxcosStorage extends Storage
         $data['q-ak'] = $token['q-ak'];
         $data['q-key-time'] = $token['q-key-time'];
         $data['q-signature'] = $token['d-signature'];
-        $data['success_action_status'] = '200';
         if (is_string($attname) && strlen($attname) > 0) {
             $filename = urlencode($attname);
             $data['Content-Disposition'] = "inline;filename={$filename}";
         }
+        $data['success_action_status'] = '200';
         $file = ['field' => 'file', 'name' => $name, 'content' => $file];
         if (is_numeric(stripos(HttpExtend::submit($this->upload(), $data, $file), '200 OK'))) {
             return ['file' => $this->path($name, $safe), 'url' => $this->url($name, $safe, $attname), 'key' => $name];
@@ -125,7 +132,7 @@ class TxcosStorage extends Storage
     public function del(string $name, bool $safe = false)
     {
         [$file] = explode('?', $name);
-        $result = HttpExtend::request('DELETE', "http://{$this->bucket}.{$this->point}/{$file}", [
+        $result = HttpExtend::request('DELETE', "http://{$this->bucket}-{$this->appid}.{$this->point}/{$file}", [
             'returnHeader' => true, 'headers' => $this->headerSign('DELETE', $file),
         ]);
         return is_numeric(stripos($result, '204 No Content'));
@@ -140,7 +147,7 @@ class TxcosStorage extends Storage
     public function has(string $name, bool $safe = false)
     {
         $file = $this->delSuffix($name);
-        $result = HttpExtend::request('HEAD', "http://{$this->bucket}.{$this->point}/{$file}", [
+        $result = HttpExtend::request('HEAD', "http://{$this->bucket}-{$this->appid}.{$this->point}/{$file}", [
             'returnHeader' => true, 'headers' => $this->headerSign('HEAD', $name),
         ]);
         return is_numeric(stripos($result, 'HTTP/1.1 200 OK'));
@@ -190,8 +197,8 @@ class TxcosStorage extends Storage
      */
     public function upload(): string
     {
-        $http = $this->app->request->isSsl() ? 'https' : 'http';
-        return "{$http}://{$this->bucket}.{$this->point}";
+        $protocol = $this->app->request->isSsl() ? 'https' : 'http';
+        return "{$protocol}://{$this->bucket}-{$this->appid}.{$this->point}";
     }
 
     /**
@@ -209,23 +216,16 @@ class TxcosStorage extends Storage
         $siteurl = $this->url($name, false, $attname);
         $policy = json_encode([
             'expiration' => date('Y-m-d\TH:i:s.000\Z', $endTimestamp),
-            'conditions' => [
-                ['q-sign-algorithm' => 'sha1'],
-                ['q-ak' => $this->secretId],
-                ['q-sign-time' => $keyTime]
-            ],
+            'conditions' => [['q-sign-algorithm' => 'sha1'], ['q-ak' => $this->secretId], ['q-sign-time' => $keyTime]],
         ]);
-        $data = [
+        return [
             'policy'           => base64_encode($policy),
             'q-sign-algorithm' => 'sha1',
             'q-ak'             => $this->secretId,
             'q-key-time'       => $keyTime,
-            'siteurl'          => $siteurl
+            'q-signature'      => hash_hmac('sha1', sha1($policy), hash_hmac('sha1', $keyTime, $this->secretKey)),
+            'siteurl'          => $siteurl,
         ];
-        $signKey = hash_hmac('sha1', $keyTime, $this->secretKey);
-        $stringToSign = sha1($policy);
-        $data['q-signature'] = hash_hmac('sha1', $stringToSign, $signKey);
-        return $data;
     }
 
     /**
@@ -237,33 +237,33 @@ class TxcosStorage extends Storage
      */
     private function headerSign(string $method, string $soruce, array $header = []): array
     {
-        // 1.生成KeyTime
+        // 1.生成 KeyTime
         $startTimestamp = time();
         $endTimestamp = $startTimestamp + 3600;
         $keyTime = "{$startTimestamp};{$endTimestamp}";
         // 2.生成 SignKey
         $signKey = hash_hmac('sha1', $keyTime, $this->secretKey);
-        // 3.生成UrlParamList,HttpParameters
-        list($parse_url, $urlParamList, $httpParameters) = [parse_url($soruce), '', ''];
+        // 3.生成 UrlParamList, HttpParameters
+        [$parse_url, $urlParamList, $httpParameters] = [parse_url($soruce), '', ''];
         if (!empty($parse_url['query'])) {
             parse_str($parse_url['query'], $params);
             uksort($params, 'strnatcasecmp');
             $urlParamList = join(';', array_keys($params));
             $httpParameters = http_build_query($params);
         }
-        // 4.生成HeaderList,HttpHeaders
-        list($headerList, $httpHeaders) = ['', ''];
+        // 4.生成 HeaderList, HttpHeaders
+        [$headerList, $httpHeaders] = ['', ''];
         if (!empty($header)) {
             uksort($header, 'strnatcasecmp');
             $headerList = join(';', array_keys($header));
             $httpHeaders = http_build_query($header);
         }
-        // 5.生成HttpString
+        // 5.生成 HttpString
         $httpString = strtolower($method) . "\n/{$parse_url['path']}\n{$httpParameters}\n{$httpHeaders}\n";
-        // 6.生成StringToSign
+        // 6.生成 StringToSign
         $httpStringSha1 = sha1($httpString);
         $stringToSign = "sha1\n{$keyTime}\n{$httpStringSha1}\n";
-        // 7.生成Signature
+        // 7.生成 Signature
         $signature = hash_hmac('sha1', $stringToSign, $signKey);
         // 8.生成签名
         $signArray = [
@@ -273,11 +273,42 @@ class TxcosStorage extends Storage
             'q-key-time'       => $keyTime,
             'q-header-list'    => $headerList,
             'q-url-param-list' => $urlParamList,
-            'q-signature'      => $signature
+            'q-signature'      => $signature,
         ];
         $header['Authorization'] = urldecode(http_build_query($signArray));
         foreach ($header as $key => $value) $header[$key] = ucfirst($key) . ": {$value}";
         return array_values($header);
     }
 
+    /**
+     * 腾讯云COS存储区域
+     * @return array
+     */
+    public static function region()
+    {
+        return [
+            'cos.ap-beijing-1.myqcloud.com'     => '中国大陆 公有云地域 北京一区(已售罄)',
+            'cos.ap-beijing.myqcloud.com'       => '中国大陆 公有云地域 北京',
+            'cos.ap-nanjing.myqcloud.com'       => '中国大陆 公有云地域 南京',
+            'cos.ap-shanghai.myqcloud.com'      => '中国大陆 公有云地域 上海',
+            'cos.ap-guangzhou.myqcloud.com'     => '中国大陆 公有云地域 广州',
+            'cos.ap-chengdu.myqcloud.com'       => '中国大陆 公有云地域 成都',
+            'cos.ap-chongqing.myqcloud.com'     => '中国大陆 公有云地域 重庆',
+            'cos.ap-shenzhen-fsi.myqcloud.com'  => '中国大陆 金融云地域 深圳金融',
+            'cos.ap-shanghai-fsi.myqcloud.com'  => '中国大陆 金融云地域 上海金融',
+            'cos.ap-beijing-fsi.myqcloud.com'   => '中国大陆 金融云地域 北京金融',
+            'cos.ap-hongkong.myqcloud.com'      => '亚太地区 公有云地域 中国香港',
+            'cos.ap-singapore.myqcloud.com'     => '亚太地区 公有云地域 新加坡',
+            'cos.ap-mumbai.myqcloud.com'        => '亚太地区 公有云地域 孟买',
+            'cos.ap-seoul.myqcloud.com'         => '亚太地区 公有云地域 首尔',
+            'cos.ap-bangkok.myqcloud.com'       => '亚太地区 公有云地域 曼谷',
+            'cos.ap-tokyo.myqcloud.com'         => '亚太地区 公有云地域 东京',
+            'cos.na-siliconvalley.myqcloud.com' => '北美地区 公有云地域 硅谷',
+            'cos.na-ashburn.myqcloud.com'       => '北美地区 公有云地域 弗吉尼亚',
+            'cos.na-toronto.myqcloud.com'       => '北美地区 公有云地域 多伦多',
+            'cos.eu-frankfurt.myqcloud.com'     => '欧洲地区 公有云地域 法兰克福',
+            'cos.eu-moscow.myqcloud.com'        => '欧洲地区 公有云地域 莫斯科	',
+        ];
+    }
+
 }