微信支付之jsapi支付和h5支付

支付类:

<?php
/**
 * Desc:微信支付jsapi和h5支付
 * Created by PhpStorm.
 * User: HOUDJ
 * Date: 2020/6/17
 * Time: 16:36
 */

namespace appcommonussiness;


class WechatPay
{
    const UNURL = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
    const SEORDERURL = 'https://api.mch.weixin.qq.com/pay/orderquery';
    //生成签名
    public function getSign($arr){
        //去除空值
        $arr = array_filter($arr);
        if(isset($arr['sign'])){
            unset($arr['sign']);
        }
        //按照键名字典排序
        ksort($arr);
        //生成url格式的字符串
        $str = $this->arrToUrl($arr) . '&key=' . config('app.wechat.api_key');
        return strtoupper(md5($str));
    }

    //获取带签名的数组
    public function setSign($arr){
        $arr['sign'] = $this->getSign($arr);;
        return $arr;
    }

    public function arrToUrl($arr){
        return urldecode(http_build_query($arr));
    }

    //验证签名
    public function chekSign($arr){
        $sign = $this->getSign($arr);
        if($sign == $arr['sign']){
            return true;
        }else{
            return false;
        }
    }

    /**
     * Notes:调用统一下单api
     * User: HOUDJ
     * Date: 2020/7/2
     */
    public function unifiedOrder($data,$type=false){
        /**
         * 1.构建原始数据
         * 2.加入签名
         * 3.将数据转换为XML
         * 4.发送XML格式的数据到接口地址
         */
        $params = [
            'appid'=> config('app.wechat.appid'),
            'mch_id'=> config('app.wechat.mch_id'),
            'nonce_str'=>md5(time()),
            'body'=>$data['body'],
            'attach'=>$data['attach'],
            'out_trade_no'=>$data['out_trade_no'],
            'total_fee'=> floatval($data['order_price']*100),
            'spbill_create_ip'=>$_SERVER['REMOTE_ADDR'],
            'notify_url'=> config('app.wechat.notify'),
            'trade_type'=>'JSAPI',

        ];
        if($type == 'h5'){
            $params['trade_type'] = 'MWEB';
        }else{
            $params['openid'] = $data['open_id'];
        }
        $params = $this->setSign($params);
        $xmldata = $this->ArrToXml($params);
        $resdata = $this->postXml(self::UNURL, $xmldata);
        $arr = $this->XmlToArr($resdata);
        return $arr;
    }

    /**
     * Notes:调用查询订单接口
     * User: HOUDJ
     * Date: 2020/7/2
     */
    public function queryOrder($trade_no){
        //构建数据
        $params = [
            'appid'=> config('app.wechat.appid'),
            'mch_id'=> config('app.wechat.mch_id'),
            'out_trade_no' => $trade_no,
            'nonce_str'=>md5(time()),
            'sign_type' => 'MD5'
        ];

        $params = $this->setSign($params);
        $xmldata = $this->ArrToXml($params);
        $resdata = $this->postXml(self::SEORDERURL, $xmldata);
        $arr = $this->XmlToArr($resdata);
        return $arr;
    }

    /**
     * Notes:获取prepayid
     * User: HOUDJ
     * Date: 2020/7/2
     */
    public function getPrepayId($oid){
        $arr = $this->unifiedOrder($oid);
        return $arr['prepay_id'];
    }

    /**
     * Notes:获取公众号支付所需要的json数据
     * User: HOUDJ
     * Date: 2020/7/2
     */
    public function getJsParams($prepay_id){
        $params = [
            'appId' => config('app.wechat.appid'),
            'timeStamp' =>time(),
            'nonceStr' => md5(time()),
            'package' =>'prepay_id=' . $prepay_id,
            'signType' =>'MD5',
            //       'paySign' => $this->getSign($params)
        ];
        $params['paySign'] = $this->getSign($params);
        return json_encode($params);
    }

