* @version : HUOSDK 9.0 */ namespace huoIdentify\identifyDriver\driver; use GuzzleHttp\Client; use GuzzleHttp\Exception\ConnectException; use huoIdentify\controller\AES; use huoIdentify\identifyDriver\Driver; use huoIdentify\model\IdentifyOrderModel; use huolib\status\CommonStatus; use huolib\status\IdentifyStatus; use think\Config; use think\Log; class Fcmgame extends Driver { const STATUS_SUCCESS = 0;//认证成功 const STATUS_IN_PROGRESS = 1;//认证中 const STATUS_FAIL = 2;//认证失败 /** * @var string */ protected $cipher = "aes-128-gcm"; /** * @var AES */ protected $aes; /** * @var array */ protected $headers; /** * @var string */ protected $key; /** * @var int $timeout */ protected $timeout = 5; /** * @var Client */ protected $http; /* ai标识 */ protected $ai = ''; protected $biz_id = ''; /** * @param int $mem_id */ public function setMemId($mem_id) { $_prefix = Config::get('identify_conf.fcmgame_ai_prefix'); $_prefix .= time(); $_pad_length = 32 - strlen($_prefix); $this->ai = $_prefix.str_pad($mem_id, $_pad_length, '0', STR_PAD_LEFT); $this->mem_id = $mem_id; } /** * @param array $config */ public function __construct($config = []) { if (empty($config)) { $config = (array)Config::get('identify_conf.fcm_game'); } parent::__construct($config); // 设置属性 $appId = get_val($config, 'appId', ''); $bizId = get_val($config, 'bizId', ''); $this->biz_id = $bizId; $key = get_val($config, 'key', ''); $this->aes = new AES($key, $this->cipher); $this->key = $key; if (!class_exists('\\GuzzleHttp\\Client')) { // 使用已有的GuzzleHttp require_once 'wxpay/TCloudAutoLoader.php'; } $this->http = new Client(['timeout' => 5]); $this->setHeaders($appId, $bizId); } /** * 实名认证 * https://wlc.nppa.gov.cn/fcm_company/index.html#/login */ public function identify() { /* 提交认证之前获取当前玩家是否有认证中的数据,有则使用查询接口 */ $_query_rs = $this->checkCertificationData(); if (CommonStatus::DATA_NOT_FOUND_EXCEPTION != $_query_rs['code']) { /* 只要返回的不是数据未找到则认为无需再次提交认证信息 */ return $this->huoReturn($_query_rs); } $_results = $this->check($this->ai, $this->real_name, $this->id_card); $_results_arr = json_decode($_results, true); if ('0' != $_results_arr['errcode']) { Log::write( 'line='.__LINE__.'&func='.__FUNCTION__.'&class='.__CLASS__.'¶m='.json_encode( array($this->config, $this->id_card, $this->real_name) ).'&rs='.$_results.'[防沉迷实名认证api]', Log::ERROR ); $_code = CommonStatus::INNER_ERROR; return $this->huoError($_code, $_results_arr['errmsg']); } /* 认证中 */ if ($_results_arr['data']['result']['status'] == self::STATUS_IN_PROGRESS) { /* 记录上报信息,用于下次查询 */ $_add_data = [ 'ai' => $this->ai, 'mem_id' => $this->mem_id, 'biz_id' => $this->biz_id, 'real_name' => $this->real_name, 'id_card' => $this->id_card, 'status' => $_results_arr['data']['result']['status'], ]; (new IdentifyOrderModel())->addData($_add_data); $_code = CommonStatus::INVALID_PARAMS; return $this->huoError($_code, $_results_arr['errmsg']); } /* 认证失败 */ if ($_results_arr['data']['result']['status'] == self::STATUS_FAIL) { $_code = IdentifyStatus::IDENTITY_FAIL; return $this->huoError($_code, $_results_arr['errmsg']); } $_code = CommonStatus::NO_ERROR; return $this->huoSuccess($_code, CommonStatus::getMsg($_code), $_results_arr['data']['result']); } /* 查询是否有认证中的数据 */ private function checkCertificationData() { $_last_order_data = (new IdentifyOrderModel())->getLastInfoByBizIdMem($this->biz_id, $this->mem_id); if (empty($_last_order_data)) { /* 数据不存在,需重新认证 */ $_code = CommonStatus::DATA_NOT_FOUND_EXCEPTION; return $this->huoError($_code, CommonStatus::getMsg($_code)); } if ($_last_order_data['status'] != self::STATUS_IN_PROGRESS || $this->real_name != $_last_order_data['real_name'] || $this->id_card != $_last_order_data['id_card']) { /* 状态不是认证中的/玩家证件信息对不上的认为数据不存在,需重新认证 */ $_code = CommonStatus::DATA_NOT_FOUND_EXCEPTION; return $this->huoError($_code, CommonStatus::getMsg($_code)); } $_query_rs = $this->query($_last_order_data['ai']); $_results_arr = json_decode($_query_rs, true); if ('0' != $_results_arr['errcode']) { Log::write( 'line='.__LINE__.'&func='.__FUNCTION__.'&class='.__CLASS__.'¶m='.json_encode($_last_order_data) .'&rs='.$_query_rs.'[防沉迷实名认证api,查询信息]', Log::ERROR ); $_code = CommonStatus::DATA_NOT_FOUND_EXCEPTION; return $this->huoError($_code, $_results_arr['errmsg']); } /* 认证中/认证失败 */ if ($_results_arr['data']['result']['status'] != self::STATUS_SUCCESS) { $_update_data = ['status' => $_results_arr['data']['result']['status']]; (new IdentifyOrderModel())->updateData($_update_data, $_last_order_data['id']); $_code = CommonStatus::INVALID_PARAMS; return $this->huoError($_code, $_results_arr['errmsg']); } $_code = CommonStatus::NO_ERROR; return $this->huoSuccess($_code, CommonStatus::getMsg($_code), $_results_arr['data']['result']); } public function loginBehavior($identify_pi) { if (empty($identify_pi)) { $_code = CommonStatus::INVALID_PARAMS; return $this->huoSuccess($_code, CommonStatus::getMsg($_code)); } $_data = [ ['bt' => 1, 'ct' => 0, 'pi' => $identify_pi] ]; $_results = $this->loginOrOut($_data); $_results_arr = json_decode($_results, true); if ('0' != $_results_arr['errcode']) { Log::write( 'line='.__LINE__.'&func='.__FUNCTION__.'&class='.__CLASS__.'¶m='.json_encode( array($this->config, $this->id_card, $this->real_name, $identify_pi) ).'&rs='.$_results.'[防沉迷行为数据上报api]', Log::ERROR ); $_code = CommonStatus::INNER_ERROR; return $this->huoError($_code, $_results_arr['errmsg']); } $_code = CommonStatus::NO_ERROR; return $this->huoSuccess($_code, CommonStatus::getMsg($_code)); } public function logoutBehavior($identify_pi) { if (empty($identify_pi)) { $_code = CommonStatus::INVALID_PARAMS; return $this->huoSuccess($_code, CommonStatus::getMsg($_code)); } $_data = [ ['bt' => 0, 'ct' => 0, 'pi' => $identify_pi] ]; $_results = $this->loginOrOut($_data); $_results_arr = json_decode($_results, true); if ('0' != $_results_arr['errcode']) { Log::write( 'line='.__LINE__.'&func='.__FUNCTION__.'&class='.__CLASS__.'¶m='.json_encode( array($this->config, $this->id_card, $this->real_name, $identify_pi) ).'&rs='.$_results.'[防沉迷行为数据上报api]', Log::ERROR ); $_code = CommonStatus::INNER_ERROR; return $this->huoError($_code, $_results_arr['errmsg']); } $_code = CommonStatus::NO_ERROR; return $this->huoSuccess($_code, CommonStatus::getMsg($_code)); } /** * check the name and idNum * * @param string $ai * @param string $name * @param string $idNum * @param string $uri * * @return string */ public function check($ai, $name, $idNum, $uri = '') { $uri = $uri ?: 'https://api.wlc.nppa.gov.cn/idcard/authentication/check'; $headers = ['Content-Type' => 'application/json; charset=utf-8']; $headers = array_merge($headers, $this->headers); return $this->doRequest('POST', $uri, $headers, ['ai' => $ai, 'name' => $name, 'idNum' => $idNum]); } /** * check for test * * @param string $ai * @param string $name * @param string $idNum * @param string $testCode * * @return string */ public function testCheck($ai, $name, $idNum, $testCode) { $uri = 'https://wlc.nppa.gov.cn/test/authentication/check/'.$testCode; return $this->check($ai, $name, $idNum, $uri); } /** * query the ai * * @param string $ai * @param string $uri * * @return string */ public function query($ai, $uri = '') { $uri = $uri ?: 'http://api2.wlc.nppa.gov.cn/idcard/authentication/query'; $query = ['ai' => $ai]; return $this->doRequest('GET', $uri, $this->headers, $query, ['query' => $query]); } /** * query for test * * @param string $ai * @param $testCode * * @return string */ public function testQuery($ai, $testCode) { $uri = 'https://wlc.nppa.gov.cn/test/authentication/query/'.$testCode; return $this->query($ai, $uri); } /** * @param $uri * @param mixed $data * * @return string * @example $data = [['bt'=>0, 'ct'=>0, 'pi'=>'1fffbjzos82bs9cnyj1dna7d6d29zg4esnh99u']] */ public function loginOrOut(array $data, $uri = '') { $this->timeout = 3; $collections = []; foreach ($data as $i => $d) { $tmp = []; $tmp['no'] = $i + 1; $tmp['si'] = isset($d['si']) ? $d['si'] : md5($d['pi']); $tmp['bt'] = $d['bt']; $tmp['ot'] = isset($d['ot']) ? $d['ot'] : time(); $tmp['ct'] = $d['ct']; $tmp['di'] = isset($d['di']) ? $d['di'] : ""; $tmp['pi'] = isset($d['pi']) ? $d['pi'] : ""; $collections['collections'][] = $tmp; } $uri = $uri ?: 'http://api2.wlc.nppa.gov.cn/behavior/collection/loginout'; $headers = ['Content-Type' => 'application/json; charset=utf-8']; $headers = array_merge($this->headers, $headers); return $this->doRequest('POST', $uri, $headers, $collections); } /** * @param array $data * @param $testCode * * @return string */ public function testLoginOrOut($data, $testCode) { $uri = 'https://wlc.nppa.gov.cn/test/collection/loginout/'.$testCode; return $this->loginOrOut($data, $uri); } /** * make the sign * * @param $body * @param array $query * * @return string */ private function makeSign($body, $query = []) { $request = array_merge($this->headers, $query); ksort($request); $ret = ''; foreach ($request as $r => $v) { $ret .= $r.$v; } // sha256 $raw = $this->key.$ret.$body; return hash("sha256", $raw); } /** * common request headers * * @param string $appId * @param string $bizId */ private function setHeaders($appId, $bizId) { $this->headers = [ 'appId' => $appId, 'bizId' => $bizId, 'timestamps' => (int)(microtime(true) * 1000), ]; } /** * do request * * @param string $method * @param string $uri * @param array $headers * @param array $body * @param array $options * * @return string */ private function doRequest($method, $uri, array $headers = [], array $body = [], array $options = []) { $raw = json_encode($body, JSON_UNESCAPED_UNICODE); $query = isset($options['query']) ? $options['query'] : []; $body = '{"data":"'.$this->aes->encrypt($raw).'"}'; $headers['sign'] = $this->makeSign($body, $query); $options = array_merge(['headers' => $headers, 'body' => $body, 'timeout' => $this->timeout], $options); try { $response = $this->http->request($method, $uri, $options); return $response->getBody()->getContents(); } catch (ConnectException $e) { $_result = $e->getMessage(); $_step = 0; $_other = 0; \huolib\tool\Log::outErrorLog(debug_backtrace(false, 1)[0], $_result, $_step, $_other); $_array = [ 'errcode' => '-1', 'errmsg' => '链接超时' ]; return json_encode($_array); } } ////////////////////////////////////////////////////// 测试用例 ///////////////////////////////////////////////////// /** * check * * @param string $code1 * @param string $code2 * @param string $code3 */ public function testCaseCheck($code1, $code2, $code3) { // 认证成功 $_result1 = $this->testCheck('100000000000000001', '某一一', '110000190101010001', $code1); var_dump($_result1); // 认证中 $_result2 = $this->testCheck('200000000000000001', '某二一', '110000190201010009', $code2); var_dump($_result2); // 认证失败 $_result3 = $this->testCheck('300000000000000001', '某三一', '110000190201010009', $code3); var_dump($_result3); } /** * query * * @param string $code1 * @param string $code2 * @param string $code3 */ public function testCaseQuery($code1, $code2, $code3) { // 认证成功 $_result1 = $this->testQuery('100000000000000001', $code1); var_dump($_result1); // 认证中 $_result2 = $this->testQuery('200000000000000001', $code2); var_dump($_result2); // 认证失败 $_result3 = $this->testQuery('300000000000000001', $code3); var_dump($_result3); } /** * login or logout * * @param $code1 * @param $code2 */ public function testCaseLoginOrOut($code1, $code2) { // 游客模式 $_result1 = $this->testLoginOrOut( [['bt' => 0, 'ct' => 2, 'si' => uniqid(), 'di' => md5('device')]], $code1 ); var_dump($_result1); // 认证模式 $_result2 = $this->testLoginOrOut( [['bt' => 1, 'ct' => 0, 'pi' => '1fffbjzos82bs9cnyj1dna7d6d29zg4esnh99u']], $code2 ); var_dump($_result2); } }