微信支付开发中刷卡支付实例的详细解析

why 24 2024-09-24

本文介绍微信支付下的刷卡支付的开发过程。微信刷卡支付是指用户打开微信钱包的刷卡的界面,商户扫码后提交完成支付的支付过程。

 image.png


image.png

一、刷卡支付API

接口地址

1

api.mch.weixin.qq.com/pay/micropay

是否需要证书

不需要。

输入参数

名称 变量名 必填 类型 示例值 描述







公众账号IDappidString(32)wx8888888888888888微信分配的公众账号ID(企业号corpid即为此appId)
商户号mch_idString(32)1900000109微信支付分配的商户号
设备号device_infoString(32)013467007045764终端设备号(商户自定义,如门店编号)
随机字符串nonce_strString(32)5K8264ILTKCH16CQ2502SI8ZNMTM67VS随机字符串,不长于32位。推荐随机数生成算法
签名signString(32)C380BEC2BFD727A4B6845133519F3AD6签名,详见签名生成算法
商品描述bodyString(128)image形象店-深圳腾大- QQ公仔商品简单描述,该字段须严格按照规范传递,具体请见参数规定
商品详情detailString(6000)
12345678910111213141516171819202122{"goods_detail":[{"goods_id":"iphone6s_16G","wxpay_goods_id":"1001","goods_name":"iPhone6s 16G","goods_num":1,"price":528800,"goods_category":"123456","body":"苹果手机"},{"goods_id":"iphone6s_32G","wxpay_goods_id":"1002","goods_name":"iPhone6s 32G","quantity":1,"price":608800,"goods_category":"123789","body":"苹果手机"}]}

商品详细列表,使用Json格式,传输签名前请务必使用CDATA标签将JSON文本串保护起来。

goods_detail []:
└ goods_id String 必填 32 商品的编号
└ wxpay_goods_id String 可选 32 微信支付定义的统一商品编号
└ goods_name String 必填 256 商品名称
└ goods_num Int 必填 商品数量
└ price Int 必填 商品单价,单位为分
└ goods_category String 可选 32 商品类目ID
└ body String 可选 1000 商品描述信息

附加数据attachString(127)说明附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据
商户订单号out_trade_noString(32)1217752501201407033233368018商户系统内部的订单号,32个字符内、可包含字母,其他说明见商户订单号
商品详情detailString(8192)与提交数据一致

实际提交的返回

订单金额total_feeInt888订单总金额,单位为分,只能为整数,详见支付金额
货币类型fee_typeString(16)CNY符合ISO4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型
终端IPspbill_create_ipString(16)8.8.8.8调用微信支付API的机器IP
商品标记goods_tagString(32)
商品标记,代金券或立减优惠功能的参数,说明详见代金券或立减优惠
指定支付方式limit_payString(32)no_creditno_credit--指定不能使用信用卡支付
授权码auth_codeString(128)120061098828009406扫码支付授权码,设备读取用户微信中的条码或者二维码信息

举例如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

<xml>

   <appid>wx2421b1c4370ec43b</appid>

   <attach>订单额外描述</attach>

   <auth_code>120269300684844649</auth_code>

   <body>刷卡支付测试</body>

   <device_info>1000</device_info>

   <goods_tag></goods_tag>

   <mch_id>10000100</mch_id>

   <nonce_str>8aaee146b1dee7cec9100add9b96cbe2</nonce_str>

   <out_trade_no>1415757673</out_trade_no>

   <spbill_create_ip>14.17.22.52</spbill_create_ip>

   <time_expire></time_expire>

   <total_fee>1</total_fee>

   <sign>C29DB7DB1FD4136B84AE35604756362C</sign>

</xml>

注:参数值用XML转义即可,CDATA标签用于说明数据不被XML解析器解析。

返回结果

名称 变量名 必填 类型 示例值 描述







返回状态码return_codeString(16)SUCCESSSUCCESS/FAIL
此字段是通信标识,非交易标识,交易是否成功需要查看result_code来判断
返回信息return_msgString(128)签名失败返回信息,如非空,为错误原因
签名失败
参数格式校验错误

当return_code为SUCCESS的时候,还会包括以下字段:

名称 变量名 必填 类型 示例值 描述







公众账号IDappidString(32)wx8888888888888888调用接口提交的公众账号ID
商户号mch_idString(32)1900000109调用接口提交的商户号
设备号device_infoString(32)013467007045764调用接口提交的终端设备号,
随机字符串nonce_strString(32)5K8264ILTKCH16CQ2502SI8ZNMTM67VS微信返回的随机字符串
签名signString(32)C380BEC2BFD727A4B6845133519F3AD6微信返回的签名,详见签名生成算法
业务结果result_codeString(16)SUCCESSSUCCESS/FAIL
错误代码err_codeString(32)SYSTEMERROR详细参见错误列表
错误代码描述err_code_desString(128)系统错误错误返回的信息描述

