新增统计,小游戏,系统设置
This commit is contained in:
@@ -15,14 +15,12 @@ namespace app\common\middleware;
|
||||
use app\common\model\Config;
|
||||
use Closure;
|
||||
use think\facade\Cache;
|
||||
use think\exception\HttpException;
|
||||
|
||||
class ApiAuth
|
||||
{
|
||||
protected $apps;
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
$this->apps = Config::whereIn('name', ['appKey', 'appSecret'])->column('value', 'name');
|
||||
$this->apps = Config::whereIn('name', ['app_id', 'app_secret'])->where('group', 'basics')->column('value', 'name');
|
||||
$params = $request->param();
|
||||
$appKey = $request->header('X-Api-AppKey');
|
||||
$timestamp = $request->header('X-Api-Timestamp');
|
||||
@@ -31,29 +29,29 @@ class ApiAuth
|
||||
|
||||
// 1. 基础检查
|
||||
if (!$signature || !$appKey || !$timestamp || !$nonce) {
|
||||
throw new HttpException(401, '缺少必要的签名参数');
|
||||
return response('缺少必要的签名参数', 401);
|
||||
}
|
||||
|
||||
// 2. 检查 AppKey 是否合法
|
||||
if ($this->apps['appKey'] != $appKey) {
|
||||
throw new HttpException(401, '无效的 AppKey');
|
||||
if ($this->apps['app_id'] != $appKey) {
|
||||
return response('无效的 AppKey', 401);
|
||||
}
|
||||
|
||||
// 3. 检查时间戳(防重放攻击,允许 60 秒误差)
|
||||
if (abs(time() - $timestamp) > 60) {
|
||||
// throw new HttpException(401, '请求已超时');
|
||||
return response('请求已超时', 401);
|
||||
}
|
||||
|
||||
// 4. 检查随机字符串
|
||||
$cacheKey = "api_nonce:" . $nonce;
|
||||
if (Cache::has($cacheKey)) {
|
||||
// throw new HttpException(401, '重复请求');
|
||||
return response('重复请求', 401);
|
||||
}
|
||||
Cache::setex($cacheKey, 60, 1);
|
||||
|
||||
// 5. 验证签名
|
||||
if (!$this->checkSignature($params, $timestamp, $nonce, $signature)) {
|
||||
throw new HttpException(401, '签名验证失败');
|
||||
return response('签名验证失败', 401);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
@@ -61,7 +59,7 @@ class ApiAuth
|
||||
|
||||
protected function checkSignature($params, $timestamp, $nonce, $signature)
|
||||
{
|
||||
$appSecret = $this->apps['appSecret'];
|
||||
$appSecret = $this->apps['app_secret'];
|
||||
unset($params['/']);
|
||||
ksort($params);
|
||||
$stringToBeSigned = http_build_query($params) . '&app_secret=' . $appSecret . '×tamp=' . $timestamp . '&nonce=' . $nonce;
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
<?php
|
||||
namespace app\common\service;
|
||||
|
||||
use app\admin\model\Config as ConfigModel;
|
||||
use think\Exception;
|
||||
|
||||
class Jk8Services
|
||||
{
|
||||
private $config = [];
|
||||
private $domain = '';
|
||||
private $accessId = '';
|
||||
private $token = '';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->config = config('jk8');
|
||||
$this->domain = config('jk8.domain');
|
||||
$this->accessId = config('jk8.access_id');
|
||||
$this->token = config('jk8.token');
|
||||
$config = ConfigModel::where('group', 'jdk_api')->column('value', 'name');
|
||||
$this->domain = $config['api_url'];
|
||||
$this->accessId = $config['access_id'];
|
||||
$this->token = $config['token'];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,96 +111,4 @@ class Jk8Services
|
||||
return $result['data']['transactionId'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 存款
|
||||
* @param array $params 参数
|
||||
* @return array
|
||||
* @throws Exception
|
||||
* @throws GameException
|
||||
*/
|
||||
public function deposit(array $params): array
|
||||
{
|
||||
$auth = $this->auth($params);
|
||||
if (!$auth['status']) {
|
||||
throw new GameException($auth['message']);
|
||||
}
|
||||
$data = [
|
||||
'username' => $params['name'],
|
||||
'auth' => $auth['auth'],
|
||||
'amount' => $params['amount'],
|
||||
'currency' => 'MYR',
|
||||
'orderid' => $params['orderNo'],
|
||||
'redirect_url' => $this->returnUrl . '?orderNo='.$params['orderNo'],
|
||||
];
|
||||
return doFormCurl($this->domain . '/merchant/generate_orders',$data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 代付
|
||||
* @param array $params 参数
|
||||
* @throws GameException|Exception
|
||||
*/
|
||||
public function payout(array $params): array
|
||||
{
|
||||
$params['type'] = 'online';
|
||||
$auth = $this->auth($params);
|
||||
if (!$auth['status']) {
|
||||
throw new GameException($auth['message']);
|
||||
}
|
||||
$data = [
|
||||
'auth' => $auth['auth'],
|
||||
'amount' => $params['amount'],
|
||||
'currency' => 'MYR',
|
||||
'orderid' => $params['orderNo'],
|
||||
'bank_id' => $params['bankCode'],
|
||||
'holder_name' => $params['bankAccountName'],
|
||||
'account_no' => $params['bankAccountNo'],
|
||||
];
|
||||
return doFormCurl($this->domain . '/merchant/withdraw_orders',$data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证
|
||||
* @param array $params 参数
|
||||
* @throws Exception
|
||||
*/
|
||||
public function depositVerifySign(array $params)
|
||||
{
|
||||
$orderInfo = PlayerRechargeRecord::query()
|
||||
->where(['tradeno' => $params['order_id']])
|
||||
->first();
|
||||
if (empty($orderInfo)) {
|
||||
return false;
|
||||
}
|
||||
return MD5($this->config[$orderInfo['payment_method']]['secret_key'] . $params['order_id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证
|
||||
* @param array $params 参数
|
||||
* @throws Exception
|
||||
*/
|
||||
public function withdrawalVerifySign(array $params)
|
||||
{
|
||||
return MD5($this->config['online']['secret_key'] . $params['order_id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单查询
|
||||
* @param $orderNo
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function query($orderNo): array
|
||||
{
|
||||
$orderInfo = PlayerRechargeRecord::query()
|
||||
->where(['tradeno' => $orderNo])
|
||||
->first();
|
||||
$data = [
|
||||
'username' => $this->config[$orderInfo['payment_method']]['merchantId'],
|
||||
'id' => $orderNo,
|
||||
];
|
||||
return doFormCurl($this->domain . '/merchant/check_status',$data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
308
app/common/service/XyxServices.php
Normal file
308
app/common/service/XyxServices.php
Normal file
@@ -0,0 +1,308 @@
|
||||
<?php
|
||||
namespace app\common\service;
|
||||
|
||||
use AllowDynamicProperties;
|
||||
use app\admin\model\Config as ConfigModel;
|
||||
use app\common\model\UserScoreLog;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use think\helper\Str;
|
||||
|
||||
#[AllowDynamicProperties] class XyxServices
|
||||
{
|
||||
public $method = 'POST';
|
||||
private $domain;
|
||||
private $appId;
|
||||
private $appSecret;
|
||||
private $player;
|
||||
private $account;
|
||||
private $password;
|
||||
|
||||
public $gameType = [
|
||||
'ECasino' => 'Casino',
|
||||
'Fishing' => 'Fishing',
|
||||
'Bingo' => 'Bingo',
|
||||
'Slot' => 'Slot',
|
||||
];
|
||||
|
||||
public $localGameType = [
|
||||
'slot' => '2',
|
||||
'multiplayer' => '1',
|
||||
'fishing' => '7',
|
||||
'bet' => '5',
|
||||
];
|
||||
public $failCode = [
|
||||
'0' => '应用不存在',
|
||||
'1000' => '参数错误',
|
||||
'1101' => '玩家账号',
|
||||
'1102' => '密码',
|
||||
'1103' => '玩家id',
|
||||
'1204' => '金额',
|
||||
'1205' => '开始时间',
|
||||
'1206' => '结束时间',
|
||||
'2001' => '渠道不存在',
|
||||
'2100' => '用户错误',
|
||||
'2102' => '用户已注册',
|
||||
'2103' => '玩家不存在',
|
||||
'2104' => '玩家已被停用',
|
||||
'2205' => '钱包余额不足',
|
||||
'2206' => '结束时间必须大于起始时间',
|
||||
'2207' => '查询时间不能超过1小时',
|
||||
'3000' => '系统错误',
|
||||
'3201' => '钱包转出失败',
|
||||
'3202' => '钱包转入失败',
|
||||
'3902' => 'JWT清除失败',
|
||||
];
|
||||
|
||||
public function __construct($player = null)
|
||||
{
|
||||
$config = ConfigModel::where('group', 'mini_games')->column('value', 'name');
|
||||
$this->appId = $config['app_id'];
|
||||
$this->appSecret = $config['app_secret'];
|
||||
$this->domain = $config['domain'];
|
||||
if (!empty($player)) {
|
||||
$this->player = $player;
|
||||
$this->account = $player['xyx_account'];
|
||||
$this->password = $player['xyx_password'];
|
||||
if (empty($this->account) || empty($this->password)) {
|
||||
$this->createPlayer($player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成请求
|
||||
* @param $url
|
||||
* @param array $params
|
||||
* @return array|mixed
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function doXyxCurl($url, array $params = [])
|
||||
{
|
||||
$headers = [
|
||||
'appId' => $this->appId,
|
||||
'timestamp' => time(),
|
||||
'nonceStr' => Str::random(6),
|
||||
];
|
||||
$data = array_merge($params,$headers);
|
||||
ksort($data);
|
||||
$signature = hash('sha256', urldecode(http_build_query($data)) . $this->appSecret);
|
||||
$headers['signature'] = $signature;
|
||||
|
||||
$client = new Client([
|
||||
'timeout' => 7,
|
||||
'verify' => true,
|
||||
]);
|
||||
try {
|
||||
$response = $client->post($url, [
|
||||
'json' => $params, // 相当于 asJson(),会自动设置 Content-Type: application/json
|
||||
'headers' => $headers,
|
||||
]);
|
||||
|
||||
if ($response->getStatusCode() !== 200) {
|
||||
throw new \Exception(lang('system_busy')); // ThinkPHP 使用 lang() 代替 trans()
|
||||
}
|
||||
|
||||
$contents = $response->getBody()->getContents();
|
||||
$data = json_decode($contents, true);
|
||||
|
||||
if (empty($data)) {
|
||||
throw new \Exception(lang('system_busy'));
|
||||
}
|
||||
|
||||
return $data;
|
||||
|
||||
} catch (GuzzleException $e) {
|
||||
// 请求失败(如超时、证书错误等)
|
||||
throw new \Exception(lang('system_busy'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取token
|
||||
*/
|
||||
public function getToken($gameId)
|
||||
{
|
||||
$params = [
|
||||
'account' => $this->account,
|
||||
'password' => $this->password,
|
||||
'game_id' => $gameId,
|
||||
];
|
||||
$res = $this->doXyxCurl($this->domain . 'agent/api/get-access-token', $params);
|
||||
if ($res['code'] != 200) {
|
||||
throw new \Exception($this->failCode[$res['code']]);
|
||||
}
|
||||
return $res['data']['access_token'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建玩家
|
||||
*/
|
||||
public function createPlayer($player)
|
||||
{
|
||||
$params = [
|
||||
'account' => 'jk' . $player['jk_user_id'],
|
||||
'password' => Str::random(12),
|
||||
];
|
||||
$res = $this->doXyxCurl($this->domain . 'agent/api/create-player', $params);
|
||||
if ($res['code'] != 200) {
|
||||
throw new \Exception($this->failCode[$res['code']]);
|
||||
}
|
||||
$player->xyx_account = $params['account'];
|
||||
$player->xyx_password = $params['password'];
|
||||
$player->save();
|
||||
$this->account = $params['account'];
|
||||
$this->password = $params['password'];
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 玩家进入游戏
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
public function login(array $data = []): string
|
||||
{
|
||||
$token = $this->getToken($data['gameCode']);
|
||||
$out = UserScoreLog::where('user_id', $this->player->id)
|
||||
->where('type', 2)
|
||||
->whereNotNull('created_by')
|
||||
->order('id', 'desc')
|
||||
->find();
|
||||
if ($out) {
|
||||
$this->balanceTransferIn($out->game_type);
|
||||
}
|
||||
$this->balanceTransferOut($data['gameCode']);
|
||||
$headers = [
|
||||
'appId' => $this->appId,
|
||||
'timestamp' => time(),
|
||||
'nonceStr' => Str::random(6),
|
||||
];
|
||||
ksort($headers);
|
||||
$signature = hash('sha256', urldecode(http_build_query($headers)) . $this->appSecret);
|
||||
$headers['signature'] = $signature;
|
||||
$headers['Authorization'] = 'Bearer ' . $token;
|
||||
|
||||
$client = new Client([
|
||||
'timeout' => 7,
|
||||
'allow_redirects' => false,
|
||||
]);
|
||||
|
||||
try {
|
||||
$response = $client->request('GET', $this->domain . 'agent/enter-game', [
|
||||
'headers' => $headers,
|
||||
]);
|
||||
if ($response->getStatusCode() == 302) {
|
||||
return $response->getHeader('Location')[0] ?? '';
|
||||
}
|
||||
} catch (RequestException $e) {
|
||||
if ($e->hasResponse() && $e->getResponse()->getStatusCode() == 302) {
|
||||
return $e->getResponse()->getHeader('Location')[0] ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取玩家游戏平台余额
|
||||
*/
|
||||
public function getBalance()
|
||||
{
|
||||
$params = [
|
||||
'account' => $this->account,
|
||||
];
|
||||
$res = $this->doXyxCurl($this->domain . 'agent/api/get-player-info', $params);
|
||||
if ($res['code'] != 200) {
|
||||
throw new \Exception($this->failCode[$res['code']]);
|
||||
}
|
||||
return $res['data']['point'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 玩家钱包转入游戏平台
|
||||
*/
|
||||
public function balanceTransferOut($gameType)
|
||||
{
|
||||
$score = $this->player->userScore()->where('game_type', $gameType)->value('score');
|
||||
if ($score == 0) {
|
||||
return true;
|
||||
}
|
||||
return $this->setBalanceTransfer(2, $gameType, $score);
|
||||
}
|
||||
|
||||
/**
|
||||
* 游戏平台转入玩家钱包
|
||||
*/
|
||||
public function balanceTransferIn($gameType)
|
||||
{
|
||||
$balance = $this->getBalance();
|
||||
if ($balance == 0) {
|
||||
$userScore = $this->player->userScore()->where('game_type', $gameType)->find();
|
||||
$userScoreLog = new UserScoreLog();
|
||||
$userScoreLog->save([
|
||||
'user_id' => $this->player->id,
|
||||
'game_type' => $gameType,
|
||||
'before' => $userScore->score,
|
||||
'after' => $userScore->score,
|
||||
'score' => 0,
|
||||
'memo' => '转入',
|
||||
'type' => 1,
|
||||
'created_by'=> 0,
|
||||
]);
|
||||
return true;
|
||||
}
|
||||
return $this->setBalanceTransfer(1, $gameType, $balance);
|
||||
}
|
||||
|
||||
/**
|
||||
* 轉帳進出額度
|
||||
* @param $type
|
||||
* @param float $amount
|
||||
* @return array|mixed|null
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function setBalanceTransfer($type,$gameType, float $amount = 0)
|
||||
{
|
||||
$yCode = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
|
||||
$tradeno = $yCode[intval(date('Y')) - 2011] . strtoupper(dechex(date('m'))) . date('d') . substr(microtime(), 2, 5) . sprintf('%02d', rand(0, 99));
|
||||
$params = [
|
||||
'account' => $this->account,
|
||||
'point' => $amount,
|
||||
'tradeno' => $tradeno
|
||||
];
|
||||
if ($type == 2) {
|
||||
$res = $this->doXyxCurl($this->domain . 'agent/api/transfer-in', $params);
|
||||
} else {
|
||||
$res = $this->doXyxCurl($this->domain . 'agent/api/transfer-out', $params);
|
||||
}
|
||||
if ($res['code'] != 200) {
|
||||
throw new \Exception($this->failCode[$res['code']]);
|
||||
}
|
||||
$userScore = $this->player->userScore()->where('game_type', $gameType)->find();
|
||||
$userScore->created_by = 0;
|
||||
if ($type == 2) {
|
||||
$userScore->score = 0;
|
||||
$userScore->memo = '转出';
|
||||
} else {
|
||||
$userScore->score += $amount;
|
||||
$userScore->memo = '转入';
|
||||
}
|
||||
$userScore->save();
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function getReportRecord(string $startTime = '', string $endTime = '')
|
||||
{
|
||||
$params = [
|
||||
'start_date' => $startTime,
|
||||
'end_date' => $endTime,
|
||||
];
|
||||
$res = $this->doXyxCurl($this->domain . 'agent/api/draw-records-by-date', $params);
|
||||
if ($res['code'] != 200) {
|
||||
throw new \Exception($this->failCode[$res['code']]);
|
||||
}
|
||||
return $res['data'];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user