596 lines
20 KiB
PHP
596 lines
20 KiB
PHP
<?php
|
||
|
||
namespace app\gateway\controller\api;
|
||
|
||
use think\admin\Controller;
|
||
use app\gateway\service\AuthService;
|
||
use app\gateway\service\RedisService;
|
||
use app\merchant\service\MerchantService;
|
||
use app\merchant\service\OrderService;
|
||
use app\merchant\service\OrderHistoryService;
|
||
use app\merchant\service\OrderAutoService;
|
||
use app\channel\service\ChannelService;
|
||
use app\merchant\service\ProductService as MerchantProductService;
|
||
use dever\Log;
|
||
|
||
/**
|
||
* 接口核心控制器
|
||
* Class Core
|
||
* @package app\gateway\service
|
||
*/
|
||
class Coremf extends Controller
|
||
{
|
||
# 是否检测数据
|
||
protected bool $check = true;
|
||
# 商户appid
|
||
protected mixed $appid = '';
|
||
# 商户id
|
||
protected int $mid = 0;
|
||
# 商户信息
|
||
protected array $merchant = array();
|
||
# token key
|
||
protected string $key = '';
|
||
# product key
|
||
protected string $product = 'query';
|
||
# proid
|
||
protected mixed $proid = 0;
|
||
# input
|
||
protected array $input = array();
|
||
# use_product
|
||
protected array $use_product = array();
|
||
# sign_type
|
||
protected int $sign_type = 1;
|
||
# code码定义
|
||
protected array $code = array
|
||
(
|
||
# 成功
|
||
1 => 'ok',
|
||
# 小于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();
|
||
if (!$this->input) {
|
||
$this->no(-100);
|
||
}
|
||
|
||
$this->appid = input('appid');
|
||
if (!$this->appid) {
|
||
$this->no(-1);
|
||
}
|
||
|
||
$this->proid = input('proid');
|
||
if ($this->proid) {
|
||
# 根据产品id 获取信息
|
||
$pinfo = \app\channel\service\ProductBaseService::instance()->getOne($this->proid);
|
||
if (!$pinfo) {
|
||
$this->no(-2);
|
||
}
|
||
$this->input['proid'] = $this->proid;
|
||
$this->product = $pinfo['key'];
|
||
if ($this->product != 'dhcz') {
|
||
if (!strstr($this->product, '_cash')) {
|
||
$this->input['cash'] = $pinfo['value'];
|
||
}
|
||
} else {
|
||
$this->proid = false;
|
||
}
|
||
} else {
|
||
$product = input('api_product');
|
||
if ($product) {
|
||
$this->product = $product;
|
||
}
|
||
}
|
||
|
||
if (!$this->product) {
|
||
$this->no(-2);
|
||
}
|
||
|
||
# 从数据库中或者缓存中取出商户的信息,并验证是否有效
|
||
$this->getMerchant();
|
||
}
|
||
|
||
/**
|
||
* 检测输入信息是否合法
|
||
*/
|
||
protected function check()
|
||
{
|
||
$this->input();
|
||
$input = $this->input;
|
||
if ($this->proid && !strstr($this->product, '_cash')) {
|
||
unset($input['cash']);
|
||
}
|
||
$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)
|
||
{
|
||
if ($opentime && strstr($opentime, ':')) {
|
||
$opentime = str_replace(':', '', $opentime);
|
||
if (strstr($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->no(-1000);
|
||
}
|
||
} else {
|
||
if ($cur >= $value[0] && $cur < $value[1]) {
|
||
$this->no(-1000);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 对输入的信息进行加密
|
||
*/
|
||
protected function getSignature()
|
||
{
|
||
$this->input();
|
||
$input = $this->input;
|
||
if ($this->proid && !strstr($this->product, '_cash')) {
|
||
unset($input['cash']);
|
||
}
|
||
return AuthService::get($input, $this->key, $this->sign_type);
|
||
}
|
||
|
||
# 获取商户信息
|
||
protected function getMerchant()
|
||
{
|
||
$this->merchant = MerchantService::instance()->get($this->appid);
|
||
if (!$this->merchant) {
|
||
$this->no(-3);
|
||
}
|
||
|
||
if ($this->product != 'query') {
|
||
if (empty($this->input['cash'])) {
|
||
$this->no(-4);
|
||
}
|
||
if ($this->product == 'dxdc') {
|
||
$cash = 0.23;//这里后续处理
|
||
if ($this->merchant['credit_surplus'] < $cash && $this->merchant['account_surplus'] < $cash) {
|
||
$this->no(-4);
|
||
}
|
||
} else {
|
||
if ($this->merchant['credit_surplus'] < $this->input['cash'] && $this->merchant['account_surplus'] < $this->input['cash']) {
|
||
$this->no(-4);
|
||
}
|
||
}
|
||
}
|
||
|
||
$this->mid = $this->merchant['id'];
|
||
if ($this->sign_type == 2) {
|
||
$this->key = $this->merchant['appsecret'];
|
||
} else {
|
||
$this->key = $this->appid . '|' . $this->merchant['appsecret'];
|
||
}
|
||
}
|
||
|
||
# 查找订单
|
||
protected function getOrder($order_id, $merchant_order_id = false)
|
||
{
|
||
$orderService = OrderService::instance();
|
||
$order = $orderService->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 notify($order_id, $request, $status = false, $die = true)
|
||
{
|
||
$orderService = OrderService::instance();
|
||
$order = $orderService->get($order_id);
|
||
if ($order) {
|
||
$up = $nup = false;
|
||
if ($order['status'] != 2 && $order['status'] != 3 && $order['status'] != 5 && $order['status'] != -6) {
|
||
$up = true;
|
||
}
|
||
if (!$status && $request) {
|
||
$channelService = ChannelService::instance();
|
||
$update = $channelService->call('notify', $order['cid'], $request, false, $order);
|
||
$merchant = MerchantService::instance()->get($order['mid']);
|
||
if (isset($order['param']) && $order['param']) {
|
||
$order['param'] = json_decode($order['param'], true);
|
||
} else {
|
||
$order['param'] = false;
|
||
}
|
||
|
||
if ($update['status'] == 3 && isset($merchant['stop']) && $merchant['stop'] > 2) {
|
||
# 是否暂停
|
||
$num = $order['num'] + 1;
|
||
$order_id = $order['order_id'] . '_' . $num;
|
||
# 该渠道下单失败,重新下单,并暂停,等待手动启动
|
||
# 记录失败的订单信息
|
||
$orderAutoService = OrderAutoService::instance();
|
||
|
||
$estate = $orderAutoService->up($order);
|
||
if ($estate) {
|
||
$orderAutoService->upChannelMsg($order['order_id'], $update['status'], $update['data'], $order['num']);
|
||
|
||
# 修改状态
|
||
$orderService->upStatus($order['order_id'], -5, '', false, $num);
|
||
}
|
||
|
||
if ($die) {
|
||
if (isset($update['yes']) && $update['yes']) {
|
||
echo $update['yes'];die;
|
||
}
|
||
echo 'success';die;
|
||
} else {
|
||
return true;
|
||
}
|
||
} elseif ($update['status'] == 3 && isset($merchant['callback_fc']) && $merchant['callback_fc'] > $order['num']) {
|
||
|
||
$num = $order['num'] + 1;
|
||
# 该渠道下单失败,开始复充
|
||
# 记录失败的订单信息
|
||
$orderAutoService = OrderAutoService::instance();
|
||
$estate = $orderAutoService->up($order);
|
||
if ($estate) {
|
||
$orderAutoService->upChannelMsg($order['order_id'], $update['status'], $update['data'], $order['num']);
|
||
|
||
# 修改状态
|
||
$orderService->upStatus($order['order_id'], -4, '', $merchant['callback_fc_time'], $num);
|
||
}
|
||
|
||
if ($die) {
|
||
if (isset($update['yes']) && $update['yes']) {
|
||
echo $update['yes'];die;
|
||
}
|
||
echo 'success';die;
|
||
} else {
|
||
return true;
|
||
}
|
||
} elseif ($update['status'] == 3 && $merchant['callback_auto'] == 2) {
|
||
# 该渠道下单失败,重新开始找另外一个渠道
|
||
$orderAutoService = OrderAutoService::instance();
|
||
$use = $orderAutoService->get($order['order_id']);
|
||
$this->use_product[] = $order['pid'];
|
||
foreach ($use as $k => $v) {
|
||
$this->use_product[] = $v['pid'];
|
||
}
|
||
$isp = false;
|
||
if (isset($order['isp']) && $order['isp'] && $order['isp'] > 0) {
|
||
$isp_config = \app\merchant\service\PercentService::instance()->getIsp();
|
||
$isp = $isp_config[$order['isp']];
|
||
}
|
||
$new_product = $this->getProduct($order['mid'], $order['product_key'], $this->use_product, $order['cash'], $isp);
|
||
if ($new_product && $order['param']) {
|
||
# 记录失败的订单信息
|
||
$orderAutoService->up($order);
|
||
$orderAutoService->upChannelMsg($order_id, $update['status'], $update['data']);
|
||
$channelService->use($order['mid'], $new_product, $order['param'], false, $order_id, $this->use_product);
|
||
if ($die) {
|
||
if (isset($update['yes']) && $update['yes']) {
|
||
echo $update['yes'];die;
|
||
}
|
||
echo 'success';die;
|
||
} else {
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
if ($update && $up) {
|
||
$nup = true;
|
||
$orderService->upChannelMsg($order['id'], $update['status'], $update['data']);
|
||
}
|
||
} elseif ($status) {
|
||
$update['status'] = $status;
|
||
$update['data'] = $request;
|
||
}
|
||
|
||
if ($update && $order['merchant_callback_error'] != 1) {
|
||
//$update['order'] = $order;
|
||
$update['project_id'] = false;
|
||
if (isset($order['project_id'])) {
|
||
$update['project_id'] = $order['project_id'];
|
||
}
|
||
if (isset($order['card_id'])) {
|
||
$update['card_id'] = $order['card_id'];
|
||
}
|
||
$update['account'] = $order['account'];
|
||
$update['cash'] = $order['cash'];
|
||
$update['merchant_order_id'] = $order['merchant_order_id'];
|
||
$update['order_id'] = $order_id;
|
||
$update['notify_num'] = $order['merchant_callback_num'];
|
||
if (isset($order['isp']) && $order['isp']) {
|
||
$update['isp'] = $order['isp'];
|
||
}
|
||
if ($order['param'] && isset($order['param']['notify']) && $order['param']['notify']) {
|
||
$update['notify'] = $order['param']['notify'];
|
||
}
|
||
if ($order['mid'] == 33 && $order['cid'] == 10026) {
|
||
if (isset($update['s_nubmer'])) {
|
||
unset($update['s_nubmer']);
|
||
}
|
||
if (isset($update['msg'])) {
|
||
unset($update['msg']);
|
||
}
|
||
}
|
||
|
||
# 商户后续操作
|
||
if ($up) {
|
||
if (isset($order['error_account_oper']) && $order['error_account_oper'] == 1) {
|
||
# 需要进行扣费
|
||
MerchantService::instance()->up($order['id'], $order['mid'], $order['pid'], $order['product_key'], $update);
|
||
} else {
|
||
# 直接发送
|
||
MerchantService::instance()->notify($order['id'], $order['mid'], $order['pid'], $order['product_key'], $update);
|
||
}
|
||
}
|
||
}
|
||
|
||
if ($update) {
|
||
if ($up && $nup) {
|
||
$orderService->upChannelMsg($order['id'], $update['status'], $update['data']);
|
||
}
|
||
if ($die) {
|
||
if (isset($update['yes']) && $update['yes']) {
|
||
echo $update['yes'];die;
|
||
}
|
||
echo 'success';die;
|
||
} else {
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
if ($die) {
|
||
echo 'fail';die;
|
||
} else {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
private function getProduct($mid, $product, $use_product, $cash, $isp = false)
|
||
{
|
||
$product_data = MerchantProductService::instance()->getAll($mid, $product);
|
||
if ($product_data) {
|
||
foreach ($product_data as $k => $v) {
|
||
if ($v['cash']) {
|
||
if ($isp && (strstr($v['cash'], '联通') || strstr($v['cash'], '移动') || strstr($v['cash'], '电信'))) {
|
||
$cash = $isp;
|
||
}
|
||
$temp = explode(',', $v['cash']);
|
||
if (!in_array($cash, $temp)) {
|
||
continue;
|
||
}
|
||
}
|
||
if (!in_array($v['pid'], $use_product)) {
|
||
return $v['pid'];
|
||
}
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
# 通用签名方法,如果有渠道不同的签名方式,需要单独实现
|
||
protected function sign($request, $type = 'sha1', $suffix = '')
|
||
{
|
||
return AuthService::signature($request, $type, $suffix);
|
||
}
|
||
|
||
# 调取服务
|
||
protected function channel($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);
|
||
}
|
||
|
||
/**
|
||
* 返回失败的消息
|
||
* @param mixed $info
|
||
* @param string $data
|
||
* @param integer $code
|
||
*/
|
||
protected function no($code = 0, $info = '', $data = '{-null-}')
|
||
{
|
||
$msg = isset($this->code[$code]) ? $this->code[$code] : 'error';
|
||
if ($info) {
|
||
$msg .= ':' . $info;
|
||
}
|
||
$data = '{-null-}';
|
||
$this->error($msg, $data, $code);
|
||
}
|
||
|
||
/**
|
||
* 返回成功的消息
|
||
* @param mixed $info
|
||
* @param string $data
|
||
* @param integer $code
|
||
*/
|
||
protected function yes($data = '{-null-}', $info = 'ok', $code = 1)
|
||
{
|
||
if (is_string($data) && $data != 'ok' && $data != 'success') {
|
||
if ($data == '订单号重复') {
|
||
return $this->no(-102);
|
||
}
|
||
return $this->no(-100, $data);
|
||
}
|
||
$this->success($info, $data, $code);
|
||
}
|
||
|
||
# 记录日志
|
||
protected function log($data)
|
||
{
|
||
Log::write('gateway', 'bee', $data);
|
||
}
|
||
#写入日志
|
||
protected function doLog($key,$name,$data){
|
||
Log::write($key, $name, $data);
|
||
}
|
||
# 队列
|
||
protected function queue($key, $value = false)
|
||
{
|
||
$redis = RedisService::getInstance();
|
||
if (!$value) {
|
||
return $redis->pop($key);
|
||
} else {
|
||
return $redis->push($key, $value);
|
||
}
|
||
}
|
||
#蜜蜂汇云签名
|
||
protected function dosign($param,$app_secret){
|
||
//对参数按key进行排序
|
||
ksort($param);
|
||
|
||
//连接所有参数名与参数值
|
||
$buff = '';
|
||
foreach ($param as $k => $v) {
|
||
if ($k != "sign") {
|
||
$buff .= $k . $v;
|
||
}
|
||
}
|
||
//连接加密串
|
||
$buff .= $app_secret;
|
||
//使用md5计算参数串哈希值
|
||
var_dump(array('buff'=>$buff,'se'=>$app_secret,'sign'=>md5($buff)));
|
||
return md5($buff);
|
||
}
|
||
|
||
|
||
public function getSign($params, $appkey, $time, $appsecret)
|
||
{
|
||
if(empty($params)){
|
||
return '';
|
||
}
|
||
|
||
$params = array_merge($params, ['app_key' => $appkey, 'timestamp' => $time]);
|
||
|
||
ksort($params);
|
||
|
||
$buff = '';
|
||
foreach ($params as $k => $v) {
|
||
if ($k != "sign") {
|
||
$buff .= $k . $v;
|
||
}
|
||
}
|
||
|
||
$buff .= $appsecret;
|
||
|
||
$params['sign'] = md5($buff);
|
||
|
||
return $params;
|
||
}
|
||
#curl请求通用方法,$https为false不验证ssl证书,$data为空则是get请求
|
||
private function curl_get_contents($url, $data = array(), $https = false) {
|
||
$results['error'] = '';
|
||
$results['status'] = 0;
|
||
$results['data'] = array();
|
||
$user_agent = $_SERVER['HTTP_USER_AGENT'];
|
||
$curl = curl_init(); // 启动一个CURL会话
|
||
if (!empty($data) && is_array($data)) {
|
||
curl_setopt($curl, CURLOPT_POST, TRUE);
|
||
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($data));
|
||
// curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));
|
||
}
|
||
if ($https) {
|
||
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查
|
||
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2); // 从证书中检查SSL加密算法是否存在
|
||
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转
|
||
|
||
}
|
||
curl_setopt($curl, CURLOPT_URL, $url); // 要访问的地址
|
||
curl_setopt($curl, CURLOPT_TIMEOUT, 30); // 设置超时限制防止死循环
|
||
curl_setopt($curl, CURLOPT_HEADER, 0); // 显示返回的Header区域内容
|
||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 获取的信息以文件流的形式返回
|
||
curl_setopt($curl, CURLOPT_USERAGENT, $user_agent); // 模拟用户使用的浏览器
|
||
curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referer
|
||
$results['data'] = curl_exec($curl); // 执行操作
|
||
if (curl_errno($curl)) {
|
||
$results['error'] = curl_error($curl); //捕抓异常
|
||
|
||
}
|
||
curl_close($curl); // 关闭CURL会话
|
||
return $results; // 返回数据
|
||
|
||
}
|
||
#post请求
|
||
public function curl_https_post($url, $data) {
|
||
return $this->curl_get_contents($url, $data, true);
|
||
}
|
||
#get请求
|
||
public function curl_https_get($url) {
|
||
return $this->curl_get_contents($url, array(), true);
|
||
}
|
||
public function send_post($url, $data)
|
||
{
|
||
|
||
$curl = curl_init();
|
||
curl_setopt_array($curl, array(
|
||
CURLOPT_URL => $url,
|
||
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_POSTFIELDS => $data,
|
||
));
|
||
|
||
$response = curl_exec($curl);
|
||
|
||
$httpCode = curl_getinfo($curl,CURLINFO_HTTP_CODE);
|
||
if($httpCode == 404){
|
||
$response = '404 Page Not Found';
|
||
}
|
||
curl_close($curl);
|
||
return $response;
|
||
|
||
}
|
||
} |