当return_code 和result_code都为SUCCESS的时,还会包括以下字段:

名称 变量名 必填 类型 示例值 描述







用户标识openidString(128)Y用户在商户appid 下的唯一标识
是否关注公众账号is_subscribeString(1)Y用户是否关注公众账号,仅在公众账号类型支付有效,取值范围:Y或N;Y-关注;N-未关注
交易类型trade_typeString(16)MICROPAY支付类型为MICROPAY(即扫码支付)
付款银行bank_typeString(16)CMC银行类型,采用字符串类型的银行标识,值列表详见银行类型
货币类型fee_typeString(16)CNY符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型
订单金额total_feeInt888订单总金额,单位为分,只能为整数,详见支付金额
现金支付货币类型cash_fee_typeString(16)CNY符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型
现金支付金额cash_feeInt100订单现金支付金额,详见支付金额
微信支付订单号transaction_idString(32)1217752501201407033233368018微信支付订单号
商户订单号out_trade_noString(32)1217752501201407033233368018商户系统的订单号,与请求一致。
商家数据包attachString(128)123456商家数据包,原样返回
支付完成时间time_endString(14)20141030133525订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。详见时间规则

举例如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

<xml>

   <return_code><![CDATA[SUCCESS]]></return_code>

   <return_msg><![CDATA[OK]]></return_msg>

   <appid><![CDATA[wx2421b1c4370ec43b]]></appid>

   <mch_id><![CDATA[10000100]]></mch_id>

   <device_info><![CDATA[1000]]></device_info>

   <nonce_str><![CDATA[GOp3TRyMXzbMlkun]]></nonce_str>

   <sign><![CDATA[D6C76CB785F07992CDE05494BB7DF7FD]]></sign>

   <result_code><![CDATA[SUCCESS]]></result_code>

   <openid><![CDATA[oUpF8uN95-Ptaags6E_roPHg7AG0]]></openid>

   <is_subscribe><![CDATA[Y]]></is_subscribe>

   <trade_type><![CDATA[MICROPAY]]></trade_type>

   <bank_type><![CDATA[CCB_DEBIT]]></bank_type>

   <total_fee>1</total_fee>

   <coupon_fee>0</coupon_fee>

   <fee_type><![CDATA[CNY]]></fee_type>

   <transaction_id><![CDATA[1008450740201411110005820873]]></transaction_id>

   <out_trade_no><![CDATA[1415757673]]></out_trade_no>

   <attach><![CDATA[订单额外描述]]></attach>

   <time_end><![CDATA[20141111170043]]></time_end>

</xml>

二、刷卡支付类实现

在微信支付原来的微信支付类文件中,仿照统一支付类的方式,添加刷卡支付类如下:

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

/**

 * 刷卡支付接口类

 */

class MicroPay_pub extends Wxpay_client_pub

{   

    function __construct()

    {

        //设置接口链接

        $this->url = "https://api.mch.weixin.qq.com/pay/micropay";

        //设置curl超时时间

        $this->curl_timeout = WxPayConf_pub::CURL_TIMEOUT;

    }

     

    /**

     * 生成接口参数xml

     */

    function createXml()

    {

        try

        {

            //检测必填参数

            if($this->parameters["out_trade_no"] == null){

                throw new SDKRuntimeException("缺少统一支付接口必填参数out_trade_no!"."<br>");

            }elseif($this->parameters["body"] == null){

                throw new SDKRuntimeException("缺少统一支付接口必填参数body!"."<br>");

            }elseif ($this->parameters["total_fee"] == null ) {

                throw new SDKRuntimeException("缺少统一支付接口必填参数total_fee!"."<br>");

            }elseif ($this->parameters["auth_code"] == null) {

                throw new SDKRuntimeException("缺少统一支付接口必填参数auth_code!"."<br>");

            }

               $this->parameters["appid"] = WxPayConf_pub::APPID;//公众账号ID

               $this->parameters["mch_id"] = WxPayConf_pub::MCHID;//商户号

               $this->parameters["spbill_create_ip"] = $_SERVER[&#39;REMOTE_ADDR&#39;];//终端ip       

            $this->parameters["nonce_str"] = $this->createNoncestr();//随机字符串

            $this->parameters["sign"] = $this->getSign($this->parameters);//签名

            // var_dump($this->parameters);

            return  $this->arrayToXml($this->parameters);

        }catch (SDKRuntimeException $e)

        {

            die($e->errorMessage());

        }

    }

}

原有的基础类和请求类也列出如下:

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

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

/**

 * 所有接口的基类

 */

class Common_util_pub

{

