get($token)) { $this->error('请先登录!'); } list($userid, $username, $gameid,$sub_username,$token_random) = explode('|', auth_code($token, "DECODE", Env::get('auth_key'))); $redisTokenRandom = Cache::store('default')->get('token|sdk|'.$userid.'|'.$gameid); //redis中玩家登录安全控制的随机码不存在时 if ( !$redisTokenRandom ) { Cache::store('default')->rm($token); $this->error('token随机码不存在,请重新登录'); } //两个token随机码不同时 elseif($redisTokenRandom!=$token_random){ Cache::store('default')->rm($token); $this->error('token随机码错误,请重新登录'); } $this->userid = $userid; $this->username = $username; $this->game_id = $gameid; $this->sub_username = $sub_username; $this->nowTime = NOW_TIMESTAMP; $this->redis = \think\Cache::store('default')->handler(); } /** * 选择支付方式 */ public function index() { $this->_ini_config(); $gameModel = new Game; $payRuleModel = new Payrule; $payTypeModel = new PayType; $sdkModel = model('common/AndroidSdk'); $version = input('version'); //sdk版本号 [v3.0.2 参数] $data = input(); $data['productname']= input('productname','','urldecode'); $data['rolename'] = input('rolename','','urldecode'); $data['serverid'] = input('serverid','','urldecode'); $data['gameid'] = $this->game_id; $data['userid'] = $this->userid; $validResult = $this->validate($data, 'Pay.index'); if (true !== $validResult) { $this->error($validResult); } elseif(!($gameInfo = $gameModel->field('id,android_sdk_id,name')->where(['id' => $this->game_id,'isdelete'=>0])->find())){ $this->error('传入游戏参数错误'); } //游戏禁止的支付方式 $denyPayType = $payRuleModel->where("game_id=".$this->game_id)->column('deny_paytype'); if(!empty($version)){ $android_sdk_id = $sdkModel->where(['version'=>$version])->value('id'); if(empty($android_sdk_id)){ $this->error('sdk版本信息不存在'); } $arrPayType = $payTypeModel->field('paytype,payname')->where('paytype',['not in',$denyPayType],['like','%h5%'])->where(['status'=>1,'used_sdk_id'=>['like','%,'.$android_sdk_id.',%']])->select(); } else{ $arrPayType = $payTypeModel->field('paytype,payname')->where('paytype',['not in',$denyPayType],['like','%h5%'])->where(['status'=>1,'used_sdk_id'=>['like','%,'.$gameInfo['android_sdk_id'].',%']])->select(); } if(empty($arrPayType)){ $this->error('该游戏的h5支付方式还未配置,请到后台配置'); } $this->assign('arrPayType',$arrPayType); return $this->fetch(); } /** * 支付处理 */ public function pay() { die(); $this->_ini_config(); $gameid = $this->game_id; //游戏ID $member_id = $this->userid; //用户ID $appid = input('appid'); //APPID $serverid = input('serverid'); //服务器ID $servername = input('servername'); //区服名称 $amount = input('amount'); //充值金额 $roleid = input('roleid'); //角色ID $attach = input('attach'); //上一级的扩展参数,多数是订单编号[麻花网络自己聚合自己时,会加个aoyou###前缀] $mc_id = input('mc_id',0); //平台币劵ID $pay_channel_id = input('channel_id',0); //当前SDK的渠道 $imeil = input('imeil'); //手机imeil码 $productname= input('productname'); //消费的商品名称 $paytype = input('paytype'); //支付类型 $rolename = input('rolename',''); //角色名 $rolelevel = input('rolelevel',''); //角色角色等级 $orderid = makeOrderid(); $pay_status = 0; //cy_pay表的支付状态 $cp_payflag = 0; //cy_paycpinfo表的支付状态 $memberModel = new Members; $frozenModel = new ChannelFrozen; $cpurlModel = new Cpurl; $gameModel = new Game; $payModel = new PayModel; $coinModel = new MemberCoin; $payCpinfoModel = new PayCpinfo; $memberChannelGameModel = new MemberChannelGame; $appModel = new App; $payLogic = new PayLogic(); $checkResult = $this->validate(['gameid' =>$gameid, 'userid' =>$member_id, 'appid' =>$appid, 'serverid' =>$serverid, 'servername' =>$servername, 'amount' =>$amount, 'roleid' =>$roleid, 'attach' =>$attach, 'mc_id' =>$mc_id, 'channel_id' =>$pay_channel_id, 'productname' =>$productname, 'paytype' =>$paytype, 'imeil' =>$imeil ], 'Pay.add'); if (true !== $checkResult) { $this->error($checkResult); } if (empty($mc_id) && (substr($paytype,0,4)=='mix-' || $paytype=='ptb')) { $this->error('请选择平台币使用劵'); } //玩家在这款游戏的归属渠道 $channel_id = $memberChannelGameModel->where(['member_id'=>$member_id,'game_id'=>$gameid])->value('channel_id'); if (empty($channel_id)) { $this->error('无关联的归属渠道信息'); } //当前游戏的渠道是否禁止消费(非归属渠道) if (isFrozenOption($pay_channel_id,$gameid,'consume')) { $this->error('您所在渠道已经被禁止在此游戏消费'); } //充值回调地址 $cpurl = $cpurlModel->where(['appid'=>$appid])->value('url'); if(empty($cpurl)){ $this->error('没有回调地址,请通知我方配置'); } $appInfo = $appModel->field('id,appkey,client_appkey,gameid')->where(['id'=>$appid])->find(); if(empty($appInfo)){ $this->error('密钥信息不存在'); } //游戏信息 $gameInfo = $gameModel->field('order_recheck')->where(['id' => $gameid])->find(); if(empty($gameInfo)){ $this->error('游戏id参数错误'); } //有使用平台币劵时 if(!empty($mc_id)){ $coinInfo = $coinModel->field('mc_id,coin_sn,mc_coin_residue,history_id,mc_coin_amount,mc_coin_number') ->where(['mc_id'=>$mc_id,'mc_userid'=>$member_id,'mc_gameid'=>$gameid,'mc_coin_residue'=>['>',0]]) ->where('(mc_expire_time=0 or mc_expire_time>'.$this->nowTime.')') ->find(); if(empty($coinInfo)){ $this->error('有效的平台币劵不存在'); } $arrPayAmount = $payLogic->calPayAmount($amount,$coinInfo['mc_coin_residue'],($coinInfo['mc_coin_amount']/$coinInfo['mc_coin_number'])); } else{ $arrPayAmount = $payLogic->calPayAmount($amount); } //实际支付金额为0时 if (!($arrPayAmount['real_amount']>0)) { $paytype = 'ptb'; //全部用平台币支付 $pay_status = 1; //支付成功 $cp_payflag = 1; //付款时间 $payData['pay_time'] = $this->nowTime; } //有实际支付金额并且支付方式是平台币时 elseif($arrPayAmount['real_amount']>0 && $paytype=='ptb'){ $this->error('平台币劵金额不足,请使用混合支付'); } //指定时间内,禁止重复下单 if(!requestDuplicateCheck('pay_duplicate_'.$member_id.'_'.$gameid,$this->payRequestLimit)){ $this->error('充值请求过多,请于'.$this->payRequestLimit.'s以后,再次进行充值操作'); } if($payModel->where(['attach'=>$attach,'gameid'=>$gameid])->find()){ $this->redis->del('pay_duplicate_'.$member_id.'_'.$gameid); $this->error('游戏合作方的订单参数不能重复'); } $payData['orderid'] = $orderid; $payData['use_coin_sn'] = !empty($mc_id) ? $coinInfo['coin_sn'] : ''; //平台币劵订单号 $payData['amount'] = $amount; $payData['real_amount'] = $arrPayAmount['real_amount']; $payData['real_ptb'] = $arrPayAmount['real_ptb']; $payData['real_ptb_amount'] = $arrPayAmount['real_ptb_amount']; $payData['userid'] = $member_id; $payData['username'] = $this->username; $payData['roleid'] = $roleid; $payData['rolename'] = $rolename; $payData['rolelevel'] = $rolelevel; $payData['paytype'] = $paytype; $payData['productname'] = $productname; $payData['serverid'] = $serverid; $payData['gameid'] = $gameid; $payData['status'] = $pay_status; $payData['ip'] = request()->ip(); $payData['imeil'] = $imeil; $payData['create_time'] = $this->nowTime; $payData['channel_id'] = $channel_id; $payData['recheck_status'] = $gameInfo['order_recheck']; $payData['attach'] = $attach; // 启动事务 Db::startTrans(); try{ $result = ''; //返回值 $payModel->insert($payData); //如果是自己聚合自己时,支付回调地址固定 if(mb_substr($attach,0,8,'UTF-8')=='xkhyn###'){ $cpurl = Config::get('self_complex_callback_url'); $attach = str_replace("xkhyn###","",$attach); //聚合的订单编号,去掉[aoyou###]前缀 } //给Cp的用户名用子账号名 $paycp_username = (!empty($this->sub_username) ? $this->sub_username : $this->username); $str = "orderid=".urlencode($orderid)."&username=".urlencode($paycp_username)."&gameid=".$gameid."&roleid=".urlencode($roleid)."&serverid=".urlencode($serverid)."&paytype=".urlencode($paytype)."&amount=".$amount."&paytime=".$this->nowTime."&attach=".urlencode($attach); $param = $str."&appkey=".urlencode($appInfo['appkey']); $md5params = md5($param); $params = $str . "&sign=".urlencode($md5params); $paycpData['orderid'] = $orderid; $paycpData['fcallbackurl'] = $cpurl; $paycpData['params'] = $params; $paycpData['create_time'] = $this->nowTime; $paycpData['payflag'] = $cp_payflag; //写入cy_paycpinfo表数据 $payCpinfoModel->insert($paycpData); //如果使用了平台币 if($arrPayAmount['real_ptb']>0){ $payLogic->saveCoinData($coinInfo,$payData); } //第三方支付用的商品简单描述 (去除&+等特殊字符) $payBody = preg_replace("/[\&\+]+/", '', $productname); //全部平台币支付,并且支付成功时 if($pay_status){ //更新member表的total_pay_amount $memberModel->where(['id'=>$member_id])->update(['total_pay_amount'=>Db::raw('total_pay_amount+'.$amount)]); } $this->redis->del('pay_duplicate_'.$member_id.'_'.$gameid); // 提交事务 Db::commit(); } catch (\Exception $e) { // 回滚事务 Db::rollback(); $this->error('订单生成失败'.$e->getMessage()); } //全部平台币支付,并且支付成功时 if($pay_status){ // 通知CP,支付成功 (new PayCallback())->callBackToCp($orderid); $payLogic->payWarning($member_id, $channel_id, $gameid, $amount); } //支付方式是支付宝或者支付宝混合支付时 if($paytype=='zfb' || $paytype=='mix-zfb'){ //支付宝支付参数 $alipayParam = $this->getAlipayParam($orderid,$arrPayAmount['real_amount'],$payBody); $result = ['alipay_param'=>$alipayParam]; } //支付方式是微信官方h5支付或者微信官方h5混合支付时 elseif($paytype=='wxpay-h5' || $paytype=='mix-wxpay-h5') { $wxpayh5_param = $this->getWxpayH5Param($orderid,$arrPayAmount['real_amount'],$payBody); if(is_array($wxpayh5_param)){ $this->redirect($wxpayh5_param['mweb_url'].'&redirect_url='.url('weixinFinish')); } else{ $this->error($wxpayh5_param); } } //更新游戏区服信息 $this->saveGameServer($member_id,$gameid,$imeil,'pay'); } /** * 微信官方h5支付 * * @param string $orderid 订单号 * @param float $real_amount 支付金额 * @param string $body 商品名称 * * @return array 支付参数数组 */ private function getWxpayH5Param($orderid,$real_amount,$body) { $pay_return = false; $wxPay = new WeixinPay; $params['appid'] = Config::get('wxpay-h5')['appid']; $params['mch_id'] = Config::get('wxpay-h5')['mch_id']; $params['nonce_str'] = random(10); $params['body'] = $body; $params['out_trade_no'] = $orderid; $params['total_fee'] = $real_amount*100; // 支付金额,以分为单位 $params['spbill_create_ip'] = $this->request->ip(); $params['notify_url'] = Config::get('wxpay-h5')['notify_url']; $params['trade_type'] = 'MWEB'; $params['scene_info'] = '{"h5_info":{"type":"Wap","wap_url":"http://m.weilongwl.com","wap_name":"麻花网络游戏"}}'; //获取签名数据 $params['sign'] = $wxPay->MakeSign($params,Config::get('wxpay-h5')['key']); $xml = dataToXml($params); $response = $wxPay->postXmlCurl($xml); if (!$response) { return '微信支付请求失败'; } $result = $wxPay->xmlToArray($response); if( array_key_exists("return_code", $result) && $result["return_code"] == "SUCCESS" && array_key_exists("result_code", $result) && $result["result_code"] == "SUCCESS") { $pay_return['prepay_id'] = $result['prepay_id']; $pay_return['trade_type'] = $result['trade_type']; $pay_return['mweb_url'] = $result['mweb_url']; $pay_return['referer'] = Config::get('wxpay-h5')['referer']; } else{ return ' 错误代码:'.$result["err_code"].' 错误代码描述:'.$result["err_code_des"]; } return $pay_return; } /** * 微信支付完成后的跳转页 * */ public function weixinFinish() { return $this->fetch('weixin_finish'); } }