Passed
Push — master ( c65cc4...4fcf9e )
by Wei
03:50
created

WechatPay::getMwebUrl()   A

Complexity

Conditions 5
Paths 16

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 5

Importance

Changes 0
Metric Value
cc 5
nc 16
nop 4
dl 0
loc 12
ccs 12
cts 12
cp 1
crap 5
rs 9.5555
c 0
b 0
f 0
1
<?php
2
/**
3
 * WechatPay
4
 *
5
 * @license MIT
6
 * @author zhangv
7
 */
8
namespace zhangv\wechat;
9
10
use \Exception;
11
use zhangv\wechat\cache\CacheProvider;
12
use zhangv\wechat\cache\JsonFileCacheProvider;
13
14
class WechatPay {
15
	const TRADETYPE_JSAPI = 'JSAPI',TRADETYPE_NATIVE = 'NATIVE',TRADETYPE_APP = 'APP',TRADETYPE_MWEB = 'MWEB';
16
	const SIGNTYPE_MD5 = 'MD5', SIGNTYPE_HMACSHA256 = 'HMAC-SHA256';
17
	const CHECKNAME_FORCECHECK = 'FORCE_CHECK',CHECKNAME_NOCHECK = 'NO_CHECK';
18
	const ACCOUNTTYPE_BASIC = 'Basic',ACCOUNTTYPE_OPERATION = 'Operation',ACCOUNTTYPE_FEES = 'Fees';
19
	const API_ENDPOINT = 'https://api.mch.weixin.qq.com/';
20
	/** 支付 */
21
	const URL_UNIFIEDORDER = 'pay/unifiedorder';
22
	const URL_ORDERQUERY = 'pay/orderquery';
23
	const URL_CLOSEORDER = 'pay/closeorder';
24
	const URL_REFUND = 'secapi/pay/refund';
25
	const URL_REFUNDQUERY = 'pay/refundquery';
26
	const URL_DOWNLOADBILL = 'pay/downloadbill';
27
	const URL_DOWNLOAD_FUND_FLOW = 'pay/downloadfundflow';
28
	const URL_REPORT = 'payitil/report';
29
	const URL_SHORTURL = 'tools/shorturl';
30
	const URL_MICROPAY = 'pay/micropay';
31
	const URL_BATCHQUERYCOMMENT = 'billcommentsp/batchquerycomment';
32
	const URL_REVERSE = 'secapi/pay/reverse';
33
	const URL_AUTHCODETOOPENID = 'tools/authcodetoopenid';
34
	/** 红包 */
35
	const URL_GETHBINFO = 'mmpaymkttransfers/gethbinfo';
36
	const URL_SENDREDPACK = 'mmpaymkttransfers/sendredpack';
37
	const URL_SENDGROUPREDPACK = 'mmpaymkttransfers/sendgroupredpack';
38
	/** 企业付款 */
39
	const URL_TRANSFER_WALLET = 'mmpaymkttransfers/promotion/transfers';
40
	const URL_QUERY_TRANSFER_WALLET = 'mmpaymkttransfers/gettransferinfo';
41
	const URL_TRANSFER_BANKCARD = 'mmpaysptrans/pay_bank';
42
	const URL_QUERY_TRANSFER_BANKCARD = 'mmpaysptrans/query_bank';
43
	/** 代金券 */
44
	const URL_SEND_COUPON = 'mmpaymkttransfers/send_coupon';
45
	const URL_QUERY_COUPON_STOCK = 'mmpaymkttransfers/query_coupon_stock';
46
	const URL_QUERY_COUPON_INFO = 'mmpaymkttransfers/querycouponsinfo';
47
	/** Sandbox获取测试公钥 */
48
	const URL_GETPUBLICKEY = 'https://fraud.mch.weixin.qq.com/risk/getpublickey';
49
	public static $BANKCODE = ['工商银行' => '1002', '农业银行' => '1005', '中国银行' => '1026', '建设银行' => '1003', '招商银行' => '1001',
50
		'邮储银行' => '1066', '交通银行' => '1020', '浦发银行' => '1004', '民生银行' => '1006', '兴业银行' => '1009', '平安银行' => '1010',
51
		'中信银行' => '1021', '华夏银行' => '1025', '广发银行' => '1027', '光大银行' => '1022', '北京银行' => '1032', '宁波银行' => '1056',];
52
53
	public $getSignKeyUrl = "sandboxnew/pay/getsignkey";
54
	public $sandbox = false;
55
56
	/** @var string */
57
	public $returnCode;
58
	/** @var string */
59
	public $returnMsg;
60
	/** @var string */
61
	public $resultCode;
62
	/** @var string */
63
	public $errCode;
64
	/** @var string */
65
	public $errCodeDes;
66
	/** @var string */
67
	public $requestXML = null;
68
	/** @var string */
69
	public $responseXML = null;
70
	/** @var array */
71
	public $requestArray = null;
72
	/** @var array */
73
	public $responseArray = null;
74
	/** @var array */
75
	private $config;
76
	/** @var HttpClient */
77
	private $httpClient = null;
78
	/** @var WechatOAuth */
79
	private $wechatOAuth = null;
80
	/** @var string */
81
	public $publicKey = null;
82
	/** @var CacheProvider */
83
	public $cacheProvider = null;
84
85
	/**
86
	 * @param $config array 配置
87
	 */
88 51
	public function __construct(array $config) {
89 51
		$this->config = $config;
90 51
		$this->httpClient = new HttpClient(5);
91 51
		$this->cacheProvider = new JsonFileCacheProvider();
92 51
	}
93
94 1
	public function setWechatOAuth($wechatOAuth){
95 1
		$this->wechatOAuth = $wechatOAuth;
96 1
	}
97
98 1
	public function getWechatOAuth(){
99 1
		if(!$this->wechatOAuth){
100 1
			$this->wechatOAuth = new WechatOAuth($this->config['app_id'],$this->config['app_secret']);
101
		}
102 1
		return $this->wechatOAuth;
103
	}
104
105 1
	public function setConfig($config){
106 1
		$this->config = $config;
107 1
	}
108
109 3
	public function getConfig(){
110 3
		return $this->config;
111
	}
112
113 38
	public function setHttpClient($httpClient){
114 38
		$this->httpClient = $httpClient;
115 38
	}
116
117 51
	public function setCacheProvider($cacheProvider){
118 51
		$this->cacheProvider = $cacheProvider;
119 51
	}
120
121 1
	public function getCacheProvider(){
122 1
		return $this->cacheProvider;
123
	}
124
125
	/**
126
	 * 获取JSAPI(公众号/小程序)的预支付单信息(prepay_id)
127
	 * @ref https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
128
	 * @param $body string 内容
129
	 * @param $out_trade_no string 商户订单号
130
	 * @param $total_fee int 总金额
131
	 * @param $openid string openid
132
	 * @param $spbill_create_ip
133
	 * @param $ext array
134
	 * @return string
135
	 * @throws \Exception
136
	 */
137 4
	public function getPrepayId($body,$out_trade_no,$total_fee,$openid,$spbill_create_ip = null,$ext = null) {
138 4
		$data = ($ext && is_array($ext))?$ext:array();
139 4
		$data["body"]         = $body;
140 4
		$data["out_trade_no"] = $out_trade_no;
141 4
		$data["total_fee"]    = $total_fee;
142 4
		$data["spbill_create_ip"] = $spbill_create_ip?:$_SERVER["REMOTE_ADDR"];
143 4
		$data["notify_url"]   = $this->config["notify_url"];
144 4
		$data["trade_type"]   = WechatPay::TRADETYPE_JSAPI;
145 4
		if(!$openid) throw new Exception('openid is required when trade_type is JSAPI');
146 4
		$data["openid"]   = $openid;
147 4
		$result = $this->unifiedOrder($data);
148 1
		return $result["prepay_id"];
149
	}
150
151
	/**
152
	 * 获取APP的的预支付单信息(prepay_id)(注意这里的appid是从开放平台申请的)
153
	 * @ref https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1
154
	 * @param $body string 内容
155
	 * @param $out_trade_no string 商户订单号
156
	 * @param $total_fee int 总金额
157
	 * @param $spbill_create_ip string 终端ID
158
	 * @param $ext array
159
	 * @return string
160
	 */
161 1
	public function getPrepayIdAPP($body,$out_trade_no,$total_fee,$spbill_create_ip,$ext = null) {
162 1
		$data = ($ext && is_array($ext))?$ext:array();
163 1
		$data["body"]         = $body;
164 1
		$data["out_trade_no"] = $out_trade_no;
165 1
		$data["total_fee"]    = $total_fee;
166 1
		$data["spbill_create_ip"] = $spbill_create_ip;
167 1
		$data["notify_url"]   = $this->config["notify_url"];
168 1
		$data["trade_type"]   = WechatPay::TRADETYPE_APP;
169 1
		$result = $this->unifiedOrder($data);
170 1
		return $result["prepay_id"];
171
	}
172
173
	/**
174
	 * 扫码支付(模式二)获取支付二维码
175
	 * @ref https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1
176
	 * @param $body
177
	 * @param $out_trade_no
178
	 * @param $total_fee
179
	 * @param $product_id
180
	 * @param $spbill_create_ip string 本地IP
181
	 * @param $ext array
182
	 * @return string
183
	 * @throws Exception
184
	 */
185 1
	public function getCodeUrl($body,$out_trade_no,$total_fee,$product_id,$spbill_create_ip = null,$ext = null){
186 1
		$data = ($ext && is_array($ext))?$ext:array();
187 1
		$data["body"]         = $body;
188 1
		$data["out_trade_no"] = $out_trade_no;
189 1
		$data["total_fee"]    = $total_fee;
190 1
		$data["spbill_create_ip"] = $spbill_create_ip?:$_SERVER["SERVER_ADDR"];
191 1
		$data["notify_url"]   = $this->config["notify_url"];
192 1
		$data["trade_type"]   = self::TRADETYPE_NATIVE;
193 1
		if(!$product_id) throw new Exception('product_id is required when trade_type is NATIVE');
194 1
		$data["product_id"]   = $product_id;
195 1
		$result = $this->unifiedOrder($data);
196 1
		return $result["code_url"];
197
	}
198
199
	/**
200
	 * H5支付获取支付跳转链接
201
	 * @ref https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_20&index=1
202
	 * @param $body string 商品描述
203
	 * @param $out_trade_no string 商户订单号
204
	 * @param $total_fee int 总金额(分)
205
	 * @param $ext array
206
	 * @return string
207
	 * @throws Exception
208
	 */
209 1
	public function getMwebUrl($body,$out_trade_no,$total_fee,$ext = null){
210 1
		$data = ($ext && is_array($ext))?$ext:array();
211 1
		$data["body"]         = $body;
212 1
		$data["out_trade_no"] = $out_trade_no;
213 1
		$data["total_fee"]    = $total_fee;
214 1
		$data["spbill_create_ip"] = isset($_SERVER["REMOTE_ADDR"])?$_SERVER["REMOTE_ADDR"]:'';
215 1
		$data["notify_url"]   = $this->config["notify_url"];
216 1
		$data["trade_type"]   = self::TRADETYPE_MWEB;
217 1
		if(!isset($this->config['h5_scene_info'])) throw new Exception('h5_scene_info should be configured');
218 1
		$data["scene_info"]   = json_encode($this->config['h5_scene_info']);
219 1
		$result = $this->unifiedOrder($data);
220 1
		return $result["mweb_url"];
221
	}
222
223
	/**
224
	 * 统一下单接口
225
	 * @ref https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
226
	 * @param array $params
227
	 * @throws Exception
228
	 * @return string JSON
229
	 */
230 7
	public function unifiedOrder($params) {
231 7
		$data = array();
232 7
		$data["appid"] = $this->config["app_id"];
233 7
		$data["device_info"] = (isset($params['device_info'])&&trim($params['device_info'])!='')?$params['device_info']:null;
234 7
		$data["body"] = $params['body'];
235 7
		$data["detail"] = isset($params['detail'])?$params['detail']:null;//optional
236 7
		$data["attach"] = isset($params['attach'])?$params['attach']:null;//optional
237 7
		$data["out_trade_no"] = isset($params['out_trade_no'])?$params['out_trade_no']:null;
238 7
		$data["fee_type"] = isset($params['fee_type'])?$params['fee_type']:'CNY';
239 7
		$data["total_fee"]    = $params['total_fee'];
240 7
		$data["spbill_create_ip"] = $params['spbill_create_ip'];
241 7
		$data["time_start"] = isset($params['time_start'])?$params['time_start']:null;//optional
242 7
		$data["time_expire"] = isset($params['time_expire'])?$params['time_expire']:null;//optional
243 7
		$data["goods_tag"] = isset($params['goods_tag'])?$params['goods_tag']:null;
244 7
		$data["notify_url"] = $this->config["notify_url"];
245 7
		$data["trade_type"] = $params['trade_type'];
246 7
		if($params['trade_type'] == WechatPay::TRADETYPE_NATIVE){
247 1
			if(!isset($params['product_id'])) throw new Exception('product_id is required when trade_type is NATIVE');
248 1
			$data["product_id"] = $params['product_id'];
249
		}
250 7
		if($params['trade_type'] == WechatPay::TRADETYPE_JSAPI){
251 4
			if(!isset($params['openid'])) throw new Exception('openid is required when trade_type is JSAPI');
252 4
			$data["openid"] = $params['openid'];
253
		}
254 7
		$result = $this->post(self::URL_UNIFIEDORDER, $data);
255 4
		return $result;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $result also could return the type array which is incompatible with the documented return type string.
Loading history...
256
	}
257
258
	/**
259
	 * 查询订单(根据微信订单号)
260
	 * @ref  https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_2
261
	 * @param $transaction_id string 微信订单号
262
	 * @return array
263
	 */
264 2
	public function queryOrderByTransactionId($transaction_id){
265 2
		$data = array();
266 2
		$data["appid"] = $this->config["app_id"];
267 2
		$data["transaction_id"] = $transaction_id;
268 2
		$result = $this->post(self::URL_ORDERQUERY, $data);
269 1
		return $result;
270
	}
271
272
	/**
273
	 * 查询订单(根据商户订单号)
274
	 * @ref  https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_2
275
	 * @param $out_trade_no string 商户订单号
276
	 * @return array
277
	 */
278 1
	public function queryOrderByOutTradeNo($out_trade_no){
279 1
		$data = array();
280 1
		$data["appid"] = $this->config["app_id"];
281 1
		$data["out_trade_no"] = $out_trade_no;
282 1
		$result = $this->post(self::URL_ORDERQUERY, $data);
283 1
		return $result;
284
	}
285
286
	/**
287
	 * 查询退款(根据微信订单号)
288
	 * @ref  https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_5
289
	 * @param $transaction_id string 微信交易号
290
	 * @param $offset int 偏移
291
	 * @return array
292
	 */
293 1
	public function queryRefundByTransactionId($transaction_id,$offset = 0){
294 1
		$data = array();
295 1
		$data["appid"] = $this->config["app_id"];
296 1
		$data["transaction_id"] = $transaction_id;
297 1
		$data["offset"] = $offset;
298 1
		$result = $this->post(self::URL_REFUNDQUERY, $data);
299 1
		return $result;
300
	}
301
302
	/**
303
	 * 查询退款(根据商户订单号)
304
	 * @ref  https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_5
305
	 * @param $out_trade_no string 商户交易号
306
	 * @param $offset int 偏移
307
	 * @return array
308
	 */
309 1
	public function queryRefundByOutTradeNo($out_trade_no,$offset = 0){
310 1
		$data = array();
311 1
		$data["appid"] = $this->config["app_id"];
312 1
		$data["out_trade_no"] = $out_trade_no;
313 1
		$data["offset"] = $offset;
314 1
		$result = $this->post(self::URL_REFUNDQUERY, $data);
315 1
		return $result;
316
	}
317
318
	/**
319
	 * 查询退款(根据微信退款单号)
320
	 * @ref  https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_5
321
	 * @param $refund_id string 微信退款单号
322
	 * @param $offset int 偏移
323
	 * @return array
324
	 */
325 1
	public function queryRefundByRefundId($refund_id,$offset = 0){
326 1
		$data = array();
327 1
		$data["appid"] = $this->config["app_id"];
328 1
		$data["refund_id"] = $refund_id;
329 1
		$data["offset"] = $offset;
330 1
		$result = $this->post(self::URL_REFUNDQUERY, $data);
331 1
		return $result;
332
	}
333
334
	/**
335
	 * 查询退款(根据商户退款单号)
336
	 * @ref  https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_5
337
	 * @param $out_refund_no string 商户退款单号
338
	 * @param $offset int 偏移
339
	 * @return array
340
	 */
341 1
	public function queryRefundByOutRefundNo($out_refund_no,$offset = 0){
342 1
		$data = array();
343 1
		$data["appid"] = $this->config["app_id"];
344 1
		$data["out_refund_no"] = $out_refund_no;
345 1
		$data["offset"] = $offset;
346 1
		$result = $this->post(self::URL_REFUNDQUERY, $data);
347 1
		return $result;
348
	}
349
350
	/**
351
	 * 关闭订单
352
	 * @ref  https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_3
353
	 * @param $out_trade_no string 商户订单号
354
	 * @return array
355
	 */
356 1
	public function closeOrder($out_trade_no){
357 1
		$data = array();
358 1
		$data["appid"] = $this->config["app_id"];
359 1
		$data["out_trade_no"] = $out_trade_no;
360 1
		$result = $this->post(self::URL_CLOSEORDER, $data,false);
361 1
		return $result;
362
	}
363
364
	/**
365
	 * 申请退款 - 使用商户订单号
366
	 * @ref  https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_4
367
	 * @ref  https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
368
	 * @param $out_trade_no string 商户订单号
369
	 * @param $out_refund_no string 商户退款单号
370
	 * @param $total_fee int 总金额(单位:分)
371
	 * @param $refund_fee int 退款金额(单位:分)
372
	 * @param $ext array 扩展数组
373
	 * @return array
374
	 */
375 1
	public function refundByOutTradeNo($out_trade_no,$out_refund_no,$total_fee,$refund_fee,$ext = array()){
376 1
		$data = ($ext && is_array($ext))?$ext:array();
377 1
		$data["appid"] = $this->config["app_id"];
378 1
		$data["out_trade_no"] = $out_trade_no;
379 1
		$data["out_refund_no"] = $out_refund_no;
380 1
		$data["total_fee"] = $total_fee;
381 1
		$data["refund_fee"] = $refund_fee;
382 1
		$result = $this->post(self::URL_REFUND, $data,true);
383 1
		return $result;
384
	}
385
386
	/**
387
	 * 申请退款 - 使用微信订单号
388
	 * @ref  https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_4
389
	 * @ref  https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
390
	 * @param $transaction_id string 微信订单号
391
	 * @param $out_refund_no string 商户退款单号
392
	 * @param $total_fee int 总金额(单位:分)
393
	 * @param $refund_fee int 退款金额(单位:分)
394
	 * @param $ext array 扩展数组
395
	 * @return array
396
	 */
397 1
	public function refundByTransactionId($transaction_id,$out_refund_no,$total_fee,$refund_fee,$ext = array()){
398 1
		$data = ($ext && is_array($ext))?$ext:array();
399 1
		$data["appid"] = $this->config["app_id"];
400 1
		$data["transaction_id"] = $transaction_id;
401 1
		$data["out_refund_no"] = $out_refund_no;
402 1
		$data["total_fee"] = $total_fee;
403 1
		$data["refund_fee"] = $refund_fee;
404 1
		$result = $this->post(self::URL_REFUND, $data,true);
405 1
		return $result;
406
	}
407
408
	/**
409
	 * 撤销订单 - 使用商户订单号
410
	 * @ref  https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_11&index=3
411
	 * @param $out_trade_no string 商户订单号
412
	 * @return array
413
	 */
414 1
	public function reverseByOutTradeNo($out_trade_no){
415 1
		$data = array();
416 1
		$data["appid"] = $this->config["app_id"];
417 1
		$data["out_trade_no"] = $out_trade_no;
418 1
		$result = $this->post(self::URL_REVERSE, $data,true);
419 1
		return $result;
420
	}
421
422
	/**
423
	 * 撤销订单 - 使用微信订单号
424
	 * @ref  https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_11&index=3
425
	 * @param $transaction_id string 微信订单号
426
	 * @return array
427
	 */
428 1
	public function reverseByTransactionId($transaction_id){
429 1
		$data = array();
430 1
		$data["appid"] = $this->config["app_id"];
431 1
		$data["transaction_id"] = $transaction_id;
432 1
		$result = $this->post(self::URL_REVERSE, $data,true);
433 1
		return $result;
434
	}
435
436
	/**
437
	 * 下载对账单
438
	 * @ref https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_6
439
	 * @param $bill_date string 下载对账单的日期,格式:20140603
440
	 * @param $bill_type string 类型 ALL|SUCCESS
441
	 * @return array
442
	 */
443 1
	public function downloadBill($bill_date,$bill_type = 'ALL'){
444 1
		$data = array();
445 1
		$data["appid"] = $this->config["app_id"];
446 1
		$data["bill_date"] = $bill_date;
447 1
		$data["bill_type"] = $bill_type;
448 1
		$result = $this->post(self::URL_DOWNLOADBILL, $data);
449 1
		return $result;
450
	}
451
452
	/**
453
	 * 下载资金账单
454
	 * @ref https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_18&index=7
455
	 * @param $bill_date string 资金账单日期,格式:20140603
456
	 * @param $account_type string 资金账户类型 Basic|Operation|Fees
457
	 * @param $tar_type string 压缩账单
458
	 * @return array
459
	 */
460 1
	public function downloadFundFlow($bill_date,$account_type = self::ACCOUNTTYPE_BASIC,$tar_type = 'GZIP'){
461 1
		$data = array();
462 1
		$data["appid"] = $this->config["app_id"];
463 1
		$data["bill_date"] = $bill_date;
464 1
		$data["account_type"] = $account_type;
465 1
		$data["tar_type"] = $tar_type;
466 1
		$result = $this->post(self::URL_DOWNLOAD_FUND_FLOW, $data);
467 1
		return $result;
468
	}
469
470
	/**
471
	 * 发放普通红包
472
	 * @ref https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_4&index=3
473
	 * @param $mch_billno string 商户订单号
474
	 * @param $send_name string 商户名称
475
	 * @param $re_openid string 用户openid
476
	 * @param $total_amount int 付款金额 单位分
477
	 * @param $total_num int 红包发放总人数
478
	 * @param $wishing string 红包祝福语
479
	 * @param $act_name string 活动名称
480
	 * @param $remark string 备注
481
	 * @param $scene_id string 场景id,发放红包使用场景,红包金额大于200时必传 PRODUCT_1:商品促销 PRODUCT_2:抽奖 PRODUCT_3:虚拟物品兑奖 PRODUCT_4:企业内部福利 PRODUCT_5:渠道分润 PRODUCT_6:保险回馈 PRODUCT_7:彩票派奖 PRODUCT_8:税务刮奖
482
	 * @param $riskinfo string 活动信息
483
	 * @param $consume_mch_id string 资金授权商户号
484
	 * @return array
485
	 * @throws Exception
486
	 */
487 2
	public function sendRedPack($mch_billno,$send_name,$re_openid,$total_amount,$total_num,$wishing,$act_name,$remark,$scene_id = '',$riskinfo = '',$consume_mch_id = ''){
488 2
		$data = array();
489 2
		$data["wxappid"] = $this->config["app_id"];
490 2
		$data["mch_billno"] = $mch_billno;
491 2
		$data["send_name"] = $send_name;
492 2
		$data["re_openid"] = $re_openid;
493 2
		$data["total_amount"] = $total_amount;
494 2
		if($total_amount > 20000 && trim($scene_id)=='') throw new Exception("scene_id is required when total_amount beyond 20000");
495 2
		$data["total_num"] = $total_num;
496 2
		$data["wishing"] = $wishing;
497 2
		$data["act_name"] = $act_name;
498 2
		$data["remark"] = $remark;
499 2
		$data["scene_id"] = $scene_id;
500 2
		$data["riskinfo"] = $riskinfo;
501 2
		$data["consume_mch_id"] = $consume_mch_id;
502 2
		$result = $this->post(self::URL_SENDREDPACK, $data, true); //cert is required
503 1
		return $result;
504
	}
505
506
	/**
507
	 * 发放裂变红包
508
	 * @ref https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_5&index=4
509
	 * @param $mch_billno string 商户订单号
510
	 * @param $send_name string 商户名称
511
	 * @param $re_openid string 用户openid
512
	 * @param $total_amount int 付款金额 单位分
513
	 * @param $total_num int 红包发放总人数
514
	 * @param $wishing string 红包祝福语
515
	 * @param $act_name string 活动名称
516
	 * @param $remark string 备注
517
	 * @param $scene_id string 场景id,发放红包使用场景,红包金额大于200时必传 PRODUCT_1:商品促销 PRODUCT_2:抽奖 PRODUCT_3:虚拟物品兑奖 PRODUCT_4:企业内部福利 PRODUCT_5:渠道分润 PRODUCT_6:保险回馈 PRODUCT_7:彩票派奖 PRODUCT_8:税务刮奖
518
	 * @param $riskinfo string 活动信息
519
	 * @param $consume_mch_id string 资金授权商户号
520
	 * @return array
521
	 * @throws Exception
522
	 */
523 2
	public function sendGroupRedPack($mch_billno,$send_name,$re_openid,$total_amount,$total_num,$wishing,$act_name,$remark,$scene_id = '',$riskinfo = '',$consume_mch_id = ''){
524 2
		$data = array();
525 2
		$data["wxappid"] = $this->config["app_id"];//NOTE: WXappid
526 2
		$data["mch_billno"] = $mch_billno;
527 2
		$data["send_name"] = $send_name;
528 2
		$data["re_openid"] = $re_openid;
529 2
		$data["total_amount"] = $total_amount;
530 2
		if($total_amount > 20000 && trim($scene_id)=='') throw new Exception("scene_id is required when total_amount beyond 20000(200rmb)");
531 2
		$data["total_num"] = $total_num;
532 2
		$data["amt_type"] = 'ALL_RAND'; //红包金额设置方式 ALL_RAND—全部随机
533 2
		$data["wishing"] = $wishing;
534 2
		$data["act_name"] = $act_name;
535 2
		$data["remark"] = $remark;
536 2
		$data["scene_id"] = $scene_id;
537 2
		$data["riskinfo"] = $riskinfo;
538 2
		$data["consume_mch_id"] = $consume_mch_id;
539 2
		$result = $this->post(self::URL_SENDGROUPREDPACK, $data, true); //cert is required
540 1
		return $result;
541
	}
542
543
	/**
544
	 * 查询红包记录
545
	 * @param $mch_billno string 商户订单号
546
	 * @return array
547
	 * @throws Exception
548
	 * @ref https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_6&index=5
549
	 */
550 2
	public function getHbInfo($mch_billno){
551 2
		$data = array();
552 2
		$data["mch_billno"] = $mch_billno;
553 2
		$data["appid"] = $this->config["app_id"];
554 2
		$data["bill_type"] = 'MCHT'; //MCHT:通过商户订单号获取红包信息。
555 2
		$result = $this->post(self::URL_GETHBINFO, $data, true); //cert is required
556 1
		return $result;
557
	}
558
559
	/**
560
	 * 拉取订单评价数据
561
	 * @ref https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_17&index=11
562
	 * @param string $begin_time 开始时间,格式为yyyyMMddHHmmss
563
	 * @param string $end_time 结束时间,格式为yyyyMMddHHmmss
564
	 * @param int $offset 偏移
565
	 * @param int $limit 条数
566
	 * @return array
567
	 */
568 1
	public function batchQueryComment($begin_time,$end_time,$offset = 0,$limit = 200){
569 1
		$data = array();
570 1
		$data["appid"] = $this->config["app_id"];
571 1
		$data["begin_time"] = $begin_time;
572 1
		$data["end_time"] = $end_time;
573 1
		$data["offset"] = $offset;
574 1
		$data["limit"] = $limit;
575 1
		$data["sign"] = $this->sign($data,WechatPay::SIGNTYPE_HMACSHA256);
576 1
		$result = $this->post(self::URL_BATCHQUERYCOMMENT, $data, true); //cert is required
577 1
		return $result;
578
	}
579
580
	/**
581
	 * 获取支付参数(JSAPI - 公众号/小程序支付 , APP - APP支付)
582
	 * @param $prepay_id string 预支付ID
583
	 * @param $trade_type string 支付类型
584
	 * @return array
585
	 */
586 1
	public function getPackage($prepay_id, $trade_type = WechatPay::TRADETYPE_JSAPI) {
587 1
		$data = array();
588 1
		if ($trade_type == WechatPay::TRADETYPE_JSAPI){
589 1
			$data["package"]   = "prepay_id=$prepay_id";
590 1
			$data["timeStamp"] = time();
591 1
			$data["nonceStr"]  = $this->getNonceStr();
592 1
			$data["appId"] = $this->config["app_id"];
593 1
			$data["signType"]  = "MD5";
594 1
			$data["paySign"]   = $this->sign($data);
595 1
		} else if ($trade_type == WechatPay::TRADETYPE_APP){
596 1
			$data["package"]   = "Sign=WXPay";
597 1
			$data['prepayid'] = $prepay_id;
598 1
			$data['partnerid'] = $this->config["mch_id"];
599 1
			$data["timestamp"] = time();
600 1
			$data["noncestr"]  = $this->getNonceStr();
601 1
			$data["appid"] = $this->config["app_id"];
602 1
			$data["sign"]   = $this->sign($data);
603
		}
604 1
		return $data;
605
	}
606
607
	/**
608
	 * 提交刷卡支付
609
	 * @ref https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_10&index=1
610
	 * @param $body
611
	 * @param $out_trade_no
612
	 * @param $total_fee
613
	 * @param $spbill_create_ip
614
	 * @param $auth_code
615
	 * @param array $ext
616
	 * @return array
617
	 */
618 1
	public function microPay($body,$out_trade_no,$total_fee,$spbill_create_ip,$auth_code,$ext = array()){
619 1
		$data = (!empty($ext) && is_array($ext))?$ext:array();
620 1
		$data["appid"] = $this->config["app_id"];
621 1
		$data["body"]         = $body;
622 1
		$data["out_trade_no"] = $out_trade_no;
623 1
		$data["total_fee"]    = $total_fee;
624 1
		$data["spbill_create_ip"] = $spbill_create_ip;
625 1
		$data["auth_code"] = $auth_code;
626 1
		$result = $this->post(self::URL_MICROPAY,$data,false);
627 1
		return $result;
628
	}
629
630
	/**
631
	 * 支付结果通知处理
632
	 * @param $notify_data array|string 通知数据
633
	 * @param $callback callable 回调
634
	 * @return null
635
	 * @throws Exception
636
	 */
637 2
	public function onPaidNotify($notify_data,callable $callback = null){
638 2
		if(!is_array($notify_data)) $notify_data = $this->xml2array($notify_data);
639 2
		if(!$this->validateSign($notify_data)) throw new Exception('Invalid paid notify data');
640 1
		if($callback && is_callable($callback)){
641 1
			return call_user_func_array( $callback , [$notify_data] );
642
		}
643
	}
644
645
	/**
646
	 * 退款结果通知处理
647
	 * @param string|array $notify_data 通知数据(XML/array)
648
	 * @param callable $callback 回调
649
	 * @return mixed
650
	 * @throws Exception
651
	 */
652 2
	public function onRefundedNotify($notify_data,callable $callback = null){
653 2
		if(!is_array($notify_data)) $notify_data = $this->xml2array($notify_data);
654 2
		if(!$this->validateSign($notify_data)) throw new Exception('Invalid refund notify data');
655 1
		if($callback && is_callable($callback)){
656 1
			return call_user_func_array( $callback ,[$notify_data] );
657
		}
658
	}
659
660
	/**
661
	 * 验证数据签名
662
	 * @param $data array 数据数组
663
	 * @return boolean 数据校验结果
664
	 */
665 5
	public function validateSign($data) {
666 5
		if (!isset($data["sign"])) {
667 1
			return false;
668
		}
669 4
		$sign = $data["sign"];
670 4
		unset($data["sign"]);
671 4
		return $this->sign($data) == $sign;
672
	}
673
674
	/**
675
	 * 响应微信支付后台通知
676
	 * @param array $data
677
	 * @param string $return_code 返回状态码 SUCCESS/FAIL
678
	 * @param string $return_msg  返回信息
679
	 * @param bool $print
680
	 * @return string
681
	 */
682 1
	public function responseNotify($print = true,$data = [],$return_code="SUCCESS", $return_msg= 'OK') {
683 1
		$data["return_code"] = $return_code;
684 1
		if ($return_msg) {
685 1
			$data["return_msg"] = $return_msg;
686
		}
687 1
		$xml = $this->array2xml($data);
688 1
		if($print === true) print $xml;
689 1
		else return $xml;
690
	}
691
692
	/**
693
	 * 交易保障
694
	 * @ref https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_8&index=8
695
	 * @param string $interface_url
696
	 * @param string $execution_time
697
	 * @param string $return_code
698
	 * @param string $result_code
699
	 * @param string $user_ip
700
	 * @param string $out_trade_no
701
	 * @param string $time
702
	 * @param string $device_info
703
	 * @param string $return_msg
704
	 * @param string $err_code
705
	 * @param string $err_code_des
706
	 * @return array
707
	 */
708 1
	public function report($interface_url,$execution_time,$return_code,$result_code,$user_ip,$out_trade_no = null,$time = null,$device_info = null,
709
	                       $return_msg = null,$err_code = null,$err_code_des = null){
710 1
		$data = array();
711 1
		$data["appid"] = $this->config["app_id"];
712 1
		$data["interface_url"] = $interface_url;
713 1
		$data["execution_time"] = $execution_time;
714 1
		$data["return_code"] = $return_code;
715 1
		$data["result_code"] = $result_code;
716 1
		$data["user_ip"] = $user_ip;
717 1
		if($out_trade_no) $data["out_trade_no"] = $out_trade_no;
718 1
		if($time) $data["time"] = $time;
719 1
		if($device_info) $data["device_info"] = $device_info;
720 1
		if($return_msg) $data["return_msg"] = $return_msg;
721 1
		if($err_code) $data["err_code"] = $err_code;
722 1
		if($err_code_des) $data["err_code_des"] = $err_code_des;
723 1
		return $this->post(self::URL_REPORT, $data, false);
724
	}
725
726
	/**
727
	 * 转换短链接
728
	 * @ref https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_9&index=8
729
	 * @param $longurl
730
	 * @return string
731
	 */
732 1
	public function shortUrl($longurl){
733 1
		$data = array();
734 1
		$data["appid"] = $this->config["app_id"];
735 1
		$data["long_url"] = $longurl;
736 1
		$result = $this->post(self::URL_SHORTURL,$data,false);
737 1
		return $result['short_url'];
738
	}
739
740
	/**
741
	 * 授权码查询openid
742
	 * @ref https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_13&index=10
743
	 * @param $auth_code
744
	 * @return mixed
745
	 */
746 1
	public function authCodeToOpenId($auth_code){
747 1
		$data = array();
748 1
		$data["appid"] = $this->config["app_id"];
749 1
		$data["auth_code"] = $auth_code;
750 1
		$result = $this->post(self::URL_AUTHCODETOOPENID,$data,false);
751 1
		return $result['openid'];
752
	}
753
754
	/**
755
	 * 企业付款到零钱
756
	 * @ref https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2
757
	 * @param $partner_trade_no
758
	 * @param $openid
759
	 * @param $amount
760
	 * @param $desc
761
	 * @param $spbill_create_ip
762
	 * @param $check_name
763
	 * @param $re_user_name
764
	 * @return array
765
	 * @throws Exception
766
	 */
767 2
	public function transferWallet($partner_trade_no,$openid,$amount,$desc,$spbill_create_ip = null,$re_user_name = null,$check_name = WechatPay::CHECKNAME_FORCECHECK){
768 2
		$data = array();
769 2
		if($check_name == WechatPay::CHECKNAME_FORCECHECK && !$re_user_name) throw new Exception('Real name is required');
770 2
		$data["mch_appid"] = $this->config["app_id"];
771 2
		$data["mchid"] = $this->config["mch_id"];
772 2
		$data["partner_trade_no"] = $partner_trade_no;
773 2
		$data["openid"] = $openid;
774 2
		$data["amount"] = $amount;
775 2
		$data["desc"] = $desc;
776 2
		$data['spbill_create_ip'] = $spbill_create_ip?:$_SERVER['SERVER_ADDR'];
777 2
		$data["check_name"] = $check_name;
778 2
		$data["re_user_name"] = $re_user_name;
779 2
		$result = $this->post(self::URL_TRANSFER_WALLET,$data,true);
780 1
		return $result;
781
	}
782
783
	/**
784
	 * 查询企业付款
785
	 * @ref https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_3
786
	 * @param $partner_trade_no
787
	 * @return array
788
	 */
789 1
	public function queryTransferWallet($partner_trade_no){
790 1
		$data = array();
791 1
		$data["appid"] = $this->config["app_id"];
792 1
		$data["mch_id"] = $this->config["mch_id"];
793 1
		$data["partner_trade_no"] = $partner_trade_no;
794 1
		$result = $this->post(self::URL_QUERY_TRANSFER_WALLET,$data,true);
795 1
		return $result;
796
	}
797
798
	/**
799
	 * 企业付款到银行卡
800
	 * @ref https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=24_2
801
	 * @param $partner_trade_no
802
	 * @param $bank_no
803
	 * @param $true_name
804
	 * @param $bank_code
805
	 * @param $amount
806
	 * @param $desc
807
	 * @return array
808
	 * @throws Exception
809
	 */
810 2
	public function transferBankCard($partner_trade_no,$bank_no,$true_name,$bank_code,$amount,$desc){
811 2
		if(!in_array($bank_code,array_values(self::$BANKCODE))) throw new Exception("Unsupported bank code: $bank_code");
812 2
		$data = array();
813 2
		$data["partner_trade_no"] = $partner_trade_no;
814 2
		$enc_bank_no = $this->rsaEncrypt($bank_no);
815 1
		$data["enc_bank_no"] = $enc_bank_no;
816 1
		$enc_true_name = $this->rsaEncrypt($true_name);
817 1
		$data["enc_true_name"] = $enc_true_name;
818 1
		$data["bank_code"] = $bank_code;
819 1
		$data["desc"] = $desc;
820 1
		$data["amount"] = $amount;
821 1
		$result = $this->post(self::URL_TRANSFER_BANKCARD,$data,true);
822 1
		return $result;
823
	}
824
825
	/**
826
	 * 查询企业付款银行卡
827
	 * @ref https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=24_3
828
	 * @param $partner_trade_no
829
	 * @return array
830
	 */
831 1
	public function queryTransferBankCard($partner_trade_no){
832 1
		$data = array();
833 1
		$data["appid"] = $this->config["app_id"];
834 1
		$data["mch_id"] = $this->config["mch_id"];
835 1
		$data["partner_trade_no"] = $partner_trade_no;
836 1
		$result = $this->post(self::URL_QUERY_TRANSFER_WALLET,$data,true);
837 1
		return $result;
838
	}
839
840
	/**
841
	 * 发放代金券
842
	 * @ref https://pay.weixin.qq.com/wiki/doc/api/tools/sp_coupon.php?chapter=12_3&index=4
843
	 * @param $coupon_stock_id
844
	 * @param $open_id
845
	 * @param $partner_trade_no
846
	 * @param string $op_user_id
847
	 * @param array $ext
848
	 * @return array
849
	 */
850 2
	public function sendCoupon($coupon_stock_id,$open_id,$partner_trade_no,$op_user_id = '',$ext = array()){
851 2
		$data = (!empty($ext) && is_array($ext))?$ext:array();
852 2
		$data["partner_trade_no"] = $partner_trade_no;
853 2
		$data["coupon_stock_id"] = $coupon_stock_id;
854 2
		$data["openid_count"] = 1;
855 2
		$data["open_id"] = $open_id;
856 2
		$data["op_user_id"] = $op_user_id;
857 2
		$result = $this->post(self::URL_SEND_COUPON,$data,true);
858 1
		return $result;
859
	}
860
861
	/**
862
	 * 查询代金券批次
863
	 * @ref https://pay.weixin.qq.com/wiki/doc/api/tools/sp_coupon.php?chapter=12_4&index=5
864
	 * @param $coupon_stock_id
865
	 * @param string $op_user_id
866
	 * @return array
867
	 */
868 1
	public function queryCouponStock($coupon_stock_id,$op_user_id = ''){
869 1
		$data = array();
870 1
		$data["coupon_stock_id"] = $coupon_stock_id;
871 1
		$data["op_user_id"] = $op_user_id;
872 1
		$result = $this->post(self::URL_QUERY_COUPON_STOCK,$data,false);
873 1
		return $result;
874
	}
875
876
	/**
877
	 * 查询代金券信息
878
	 * @ref https://pay.weixin.qq.com/wiki/doc/api/tools/sp_coupon.php?chapter=12_5&index=6
879
	 * @param $coupon_id
880
	 * @param $open_id
881
	 * @param $stock_id
882
	 * @param string $op_user_id
883
	 * @param array $ext
884
	 * @return array
885
	 */
886 1
	public function queryCouponsInfo($coupon_id,$open_id,$stock_id,$op_user_id = '',$ext = array()){
887 1
		$data = (!empty($ext) && is_array($ext))?$ext:array();
888 1
		$data["coupon_id"] = $coupon_id;
889 1
		$data["stock_id"] = $stock_id;
890 1
		$data["open_id"] = $open_id;
891 1
		$data["op_user_id"] = $op_user_id;
892 1
		$result = $this->post(self::URL_QUERY_COUPON_INFO,$data,false);
893 1
		return $result;
894
	}
895
896
	/**
897
	 * 获取RSA加密公钥
898
	 * @ref https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=24_7&index=4
899
	 * @param bool $refresh
900
	 * @return string
901
	 * @throws Exception
902
	 */
903 3
	public function getPublicKey($refresh = false){
904 3
		if(!$this->publicKey) {
905 2
			if (!$refresh && file_exists($this->config["rsa_pubkey_path"])) {
906 1
				$this->publicKey = file_get_contents($this->config["rsa_pubkey_path"]);
907
			}else{
908 2
				$data = array();
909 2
				$data["mch_id"] = $this->config["mch_id"];
910 2
				$data["sign_type"] = $this->config["sign_type"];
911 2
				$result = $this->post(self::URL_GETPUBLICKEY, $data, true);
912 1
				$pubkey = $result['pub_key'];
913 1
				$this->publicKey = $this->convertPKCS1toPKCS8($pubkey);
914 1
				$fp = @fopen($this->config["rsa_pubkey_path"], "w");
915 1
				fwrite($fp, $this->publicKey);
0 ignored issues
show
Bug introduced by
It seems like $fp can also be of type false; however, parameter $handle of fwrite() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

915
				fwrite(/** @scrutinizer ignore-type */ $fp, $this->publicKey);
Loading history...
916 1
				fclose($fp);
0 ignored issues
show
Bug introduced by
It seems like $fp can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

916
				fclose(/** @scrutinizer ignore-type */ $fp);
Loading history...
917
			}
918
		}
919 2
		return $this->publicKey;
920
	}
921
922 2
	public function setPublicKey($publicKey){
923 2
		$this->publicKey = $publicKey;
924 2
	}
925
926 1
	private function convertPKCS1toPKCS8($pkcs1){
927 1
		$start_key = $pkcs1;
928 1
		$start_key = str_replace('-----BEGIN RSA PUBLIC KEY-----', '', $start_key);
929 1
		$start_key = trim(str_replace('-----END RSA PUBLIC KEY-----', '', $start_key));
930 1
		$key = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A' . str_replace("\n", '', $start_key);
931 1
		$key = "-----BEGIN PUBLIC KEY-----\n" . wordwrap($key, 64, "\n", true) . "\n-----END PUBLIC KEY-----";
932 1
		return $key;
933
	}
934
935 4
	public function rsaEncrypt($data,$pubkey = null){
936 4
		if(!$pubkey) $pubkey = $this->getPublicKey();
937 3
		$encrypted = null;
938 3
		$pubkey = openssl_get_publickey($pubkey);
939 3
		if (@openssl_public_encrypt($data, $encrypted, $pubkey,OPENSSL_PKCS1_OAEP_PADDING))
940 2
			$data = base64_encode($encrypted);
941
		else
942 1
			throw new Exception('Unable to encrypt data');
943 2
		return $data;
944
	}
945
946
	/**
947
	 * sandbox环境获取验签秘钥
948
	 * @ref https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=23_1
949
	 * @return array
950
	 */
951 1
	public function getSignKey(){
952 1
		$data = array();
953 1
		$data["mch_id"] = $this->config["mch_id"];
954 1
		$result = $this->post($this->getSignKeyUrl,$data,false);
955 1
		return $result['sandbox_signkey'];
956
	}
957
958
	/**
959
	 * 获取JSAPI所需要的页面参数
960
	 * @param string $url
961
	 * @param string $ticket
962
	 * @return array
963
	 */
964 1
	public function getSignPackage($url, $ticket = null){
965 1
		if(!$ticket) $ticket = $this->getTicket();
966 1
		$timestamp = time();
967 1
		$nonceStr = $this->getNonceStr();
968 1
		$rawString = "jsapi_ticket=$ticket&noncestr=$nonceStr&timestamp=$timestamp&url=$url";
969 1
		$signature = sha1($rawString);
970
971
		$signPackage = array(
972 1
			"appId" => $this->config['app_id'],
973 1
			"nonceStr" => $nonceStr,
974 1
			"timestamp" => $timestamp,
975 1
			"url" => $url,
976 1
			"signature" => $signature,
977 1
			"rawString" => $rawString
978
		);
979 1
		return $signPackage;
980
	}
981
982
	/**
983
	 * 获取JSAPI Ticket
984
	 * @param boolean $cache
985
	 * @return string
986
	 */
987 1
	public function getTicket($cache = true){
988 1
		$ticket = null;
989 1
		$cacheKey = 'jsapi_ticket';
990 1
		if($cache === true){
991 1
			$data = $this->cacheProvider->get($cacheKey);
992 1
			if ($data && $data->expires_at > time()) {
993 1
				$ticket = $data->ticket;
994
			}
995
		}
996 1
		if(!$ticket){
997 1
			$data = $this->getWechatOAuth()->getTicket();
998 1
			if($cache === true){
999 1
				$this->cacheProvider->set($cacheKey,$data,time() + $data->expires_in);
1000
			}
1001 1
			$ticket = $data->ticket;
1002
		}
1003 1
		return $ticket;
1004
	}
1005
1006 38
	private function post($url, $data,$cert = true) {
1007 38
		if(!isset($data['mch_id']) && !isset($data['mchid'])) $data["mch_id"] = $this->config["mch_id"];
1008 38
		if(!isset($data['nonce_str'])) $data["nonce_str"] = $this->getNonceStr();
1009 38
		if(!isset($data['sign'])) $data['sign'] = $this->sign($data);
1010 38
		$this->requestXML = $this->responseXML = null;
1011 38
		$this->requestArray = $this->responseArray = null;
1012
1013 38
		$this->requestArray = $data;
1014 38
		$this->requestXML = $this->array2xml($data);
1015
		$opts = [
1016 38
			CURLOPT_SSL_VERIFYPEER => false,
1017 38
			CURLOPT_SSL_VERIFYHOST => false,
1018 38
			CURLOPT_RETURNTRANSFER => true,
1019 38
			CURLOPT_TIMEOUT => 10
1020
		];
1021 38
		if($cert == true){
1022 30
			$opts[CURLOPT_SSLCERTTYPE] = 'PEM';
1023 30
			$opts[CURLOPT_SSLCERT] = $this->config['ssl_cert_path'];
1024 30
			$opts[CURLOPT_SSLKEYTYPE] = 'PEM';
1025 30
			$opts[CURLOPT_SSLKEY] = $this->config['ssl_key_path'];
1026
		}
1027 38
		$processResponse = true;
1028 38
		if(in_array($url,[self::URL_DOWNLOADBILL,self::URL_DOWNLOAD_FUND_FLOW,self::URL_BATCHQUERYCOMMENT])){
1029 3
			$processResponse = false;
1030
		}
1031 38
		if($this->sandbox === true) $url = "sandboxnew/{$url}";
1032
1033 38
		$content = $this->httpClient->post(self::API_ENDPOINT . $url,$this->requestXML,[],$opts);
1034 38
		if(!$content) throw new Exception("Empty response with {$this->requestXML}");
1035
1036 38
		$this->responseXML = $content;
1037 38
		if($processResponse)
1038 35
			return $this->processResponseXML($this->responseXML);
1039 3
		else return $this->responseXML;
1040
1041
	}
1042
1043
	/**
1044
	 * @param $responseXML
1045
	 * @return array
1046
	 * @throws Exception
1047
	 */
1048 35
	private function processResponseXML($responseXML){
1049 35
		$result = $this->xml2array($responseXML);
1050 35
		$this->responseArray = $result;
1051 35
		if(empty($result['return_code'])){
1052 1
			throw new Exception("No return code presents in {$this->responseXML}");
1053
		}
1054 34
		$this->returnCode = $result["return_code"];
1055 34
		$this->returnMsg = isset($result['return_msg'])?$result['return_msg']:'';
1056
1057 34
		if ($this->returnCode == "SUCCESS") {
1058 28
			if(isset($result['result_code']) && $result['result_code'] == "FAIL"){
1059 3
				$this->resultCode = $result['result_code'];
1060 3
				$this->errCode = $result['err_code'];
1061 3
				$this->errCodeDes = $result['err_code_des'];
1062 3
				throw new Exception("[$this->errCode]$this->errCodeDes");
1063
			}else{
1064 25
				return $result;
1065
			}
1066 6
		} else if($this->returnCode == 'FAIL'){
1067 6
			throw new Exception($this->returnMsg);
1068
		}
1069
	}
1070
1071 45
	public function sign($data,$sign_type = WechatPay::SIGNTYPE_MD5) {
1072 45
		ksort($data);
1073 45
		$string1 = "";
1074 45
		foreach ($data as $k => $v) {
1075 45
			if ($v && trim($v)!='') {
1076 45
				$string1 .= "$k=$v&";
1077
			}
1078
		}
1079 45
		$stringSignTemp = $string1 . "key=" . $this->config["api_key"];
1080 45
		if($sign_type == WechatPay::SIGNTYPE_MD5){
1081 43
			$sign = strtoupper(md5($stringSignTemp));
1082 3
		}elseif($sign_type == WechatPay::SIGNTYPE_HMACSHA256){
1083 2
			$sign = strtoupper(hash_hmac('sha256',$stringSignTemp,$this->config["api_key"]));
1084 1
		}else throw new Exception("Not supported sign type - $sign_type");
1085 44
		return $sign;
1086
	}
1087
1088 39
	private function array2xml($array) {
1089 39
		$xml = "<xml>" . PHP_EOL;
1090 39
		foreach ($array as $k => $v) {
1091 39
			if($v && trim($v)!='')
1092 39
				$xml .= "<$k><![CDATA[$v]]></$k>" . PHP_EOL;
1093
		}
1094 39
		$xml .= "</xml>";
1095 39
		return $xml;
1096
	}
1097
1098 37
	private function xml2array($xml) {
1099 37
		$array = [];
1100 37
		$tmp = (array) simplexml_load_string($xml);
1101 37
		foreach ( $tmp as $k => $v) {
1102 37
			$array[$k] = (string) $v;
1103
		}
1104 37
		return $array;
1105
	}
1106
1107 40
	private function getNonceStr() {
1108 40
		return substr(str_shuffle("abcdefghijklmnopqrstuvwxyz0123456789"),0,32);
1109
	}
1110
1111
}