zoukankan      html  css  js  c++  java
  • 移动APP 微信支付完整过程(wxPay 方案一)

    apicloud、weixinpay官方提供了两种方案。

    本模块封装了两套支付方案:
    
    方案一:开发者通过 getOrderId、payOrder 自己处理签名过程(微信开放平台建议把 getOrderId 放在服务器端执行);
    
    方案二:通过 config 接口和 pay 接口把签名过程交予模块内部处理。config 接口的参数可通过 key.xml 文件配置。
      (本支付方案用于开发阶段测试验证账号的正确性,正式发版时请使用支付方案一)

    方案二、属于本地测试账号是否完整的流程,正式使用的话使用方案一。

    方案一、微信支付流程为:

    1、获取与支付订单。(这个订单号是微信生成的)。
    2、调用微信支付。

    完整的方案一支付流程为:

    1、申请微信开发平台的账号、创建移动应用、申请开发者资质认证(整个过程APICLOUD官方网站已经给出了相当明确的操作步骤,与实际操作没有差异,按照文档一步一步来,是没有问题的),附带链接地址:http://docs.apicloud.com/Others/Open-SDK-Integration-Guide/weChat

    2、配置移动应用中 config.xml 文件

      <feature name="wxPay">
        <param name="urlScheme" value="wxd0d84bbf23b4a0e4"/>
        <param name="apiKey" value="wxd0d84bbf23b4a0e4"/>
        <param name="apiSecret" value="a354f72aa1b4c2b8eaad137ac81434cd"/>
      </feature>

    3、getOrderId(),将获取预支付订单号,建议将获取预支付订单号放置服务器端执行。(服务端代码如下:)

    $dataArr = array(
        'appid' => $appId,
        'mch_id' => $mchId,
        'nonce_str' => getNonceStr(),
        'body' => $body,
        'attach' => $attach,
        'out_trade_no' => getNonceStr(),
        'total_fee' => $totalFee,
        'spbill_create_ip' => $cIp,
        'notify_url' => $url,
        'trade_type' => 'APP'
    );
    
    //转XML格式
    function createXML($rootNode, $arr) {
        //创建一个文档,文档时xml的,版本号为1.0,编码格式utf-8
        $xmlObj = new DOMDocument('1.0', 'UTF-8');
        //创建根节点
        $Node = $xmlObj - > createElement($rootNode);
        //把创建好的节点加到文档中
        $root = $xmlObj - > appendChild($Node);
        //开始把数组中的数据加入文档
        foreach($arr as $key => $value) {
            //如果是$value是一个数组
            if (is_array($value)) {
                //先创建一个节点
                $childNode = $xmlObj - > createElement($key);
                //将节点添加到$root中
                $root - > appendChild($childNode);
                //循环添加数据
                foreach($value as $key2 => $val2) {
                    //创建节点的同时添加数据
                    $childNode2 = $xmlObj - > createElement($key2, $val2);
                    //将节点添加到$childNode
                    $childNode - > appendChild($childNode2);
                }
            } else {
                //创建一个节点,根据键和值
                $childNode = $xmlObj - > createElement($key, $value);
                //把节点加到根节点
                $root - > appendChild($childNode);
            }
        }
        //把创建好的xml保存到本地
        $xmlObj - > save('xml/log.xml');
        $str = $xmlObj - > saveXML();
        //        echo $str;
        //返回xml字符串
        return $str;
    }
    
    //封装签名算法
    function MakeSign($arr) {
        //签名步骤一:按字典序排序参数
        ksort($arr);
        $string = ToUrlParams($arr);
        //签名步骤二:在string后加入KEY
        $string = $string.
        "&key=".$key;
        //签名步骤三:MD5加密
        $string = md5($string);
        //签名步骤四:所有字符转为大写
        $result = strtoupper($string);
        return $result;
    }
    
    /**
     * 格式化参数格式化成url参数
     */
    function ToUrlParams($arr) {
        $buff = "";
        foreach($arr as $k => $v) {
            if ($k != "sign" && $v != "" && !is_array($v)) {
                $buff. = $k.
                "=".$v.
                "&";
            }
        }
        $buff = trim($buff, "&");
        return $buff;
    }
    
    //随机字符串(不长于32位)
    function getNonceStr($length = 32) {
        $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
        $str = "";
        for ($i = 0; $i < $length; $i++) {
            $str. = substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }
    
    function curl($url, $post_data) {
        $headerArray = array(
            'Accept:application/json, text/javascript, */*',
            'Content-Type:application/x-www-form-urlencoded',
            'Referer:https://mp.weixin.qq.com/'
        );
    
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        // 对认证证书来源的检查,0表示阻止对证书的合法性的检查。
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        // 从证书中检查SSL加密算法是否存在
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //关闭直接输出
        curl_setopt($ch, CURLOPT_POST, 1); //使用post提交数据
        curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data); //设置 post提交的数据
        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.69 Safari/537.36'); //设置用户代理
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headerArray); //设置头信息
    
        $loginData = curl_exec($ch); //这里会返回token,需要处理一下。
    
        return $loginData;
    
        $token = array_pop($token);
        curl_close($ch);
    }
    
    /**
     * 解析xml文档,转化为对象
     * @param  String $xmlStr xml文档
     * @return Object         返回Obj对象
     */
    function xmlToObject($xmlStr) {
        if (!is_string($xmlStr) || empty($xmlStr)) {
            return false;
        }
        // 由于解析xml的时候,即使被解析的变量为空,依然不会报错,会返回一个空的对象,所以,我们这里做了处理,当被解析的变量不是字符串,或者该变量为空,
      直接返回false
    libxml_disable_entity_loader(true); $postObj = json_decode(json_encode(simplexml_load_string($xmlStr, 'SimpleXMLElement', LIBXML_NOCDATA)), true); //将xml数据转换成对象返回 return $postObj; }
    //=====================执行=======================
    $sign = MakeSign($dataArr);//签名生成
    $dataArr['sign'] = $sign;
    
    $xmlStr = createXML('xml', $dataArr);//统一下单xml数据生成
    $reArr = explode('?>', $xmlStr);
    $reArr = end($reArr);
    
    $xml = curl('https://api.mch.weixin.qq.com/pay/unifiedorder', $reArr);//发送请求 统一下单数据
    
    //解析返回的xml字符串
    $re = xmlToObject($xml);
    
    //判断统一下单是否成功
    if ($re['result_code'] == 'SUCCESS') {
    
        //支付请求数据
        $payData = array(
            'appid' => $re['appid'],
            'partnerid' => $re['mch_id'],
            'prepayid' => $re['prepay_id'],
            'noncestr' => getNonceStr(),
            'package' => 'Sign=WXPay',
            'timestamp' => time()
        );
    
    
        //生成支付请求的签名
        $paySign = MakeSign($payData);
    
        $payData['sign'] = $paySign;
    
        //拼接成APICLOUD所需要支付数据请求
        $payDatas = array(
            'apiKey' => $re['appid'],
            'orderId' => $re['prepay_id'],
            'mchId' => $re['mch_id'],
            'nonceStr' => $payData['noncestr'],
            'package' => 'Sign=WXPay',
            'timeStamp' => $payData['timestamp'],
            'sign' => $paySign
        );
    
        //返回支付请求数据
        echo json_encode($payDatas);
    } else {
        $re['payData'] = "error";
        echo json_encode($re);
    }

    4、预支付下单成功后,将拼接好的支付请求数据返回,也就是上述代码中数组$payDatas(注意:第二次参与签名的字段是:appid、partnerid、prepayid、noncestr、package、timestamp),app端代码如下:

    api.ajax({
                url: baseUrl +'/api/v1/mallOrder/toPay?memberId=' +memberId+ '&orderId=' +orderId,
                timeout: 10,
                dataType: 'json',
                method: 'get'
            }, function(ret, err) {
                api.hideProgress();
                /*** 登录异常 ***/
                if (err) {
                    api.toast({
                    msg:'网络异常,请稍后重试',
                    duration: '1300',
                    localtion: 'middle'
                 });
                    return;
                }
                var wxPay = api.require('wxPay');
                var data = ret.data;
                wxPay.payOrder(data, function(ret, err) {
                    var statue = false;
                    if (ret.status) {
                        statue = true;
                        openPayResult(statue);
                    } else {
                        statue = false;
                        openPayResult(statue);
                    }
                });
    
            });

    5、以上描述,已经亲测没有问题,如果代码或叙述有问题的,欢迎各位大神指教批评;如果有帮到各位初学者的不胜荣幸;另外说下我之前遇到过支付过程中返回-1的问题:这个问题不得不说APICLOUD官网有那么一点点的坑,官网上面payOrder()的参数为:appKey、orderId、mchId、nonceStr、timeStamp、package,就会以为参与第二次支付签名的参数是这些,但其实并不是,那么参与第二次支付签名的参数是:appid、partnerid、prepayid、noncestr、package、timestamp,生成签名后,需要将payOrder()所需要的参数一一对应重新填写(appKey==appid、orderId==prepayid、mchId==partnerid、nonceStr==noncestr、package==package、timeStamp==timestamp)。

  • 相关阅读:
    高速传输线PCB设计
    带状线和微带线
    资源分配
    异步时钟切换电路
    Mathcad操作tips:2D绘图
    Mathcad操作tips:函数、符号计算
    慢性胃炎注意事项
    Arduino I2C + 三轴加速度计ADXL345
    Arduino SPI + SPI Flash芯片W25Q80BV
    Arduino I2C + 三轴加速度计LIS3DH
  • 原文地址:https://www.cnblogs.com/haonanZhang/p/9228031.html
Copyright © 2011-2022 走看看