wang hou sheng 8 months ago
parent fc6382e62e
commit 8a35cbe224
  1. 76
      app/api/controller/Ocr.php
  2. 67
      app/api/service/Ocr.php
  3. 16
      app/api/service/Setting.php
  4. 7
      app/common/enum/Setting.php
  5. 259
      app/common/library/baidu/OcrCard.php
  6. 128
      app/common/library/baidu/OcrLicense.php
  7. 25
      app/common/model/store/Setting.php
  8. 2
      app/store/controller/Setting.php

@ -0,0 +1,76 @@
<?php
namespace app\api\controller;
use app\api\model\UploadFile;
use cores\exception\BaseException;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\response\Json;
class Ocr extends Controller
{
/**
* @notes:身份证识别
* @return Json
* @throws BaseException
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @author: wanghousheng
*/
public function checkCard(): 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('图片不存在');
}
$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']);
}
}

@ -0,0 +1,67 @@
<?php
declare (strict_types=1);
namespace app\api\service;
use app\api\service\User as UserService;
use app\common\library\baidu\OcrCard;
use app\common\library\baidu\OcrLicense;
use app\common\service\BaseService;
use cores\exception\BaseException;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
class Ocr extends BaseService
{
/**
* @notes:获取配置
* @return array
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @author: wanghousheng
*/
/**
* @notes:
* @param string $img_url //证件地址 可外网访问的
* @param int $type //1 正面 2反面
* @return array
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException|BaseException
* @author: wanghousheng
*/
public static function checkCard(string $img_url, int $type = 1): 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 OcrCard($clientId, $clientSecret);
return $obj->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);
}
}

@ -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

@ -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' => '账户注册设置',

@ -0,0 +1,259 @@
<?php
namespace app\common\library\baidu;
use DateTime;
class OcrCard
{
const CARDURL = 'https://aip.baidubce.com/rest/2.0/ocr/v1/idcard';
const TOKENURL = 'https://aip.baidubce.com/oauth/2.0/token';
private int $status = 1;
private string $msg = 'success';
private array $data = [];
private string $clientId;
private string $clientSecret;
public function __construct(string $clientId, string $clientSecret)
{
$this->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);
}
}

@ -0,0 +1,128 @@
<?php
namespace app\common\library\baidu;
class OcrLicense
{
const LICENSEURL = 'https://aip.baidubce.com/rest/2.0/ocr/v1/business_license';
const TOKENURL = 'https://aip.baidubce.com/oauth/2.0/token';
private int $status = 1;
private string $msg = 'success';
private array $data = [];
private string $clientId;
private string $clientSecret;
public function __construct(string $clientId, string $clientSecret)
{
$this->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;
}
}

@ -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,

@ -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;
/**
* 系统设置

Loading…
Cancel
Save