微信小程序支付功能
add_balance: function() {
var that = this;
var total_payed_price = this.data.recharge;
var rc_id = this.data.rc_id;
getData.getData('rechargePay', {
openid: app.globalData.openid,
total_payed_price: total_payed_price,
rc_id: rc_id,
method: 'POST'
}, function(res) {
if (res.errno) {
wx.showToast({
title: res.errdesc
});
return;
}
var data = res.data;
wx.requestPayment({
'timeStamp': data.timeStamp.toString(),
'nonceStr': data.nonceStr,
'package': data.package,
'signType': 'MD5',
'paySign': data.sign,
'success': function(res) {
console.log('支付成功');
},
'fail': function(res) {
console.log('支付失败');
return;
},
'complete': function(res) {
console.log('支付完成');
console.log(res);
var url = that.data.url;
console.log('get url', url);
if (res.errMsg == 'requestPayment:ok') {
wx.showModal({
title: '提示',
content: '充值成功'
});
if (url) {
setTimeout(function() {
// 直接跳转,当前页面出栈
wx.redirectTo({
url: '/pages' + url
});
}, 2000)
} else {
setTimeout(() => {
wx.navigateBack()
}, 2000)
}
}
return;
}
});
})
}
上述是小程序端的操作。
下面是php的操作。
<?php
namespace Api\Action;
use Vendor\Func\Http;
/**
* 充值相关接口
*/
class RechargeAction extends CommonAction
{
/**
* 获取充值项
*/
public function get_recharge_config(){
$recharge_config = M('recharge_config');
$recharge_config_list = $recharge_config->where(array('status'=>1,'is_show'=>1))->field('id,recharge,amount')->select();
$this->json->setAttr('data',$recharge_config_list);
$this->json->Send();
}
/***
* 余额充值微信支付
*/
public function pay(){
if (!$openid = trim($_POST['openid'])){
$this->json->setErr(10001,'缺少参数');
$this->json->Send();
}
if(!$rc_id = $_POST['rc_id']){
$this->json->setErr(10001,'没有余额充值id');
$this->json->Send();
}
$total_payed_price = (float)$_POST['total_payed_price']; // 实际支付金额
if ($total_payed_price <= 0){
$this->json->setErr(10002,'支付金额不可为0或负数');
$this->json->Send();
}
$recharge_config = M('recharge_config');
$recharge_flag = $recharge_config->where(array('id'=>$rc_id,'status'=>1,'is_show'=>1))->find();
if (!$recharge_config) {
$this->json->setErr(10002,'充值项不存在');
$this->json->Send();
}
$money_amount = $recharge_flag['amount']; // 应到账金额
$user = M('user');
$user_info = $user->where(array('openid'=>$openid))->find();
if (!$user_info){
$this->json->setErr(10001,'用户信息不存在');
$this->json->Send();
}
$uid = $user_info['id'];
$user_balance = $user_info['balance'];
// step1 生成订单
$order_info = $this->makeorder($uid,$total_payed_price,$money_amount,$user_balance);
$order_num = $order_info['order_num'];
$products_name = $order_info['products_name'];
// step2 unifiedorder
$unifiedorder = $this->unifiedorder($openid,$order_num,$total_payed_price*100,$products_name);
$data = [
'appId' => C('APPID'),
'timeStamp' => time(),
'nonceStr' => $this->createNonceStr(),
'package' => 'prepay_id='.$unifiedorder['prepay_id'],
'signType' => 'MD5'
];
$sign = $this->MakeSign($data);
$data['sign'] = $sign;
// step3 将数据package下放到小程序中
$this->json->setAttr('data',$data);
$this->json->Send();
}
/***
* 生成充值订单
*/
private function makeorder($uid,$total_payed_price,$money_amount,$user_balance){
$recharge_order = M('recharge_order');
$now = time();
$order_num = 'cz'.$uid.substr($now,3).rand(1000,9999);
$order_add_data = [
'order_num' => $order_num,
'amount' => $money_amount, //订单价格
'balance' => ($user_balance+$money_amount),
'uid' => $uid,
'status' => 1, //未到账
'total_payed_price' => $total_payed_price,
'create_time' => $now, //订单生成时间
];
$order_add_flag = $recharge_order->add($order_add_data);
if (!$order_add_flag){
$this->json->setErr(10003,'生成订单失败');
$this->json->Send();
}
$return_data['order_num'] = $order_num;
$return_data['products_name'] ='余额充值';
return $return_data;
}
public function unifiedorder($openid,$order_num,$total_fee,$products_name){
$trade_no = $order_num;
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
$data = [
'appid' => C('APPID'),
'mch_id' => C('MCHID'),
'nonce_str' => $this->createNonceStr(),
'sign_type' => 'MD5',
'body' => $products_name, //商品名称组合
'attach' => C('APP_NAME').'-附加信息',
'out_trade_no' => $trade_no, //订单号
'fee_type' => 'CNY',
'total_fee' => $total_fee,
'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],
'goods_tag' => C('APP_NAME').'-商品标记',
'notify_url' => C('RECHARGE_URL'),
'trade_type' => 'JSAPI',
'openid' => $openid
];
$sign = $this->MakeSign($data);
$data['sign'] = $sign;
$xml = $this->ToXml($data);
$result = $this->FromXml(Http::postXmlCurl($url,$xml));
return $result;
}
public function FromXml($xml)
{
if(!$xml){
throw new WxPayException("xml数据异常!");
}
//将XML转为array
//禁止引用外部xml实体
libxml_disable_entity_loader(true);
$values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $values;
}
public function ToXml($array){
if(!is_array($array)|| count($array) <= 0){
return ;
}
$xml = '<xml version="1.0">';
foreach ($array as $key=>$val){
if (is_numeric($val)){
$xml.="<".$key.">".$val."</".$key.">";
}else{
$xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
}
}
$xml.="</xml>";
return $xml;
}
private function createNonceStr($length = 16) {
$chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
$str = '';
for ( $i = 0; $i < $length; $i++ ) {
$str .= substr($chars, mt_rand(0, strlen($chars)-1), 1);
}
return $str;
}
private function MakeSign($data)
{
//签名步骤一:按字典序排序参数
ksort($data);
$string = $this->ToUrlParams($data);
//签名步骤二:在string后加入KEY
$string = $string . "&key=".C('WEIXIN_PAY_KEY');
//签名步骤三:MD5加密
$string = md5($string);
//签名步骤四:所有字符转为大写
$result = strtoupper($string);
return $result;
}
private function ToUrlParams($array)
{
$buff = "";
foreach ($array as $k => $v)
{
if($k != "sign" && $v != "" && !is_array($v)){
$buff .= $k . "=" . $v . "&";
}
}
$buff = trim($buff, "&");
return $buff;
}
//微信支付回调
public function order_notice(){
$xml = $GLOBALS['HTTP_RAW_POST_DATA'];
$data = $this->FromXml($xml);
// 保存微信服务器返回的签名sign
$data_sign = $data['sign'];
// sign不参与签名算法
unset($data['sign']);
$sign = $this->MakeSign($data);
// 判断签名是否正确 判断支付状态
if ( ($sign===$data_sign) && ($data['return_code']=='SUCCESS') && ($data['result_code']=='SUCCESS') ) {
//获取服务器返回的数据
$order_num = $data['out_trade_no']; //订单单号
$openid = $data['openid']; //付款人openID
$total_fee = $data['total_fee']; //付款金额
$transaction_id = $data['transaction_id']; //微信支付流水号
$user = M('user');
$user_info = $user->where(array('openid'=>$openid))->find();
$save_data = array(
'total_payed_price' => $total_fee/100, //实际到帐金额
'transaction_id' => $transaction_id,
'pay_time' => time(),
'status' => 2,
);
// 开启事务
M()->startTrans();
$error_count = 0;
// step 1 修改充值订单数据
$recharge_order = M('recharge_order');
$recharge_order_info = $recharge_order->where(array('order_num'=>$order_num,'uid'=>$user_info['id']))->find();
$recharge_amount= $recharge_order_info['amount'];
$recharge_save_flag = $recharge_order->where(array('order_num'=>$order_num,'uid'=>$user_info['id']))->save($save_data);
if(!$recharge_save_flag){
$error_count++;
}
// step 2 修改充值订单数据
$save_balance = $user_info['balance']+$recharge_amount;
$balance_save_flag = $user->where(array('openid'=>$openid))->save(['balance'=>$save_balance]);
if (!$balance_save_flag) {
$error_count++;
}
// step 3 增加充值记录
$balance_record = M('balance_record');
$balance_record_data = [
'uid' => $user_info['id'],
'amount' => $recharge_amount,
'balance' => $save_balance,
'type' => 1, // 增加
'from' => 1, // 充值
'remark' => '余额充值', // 充值
'create_time' => time(),
];
$add_flag = $balance_record->add($balance_record_data);
if (!$add_flag) {
$error_count ++;
}
if ($error_count > 0) {
M()->rollback();
$result = -2;
} else {
M()->commit();
$result = 0;
}
}else{
$result = -1;
}
// 返回状态给微信服务器
$str = '';
if ($result === 0) { // 成功之后不会再回调
$str='<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
} elseif ($result === -1){ // 失败后会继续发送几次回调
$str='<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>';
} elseif ($result === -2) { // 失败后会继续发送几次回调
$str='<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[操作失败]]></return_msg></xml>';
}
exit($str);
}
}