移动APP 微信支付完整过程(wxPay 方案一)

2
回复
623
查看
[复制链接]

74

主题

88

帖子

641

安币

代码手工艺人

Rank: 4

发表于 2019-4-30 16:01:34 | 显示全部楼层 |阅读模式
前两天开始做移动端APP的微信支付,过程中遇到了一些问题,比如支付的过程中返回值总是:-1 {status:false},这些问题已经得到了解决。前人栽树,后人尽管乘凉,那么分享一下整个支付过程(wxPay 方案一):
1、申请微信开发平台的账号、创建移动应用、申请开发者资质认证(整个过程APICLOUD官方网站已经给出了相当明确的操作步骤,与实际操作没有差异,按照文档一步一步来,是没有问题的),附带链接地址:http://docs.apicloud.com/Others/Open-SDK-Integration-Guide/weChat

2、配置移动应用中 config.xml 文件
<feature name="wxPay">    <param name="urlScheme" value="***"/>    <param name="apiKey" value="***"/>    <param name="apiSecret" value="***"/>  </feature>
复制代码

配置获取方式说明以及截图:从微信开发平台获取,登录微信开发平台 —>管理中心—>移动应用—>查看(urlScheme的值和apiKey相同)(微信开发平台链接:https://open.weixin.qq.com/
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端代码如下:
$.ajax({            url:url,            data:{                body:body,                attach:attach,                total_fee:total_fee            },            dataType:"json",            type:"post",            success:function(data){                if(data.payData != "error"){                    var wxPay = api.require('wxPay');                    wxPay.payOrder(data, function(ret, err) {                        if (ret.status) {                            //支付成功                            alert('支付成功');                            }                        } else {                            alert(err.code);

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

0

主题

177

帖子

282

安币

攻城狮

Rank: 3Rank: 3

QQ达人

发表于 2019-7-2 13:59:18 | 显示全部楼层
感谢分享,安卓巴士有你更精彩:)

0

主题

52

帖子

637

安币

代码手工艺人

Rank: 4

发表于 2019-8-19 15:13:40 | 显示全部楼层
感谢分享,安卓巴士有你更精彩:)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

领先的中文移动开发者社区
18620764416
7*24全天服务
意见反馈:1294855032@qq.com

扫一扫关注我们

Powered by Discuz! X3.2© 2001-2019 Comsenz Inc.( 粤ICP备15117877号 )