微信小程序支付功能

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);
    }


}
posted @ 2019-03-26 17:30  TBHacker  阅读(636)  评论(0编辑  收藏  举报