    /**
     * Notes:数组转xml
     * User: HOUDJ
     * Date: 2020/7/2
     */
    public function ArrToXml($arr)
    {
        if(!is_array($arr) || count($arr) == 0) return '';

        $xml = "<xml>";
        foreach ($arr as $key=>$val)
        {
            if (is_numeric($val)){
                $xml.="<".$key.">".$val."</".$key.">";
            }else{
                $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
            }
        }
        $xml.="</xml>";
        return $xml;
    }

    /**
     * Notes:Xml转数组
     * User: HOUDJ
     * Date: 2020/7/2
     */
    public function XmlToArr($xml)
    {
        if($xml == '') return '';
        libxml_disable_entity_loader(true);
        $arr = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $arr;
    }

    /**
     * Notes:发送
     * User: HOUDJ
     * Date: 2020/7/2
     */
    public function postXml($url,$postfields){
        $ch = curl_init();
        $params[CURLOPT_URL] = $url;    //请求url地址
        $params[CURLOPT_HEADER] = false; //是否返回响应头信息
        $params[CURLOPT_RETURNTRANSFER] = true; //是否将结果返回
        $params[CURLOPT_FOLLOWLOCATION] = true; //是否重定向
        $params[CURLOPT_POST] = true;
        $params[CURLOPT_POSTFIELDS] = $postfields;
        $params[CURLOPT_SSL_VERIFYPEER] = false;
        $params[CURLOPT_SSL_VERIFYHOST] = false;
        curl_setopt_array($ch, $params); //传入curl参数
        $content = curl_exec($ch); //执行
        curl_close($ch); //关闭连接
        return $content;
    }

    /**
     * Notes:获取post过来的数据
     * User: HOUDJ
     * Date: 2020/7/3
     */
    public function getPost(){
        $xml = isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : file_get_contents("php://input");
        return $xml;
    }

}

支付:

判断当前支付环境是h5还是为微信内支付,前台通过user_anv传递环境

    public function createOrder(){
        $project_id=$this->request->param('project_id',0,'intval');
        $integral=$this->request->param('integral',0,'intval');
        if(!$project_id){
            return returnMsg(config('status.error'),'','参数错误');
        }
        $orders=new OrdersModel();
        $info=$orders->createOrder($this->userId,$project_id,$integral);//生成订单
        if($info['code']){//订单生成成功 处理支付
            //如果当前是微信环境并且用户openid不为空 调取jsapi支付 否则h5支付
            $data['body']=$info['data']['body'];
            $data['out_trade_no']=$info['data']['order_sn'];
            $data['order_price']=$info['data']['pay_price'];
            $data['open_id']=$this->open_id;
            $data['attach']='课程购买';
            $pay=new WechatPay();
            if($this->user_env && $this->open_id){
                $prepay_id = $pay->getPrepayId($data);
                $code_str = $pay->getJsParams($prepay_id);
                $info['data']['pay_type']='jsapi';
                $info['data']['pay']=$code_str;
            }else{
                $code_str = $pay->unifiedOrder($data,'h5');
                $info['data']['pay_type']='h5';
                $info['data']['pay']=$code_str['mweb_url'];
            }
            return returnMsg($info['code'],$info['data'],$info['msg']);
        }else{
            return returnMsg($info['code'],$info['data'],$info['msg']);
        }
    }

jsapi支付返回

{
    "code": 1,
    "data": {
        "stu_id": 15,
        "order_sn": "DD1593756697752151350",
        "order_price": "0.01",
        "pay_price": "0.01",
        "cost_integral": 0,
        "body": "学员注册",
        "pay_type": "jsapi",
        "pay": "{"appId":"wxbf20372629712be4","timeStamp":1593756697,"nonceStr":"23709aa6c748eab1f7abe3afbd1c6d7f","package":"prepay_id=wx0314113788641179329909651256281400","signType":"MD5","paySign":"D4E388855A2E8AFA6C8736C98F0B74DD"}"
    },
    "msg": "订单生成成功"
}

