feat: 项目基础框架+配置+Kernel
This commit is contained in:
@@ -0,0 +1,474 @@
|
||||
<?php
|
||||
|
||||
namespace App\DAO;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Carbon;
|
||||
use GuzzleHttp\Client;
|
||||
use App\AccountLog;
|
||||
use App\Currency;
|
||||
use App\ChainHash;
|
||||
use App\LbxHash;
|
||||
use App\UsersWallet;
|
||||
use App\Jobs\UpdateBalance;
|
||||
class BlockChain
|
||||
{
|
||||
|
||||
public static function getChainBalance($wallet, $chain_currency = '')
|
||||
{
|
||||
try {
|
||||
throw_unless($wallet, new \Exception('钱包不存在'));
|
||||
throw_if(empty($wallet->address), new \Exception('钱包地址不存在'));
|
||||
$currency = Currency::find($wallet->currency);
|
||||
throw_unless($currency, new \Exception('币种不存在'));
|
||||
$address = $wallet->address;
|
||||
$method = 'GET';
|
||||
$chain_currency == '' && $chain_currency = $currency->type;
|
||||
switch ($chain_currency) {
|
||||
case 'eth':
|
||||
$uri = '/wallet/eth/balance';
|
||||
$params = [
|
||||
'query' => [
|
||||
'address' => $address,
|
||||
]
|
||||
];
|
||||
break;
|
||||
case 'erc20':
|
||||
$uri = '/wallet/eth/tokenbalance';
|
||||
$params = [
|
||||
'query' => [
|
||||
'address' => $address,
|
||||
'tokenaddress' => $currency->contract_address,
|
||||
]
|
||||
];
|
||||
break;
|
||||
case 'btc':
|
||||
$uri = '/wallet/btc/balance';
|
||||
$params = [
|
||||
'query' => [
|
||||
'address' => $address,
|
||||
]
|
||||
];
|
||||
break;
|
||||
case 'usdt':
|
||||
$uri = '/wallet/usdt/balance';
|
||||
$params = [
|
||||
'query' => [
|
||||
'address' => $address,
|
||||
]
|
||||
];
|
||||
break;
|
||||
default:
|
||||
throw new \Exception('不支持的数字货币');
|
||||
break;
|
||||
}
|
||||
$http_client = app('LbxChainServer');
|
||||
$response = $http_client->request($method, $uri, $params);
|
||||
$result = $response->getBody()->getContents();
|
||||
$result = json_decode($result, true);
|
||||
//echo $uri;
|
||||
//var_dump($params);
|
||||
//var_dump($result);
|
||||
if (!isset($result['code']) || !isset($result['data'])) {
|
||||
throw new \Exception('请求接口发生错误');
|
||||
}
|
||||
if ($result['code'] != 0) {
|
||||
throw new \Exception($result['msg'] ?? $result['errorinfo']);
|
||||
}
|
||||
$balance_data = $result['data'];
|
||||
$chain_balance = $balance_data['balance'];
|
||||
$lessen = bc_pow(10, $currency->decimal_scale);
|
||||
$fact_chain_balance = bc_div($chain_balance, $lessen);
|
||||
return $fact_chain_balance;
|
||||
} catch (\Throwable $th) {
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
|
||||
public static function updateWalletBalance($wallet, $no_balance_continue = false)
|
||||
{
|
||||
try {
|
||||
$fact_chain_balance = self::getChainBalance($wallet);
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
|
||||
$wallet->refresh();
|
||||
//比较现链上余额是否比原链上余额要大
|
||||
$compare_result = bc_comp($fact_chain_balance, $wallet->old_balance);
|
||||
if ($compare_result > 0) {
|
||||
$diff_balance = bc_sub($fact_chain_balance, $wallet->old_balance);
|
||||
$wallet->old_balance = $fact_chain_balance; //更新链上余额
|
||||
$save_result = $wallet->save();
|
||||
if (!$save_result) {
|
||||
throw new \Exception('更新链上余额失败');
|
||||
}
|
||||
$change_result = change_wallet_balance($wallet, 4, $diff_balance, AccountLog::ETH_EXCHANGE, '链上充币增加');
|
||||
if ($change_result !== true) {
|
||||
throw new \Exception($change_result);
|
||||
}
|
||||
} elseif ($compare_result == 0) {
|
||||
// throw new \Exception(
|
||||
// '用户id:' . $wallet->user_id . ',币种:' . $wallet->currencyCoin->name
|
||||
// . '(' . $wallet->currencyCoin->type . '):链上余额无增加'
|
||||
// );
|
||||
if ($no_balance_continue) {
|
||||
UpdateBalance::dispatch($wallet, false)
|
||||
->onQueue('update:block:balance')
|
||||
->delay(Carbon::now()->addMinutes(5));
|
||||
}
|
||||
} else {
|
||||
|
||||
if ($no_balance_continue) {
|
||||
UpdateBalance::dispatch($wallet, false)
|
||||
->onQueue('update:block:balance')
|
||||
->delay(Carbon::now()->addMinutes(5));
|
||||
}
|
||||
throw new \Exception(
|
||||
'用户id:' . $wallet->user_id . ',币种:' . $wallet->currencyCoin->name
|
||||
. '(' . $wallet->currencyCoin->type . '):链上余额小于系统链上余额'
|
||||
);
|
||||
}
|
||||
DB::commit();
|
||||
} catch (\Exception $ex) {
|
||||
DB::rollBack();
|
||||
throw $ex;
|
||||
}
|
||||
return true;
|
||||
} catch (\Throwable $th) {
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 链上转账
|
||||
*
|
||||
* @param string $currency_name 钱包本身对应的币种名称
|
||||
* @param string $chain_currency 要转的链上币种类型,例如用usdt的钱包地址不仅可以转USDT还可以转BTC,用erc20的钱包地址不仅可以转ERC20代币还可以转ETH
|
||||
* @param string $to_address 转入地址
|
||||
* @param float $transfer_qty 转账数量
|
||||
* @param string $from_address 转出地址
|
||||
* @param string $from_private_key 转出私钥
|
||||
* @param integer $type 转账类型 1 归拢,2 打入手续费,3 提币
|
||||
* @param float $fee 链上手续费
|
||||
* @param string $verificationcode 验证码
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function transfer($currency_name, $chain_currency, $to_address, $transfer_qty, $from_address, $from_private_key, $type, $fee = 0, $verificationcode = '')
|
||||
{
|
||||
try {
|
||||
$currency = Currency::where('name', $currency_name)->first();
|
||||
$chain_currency = Currency::where('name', $chain_currency)->first();
|
||||
if (!$currency) {
|
||||
throw new \Exception('货币不存在');
|
||||
}
|
||||
if (!in_array($currency->type, ['eth', 'erc20', 'usdt', 'btc'])) {
|
||||
throw new \Exception('货币类型不支持');
|
||||
}
|
||||
if (
|
||||
empty($to_address)
|
||||
|| empty($transfer_qty)
|
||||
|| bc_comp($transfer_qty, 0) <= 0
|
||||
|| empty($from_address)
|
||||
|| empty($from_private_key)
|
||||
) {
|
||||
throw new \Exception('参数不完整或不合法');
|
||||
}
|
||||
$origin_transfer_qty = $transfer_qty;
|
||||
$decimal_scale = $chain_currency->decimal_scale ?? 0; //调整为按链上通道的小数位数,解决代币和主链小数位数不一致的问题
|
||||
$lessen = bc_pow(10, $decimal_scale);
|
||||
$transfer_qty = bc_mul($transfer_qty, $lessen, 0); //转账数量转换为区块链上的单位
|
||||
$fee = bc_mul($currency->chain_fee, $lessen, 0); //手续费转换为区域链上的单位
|
||||
$http_client = app('LbxChainServer');
|
||||
$method = 'POST';
|
||||
$result = [];
|
||||
$params = [
|
||||
'multipart' => [
|
||||
[
|
||||
'name' => 'type',
|
||||
'contents' => $type,
|
||||
],
|
||||
[
|
||||
'name' => 'fromaddress',
|
||||
'contents' => $from_address,
|
||||
],
|
||||
[
|
||||
'name' => 'privkey',
|
||||
'contents' => $from_private_key,
|
||||
],
|
||||
[
|
||||
'name' => 'toaddress',
|
||||
'contents' => $to_address,
|
||||
],
|
||||
[
|
||||
'name' => 'amount',
|
||||
'contents' => $transfer_qty,
|
||||
],
|
||||
[
|
||||
'name' => 'tokenaddress',
|
||||
'contents' => $currency->contract_address ?? '',
|
||||
],
|
||||
[
|
||||
'name' => 'fee',
|
||||
'contents' => $fee,
|
||||
],
|
||||
[
|
||||
'name' => 'verificationcode',
|
||||
'contents' => $verificationcode,
|
||||
],
|
||||
]
|
||||
];
|
||||
switch ($chain_currency->type) {
|
||||
case 'erc20':
|
||||
$uri = '/v3/wallet/eth/tokensendto';
|
||||
break;
|
||||
case 'eth':
|
||||
$uri = '/v3/wallet/eth/sendto';
|
||||
break;
|
||||
case 'btc':
|
||||
$uri = '/v3/wallet/btc/sendto';
|
||||
break;
|
||||
case 'usdt':
|
||||
$uri = '/v3/wallet/usdt/sendto';
|
||||
break;
|
||||
default:
|
||||
throw new \Exception('暂不支持' . $chain_currency->type . '币种');
|
||||
break;
|
||||
}
|
||||
|
||||
$response = $http_client->request($method, $uri, $params);
|
||||
$result = json_decode($response->getBody()->getContents(), true);
|
||||
isset($result['txid']) || $result['txid'] = $result['data']['txHex'] ?? ($result['data']['txid'] ?? '');
|
||||
if (isset($result['code']) && $result['code'] == 0) {
|
||||
$chain_hash = [
|
||||
'code' => strtoupper($currency->type),
|
||||
'txid' => $result['txid'],
|
||||
'amount' => $origin_transfer_qty,
|
||||
'sender' => $from_address,
|
||||
'recipient' => $to_address,
|
||||
];
|
||||
ChainHash::unguarded(function () use ($chain_hash) {
|
||||
return ChainHash::create($chain_hash);
|
||||
});
|
||||
} else {
|
||||
throw new \Exception($result['msg'] ?? var_export($result, true));
|
||||
}
|
||||
//dump($params);
|
||||
return $result;
|
||||
} catch (\Exception $e) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 打入手续费
|
||||
*
|
||||
* @param UsersWallet $wallet
|
||||
* @param boolean $refresh_balance
|
||||
* @return void
|
||||
*/
|
||||
public static function transferPoundage(UsersWallet $wallet, $refresh_balance = false)
|
||||
{
|
||||
try {
|
||||
//检测当前是否已有手续费打入的交易hash
|
||||
//是否先刷新链上余额
|
||||
if ($refresh_balance) {
|
||||
$wallet->refresh();
|
||||
self::updateWalletBalance($wallet);
|
||||
}
|
||||
$wallet->refresh();
|
||||
if (bc_comp($wallet->old_balance, 0) <= 0) {
|
||||
throw new \Exception('用户链上余额为0,无须打入手续费');
|
||||
}
|
||||
$fee_currency = $currency = $wallet->currencyCoin;
|
||||
$currency_type = $currency->type;
|
||||
$fee_name = '';
|
||||
if ($currency_type == 'eth' || $currency_type == 'btc' || $currency_type == 'eos' || $currency_type == 'xrp') {
|
||||
throw new \Exception($wallet->currencyCoin->name . '币种无需额外打入归拢手续费');
|
||||
} elseif ($currency_type == 'erc20') {
|
||||
//从总账号往钱包打入eth
|
||||
$transfer_qty = $fee_currency->chain_fee;
|
||||
$from_address = $fee_currency->total_account;
|
||||
$from_private_key = $fee_currency->origin_key;
|
||||
$fee_name = 'eth';
|
||||
} elseif ($currency_type == 'usdt') {
|
||||
//从总账号往钱包打入btc
|
||||
$transfer_qty = bc_add($fee_currency->chain_fee, '0.00000546');
|
||||
$from_address = $fee_currency->total_account;
|
||||
$from_private_key = $fee_currency->origin_key;
|
||||
$fee_name = 'btc';
|
||||
} else {
|
||||
throw new \Exception('不支持的数字货币');
|
||||
}
|
||||
if (empty($from_address) || empty($from_private_key)) {
|
||||
throw new \Exception($fee_name . '币种总账号信息未设置');
|
||||
}
|
||||
$fee_balance = self::getChainBalance($wallet, $fee_name);
|
||||
//当链上手续费余额大于需要转入的手续费时,提示无须再打入手续费
|
||||
if (bc_comp($fee_balance, $transfer_qty) >= 0) {
|
||||
throw new \Exception('钱包内' . $fee_name . '余额充足,无须打入');
|
||||
} else {
|
||||
//当有余额时看相差多少,只打入相差的部分
|
||||
$transfer_qty = bc_sub($transfer_qty, bc_comp($fee_balance, 0) >= 0 ? $fee_balance : 0);
|
||||
}
|
||||
|
||||
$params = [
|
||||
'currency_type' => $currency_type,
|
||||
'fee_name' => $fee_name,
|
||||
'to_address' => $wallet->address,
|
||||
'transfer_qty' => $transfer_qty,
|
||||
'from_address' => $from_address,
|
||||
'from_private_key' => $from_private_key,
|
||||
'type' => 2,
|
||||
];
|
||||
$query_str = md5(http_build_query($params));
|
||||
if (Cache::has($query_str)) {
|
||||
throw new \Exception('当前链上已有手续费交易正在确认,请勿重复打入手续费!交易哈希:' . Cache::get($query_str));
|
||||
}
|
||||
|
||||
// 从当日哈希表中检测是否已有未确认的打入手续费的交易
|
||||
$fee_transaction = LbxHash::where('wallet_id', $wallet->id)
|
||||
->where('created_at', '>=', Carbon::today())
|
||||
->where('type', 2)
|
||||
->where('status', 0)
|
||||
->first();
|
||||
if ($fee_transaction) {
|
||||
throw new \Exception('当前链上已有手续费交易正在确认,请勿重复打入手续费!交易哈希:' . $fee_transaction->txid);
|
||||
}
|
||||
|
||||
DB::beginTransaction();
|
||||
$result = self::transfer($currency_type, $fee_name, $wallet->address, $transfer_qty, $from_address, $from_private_key, 2);
|
||||
if ($result['code'] == 0) {
|
||||
Cache::put($query_str, $result['txid'], 20);
|
||||
//记录链上哈希信息
|
||||
$lbx_hash_data = [
|
||||
'wallet_id' => $wallet->id,
|
||||
'txid' => $result['txid'],
|
||||
'type' => 2, //打入手续费
|
||||
'amount' => $transfer_qty,
|
||||
'status' => 0,
|
||||
];
|
||||
LbxHash::unguarded(function () use ($lbx_hash_data) {
|
||||
return LbxHash::create($lbx_hash_data);
|
||||
});
|
||||
}
|
||||
DB::commit();
|
||||
return $result;
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 钱包链上余额归拢到总账号
|
||||
*
|
||||
* @param \App\UsersWallet $wallet 要归拢的钱包
|
||||
* @param bool $refresh_balance 是否从链上刷新余额
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function collect(UsersWallet $wallet, $refresh_balance = false)
|
||||
{
|
||||
$currency = $wallet->currencyCoin;
|
||||
if (!$currency) {
|
||||
throw new \Exception('对应币种不存在');
|
||||
}
|
||||
$from_address = $wallet->address;
|
||||
$from_private_key = $wallet->private;
|
||||
|
||||
//$to_address = $currency->total_account;
|
||||
$to_address = $currency->collect_account;
|
||||
$contract_address = $currency->contract_address;
|
||||
$currency_type = $currency->type;
|
||||
if (empty($to_address)) {
|
||||
throw new \Exception('归拢地址未设置');
|
||||
}
|
||||
if ($currency_type == 'erc20' && empty($contract_address)) {
|
||||
throw new \Exception('合约地址未设置');
|
||||
}
|
||||
// 根据币种手续费计算
|
||||
$base_transfer_use_qty = 0; //除手续费消耗主链的数量
|
||||
switch ($currency_type) {
|
||||
case 'eth':
|
||||
$fee_currency_name = 'eth';
|
||||
$transfer_fee = $currency->chain_fee ?? 0.001;
|
||||
break;
|
||||
case 'btc':
|
||||
$fee_currency_name = 'btc';
|
||||
$transfer_fee = $currency->chain_fee ?? 0.00006;
|
||||
break;
|
||||
case 'erc20':
|
||||
$fee_currency_name = 'eth';
|
||||
$transfer_fee = $currency->chain_fee ?? 0.001;
|
||||
break;
|
||||
case 'usdt':
|
||||
$fee_currency_name = 'btc';
|
||||
$base_transfer_use_qty = 0.00000546;
|
||||
$transfer_fee = $currency->chain_fee ?? 0.00006;
|
||||
break;
|
||||
default:
|
||||
$fee_currency_name = '';
|
||||
$transfer_fee = 0;
|
||||
}
|
||||
// 查询上次归拢是否完成
|
||||
$lbx_hash = LbxHash::where('status', 0)
|
||||
->where('type', 0)
|
||||
->where('wallet_id', $wallet->id)
|
||||
->first();
|
||||
if ($lbx_hash) {
|
||||
throw new \Exception('当前有归拢操作未完成');
|
||||
}
|
||||
// 是否先刷新链上余额
|
||||
if ($refresh_balance) {
|
||||
self::updateWalletBalance($wallet);
|
||||
}
|
||||
$wallet->refresh();
|
||||
if ($currency_type == 'erc20' || $currency_type == 'usdt') {
|
||||
//检测手续费是否充足:erc20扣eth, usdt扣btc
|
||||
$fee_balance = self::getChainBalance($wallet, $fee_currency_name);
|
||||
$base_total_use_qty = bc_add($base_transfer_use_qty, $transfer_fee); //手续费+链上交易额外消耗,例如USDT要额外消耗0.00000546BTC
|
||||
|
||||
if (bc_comp($fee_balance, $base_total_use_qty) < 0) {
|
||||
throw new \Exception('钱包内手续费可用余额(' . $fee_balance . ')不足,不能归拢');
|
||||
}
|
||||
$transfer_qty = $wallet->old_balance; //代币有多少归多少
|
||||
} else {
|
||||
$transfer_qty = bc_sub($wallet->old_balance, $transfer_fee); //主链归拢减去手续费
|
||||
}
|
||||
//如果链上余额为空或者只有手续费(ETH、BTC)就没必要做归拢
|
||||
if (bc_comp($transfer_qty, 0) <= 0) {
|
||||
throw new \Exception('余额为空或手续费不足,不能归拢');
|
||||
}
|
||||
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
$result = self::transfer($currency->name, $currency->type, $to_address, $transfer_qty, $from_address, $from_private_key, 1);
|
||||
if (!isset($result['code']) || $result['code'] != 0) {
|
||||
throw new \Exception(var_export($result, true));
|
||||
}
|
||||
//记录链上哈希信息
|
||||
$lbx_hash_data = [
|
||||
'wallet_id' => $wallet->id,
|
||||
'txid' => $result['txid'],
|
||||
'type' => 0,
|
||||
'amount' => $transfer_qty,
|
||||
'status' => 0,
|
||||
];
|
||||
LbxHash::unguarded(function () use ($lbx_hash_data) {
|
||||
return LbxHash::create($lbx_hash_data);
|
||||
});
|
||||
$wallet->refresh();
|
||||
$wallet->txid = $result['txid'];
|
||||
$wallet->gl_time = time();
|
||||
$wallet->save();
|
||||
DB::commit();
|
||||
return $result;
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
namespace App\DAO;
|
||||
|
||||
use DB;
|
||||
use App\Utils\RPC;
|
||||
use App\Brand;
|
||||
|
||||
use Request;
|
||||
|
||||
class BrandDAO
|
||||
{
|
||||
public static function lists($num = 0) {
|
||||
if($num == 0) {
|
||||
$brand = Brand::get();
|
||||
} else {
|
||||
$brand = Brand::paginate($num);
|
||||
}
|
||||
return $brand;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
namespace App\DAO;
|
||||
|
||||
use App\Activity;
|
||||
use App\ActivityItem;
|
||||
use App\Utils\RPC;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Pagination\Paginator;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: joey
|
||||
* Date: 2018/1/31
|
||||
* Time: 15:54
|
||||
*/
|
||||
class ExpressADO
|
||||
{
|
||||
/**
|
||||
* 获取物流详情
|
||||
* @param string $url 请求Url
|
||||
* @param array $datas 提交的数据
|
||||
* @return url响应返回的html
|
||||
*/
|
||||
public static function getContetn($ShipperCode, $LogisticCode)
|
||||
{
|
||||
$kdniao = Config::get("express.kdniao");
|
||||
if (empty($ShipperCode) || empty($LogisticCode))
|
||||
return "";
|
||||
$requestData= "{'OrderCode':'','ShipperCode':'".$ShipperCode."','LogisticCode':'".$LogisticCode."'}";
|
||||
$datas = array(
|
||||
'EBusinessID' => $kdniao["EBusinessID"],
|
||||
'RequestType' => '1002',
|
||||
'RequestData' => urlencode($requestData) ,
|
||||
'DataType' => '2',
|
||||
);
|
||||
$datas['DataSign'] = ExpressADO::encrypt($requestData, $kdniao["AppKey"]);
|
||||
$result = ExpressADO::sendPost($kdniao["ReqURL"], $datas);
|
||||
$result = json_decode($result,true);
|
||||
return $result["Traces"];
|
||||
}
|
||||
/**
|
||||
* post提交数据
|
||||
* @param string $url 请求Url
|
||||
* @param array $datas 提交的数据
|
||||
* @return url响应返回的html
|
||||
*/
|
||||
public static function sendPost($url, $datas)
|
||||
{
|
||||
$temps = array();
|
||||
foreach ($datas as $key => $value) {
|
||||
$temps[] = sprintf('%s=%s', $key, $value);
|
||||
}
|
||||
$post_data = implode('&', $temps);
|
||||
$url_info = parse_url($url);
|
||||
if(empty($url_info['port']))
|
||||
{
|
||||
$url_info['port']=80;
|
||||
}
|
||||
$httpheader = "POST " . $url_info['path'] . " HTTP/1.0\r\n";
|
||||
$httpheader.= "Host:" . $url_info['host'] . "\r\n";
|
||||
$httpheader.= "Content-Type:application/x-www-form-urlencoded\r\n";
|
||||
$httpheader.= "Content-Length:" . strlen($post_data) . "\r\n";
|
||||
$httpheader.= "Connection:close\r\n\r\n";
|
||||
$httpheader.= $post_data;
|
||||
$fd = fsockopen($url_info['host'], $url_info['port']);
|
||||
fwrite($fd, $httpheader);
|
||||
$gets = "";
|
||||
$headerFlag = true;
|
||||
while (!feof($fd)) {
|
||||
if (($header = @fgets($fd)) && ($header == "\r\n" || $header == "\n")) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (!feof($fd)) {
|
||||
$gets.= fread($fd, 128);
|
||||
}
|
||||
fclose($fd);
|
||||
|
||||
return $gets;
|
||||
}
|
||||
/**
|
||||
* 电商Sign签名生成
|
||||
* @param data 内容
|
||||
* @param appkey Appkey
|
||||
* @return DataSign签名
|
||||
*/
|
||||
public static function encrypt($data, $appkey) {
|
||||
return urlencode(base64_encode(md5($data.$appkey)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
namespace App\DAO;
|
||||
|
||||
use App\User;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Users;
|
||||
use App\Level;
|
||||
use App\UserUpgradeLog;
|
||||
use App\PrizePool;
|
||||
use App\LeverTransaction;
|
||||
use App\UsersWallet;
|
||||
USE App\UsersWalletcopy;
|
||||
use App\Setting;
|
||||
use App\AccountLog;
|
||||
|
||||
|
||||
class FactprofitsDAO
|
||||
{
|
||||
/**
|
||||
* 会员历史总盈亏释放
|
||||
* @param project $user_id 要释放用户的id
|
||||
*/
|
||||
public static function Profit_loss_release($user_id)
|
||||
{
|
||||
$profit_loss_release=Setting::getValueByKey('profit_loss_release','')/1000;
|
||||
$sum=LeverTransaction::where("user_id","=",$user_id)->where("status","=",3)->sum("fact_profits");
|
||||
// var_dump($profit_loss_release);
|
||||
// var_dump($sum);die;
|
||||
if($sum<0)
|
||||
{
|
||||
$aaaa=UsersWalletcopy::leftjoin("currency","currency.id","=","users_wallet.currency")->where("currency.name","=","USDC")->where("users_wallet.user_id","=",$user_id)->select("users_wallet.id","users_wallet.lever_balance","users_wallet.user_id","currency.id as currency_id")->first();
|
||||
$user_walllet=UsersWalletcopy::where("user_id","=",$aaaa->user_id)->where("currency","=",$aaaa->currency_id)->first();
|
||||
$number=-bc_mul($sum,$profit_loss_release,8);
|
||||
$user_walllet->lever_balance=$user_walllet->lever_balance+$number;
|
||||
$user_walllet->save();
|
||||
try {
|
||||
//增加杠杆币日志记录
|
||||
$result = change_wallet_balance(
|
||||
$user_walllet,
|
||||
3,
|
||||
+$number,
|
||||
AccountLog::PROFIT_LOSS_RELEASE,
|
||||
'历史盈亏释放,增加杠杆币'.$number,
|
||||
false,
|
||||
$user_id,
|
||||
0
|
||||
);
|
||||
if ($result !== true) {
|
||||
throw new \Exception('历史盈亏释放,增加杠杆币:' . $result);
|
||||
}
|
||||
DB::commit();
|
||||
return true;
|
||||
} catch (\Exception $ex) {
|
||||
DB::rollBack();
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
<?PHP
|
||||
namespace App\DAO\Lib;
|
||||
class mail
|
||||
{
|
||||
|
||||
protected $base_url = 'http://api.mysubmail.com/';
|
||||
|
||||
protected $mail_configs;
|
||||
protected $signType = 'normal';
|
||||
|
||||
function __construct($mail_config)
|
||||
{
|
||||
$this->mail_configs = $mail_config;
|
||||
if (!empty($mail_config['server'])) {
|
||||
$this->base_url = $mail_config['server'];
|
||||
}
|
||||
}
|
||||
|
||||
protected function createSignature($request)
|
||||
{
|
||||
$r = "";
|
||||
switch ($this->signType) {
|
||||
case 'normal':
|
||||
$r = $this->mail_configs['appkey'];
|
||||
break;
|
||||
case 'md5':
|
||||
$r = $this->buildSignature($this->argSort($request));
|
||||
break;
|
||||
case 'sha1':
|
||||
$r = $this->buildSignature($this->argSort($request));
|
||||
break;
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
protected function buildSignature($request)
|
||||
{
|
||||
$arg = "";
|
||||
$app = $this->mail_configs['appid'];
|
||||
$appkey = $this->mail_configs['appkey'];
|
||||
while (list ($key, $val) = each($request)) {
|
||||
if (strpos($key, "attachments") === false) {
|
||||
$arg .= $key . "=" . $val . "&";
|
||||
}
|
||||
}
|
||||
$arg = substr($arg, 0, count($arg) - 2);
|
||||
if (get_magic_quotes_gpc()) {
|
||||
$arg = stripslashes($arg);
|
||||
}
|
||||
if ($this->signType == 'sha1') {
|
||||
$r = sha1($app . $appkey . $arg . $app . $appkey);
|
||||
} else {
|
||||
$r = md5($app . $appkey . $arg . $app . $appkey);
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
protected function argSort($request)
|
||||
{
|
||||
ksort($request);
|
||||
reset($request);
|
||||
return $request;
|
||||
}
|
||||
|
||||
public function getTimestamp()
|
||||
{
|
||||
$api = $this->base_url . 'service/timestamp.json';
|
||||
$ch = curl_init($api);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
|
||||
$output = curl_exec($ch);
|
||||
$timestamp = json_decode($output, true);
|
||||
|
||||
return $timestamp['timestamp'];
|
||||
}
|
||||
|
||||
protected function APIHttpRequestCURL($api, $post_data, $method = 'post')
|
||||
{
|
||||
if ($method != 'get') {
|
||||
$ch = curl_init();
|
||||
curl_setopt_array($ch, array(
|
||||
CURLOPT_URL => $api,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_POSTFIELDS => http_build_query($post_data),
|
||||
CURLOPT_CUSTOMREQUEST => strtoupper($method),
|
||||
CURLOPT_HTTPHEADER => array("Content-Type: application/x-www-form-urlencoded")
|
||||
));
|
||||
} else {
|
||||
$url = $api . '?' . http_build_query($post_data);
|
||||
$ch = curl_init($url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);
|
||||
}
|
||||
$output = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
$output = trim($output, "\xEF\xBB\xBF");
|
||||
return json_decode($output, true);
|
||||
}
|
||||
|
||||
|
||||
public function send($request)
|
||||
{
|
||||
$api = $this->base_url . 'mail/send.json';
|
||||
$request['appid'] = $this->mail_configs['appid'];
|
||||
$request['timestamp'] = $this->getTimestamp();
|
||||
if (empty($this->mail_configs['sign_type'])
|
||||
&& $this->mail_configs['sign_type'] == ""
|
||||
&& $this->mail_configs['sign_type'] != "normal"
|
||||
&& $this->mail_configs['sign_type'] != "md5"
|
||||
&& $this->mail_configs['sign_type'] != "sha1"
|
||||
) {
|
||||
$this->signType = 'normal';
|
||||
} else {
|
||||
$this->signType = $this->mail_configs['sign_type'];
|
||||
$request['sign_type'] = $this->mail_configs['sign_type'];
|
||||
}
|
||||
$request['signature'] = $this->createSignature($request);
|
||||
$send = $this->APIHttpRequestCURL($api, $request);
|
||||
|
||||
return $send;
|
||||
}
|
||||
|
||||
public function xsend($request)
|
||||
{
|
||||
$api = $this->base_url . 'mail/xsend.json';
|
||||
$request['appid'] = $this->mail_configs['appid'];
|
||||
$request['timestamp'] = $this->getTimestamp();
|
||||
if (empty($this->mail_configs['sign_type'])
|
||||
&& $this->mail_configs['sign_type'] == ""
|
||||
&& $this->mail_configs['sign_type'] != "normal"
|
||||
&& $this->mail_configs['sign_type'] != "md5"
|
||||
&& $this->mail_configs['sign_type'] != "sha1"
|
||||
) {
|
||||
$this->signType = 'normal';
|
||||
} else {
|
||||
$this->signType = $this->mail_configs['sign_type'];
|
||||
$request['sign_type'] = $this->mail_configs['sign_type'];
|
||||
}
|
||||
$request['signature'] = $this->createSignature($request);
|
||||
$xsend = $this->APIHttpRequestCURL($api, $request);
|
||||
return $xsend;
|
||||
}
|
||||
|
||||
public function subscribe($request)
|
||||
{
|
||||
$api = $this->base_url . 'addressbook/mail/subscribe.json';
|
||||
$request['appid'] = $this->mail_configs['appid'];
|
||||
$request['timestamp'] = $this->getTimestamp();
|
||||
if (empty($this->mail_configs['sign_type'])
|
||||
&& $this->mail_configs['sign_type'] == ""
|
||||
&& $this->mail_configs['sign_type'] != "normal"
|
||||
&& $this->mail_configs['sign_type'] != "md5"
|
||||
&& $this->mail_configs['sign_type'] != "sha1"
|
||||
) {
|
||||
$this->signType = 'normal';
|
||||
} else {
|
||||
$this->signType = $this->mail_configs['sign_type'];
|
||||
$request['sign_type'] = $this->mail_configs['sign_type'];
|
||||
}
|
||||
$request['signature'] = $this->createSignature($request);
|
||||
$subscribe = $this->APIHttpRequestCURL($api, $request);
|
||||
return $subscribe;
|
||||
}
|
||||
|
||||
public function unsubscribe($request)
|
||||
{
|
||||
$api = $this->base_url . 'addressbook/mail/unsubscribe.json';
|
||||
$request['appid'] = $this->mail_configs['appid'];
|
||||
$request['timestamp'] = $this->getTimestamp();
|
||||
if (empty($this->mail_configs['sign_type'])
|
||||
&& $this->mail_configs['sign_type'] == ""
|
||||
&& $this->mail_configs['sign_type'] != "normal"
|
||||
&& $this->mail_configs['sign_type'] != "md5"
|
||||
&& $this->mail_configs['sign_type'] != "sha1"
|
||||
) {
|
||||
$this->signType = 'normal';
|
||||
} else {
|
||||
$this->signType = $this->mail_configs['sign_type'];
|
||||
$request['sign_type'] = $this->mail_configs['sign_type'];
|
||||
}
|
||||
$request['signature'] = $this->createSignature($request);
|
||||
$unsubscribe = $this->APIHttpRequestCURL($api, $request);
|
||||
return $unsubscribe;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Kewail\Sms\Demo;
|
||||
|
||||
require_once "SmsSingleSender.php";
|
||||
|
||||
use Kewail\Sms\SmsSingleSender;
|
||||
|
||||
try {
|
||||
// 请根据实际 accesskey 和 secretkey 进行开发,以下只作为演示 sdk 使用
|
||||
$accesskey = "";
|
||||
$secretkey = "";
|
||||
$phoneNumber = "";
|
||||
|
||||
$singleSender = new SmsSingleSender($accesskey, $secretkey);
|
||||
|
||||
// 普通单发
|
||||
$result = $singleSender->send(0, "86", $phoneNumber , "【Kewail科技】您注册的验证码:128128有效时间30分钟。", "", "");
|
||||
$rsp = json_decode($result);
|
||||
echo $result;
|
||||
echo "<br>";
|
||||
|
||||
} catch (\Exception $e) {
|
||||
echo var_dump($e);
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
// Works well with php5.3 and php5.6.
|
||||
|
||||
namespace App\DAO\Moducloud;
|
||||
|
||||
class SmsSenderUtil {
|
||||
function getRandom() {
|
||||
return rand(100000, 999999);
|
||||
}
|
||||
|
||||
function calculateSig($secretkey, $random, $curTime, $phoneNumbers) {
|
||||
$phoneNumbersString = $phoneNumbers[0];
|
||||
for ($i = 1; $i < count($phoneNumbers); $i++) {
|
||||
$phoneNumbersString .= ("," . $phoneNumbers[$i]);
|
||||
}
|
||||
return hash("sha256", "secretkey=".$secretkey."&random=".$random
|
||||
."&time=".$curTime."&mobile=".$phoneNumbersString);
|
||||
}
|
||||
|
||||
function calculateSigForTemplAndPhoneNumbers($secretkey, $random, $curTime, $phoneNumbers) {
|
||||
$phoneNumbersString = $phoneNumbers[0];
|
||||
for ($i = 1; $i < count($phoneNumbers); $i++) {
|
||||
$phoneNumbersString .= ("," . $phoneNumbers[$i]);
|
||||
}
|
||||
return hash("sha256", "secretkey=".$secretkey."&random=".$random
|
||||
."&time=".$curTime."&mobile=".$phoneNumbersString);
|
||||
}
|
||||
|
||||
function phoneNumbersToArray($nationCode, $phoneNumbers) {
|
||||
$i = 0;
|
||||
$tel = array();
|
||||
do {
|
||||
$telElement = new \stdClass();
|
||||
$telElement->nationcode = $nationCode;
|
||||
$telElement->mobile = $phoneNumbers[$i];
|
||||
array_push($tel, $telElement);
|
||||
} while (++$i < count($phoneNumbers));
|
||||
return $tel;
|
||||
}
|
||||
|
||||
function calculateSigForTempl($secretkey, $random, $curTime, $phoneNumber) {
|
||||
$phoneNumbers = array($phoneNumber);
|
||||
return $this->calculateSigForTemplAndPhoneNumbers($secretkey, $random, $curTime, $phoneNumbers);
|
||||
}
|
||||
|
||||
function sendCurlPost($url, $dataObj) {
|
||||
$curl = curl_init();
|
||||
curl_setopt($curl, CURLOPT_URL, $url);
|
||||
curl_setopt($curl, CURLOPT_HEADER, 0);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($curl, CURLOPT_POST, 1);
|
||||
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($dataObj));
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: application/json', 'Content-Length: ' . strlen(json_encode($dataObj))));
|
||||
$ret = curl_exec($curl);
|
||||
if (false == $ret) {
|
||||
// curl_exec failed
|
||||
$result = "{ \"result\":" . -2 . ",\"errmsg\":\"" . curl_error($curl) . "\"}";
|
||||
} else {
|
||||
$rsp = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||||
if (200 != $rsp) {
|
||||
$result = "{ \"result\":" . -1 . ",\"errmsg\":\"". $rsp . " " . curl_error($curl) ."\"}";
|
||||
} else {
|
||||
$result = $ret;
|
||||
}
|
||||
}
|
||||
curl_close($curl);
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,302 @@
|
||||
<?php
|
||||
|
||||
// Works well with php5.3 and php5.6.
|
||||
|
||||
namespace App\DAO\Moducloud;
|
||||
|
||||
require_once('SmsSenderUtil.php');
|
||||
|
||||
class SmsSingleSender {
|
||||
var $url;
|
||||
var $accesskey;
|
||||
var $secretkey;
|
||||
var $util;
|
||||
|
||||
function __construct($accesskey, $secretkey) {
|
||||
$this->url = "https://live.kewail.com/sms/v1/sendsinglesms";
|
||||
$this->accesskey = $accesskey;
|
||||
$this->secretkey = $secretkey;
|
||||
$this->util = new SmsSenderUtil();
|
||||
}
|
||||
|
||||
/**
|
||||
* 普通单发,明确指定内容,如果有多个签名,请在内容中以【】的方式添加到信息内容中,否则系统将使用默认签名
|
||||
* @param int $type 短信类型,0 为普通短信,1 营销短信
|
||||
* @param string $nationCode 国家码,如 86 为中国
|
||||
* @param string $phoneNumber 不带国家码的手机号
|
||||
* @param string $msg 信息内容,必须与申请的模板格式一致,否则将返回错误
|
||||
* @param string $extend 扩展码,可填空串
|
||||
* @param string $ext 服务端原样返回的参数,可填空串
|
||||
* @return string json string { "result": xxxxx, "errmsg": "xxxxxx" ... },被省略的内容参见协议文档
|
||||
*/
|
||||
function send($type, $nationCode, $phoneNumber, $msg, $extend = "", $ext = "") {
|
||||
/*
|
||||
请求包体
|
||||
{
|
||||
"tel": {
|
||||
"nationcode": "86",
|
||||
"mobile": "13788888888"
|
||||
},
|
||||
"type": 0,
|
||||
"msg": "你的验证码是1234",
|
||||
"sig": "fdba654e05bc0d15796713a1a1a2318c",
|
||||
"time": 1479888540,
|
||||
"extend": "",
|
||||
"ext": ""
|
||||
}
|
||||
应答包体
|
||||
{
|
||||
"result": 0,
|
||||
"errmsg": "OK",
|
||||
"ext": "",
|
||||
"sid": "xxxxxxx",
|
||||
"fee": 1
|
||||
}
|
||||
*/
|
||||
$random = $this->util->getRandom();
|
||||
$curTime = time();
|
||||
$wholeUrl = $this->url . "?accesskey=" . $this->accesskey . "&random=" . $random;
|
||||
|
||||
// 按照协议组织 post 包体
|
||||
$data = new \stdClass();
|
||||
$tel = new \stdClass();
|
||||
$tel->nationcode = "".$nationCode;
|
||||
$tel->mobile = "".$phoneNumber;
|
||||
|
||||
$data->tel = $tel;
|
||||
$data->type = (int)$type;
|
||||
$data->msg = $msg;
|
||||
$data->sig = hash("sha256",
|
||||
"secretkey=".$this->secretkey."&random=".$random."&time=".$curTime."&mobile=".$phoneNumber, FALSE);
|
||||
$data->time = $curTime;
|
||||
$data->extend = $extend;
|
||||
$data->ext = $ext;
|
||||
return $this->util->sendCurlPost($wholeUrl, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定模板单发
|
||||
* @param string $nationCode 国家码,如 86 为中国
|
||||
* @param string $phoneNumber 不带国家码的手机号
|
||||
* @param int $templId 模板 id
|
||||
* @param array $params 模板参数列表,如模板 {1}...{2}...{3},那么需要带三个参数
|
||||
* @param string $sign 签名,如果填空串,系统会使用默认签名
|
||||
* @param string $extend 扩展码,可填空串
|
||||
* @param string $ext 服务端原样返回的参数,可填空串
|
||||
* @return string json string { "result": xxxxx, "errmsg": "xxxxxx" ... },被省略的内容参见协议文档
|
||||
*/
|
||||
function sendWithParam($nationCode, $phoneNumber, $templId = 0, $params, $sign = "", $extend = "", $ext = "") {
|
||||
/*
|
||||
请求包体
|
||||
{
|
||||
"tel": {
|
||||
"nationcode": "86",
|
||||
"mobile": "13788888888"
|
||||
},
|
||||
"sign": "Kewail",
|
||||
"tpl_id": 19,
|
||||
"params": [
|
||||
"验证码",
|
||||
"1234",
|
||||
"4"
|
||||
],
|
||||
"sig": "fdba654e05bc0d15796713a1a1a2318c",
|
||||
"time": 1479888540,
|
||||
"extend": "",
|
||||
"ext": ""
|
||||
}
|
||||
应答包体
|
||||
{
|
||||
"result": 0,
|
||||
"errmsg": "OK",
|
||||
"ext": "",
|
||||
"sid": "xxxxxxx",
|
||||
"fee": 1
|
||||
}
|
||||
*/
|
||||
$random = $this->util->getRandom();
|
||||
$curTime = time();
|
||||
$wholeUrl = $this->url . "?sdkaccesskey=" . $this->accesskey . "&random=" . $random;
|
||||
|
||||
// 按照协议组织 post 包体
|
||||
$data = new \stdClass();
|
||||
$tel = new \stdClass();
|
||||
$tel->nationcode = "".$nationCode;
|
||||
$tel->mobile = "".$phoneNumber;
|
||||
|
||||
$data->tel = $tel;
|
||||
$data->sig = $this->util->calculateSigForTempl($this->secretkey, $random, $curTime, $phoneNumber);
|
||||
$data->tpl_id = $templId;
|
||||
$data->params = $params;
|
||||
$data->sign = $sign;
|
||||
$data->time = $curTime;
|
||||
$data->extend = $extend;
|
||||
$data->ext = $ext;
|
||||
return $this->util->sendCurlPost($wholeUrl, $data);
|
||||
}
|
||||
}
|
||||
|
||||
class SmsMultiSender {
|
||||
var $url;
|
||||
var $accesskey;
|
||||
var $secretkey;
|
||||
var $util;
|
||||
|
||||
function __construct($accesskey, $secretkey) {
|
||||
$this->url = "https://live.kewail.com/sms/v1/sendsinglesms";
|
||||
$this->accesskey = $accesskey;
|
||||
$this->secretkey = $secretkey;
|
||||
$this->util = new SmsSenderUtil();
|
||||
}
|
||||
|
||||
/**
|
||||
* 普通群发,明确指定内容,如果有多个签名,请在内容中以【】的方式添加到信息内容中,否则系统将使用默认签名
|
||||
* 【注意】海外短信无群发功能
|
||||
* @param int $type 短信类型,0 为普通短信,1 营销短信
|
||||
* @param string $nationCode 国家码,如 86 为中国
|
||||
* @param string $phoneNumbers 不带国家码的手机号列表
|
||||
* @param string $msg 信息内容,必须与申请的模板格式一致,否则将返回错误
|
||||
* @param string $extend 扩展码,可填空串
|
||||
* @param string $ext 服务端原样返回的参数,可填空串
|
||||
* @return string json string { "result": xxxxx, "errmsg": "xxxxxx" ... },被省略的内容参见协议文档
|
||||
*/
|
||||
function send($type, $nationCode, $phoneNumbers, $msg, $extend = "", $ext = "") {
|
||||
/*
|
||||
请求包体
|
||||
{
|
||||
"tel": [
|
||||
{
|
||||
"nationcode": "86",
|
||||
"mobile": "13788888888"
|
||||
},
|
||||
{
|
||||
"nationcode": "86",
|
||||
"mobile": "13788888889"
|
||||
}
|
||||
],
|
||||
"type": 0,
|
||||
"msg": "你的验证码是1234",
|
||||
"sig": "fdba654e05bc0d15796713a1a1a2318c",
|
||||
"time": 1479888540,
|
||||
"extend": "",
|
||||
"ext": ""
|
||||
}
|
||||
应答包体
|
||||
{
|
||||
"result": 0,
|
||||
"errmsg": "OK",
|
||||
"ext": "",
|
||||
"detail": [
|
||||
{
|
||||
"result": 0,
|
||||
"errmsg": "OK",
|
||||
"mobile": "13788888888",
|
||||
"nationcode": "86",
|
||||
"sid": "xxxxxxx",
|
||||
"fee": 1
|
||||
},
|
||||
{
|
||||
"result": 0,
|
||||
"errmsg": "OK",
|
||||
"mobile": "13788888889",
|
||||
"nationcode": "86",
|
||||
"sid": "xxxxxxx",
|
||||
"fee": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
*/
|
||||
$random = $this->util->getRandom();
|
||||
$curTime = time();
|
||||
$wholeUrl = $this->url . "?accesskey=" . $this->accesskey . "&random=" . $random;
|
||||
$data = new \stdClass();
|
||||
$data->tel = $this->util->phoneNumbersToArray($nationCode, $phoneNumbers);
|
||||
$data->type = $type;
|
||||
$data->msg = $msg;
|
||||
$data->sig = $this->util->calculateSig($this->secretkey, $random, $curTime, $phoneNumbers);
|
||||
$data->time = $curTime;
|
||||
$data->extend = $extend;
|
||||
$data->ext = $ext;
|
||||
return $this->util->sendCurlPost($wholeUrl, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定模板群发
|
||||
* 【注意】海外短信无群发功能
|
||||
* @param string $nationCode 国家码,如 86 为中国
|
||||
* @param array $phoneNumbers 不带国家码的手机号列表
|
||||
* @param int $templId 模板 id
|
||||
* @param array $params 模板参数列表,如模板 {1}...{2}...{3},那么需要带三个参数
|
||||
* @param string $sign 签名,如果填空串,系统会使用默认签名
|
||||
* @param string $extend 扩展码,可填空串
|
||||
* @param string $ext 服务端原样返回的参数,可填空串
|
||||
* @return string json string { "result": xxxxx, "errmsg": "xxxxxx" ... },被省略的内容参见协议文档
|
||||
*/
|
||||
function sendWithParam($nationCode, $phoneNumbers, $templId, $params, $sign = "", $extend ="", $ext = "") {
|
||||
/*
|
||||
请求包体
|
||||
{
|
||||
"tel": [
|
||||
{
|
||||
"nationcode": "86",
|
||||
"mobile": "13788888888"
|
||||
},
|
||||
{
|
||||
"nationcode": "86",
|
||||
"mobile": "13788888889"
|
||||
}
|
||||
],
|
||||
"sign": "Kewail",
|
||||
"tpl_id": 19,
|
||||
"params": [
|
||||
"验证码",
|
||||
"1234",
|
||||
"4"
|
||||
],
|
||||
"sig": "fdba654e05bc0d15796713a1a1a2318c",
|
||||
"time": 1479888540,
|
||||
"extend": "",
|
||||
"ext": ""
|
||||
}
|
||||
应答包体
|
||||
{
|
||||
"result": 0,
|
||||
"errmsg": "OK",
|
||||
"ext": "",
|
||||
"detail": [
|
||||
{
|
||||
"result": 0,
|
||||
"errmsg": "OK",
|
||||
"mobile": "13788888888",
|
||||
"nationcode": "86",
|
||||
"sid": "xxxxxxx",
|
||||
"fee": 1
|
||||
},
|
||||
{
|
||||
"result": 0,
|
||||
"errmsg": "OK",
|
||||
"mobile": "13788888889",
|
||||
"nationcode": "86",
|
||||
"sid": "xxxxxxx",
|
||||
"fee": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
*/
|
||||
$random = $this->util->getRandom();
|
||||
$curTime = time();
|
||||
$wholeUrl = $this->url . "?accesskey=" . $this->accesskey . "&random=" . $random;
|
||||
$data = new \stdClass();
|
||||
$data->tel = $this->util->phoneNumbersToArray($nationCode, $phoneNumbers);
|
||||
$data->sign = $sign;
|
||||
$data->tpl_id = $templId;
|
||||
$data->params = $params;
|
||||
$data->sig = $this->util->calculateSigForTemplAndPhoneNumbers(
|
||||
$this->secretkey, $random, $curTime, $phoneNumbers);
|
||||
$data->time = $curTime;
|
||||
$data->extend = $extend;
|
||||
$data->ext = $ext;
|
||||
return $this->util->sendCurlPost($wholeUrl, $data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
namespace App\DAO\PrizePool;
|
||||
|
||||
use App\PrizePool as PrizePoolModel;
|
||||
use App\Setting;
|
||||
|
||||
class CandyCalculator implements PrizeCalculator
|
||||
{
|
||||
protected $reward_type = PrizePoolModel::REWARD_CANDY;
|
||||
protected $reward_currency = PrizePoolModel::CURRENCY_NONE;
|
||||
protected $currency_type = PrizePoolModel::CURRENCY_NONE;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public function calculate($scene, $reward_qty, $to_user, $from_user = null, $memo = '', $attach_data = [])
|
||||
{
|
||||
$fasten_data = [
|
||||
'reward_type' => $this->reward_type,
|
||||
'reward_currency' => $this->reward_currency,
|
||||
'create_time' => time(), //发奖时间
|
||||
];
|
||||
$origin_reward_qty = $reward_qty; //原始奖励数量
|
||||
$candy_tousdt = Setting::getValueByKey('candy_tousdt', 100);
|
||||
$candy_tousdt = bc_div($candy_tousdt, 100);
|
||||
$reward_qty = bc_div($reward_qty, $candy_tousdt, 4);
|
||||
$extra_data = $attach_data['extra_data'];
|
||||
if (is_string($extra_data) && !empty($extra_data)) {
|
||||
$extra_data = unserialize($extra_data);
|
||||
}
|
||||
$extra_data['origin_reward_qty '] = $origin_reward_qty;
|
||||
$extra_data['candy_tousdt'] = $candy_tousdt;
|
||||
$attach_data['extra_data'] = serialize($extra_data);
|
||||
try {
|
||||
PrizePoolModel::unguard();
|
||||
$data = [
|
||||
'scene' => $scene,
|
||||
'reward_qty' => $reward_qty,
|
||||
'to_user_id' => $to_user->id,
|
||||
'from_user_id' => $from_user ? $from_user->id : $to_user->id,
|
||||
'memo' => $memo,
|
||||
];
|
||||
$data = array_merge($data, $attach_data, $fasten_data);
|
||||
$prize_pool = PrizePoolModel::create($data);
|
||||
} catch (\Exception $e) {
|
||||
return null;
|
||||
} finally {
|
||||
PrizePoolModel::reguard();
|
||||
}
|
||||
return isset($prize_pool->id) ? $prize_pool : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
namespace App\DAO\PrizePool;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\PrizePool;
|
||||
use App\{Users, AccountLog};
|
||||
|
||||
class CandySender implements PrizeSender
|
||||
{
|
||||
public function send(\App\PrizePool &$prize) : bool
|
||||
{
|
||||
try {
|
||||
$prize->refresh();
|
||||
if ($prize->status != 0) {
|
||||
throw new \Exception('奖励发放异常');
|
||||
}
|
||||
if ($prize->reward_type != PrizePool::REWARD_CANDY) {
|
||||
throw new \Exception('奖励发放类型不匹配');
|
||||
}
|
||||
DB::transaction(function () use (&$prize) {
|
||||
$user = Users::lockForUpdate()->find($prize->to_user_id);
|
||||
$change_result = change_user_candy($user, $prize->reward_qty, AccountLog::REWARD_CANDY, $prize->memo);
|
||||
if ($change_result !== true) {
|
||||
throw new \Exception($change_result);
|
||||
}
|
||||
$prize->receive_time = time();
|
||||
$prize->status = 1;
|
||||
$result = $prize->save();
|
||||
if (!$result) {
|
||||
throw new \Exception('奖励通证发放失败');
|
||||
}
|
||||
});
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
$error_info = serialize([
|
||||
'time' => time(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine(),
|
||||
'message' => $e->getMessage(),
|
||||
]);
|
||||
$prize->error_info = $error_info;
|
||||
$prize->save();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\DAO\PrizePool;
|
||||
|
||||
use App\PrizePool as PrizePoolModel;
|
||||
|
||||
class CurrencyCalculator implements PrizeCalculator
|
||||
{
|
||||
protected $reward_type = PrizePoolModel::REWARD_CURRENCY;
|
||||
protected $reward_currency;
|
||||
protected $currency_type;
|
||||
|
||||
public function __construct($reward_currency, $currency_type)
|
||||
{
|
||||
$this->reward_currency = $reward_currency;
|
||||
$this->currency_type = $currency_type;
|
||||
}
|
||||
|
||||
public function calculate($scene, $reward_qty, $to_user, $from_user = null, $memo = '', $attach_data = [])
|
||||
{
|
||||
$fasten_data = [
|
||||
'reward_type' => $this->reward_type,
|
||||
'reward_currency' => $this->reward_currency,
|
||||
'create_time' => time(), //发奖时间
|
||||
];
|
||||
try {
|
||||
PrizePoolModel::unguard();
|
||||
$data = [
|
||||
'scene' => $scene,
|
||||
'reward_qty' => $reward_qty,
|
||||
'to_user_id' => $to_user->id,
|
||||
'from_user_id' => $from_user ? $from_user->id : $to_user->id,
|
||||
'memo' => $memo,
|
||||
];
|
||||
$data = array_merge($data, $attach_data, $fasten_data);
|
||||
$prize_pool = PrizePoolModel::create($data);
|
||||
} catch (\Exception $e) {
|
||||
return null;
|
||||
} finally {
|
||||
PrizePoolModel::reguard();
|
||||
}
|
||||
return isset($prize_pool->id) ? $prize_pool : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
namespace App\DAO\PrizePool;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\{Users, AccountLog, UsersWallet, PrizePool};
|
||||
|
||||
class CurrencySender implements PrizeSender
|
||||
{
|
||||
public function send(\App\PrizePool &$prize) : bool
|
||||
{
|
||||
try {
|
||||
$prize->refresh();
|
||||
if ($prize->status != 0) {
|
||||
throw new \Exception('奖励发放异常');
|
||||
}
|
||||
if ($prize->reward_type != PrizePool::REWARD_CURRENCY) {
|
||||
throw new \Exception('奖励发放类型不匹配');
|
||||
}
|
||||
if (!in_array($prize->currency_type, [1, 2, 3])) {
|
||||
throw new \Exception('币种类型不正确');
|
||||
}
|
||||
DB::transaction(function () use (&$prize) {
|
||||
$user_wallet = UsersWallet::where('user_id', $prize->to_user_id)
|
||||
->where('currency', $prize->reward_currency)
|
||||
->lockForUpdate()
|
||||
->first();
|
||||
if (!$user_wallet) {
|
||||
throw new \Exception('用户钱包不存在');
|
||||
}
|
||||
$change_result = change_wallet_balance($user_wallet, $prize->currency_type, $prize->reward_qty, AccountLog::REWARD_CURRENCY, $prize->memo, false, $prize->from_user_id, $prize->sign, $extra_data);
|
||||
if ($change_result !== true) {
|
||||
throw new \Exception($change_result);
|
||||
}
|
||||
$prize->receive_time = time();
|
||||
$prize->status = 1;
|
||||
$result = $prize->save();
|
||||
if (!$result) {
|
||||
throw new \Exception('奖励通证发放失败');
|
||||
}
|
||||
});
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
$error_info = serialize([
|
||||
'time' => time(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine(),
|
||||
'message' => $e->getMessage(),
|
||||
]);
|
||||
$prize->error_info = $error_info;
|
||||
$prize->save();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\DAO\PrizePool;
|
||||
|
||||
interface PrizeCalculator
|
||||
{
|
||||
/**
|
||||
* 计算奖励
|
||||
*
|
||||
* @param integer $scene 奖励场景
|
||||
* @param float $reward_qty 奖励数量
|
||||
* @param \App\Users $to_user 被奖励者
|
||||
* @param \App\Users $from_user 触发用户
|
||||
* @param string $memo 备注
|
||||
* @param array $attach_data 附加数据
|
||||
* @return \App\PrizePool 返回奖池记录
|
||||
*/
|
||||
public function calculate($scene, $reward_qty, $to_user, $from_user = null, $memo = '', $attach_data = []);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
namespace App\DAO\PrizePool;
|
||||
|
||||
interface PrizeSender
|
||||
{
|
||||
/**
|
||||
* 发放奖励
|
||||
*
|
||||
* @param \App\PrizePool $prize
|
||||
* @return boolean
|
||||
*/
|
||||
public function send(\App\PrizePool &$prize) : bool;
|
||||
}
|
||||
@@ -0,0 +1,557 @@
|
||||
<?php
|
||||
namespace App\DAO;
|
||||
|
||||
use Illuminate\Support\Facades\{DB, Log};
|
||||
use App\{AccountLog, LeverTransaction, PrizePool, Setting, Users};
|
||||
use App\DAO\PrizePool\{CandySender, CandyCalculator};
|
||||
|
||||
class RewardDAO
|
||||
{
|
||||
/**
|
||||
* 向用户直属工作室发放奖励
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function rewardLeverFeeToAtelier($lever_trade)
|
||||
{
|
||||
$today = strtotime(date('Y-m-d'));
|
||||
$candy_tousdt = Setting::getValueByKey('candy_tousdt', 100);
|
||||
$candy_tousdt = bc_div($candy_tousdt, 100);
|
||||
$atelier_reward_day_must_trade = Setting::getValueByKey('atelier_reward_day_must_trade', 0); //工作室每日最低交易量
|
||||
$atelier_reward_day_limit = Setting::getValueByKey('atelier_reward_day_limit', 0); //工作室每日奖励上限
|
||||
$atelier_reward_ratio = Setting::getValueByKey('atelier_reward_ratio', 0); //工作室奖励比例百分比
|
||||
$atelier_reward_ratio = bc_div($atelier_reward_ratio, 100, 4); //工作室奖励比例转化小数
|
||||
$can_reward_qty = 0;
|
||||
|
||||
$user_id = $lever_trade->user_id;
|
||||
$trade_id = $lever_trade->trade_id;
|
||||
$trade_fee = $lever_trade->trade_fee;
|
||||
$origin_reward_qty = bc_mul($trade_fee, $atelier_reward_ratio, 4); //奖励数量
|
||||
$convert_reward_qty = bc_div($origin_reward_qty, $candy_tousdt, 4); //换算成与usdt等值糖果
|
||||
$fact_convert_reward_qty = $convert_reward_qty;
|
||||
|
||||
$user = Users::find($user_id);
|
||||
$parents_path = UserDAO::getParentsPathDesc($user);
|
||||
$ateliers = UserDAO::getParentsAtelier($user);
|
||||
|
||||
if (count($ateliers) <= 0) {
|
||||
return;
|
||||
}
|
||||
$atelier = $ateliers->first();
|
||||
if (!$atelier) {
|
||||
return;
|
||||
}
|
||||
$key = array_search($atelier->id, $parents_path);
|
||||
$current_level = $key + 1;
|
||||
//每日已开仓交易量
|
||||
$today_has_trades = LeverTransaction::where('user_id', $atelier->user_id)
|
||||
->where('status', LeverTransaction::TRANSACTION)
|
||||
->where('create_time', '>=', $today)
|
||||
->count();
|
||||
if ($today_has_trades < $atelier_reward_day_must_trade) {
|
||||
return;
|
||||
}
|
||||
//每日已奖励数量
|
||||
$rewarded_qty = PrizePool::where('scene', PrizePool::LEVER_TRADE_FEE_ATELIER)
|
||||
->where('sign', 0)
|
||||
->where('status', 1)
|
||||
->where('create_time', '>=', $today)
|
||||
->sum('reward_qty');
|
||||
//奖励是否已达上限
|
||||
if (bc_comp($atelier_reward_day_limit, 0) > 0) {
|
||||
if (bc_comp($rewarded_qty, $atelier_reward_day_limit) >= 0) {
|
||||
return;
|
||||
}
|
||||
//计算还有多少才达到封顶
|
||||
$can_reward_qty = bc_sub($atelier_reward_day_limit, $rewarded_qty);
|
||||
//如果即将奖励的值超过封顶,就抹去多余的奖励,以保证奖励不会超过封顶
|
||||
bc_comp($convert_reward_qty, $can_reward_qty) > 0 && $fact_convert_reward_qty = $can_reward_qty;
|
||||
}
|
||||
|
||||
$fact_reward_qty = bc_mul($fact_convert_reward_qty, $candy_tousdt, 4); //未折合usdt的糖果数量
|
||||
|
||||
$prize_calculator = new CandyCalculator();
|
||||
$prize_sender = new CandySender();
|
||||
$attach_data = [
|
||||
'sign' => $current_level,
|
||||
'extra_data' => serialize([
|
||||
'trade_id' => $trade_id, //交易id
|
||||
'level' => $current_level, //用户是第几级
|
||||
'trade_fee' => $trade_fee, //交易手续费
|
||||
'atelier_reward_day_limit' => $atelier_reward_day_limit, //工作室日奖励上限
|
||||
'atelier_reward_ratio' => $atelier_reward_ratio, //奖励比例
|
||||
'rewarded_qty' => $rewarded_qty, //已奖励数量
|
||||
'can_reward_qty' => $can_reward_qty, //还能拿的奖励数量
|
||||
'convert_reward_qty' => $convert_reward_qty,
|
||||
'fact_convert_reward_qty' => $fact_convert_reward_qty,
|
||||
'fact_reward_qty' => $fact_reward_qty,
|
||||
]),
|
||||
];
|
||||
try {
|
||||
//插入奖励记录到奖池
|
||||
$prize_pool = PrizePool::calculate(
|
||||
$prize_calculator,
|
||||
PrizePool::LEVER_TRADE_FEE_ATELIER,
|
||||
$fact_reward_qty,
|
||||
$atelier,
|
||||
$user,
|
||||
'工作室' . $current_level . '级用户杠杆交易手续费结算',
|
||||
$attach_data
|
||||
);
|
||||
if (!$prize_pool) {
|
||||
throw new \Exception('交易id:' . $trade_id . ',向第' . $current_level . '级上级(id:' . $atelier->id . ')触发奖励失败');
|
||||
}
|
||||
//发放奖励
|
||||
$receive_result = PrizePool::send($prize_sender, $prize_pool);
|
||||
if (!$receive_result) {
|
||||
throw new \Exception('交易id:' . $trade_id . ',向第' . $current_level . '级上级(id:' . $atelier->id . ')发放奖励失败');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$path = base_path() . '/storage/logs/reward/lever_trade/atelier/';
|
||||
$filename = date('Ymd') . '.log';
|
||||
file_exists($path) || @mkdir($path);
|
||||
error_log(
|
||||
date('Y-m-d H:i:s') . PHP_EOL . $e->getMessage() . PHP_EOL,
|
||||
3,
|
||||
$path . $filename
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 奖励杠杆交易手续费
|
||||
* @param App\LeverTransaction $lever_trade 杠杆交易
|
||||
* @return void
|
||||
*/
|
||||
public static function rewardLeverTransationFee($lever_trade)
|
||||
{
|
||||
$lever_fee_options = Setting::getValueByKey('lever_fee_options');
|
||||
$lever_fee_options = empty($lever_fee_options) ? [] : unserialize($lever_fee_options);
|
||||
|
||||
//如果没有取到参数直接返回
|
||||
if (count($lever_fee_options) <= 0) {
|
||||
return ;
|
||||
}
|
||||
|
||||
$generations = array_column($lever_fee_options, 'generation');
|
||||
$reward_ratio = array_column($lever_fee_options, 'reward_ratio');
|
||||
$need_has_trades_list = array_column($lever_fee_options, 'need_has_trades');
|
||||
array_multisort($generations, SORT_ASC, SORT_NUMERIC, $lever_fee_options);
|
||||
|
||||
$max_generation = max($generations);
|
||||
|
||||
$from_user_id = $lever_trade->user_id;
|
||||
$trade_fee = $lever_trade->trade_fee;
|
||||
$trade_id = $lever_trade->id;
|
||||
|
||||
$from_user = Users::find($from_user_id);
|
||||
$parents = UserDAO::getParentsPathDesc($from_user, $max_generation);
|
||||
|
||||
$prize_calculator = new CandyCalculator();
|
||||
$prize_sender = new CandySender();
|
||||
|
||||
foreach ($parents as $key => $value) {
|
||||
try {
|
||||
$current_level = $key + 1; //当前用户是受奖励用户的第几级
|
||||
$has_trade_num = 0; //当前用户交易笔数
|
||||
$need_has_trades = 0; //当前用户需要交易的笔数
|
||||
if (!in_array($current_level, $generations)) {
|
||||
continue;
|
||||
}
|
||||
$v_key = array_search($current_level, $generations); //查询键值
|
||||
|
||||
$need_has_trades = $need_has_trades_list[$v_key];
|
||||
$current_rebate_ratio = $reward_ratio[$v_key];
|
||||
$current_user = Users::find($value);
|
||||
if (!$current_user) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$candy_number = bc_div(bc_mul($trade_fee, $current_rebate_ratio), 100, 4);
|
||||
$attach_data = [
|
||||
'sign' => $current_level,
|
||||
'extra_data' => serialize([
|
||||
'trade_id' => $trade_id, //交易id
|
||||
'level' => $current_level, //用户是第几级
|
||||
'trade_fee' => $trade_fee, //交易手续费
|
||||
'current_rebate_ratio' => $current_rebate_ratio, //奖励比例
|
||||
]),
|
||||
];
|
||||
//检测当前用户有没有自行体验X笔
|
||||
$has_trade_num = LeverTransaction::where('user_id', $value)
|
||||
->whereIn('status', [1, 2, 3])
|
||||
->count();
|
||||
if ($has_trade_num < $need_has_trades) {
|
||||
continue;
|
||||
}
|
||||
//插入奖励记录到奖池
|
||||
$prize_pool = PrizePool::calculate(
|
||||
$prize_calculator,
|
||||
PrizePool::LEVER_TRADE_FEE,
|
||||
$candy_number,
|
||||
$current_user,
|
||||
$from_user,
|
||||
$current_level . '级用户杠杆交易手续费结算',
|
||||
$attach_data
|
||||
);
|
||||
if (!$prize_pool) {
|
||||
throw new \Exception('交易id:' . $trade_id . ',向第' . $current_level . '级上级(id:' . $current_user->id . ')触发奖励失败');
|
||||
}
|
||||
//发放奖励
|
||||
$receive_result = PrizePool::send($prize_sender, $prize_pool);
|
||||
if (!$receive_result) {
|
||||
throw new \Exception('交易id:' . $trade_id . ',向第' . $current_level . '级上级(id:' . $current_user->id . ')发放奖励失败');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$path = base_path() . '/storage/logs/reward/lever_trade/';
|
||||
$filename = date('Ymd') . '.log';
|
||||
file_exists($path) || @mkdir($path);
|
||||
error_log(
|
||||
date('Y-m-d H:i:s') . PHP_EOL . $e->getMessage() . PHP_EOL,
|
||||
3,
|
||||
$path . $filename
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 取转账次数对应的积分奖励比例
|
||||
*
|
||||
* @param integer $transfer_out_times
|
||||
* @return float 返回奖励比例(百分比,需要自己除以100)
|
||||
*/
|
||||
public static function getRatioByTurnsOutTimes($transfer_out_times)
|
||||
{
|
||||
$times_ratio = Setting::getValueByKey('transfer_out_ratio');
|
||||
empty($times_ratio) || $times_ratio = unserialize($times_ratio);
|
||||
$fact_ratio = self::getDataByRangeValue($times_ratio, $transfer_out_times);
|
||||
return $fact_ratio;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取范围内对应的值
|
||||
*
|
||||
* @param array $ratio_array 比例数组
|
||||
* @param float $compare_value 要比较的值
|
||||
* @return float
|
||||
*/
|
||||
public static function getDataByRangeValue($ratio_array, $compare_value)
|
||||
{
|
||||
$fact_data = reset($ratio_array); //先给个默认值
|
||||
krsort($ratio_array);
|
||||
foreach ($ratio_array as $key => $value) {
|
||||
if ($compare_value >= $key) {
|
||||
$fact_data = $value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $fact_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 静态奖
|
||||
*
|
||||
* @param App\Users $user 用户模型实例
|
||||
* @return bool 成功返回真,失败返回假
|
||||
*/
|
||||
public static function staticReward($user)
|
||||
{
|
||||
$today = strtotime(date('Y-m-d'));
|
||||
$static_day_release_ratio = Setting::getValueByKey('static_day_release_ratio');
|
||||
//先通过时间戳判断用户是否领取过
|
||||
if ($user->static_time > $today) {
|
||||
return false;
|
||||
}
|
||||
//再通过记录判断用户是否领取过
|
||||
$count = AccountLog::where('type', AccountLog::DAY_STATIC_RELEASE)
|
||||
->where('created_time', '>=', $today)
|
||||
->where('user_id', $user->id)
|
||||
->count();
|
||||
$count || $count = 0;
|
||||
if ($count > 0) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
DB::transaction(function () use ($user, $static_day_release_ratio) {
|
||||
$release_balance = round($user->integral * $static_day_release_ratio / 100, 5);
|
||||
$result = release_user_integral($user, $release_balance, AccountLog::DAY_STATIC_RELEASE, '每日静态释放奖励');
|
||||
if (!$result) {
|
||||
throw new \Exception('释放积分失败');
|
||||
}
|
||||
$user->static_time = time();
|
||||
$user->save(); //更新用户的静态奖领取时间
|
||||
});
|
||||
return true;
|
||||
} catch(\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 余额转出级差奖
|
||||
*
|
||||
* @param app\Users $user 用户模型
|
||||
* @param float $transfer_out_qty 转出数量
|
||||
* @return bool
|
||||
*/
|
||||
public static function levelDifferenceReward($user, $transfer_out_qty)
|
||||
{
|
||||
$parents = UserDAO::getParentsPathDesc($user);
|
||||
$times_ratio = Setting::getValueByKey('transfer_out_ratio');
|
||||
$times_ratio = empty($times_ratio) ? [] : unserialize($times_ratio);
|
||||
krsort($times_ratio);
|
||||
$max_ratio = reset($times_ratio);
|
||||
$current_max = self::getRatioByTurnsOutTimes($user->transfer_out_times); //取转账人的比例
|
||||
rsort($parents);
|
||||
$param = compact('times_ratio', 'max_ratio', 'current_max');
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
foreach ($parents as $key => $value) {
|
||||
$parent = Users::find($value);
|
||||
if (!$parent) {
|
||||
abort(400, '用户id:' . $user->id . '的上级(id:' . $value . ')不存在');
|
||||
return false;
|
||||
}
|
||||
$transfer_out_times = $parent->transfer_out_times; //转出次数
|
||||
$current_ratio = self::getRatioByTurnsOutTimes($transfer_out_times); //根据转出次数算出比例
|
||||
if ($current_max >= $current_ratio) {
|
||||
continue;
|
||||
}
|
||||
$fact_ratio = $current_ratio - $current_max; //比例差
|
||||
$param = compact('current_max', 'current_ratio', 'transfer_out_times', 'fact_ratio');
|
||||
$fact_reward_qty = $transfer_out_qty * $fact_ratio / 100; //应奖励的积分
|
||||
//向当前用户的钱包返比例差的积分
|
||||
$result = change_user_money($parent, 2, $fact_reward_qty, AccountLog::TRANSFER_OUT_LEVEL_DIFFERENCE_REWARD_INTEGRAL,'转出级差奖励积分');
|
||||
if ($result !== true) {
|
||||
throw new \Exception('释放积分到余额失败:' . $result);
|
||||
}
|
||||
$current_max = $current_ratio; //改变指针
|
||||
if ($current_max == $max_ratio) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
DB::commit();
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
echo '<pre>';
|
||||
echo '错误:' . $e->getMessage() . PHP_EOL . ',文件:' . $e->getFile() . PHP_EOL . '行号:'. $e->getLine();
|
||||
DB::rollBack();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 余额兑换积分奖励(加速释放)
|
||||
*
|
||||
* @param app\common\model\User $user 用户模型
|
||||
* @param float $exchange_qty 兑换数量
|
||||
*/
|
||||
public static function exchangeReward($user, $exchange_qty)
|
||||
{
|
||||
$path = UserDAO::getParentsPathDesc($user, 20);
|
||||
//array_shift($path); //删除直推上级
|
||||
if (count($path) < 1) {
|
||||
return false;
|
||||
}
|
||||
DB::beginTransaction();
|
||||
foreach ($path as $key => $value) {
|
||||
$fact_ratio = 0;
|
||||
$current_generations = $key + 1; //因为key从0开始所以加1;
|
||||
$parent = Users::find($value);
|
||||
//取当前被触发用户的级别
|
||||
$parent_level = $parent->level->code;
|
||||
if ($parent_level <= 1) {
|
||||
//普通会员不享受动态奖
|
||||
continue;
|
||||
}
|
||||
//根据代数来决定比例
|
||||
$can_generations = $parent->level->generations['exchange'];
|
||||
if ($can_generations < $current_generations) {
|
||||
//当前被触发人级别不能拿超过自己级别对应的代数
|
||||
continue;
|
||||
}
|
||||
if ($parent_level == 2 && $current_generations == 1) {
|
||||
//直推奖:根据直推人数来决定比例
|
||||
$children_qty = Users::where('parent_id', $value)->count();
|
||||
$children_qty || $children_qty = 0;
|
||||
$exchange_recommend_ratio = Setting::getValueByKey('exchange_recommend_ratio');
|
||||
$exchange_recommend_ratio = empty($exchange_recommend_ratio) ? [] : unserialize($exchange_recommend_ratio);
|
||||
$fact_ratio = self::getDataByRangeValue($exchange_recommend_ratio, $children_qty);
|
||||
} else {
|
||||
$ratio = Setting::getValueByKey('exchange_generations_ratio'); //取每一代对应的比例
|
||||
$ratio = empty($ratio) ? [] : unserialize($ratio);
|
||||
$fact_ratio = self::getDataByRangeValue($ratio, $current_generations);
|
||||
}
|
||||
$fact_reward_qty = round($exchange_qty * $fact_ratio / 100, 5);
|
||||
//奖励不能超过积分
|
||||
$before_integral = $parent->integral;
|
||||
$before_integral < $fact_reward_qty && $fact_reward_qty = $parent->integral;
|
||||
if ($fact_reward_qty == 0) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
$result = release_user_integral($parent, $fact_reward_qty, AccountLog::BALANCE_EXCHANGE_INTEGRAL_REWARD, '余额兑换积分奖励:');
|
||||
if (!$result) {
|
||||
throw new \Exception('释放积分到余额失败');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
echo '<pre>';
|
||||
echo '错误:' . $e->getMessage() . PHP_EOL . ',文件:' . $e->getFile() . PHP_EOL . '行号:'. $e->getLine();
|
||||
DB::rollback();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
DB::commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 余额增加奖励(转入加速释放)
|
||||
*
|
||||
* @param app\common\model\User $user 用户模型
|
||||
* @param float $add_qty 兑换数量
|
||||
* @return bool 成功返回真,否则假
|
||||
*/
|
||||
public static function balanceAddReward($user, $add_qty)
|
||||
{
|
||||
$path = UserDAO::getParentsPathDesc($user, 20);
|
||||
if (count($path) < 1) {
|
||||
return false;
|
||||
}
|
||||
DB::beginTransaction();
|
||||
foreach ($path as $key => $value) {
|
||||
$fact_ratio = 0;
|
||||
$current_generations = $key + 1; //因为key从0开始所以加1;
|
||||
$parent = Users::find($value);
|
||||
//取当前被触发用户的级别
|
||||
$parent_level = $parent->level->code;
|
||||
if ($parent_level <= 1) {
|
||||
//普通会员不享受动态奖
|
||||
continue;
|
||||
}
|
||||
$can_generations = $parent->level->generations['balance_add'];
|
||||
if ($can_generations < $current_generations) {
|
||||
//当前被触发人级别不能拿超过自己级别对应的代数
|
||||
continue;
|
||||
}
|
||||
if ($parent_level == 2 && $current_generations == 1) {
|
||||
//直推奖:根据直推人数来决定比例
|
||||
$children_qty = Users::where('parent_id', $value)->count();
|
||||
$children_qty || $children_qty = 0;
|
||||
$balanceadd_recommend_ratio = Setting::getValueByKey('balanceadd_recommend_ratio');
|
||||
$balanceadd_recommend_ratio = empty($balanceadd_recommend_ratio) ? [] : unserialize($balanceadd_recommend_ratio);
|
||||
$fact_ratio = self::getDataByRangeValue($balanceadd_recommend_ratio, $children_qty);
|
||||
} else {
|
||||
//根据代数来决定比例
|
||||
$ratio = Setting::getValueByKey('balanceadd_generations_ratio'); //取每一代对应的比例
|
||||
$ratio = empty($ratio) ? [] : unserialize($ratio);
|
||||
$fact_ratio = self::getDataByRangeValue($ratio, $current_generations);
|
||||
}
|
||||
$fact_reward_qty = round($add_qty * $fact_ratio / 100, 5);
|
||||
//奖励不能超过积分
|
||||
$before_integral = $parent->integral;
|
||||
$before_integral < $fact_reward_qty && $fact_reward_qty = $parent->integral;
|
||||
if ($fact_reward_qty == 0) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
$result = release_user_integral($parent, $fact_reward_qty, AccountLog::TRANSFER_IN_PARENTS_REWARD_INTEGRAL, '余额转入奖励:');
|
||||
if (!$result) {
|
||||
throw new \Exception('释放积分到余额失败');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
echo '<pre>';
|
||||
echo '错误:' . $e->getMessage() . PHP_EOL . ',文件:' . $e->getFile() . PHP_EOL . '行号:'. $e->getLine();
|
||||
DB::rollback();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
DB::commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 余额减少奖励(转出加速释放)
|
||||
*
|
||||
* @param app\common\model\User $user 用户模型
|
||||
* @param float $sub_qty 兑换数量
|
||||
* @return bool 成功返回真,否则假
|
||||
*/
|
||||
public static function balanceSubReward($user, $sub_qty)
|
||||
{
|
||||
$parents = UserDAO::getParentsPathDesc($user, 15);//查询用户的指定代数的上级(根据parents_path信息),$qty 要取的上级代数,不传或传null则取全部
|
||||
if (count($parents) < 1) {
|
||||
return false;
|
||||
}
|
||||
$fact_ratio = Setting::getValueByKey('balance_sub_ratio');
|
||||
DB::beginTransaction();
|
||||
foreach ($parents as $key => $value) {
|
||||
$current_generations = $key + 1; //因为key从0开始所以加1;
|
||||
$parent = Users::find($value);
|
||||
//取当前被触发用户的级别
|
||||
$parent_level = $parent->level->code;
|
||||
$can_generations = $parent->level->generations['balance_sub'];
|
||||
if ($parent_level <= 1 || $can_generations < $current_generations) {
|
||||
//普通会员不享受动态奖
|
||||
continue;
|
||||
}
|
||||
$fact_reward_qty = round($sub_qty * $fact_ratio / 100, 5);
|
||||
if ($fact_reward_qty == 0) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
$result = change_user_money($parent, 2, $fact_reward_qty, AccountLog::TRANSFER_OUT_PARENTS_REWARD_INTEGRAL, '余额减少上级奖励-增加积分');
|
||||
if ($result !== true) {
|
||||
throw new \Exception('奖励积分失败(余额转出上级奖励)'. $result);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
DB::commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 平级余额减少奖励积分(暂且只有转出)
|
||||
*
|
||||
* @param app\common\model\User $user 转出用户模型
|
||||
* @param float $qty 数量
|
||||
*/
|
||||
public static function equalLevelReward($user, $qty)
|
||||
{
|
||||
$parents = UserDAO::getParentsPathDesc($user);
|
||||
if (count($parents) < 1) {
|
||||
return false;
|
||||
}
|
||||
$userlevel = $user->level->code;
|
||||
$fact_ratio = Setting::getValueByKey('equal_level_ratio');
|
||||
DB::beginTransaction();
|
||||
foreach ($parents as $key => $value) {
|
||||
$current_generations = $key + 1;
|
||||
//取当前被触发用户的级别
|
||||
$parent = Users::find($value);
|
||||
$parent_level = $parent->level->code;
|
||||
$can_generations = $parent->level->generations['equal_level'];
|
||||
if ($parent_level <= 1 || $can_generations < $current_generations || $userlevel != $parent_level) {
|
||||
//当前被触发人级别不能拿超过自己级别对应的代数,或者不是平级
|
||||
continue;
|
||||
}
|
||||
$fact_reward_qty = round($qty * $fact_ratio / 100, 4);
|
||||
try {
|
||||
$result = change_user_money($parent, 2, $fact_reward_qty, AccountLog::TRANSFER_OUT_EQUALLEVEL_REWARD_INTEGRAL, '余额减少平级奖励-增加积分');
|
||||
if ($result !== true) {
|
||||
throw new \Exception('奖励积分失败(余额转出平级奖励):' . $result);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
DB::commit();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
<?php
|
||||
namespace App\DAO;
|
||||
|
||||
|
||||
use App\DAO\Lib\mail;
|
||||
|
||||
class SubmailMailSend
|
||||
{
|
||||
|
||||
protected $configs;
|
||||
|
||||
protected $To = array();
|
||||
|
||||
protected $Addressbook = array();
|
||||
|
||||
protected $From = '';
|
||||
|
||||
protected $From_name = '';
|
||||
|
||||
protected $Reply = '';
|
||||
|
||||
protected $Cc = array();
|
||||
|
||||
protected $Bcc = array();
|
||||
|
||||
protected $Subject = '';
|
||||
|
||||
protected $Text = '';
|
||||
|
||||
protected $Html = '';
|
||||
|
||||
protected $Vars = array();
|
||||
|
||||
protected $Links = array();
|
||||
|
||||
protected $Attachments = array();
|
||||
|
||||
protected $Headers = array();
|
||||
|
||||
protected $asynchronous = "false";
|
||||
|
||||
|
||||
function __construct($configs)
|
||||
{
|
||||
$this->configs = $configs;
|
||||
}
|
||||
|
||||
public function AddTo($address, $name = '')
|
||||
{
|
||||
array_push($this->To, array('address' => $address, 'name' => $name));
|
||||
}
|
||||
|
||||
public function AddAddressbook($addressbook)
|
||||
{
|
||||
array_push($this->Addressbook, $addressbook);
|
||||
}
|
||||
|
||||
public function SetSender($sender, $name = '')
|
||||
{
|
||||
$this->From = $sender;
|
||||
$this->From_name = $name;
|
||||
}
|
||||
|
||||
public function SetReply($reply)
|
||||
{
|
||||
$this->Reply = $reply;
|
||||
}
|
||||
|
||||
public function AddCc($address, $name = '')
|
||||
{
|
||||
array_push($this->Cc, array('address' => $address, 'name' => $name));
|
||||
}
|
||||
|
||||
public function AddBcc($address, $name = '')
|
||||
{
|
||||
array_push($this->Bcc, array('address' => $address, 'name' => $name));
|
||||
}
|
||||
|
||||
public function SetSubject($subject)
|
||||
{
|
||||
$this->Subject = $subject;
|
||||
}
|
||||
|
||||
public function SetText($text)
|
||||
{
|
||||
$this->Text = $text;
|
||||
}
|
||||
|
||||
public function SetHtml($html)
|
||||
{
|
||||
$this->Html = $html;
|
||||
}
|
||||
|
||||
public function AddVar($key, $val)
|
||||
{
|
||||
$this->Vars[$key] = $val;
|
||||
}
|
||||
|
||||
public function AddLink($key, $val)
|
||||
{
|
||||
$this->Links[$key] = $val;
|
||||
}
|
||||
|
||||
public function AddAttachment($attachment)
|
||||
{
|
||||
array_push($this->Attachments, $attachment);
|
||||
}
|
||||
|
||||
public function AddHeaders($key, $val)
|
||||
{
|
||||
$this->Headers[$key] = $val;
|
||||
}
|
||||
|
||||
public function setAsynchronous($asynchronous)
|
||||
{
|
||||
if ($asynchronous == true) {
|
||||
$this->asynchronous = true;
|
||||
} else {
|
||||
$this->asynchronous = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected function buildRequest()
|
||||
{
|
||||
$request = array();
|
||||
if (!empty($this->To)) {
|
||||
$request['to'] = '';
|
||||
foreach ($this->To as $tmp) {
|
||||
$request['to'] .= $tmp['name'] . '<' . $tmp['address'] . '>,';
|
||||
}
|
||||
$request['to'] = substr($request['to'], 0, strlen($request['to']) - 1);
|
||||
//dd($request['to']);
|
||||
}
|
||||
if (!empty($this->Addressbook)) {
|
||||
$request['addressbook'] = '';
|
||||
foreach ($this->Addressbook as $tmp) {
|
||||
$request['addressbook'] .= $tmp . ',';
|
||||
}
|
||||
$request['addressbook'] = substr($request['addressbook'], 0, strlen($request['addressbook']) - 1);
|
||||
}
|
||||
$request['from'] = $this->From;
|
||||
if ($this->From_name != '') {
|
||||
$request['from_name'] = $this->From_name;
|
||||
}
|
||||
if ($this->Reply != '') {
|
||||
$request['reply'] = $this->Reply;
|
||||
}
|
||||
if (!empty($this->Cc)) {
|
||||
$request['cc'] = '';
|
||||
foreach ($this->Cc as $tmp) {
|
||||
$request['cc'] .= $tmp['name'] . '<' . $tmp['address'] . '>,';
|
||||
}
|
||||
$request['cc'] = substr($request['cc'], 0, strlen($request['cc']) - 1);
|
||||
}
|
||||
if (!empty($this->Bcc)) {
|
||||
$request['bcc'] = '';
|
||||
foreach ($this->Bcc as $tmp) {
|
||||
$request['bcc'] .= $tmp['name'] . '<' . $tmp['address'] . '>,';
|
||||
}
|
||||
$request['bcc'] = substr($request['bcc'], 0, strlen($request['bcc']) - 1);
|
||||
}
|
||||
$request['subject'] = $this->Subject;
|
||||
if ($this->Text != '') {
|
||||
$request['text'] = $this->Text;
|
||||
}
|
||||
|
||||
if ($this->Html != '') {
|
||||
$request['html'] = $this->Html;
|
||||
}
|
||||
|
||||
if (!empty($this->Vars)) {
|
||||
$request['vars'] = json_encode($this->Vars);
|
||||
}
|
||||
|
||||
if (!empty($this->Links)) {
|
||||
$request['links'] = json_encode($this->Links);
|
||||
}
|
||||
|
||||
if (!empty($this->Attachments)) {
|
||||
for ($i = 0; $i < count($this->Attachments); $i++) {
|
||||
//$request['attachments['.$i.']']="@".$this->Attachments[$i];
|
||||
$request['attachments[' . $i . ']'] = curl_file_create($this->Attachments[$i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($this->asynchronous)) {
|
||||
$request['asynchronous'] = $this->asynchronous;
|
||||
}
|
||||
|
||||
if (!empty($this->Headers)) {
|
||||
$request['headers'] = json_encode($this->Headers);
|
||||
}
|
||||
|
||||
return $request;
|
||||
}
|
||||
|
||||
public function send()
|
||||
{
|
||||
$mail = new mail($this->configs);
|
||||
return $mail->send($this->buildRequest());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
|
||||
namespace App\DAO;
|
||||
|
||||
use Qiniu\Storage\UploadManager;
|
||||
use Qiniu\Auth;
|
||||
use App\Setting;
|
||||
|
||||
class UploaderDAO
|
||||
{
|
||||
|
||||
private static $stateMap = [ //上传状态映射表,国际化用户需考虑此处数据的国际化
|
||||
"SUCCESS", //上传成功标记,在UEditor中内不可改变,否则flash判断会出错
|
||||
"文件大小超出 upload_max_filesize 限制",
|
||||
"文件大小超出 MAX_FILE_SIZE 限制",
|
||||
"文件未被完整上传",
|
||||
"没有文件被上传",
|
||||
"上传文件为空",
|
||||
"ERROR_TMP_FILE" => "临时文件错误",
|
||||
"ERROR_TMP_FILE_NOT_FOUND" => "找不到临时文件",
|
||||
"ERROR_SIZE_EXCEED" => "文件大小超出网站限制",
|
||||
"ERROR_TYPE_NOT_ALLOWED" => "文件类型不允许",
|
||||
"ERROR_CREATE_DIR" => "目录创建失败",
|
||||
"ERROR_DIR_NOT_WRITEABLE" => "目录没有写权限",
|
||||
"ERROR_FILE_MOVE" => "文件保存时出错",
|
||||
"ERROR_FILE_NOT_FOUND" => "找不到上传文件",
|
||||
"ERROR_WRITE_CONTENT" => "写入文件内容错误",
|
||||
"ERROR_UNKNOWN" => "未知错误",
|
||||
"ERROR_DEAD_LINK" => "链接不可用",
|
||||
"ERROR_HTTP_LINK" => "链接不是http链接",
|
||||
"ERROR_HTTP_CONTENTTYPE" => "链接contentType不正确",
|
||||
"INVALID_URL" => "非法 URL",
|
||||
"INVALID_IP" => "非法 IP"
|
||||
];
|
||||
|
||||
/**
|
||||
* 上传错误检查
|
||||
* @param string $errCode
|
||||
* @return string
|
||||
*/
|
||||
public static function getStateInfo($errCode)
|
||||
{
|
||||
return !self::$stateMap[$errCode] ? self::$stateMap["ERROR_UNKNOWN"] : self::$stateMap[$errCode];
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件上传
|
||||
*
|
||||
* @param \Illuminate\Http\UploadedFile $file
|
||||
* @return array
|
||||
*/
|
||||
public static function fileUpload($file, $scene = '')
|
||||
{
|
||||
//读取上传参数
|
||||
$upload_file_size = intval(Setting::getValueByKey('upload_file_size', 0));
|
||||
$upload_file_ext_list = Setting::getValueByKey('upload_file_ext_list');
|
||||
$upload_file_ext_list == '' && $upload_file_ext_list = 'png,jpg,jpeg,gif,bmp';
|
||||
//文件大小判断
|
||||
$upload_file_size *= 1048576; //文件上传最大
|
||||
$filesize = $file->getSize();
|
||||
$filename = $file->getFilename();
|
||||
$origin = $file->getClientOriginalName();
|
||||
$ext = $file->guessExtension();
|
||||
empty($scene) || $scene .= '/';
|
||||
|
||||
//文件扩展名判断
|
||||
$upload_file_ext_list = explode(',', strtolower(str_replace(' ', '', $upload_file_ext_list)));
|
||||
|
||||
if (!in_array($ext, $upload_file_ext_list)) {
|
||||
return [
|
||||
'state' => self::getStateInfo('ERROR_TYPE_NOT_ALLOWED'),
|
||||
'url' => '',
|
||||
'title' => $filename,
|
||||
'original' => $origin,
|
||||
'type' => '.' . $ext,
|
||||
'size' => $filesize,
|
||||
];
|
||||
}
|
||||
//文件大小校验
|
||||
if ($upload_file_size > 0 && $filesize > $upload_file_size) {
|
||||
return [
|
||||
'state' => self::getStateInfo('ERROR_SIZE_EXCEED'),
|
||||
'url' => '',
|
||||
'title' => $filename,
|
||||
'original' => $origin,
|
||||
'type' => '.' . $ext,
|
||||
'size' => $filesize,
|
||||
];
|
||||
}
|
||||
//读取存储参数
|
||||
$use_qiniu_storage = Setting::getValueByKey('use_qiniu_storage', 0);
|
||||
$qiniu_url = Setting::getValueByKey('qiniu_url', '');
|
||||
$access_key = Setting::getValueByKey('qiniu_access_key', '');
|
||||
$secret_key = Setting::getValueByKey('qiniu_secret_key', '');
|
||||
$bucket_name = Setting::getValueByKey('qiniu_bucket_name', '');
|
||||
|
||||
$url = $use_qiniu_storage ? $qiniu_url : url('');
|
||||
|
||||
if ($use_qiniu_storage) {
|
||||
$file_obj = new \SplFileObject($file->getPathname());
|
||||
$file_content = $file_obj->fread($file->getSize());
|
||||
$upManager = new UploadManager();
|
||||
$auth = new Auth($access_key, $secret_key);
|
||||
$token = $auth->uploadToken($bucket_name);
|
||||
list($ret, $error) = $upManager->put($token, $filename, $file_content);
|
||||
if ($error) {
|
||||
return [
|
||||
'state' => is_string($error) ? $error : $error->message(),
|
||||
'url' => '',
|
||||
'title' => $filename,
|
||||
'original' => $origin,
|
||||
'type' => '.' . $ext,
|
||||
'size' => $filesize,
|
||||
];
|
||||
}
|
||||
$file_url = $url . '/' . $ret['key'];
|
||||
} else {
|
||||
$path = '/upload/' . $scene . date('Ymd') . '/';
|
||||
$full_path = public_path() . $path;
|
||||
file_exists($path) || @mkdir($full_path, 0777, true);
|
||||
$file->move($full_path);
|
||||
|
||||
if($scene =='admin/'){
|
||||
$file_url =$path . $filename;
|
||||
}else{
|
||||
$file_url = $url . $path . $filename;
|
||||
}
|
||||
|
||||
}
|
||||
return [
|
||||
'state' => self::getStateInfo(0),
|
||||
'url' => $file_url,
|
||||
'title' => $filename,
|
||||
'original' => $origin,
|
||||
'type' => '.' . $ext,
|
||||
'size' => $filesize,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,424 @@
|
||||
<?php
|
||||
namespace App\DAO;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\{Users, PrizePool, Setting};
|
||||
use App\DAO\PrizePool\CandySender;
|
||||
use App\Events\RealNameEvent;
|
||||
|
||||
class UserDAO
|
||||
{
|
||||
/**
|
||||
* 检查是否符合升级工作室条件,若符合自动升级
|
||||
*
|
||||
* @param App\Users $user
|
||||
* @return boolean
|
||||
*/
|
||||
public static function checkUpgradeAtelierCondition(&$user) : bool
|
||||
{
|
||||
$user->refresh();
|
||||
//检查自身是否已实名或已经是工作室
|
||||
if ($user->is_realname != 2 || $user->is_atelier == 1) {
|
||||
return false;
|
||||
}
|
||||
$upgrade_atelier_must_has_son = Setting::getValueByKey('upgrade_atelier_must_has_son'); //升级工作室直推实名人数要求
|
||||
$upgrade_atelier_must_team_son = Setting::getValueByKey('upgrade_atelier_must_team_son'); //升级工作室团队实名人数要求
|
||||
$upgrade_atelier_must_team_recharge = Setting::getValueByKey('upgrade_atelier_must_team_recharge'); //升级工作室团队充值金额
|
||||
//检查直推实名人数
|
||||
if ($user->zhitui_real_number < $upgrade_atelier_must_has_son) {
|
||||
return false;
|
||||
}
|
||||
//检查团队实名人数
|
||||
if ($user->real_teamnumber < $upgrade_atelier_must_team_son) {
|
||||
return false;
|
||||
}
|
||||
//检查团队充值金额
|
||||
if ($user->top_upnumber < $upgrade_atelier_must_team_recharge) {
|
||||
return false;
|
||||
}
|
||||
$user->is_atelier = 1;
|
||||
return $user->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户的上级是否有通证变动
|
||||
* @param App\Users $user 用户查询的对象
|
||||
*/
|
||||
public static function addCandyNumber($user)
|
||||
{
|
||||
$parents = self::getParentsPathDesc($user);
|
||||
foreach ($parents as $key => $user_id) {
|
||||
$current_user = Users::find($user_id);//检查该上级是否实名认证过
|
||||
if ($current_user->is_realname == 2) {
|
||||
//该上级实名认证过
|
||||
self::checkUserRealNameReward($current_user); //检查是否符合发奖条件,符合就发放奖励
|
||||
self::checkUpgradeAtelierCondition($current_user); //检查是否符合升级工作室条件
|
||||
} else {
|
||||
//该上级还没实名认证
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测用户是否符合实名奖励
|
||||
*
|
||||
* @param App\Users $user
|
||||
* @return bool
|
||||
*/
|
||||
public static function checkUserRealNameReward(&$user)
|
||||
{
|
||||
if (!$user) {
|
||||
return false;
|
||||
}
|
||||
//获取setting值
|
||||
$real_name_candy = Setting::getValueByKey('real_name_candy', '');
|
||||
$zhitui2_number = Setting::getValueByKey('zhitui2_number', '');
|
||||
$zhitui2_candy = Setting::getValueByKey('zhitui2_candy', '');
|
||||
$zhitui3_number = Setting::getValueByKey('zhitui3_number', '');
|
||||
$zhitui3_real_teamnumber = Setting::getValueByKey('zhitui3_real_teamnumber', '');
|
||||
$zhitui3_top_upnumber = Setting::getValueByKey('zhitui3_top_upnumber', '');
|
||||
$zhitui3_candy = Setting::getValueByKey('zhitui3_candy', '');
|
||||
$zhitui4_number = Setting::getValueByKey('zhitui4_number', '');
|
||||
$zhitui4_real_teamnumber = Setting::getValueByKey('zhitui4_real_teamnumber', '');
|
||||
$zhitui4_top_upnumber = Setting::getValueByKey('zhitui4_top_upnumber', '');
|
||||
$zhitui4_candy = Setting::getValueByKey('zhitui4_candy', '');
|
||||
$zhitui5_number = Setting::getValueByKey('zhitui5_number', '');
|
||||
$zhitui5_real_teamnumber = Setting::getValueByKey('zhitui5_real_teamnumber', '');
|
||||
$zhitui5_top_upnumber = Setting::getValueByKey('zhitui5_top_upnumber', '');
|
||||
$zhitui5_candy = Setting::getValueByKey('zhitui5_candy', '');
|
||||
$zhitui6_number = Setting::getValueByKey('zhitui6_number', '');
|
||||
$zhitui6_real_teamnumber = Setting::getValueByKey('zhitui6_real_teamnumber', '');
|
||||
$zhitui6_top_upnumber = Setting::getValueByKey('zhitui6_top_upnumber', '');
|
||||
$zhitui6_candy = Setting::getValueByKey('zhitui6_candy', '');
|
||||
|
||||
$only = 1;
|
||||
$user->refresh();
|
||||
$push_status = $user->push_status;
|
||||
|
||||
//实名认证过的有效直推人数
|
||||
$real_zhitui = Users::where("is_realname", 2)
|
||||
->where("parent_id", $user->id)
|
||||
->count();
|
||||
|
||||
$user->zhitui_real_number = $real_zhitui ?: 0; //更新直推实名人数
|
||||
$user->real_teamnumber += 1;
|
||||
|
||||
if ($push_status == 1) {
|
||||
if ($real_zhitui >= $zhitui2_number) {
|
||||
$user->candy_number += $zhitui2_candy;
|
||||
$user->push_status = 2;
|
||||
$log_candy_number = $zhitui2_candy;
|
||||
$only = 2;
|
||||
}
|
||||
} elseif ($push_status == 2) {
|
||||
if ($real_zhitui >= $zhitui3_number && $user->real_teamnumber >= $zhitui3_real_teamnumber && $user->top_upnumber >= $zhitui3_top_upnumber) {
|
||||
$user->candy_number += $zhitui3_candy;
|
||||
$user->push_status = 3;
|
||||
$log_candy_number = $zhitui3_candy;
|
||||
$only = 2;
|
||||
}
|
||||
} elseif ($push_status == 3) {
|
||||
if ($real_zhitui >= $zhitui4_number && $user->real_teamnumber >= $zhitui4_real_teamnumber && $user->top_upnumber >= $zhitui4_top_upnumber) {
|
||||
$user->candy_number += $zhitui4_candy;
|
||||
$user->push_status = 4;
|
||||
$log_candy_number = $zhitui4_candy;
|
||||
$only = 2;
|
||||
}
|
||||
} elseif ($push_status == 4) {
|
||||
if ($real_zhitui >= $zhitui5_number && $user->real_teamnumber >= $zhitui5_real_teamnumber && $user->top_upnumber >= $zhitui5_top_upnumber) {
|
||||
$user->candy_number += $zhitui5_candy;
|
||||
$user->push_status = 5;
|
||||
$log_candy_number = $zhitui5_candy;
|
||||
$only = 2;
|
||||
}
|
||||
} elseif ($push_status == 5) {
|
||||
if ($real_zhitui >= $zhitui6_number && $user->real_teamnumber >= $zhitui6_real_teamnumber && $user->top_upnumber >= $zhitui6_top_upnumber) {
|
||||
$user->candy_number += $zhitui6_candy;
|
||||
$user->push_status = 6;
|
||||
$log_candy_number = $zhitui6_candy;
|
||||
$only = 2;
|
||||
}
|
||||
}
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
//当天新增实名认证团队人数
|
||||
$beginToday=mktime(0,0,0,date('m'),date('d'),date('Y'));
|
||||
if($user->new_isreal_time<$beginToday)
|
||||
{
|
||||
$user->today_real_teamnumber=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$user->today_real_teamnumber=$user->today_real_teamnumber+1;
|
||||
}
|
||||
$user->new_isreal_time=time();
|
||||
|
||||
|
||||
|
||||
$result = $user->save();
|
||||
if (!$result) {
|
||||
throw new \Exception('用户' . $user->account_number . '更新信息失败');
|
||||
}
|
||||
//开始记录日志
|
||||
if ($only == 2) {
|
||||
$prize_pool = new PrizePool();
|
||||
$prize_pool->scene = PrizePool::CERTIFICATION;//const CERTIFICATION = 1; //实名认证奖励
|
||||
$prize_pool->reward_type = PrizePool::REWARD_CANDY;//const REWARD_CANDY = 0; //奖励通证
|
||||
$prize_pool->reward_qty = $log_candy_number;
|
||||
$prize_pool->from_user_id = $user->id;
|
||||
$prize_pool->to_user_id = $user->id;
|
||||
$prize_pool->status = 1;
|
||||
$prize_pool->memo = '下级直推' . $real_zhitui . '人,实名认证团队' . $user->real_teamnumber . '人,充值金额' . $user->top_upnumber . '美金,触发通证奖励' . $log_candy_number;
|
||||
$prize_pool->create_time = time();
|
||||
$prize_pool->receive_time = time();
|
||||
$result = $prize_pool->save();
|
||||
if (!$result) {
|
||||
throw new \Exception('用户' . $user->account_number . '奖励记录失败');
|
||||
}
|
||||
}
|
||||
DB::commit();
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 取用户的上级工作室
|
||||
*
|
||||
* @param App\Users $user
|
||||
* @return App\Users||null
|
||||
*/
|
||||
public static function getParentsAtelier($user)
|
||||
{
|
||||
$parents = UserDAO::getParentsPathDesc($user);
|
||||
//将所有上级工作室查出来
|
||||
$parent_atelier = Users::where('is_atelier', 1)
|
||||
->whereIn('id', $parents)
|
||||
->get();
|
||||
if (count($parent_atelier) <= 0) {
|
||||
return $parent_atelier;
|
||||
}
|
||||
$parents_sort = array_flip($parents);
|
||||
//检测有没有达到封页
|
||||
$sorted = $parent_atelier->sortBy(function ($item, $key) use ($parents_sort) {
|
||||
$sort = $parents_sort[$item->id];
|
||||
return $sort;
|
||||
});
|
||||
$sorted = $sorted->values();
|
||||
return $sorted;
|
||||
}
|
||||
|
||||
//递归查询用户下级所有人数
|
||||
public function GetTeamMember($members, $mid)
|
||||
{
|
||||
$Teams = array();//最终结果
|
||||
$mids = array($mid);//第一次执行时候的用户id
|
||||
do {
|
||||
$othermids = array();
|
||||
$state = false;
|
||||
foreach ($mids as $valueone) {
|
||||
foreach ($members as $key => $valuetwo) {
|
||||
if ($valuetwo['parent_id'] == $valueone && $valuetwo['is_realname'] == 2) //实名认证通过的团队人数
|
||||
{
|
||||
$Teams[] = $valuetwo['id'];//找到我的下级立即添加到最终结果中
|
||||
$othermids[] = $valuetwo['id'];//将我的下级id保存起来用来下轮循环他的下级
|
||||
// array_splice($members,$key,1);//从所有会员中删除他
|
||||
$state = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
$mids = $othermids;//foreach中找到的我的下级集合,用来下次循环
|
||||
} while ($state == true);
|
||||
$Teams = Users::whereIn("id", $Teams)->where("is_realname", "=", 2)->count();
|
||||
|
||||
return $Teams;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户团队充值业绩金额
|
||||
* @param integer $id 用户的id值,用于查询更新该用户上级的团队充值金额
|
||||
* @return $number 充值金额值
|
||||
* * @param integer $qty 要取的上级代数,不传或传null则取全部
|
||||
*/
|
||||
public static function updateTopUpnumber($id, $number, $qty = null)
|
||||
{
|
||||
$user = Users::find($id);
|
||||
$parents = self::getParentsPathDesc($user, $qty);
|
||||
$result = Users::whereIn('id', $parents)->increment('top_upnumber', $number);
|
||||
//此处应再遍历检查一下$parents是否符合升级条件
|
||||
foreach ($parents as $key => $current_user_id) {
|
||||
$current_user = Users::find($current_user_id);
|
||||
if (!$current_user) {
|
||||
continue;
|
||||
}
|
||||
self::checkUserRealNameReward($current_user);
|
||||
self::checkUpgradeAtelierCondition($current_user);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询用户的指定代数的上级(根据parents_path信息)
|
||||
*
|
||||
* @param App\Users $user 用户模型实例
|
||||
* @param integer $qty 要取的上级代数,不传或传null则取全部
|
||||
* @return array 返回包含上级id的数组
|
||||
*/
|
||||
public static function getParentsPathDesc($user, $qty = null)
|
||||
{
|
||||
$path = $user->parents_path;
|
||||
if ($path == null || empty($path)) {
|
||||
return [];
|
||||
}
|
||||
$parents = explode(',', $path);
|
||||
$parents = array_filter($parents);
|
||||
krsort($parents);
|
||||
$parents = array_slice($parents, 0, $qty);
|
||||
return $parents;
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归查询上级
|
||||
*
|
||||
* @param App\Users $user 用户模型实例
|
||||
* @return array
|
||||
*/
|
||||
public static function getRealParents($user)
|
||||
{
|
||||
$found_parent_node = [];
|
||||
$parents = self::findParent($user, $found_parent_node);
|
||||
return $parents;
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归查询上级(字符串)
|
||||
*
|
||||
* @param App\Users $user 用户模型实例
|
||||
* @return string 返回逗号间隔的path
|
||||
*/
|
||||
public static function getRealParentsPath($user)
|
||||
{
|
||||
$parents = self::getRealParents($user);
|
||||
if (count($parents) > 0) {
|
||||
return implode(',', $parents);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
private static function findParent($user, &$found_parent_node)
|
||||
{
|
||||
$parent_id = $user->parent_id;
|
||||
|
||||
if ($parent_id) {
|
||||
//检测节点关系是否有死循环
|
||||
if (in_array($parent_id, $found_parent_node)) {
|
||||
$context = [
|
||||
'user_id' => $user->id,
|
||||
'parent_id' => $parent_id,
|
||||
'found_parent_node' => $found_parent_node,
|
||||
];
|
||||
//记录错误日志
|
||||
Log::useDailyFiles(base_path('storage/logs/user/'), 7);
|
||||
Log::critical('id:' . $user->id . '的用户,上级关系存在死循环', $context);
|
||||
return [];
|
||||
}
|
||||
array_unshift($found_parent_node, $parent_id);
|
||||
$parent = Users::find($parent_id);
|
||||
$result = self::findParent($parent, $found_parent_node);
|
||||
unset($parent);
|
||||
array_push($result, $parent_id);
|
||||
return $result;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否符合对应级别的升级,若符合就升级(不降级)
|
||||
*
|
||||
* @param App\Users $user 要升级的用户模型实例
|
||||
* @param App\Users $from_user 触发者用户模型实例
|
||||
* @return void 无返回值
|
||||
*/
|
||||
public static function upgradeCheck($user)
|
||||
{
|
||||
$before_level = $user->level_id;
|
||||
$new_level = 2;
|
||||
if ($user->is_disable == 1) {
|
||||
$new_level = 1;
|
||||
} else if ($user->total_integral >= 1000000) {
|
||||
$new_level = 5;
|
||||
} else if ($user->total_topup >= 10000) {
|
||||
$new_level = 4;
|
||||
} else if ($user->total_topup >= 300) {
|
||||
$new_level = 3;
|
||||
}
|
||||
|
||||
//查询等级对应的id
|
||||
$level = Level::where('code', $new_level)->first();
|
||||
//不掉级处理
|
||||
if ($before_level < $new_level) {
|
||||
try {
|
||||
DB::transaction(function () use ($user, $level, $before_level, $new_level) {
|
||||
$user_upgrade_log = new UserUpgradeLog();
|
||||
$user_upgrade_log->user_id = $user->id;
|
||||
$user_upgrade_log->from_user_id = $user->id;
|
||||
$user_upgrade_log->before_level = $before_level;
|
||||
$user_upgrade_log->after_level = $new_level;
|
||||
$user_upgrade_log->memo = '用户等级变更:由[' . self::get_level_name($before_level) . ']升级到[' . self::get_level_name($new_level) . ']';
|
||||
$user_upgrade_log->created_time = time();
|
||||
$result = $user_upgrade_log->save();
|
||||
if (!$result) {
|
||||
throw new \Exception('记录用户升级日志失败');
|
||||
}
|
||||
$user->level_id = $level->id;
|
||||
$result = $user->save();
|
||||
if (!$result) {
|
||||
throw new \Exception('变更用户等级失败');
|
||||
}
|
||||
});
|
||||
} catch (\Exception $e) {
|
||||
echo '<pre>';
|
||||
echo '错误:' . $e->getMessage() . PHP_EOL . ',文件:' . $e->getFile() . PHP_EOL . '行号:' . $e->getLine();
|
||||
return;
|
||||
}
|
||||
// $parent = Users::find($user->parent_id);
|
||||
// if ($parent) {
|
||||
// self::upgradeCheck($parent, $user);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function get_level_name($id = 2)
|
||||
{
|
||||
|
||||
$name = '';
|
||||
switch ($id) {
|
||||
case 1:
|
||||
$name = '限制会员';
|
||||
break;
|
||||
case 2:
|
||||
$name = '临时会员';
|
||||
break;
|
||||
case 3:
|
||||
$name = '正式会员';
|
||||
break;
|
||||
case 4:
|
||||
$name = '五星会员';
|
||||
break;
|
||||
case 5:
|
||||
$name = 'VIP会员';
|
||||
break;
|
||||
default:
|
||||
$name = '临时会员';
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user