713 lines
20 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace app\openapi\controller;
use app\channel\service\ChannelService;
use app\core\Service;
use app\gateway\service\AuthService;
use app\gateway\service\RedisService;
use app\merchant\service\MerchantMappingProductService;
use app\merchant\service\MerchantService;
use app\merchant\service\OrderHistoryService;
use app\merchant\service\OrderLastHistoryService;
use app\merchant\service\OrderLastweekHistoryService;
use app\merchant\service\OrderService;
use app\merchant\service\OrderTwoHistoryService;
use dever\Log;
use Exception;
use think\admin\Controller;
use think\exception\HttpResponseException;
//use think\facade\Http;
/**
* 快手接口核心控制器
* Class Core
* @package app\gateway\service
*/
class Coreks extends Controller
{
# 是否检测数据
protected bool $check = true;
# 商户appid
protected string $appid = '';
# 商户id
protected int $mid = 0;
# 商户信息
protected array $merchant = array();
# token key
protected string $key = '';
# product key
protected string $product = 'query';
# proid
protected $proid = 0;
# mapping proids
protected $mappingid = 0;
# input
protected array $input = array();
# sign_type
protected int $sign_type = 1;
# code码定义
protected array $code = array
(
# 成功
1 => 'ok',
# 快手错误代码
'4013001' => 'appKey参数缺失',
'4013022' => '黑名单',
'4012004' => '查询不到该手机号信息',
'4013017' => '商品售价参数错误',
'4013008' => 'Param参数缺失',
'4013007' => '签名校验失败',
# 小于0为失败
-1 => 'appid为空',
-2 => '产品错误',
-3 => 'appid无效',
-4 => '余额不足或者没有传入价格',
-5 => 'signature不能为空',
-6 => 'nonce不能为空',
-7 => 'time不能为空',
-8 => 'signature已失效',
-9 => 'signature验证失败',
-100 => '请求错误',
-101 => '订单不存在',
-102 => '订单号重复',
-1000 => '系统维护中',
);
public function initialize(): void
{
parent::initialize();
$this->sign_type = sysconf('sign_type');
if ($this->check) {
$this->check();
}
}
# 获取输入的信息
public function input(): void
{
$this->input = input();
Log::write('openapi', 'kuaishou_request', $this->input);#写入到日志里
if (isset($this->input['test'])) {
$this->testtrue = 1;
} else {
$this->testtrue = 2;
}
#
$this->agentId = input('appkey');
// $this->noKS(4013007);
// var_dump($this->agentId );die;
if (!$this->agentId) {
$this->noKS(4013001);
}
if (is_string($this->input['param'])) {
$this->input['param'] = json_decode($this->input['param'], true);
}
// var_dump($this->input['param']);die;
$this->input = $inputData = $this->input['param'];
if ($inputData['bizType'] == '10') {
$this->agentId = $this->agentId . '_KC';
}
if (!$this->input) {
$this->noKS(4013008);
}
$this->mappingid = $inputData['relItemId'];
// $this->product = 'dhcz';
if ($this->mappingid) {
# 根据产品id 获取信息
$pinfo = MerchantMappingProductService::instance()->getOne($this->mappingid);
$this->pinfo = $pinfo;
// if($pinfo)
if (!$pinfo) {
$this->product = 'dhcz';
} else {
$this->product = $pinfo['key'];
}
} else {
$this->product = 'dhcz';
}
// $this->product = 'dhcz';
$this->order = $inputData['orderId'];
$this->ksorder = $inputData['ksOrderId'];
$this->salePrice = $inputData['price'];
$this->cash = $inputData['amount'] / 100;
$this->input['cash'] = $this->cash;
$this->input['order'] = $this->order;
$this->encryptAccount = $inputData['encryptAccount'];
$this->input['getMobile_num'] = 0;
unset($this->input['orderId']);
# 从数据库中或者缓存中取出商户的信息,并验证是否有效
$this->getMerchant();
$this->card = $this->getMobile();
$this->input['card'] = $this->card;
$this->input['mobile'] = $this->input['card'];
if ($this->product == 'dhcz') {
$this->getNewProduct();
}
if (isset($this->input['ksOrderId'])) {
$this->input['parent_order_id'] = $this->input['ksOrderId'];
}
}
public function getNewProduct(): void
{
if (is_string($this->merchant['other_param'])) {
$array = json_decode($this->merchant['other_param'], true);
if (is_array($array)) {
if (isset($array['phone_global_sub_product']) && $array['phone_global_sub_product'] == 1) {
$isp = Service::instance()->isp($this->input['mobile']);
if ($isp == 1) {
$this->product = 'ydcz';
} elseif ($isp == 2) {
$this->product = 'ltcz';
} elseif ($isp == 3) {
$this->product = 'dxcz';
}
}
}
}
}
/**
* 检测输入信息是否合法
*/
protected function check()
{
// $this->input();
// $input = $this->input;
// if ($this->proid) {
// unset($input['cash']);
// }
// if (isset($input['notify'])) {
// //$input['notify'] = urlencode($input['notify']);
// }
// if(isset($this->input['fillOrderNo'])){
// #判断是否为京东订单
// $signature = array("a1","a2");
// }else {
// $signature = AuthService::check($input, $this->key, $this->sign_type);
// }
// if (is_numeric($signature)) {
// $this->no($signature);
// }
// unset($this->input['signature']);
// if (isset($this->input['nonce'])) {
// unset($this->input['nonce']);
// }
// if (isset($this->input['time'])) {
// unset($this->input['time']);
// }
}
# 检测开放或者维护时间
protected function checkOpenTime($opentime): void
{
if ($opentime && strstr($opentime, ':')) {
$opentime = str_replace(':', '', $opentime);
if (str_contains($opentime, '-')) {
$value = explode('-', $opentime);
$cur = intval(date('Hi'));
$value[0] = intval($value[0]);
$value[1] = intval($value[1]);
if ($value[1] < $value[0]) {
if ($cur >= $value[0] || $cur < $value[1]) {
$this->noKS(-1000);
}
} else {
if ($cur >= $value[0] && $cur < $value[1]) {
$this->noKS(-1000);
}
}
}
}
}
/**
* 对输入的信息进行加密
*/
protected function getSignature()
{
$this->input();
$input = $this->input;
if ($this->proid) {
unset($input['cash']);
}
return AuthService::get($input, $this->key, $this->sign_type);
}
public function test1($notify_url, $post_data): mixed
{
// $postdata = http_build_query($post_data);
$options = array(
'http' => array(
'method' => 'POST',
'header' => 'Content-type:application/x-www-form-urlencoded',
'timeout' => 15 * 60 // 超时时间(单位:s
)
);
$context = stream_context_create($options, $post_data);
$result = file_get_contents($notify_url, false, $context);
return $result;
}
public static function get_curl_post($geturl): mixed
{
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $geturl,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => array(
'User-Agent: Apifox/1.0.0 (https://apifox.com)',
'Accept: */*',
'Host: openapi.kwaixiaodian.com',
'Connection: keep-alive',
'Content-Type: application/x-www-form-urlencoded'
),
));
$response = curl_exec($curl);
curl_close($curl);
return $response;
}
# 获取商户信息
protected function getMobile()
{
// $getUrl = 'https://openapi.kwaixiaodian.com/open/industry/virtual/order/decrypt?';
$param = array();
$param['decryptList'][0] = array(
'encryptedData' => $this->encryptAccount,
'sceneType' => '1'
);
$param['orderId'] = $this->ksorder;
$param = json_encode($param);
$post_data = array(
'appkey' => $this->agentId,
'method' => 'open.industry.virtual.order.decrypt',
'param' => urlencode($param),
'version' => 1,
'signMethod' => 'MD5',
'timestamp' => time()
);
if (isset($this->access_token) && $this->access_token_time > time() && $this->testtrue != 1) {
$post_data['access_token'] = $this->access_token;
} else {
$post_data['access_token'] = $this->getKuaishouToken();
// var_dump($this->input);die;
if ($post_data['access_token'] == 'error') {
return $this->noKS('4012004');
}
}
$post_data['sign'] = $this->sign($post_data, $param);
$getUrl = 'https://open.kwaixiaodian.com/open/industry/virtual/order/decrypt?access_token=' . $post_data['access_token'] . '&method=open.industry.virtual.order.decrypt&param=' . $post_data['param'] . '&sign=' . $post_data['sign'] . '&appkey=' . $post_data['appkey'] . '&version=1&signMethod=MD5&timestamp=' . $post_data['timestamp'];
$result = $this->get_curl_post($getUrl);
$result = json_decode($result, true);
$num = $this->input['getMobile_num'];
$num++;
if ($result['result'] == 1) {
$result = $result['data'][0]['decryptedData'];
} elseif ($num < 3) {
$this->getMobile();
}
return $result;
}
#sing签名
public function sign($post_data, $paramJson): string
{
// $keys = '16fb1715cc284e2653a13f40e2e813f9';
$signData = 'access_token=' . $post_data['access_token'] . '&appkey=' . $post_data['appkey'] . '&method=open.industry.virtual.order.decrypt&param=' . $paramJson . '&signMethod=MD5&timestamp=' . $post_data['timestamp'] . '&version=1&signSecret=' . $this->signkey;
return (md5($signData));
}
//发送回调
public function send_post($notify_url, $post_data, $type): mixed
{
$postdate = http_build_query($post_data);
$options = array(
'http' => array(
'method' => $type,
'header' => 'Content-type:application/x-www-form-urlencoded',
'content' => $postdate,
'timeout' => 15 * 60 // 超时时间(单位:s
)
);
$context = stream_context_create($options);
return file_get_contents($notify_url, false, $context);
}
#测试
/**
* @param $url
* @return bool
*/
public function send_get($url): bool
{
$curl = curl_init(); //初始化
curl_setopt($curl, CURLOPT_URL, $url); //设置抓取的url
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); //设置获取的信息以文件流的形式返回,而不是直接输出。
$output = curl_exec($curl); //执行命令
curl_close($curl); //关闭URL请求
return $output;
}
protected function getMerchant(): void
{
$this->merchant = MerchantService::instance()->get('PT_' . $this->agentId);
if (str_ends_with($this->agentId, "_KC")) {
$this->agentId = substr($this->agentId, 0, -3);
}
$this->mid = $this->merchant['id'];
// $this->agentId = $this->merchant['agentId'];
$this->agentkey = $this->merchant['agentkey'];
$this->refresh_token = $this->merchant['refresh_token'];
$this->access_token_time = $this->merchant['access_token_time'];
$this->access_token = $this->merchant['access_token'];
$this->callnotify = $this->merchant['notify_url'];
$this->signkey = $this->merchant['other_key'];
}
# 查找订单
protected function getOrder($order_id, $merchant_order_id = false)
{
$orderService = OrderService::instance();
$order = $orderService->get($order_id, $merchant_order_id, $this->mid);
if (!$order) {
$orderLastweekHistoryService = OrderLastweekHistoryService::instance();
$order = $orderLastweekHistoryService->get($order_id, $merchant_order_id, $this->mid);
}
if (!$order) {
$orderLastHistoryService = OrderLastHistoryService::instance();
$order = $orderLastHistoryService->get($order_id, $merchant_order_id, $this->mid);
}
if (!$order) {
$orderTwoHistoryService = OrderTwoHistoryService::instance();
$order = $orderTwoHistoryService->get($order_id, $merchant_order_id, $this->mid);
}
if (!$order) {
$orderHistoryService = OrderHistoryService::instance();
$order = $orderHistoryService->get($order_id, $merchant_order_id, $this->mid);
}
return $order;
}
# 通用签名方法,如果有渠道不同的签名方式,需要单独实现
# 调取服务
protected function channel($merchant, $product, $async = false, $param = false, $order = '')
{
if (!$param) {
$param = $this->input;
}
return ChannelService::instance()->use($merchant, $product, $param, $async, $order);
}
/**
* 返回快手下单失败的消息
* @param integer $code
* @param string $ksOrderNo
* @param string $error_msg
* @param string $qudao
*/
protected function noKS($code = 0, $ksOrderNo = '', $error_msg = '', $qudao = '')
{
$msg = $this->code[$code] ?? 'error';
if ($error_msg) {
$error_msg = $msg . ':' . $error_msg;
} elseif ($msg != 'error') {
$error_msg = $msg;
}
$data = array(
'createTime' => date('c'),
'orderNo' => 'E' . $ksOrderNo,
'orederId' => $ksOrderNo,
'status' => 'FAILED'
);
$msg = array(
'result' => $code,
'error_msg' => $error_msg,
'data' => $data
);
throw new HttpResponseException(json($msg));
// $this->error($msg, $data, $code);
}
/**
* 返回成功的消息
* @param string $data
* @param string $qudao
* @param string $OrderNo
* @param mixed $info
* @return mixed
*/
protected function yesks($data = '{-null-}', $qudao = '', $OrderNo = '', $info = false)
{
if (is_string($data) && $data != 'ok') {
if ($data == '订单号重复') {
$data = $this->getOrder('', $OrderNo);
$ksdata = array(
'createTime' => date('c'),
'orderNo' => $OrderNo,
'orederId' => $data['order_id'],
'status' => 'ACCEPTED'
);
$ksmsg = array(
'result' => '1',
'data' => $ksdata
);
throw new HttpResponseException(json($ksmsg));
} elseif (str_contains($data, '已被列入黑名单')) {
$this->blackks($OrderNo);
}
return $this->noKS('JDI_00001', $OrderNo);
}
switch ($qudao) {
case 'submit':
$data = $this->getOrder('', $OrderNo);
$ksdata = array(
'createTime' => date('c'),
'orderNo' => $OrderNo,
'orederId' => $data['order_id'],
'status' => 'ACCEPTED'
);
$ksmsg = array(
'result' => '1',
'data' => $ksdata
);
break;
case '':
break;
default:
}
throw new HttpResponseException(json($ksmsg));
}
/**
* 返回并拉黑的消息
* @param mixed $info
* @param string $data
* @param integer $code
*/
protected function blackks($OrderNo = '')
{
$ksdata = array(
'createTime' => date('c'),
'orderNo' => $OrderNo,
'orederId' => 'E' . $OrderNo,
'status' => 'ACCEPTED'
);
$ksmsg = array(
'result' => '1',
'data' => $ksdata
);
$setData = array(
'mid' => $this->mid,
'orderNo' => $OrderNo,
'agentkey' => $this->agentkey,
'notify_url' => $this->callnotify,
'agentId' => $this->agentId,
'access_token' => $this->access_token,
);
try {
#推送到redis队列
$this->queue('blackcall', $setData);
} catch (Exception $e) {
Log::write('gateway', 'redis_kuaishou_black', $setData);
Log::write('errorTip', 'redis', $e->getMessage());
}
throw new HttpResponseException(json($ksmsg));
//TODO 需要处理redis
}
#获取解密接口
protected function decrypt($merchant, $product, $async = false, $param = false, $order = '')
{
if (!$param) {
$param = $this->input;
}
if ($product == 'cardbuy') {
$async = false;
}
return ChannelService::instance()->use($merchant, $product, $param, $async, $order);
}
# 记录日志
protected function log($data)
{
Log::write('gateway', 'callback', $data);
}
# 队列
protected function queue($key, $value = false)
{
$redis = RedisService::getInstance();
if (!$value) {
return $redis->pop($key);
} else {
return $redis->push($key, $value);
}
}
#获取快手token
public function getKuaishouToken()
{
$tokenurl = 'https://openapi.kwaixiaodian.com/oauth2/refresh_token';
$token_data = array(
'grant_type' => 'refresh_token',
'refresh_token' => $this->refresh_token,
'app_id' => $this->agentId,
'app_secret' => $this->agentkey
);
try {
$resulttoken = $this->send_post($tokenurl, $token_data, 'POST');
$tokenresult = json_decode($resulttoken, true);
if ($tokenresult['result'] != 1) {
#判断未获取数据
Log::write('errorTip', 'getKSToken_error', $resulttoken);
return 'error';
}
} catch (Exception $e) {
Log::write('errorTip', 'getKSToken_error', $e->getMessage());
return 'error';
}
// var_dump($resulttoken);die;
#更新refresh_token
$updaterefresh_token = array(
'refresh_token' => $tokenresult['refresh_token'],
'access_token' => $tokenresult['access_token'],
'access_token_time' => time() + $tokenresult['expires_in']
);
MerchantService::instance()->db()
// ->where(array('id' => $this->mid))
->whereLike('agentId', "%" . $this->agentId . '%')->update($updaterefresh_token);
Log::write('gateway', 'token', $tokenresult);
return $tokenresult['access_token'];
}
}