移动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_rand0, 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_loadertrue); $postObj = json_decodejson_encodesimplexml_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'
        }, functionret, err) {
            api.hideProgress);
            /*** 登录异常 ***/
            if err) {
                api.toast{
                msg:'网络异常,请稍后重试',
                duration: '1300',
                localtion: 'middle'
             });
                return;
            }
            var wxPay = api.require'wxPay');
            var data = ret.data;
            wxPay.payOrderdata, functionret, err) {
                var statue = false;
                if ret.status) {
                    statue = true;
                    openPayResultstatue);
                } else {
                    statue = false;
                    openPayResultstatue);
                }
            });

        });

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)。

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注