764 lines
26 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\channel\service\system;
use app\gateway\service\CurlService;
use app\gateway\service\AuthService;
use app\gateway\service\RedisService;
use app\channel\service\ProductService;
use app\channel\service\ChannelService;
use app\channel\service\ShopService;
use app\merchant\service\OrderService;
use app\merchant\service\OrderAutoService;
use app\merchant\service\MerchantService;
use app\merchant\service\ProductService as MerchantProductService;
use dever\Log;
/**
* 系统核心
* Class Core
* @package app\channel\service
*/
class Core
{
protected $async = false;
protected $data = array();
protected $channel = array();
protected $product = array();
protected $host = '';
protected $mid = '';
protected $token = '';
protected $card_id = '';
public function __construct($async = false, $data = array(), $channel = array(), $product = array())
{
$this->async = $async;
$this->data = $data;
$this->channel = $channel;
$this->product = $product;
if ($this->channel) {
if (isset($this->channel['host']) && $this->channel['host']) {
$this->host = $this->channel['host'];
}
if (isset($this->channel['mid']) && $this->channel['mid']) {
$this->mid = $this->channel['mid'];
}
if (isset($this->channel['token']) && $this->channel['token']) {
$this->token = $this->channel['token'];
}
}
}
# 通用的充值
public function def($method, $param)
{
if (strstr($method, '_')) {
$temp = explode('_', $method);
$method = $temp[1];
return $this->$method($param);
} else {
return false;
}
}
# 检测传入数据
protected function param($param, $check)
{
if (empty($param['order'])) {
return 'order';
}
if (!isset($param['cash'])) {
$param['cash'] = 0;
}
$detail = array();
if ($check) {
foreach ($check as $k => $v) {
if (!isset($param[$k])) {
return $k;
} elseif (empty($param[$k]) && $param[$k] != 0) {
return $k;
} else {
$detail[$v] = $param[$k];
}
}
}
# 获取订单号
$merchant_order = $param['order'];
$param['order'] = $this->createOrder($param['order']);
$account = '';
if (isset($param['card']) && $param['card']) {
$account = $param['card'];
} elseif (isset($param['mobile']) && $param['mobile']) {
$account = $param['mobile'];
} elseif (isset($param['qq']) && $param['qq']) {
$account = $param['qq'];
} elseif (isset($param['account']) && $param['account']) {
$account = $param['account'];
}
$parent_order_id = '';
if (isset($param['parent_order_id']) && $param['parent_order_id']) {
$parent_order_id = $param['parent_order_id'];
}
$response = array();
if ($this->async) {
$this->data['order'] = $param['order'];
$log['type'] = 'merchant_request';
$log['config'] = $this->data;
$this->log($log);
# 下单
$status = 1;
if (isset($this->data['product_key']) && ($this->data['product_key'] != 'zshcz1')) {
} elseif ($account) {
$account_state = OrderService::instance()->countByAccount($account);
if (!$account_state) {
return '已达到最大下单次数';
}
# 检测该账号是否最近5分钟之内下单如果有就延迟下单
$account_order = OrderService::instance()->getByAccount($account, $param['cash']);
if ($account_order) {
$this->data['time'] = time() + 900;
$status = -1;
} else {
/*
# 检测汇天下当前石化渠道是否同时有80个处理中
if ($this->product && isset($this->product['limit_order']) && $this->product['limit_order'] > 0) {
$total = OrderService::instance()->getNum($this->data['product']);
if ($total >= $this->product['limit_order']) {
$status = -3;
}
}
*/
}
}
if (isset($param['s']) && $param['s']) {
$this->channel['order_limit'] = 0;
unset($param['s']);
}
if (isset($this->channel['order_limit']) && $this->channel['order_limit'] > 0) {
$status = -3;
}
$state = $this->create($param['order'], '', $merchant_order, $param['cash'], '', $this->data, $response, $status, $account, $parent_order_id, $this->card_id, false);
if (!$state) {
return '余额不足下单失败';
}
if ($status == 1) {
$this->queue('submit', $this->data);
}
return array('order' => $param['order'], 'account' => $account, 'status' => 1);
} elseif ($this->data['merchant'] == 6000 && $account) {
# 检测该账号是否最近5分钟之内下单如果有就延迟下单
$account_order = OrderService::instance()->getByAccount($account, $param['cash']);
if ($account_order) {
$this->data['order'] = $param['order'];
$this->data['time'] = time() + 300;
$status = -1;
$this->create($param['order'], '', $merchant_order, $param['cash'], '', $this->data, $response, $status, $account, $parent_order_id, $this->card_id, false);
return 'order';
}
} elseif (!$this->data['use_product']) {
$order = OrderService::instance()->get($param['order']);
if ($order && $order['status'] > 1 && $order['status'] != 5) {
return 'order';
}
}
/*
if (!$this->async) {
$merchant_info = MerchantService::instance()->get($this->data['merchant']);
if ($merchant_info['account_surplus'] < $param['cash'] && $merchant_info['credit_surplus'] < $param['cash']) {
$response['msg'] = 'error';
$response['data'] = '余额不足下单失败';
$this->create($param['order'], '', $merchant_order, $param['cash'], '', $this->data, $response, 3, $account);
return $response['data'];
}
}
*/
return array
(
'order' => $param['order'],
'merchant_order' => $merchant_order,
'cash' => $param['cash'],
'detail' => $detail,
'account' => $account,
'status' => -1
);
}
# 获取店铺id
protected function shop()
{
if ($this->data) {
$product = $this->product ? $this->product : ProductService::instance()->get($this->data['merchant'], $this->data['product']);
if ($product && $product['shop_id'] > 0) {
$shop = ShopService::instance()->get($product['shop_id']);
if ($shop && $shop['shop_id']) {
return $shop['shop_id'];
}
}
}
return 0;
}
protected function getUrl($url,$version = 3)
{
$host = sysconf('system_host');
$api_host = sysconf('api_notify_host');
if($api_host && $version == 4){
$host = $api_host;
}
if (!$host) {
if (isset($_SERVER['SERVER_PORT']) && isset($_SERVER['HTTP_HOST'])) {
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
$host = $protocol.$_SERVER['HTTP_HOST'];
} else {
$host = 'https://reapi.gcdat.com';
}
}
return $host . $url;
}
# 通知回调地址
protected function getNotify($order, $type, $api_id = false): string
{
if ($api_id) {
$type .= '&s_api_id=' . $api_id;
}
$api_host = sysconf('api_notify_host');
if($api_host){
$url = $this->getUrl('/call?s_order=' . $order . '&s_type=' . $type.'&version=v4',4);
}else{
$url = $this->getUrl('/gateway/api.notify/call?s_order=' . $order . '&s_type=' . $type);#修改原为v3.0之前版本
}
return $url;
}
# 创建订单
protected function create($order_id, $channel_order_id, $merchant_order_id, $cash, $url, $request, &$response, $status = 1, $account = '', $parent_order_id = '', $card_id = false, $kou = true)
{
$response_data = '';
if ($response) {
if ($response['msg'] == 'success') {
# 直接成功
$status = 2;
} elseif ($response['msg'] == 'ok') {
$status = 4;
} elseif ($response['msg'] == 'yescard') {
$status = 7;
} else {
$status = 3;
}
$response_data = $response['data'];
}
if ($this->data) {
$product = $this->product ? $this->product : ProductService::instance()->get($this->data['merchant'], $this->data['product']);
if ($product) {
if ($card_id == -1) {
$status = 3;
}
$channel = ChannelService::instance()->get($product['cid']);
if ($channel && $product['cid'] == $channel['id']) {
if (isset($this->data['project_id']) && $this->data['project_id']) {
$project_id = $this->data['project_id'];
} else {
$project_id = false;
}
$order = OrderService::instance()->up($this->data['merchant'], $channel['id'], $product['id'], $product['key'], $order_id, $channel_order_id, $merchant_order_id, $cash, $url, $request, $response_data, $status, $account, $parent_order_id, $project_id, $card_id, $this->data['param'], $kou);
if (!$order) {
return false;
}
# 商户后续操作
$merchant = MerchantService::instance()->get($this->data['merchant']);
#TODO 山东电信换渠道处理TODO未处理万
if ($status == 3 && $merchant['id'] == 2 && isset($this->data['product_key']) && $channel['id'] == '2' && isset($request['szProductId']) && strstr($request['szProductId'], '3000')) {
# 如果直接下单失败就获取另外一个相同key的商品吧
$use_product = array();
if (empty($this->data['use_product'])) {
$this->data['use_product'] = array();
}
$this->data['use_product'][] = $product['id'];
$isp = false;
if (isset($order['isp']) && $order['isp']) {
$isp_config = \app\merchant\service\PercentService::instance()->getIsp();
$isp = $isp_config[$order['isp']];
}
$new_product = $this->getProduct($this->data['merchant'], $this->data['product_key'], $this->data['use_product'], $cash, $isp);
if ($new_product) {
# 记录失败的订单信息
OrderAutoService::instance()->up($order['id']);
$response['msg'] = ChannelService::instance()->use($this->data['merchant'], $new_product, $this->data['param'], false, $order_id, $this->data['use_product']);
return true;
}
}
if ($status == 3 && isset($merchant['stop']) && ($merchant['stop'] == 2 || $merchant['stop'] == 4)) {
# 是否暂停
$num = 1;
$order_id = $order['order_id'] . '_' . $num;
# 该渠道下单失败,重新下单,并暂停,等待手动启动
# 记录失败的订单信息
OrderAutoService::instance()->up($order['id']);
# 修改状态
OrderService::instance()->upStatus($order['order_id'], -5, '', false, $num);
return true;
} elseif ($status == 3 && $merchant['order_auto'] == 2 && isset($this->data['product_key'])) {
# 如果直接下单失败就获取另外一个相同key的商品吧
$use_product = array();
if (empty($this->data['use_product'])) {
$this->data['use_product'] = array();
}
$this->data['use_product'][] = $product['id'];
$isp = false;
if (isset($order['isp']) && $order['isp']) {
$isp_config = \app\merchant\service\PercentService::instance()->getIsp();
$isp = $isp_config[$order['isp']];
}
$new_product = $this->getProduct($this->data['merchant'], $this->data['product_key'], $this->data['use_product'], $cash, $isp);
if ($new_product) {
# 记录失败的订单信息
OrderAutoService::instance()->up($order['id']);
$response['msg'] = ChannelService::instance()->use($this->data['merchant'], $new_product, $this->data['param'], false, $order_id, $this->data['use_product']);
return true;
}
}
/*
if ($status == 3 && $product['id'] == 13 && isset($response['array']['status_code']) && $response['array']['status_code'] == '40000' && isset($response['array']['status_msg']) && strstr($response['array']['status_msg'], '账户余额')) {
# 如果是八达通失败,并且账户余额不足,就不通知用户失败,直接延迟到失败表中
$this->data['order'] = $order_id;
OrderService::instance()->upStatus($order_id, -2, $this->data);
return true;
}
*/
$result = array();
$result['project_id'] = $project_id;
$result['order_id'] = $order_id;
$result['merchant_order_id'] = $order['merchant_order_id'];
$result['status'] = $order['status'];
$result['notify_num'] = $order['merchant_callback_num'];
$result['cash'] = $order['cash'];
$result['account'] = $order['account'];
if (isset($order['isp']) && $order['isp']) {
$result['isp'] = $order['isp'];
}
$result['order'] = $order;
if (isset($this->data['param']['notify']) && $this->data['param']['notify']) {
$result['notify'] = $this->data['param']['notify'];
}
MerchantService::instance()->up($order['id'], $merchant, $product['id'], $product['key'], $result);
return true;
}
}
}
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 createOrder($order)
{
if (isset($this->data['order']) && $this->data['order']) {
return $this->data['order'];
}
$order = $this->createOrderId();
$info = OrderService::instance()->get($order);
if (!$info) {
return $order;
} else {
return $this->createOrder($order);
}
//return sha1($this->data['merchant'] . '_' . $this->data['product'] . '_' . $this->createOrderId() . '_' . $order);
}
# 生成订单号
protected function createOrderId()
{
$prefix = sysconf('system_order_perfix');
if (!$prefix) {
$prefix = 'Q';
}
return $prefix . date('Ymd').substr(time(), -5) . substr(microtime(), 2, 5) . sprintf('%02d', mt_rand(100000, 999999));
// if (function_exists('session_create_id')) {
// return strtoupper(session_create_id());
// } else {
// $charid = strtoupper(md5(uniqid(mt_rand(), true)));
// return substr($charid, 0, 8) . substr($charid, 8, 4) . substr($charid, 12, 4) . substr($charid, 16, 4) . substr($charid, 20, 12);
// }
}
# 队列
protected function queue($key, $value = false)
{
$redis = RedisService::getInstance();
if (!$value) {
return $redis->pop($key);
} else {
return $redis->push($key, $value);
}
}
# 请求数据
protected function curl($method, $url, $param = array(), $json = false, $header = false)
{
$log['type'] = 'request';
$log['url'] = $url;
$log['param'] = $param;
$log['config'] = $this->data;
$this->log($log);
$data = CurlService::getInstance($url, $param, $method, $json, $header)->result();
if (!$data) {
$data = CurlService::getInstance($url, $param, $method, $json, $header)->result();
}
return $data;
}
public function http_send($type,$url,$data,$json = false)
{
$header = 'Content-type: application/x-www-form-urlencoded';
$payload = $data;
if($json){
$payload = json_encode($data); // 将数据编码为JSON
$header = 'Content-type: application/json';
}
$options = array(
'http' => array(
'header' => $header,
'method' => $type,
'content' => $payload,
),
);
// var_dump($options);die;
$context = stream_context_create($options); // 创建流上下文
$result = file_get_contents($url, false, $context); // 发送请求
if ($result === FALSE) {
return 'Error';
}
return $result; // 解码JSON响应
// return $this->async;
}
# 通用签名方法,如果有渠道不同的签名方式,需要单独实现
protected function sign($request, $type = 'sha1', $suffix = '', $empty = true)
{
return AuthService::signature($request, $type, $suffix, $empty);
}
protected function getParam($param, $token, $sign_type = 1)
{
return AuthService::get($param, $token, $sign_type);
}
protected function timestamp()
{
return AuthService::timestamp();
}
# 记录日志
protected function log($data)
{
Log::write('gateway', 'log', $data);
}
protected function json_decode($data)
{
$array = json_decode($data, true);
if (!is_array($array) || is_null($array) || json_last_error() != JSON_ERROR_NONE) {
return false;
}
return $array;
}
# 获取手机号
protected function getMobile($card, $n = 1)
{
$info = \app\merchant\service\MobileService::instance()->get($card);
if ($info && $info['mobile']) {
return $info['mobile'];
}
$tel_arr = array(
'130','131','132','133','134','135','136','137','138','139','144','147','150','151','152','153','155','156','157','158','159','176','177','178','180','181','182','183','184','185','186','187','188','189','199',
);
for($i = 0; $i < $n; $i++) {
$tmp[] = $tel_arr[array_rand($tel_arr)].mt_rand(1000,9999).mt_rand(1000,9999);
// $tmp[] = $tel_arr[array_rand($tel_arr)].'xxxx'.mt_rand(1000,9999);
}
$tem = array_unique($tmp);
if (isset($tem[0])) {
$mobile = $tem[0];
\app\merchant\service\MobileService::instance()->up($card, $mobile);
} else {
$mobile = '13800138000';
}
return $mobile;
}
# 获取手机运营商
protected function isp($mobile)
{
return ChannelService::instance()->isp($mobile);
}
# 获取产品id
protected function getGid($cash)
{
$info = $this->product;
if ($info) {
if (isset($info['gid_rule']) && $info['gid_rule']) {
$rule = json_decode($info['gid_rule'], true);
if (isset($rule[$cash]) && $rule[$cash]) {
$gid = $rule[$cash];
return $gid;
}
}
if (isset($info['gid']) && $info['gid']) {
return $info['gid'];
}
}
return -1;
}
//随机生成n条手机号
protected function randomMobile($n = 1)
{
$tel_arr = array(
'130','131','132','133','134','135','136','137','138','139','144','147','150','151','152','153','155','156','157','158','159','176','177','178','180','181','182','183','184','185','186','187','188','189',
);
for($i = 0; $i < $n; $i++) {
$tmp[] = $tel_arr[array_rand($tel_arr)].$this->rands().$this->rands();
}
return array_unique($tmp);
}
//随机生成身份证号
protected function randomShenfen()
{
$city = array(11,12,13,14,15,21,22,23,31,32,33,34,35,36,37,41,42,43,44,45,46,50,51,52,53,54,61,62,63,64,65,71,81,82,91);
//校验位
$parity = array('1','0','X','9','8','7','6','5','4','3','2');
// $a = array('a','b','c');
$arr = array(0,1,2,3,4,5);
$str = '';
// echo $city[array_rand($city)];
//前两位
$str .=$city[array_rand($city)];
//地区位后四位
for($i=0;$i<4;$i++){
$str .=$arr[array_rand($arr)];
}
//出生年 随机20世纪
$str .= '19'.mt_rand(0,9).mt_rand(0,9);
//月份
$month = array('01','02','03','04','05','06','07','08','09','10','11','12');
$str .=$month[array_rand($month)];
//天
$day = mt_rand(0,3);
if($day==3){
$str .=$day.mt_rand(0,1);
}else{
$str .=$day.mt_rand(0,9);
}
//顺序码
for($i=0;$i<3;$i++){
$str .=mt_rand(0,9);
}
//计算加权因子
for($i=18;$i>1;$i--){
$factor[] = fmod(pow(2,$i-1),11);
}
//将加权因子和身份证号对应相乘,再求和
$sum = 0;
for($i=0;$i<count($factor);$i++){
$sum +=$factor[$i]*$str[$i];
}
//将sum对11求余
$mod = fmod($sum,11);
$str .=$parity[$mod];
return $str;
}
# 随机生成姓名
protected function randomName()
{
$name=new rndChinaName();
return $name->getName();
}
protected function rands()
{
$s = mt_rand(1000,9999);
if ($s == '1234') {
return $this->rands();
} elseif ($s == '2345') {
return $this->rands();
} elseif ($s == '3456') {
return $this->rands();
} elseif ($s == '4567') {
return $this->rands();
} elseif ($s == '5678') {
return $this->rands();
} elseif ($s == '6789') {
return $this->rands();
}
return $s;
}
protected function maketime($v)
{
if (!$v) {
return '';
}
if (is_numeric($v)) {
return $v;
}
if (is_array($v)) {
$v = $v[1];
}
if (strstr($v, ' ')) {
$t = explode(' ', $v);
$v = $t[0];
$s = explode(':', $t[1]);
} else {
$s = array(0, 0, 0);
}
if (!isset($s[1])) {
$s[1] = 0;
}
if (!isset($s[2])) {
$s[2] = 0;
}
if (strstr($v, '-')) {
$t = explode('-', $v);
} elseif (strstr($v, '/')) {
$u = explode('/', $v);
$t[0] = $u[2];
$t[1] = $u[0];
$t[2] = $u[1];
}
if (!isset($t)) {
$t = array(0, 0, 0);
}
if (!isset($t[1])) {
$t[1] = 0;
}
if (!isset($t[2])) {
$t[2] = 0;
}
$v = mktime($s[0], $s[1], $s[2], $t[1], $t[2], $t[0]);
return $v;
}
# 获取手机运营商
protected function getMobileInfo($mobile)
{
//git clone https://github.com/shitoudev/phone-location /www/wwwroot/api/extend/phone
// TODO 此处不同服务器需改动的绝对路径
include '/www/wwwroot/bao111/extend/phone/src/PhoneLocation.php';
$pl = new \Shitoudev\Phone\PhoneLocation();
$info = $pl->find($mobile);
return $info;
}
public function diy_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);
}
}