// +---------------------------------------------------------------------- namespace app\common\repositories\system; use app\common\dao\system\SystemStorageDao; use app\common\repositories\BaseRepository; use app\common\repositories\system\config\ConfigValueRepository; use crmeb\services\UploadService; use FormBuilder\Factory\Elm; use think\exception\ValidateException; use think\facade\Db; use think\facade\Route; use think\queue\command\Retry; class StorageRepository extends BaseRepository { protected $service; public function __construct(SystemStorageDao $dao, UploadService $service) { $this->dao = $dao; $this->service = $service; } public function getType() { return $this->service->getType(); } public function getPrefix($type = 1) { return $this->service::getPrefix($type); } public function lstRegion(array $where, int $page, int $limit) { $prefix = $this->service::getPrefix($where['type']); $accessKey = $prefix . 'accessKey'; $where['access_key'] = systemConfig($accessKey); $query = $this->dao->getSearch($where); $count = $query->count(); $list = $query->page($page, $limit)->select(); return compact('count', 'list'); } public function getConfig(int $type) { $res = ['name' => '', 'region' => '', 'domain' => '', 'cdn' => '']; try { $config = $this->dao->getWhere(['type' => $type, 'status' => 1, 'is_del' => 0]); if ($config) { return ['name' => $config->name, 'region' => $config->region, 'domain' => $config->domain, 'cdn' => $config->cdn]; } } catch (\Throwable $e) { } return $res; } public function form($type) { $prefix = $this->service::getPrefix($type); //获取配置 //accessKey $accessKey = $prefix . 'accessKey'; //secretKey $secretKey = $prefix . 'secretKey'; $form = Elm::createForm(Route::buildUrl('systemStorageUpdate')->build()); $rule = [ Elm::hidden('upload_type', $type), Elm::input('accessKey', 'AccessKey:', systemConfig($accessKey))->placeholder('请输入accessKey')->required(), Elm::input('secretKey', 'SecretKey:', systemConfig($secretKey))->placeholder('请输入secretKey')->required(), ]; if ($type == $this->service::STORAGE_TENGXUN) { $rule[] = Elm::input('tengxun_appid', 'APPID:', systemConfig('tengxun_appid'))->placeholder('请输入APPID')->required(); } if ($type == $this->service::STORAGE_JINGDONG) { $rule[] = Elm::input('jd_storageRegion', 'storageRegion:', systemConfig('jd_storageRegion'))->placeholder('请输入storageRegion')->required(); } $form->setRule($rule); return $form->setTitle('配置'); } public function createRegionForm(int $type) { $upload = UploadService::create($type); $prefix = $this->service::getPrefix($type); $accessKey = $prefix . 'accessKey'; $secretKey = $prefix . 'secretKey'; $config = systemConfig([$accessKey, $secretKey, 'tengxun_appid']); $form = Elm::createForm(Route::buildUrl('systemStorageCreateRegion', ['type' => $type])->build()); $ruleConfig = []; if (!$config[$accessKey]) { $ruleConfig = [ Elm::input('accessKey', 'AccessKey:', $config[$accessKey])->placeholder('请输入accessKey')->required(), Elm::input('secretKey', 'SecretKey:', $config[$secretKey])->placeholder('请输入secretKey')->required(), ]; } if ($type == $this->service::STORAGE_TENGXUN && !$config['tengxun_appid']) { $ruleConfig[] = Elm::input('tengxun_appid', 'APPID:')->placeholder('请输入APPID')->required(); } $rule = [ Elm::input('name', '空间名称')->required()->min(5), Elm::select('region', '空间区域')->options($upload->getRegion())->required(), Elm::radio('acl', '读写权限', 'public-read')->options([ ['label' => '公共读(推荐)', 'value' => 'public-read'], ['label' => '公共读写', 'value' => 'public-read-write'], ])->required(), ]; $rule = array_merge($ruleConfig, $rule); $form->setRule($rule); return $form->setTitle('添加云空间'); } /** * * @param $id * @return \FormBuilder\Form * @author Qinii * @day 2024/3/13 */ public function editDomainForm($id) { $storage = $this->dao->get($id); $form = Elm::createForm(Route::buildUrl('systemStorageUpdateDomain', ['id' => $id])->build()); $rule = [ Elm::input('domain', '空间域名', $storage['domain']), Elm::input('cdn', 'cdn域名', $storage['cdn']), ]; $form->setRule($rule); return $form->setTitle('配置'); } /** * 修改空间域名 * @param int $id * @param string $domain * @param array $data * @return bool * @author Qinii * @day 2024/3/13 */ public function updateDomain(int $id, string $domain, array $data = []) { $info = $this->dao->get($id); if (!$info) { throw new ValidateException('数据不存在'); } if ($info->domain != $domain) { $info->domain = $domain; $upload = UploadService::create($info->type); //是否添加过域名不存在需要绑定域名 $domainList = $upload->getDomian($info->name, $info->region); $domainParse = parse_url($domain); if (false === $domainParse) { throw new ValidateException('域名输入有误'); } if (!in_array($domainParse['host'], $domainList)) { //绑定域名到云储存桶 $res = $upload->bindDomian($info->name, $domain, $info->region); if (false === $res) { throw new ValidateException($upload->getError()); } } //七牛云需要通过接口获取cname if (2 === ((int)$info->type)) { $resDomain = $upload->getDomianInfo($domain); $info->cname = $resDomain['cname'] ?? ''; } $info->save(); } if ($info->cdn != $data['cdn']) { $info->cdn = $data['cdn']; $info->save(); } return true; } /** * 选择使用某个存储空间 * @param $id * @param $info * @return mixed|\think\response\Json * @author Qinii * @day 2024/3/13 */ public function status($id, $info) { //设置跨域规则 try { $upload = UploadService::create($info->type); $res = $upload->setBucketCors($info->name, $info->region); if (false === $res) { return app('json')->fail($upload->getError()); } } catch (\Throwable $e) { } //修改状态 return Db::transaction(function () use ($id, $info) { $this->dao->getSearch(['type' => $info->type])->update(['status' => 0]); $info->status = 1; $info->save(); }); } /** * 删除存储空间 * @param int $id * @return bool * @author Qinii * @day 2024/3/13 */ public function deleteRegion(int $id) { $storageInfo = $this->dao->getSearch(['is_del' => 0, 'id' => $id])->find(); if (!$storageInfo) { throw new ValidateException('数据不存在'); } if ($storageInfo->status) { throw new ValidateException('存储空间使用中不能删除'); } try { $upload = UploadService::create($storageInfo->type); $res = $upload->deleteBucket($storageInfo->name, $storageInfo->region); if (false === $res) { throw new ValidateException($upload->getError()); } } catch (\Throwable $e) { throw new ValidateException($e->getMessage()); } $storageInfo->delete(); return true; } /** * 添加存储空间 * @param int $type * @param array $data * @return bool * @author Qinii * @day 2024/3/13 */ public function createRegion(int $type, array $data, array $params) { $prefix = $this->service::getPrefix($type); $access_key = ''; if ($params && $params['accessKey']){ $access_key = $params['accessKey']; $secretKey = $params['accessKey']; unset($params['accessKey'],$params['accessKey']); $params[$prefix.'accessKey'] = $access_key; $params[$prefix.'secretKey'] = $secretKey; app()->make(ConfigValueRepository::class)->setFormData($params,0); } $access_key = $access_key ?: systemConfig($prefix . 'accessKey'); $data['type'] = $type; $count = $this->dao->getWhereCount(['name' => $data['name'], 'access_key' => $access_key]); if ($count) throw new ValidateException('空间名称已存在'); $upload = UploadService::create($type); $res = $upload->createBucket($data['name'], $data['region'], $data['acl']); if (false === $res) { throw new ValidateException($upload->getError()); } if ($type === $this->service::STORAGE_ALIYUN) { $data['region'] = $this->getReagionHost($type, $data['region']); } $data['domain'] = $this->getDomain($type, $data['name'], $data['region'], systemConfig('tengxun_appid')); if ($type === $this->service::STORAGE_QINIU) { $domianList = $upload->getDomian($data['name']); $data['domain'] = $domianList[count($domianList) - 1]; } else { $data['cname'] = $data['domain']; } $data['access_key'] = $access_key; if ($type === $this->service::STORAGE_TENGXUN) { $data['name'] = $data['name'].'-'.systemConfig('tengxun_appid'); } $this->dao->create($data); $this->setDefualtUse($type,$access_key); return true; } /** * 同步存储空间 * @param $type * @return bool * @author Qinii * @day 2024/3/14 */ public function synchRegion(int $type) { $upload = $this->service::create($type); $list = $upload->listbuckets(); $data = []; if ($list) { $prefix = $this->service::getPrefix($type); $access_key = systemConfig($prefix . 'accessKey'); $data = $this->{$prefix . 'sync_region'}($access_key, $list); } if ($data) { $this->dao->insertAll($data); $this->setDefualtUse($type,$access_key); } return true; } public function setDefualtUse(int $type,$access_key) { $config = $this->dao->getSearch([])->where(['type' => $type,'is_del' => 0,'access_key' => $access_key])->order('status DESC,create_time DESC')->find(); if (!$config['status']) { $config->status = 1; $config->save(); } } /** * 同步存储空间-七牛 * @param $access_key * @param $list * @return array * @author Qinii * @day 2024/3/15 */ public function qiniu_sync_region($access_key, $list) { $data = []; $namesArray = []; foreach ($list as $item) { array_push($namesArray, $item['id']); if (!$this->dao->getWhereCount(['name' => $item['id'], 'access_key' => $access_key])) { $data[] = [ 'type' => $this->service::STORAGE_QINIU, 'access_key' => $access_key, 'name' => $item['id'], 'region' => $item['region'], 'acl' => $item['private'] == 0 ? 'public-read' : 'private', 'status' => 0, ]; } } $removeList = $this->dao->getSearch([])->where([ 'type' => $this->service::STORAGE_QINIU, 'access_key' => $access_key ])->whereNotIn('name', $namesArray)->delete(); return $data; } /** * 同步存储空间-阿里 * @param $access_key * @param $list * @return array * @author Qinii * @day 2024/3/15 */ public function sync_region($access_key, $list) { $data = []; $type = $this->service::STORAGE_ALIYUN; $namesArray = []; foreach ($list as $item) { array_push($namesArray, $item['name']); if (!$this->dao->getWhereCount(['name' => $item['name'], 'access_key' => $access_key])) { $region = $this->getReagionHost($type, $item['location']); $data[] = [ 'type' => $type, 'access_key' => $access_key, 'name' => $item['name'], 'region' => $region, 'acl' => 'public-read', 'domain' => $this->getDomain($type, $item['name'], $region), 'status' => 0, ]; } } $removeList = $this->dao->getSearch([])->where([ 'type' => $type, 'access_key' => $access_key ])->whereNotIn('name', $namesArray)->delete(); return $data; } /** * 同步存储空间-腾讯 * @param $access_key * @param $list * @return array * @author Qinii * @day 2024/3/15 */ public function tengxun_sync_region($access_key, $list) { if (isset($list['Name'])) { $newlist = $list; $list = []; $list[] = $newlist; } $data = []; $namesArray = []; foreach ($list as $item) { array_push($namesArray, $item['Name']); $res = $this->dao->getWhereCount(['name' => $item['Name'], 'access_key' => $access_key]); if (!$res) { $data[] = [ 'type' => $this->service::STORAGE_TENGXUN, 'access_key' => $access_key, 'name' => $item['Name'], 'region' => $item['Location'], 'acl' => 'public-read', 'status' => 0, 'domain' => systemConfig('tengxun_appid') ? $this->getDomain($this->service::STORAGE_TENGXUN, $item['Name'], $item['Location']) : '', ]; } } $removeList = $this->dao->getSearch([])->where([ 'type' => $this->service::STORAGE_TENGXUN, 'access_key' => $access_key ])->whereNotIn('name', $namesArray)->delete(); return $data; } /** * 同步存储空间-华为 * @param $access_key * @param $list * @return array * @author Qinii * @day 2024/3/15 */ public function obs_sync_region($access_key, $list) { if (isset($list['Name']) && !empty($list['Name'])) { $newlist = $list; $list = []; $list[] = $newlist; } $data = []; $namesArray = []; foreach ($list as $item) { array_push($namesArray, $item['Name']); if (!$this->dao->getWhereCount(['name' => $item['Name'], 'access_key' => $access_key])) { $data[] = [ 'type' => $this->service::STORAGE_HUAWEI, 'access_key' => $access_key, 'name' => $item['Name'], 'region' => $item['Location'], 'acl' => 'public-read', 'status' => 0, 'domain' => $this->getDomain($this->service::STORAGE_HUAWEI, $item['Name'], $item['Location']), ]; } } $removeList = $this->dao->getSearch([])->where([ 'type' => $this->service::STORAGE_HUAWEI, 'access_key' => $access_key ])->whereNotIn('name', $namesArray)->delete(); return $data; } /** * 同步存储空间-京东 * @param $access_key * @param $list * @return array * @author Qinii * @day 2024/3/15 */ public function jdoss_sync_region($access_key, $list) { $list = $list['Buckets']; $data = []; $namesArray = []; $location = explode('.', $list['@metadata']['effectiveUri'])[1] ?? 'cn-north-1'; foreach ($list as $item) { array_push($namesArray, $item['Name']); if (!$this->dao->getWhereCount(['name' => $item['Name'], 'access_key' => $access_key])) { $data[] = [ 'type' => $this->service::STORAGE_JINGDONG, 'access_key' => $access_key, 'name' => $item['Name'], 'region' => $location, 'acl' => 'public-read', 'status' => 0, 'domain' => $this->getDomain($this->service::STORAGE_JINGDONG, $item['Name'], $location), ]; } } $removeList = $this->dao->getSearch([])->where([ 'type' => $this->service::STORAGE_JINGDONG, 'access_key' => $access_key ])->whereNotIn('name', $namesArray)->delete(); return $data; } /** * 同步存储空间-天翼 * @param $access_key * @param $list * @return array * @author Qinii * @day 2024/3/15 */ public function ctoss_sync_region($access_key, $list) { if (isset($list['Name'])) { $newlist = $list; $list = []; $list[] = $newlist; } $namesArray = []; $data = []; foreach ($list as $item) { array_push($namesArray, $item['Name']); if (!$this->dao->getWhereCount(['name' => $item['Name'], 'access_key' => $access_key])) { $data[] = [ 'type' => $this->service::STORAGE_TIANYI, 'access_key' => $access_key, 'name' => $item['Name'], 'region' => $item['Location'], 'acl' => 'public-read', 'status' => 0, 'domain' => $this->getDomain($this->service::STORAGE_TIANYI, $item['Name'], $item['Location']), ]; } } $removeList = $this->dao->getSearch([])->where([ 'type' => $this->service::STORAGE_JINGDONG, 'access_key' => $access_key ])->whereNotIn('name', $namesArray)->delete(); return $data; } /** * 同步存储空间-UC * @param $access_key * @param $list * @return bool * @author Qinii * @day 2024/3/15 */ public function uc_sync_region($access_key, $list) { $data = []; $namesArray = []; if($list && !empty($list)){ foreach ($list as $item){ array_push($namesArray, $item['BucketName']); if (!$this->dao->getWhereCount(['name' => $item['BucketName'], 'access_key' => $access_key])) { $data[] = [ 'type' => $this->service::STORAGE_UCLOUD, 'access_key' => $access_key, 'name' => $item['BucketName'], 'region' => $item['Region'], 'acl' => $item['Type'], 'status' => 0, 'domain' => $this->getDomain($this->service::STORAGE_UCLOUD, $item['BucketName'], $item['Region']), ]; } } } $removeList = $this->dao->getSearch([])->where([ 'type' => $this->service::STORAGE_UCLOUD, 'access_key' => $access_key ])->whereNotIn('name', $namesArray)->delete(); return $data; } public function getDomain(int $type, string $name, string $reagion, string $appid = '') { $domainName = ''; switch ($type) { case $this->service::STORAGE_ALIYUN: // oss 阿里云 $domainName = 'https://' . $name . '.' . $reagion; break; case $this->service::STORAGE_TENGXUN:// cos 腾讯云 $domainName = 'https://' . $name . ($appid ? '-' . $appid : '') . '.cos.' . $reagion . '.myqcloud.com'; break; case $this->service::STORAGE_JINGDONG:// cos 京东云 $domainName = 'https://' . $name . '.s3.' . $reagion . '.jdcloud-oss.com'; break; case $this->service::STORAGE_HUAWEI:// cos 华为云 $domainName = 'https://' . $name . '.obs.' . $reagion . '.myhuaweicloud.com'; break; case $this->service::STORAGE_TIANYI:// cos 天翼云 $domainName = 'https://' . $name . '.obs.' . $reagion . '.ctyun.cn'; break; case $this->service::STORAGE_UCLOUD:// ucloud 优刻得 $domainName = 'https://' . $name .'.' . $reagion .'.ufileos.com'; break; } return $domainName; } public function getReagionHost(int $type, string $reagion) { $upload = UploadService::create($type); $reagionList = $upload->getRegion(); foreach ($reagionList as $item) { if (strstr($item['value'], $reagion) !== false) { return $item['value']; } } return ''; } public function domains(?int $type) { $type = $type ?: (systemConfig('upload_type') ?: 1); $domain = $this->dao->getSearch([])->where(['type' => $type,'is_del' => 0])->where('domain','>',0)->column('domain'); return $domain ?: []; } }