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

24次阅读

共计 4932 个字符,预计需要花费 13 分钟才能阅读完成。

前两天开始做移动端 APP 的微信支付,过程中遇到了一些问题,比如支付的过程中返回值总是:-1 {status:false},这些问题已经得到了解决。前人栽树,后人尽管乘凉,那么分享一下整个支付过程(wxPay 方案一):

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

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