epay / website /includes /lib /Payment.php
xxsxx's picture
Upload 1045 files
0d5b03e verified
<?php
namespace lib;
use Exception;
class Payment {
//生成签名
static public function makeSign($data, $key) {
ksort($data);
$signStr = '';
foreach ($data as $k => $v) {
if($k != 'sign' && $k != 'sign_type' && $v != ''){
$signStr .= $k . '=' . $v . '&';
}
}
$signStr = substr($signStr, 0, -1);
$sign = md5($signStr . $key);
return $sign;
}
//验证签名
static public function verifySign($data, $key) {
if(!isset($data['sign'])) return false;
$sign = self::makeSign($data, $key);
return $sign === $data['sign'];
}
// 页面支付返回信息
static public function echoDefault($result){
global $cdnpublic,$order,$conf,$sitename,$ordername;
$type = $result['type'];
if(!$type) return false;
switch($type){
case 'jump': //跳转
$html_text = '<script>window.location.replace(\''.$result['url'].'\');</script>';
if(isset($result['submit']) && $result['submit']){
submitTemplate($html_text);
}else{
echo $html_text;
}
break;
case 'html': //显示html
$html_text = $result['data'];
if(isset($result['submit']) && $result['submit'] && substr($html_text, 0, 6) == '<form '){
submitTemplate($html_text);
}else{
echo $html_text;
}
break;
case 'json': //显示JSON
echo json_encode($result['data']);
break;
case 'page': //显示指定页面
include_once SYSTEM_ROOT.'txprotect.php';
if(isset($result['data'])) extract($result['data']);
if($conf['pageordername']==1)$order['name']=$ordername?$ordername:'onlinepay';
include PAYPAGE_ROOT.$result['page'].'.php';
break;
case 'qrcode': //扫码页面
case 'scheme': //跳转urlscheme页面
if($result['page'] == 'wxpay_mini') $result['page'] = 'wxpay_h5';
include_once SYSTEM_ROOT.'txprotect.php';
$code_url = $result['url'];
if($conf['pageordername']==1)$order['name']=$ordername?$ordername:'onlinepay';
if($conf['wework_payopen'] == 1 && ($result['page'] == 'wxpay_wap' && strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger')===false || $result['page'] == 'wxpay_qrcode' && checkmobile())){
$code_url_wxkf = self::getWxkfPayUrl($code_url);
if($code_url_wxkf){
$code_url = $code_url_wxkf;
include PAYPAGE_ROOT.'wxpay_h5.php';
break;
}
}
include PAYPAGE_ROOT.$result['page'].'.php';
break;
case 'return': //同步回调
returnTemplate($result['url']);
break;
case 'error': //错误提示
sysmsg($result['msg']);
break;
default:break;
}
}
// API支付返回信息
static public function echoJson($result){
global $order,$siteurl;
if(!$result) return false;
$type = $result['type'];
if(!$type) return false;
$json['code'] = 1;
$json['trade_no'] = TRADE_NO;
switch($type){
case 'jump':
$json['payurl'] = $result['url'];
break;
case 'html':
$json['html'] = $result['data'];
break;
case 'qrcode':
$json['qrcode'] = $result['url'];
break;
case 'scheme':
$json['urlscheme'] = $result['url'];
break;
case 'error':
$json['code'] = -2;
$json['msg'] = $result['msg'];
break;
default:
$json['payurl'] = $siteurl.'pay/submit/'.TRADE_NO.'/';
break;
}
exit(json_encode($json));
}
// 订单回调处理
static public function processOrder($isnotify, $order, $api_trade_no, $buyer){
global $DB,$conf,$siteurl;
if($order['status']==0 || $order['status']==4){
if($DB->exec("UPDATE `pre_order` SET `status`=1 WHERE `trade_no`='".$order['trade_no']."'")){
$data = ['endtime'=>'NOW()', 'date'=>'CURDATE()'];
if(!empty($api_trade_no)) $data['api_trade_no'] = $api_trade_no;
if(!empty($buyer)) $data['buyer'] = $buyer;
if($order['settle']>0) $data['settle'] = $order['settle'];
$DB->update('order', $data, ['trade_no'=>$order['trade_no']]);
$order['api_trade_no'] = $api_trade_no;
processOrder($order, $isnotify);
}
}elseif(empty($order['api_trade_no']) && !empty($api_trade_no)){
$data = ['api_trade_no'=>$api_trade_no];
if(!empty($buyer)) $data['buyer'] = $buyer;
$DB->update('order', $data, ['trade_no'=>$order['trade_no']]);
}
if($isnotify && $order['settle']>0){
$DB->update('order', ['settle'=>$order['settle']], ['trade_no'=>$order['trade_no']]);
}
if(!$isnotify){
include_once SYSTEM_ROOT.'txprotect.php';
if($order['status'] == 2){
$jumpurl = '/payerr.html';
returnTemplate($jumpurl);
return;
}
// 支付完成5分钟后禁止跳转回网站
if(!empty($order['endtime']) && time() - strtotime($order['endtime']) > 300){
$jumpurl = '/payok.html';
}else{
$url=creat_callback($order);
$jumpurl = $url['return'];
}
returnTemplate($jumpurl);
}
}
// 更新订单信息
static public function updateOrder($trade_no, $api_trade_no, $buyer = null, $status = null){
global $DB;
$data = ['api_trade_no'=>$api_trade_no];
if(!empty($buyer)) $data['buyer'] = $buyer;
if($status) $data['status'] = $status;
$DB->update('order', $data, ['trade_no'=>$trade_no]);
}
// 更新订单扩展信息
static public function updateOrderExt($trade_no, $data){
global $DB;
$DB->update('order', ['ext'=>serialize($data)], ['trade_no'=>$trade_no]);
}
// 更新合单状态
static public function updateOrderCombine($trade_no){
global $DB;
$DB->update('order', ['combine'=>1], ['trade_no'=>$trade_no]);
}
// 更新订单分账接收人
static public function updateOrderProfits($order, $plugin){
global $DB;
$support_plugins = ['alipay', 'alipaysl', 'alipayd', 'wxpayn', 'wxpaynp'];
if(in_array($plugin, $support_plugins)){
$psreceiver = $DB->getRow("SELECT * FROM `pre_psreceiver` WHERE `channel`='{$order['channel']}' AND `uid`='{$order['uid']}' AND `status`=1");
if(!$psreceiver) $psreceiver = $DB->getRow("SELECT * FROM `pre_psreceiver` WHERE `channel`='{$order['channel']}' AND `uid` IS NULL AND `status`=1");
if($psreceiver){
if(!$psreceiver['minmoney'] || $order['realmoney']>=$psreceiver['minmoney']){
$DB->update('order', ['profits'=>$psreceiver['id']], ['trade_no'=>$order['trade_no']]);
return intval($psreceiver['id']);
}
}
}
return 0;
}
// 更新订单分账接收人2
static public function updateOrderProfits2($order, $plugin){
return;
global $DB;
$support_plugins = ['adapay'];
if(in_array($plugin, $support_plugins)){
$psreceiver = $DB->getRow("SELECT * FROM `pre_psreceiver2` WHERE `channel`='{$order['channel']}' AND `uid`='{$order['uid']}' AND `status`=1");
if(!$psreceiver) $psreceiver = $DB->getRow("SELECT * FROM `pre_psreceiver2` WHERE `channel`='{$order['channel']}' AND `uid` IS NULL AND `status`=1");
if($psreceiver){
if(!$psreceiver['minmoney'] || $order['realmoney']>=$psreceiver['minmoney']){
$DB->update('order', ['profits2'=>$psreceiver['id']], ['trade_no'=>$order['trade_no']]);
return intval($psreceiver['id']);
}
}
}
return 0;
}
//支付宝直付通确认结算
public static function alipaydSettle($trade_no, $api_trade_no, $realmoney, $combine = 0, $ext = null){
global $channel;
$alipay_config = require(PLUGIN_ROOT.'alipayd/inc/config.php');
$alipaySevice = new \Alipay\AlipayTradeService($alipay_config);
if($combine == 1){
if(!$ext) throw new Exception('子单支付结果数据不存在');
$sub_orders = unserialize($ext);
$failnum = 0;
$errmsg = '';
foreach($sub_orders as &$sub_order){
if($sub_order['settle'] == 0){
try{
$alipaySevice->settle_confirm($sub_order['trade_no'], $sub_order['total_amount']);
$sub_order['settle'] == 1;
}catch(Exception $e){
$failnum++;
$errmsg .= $e->getMessage().',';
}
}
}
\lib\Payment::updateOrderExt($trade_no, $sub_orders);
if($failnum > 0) throw new Exception('部分子单结算失败,失败数量:'.$failnum.',失败原因:'.$errmsg);
return true;
}
return $alipaySevice->settle_confirm($api_trade_no, $realmoney);
}
//微信收付通确认结算
public static function wxpaynpSettle($trade_no, $api_trade_no){
global $channel;
$wechatpay_config = require(PLUGIN_ROOT.'/wxpaynp/inc/config.php');
if($wechatpay_config['ecommerce']){
if(!$order['profits']){
$client = new \WeChatPay\V3\ProfitsharingService($wechatpay_config);
return $client->unfreeze($trade_no, $api_trade_no);
}else{
throw new Exception('当前订单需要分账,请进入分账订单页面确认分账');
}
}else{
throw new Exception('非电商收付通订单');
}
}
//支付宝预授权资金支付
public static function alipayPreAuthPay($trade_no){
global $channel, $order, $conf;
$alipay_config = require(PLUGIN_ROOT.$channel['plugin'].'/inc/config.php');
$alipaySevice = new \Alipay\AlipayTradeService($alipay_config);
$bizContent = [
'out_order_no' => $trade_no,
'out_request_no' => $trade_no,
];
$result = $alipaySevice->preAuthQuery($bizContent);
//print_r($result);exit;
if(!isset($result['auth_no'])) throw new Exception('预授权订单查询失败');
if($result['rest_amount'] == 0) throw new Exception('剩余冻结金额为0');
if($result['order_status'] == 'AUTHORIZED'){
$auth_no = $result['auth_no'];
$ordername = !empty($conf['ordername'])?ordername_replace($conf['ordername'],$order['name'],$order['uid'],$trade_no):$order['name'];
$bizContent = [
'out_trade_no' => $trade_no,
'total_amount' => $result['rest_amount'],
'subject' => $ordername,
'product_code' => 'PREAUTH_PAY',
'auth_no' => $auth_no,
'auth_confirm_mode' => 'COMPLETE'
];
return $aop->scanPay($bizContent);
}else{
throw new Exception('该笔订单非已授权状态,无需支付');
}
}
//支付宝预授权资金解冻
public static function alipayUnfreeze($trade_no){
global $channel;
$alipay_config = require(PLUGIN_ROOT.$channel['plugin'].'/inc/config.php');
$alipaySevice = new \Alipay\AlipayTradeService($alipay_config);
$bizContent = [
'out_order_no' => $trade_no,
'out_request_no' => $trade_no,
];
$result = $alipaySevice->preAuthQuery($bizContent);
//print_r($result);exit;
if(!isset($result['auth_no'])) throw new Exception('预授权订单查询失败');
if($result['rest_amount'] == 0) throw new Exception('剩余冻结金额为0');
if($result['order_status'] == 'AUTHORIZED'){
$auth_no = $result['auth_no'];
$bizContent = [
'auth_no' => $auth_no,
'out_request_no' => date("YmdHis").rand(11111,99999),
'amount' => $result['rest_amount'],
'remark' => '解冻资金'
];
return $alipaySevice->preAuthUnfreeze($bizContent);
}else{
throw new Exception('该笔订单非已授权状态,无需解冻');
}
}
//支付宝红包转账
public static function alipayRedPacketTransfer($payee_user_id, $money, $order_id){
global $channel, $conf;
$out_biz_no = date("YmdHis").rand(11111,99999);
$alipay_config = require(PLUGIN_ROOT.$channel['plugin'].'/inc/config.php');
$alipaySevice = new \Alipay\AlipayTransferService($alipay_config);
$alipaySevice->redPacketTansfer($out_biz_no, $money, $payee_user_id, $conf['sitename'], $order_id);
}
//支付宝红包资金退回
public static function alipayRedPacketRefund($trade_no, $money){
global $channel;
$out_biz_no = date("YmdHis").rand(11111,99999);
$alipay_config = require(PLUGIN_ROOT.$channel['plugin'].'/inc/config.php');
$alipaySevice = new \Alipay\AlipayTransferService($alipay_config);
$alipaySevice->redPacketRefund($out_biz_no, $trade_no, $money);
}
//加锁设置订单扩展数据
public static function lockPayData($trade_no, $func){
global $DB;
$DB->beginTransaction();
$data = $DB->getColumn("SELECT ext FROM pre_order WHERE trade_no=:trade_no FOR UPDATE", [':trade_no'=>$trade_no]);
if($data) {
$DB->rollBack();
return unserialize($data);
}
try{
$data = $func();
}catch(\Exception $e){
$DB->rollBack();
throw $e;
}
if($data){
$DB->update('order', ['ext'=>serialize($data)], ['trade_no' => $trade_no]);
}
$DB->commit();
return $data;
}
//获取微信客服跳转链接
public static function getWxkfPayUrl($pay_url){
global $order, $DB, $conf;
$cookiesid = $_COOKIE['mysid'];
if(!$cookiesid||!preg_match('/^[0-9a-z]{32}$/i', $cookiesid)){
$cookiesid = getSid();
setcookie("mysid", $cookiesid, time() + 2592000, '/');
}
if($conf['wework_paykfid'] > 0){
$wxkfaccount = $DB->getRow("SELECT * FROM pre_wxkfaccount WHERE id=:id", [':id'=>$conf['wework_paykfid']]);
}elseif($conf['wework_paymsgmode'] == 1){
$usekflist = $DB->getAll("SELECT DISTINCT aid FROM pre_wxkflog WHERE `sid`=:sid AND addtime>=:addtime AND status=1", [':sid'=>$cookiesid, ':addtime'=>date("Y-m-d H:i:s", strtotime('-48 hours'))]);
$usekfids = [0];
foreach($usekflist as $usekf){
$usekfids[] = intval($usekf['aid']);
}
$wxkfaccount = $DB->getRow("SELECT A.* FROM pre_wxkfaccount A LEFT JOIN pre_wework B ON A.wid=B.id WHERE A.id NOT IN (".implode(",", $usekfids).") AND B.status=1 ORDER BY A.usetime ASC LIMIT 1");
}else{
$wxkfaccount = $DB->getRow("SELECT A.* FROM pre_wxkfaccount A LEFT JOIN pre_wework B ON A.wid=B.id WHERE B.status=1 ORDER BY A.usetime ASC LIMIT 1");
}
if(!$wxkfaccount) return false;
$DB->insert('wxkflog', ['trade_no'=>$order['trade_no'], 'aid'=>$wxkfaccount['id'], 'sid'=>$cookiesid, 'payurl'=>$pay_url, 'addtime'=>'NOW()']);
$scene_param = 'orderid='.$order['trade_no'].'&money='.$order['realmoney'];
try{
if(!empty($wxkfaccount['url'])){
$kfurl = $wxkfaccount['url'];
$DB->update('wxkfaccount', ['usetime'=>'NOW()'], ['id'=>$wxkfaccount['id']]);
}else{
$wework = new wechat\WeWorkAPI($wxkfaccount['wid']);
$kfurl = $wework->getKFURL($wxkfaccount['openkfid'], 'pay');
$DB->update('wxkfaccount', ['url'=>$kfurl, 'usetime'=>'NOW()'], ['id'=>$wxkfaccount['id']]);
}
$kfurl .= '&scene_param='.urlencode($scene_param);
return $kfurl;
}catch(\Exception $e){
sysmsg($e->getMessage());
}
}
}