You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
67 lines
3.4 KiB
67 lines
3.4 KiB
<?php
|
|
namespace App\Services\ContentSecurity;
|
|
|
|
use App\Models\Upload;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Log;
|
|
use InvalidArgumentException;
|
|
|
|
class AvatarCheck
|
|
{
|
|
public function submit($user, Upload $upload): array
|
|
{
|
|
if (!$user->openid) throw new InvalidArgumentException('请重新进入小程序后再试');
|
|
$id = DB::table('content_security_checks')->insertGetId([
|
|
'user_id' => $user->id, 'upload_id' => $upload->id, 'url' => $upload->url,
|
|
'status' => 'pending', 'created_at' => now(), 'updated_at' => now(),
|
|
]);
|
|
try {
|
|
// The SDK convenience method uses v1; explicitly send all v2 parameters.
|
|
$result = miniProgramApp()->content_security->httpPostJson('wxa/media_check_async', [
|
|
'media_url' => $upload->url, 'media_type' => 2, 'version' => 2,
|
|
'scene' => 1, 'openid' => $user->openid,
|
|
]);
|
|
if ((int) ($result['errcode'] ?? -1) !== 0 || empty($result['trace_id'])) throw new \RuntimeException('WeChat media check submission failed');
|
|
DB::table('content_security_checks')->where('id', $id)->update(['trace_id' => $result['trace_id'], 'updated_at' => now()]);
|
|
} catch (\Throwable $e) {
|
|
DB::table('content_security_checks')->where('id', $id)->update(['status' => 'error', 'updated_at' => now()]);
|
|
Log::warning('Avatar check submission failed', ['check_id' => $id, 'exception' => get_class($e)]);
|
|
throw new InvalidArgumentException('内容检测暂不可用,请稍后重新上传');
|
|
}
|
|
return ['check_id' => $id, 'status' => 'pending'];
|
|
}
|
|
|
|
public function result(int $userId, int $id): array
|
|
{
|
|
$row = DB::table('content_security_checks')->where('id', $id)->where('user_id', $userId)->first();
|
|
if (!$row) throw new InvalidArgumentException('检测记录不存在');
|
|
$status = $row->status;
|
|
if ($status === 'pending' && strtotime($row->created_at) < time() - 600) $status = 'error';
|
|
return ['check_id' => $row->id, 'status' => $status, 'url' => $status === 'pass' ? $row->url : null];
|
|
}
|
|
|
|
public function receive(array $message): void
|
|
{
|
|
if (($message['Event'] ?? '') !== 'wxa_media_check') return;
|
|
$trace = $message['trace_id'] ?? '';
|
|
if (!$trace) return;
|
|
if (!DB::table('content_security_checks')->where('trace_id', $trace)->exists()) {
|
|
// A callback may arrive before the submission response is stored; request a retry.
|
|
throw new \RuntimeException('Unknown media check trace');
|
|
}
|
|
$suggest = $message['result']['suggest'] ?? '';
|
|
$error = (int) ($message['errcode'] ?? -1);
|
|
$status = $error !== 0 ? 'error' : ($suggest === 'pass' ? 'pass' : 'reject');
|
|
// Only a signed callback can reach here. Duplicates cannot overwrite a final decision.
|
|
DB::table('content_security_checks')->where('trace_id', $trace)->where('status', 'pending')
|
|
->update(['status' => $status, 'suggest' => $suggest, 'error_code' => $error, 'updated_at' => now()]);
|
|
}
|
|
|
|
public function assertApproved(int $userId, string $url): void
|
|
{
|
|
$approved = DB::table('content_security_checks')->where('user_id', $userId)->where('url', $url)
|
|
->where('status', 'pass')->exists();
|
|
if (!$approved) throw new InvalidArgumentException('头像尚未通过内容检测,请重新上传并等待检测通过');
|
|
}
|
|
}
|