mirror of
https://github.com/lsky-org/lsky-pro.git
synced 2025-01-08 11:57:52 +08:00
支持腾讯云图片审核
This commit is contained in:
parent
b33c309a56
commit
71924b0397
21
app/Enums/Scan/TencentOption.php
Normal file
21
app/Enums/Scan/TencentOption.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enums\Scan;
|
||||
|
||||
final class TencentOption
|
||||
{
|
||||
/** @var string SecretId */
|
||||
const SecretId = 'secret_id';
|
||||
|
||||
/** @var string SecretKey */
|
||||
const SecretKey = 'secret_key';
|
||||
|
||||
/** @var string Region */
|
||||
const Region = 'region';
|
||||
|
||||
/** @var string Endpoint */
|
||||
const Endpoint = 'endpoint';
|
||||
|
||||
/** @var string 业务场景 */
|
||||
const BizType = 'biz_type';
|
||||
}
|
@ -43,11 +43,17 @@ class GroupRequest extends FormRequest
|
||||
'exclude_if:configs.is_enable_scan,false',
|
||||
'in:mark,delete',
|
||||
],
|
||||
'configs.scan_configs.driver' => ['exclude_if:configs.is_enable_scan,false', 'in:aliyun'],
|
||||
'configs.scan_configs.driver' => ['exclude_if:configs.is_enable_scan,false', 'in:tencent,aliyun,baidu'],
|
||||
'configs.scan_configs.drivers.tencent.endpoint' => [$requiredIfReview('tencent')],
|
||||
'configs.scan_configs.drivers.tencent.secret_id' => [$requiredIfReview('tencent')],
|
||||
'configs.scan_configs.drivers.tencent.secret_key' => [$requiredIfReview('tencent')],
|
||||
'configs.scan_configs.drivers.tencent.region' => [$requiredIfReview('tencent')],
|
||||
'configs.scan_configs.drivers.tencent.biz_type' => '',
|
||||
|
||||
'configs.scan_configs.drivers.aliyun.access_key_id' => [$requiredIfReview('aliyun')],
|
||||
'configs.scan_configs.drivers.aliyun.access_key_secret' => [$requiredIfReview('aliyun')],
|
||||
'configs.scan_configs.drivers.aliyun.biz_type' => [$requiredIfReview('aliyun')],
|
||||
'configs.scan_configs.drivers.aliyun.region_id' => [$requiredIfReview('aliyun')],
|
||||
'configs.scan_configs.drivers.aliyun.biz_type' => '',
|
||||
'configs.scan_configs.drivers.aliyun.scenes' => [$requiredIfReview('aliyun'), 'array'],
|
||||
|
||||
'configs.is_enable_original_protection' => 'boolean',
|
||||
@ -110,10 +116,15 @@ class GroupRequest extends FormRequest
|
||||
'configs.is_enable_scan' => '是否启用图片审核',
|
||||
'configs.scanned_action' => '图片审核动作',
|
||||
'configs.scan_configs.driver' => '图片审核驱动',
|
||||
'configs.scan_configs.drivers.tencent.endpoint' => 'Endpoint',
|
||||
'configs.scan_configs.drivers.tencent.secret_id' => 'SecretId',
|
||||
'configs.scan_configs.drivers.tencent.secret_key' => 'SecretKey',
|
||||
'configs.scan_configs.drivers.tencent.region' => '地域节点',
|
||||
'configs.scan_configs.drivers.tencent.biz_type' => '业务场景',
|
||||
'configs.scan_configs.drivers.aliyun.access_key_id' => 'AccessKeyId',
|
||||
'configs.scan_configs.drivers.aliyun.access_key_secret' => 'AccessKeySecret',
|
||||
'configs.scan_configs.drivers.aliyun.biz_type' => '场景名称',
|
||||
'configs.scan_configs.drivers.aliyun.region_id' => '地域节点',
|
||||
'configs.scan_configs.drivers.aliyun.biz_type' => '场景名称',
|
||||
'configs.scan_configs.drivers.aliyun.scenes' => '审核场景',
|
||||
|
||||
'configs.is_enable_original_protection' => '是否启用原图保护功能',
|
||||
|
@ -8,6 +8,7 @@ use App\Enums\ConfigKey;
|
||||
use App\Enums\GroupConfigKey;
|
||||
use App\Enums\ImagePermission;
|
||||
use App\Enums\Scan\AliyunOption;
|
||||
use App\Enums\Scan\TencentOption;
|
||||
use App\Enums\Strategy\CosOption;
|
||||
use App\Enums\Strategy\FtpOption;
|
||||
use App\Enums\Strategy\KodoOption;
|
||||
@ -54,6 +55,11 @@ use League\Flysystem\WebDAV\WebDAVAdapter;
|
||||
use Overtrue\Flysystem\Cos\CosAdapter;
|
||||
use Overtrue\Flysystem\Qiniu\QiniuAdapter;
|
||||
use Sabre\DAV\Client;
|
||||
use TencentCloud\Common\Credential;
|
||||
use TencentCloud\Common\Profile\ClientProfile;
|
||||
use TencentCloud\Common\Profile\HttpProfile;
|
||||
use TencentCloud\Ims\V20201229\ImsClient;
|
||||
use TencentCloud\Ims\V20201229\Models\ImageModerationRequest;
|
||||
use WispX\Flysystem\Upyun\UpyunAdapter;
|
||||
use Zing\Flysystem\Oss\OssAdapter;
|
||||
use OSS\OssClient;
|
||||
@ -211,7 +217,12 @@ class ImageService
|
||||
// 图片检测,跳过 tif 以及 psd 格式
|
||||
if ($configs->get(GroupConfigKey::IsEnableScan) && ! in_array($extension, ['psd', 'tif'])) {
|
||||
$scanConfigs = $configs->get(GroupConfigKey::ScanConfigs);
|
||||
if ($this->scan($scanConfigs['driver'], collect($scanConfigs['drivers'][$scanConfigs['driver']]), $image)) {
|
||||
if ($this->scan(
|
||||
driver: $scanConfigs['driver'],
|
||||
configs: collect($scanConfigs['drivers'][$scanConfigs['driver']]),
|
||||
image: $image,
|
||||
file: $file,
|
||||
)) {
|
||||
// 标记 or 删除
|
||||
if ($configs->get(GroupConfigKey::ScannedAction) === 'delete') {
|
||||
$image->delete();
|
||||
@ -354,14 +365,47 @@ class ImageService
|
||||
* @param $driver
|
||||
* @param Collection $configs
|
||||
* @param Image $image
|
||||
* @param UploadedFile $file
|
||||
* @return bool true=违规
|
||||
* @throws UploadException
|
||||
*/
|
||||
public function scan($driver, Collection $configs, Image $image): bool
|
||||
public function scan($driver, Collection $configs, Image $image, UploadedFile $file): bool
|
||||
{
|
||||
$flag = false;
|
||||
try {
|
||||
if ($driver === 'tencent') {
|
||||
// 图片大小不得超过 5mb
|
||||
if ($file->getSize() >= 5242880) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$cred = new Credential($configs->get(TencentOption::SecretId), $configs->get(TencentOption::SecretKey));
|
||||
$httpProfile = new HttpProfile();
|
||||
$httpProfile->setEndpoint($configs->get(TencentOption::Endpoint));
|
||||
$clientProfile = new ClientProfile();
|
||||
$clientProfile->setHttpProfile($httpProfile);
|
||||
$client = new ImsClient($cred, $configs->get(TencentOption::Region), $clientProfile);
|
||||
$req = new ImageModerationRequest();
|
||||
$params = [
|
||||
"FileContent" => base64_encode($file->getContent()),
|
||||
];
|
||||
if ($configs->get(TencentOption::BizType)) {
|
||||
$params['BizType'] = $configs->get(TencentOption::BizType);
|
||||
}
|
||||
$req->fromJsonString(json_encode($params));
|
||||
$resp = $client->ImageModeration($req);
|
||||
|
||||
if ($resp->getSuggestion() === 'Block') {
|
||||
$flag = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($driver === 'aliyun') {
|
||||
// 20 mb以内、宽高不超过 30000px
|
||||
if ($file->getSize() >= 20971520 || $image->width >= 30000 || $image->height >= 30000) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AlibabaCloud::accessKeyClient(
|
||||
$configs->get(AliyunOption::AccessKeyId),
|
||||
$configs->get(AliyunOption::AccessKeySecret),
|
||||
@ -386,7 +430,7 @@ class ImageService
|
||||
}
|
||||
}
|
||||
|
||||
if ($driver === 'tencent') {
|
||||
if ($driver === 'baidu') {
|
||||
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
|
@ -6,13 +6,14 @@ use App\Enums\ConfigKey;
|
||||
use App\Enums\GroupConfigKey;
|
||||
use App\Enums\Mail\SmtpOption;
|
||||
use App\Enums\Scan\AliyunOption;
|
||||
use App\Enums\Scan\TencentOption;
|
||||
use App\Enums\Watermark\FontOption;
|
||||
use App\Enums\Watermark\ImageOption;
|
||||
|
||||
return [
|
||||
'app' => [
|
||||
ConfigKey::AppName => 'Lsky Pro',
|
||||
ConfigKey::AppVersion => 'V 2.0.1',
|
||||
ConfigKey::AppVersion => 'V 2.0.2',
|
||||
ConfigKey::SiteKeywords => 'Lsky Pro,lsky,兰空图床',
|
||||
ConfigKey::SiteDescription => 'Lsky Pro, Your photo album on the cloud.',
|
||||
ConfigKey::SiteNotice => '',
|
||||
@ -45,8 +46,15 @@ return [
|
||||
GroupConfigKey::IsEnableOriginalProtection => 0,
|
||||
GroupConfigKey::ScannedAction => 'mark', // in mark or delete
|
||||
GroupConfigKey::ScanConfigs => [
|
||||
'driver' => 'aliyun',
|
||||
'driver' => 'tencent',
|
||||
'drivers' => [
|
||||
'tencent' => [
|
||||
TencentOption::Endpoint => 'ims.tencentcloudapi.com',
|
||||
TencentOption::SecretId => '',
|
||||
TencentOption::SecretKey => '',
|
||||
TencentOption::Region => '',
|
||||
TencentOption::BizType => ''
|
||||
],
|
||||
'aliyun' => [
|
||||
AliyunOption::AccessKeyId => '',
|
||||
AliyunOption::AccessKeySecret => '',
|
||||
|
@ -116,9 +116,34 @@
|
||||
</div>
|
||||
<div class="col-span-6 mb-4">
|
||||
<x-fieldset title="审核驱动">
|
||||
<x-fieldset-radio id="configs[scan_configs][driver]" name="configs[scan_configs][driver]" data-select="scan" value="aliyun" checked>阿里云</x-fieldset-radio>
|
||||
<x-fieldset-radio id="configs[scan_configs][driver]_tencent" name="configs[scan_configs][driver]" data-select="scan" value="tencent" checked>腾讯云</x-fieldset-radio>
|
||||
<x-fieldset-radio id="configs[scan_configs][driver]_aliyun" name="configs[scan_configs][driver]" data-select="scan" value="aliyun">阿里云</x-fieldset-radio>
|
||||
</x-fieldset>
|
||||
</div>
|
||||
|
||||
<div class="hidden mb-4" data-scan-driver="tencent">
|
||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||
<label for="configs[scan_configs][drivers][tencent][endpoint]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>Endpoint</label>
|
||||
<x-input type="text" name="configs[scan_configs][drivers][tencent][endpoint]" id="configs[scan_configs][drivers][tencent][endpoint]" autocomplete="endpoint" placeholder="请输入 Endpoint" value="ims.tencentcloudapi.com" />
|
||||
</div>
|
||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||
<label for="configs[scan_configs][drivers][tencent][secret_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>SecretId</label>
|
||||
<x-input type="text" name="configs[scan_configs][drivers][tencent][secret_id]" id="configs[scan_configs][drivers][tencent][secret_id]" autocomplete="secret_id" placeholder="请输入 SecretId" />
|
||||
</div>
|
||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||
<label for="configs[scan_configs][drivers][tencent][secret_key]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>SecretKey</label>
|
||||
<x-input type="password" name="configs[scan_configs][drivers][tencent][secret_key]" id="configs[scan_configs][drivers][tencent][secret_key]" autocomplete="secret_key" placeholder="请输入 SecretKey" />
|
||||
</div>
|
||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||
<label for="configs[scan_configs][drivers][tencent][region]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>地域</label>
|
||||
<x-input type="text" name="configs[scan_configs][drivers][tencent][region]" id="configs[scan_configs][drivers][tencent][region]" autocomplete="region" placeholder="请输入地域节点,例如:ap-beijing" />
|
||||
</div>
|
||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||
<label for="configs[scan_configs][drivers][tencent][biz_type]" class="block text-sm font-medium text-gray-700">场景名称</label>
|
||||
<x-input type="text" name="configs[scan_configs][drivers][tencent][biz_type]" id="configs[scan_configs][drivers][tencent][biz_type]" autocomplete="biz_type" placeholder="业务场景名称,可为空" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hidden mb-4" data-scan-driver="aliyun">
|
||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||
<label for="configs[scan_configs][drivers][aliyun][access_key_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKeyId</label>
|
||||
@ -128,14 +153,14 @@
|
||||
<label for="configs[scan_configs][drivers][aliyun][access_key_secret]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKeySecret</label>
|
||||
<x-input type="password" name="configs[scan_configs][drivers][aliyun][access_key_secret]" id="configs[scan_configs][drivers][aliyun][access_key_secret]" autocomplete="access_key_id" placeholder="请输入 AccessKeySecret" />
|
||||
</div>
|
||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||
<label for="configs[scan_configs][drivers][aliyun][biz_type]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>场景名称</label>
|
||||
<x-input type="text" name="configs[scan_configs][drivers][aliyun][biz_type]" id="configs[scan_configs][drivers][aliyun][biz_type]" autocomplete="biz_type" placeholder="请输入业务场景名称" />
|
||||
</div>
|
||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||
<label for="configs[scan_configs][drivers][aliyun][region_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>地域节点</label>
|
||||
<x-input type="text" name="configs[scan_configs][drivers][aliyun][region_id]" id="configs[scan_configs][drivers][aliyun][region_id]" autocomplete="region_id" placeholder="请输入地域节点,例如:cn-shanghai" />
|
||||
</div>
|
||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||
<label for="configs[scan_configs][drivers][aliyun][biz_type]" class="block text-sm font-medium text-gray-700">场景名称</label>
|
||||
<x-input type="text" name="configs[scan_configs][drivers][aliyun][biz_type]" id="configs[scan_configs][drivers][aliyun][biz_type]" autocomplete="biz_type" placeholder="请输入业务场景名称" />
|
||||
</div>
|
||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||
<x-fieldset title="审核场景">
|
||||
@foreach($scenes as $key => $scene)
|
||||
|
@ -112,9 +112,34 @@
|
||||
</div>
|
||||
<div class="col-span-6 mb-4">
|
||||
<x-fieldset title="审核驱动">
|
||||
<x-fieldset-radio id="configs[scan_configs][driver]_tencent" name="configs[scan_configs][driver]" data-select="scan" value="tencent" :checked="($group->configs['scan_configs']['driver'] ?? '') === 'tencent'">腾讯云</x-fieldset-radio>
|
||||
<x-fieldset-radio id="configs[scan_configs][driver]" name="configs[scan_configs][driver]" data-select="scan" value="aliyun" :checked="($group->configs['scan_configs']['driver'] ?? '') === 'aliyun'">阿里云</x-fieldset-radio>
|
||||
</x-fieldset>
|
||||
</div>
|
||||
|
||||
<div class="hidden mb-4" data-scan-driver="tencent">
|
||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||
<label for="configs[scan_configs][drivers][tencent][endpoint]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>Endpoint</label>
|
||||
<x-input type="text" name="configs[scan_configs][drivers][tencent][endpoint]" id="configs[scan_configs][drivers][tencent][endpoint]" autocomplete="endpoint" placeholder="请输入 Endpoint" value="{{ $group->configs['scan_configs']['drivers']['tencent']['endpoint'] ?? '' }}" />
|
||||
</div>
|
||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||
<label for="configs[scan_configs][drivers][tencent][secret_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>SecretId</label>
|
||||
<x-input type="text" name="configs[scan_configs][drivers][tencent][secret_id]" id="configs[scan_configs][drivers][tencent][secret_id]" autocomplete="secret_id" placeholder="请输入 SecretId" value="{{ $group->configs['scan_configs']['drivers']['tencent']['secret_id'] ?? '' }}" />
|
||||
</div>
|
||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||
<label for="configs[scan_configs][drivers][tencent][secret_key]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>SecretKey</label>
|
||||
<x-input type="password" name="configs[scan_configs][drivers][tencent][secret_key]" id="configs[scan_configs][drivers][tencent][secret_key]" autocomplete="secret_key" placeholder="请输入 SecretKey" value="{{ $group->configs['scan_configs']['drivers']['tencent']['secret_key'] ?? '' }}" />
|
||||
</div>
|
||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||
<label for="configs[scan_configs][drivers][tencent][region]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>地域</label>
|
||||
<x-input type="text" name="configs[scan_configs][drivers][tencent][region]" id="configs[scan_configs][drivers][tencent][region]" autocomplete="region" placeholder="请输入地域节点,例如:ap-beijing" value="{{ $group->configs['scan_configs']['drivers']['tencent']['region'] ?? '' }}" />
|
||||
</div>
|
||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||
<label for="configs[scan_configs][drivers][tencent][biz_type]" class="block text-sm font-medium text-gray-700">场景名称</label>
|
||||
<x-input type="text" name="configs[scan_configs][drivers][tencent][biz_type]" id="configs[scan_configs][drivers][tencent][biz_type]" autocomplete="biz_type" placeholder="业务场景名称,可为空" value="{{ $group->configs['scan_configs']['drivers']['tencent']['biz_type'] ?? '' }}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hidden mb-4" data-scan-driver="aliyun">
|
||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||
<label for="configs[scan_configs][drivers][aliyun][access_key_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKeyId</label>
|
||||
@ -124,14 +149,14 @@
|
||||
<label for="configs[scan_configs][drivers][aliyun][access_key_secret]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>AccessKeySecret</label>
|
||||
<x-input type="password" name="configs[scan_configs][drivers][aliyun][access_key_secret]" id="configs[scan_configs][drivers][aliyun][access_key_secret]" autocomplete="access_key_id" placeholder="请输入 AccessKeySecret" value="{{ $group->configs['scan_configs']['drivers']['aliyun']['access_key_secret'] ?? '' }}" />
|
||||
</div>
|
||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||
<label for="configs[scan_configs][drivers][aliyun][biz_type]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>场景名称</label>
|
||||
<x-input type="text" name="configs[scan_configs][drivers][aliyun][biz_type]" id="configs[scan_configs][drivers][aliyun][biz_type]" autocomplete="biz_type" placeholder="请输入业务场景名称" value="{{ $group->configs['scan_configs']['drivers']['aliyun']['biz_type'] ?? '' }}" />
|
||||
</div>
|
||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||
<label for="configs[scan_configs][drivers][aliyun][region_id]" class="block text-sm font-medium text-gray-700"><span class="text-red-600">*</span>地域节点</label>
|
||||
<x-input type="text" name="configs[scan_configs][drivers][aliyun][region_id]" id="configs[scan_configs][drivers][aliyun][region_id]" autocomplete="region_id" placeholder="请输入地域节点,例如:cn-shanghai" value="{{ $group->configs['scan_configs']['drivers']['aliyun']['region_id'] ?? '' }}" />
|
||||
</div>
|
||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||
<label for="configs[scan_configs][drivers][aliyun][biz_type]" class="block text-sm font-medium text-gray-700">场景名称</label>
|
||||
<x-input type="text" name="configs[scan_configs][drivers][aliyun][biz_type]" id="configs[scan_configs][drivers][aliyun][biz_type]" autocomplete="biz_type" placeholder="请输入业务场景名称" value="{{ $group->configs['scan_configs']['drivers']['aliyun']['biz_type'] ?? '' }}" />
|
||||
</div>
|
||||
<div class="col-span-6 sm:col-span-3 mb-4">
|
||||
<x-fieldset title="审核场景">
|
||||
@foreach($scenes as $key => $scene)
|
||||
|
Loading…
Reference in New Issue
Block a user