730 lines
20 KiB
PHP
730 lines
20 KiB
PHP
<?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\MerchantService;
|
||
use app\merchant\service\MerchatMappingProductService;
|
||
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);
|
||
}
|
||
|
||
|
||
//Todo
|
||
$this->mappingid = $inputData['relItemId'];
|
||
// $this->product = 'dhcz';
|
||
if ($this->mappingid) {
|
||
# 根据产品id 获取信息
|
||
$pinfo = MerchatMappingProductService::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);
|
||
|
||
|
||
|
||
|
||
// $param1 = '{"decryptList":[{"encryptedData":"' . $this->encryptAccount . '","sceneType":"1"}],"orderId":' . $this->ksorder . '}';
|
||
|
||
// var_dump($param);die;
|
||
|
||
$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¶m=' . $post_data['param'] . '&sign=' . $post_data['sign'] . '&appkey=' . $post_data['appkey'] . '&version=1&signMethod=MD5×tamp=' . $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¶m=' . $paramJson . '&signMethod=MD5×tamp=' . $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'];
|
||
}
|
||
|
||
|
||
}
|