Completed
Push — master ( c385cb...b0036f )
by Wei
04:12
created

WechatPay::getCacheProvider()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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