v1.0
parent
fc6382e62e
commit
8a35cbe224
@ -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); |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue