From 8a35cbe22436221cae6f3d6aba815e6fd5e52756 Mon Sep 17 00:00:00 2001 From: wang hou sheng <76928547+wanghousheng@users.noreply.github.com> Date: Tue, 2 Apr 2024 13:25:47 +0800 Subject: [PATCH] 1 --- app/api/controller/Ocr.php | 76 +++++++ app/api/service/Ocr.php | 67 ++++++ app/api/service/Setting.php | 16 +- app/common/enum/Setting.php | 7 + app/common/library/baidu/OcrCard.php | 259 ++++++++++++++++++++++++ app/common/library/baidu/OcrLicense.php | 128 ++++++++++++ app/common/model/store/Setting.php | 25 ++- app/store/controller/Setting.php | 2 +- 8 files changed, 568 insertions(+), 12 deletions(-) create mode 100644 app/api/controller/Ocr.php create mode 100644 app/api/service/Ocr.php create mode 100644 app/common/library/baidu/OcrCard.php create mode 100644 app/common/library/baidu/OcrLicense.php diff --git a/app/api/controller/Ocr.php b/app/api/controller/Ocr.php new file mode 100644 index 00000000..489de83f --- /dev/null +++ b/app/api/controller/Ocr.php @@ -0,0 +1,76 @@ +request->post('img_id')); + if (!$img_id) { + return $this->renderError('图片ID不能为空'); + } + $img_url = ''; + $file = UploadFile::detail($img_id); + if (!empty($file)) { + $file = $file->toArray(); + $img_url = $file['preview_url']; + } + if (!$img_url) { + return $this->renderError('图片不存在'); + } + $type = intval($this->request->post('type', 1)); + $result = \app\api\service\Ocr::checkCard($img_url, $type); + if (!empty($result['status']) && !empty($result['data'])) { + return $this->renderSuccess($result['data']); + } + return $this->renderError($result['msg']); + } + + /** + * @notes:营业执照识别 + * @return Json + * @throws BaseException + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author: wanghousheng + */ + public function checkLicense(): Json + { + $img_id = intval($this->request->post('img_id')); + if (!$img_id) { + return $this->renderError('图片ID不能为空'); + } + $img_url = ''; + $file = UploadFile::detail($img_id); + if (!empty($file)) { + $file = $file->toArray(); + $img_url = $file['preview_url']; + } + if (!$img_url) { + return $this->renderError('图片不存在'); + } + $result = \app\api\service\Ocr::checkLicense($img_url); + if (!empty($result['status']) && !empty($result['data'])) { + return $this->renderSuccess($result['data']); + } + return $this->renderError($result['msg']); + } +} \ No newline at end of file diff --git a/app/api/service/Ocr.php b/app/api/service/Ocr.php new file mode 100644 index 00000000..da71ff08 --- /dev/null +++ b/app/api/service/Ocr.php @@ -0,0 +1,67 @@ +checkCard($img_url, $type); + } + + /** + * @notes:营业执照识别 + * @param string $img_url + * @return array + * @throws BaseException + * @throws DataNotFoundException + * @throws DbException + * @throws ModelNotFoundException + * @author: wanghousheng + */ + public static function checkLicense(string $img_url): array + { + // 当前用户ID + UserService::getCurrentLoginUserId(); + $config = Setting::getOcr(); + $clientSecret = !empty($config['secret_key']) ? $config['secret_key'] : ''; + $clientId = !empty($config['access_key']) ? $config['access_key'] : ''; + $obj = new OcrLicense($clientId, $clientSecret); + return $obj->check($img_url); + } +} \ No newline at end of file diff --git a/app/api/service/Setting.php b/app/api/service/Setting.php index e52931d1..5fdac2a4 100644 --- a/app/api/service/Setting.php +++ b/app/api/service/Setting.php @@ -13,9 +13,9 @@ declare (strict_types=1); namespace app\api\service; use app\api\model\Setting as SettingModel; +use app\common\enum\Setting as SettingEnum; use app\common\library\helper; use app\common\service\BaseService; -use app\common\enum\Setting as SettingEnum; /** * 服务类:商城设置 @@ -138,6 +138,20 @@ class Setting extends BaseService return helper::pick($values, ['enabled', 'provider', 'config']); } + /** + * @notes:获取ocr设置 + * @return array + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + * @author: wanghousheng + */ + public static function getOcr(): array + { + $values = SettingModel::getItem(SettingEnum::OCR); + return helper::pick($values, ['secret_key', 'access_key']); + } + /** * 获取分类页模板设置 * @return array|mixed diff --git a/app/common/enum/Setting.php b/app/common/enum/Setting.php index ece820af..8df0e786 100644 --- a/app/common/enum/Setting.php +++ b/app/common/enum/Setting.php @@ -24,6 +24,9 @@ class Setting extends EnumBasics // 交易设置 const TRADE = 'trade'; + //ocr设置 + const OCR = 'ocr'; + // 短信通知 const SMS = 'sms'; @@ -98,6 +101,10 @@ class Setting extends EnumBasics 'value' => self::FULL_FREE, 'describe' => '满额包邮设置', ], + self::OCR => [ + 'value' => self::OCR, + 'describe' => 'ocr设置', + ], self::REGISTER => [ 'value' => self::REGISTER, 'describe' => '账户注册设置', diff --git a/app/common/library/baidu/OcrCard.php b/app/common/library/baidu/OcrCard.php new file mode 100644 index 00000000..73123763 --- /dev/null +++ b/app/common/library/baidu/OcrCard.php @@ -0,0 +1,259 @@ +clientId = $clientId; + $this->clientSecret = $clientSecret; + } + + /** + * @notes:图片状态 + * @param string $key + * @author: wanghousheng + */ + private function imageStatus(string $key) + { + $this->status = 0; + switch ($key) { + case 'normal': + $this->status = 1; + break; + case 'reversed_side': + $this->msg = '身份证正反面颠倒'; + break; + case 'non_idcard': + $this->msg = '上传的图片中不包含身份证'; + break; + case'blurred': + $this->msg = '身份证模糊'; + break; + case'other_type_card': + $this->msg = '非身份证类型照'; + break; + case'over_exposure': + $this->msg = '身份证关键字段反光或过曝'; + break; + case'over_dark': + $this->msg = '身份证欠曝(亮度过低)'; + break; + default: + "不合法的证件照"; + break; + } + } + + private function riskType(string $key) + { + $this->status = 0; + switch ($key) { + case 'normal': + $this->status = 1; + break; + case 'copy': + $this->msg = '不能上传复印件'; + break; + case 'temporary': + $this->msg = '临时身份证'; + break; + case'screen': + $this->msg = '身份证翻拍'; + break; + default: + "不合法的证件照"; + break; + } + } + + private function resultHandle(): array + { + return ['status' => $this->status, 'msg' => $this->msg, 'data' => $this->data]; + } + + /** + * @notes:验证身份证正面信息 + * @param $data + * @return void + * @author: wanghousheng + */ + private function validateFrontData($data): void + { + $address = ''; + $card_no = ''; + $birthday = ''; + $username = ''; + $sex = ''; + $nation = ''; + + if (!empty($data->log_id) && !empty($data->image_status) && !empty($data->words_result) && !empty($data->words_result_num)) { + $this->imageStatus($data->image_status); + if (!$this->status) { + return; + } + if (!empty($data->risk_type)) { + $this->riskType($data->risk_type); + if (!$this->status) { + return; + } + } + $words_result_num = intval($data->words_result_num); + if ($words_result_num != 6) { + $this->msg = '身份信息不全'; + return; + } + //身份信息 + $arr = $data->words_result; + if (!empty($arr->住址->words)) { + $address = $arr->住址->words; + } + if (!empty($arr->公民身份号码->words)) { + $card_no = $arr->公民身份号码->words; + } + if (!empty($arr->出生->words)) { + $birthday = $arr->出生->words; + $date = DateTime::createFromFormat('Ymd', $birthday); + $birthday = $date->format('Y-m-d'); + } + if (!empty($arr->姓名->words)) { + $username = $arr->姓名->words; + } + if (!empty($arr->性别->words)) { + $sex = $arr->性别->words; + } + if (!empty($arr->民族->words)) { + $nation = $arr->民族->words; + } + } else { + $this->msg = '接口异常'; + } + $this->data = compact('address', 'sex', 'nation', 'birthday', 'username', 'card_no'); + } + + /** + * @notes:验证身份证反面信息 + * @param $data + * @return void + * @author: wanghousheng + */ + private function validateBackData($data): void + { + $invalid_date = ''; + $issuance_office = ''; + $issuance_date = ''; + if (!empty($data->log_id) && !empty($data->image_status) && !empty($data->words_result) && !empty($data->words_result_num)) { + $this->imageStatus($data->image_status); + if (!$this->status) { + return; + } + if (!empty($data->risk_type)) { + $this->riskType($data->risk_type); + if (!$this->status) { + return; + } + } + $words_result_num = intval($data->words_result_num); + if ($words_result_num != 3) { + $this->msg = '身份信息不全'; + return; + } + //身份信息 + $arr = $data->words_result; + if (!empty($arr->失效日期->words)) { + $invalid_date = $arr->失效日期->words; + $date = DateTime::createFromFormat('Ymd', $invalid_date); + $invalid_date = $date->format('Y-m-d'); + } + if (!empty($arr->签发机关->words)) { + $issuance_office = $arr->签发机关->words; + } + if (!empty($arr->签发日期->words)) { + $issuance_date = $arr->签发日期->words; + $date = DateTime::createFromFormat('Ymd', $issuance_date); + $issuance_date = $date->format('Y-m-d'); + } + } else { + $this->msg = '接口异常'; + } + $this->data = compact('invalid_date', 'issuance_date', 'issuance_office'); + } + + + /** + * @notes:获取token + * @return mixed|string + * @author: wanghousheng + */ + private function getToken() + { + $token = ''; + $data['grant_type'] = 'client_credentials'; + $data['client_id'] = $this->clientId; + $data['client_secret'] = $this->clientSecret; + $result = $this->post(self::TOKENURL, $data); + if (!empty($result->access_token)) { + $token = $result->access_token; + } else { + $this->msg = '获取token失败'; + } + return $token; + } + + /** + * @notes: + * @param string $img_url //证件地址 可外网访问的 + * @param int $type //1 正面 2反面 + * @return array + * @author: wanghousheng + */ + public function checkCard(string $img_url, int $type = 1): array + { + $token = $this->getToken(); + if (!$token) { + return $this->resultHandle(); + } + $data['url'] = $img_url; + $data['id_card_side'] = 'front'; + if ($type != 1) { + $data['id_card_side'] = 'back'; + } + $data['detect_risk'] = 'true'; + $url = self::CARDURL . '?access_token=' . $token; + $result = $this->post($url, $data); + if ($type == 1) { + $this->validateFrontData($result); + } else { + $this->validateBackData($result); + } + return $this->resultHandle(); + } + + private function post(string $url, array $postData) + { + $curl = curl_init(); + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_HEADER, 0); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($curl, CURLOPT_POST, 1); + curl_setopt($curl, CURLOPT_POSTFIELDS, $postData); + $response = curl_exec($curl); + curl_close($curl); + return json_decode($response); + } +} \ No newline at end of file diff --git a/app/common/library/baidu/OcrLicense.php b/app/common/library/baidu/OcrLicense.php new file mode 100644 index 00000000..a446a083 --- /dev/null +++ b/app/common/library/baidu/OcrLicense.php @@ -0,0 +1,128 @@ +clientId = $clientId; + $this->clientSecret = $clientSecret; + } + + public function check($img_url): array + { + $token = $this->getToken(); + if (!$token) { + return $this->resultHandle(); + } + $data['url'] = $img_url; + $data['risk_warn'] = 'true'; + $url = self::LICENSEURL . '?access_token=' . $token; + $result = $this->post($url, $data); + $this->validateData($result); + return $this->resultHandle(); + } + + private function validateData($data) + { + $name = ''; + $credit_code = ''; + if (!empty($data->log_id) && !empty($data->words_result) && !empty($data->words_result_num)) { + if (!empty($data->risk_type)) { + $this->riskType($data->risk_type); + if (!$this->status) { + return; + } + } + $words_result_num = intval($data->words_result_num); + if ($words_result_num != 16) { + $this->msg = '证件信息不全'; + return; + } + //身份信息 + $arr = $data->words_result; + if (!empty($arr->单位名称->words)) { + $name = $arr->单位名称->words; + } + if (!empty($arr->社会信用代码->words)) { + $credit_code = $arr->社会信用代码->words; + } + } else { + $this->msg = '接口异常'; + } + $this->data = compact('name', 'credit_code'); + } + + private function riskType(string $key) + { + $this->status = 0; + switch ($key) { + case 'normal': + $this->status = 1; + break; + case 'copy': + $this->msg = '不能上传复印件'; + break; + case 'temporary': + $this->msg = '不能上传临时证件'; + break; + case'screen': + $this->msg = '不能上传翻拍证件'; + break; + default: + "不合法的证件照"; + break; + } + } + + private function resultHandle(): array + { + return ['status' => $this->status, 'msg' => $this->msg, 'data' => $this->data]; + } + + private function post(string $url, array $postData) + { + $curl = curl_init(); + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_HEADER, 0); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($curl, CURLOPT_POST, 1); + curl_setopt($curl, CURLOPT_POSTFIELDS, $postData); + $response = curl_exec($curl); + curl_close($curl); + return json_decode($response); + } + + /** + * @notes:获取token + * @return mixed|string + * @author: wanghousheng + */ + private function getToken() + { + $token = ''; + $data['grant_type'] = 'client_credentials'; + $data['client_id'] = $this->clientId; + $data['client_secret'] = $this->clientSecret; + $result = $this->post(self::TOKENURL, $data); + if (!empty($result->access_token)) { + $token = $result->access_token; + } else { + $this->msg = '获取token失败'; + } + return $token; + } +} \ No newline at end of file diff --git a/app/common/model/store/Setting.php b/app/common/model/store/Setting.php index 7894814e..82c353cc 100644 --- a/app/common/model/store/Setting.php +++ b/app/common/model/store/Setting.php @@ -12,18 +12,14 @@ declare (strict_types=1); namespace app\common\model\store; -use cores\BaseModel; -use think\facade\Cache; -use app\common\library\helper; -use app\common\enum\{ - Client as ClientEnum, - Setting as SettingEnum, - file\Storage as StorageEnum, - payment\Method as PaymentMethodEnum, +use app\common\enum\{file\Storage as StorageEnum, order\DeliveryType as DeliveryTypeEnum, + Setting as SettingEnum, setting\sms\Scene as SettingSmsSceneEnum, - store\page\category\Style as PageCategoryStyleEnum -}; + store\page\category\Style as PageCategoryStyleEnum}; +use app\common\library\helper; +use cores\BaseModel; +use think\facade\Cache; /** * 系统设置模型 @@ -164,6 +160,15 @@ class Setting extends BaseModel 'freight_rule' => '10', ] ], + // OCR设置 + SettingEnum::OCR => [ + 'key' => SettingEnum::OCR, + 'describe' => 'OCR设置', + 'values' => [ + 'access_key' => '', + 'secret_key' => '', + ] + ], // 上传设置 SettingEnum::STORAGE => [ 'key' => SettingEnum::STORAGE, diff --git a/app/store/controller/Setting.php b/app/store/controller/Setting.php index 62969517..94d1c128 100644 --- a/app/store/controller/Setting.php +++ b/app/store/controller/Setting.php @@ -12,8 +12,8 @@ declare (strict_types=1); namespace app\store\controller; -use think\response\Json; use app\store\model\Setting as SettingModel; +use think\response\Json; /** * 系统设置