H5支付返回

{
    "code": 1,
    "data": {
        "stu_id": 15,
        "order_sn": "DD1593756510004805466",
        "order_price": "0.01",
        "pay_price": "0.01",
        "cost_integral": 0,
        "body": "学员注册",
        "pay_type": "h5",
        "pay": "https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx0314083017318922e8e1ab591995287800&package=1813868424"
    },
    "msg": "订单生成成功"
}

支付回调:

<?php
/**
 * Created by PhpStorm.
 * User: HOUDJ
 * Date: 2020/7/2
 * Time: 16:16
 */

namespace appindexcontroller;
use appBaseController;
use appcommonussinessWechatPay;
use appindexmodelOrders;
use appindexmodelPayLogs;
use appindexmodelStudentStudyRules;
use appindexmodelStudents;

class Payment extends BaseController
{
    /**
     * Notes:支付回调
     * User: HOUDJ
     * Date: 2020/7/3
     */
    public function notify(){
        $pay=new WechatPay();
        $xmlData = $pay->getPost();
        $arr = $pay->XmlToArr($xmlData);
        if($pay->chekSign($arr)){
            if($arr['return_code'] == 'SUCCESS' && $arr['result_code'] == 'SUCCESS') {
                $this->pay_action($arr, $arr['out_trade_no']);
            }else{
                logs(date('Y-m-d H:i:s').'业务结果错误:'.json_encode($arr),'pay_notify_fail');
            }
            //通知微信
            $returnParams = [
                'return_code' => 'SUCCESS',
                'return_msg'  => 'OK'
            ];
            echo $pay->ArrToXml($returnParams);
        }else{
            logs(date('Y-m-d H:i:s').'签名错误:'.json_encode($arr),'pay_notify_fail');
            //通知微信
            $returnParams = [
                'return_code' => 'FAIL',
                'return_msg'  => '签名错误'
            ];
            echo $pay->ArrToXml($returnParams);
        }
    }

    /**
     * Notes:h5查询是否支付成功
     * User: HOUDJ
     * Date: 2020/7/3
     */
    public function h5_notify(){
        $order_sn=$this->request->param('order_sn');
        $pay=new WechatPay();
        $arr=$pay->queryOrder($order_sn);
        if($arr['return_code'] == 'SUCCESS' && $arr['result_code'] == 'SUCCESS') {
            $this->pay_action($arr,$order_sn);
            return returnMsg(config('status.success'),'','支付成功');
        }else{
            logs(date('Y-m-d H:i:s').'业务结果错误:'.json_encode($arr),'pay_notify_fail');
            return returnMsg(config('status.error'),'','支付失败');
        }
    }

    /**
     * Notes:处理支付成功的逻辑
     * User: HOUDJ
     * Date: 2020/7/3
     */
    public function pay_action($arr,$order_sn=''){
        logs(date('Y-m-d H:i:s').json_encode($arr), 'pay_notify_success');
        //将金额分转化成交易金额
        $total_fee = number_format($arr['total_fee']/100,2,'.','');
        //改变订单状态
        $orderInfo= Orders::where('order_sn', '=', $order_sn)->find();
        $map[] = ['id', '=', $orderInfo['id']];
        Orders::updateOrderStatus($map, ['order_status' => 1, 'pay_time' => time(), 'pay_price' => $total_fee]);
        //如果是购买的课程 将课程的效期显示 如果购买的会员注册 则将会员状态改变
        if($arr['attach']=='课程购买') {
            StudentStudyRules::where('order_id', '=', $orderInfo['id'])->update(['status' => 1]);
        }else{
            Students::where('id','=',$orderInfo['stu_id'])->update(['status'=>2,'frozen'=>0]);
        }
        PayLogs::logs($orderInfo,$arr,$total_fee);
    }
}
原文地址:https://www.cnblogs.com/houdj/p/13230771.html