WxRefund.php
6.6 KB
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
209
210
211
212
213
214
215
216
217
218
219
220
221
222
<?php
/**
* Created by PhpStorm.
* User: 29925
* Date: 2018/7/21
* Time: 11:39
*/
/*
* 微信退款
*/
class WxRefund {
protected $appid;
protected $mch_id;
protected $key;
protected $transaction_id;
protected $out_refund_no;
protected $total_fee;
protected $refund_fee;
protected $refund_desc;
function __construct($appid, $mch_id, $key, $transaction_id, $out_refund_no, $total_fee, $refund_fee, $refund_desc) {
$this->appid = $appid;
$this->mch_id = $mch_id;
$this->key = $key;
$this->transaction_id = $transaction_id;
$this->out_refund_no = $out_refund_no;
$this->total_fee = $total_fee;
$this->refund_fee = $refund_fee;
$this->refund_desc = $refund_desc;
}
public function pay() {
//微信退款
$return = $this->weixinrefund();
return $return;
}
//退款接口
private function refund() {
$url = 'https://api.mch.weixin.qq.com/secapi/pay/refund';
$parameters = array(
'appid' => $this->appid, //appID
'mch_id' => $this->mch_id, //商户号
'nonce_str' => $this->createNoncestr(), //随机字符串
'transaction_id' => $this->transaction_id,
// 'out_trade_no' => '2015450806125348', //商户订单号
'out_refund_no'=> $this->out_refund_no,
// 'total_fee' => floatval(0.01 * 100), //总金额 单位 分
'total_fee' => $this->total_fee,
'refund_fee' => $this->refund_fee,
'notify_url' => url('portal/Notify/notify', '', '', true), //通知地址 确保外网能正常访问
'refund_desc' => $this->refund_desc
);
//统一下单签名
$parameters['sign'] = $this->getSign($parameters);
$xmlData = $this->arrayToXmlT($parameters);
$return = $this->xmlToArray($this->postXmlCurl($xmlData, $url, 60,1));
return $return;
}
private static function postXmlCurl($xml, $url, $second = 30,$pem = null)
{
$ch = curl_init();
//设置超时
curl_setopt($ch, CURLOPT_TIMEOUT, $second);
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);
if($pem) {
//以下是证书相关代码
curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
curl_setopt($ch,CURLOPT_SSLCERT,VENDOR_PATH.'WxpayAPI/cert/apiclient_cert.pem');//绝对路径
curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
curl_setopt($ch,CURLOPT_SSLKEY,VENDOR_PATH.'WxpayAPI/cert/apiclient_key.pem');//绝对路径
}
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
curl_setopt($ch, CURLOPT_TIMEOUT, 40);
set_time_limit(0);
//运行curl
$data = curl_exec($ch);
//返回结果
if ($data) {
curl_close($ch);
return $data;
} else {
$error = curl_errno($ch);
curl_close($ch);
return $error;
// throw new WxPayException("curl出错,错误码:$error");
}
}
//数组转换成xml
private function arrayToXml($arr) {
$xml = "<root>";
foreach ($arr as $key => $val) {
if (is_array($val)) {
$xml .= "<" . $key . ">" . arrayToXml($val) . "</" . $key . ">";
} else {
$xml .= "<" . $key . ">" . $val . "</" . $key . ">";
}
}
$xml .= "</root>";
return $xml;
}
//数组转换成xml
private function arrayToXmlT($arr) {
$xml = "<xml>";
foreach ($arr as $key => $val) {
if (is_array($val)) {
$xml .= "<" . $key . ">" . arrayToXmlT($val) . "</" . $key . ">";
} else {
$xml .= "<" . $key . ">" . $val . "</" . $key . ">";
}
}
$xml .= "</xml>";
return $xml;
}
//xml转换成数组
private function xmlToArray($xml) {
//禁止引用外部xml实体
libxml_disable_entity_loader(true);
$xmlstring = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
$val = json_decode(json_encode($xmlstring), true);
return $val;
}
//微信接口
private function weixinrefund() {
//退款接口
$refund = $this->refund();
return $refund;
// print_r($unifiedorder);
$parameters = array(
'appId' => $this->appid, //小程序ID
'timeStamp' => '' . time() . '', //时间戳
'nonceStr' => $this->createNoncestr(), //随机串
'package' => 'prepay_id=' . $refund['prepay_id'], //数据包
'signType' => 'MD5'//签名方式
);
//签名
$parameters['paySign'] = $this->getSign($parameters);
return $parameters;
}
//作用:产生随机字符串,不长于32位
private 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;
}
//作用:生成签名
private function getSign($Obj) {
foreach ($Obj as $k => $v) {
$Parameters[$k] = $v;
}
//签名步骤一:按字典序排序参数
ksort($Parameters);
$String = $this->formatBizQueryParaMap($Parameters, false);
//签名步骤二:在string后加入KEY
$String = $String . "&key=" . $this->key;
//签名步骤三:MD5加密
$String = md5($String);
//签名步骤四:所有字符转为大写
$result_ = strtoupper($String);
return $result_;
}
///作用:格式化参数,签名过程需要使用
private function formatBizQueryParaMap($paraMap, $urlencode) {
$buff = "";
ksort($paraMap);
foreach ($paraMap as $k => $v) {
if ($urlencode) {
$v = urlencode($v);
}
$buff .= $k . "=" . $v . "&";
}
$reqPar = "";
if (strlen($buff) > 0) {
$reqPar = substr($buff, 0, strlen($buff) - 1);
}
return $reqPar;
}
}