Dai Chong's blog

小程序支付

 现如今的小程序愈发重要,微信小程序开发也成为开发者必须掌握的重要的技能之一。
 经过多年的发展,小程序开发更新换代非常快,在最近的开发中发现之前小程序支付的写法已经完全不适用了,害得我研究了很久,特写一篇文章记录一下。

开发前提

 (1)开通微信支付商户号。
 (2)开通小程序。
 (3)微信支付平台设置特约商户APPID,绑定小程序Appid。(这里要注意,小程序和支付商户必须是同一个主体)。
 (4)小程序绑定微信支付商户号。

具体差别

 可以从很久之前的文章看出,现在的小程序支付多了一个二次签名的步骤,这点需要大家注意。
 其他的步骤倒是没什么差别,具体可 官方文档

上代码(废话不多说,yii2写法)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
public function actionIndex()
{
try {
$user_id = FsRequest::userId('true');

if (!$user_id) {
throw new Exception('请先登录', [], 201);
}

$data = \Yii::$app->request->post();
if (empty($data)) {
throw new Exception('参数不全', [], 201);
}
$openId = WeixinUser::find()->where(['ecuid' => $user_id])->select(['dingdang_mini'])->one();
if (!$openId) {
throw new Exception('未绑定小程序', [], 201);
}
$payParams = [
'appid' => $appid,
'mch_id' => $mch_id,
'nonce_str' => WxHelper::createNoncestr(32),
'sign' => '',
'body' => $data['body'],
'out_trade_no' => $data['orderId'],
'total_fee' => (int)($data['price'] * 100),
'openid' => $openId->dingdang_mini,
'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],
'notify_url' => '支付回调',
'trade_type' => 'JSAPI',
];

$payParams['sign'] = WxHelper::paySign($payParams, $key);
$xml = WxHelper::arrayToXml($payParams);
// die($xml);
$payUrl = 'https://api.mch.weixin.qq.com/pay/unifiedorder';

$curl = new Curl();
$curl->setHeader('Content-Type', 'text/xml; charset=utf-8'); // xml
$curl->post($payUrl, $xml);
// 请求失败
if ($curl->error) {
throw new Exception($curl->errorMessage, [], 201);
} else {
// 微信返回错误
$result = WxHelper::xmlToArray($curl->response);
if ($result['result_code'] == 'FAIL') {
throw new Exception($result['err_code_des'], [], 201);
}
// 二次签名
$payParamsResult = [
'appId' => $this->appid,
'nonceStr' => WxHelper::createNoncestr(32),
'package' => 'prepay_id=' . $result['prepay_id'],
'paySign' => '',
'signType' => 'MD5',
'timeStamp' => (string)time()
];
$payParamsResult['paySign'] = WxHelper::paySign($payParamsResult, $this->key);
FsResponse::jsonSuccess($payParamsResult);
}
} catch (Exception $e) {
return FsResponse::jsonFaild($e->getCode(), $e->getMessage());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<?php
// 具体方法
namespace app\library\wechat;

use \Curl\Curl;
use app\models\redis\WxAccessToken;
use yii\db\Exception;

/**
* Class WxHelper
* @package app\library
*/
class WxHelper
{
// 获取小程序AccessToken
public static function getToken()
{
$token = WxAccessToken::get();
if (!$token) {
$url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' . $appId . '&secret=' . $secret;
$curl = new Curl();
$curl->get($url);
if ($curl->error) {
WxAccessToken::delete();
throw new Exception($curl->errorMessage, [],210);
}
if (isset($curl->response->errcode)) {
WxAccessToken::delete();
throw new Exception($curl->response->errmsg,[],210);
}
$token = $curl->response->access_token;
$time = $curl->response->expires_in;
WxAccessToken::set($token, $time - 100);
}
return $token;


}

public static function xmlToArray($xml)
{
//禁止引用外部xml实体
libxml_disable_entity_loader(true);
$values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $values;
}

public static function paySign($payParams, $key)
{
ksort($payParams);
$signString = self::toUrlParams($payParams);
$signString .= '&key=' . $key;
$signString = strtoupper(md5($signString));
return $signString;
}

#生成随机字符串
public static function createNoncestr($length = 7)
{
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ0123456789";
$str = "";
for ($i = 0; $i < $length; $i++) {
$str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
}
return $str;
}

public static function toUrlParams($payParams)
{
$buff = "";
foreach ($payParams as $k => $v) {
if ($k != "sign" && $v != "" && !is_array($v)) {
$buff .= $k . "=" . $v . "&";
}
}

$buff = trim($buff, "&");
return $buff;
}

public static function arrayToXml($array)
{
$xml = "<xml>";
foreach ($array as $key => $val) {
if (is_numeric($val)) {
$xml .= "<" . $key . ">" . $val . "</" . $key . ">";
} else {
$xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
}
}
$xml .= "</xml>";
return $xml;
}
}

总结

 微信支付比较简单,只是文档写的不清晰导致开发难度增加。


 评论