    function __construct() {

    }

 

    function trimString($value)

    {

        $ret = null;

        if (null != $value)

        {

            $ret = $value;

            if (strlen($ret) == 0)

            {

                $ret = null;

            }

        }

        return $ret;

    }

     

    /**

     *     作用:产生随机字符串,不长于32位

     */

    public function createNoncestr( $length = 32 )

    {

        $chars = "abcdefghijklmnopqrstuvwxyz0123456789"

        $str ="";

        for ( $i = 0; $i < $length; $i++ )  { 

            $str.= substr($chars, mt_rand(0, strlen($chars)-1), 1); 

        

        return $str;

    }

     

    /**

     *     作用:格式化参数,签名过程需要使用

     */

    function formatBizQueryParaMap($paraMap, $urlencode)

    {

        $buff = "";

        ksort($paraMap);

        foreach ($paraMap as $k => $v)

        {

            if($urlencode)

            {

               $v = urlencode($v);

            }

            //$buff .= strtolower($k) . "=" . $v . "&";

            $buff .= $k . "=" . $v . "&";

        }

        $reqPar;

        if (strlen($buff) > 0)

        {

            $reqPar = substr($buff, 0, strlen($buff)-1);

        }

        return $reqPar;

    }

     

    /**

     *     作用:生成签名

     */

    public function getSign($Obj)

    {

        foreach ($Obj as $k => $v)

        {

            $Parameters[$k] = $v;

        }

        //签名步骤一:按字典序排序参数

        ksort($Parameters);

        $String = $this->formatBizQueryParaMap($Parameters, false);

        //echo &#39;【string1】&#39;.$String.&#39;</br>&#39;;

        //签名步骤二:在string后加入KEY

        $String = $String."&key=".WxPayConf_pub::KEY;

        //echo "【string2】".$String."</br>";

        //签名步骤三:MD5加密

        $String = md5($String);

        //echo "【string3】 ".$String."</br>";

        //签名步骤四:所有字符转为大写

        $result_ = strtoupper($String);

        //echo "【result】 ".$result_."</br>";

        return $result_;

    }

     

    /**

     *     作用:array转xml

     */

    function arrayToXml($arr)

    {

        $xml = "<xml>";

        foreach ($arr as $key=>$val)

        {

             if (is_numeric($val))

             {

                 $xml.="<".$key.">".$val."</".$key.">";

 

             }

             else

                 $xml.="<".$key."><![CDATA[".$val."]]></".$key.">"

        }

        $xml.="</xml>";

        return $xml;

    }

     

    /**

     *     作用:将xml转为array

     */

    public function xmlToArray($xml)

    {       

        //将XML转为array       

        $array_data = json_decode(json_encode(simplexml_load_string($xml, &#39;SimpleXMLElement&#39;, LIBXML_NOCDATA)), true);       

        return $array_data;

    }

 

    /**

     *     作用:以post方式提交xml到对应的接口url

     */

    public function postXmlCurl($xml,$url,$second=30)

    {       

        //初始化curl       

           $ch = curl_init();

        //设置超时

        curl_setopt($ch, CURLOP_TIMEOUT, $second);

        //这里设置代理,如果有的话

        //curl_setopt($ch,CURLOPT_PROXY, &#39;8.8.8.8&#39;);

        //curl_setopt($ch,CURLOPT_PROXYPORT, 8080);

        curl_setopt($ch,CURLOPT_URL, $url);

        curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);

        curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);

        //设置header

        curl_setopt($ch, CURLOPT_HEADER, FALSE);

        //要求结果为字符串且输出到屏幕上

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);

        //post提交方式

        curl_setopt($ch, CURLOPT_POST, TRUE);

        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);

        //运行curl

        $data = curl_exec($ch);

        curl_close($ch);

        //返回结果

        if($data)

        {

            curl_close($ch);

            return $data;

        }

        else

        {

            $error = curl_errno($ch);

            echo "curl出错,错误码:$error"."<br>";

            echo "<a href=&#39;http://curl.haxx.se/libcurl/c/libcurl-errors.html&#39;>错误原因查询</a></br>";

            curl_close($ch);

            return false;

        }

    }

 

    /**

     *     作用:使用证书,以post方式提交xml到对应的接口url

     */

    function postXmlSSLCurl($xml,$url,$second=30)

    {

        $ch = curl_init();

        //超时时间

        curl_setopt($ch,CURLOPT_TIMEOUT,$second);

        //这里设置代理,如果有的话

        //curl_setopt($ch,CURLOPT_PROXY, &#39;8.8.8.8&#39;);

        //curl_setopt($ch,CURLOPT_PROXYPORT, 8080);

        curl_setopt($ch,CURLOPT_URL, $url);

        curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);

        curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);

        //设置header

        curl_setopt($ch,CURLOPT_HEADER,FALSE);

        //要求结果为字符串且输出到屏幕上

        curl_setopt($ch,CURLOPT_RETURNTRANSFER,TRUE);

        //设置证书

        //使用证书:cert 与 key 分别属于两个.pem文件

        //默认格式为PEM,可以注释

        curl_setopt($ch,CURLOPT_SSLCERTTYPE,&#39;PEM&#39;);

        curl_setopt($ch,CURLOPT_SSLCERT, dirname(__FILE__).WxPayConf_pub::SSLCERT_PATH);

        //默认格式为PEM,可以注释

        curl_setopt($ch,CURLOPT_SSLKEYTYPE,&#39;PEM&#39;);

        curl_setopt($ch,CURLOPT_SSLKEY, dirname(__FILE__).WxPayConf_pub::SSLKEY_PATH);

        //post提交方式

        curl_setopt($ch,CURLOPT_POST, true);

        curl_setopt($ch,CURLOPT_POSTFIELDS,$xml);

        $data = curl_exec($ch);

        //返回结果

        if($data){

            curl_close($ch);

            return $data;

        }

        else {

            $error = curl_errno($ch);

            echo "curl出错,错误码:$error"."<br>";

            echo "<a href=&#39;http://curl.haxx.se/libcurl/c/libcurl-errors.html&#39;>错误原因查询</a></br>";

            curl_close($ch);

            return false;

        }

    }

     

    /**

     *     作用:打印数组

     */

    function printErr($wording=&#39;&#39;,$err=&#39;&#39;)

    {

        print_r(&#39;<pre class="brush:php;toolbar:false">&#39;);

        echo $wording."</br>";

        var_dump($err);

        print_r(&#39;

'); } } /** * 请求型接口的基类 */ class Wxpay_client_pub extends Common_util_pub { var $parameters;//请求参数,类型为关联数组 public $response;//微信返回的响应 public $result;//返回参数,类型为关联数组 var $url;//接口链接 var $curl_timeout;//curl超时时间 /** * 作用:设置请求参数 */ function setParameter($parameter, $parameterValue) { $this->parameters[$this->trimString($parameter)] = $this->trimString($parameterValue); } /** * 作用:设置标配的请求参数,生成签名,生成接口参数xml */ function createXml() { $this->parameters["appid"] = WxPayConf_pub::APPID;//公众账号ID $this->parameters["mch_id"] = WxPayConf_pub::MCHID;//商户号 $this->parameters["nonce_str"] = $this->createNoncestr();//随机字符串 $this->parameters["sign"] = $this->getSign($this->parameters);//签名 return $this->arrayToXml($this->parameters); } /** * 作用:post请求xml */ function postXml() { $xml = $this->createXml(); $this->response = $this->postXmlCurl($xml,$this->url,$this->curl_timeout); return $this->response; } /** * 作用:使用证书post请求xml */ function postXmlSSL() { $xml = $this->createXml(); $this->response = $this->postXmlSSLCurl($xml,$this->url,$this->curl_timeout); return $this->response; } /** * 作用:获取结果,默认不使用证书 */ function getResult() { $this->postXml(); $this->result = $this->xmlToArray($this->response); return $this->result; } }

三、发起支付

在程序中,获得用户的授权码,并填入到$authcode参数中。授权码就是条码上的那一串18位纯数字,以10、11、12、13、14、15开头

其他参数则自动生成或者手动输入指定。

调用函数如下所示

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

//全局引入微信支付类

Vendor(&#39;Wxpay.WxPayPubHelper.WxPayPubHelper&#39;);

//使用统一支付接口

$microPay = new \MicroPay_pub();

//设置统一支付接口参数

$microPay->setParameter("body","方倍商户刷卡支付");//商品描述

$microPay->setParameter("out_trade_no", "$out_trade_no");//商户订单号

$microPay->setParameter("total_fee", $total_fee);//总金额 

$microPay->setParameter("auth_code", $authcode);//授权码

 

//获取统一支付接口结果

$microPayResult = $microPay->getResult();

 

//3. 异常判断

if (!isset($microPayResult["result_code"]) || ($microPayResult["result_code"] == "FAIL")) {

    $this->resRpcError(isset($microPayResult[&#39;result_code&#39;]) ? $microPayResult[&#39;err_code_des&#39;] : $microPayResult[&#39;return_msg&#39;], "21000");

}



版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:微信小程序中实现【回到顶部】按钮效果的方法展示
下一篇:微信小程序开发弹窗页面的方法详细介绍与解读
相关文章

 发表评论

暂时没有评论,来抢沙发吧~