houdj

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

支付类:

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

namespace app\common\bussiness;


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 app\index\controller;
use app\BaseController;
use app\common\bussiness\WechatPay;
use app\index\model\Orders;
use app\index\model\PayLogs;
use app\index\model\StudentStudyRules;
use app\index\model\Students;

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

 

分类:

技术点:

相关文章:

  • 2021-12-29
  • 2021-09-03
  • 2021-04-24
  • 2021-11-17
  • 2021-07-13
  • 2021-12-09
  • 2021-12-15
  • 2021-10-13
猜你喜欢
  • 2021-12-29
  • 2022-01-08
  • 2022-01-01
  • 2019-12-24
  • 2021-11-07
  • 2021-10-03
  • 2021-10-01
相关资源
相似解决方案