Completed
Push — master ( 9bc9b6...ec4bbc )
by Wei
04:31
created

WechatPay::report()   B

Complexity

Conditions 7
Paths 64

Size

Total Lines 16
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 7

Importance

Changes 0
Metric Value
cc 7
eloc 14
nc 64
nop 11
dl 0
loc 16
ccs 15
cts 15
cp 1
crap 7
rs 8.8333
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/**
3
 * WechatPay
4
 *
5
 * @license MIT
6
 * @author zhangv
7
 */
8
namespace zhangv\wechat\pay;
9
10
use \Exception;
11
use zhangv\wechat\pay\util\HttpClient;
12
use zhangv\wechat\pay\util\WechatOAuth;
13
use zhangv\wechat\pay\cache\CacheProvider;
14
use zhangv\wechat\pay\cache\JsonFileCacheProvider;
15
16
/**
17
 * Class WechatPay
18
 * @package zhangv\wechat
19
 * @author zhangv
20
 * @license MIT
21
 *
22
 * @method static service\App       App(array $config)
23
 * @method static service\Jsapi     Jsapi(array $config)
24
 * @method static service\Micro     Micro(array $config)
25
 * @method static service\Mweb      Mweb(array $config)
26
 * @method static service\Native    Native(array $config)
27
 * @method static service\Weapp     Weapp(array $config)
28
 * @method static service\Mchpay    Mchpay(array $config)
29
 * @method static service\Redpack   Redpack(array $config)
30
 * @method static service\Coupon    Coupon(array $config)
31
 */
32
class WechatPay {
33
	const TRADETYPE_JSAPI = 'JSAPI',TRADETYPE_NATIVE = 'NATIVE',TRADETYPE_APP = 'APP',TRADETYPE_MWEB = 'MWEB';
34
	const SIGNTYPE_MD5 = 'MD5', SIGNTYPE_HMACSHA256 = 'HMAC-SHA256';
35
	const CHECKNAME_FORCECHECK = 'FORCE_CHECK',CHECKNAME_NOCHECK = 'NO_CHECK';
36
	const ACCOUNTTYPE_BASIC = 'Basic',ACCOUNTTYPE_OPERATION = 'Operation',ACCOUNTTYPE_FEES = 'Fees';
37
	const API_ENDPOINT = 'https://api.mch.weixin.qq.com/';
38
	/** 支付 */
39
	const URL_UNIFIEDORDER = 'pay/unifiedorder';
40
	const URL_ORDERQUERY = 'pay/orderquery';
41
	const URL_CLOSEORDER = 'pay/closeorder';
42
	const URL_REFUND = 'secapi/pay/refund';
43
	const URL_REFUNDQUERY = 'pay/refundquery';
44
	const URL_DOWNLOADBILL = 'pay/downloadbill';
45
	const URL_DOWNLOAD_FUND_FLOW = 'pay/downloadfundflow';
46
	const URL_REPORT = 'payitil/report';
47
	const URL_SHORTURL = 'tools/shorturl';
48
	const URL_MICROPAY = 'pay/micropay';
49
	const URL_BATCHQUERYCOMMENT = 'billcommentsp/batchquerycomment';
50
	const URL_REVERSE = 'secapi/pay/reverse';
51
	const URL_AUTHCODETOOPENID = 'tools/authcodetoopenid';
52
	/** 红包 */
53
	const URL_GETHBINFO = 'mmpaymkttransfers/gethbinfo';
54
	const URL_SENDREDPACK = 'mmpaymkttransfers/sendredpack';
55
	const URL_SENDGROUPREDPACK = 'mmpaymkttransfers/sendgroupredpack';
56
	/** 企业付款 */
57
	const URL_TRANSFER_WALLET = 'mmpaymkttransfers/promotion/transfers';
58
	const URL_QUERY_TRANSFER_WALLET = 'mmpaymkttransfers/gettransferinfo';
59
	const URL_TRANSFER_BANKCARD = 'mmpaysptrans/pay_bank';
60
	const URL_QUERY_TRANSFER_BANKCARD = 'mmpaysptrans/query_bank';
61
	/** 代金券 */
62
	const URL_SEND_COUPON = 'mmpaymkttransfers/send_coupon';
63
	const URL_QUERY_COUPON_STOCK = 'mmpaymkttransfers/query_coupon_stock';
64
	const URL_QUERY_COUPON_INFO = 'mmpaymkttransfers/querycouponsinfo';
65
	/** Sandbox获取测试公钥 */
66
	const URL_GETPUBLICKEY = 'https://fraud.mch.weixin.qq.com/risk/getpublickey';
67
	public static $BANKCODE = [
68
		'工商银行' => '1002', '农业银行' => '1005', '中国银行' => '1026', '建设银行' => '1003', '招商银行' => '1001',
69
		'邮储银行' => '1066', '交通银行' => '1020', '浦发银行' => '1004', '民生银行' => '1006', '兴业银行' => '1009',
70
		'平安银行' => '1010', '中信银行' => '1021', '华夏银行' => '1025', '广发银行' => '1027', '光大银行' => '1022',
71
		'北京银行' => '1032', '宁波银行' => '1056',
72
	];
73
74
	public $getSignKeyUrl = "sandboxnew/pay/getsignkey";
75
	public $sandbox = false;
76
77
	/** @var string */
78
	public $returnCode;
79
	/** @var string */
80
	public $returnMsg;
81
	/** @var string */
82
	public $resultCode;
83
	/** @var string */
84
	public $errCode;
85
	/** @var string */
86
	public $errCodeDes;
87
	/** @var string */
88
	public $requestXML = null;
89
	/** @var string */
90
	public $responseXML = null;
91
	/** @var array */
92
	public $requestArray = null;
93
	/** @var array */
94
	public $responseArray = null;
95
	/** @var array */
96
	protected $config;
97
	/** @var HttpClient */
98
	protected $httpClient = null;
99
	/** @var WechatOAuth */
100
	protected $wechatOAuth = null;
101
	/** @var string */
102
	public $publicKey = null;
103
	/** @var CacheProvider */
104
	public $cacheProvider = null;
105
106
	/**
107
	 * @param $config array 配置
108
	 */
109 54
	public function __construct(array $config) {
110 54
		$this->config = $config;
111 54
		$this->httpClient = new HttpClient(5);
112 54
		$this->cacheProvider = new JsonFileCacheProvider();
113 54
	}
114
115
	/**
116
	 * @param string $name
117
	 * @param string $config
118
	 * @return mixed
119
	 */
120 28
	private static function load($name, $config) {
121 28
		$service = __NAMESPACE__ . "\\service\\{$name}";
122 28
		return new $service($config);
123
	}
124
125
	/**
126
	 * @param string $name
127
	 * @param array  $config
128
	 *
129
	 * @return mixed
130
	 */
131 28
	public static function __callStatic($name, $config) {
132 28
		return self::load($name, $config);
0 ignored issues
show
Bug introduced by
$config of type array is incompatible with the type string expected by parameter $config of zhangv\wechat\pay\WechatPay::load(). ( Ignorable by Annotation )

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

132
		return self::load($name, /** @scrutinizer ignore-type */ $config);
Loading history...
133
	}
134
135 1
	public function setWechatOAuth($wechatOAuth){
136 1
		$this->wechatOAuth = $wechatOAuth;
137 1
	}
138
139 1
	public function getWechatOAuth(){
140 1
		if(!$this->wechatOAuth){
141 1
			$this->wechatOAuth = new WechatOAuth($this->config['app_id'],$this->config['app_secret']);
142
		}
143 1
		return $this->wechatOAuth;
144
	}
145
146 1
	public function setConfig($config){
147 1
		$this->config = $config;
148 1
	}
149
150 3
	public function getConfig(){
151 3
		return $this->config;
152
	}
153
154 39
	public function setHttpClient($httpClient){
155 39
		$this->httpClient = $httpClient;
156 39
	}
157
158 54
	public function setCacheProvider($cacheProvider){
159 54
		$this->cacheProvider = $cacheProvider;
160 54
	}
161
162 1
	public function getCacheProvider(){
163 1
		return $this->cacheProvider;
164
	}
165
166
	/**
167
	 * 统一下单接口
168
	 * @link https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
169
	 * @param array $params
170
	 * @throws Exception
171
	 * @return array
172
	 */
173 8
	public function unifiedOrder($params) {
174 8
		$data = array();
175 8
		$data["appid"] = $this->config["app_id"];
176 8
		$data["device_info"] = (isset($params['device_info'])&&trim($params['device_info'])!='')?$params['device_info']:null;
177 8
		$data["body"] = $params['body'];
178 8
		$data["detail"] = isset($params['detail'])?$params['detail']:null;//optional
179 8
		$data["attach"] = isset($params['attach'])?$params['attach']:null;//optional
180 8
		$data["out_trade_no"] = isset($params['out_trade_no'])?$params['out_trade_no']:null;
181 8
		$data["fee_type"] = isset($params['fee_type'])?$params['fee_type']:'CNY';
182 8
		$data["total_fee"]    = $params['total_fee'];
183 8
		$data["spbill_create_ip"] = $params['spbill_create_ip'];
184 8
		$data["time_start"] = isset($params['time_start'])?$params['time_start']:null;//optional
185 8
		$data["time_expire"] = isset($params['time_expire'])?$params['time_expire']:null;//optional
186 8
		$data["goods_tag"] = isset($params['goods_tag'])?$params['goods_tag']:null;
187 8
		$data["notify_url"] = $this->config["notify_url"];
188 8
		$data["trade_type"] = $params['trade_type'];
189 8
		if($params['trade_type'] == WechatPay::TRADETYPE_NATIVE){
190 1
			if(!isset($params['product_id'])) throw new Exception('product_id is required when trade_type is NATIVE');
191 1
			$data["product_id"] = $params['product_id'];
192
		}
193 8
		if($params['trade_type'] == WechatPay::TRADETYPE_JSAPI){
194 5
			if(!isset($params['openid'])) throw new Exception('openid is required when trade_type is JSAPI');
195 5
			$data["openid"] = $params['openid'];
196
		}
197 8
		$result = $this->post(self::URL_UNIFIEDORDER, $data);
198 5
		return $result;
199
	}
200
201
	/**
202
	 * 查询订单(根据微信订单号)
203
	 * @link  https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_2
204
	 * @param $transaction_id string 微信订单号
205
	 * @return array
206
	 */
207 2
	public function queryOrderByTransactionId($transaction_id){
208 2
		$data = array();
209 2
		$data["appid"] = $this->config["app_id"];
210 2
		$data["transaction_id"] = $transaction_id;
211 2
		$result = $this->post(self::URL_ORDERQUERY, $data);
212 1
		return $result;
213
	}
214
215
	/**
216
	 * 查询订单(根据商户订单号)
217
	 * @link  https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_2
218
	 * @param $out_trade_no string 商户订单号
219
	 * @return array
220
	 */
221 1
	public function queryOrderByOutTradeNo($out_trade_no){
222 1
		$data = array();
223 1
		$data["appid"] = $this->config["app_id"];
224 1
		$data["out_trade_no"] = $out_trade_no;
225 1
		$result = $this->post(self::URL_ORDERQUERY, $data);
226 1
		return $result;
227
	}
228
229
	/**
230
	 * 查询退款(根据微信订单号)
231
	 * @link  https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_5
232
	 * @param $transaction_id string 微信交易号
233
	 * @param $offset int 偏移
234
	 * @return array
235
	 */
236 1
	public function queryRefundByTransactionId($transaction_id,$offset = 0){
237 1
		$data = array();
238 1
		$data["appid"] = $this->config["app_id"];
239 1
		$data["transaction_id"] = $transaction_id;
240 1
		$data["offset"] = $offset;
241 1
		$result = $this->post(self::URL_REFUNDQUERY, $data);
242 1
		return $result;
243
	}
244
245
	/**
246
	 * 查询退款(根据商户订单号)
247
	 * @link  https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_5
248
	 * @param $out_trade_no string 商户交易号
249
	 * @param $offset int 偏移
250
	 * @return array
251
	 */
252 1
	public function queryRefundByOutTradeNo($out_trade_no,$offset = 0){
253 1
		$data = array();
254 1
		$data["appid"] = $this->config["app_id"];
255 1
		$data["out_trade_no"] = $out_trade_no;
256 1
		$data["offset"] = $offset;
257 1
		$result = $this->post(self::URL_REFUNDQUERY, $data);
258 1
		return $result;
259
	}
260
261
	/**
262
	 * 查询退款(根据微信退款单号)
263
	 * @link  https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_5
264
	 * @param $refund_id string 微信退款单号
265
	 * @param $offset int 偏移
266
	 * @return array
267
	 */
268 1
	public function queryRefundByRefundId($refund_id,$offset = 0){
269 1
		$data = array();
270 1
		$data["appid"] = $this->config["app_id"];
271 1
		$data["refund_id"] = $refund_id;
272 1
		$data["offset"] = $offset;
273 1
		$result = $this->post(self::URL_REFUNDQUERY, $data);
274 1
		return $result;
275
	}
276
277
	/**
278
	 * 查询退款(根据商户退款单号)
279
	 * @link  https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_5
280
	 * @param $out_refund_no string 商户退款单号
281
	 * @param $offset int 偏移
282
	 * @return array
283
	 */
284 1
	public function queryRefundByOutRefundNo($out_refund_no,$offset = 0){
285 1
		$data = array();
286 1
		$data["appid"] = $this->config["app_id"];
287 1
		$data["out_refund_no"] = $out_refund_no;
288 1
		$data["offset"] = $offset;
289 1
		$result = $this->post(self::URL_REFUNDQUERY, $data);
290 1
		return $result;
291
	}
292
293
	/**
294
	 * 关闭订单
295
	 * @link  https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_3
296
	 * @param $out_trade_no string 商户订单号
297
	 * @return array
298
	 */
299 1
	public function closeOrder($out_trade_no){
300 1
		$data = array();
301 1
		$data["appid"] = $this->config["app_id"];
302 1
		$data["out_trade_no"] = $out_trade_no;
303 1
		$result = $this->post(self::URL_CLOSEORDER, $data,false);
304 1
		return $result;
305
	}
306
307
	/**
308
	 * 申请退款 - 使用商户订单号
309
	 * @link  https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_4
310
	 * @link  https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
311
	 * @param $out_trade_no string 商户订单号
312
	 * @param $out_refund_no string 商户退款单号
313
	 * @param $total_fee int 总金额(单位:分)
314
	 * @param $refund_fee int 退款金额(单位:分)
315
	 * @param $ext array 扩展数组
316
	 * @return array
317
	 */
318 1
	public function refundByOutTradeNo($out_trade_no,$out_refund_no,$total_fee,$refund_fee,$ext = array()){
319 1
		$data = ($ext && is_array($ext))?$ext:array();
320 1
		$data["appid"] = $this->config["app_id"];
321 1
		$data["out_trade_no"] = $out_trade_no;
322 1
		$data["out_refund_no"] = $out_refund_no;
323 1
		$data["total_fee"] = $total_fee;
324 1
		$data["refund_fee"] = $refund_fee;
325 1
		$result = $this->post(self::URL_REFUND, $data,true);
326 1
		return $result;
327
	}
328
329
	/**
330
	 * 申请退款 - 使用微信订单号
331
	 * @link  https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_4
332
	 * @link  https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
333
	 * @param $transaction_id string 微信订单号
334
	 * @param $out_refund_no string 商户退款单号
335
	 * @param $total_fee int 总金额(单位:分)
336
	 * @param $refund_fee int 退款金额(单位:分)
337
	 * @param $ext array 扩展数组
338
	 * @return array
339
	 */
340 1
	public function refundByTransactionId($transaction_id,$out_refund_no,$total_fee,$refund_fee,$ext = array()){
341 1
		$data = ($ext && is_array($ext))?$ext:array();
342 1
		$data["appid"] = $this->config["app_id"];
343 1
		$data["transaction_id"] = $transaction_id;
344 1
		$data["out_refund_no"] = $out_refund_no;
345 1
		$data["total_fee"] = $total_fee;
346 1
		$data["refund_fee"] = $refund_fee;
347 1
		$result = $this->post(self::URL_REFUND, $data,true);
348 1
		return $result;
349
	}
350
351
	/**
352
	 * 下载对账单
353
	 * @link https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_6
354
	 * @param $bill_date string 下载对账单的日期,格式:20140603
355
	 * @param $bill_type string 类型 ALL|SUCCESS
356
	 * @return array
357
	 */
358 1
	public function downloadBill($bill_date,$bill_type = 'ALL'){
359 1
		$data = array();
360 1
		$data["appid"] = $this->config["app_id"];
361 1
		$data["bill_date"] = $bill_date;
362 1
		$data["bill_type"] = $bill_type;
363 1
		$result = $this->post(self::URL_DOWNLOADBILL, $data);
364 1
		return $result;
365
	}
366
367
	/**
368
	 * 下载资金账单
369
	 * @link https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_18&index=7
370
	 * @param $bill_date string 资金账单日期,格式:20140603
371
	 * @param $account_type string 资金账户类型 Basic|Operation|Fees
372
	 * @param $tar_type string 压缩账单
373
	 * @return array
374
	 */
375 1
	public function downloadFundFlow($bill_date,$account_type = self::ACCOUNTTYPE_BASIC,$tar_type = 'GZIP'){
376 1
		$data = array();
377 1
		$data["appid"] = $this->config["app_id"];
378 1
		$data["bill_date"] = $bill_date;
379 1
		$data["account_type"] = $account_type;
380 1
		$data["tar_type"] = $tar_type;
381 1
		$result = $this->post(self::URL_DOWNLOAD_FUND_FLOW, $data);
382 1
		return $result;
383
	}
384
385
	/**
386
	 * 拉取订单评价数据
387
	 * @link https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_17&index=11
388
	 * @param string $begin_time 开始时间,格式为yyyyMMddHHmmss
389
	 * @param string $end_time 结束时间,格式为yyyyMMddHHmmss
390
	 * @param int $offset 偏移
391
	 * @param int $limit 条数
392
	 * @return array
393
	 */
394 1
	public function batchQueryComment($begin_time,$end_time,$offset = 0,$limit = 200){
395 1
		$data = array();
396 1
		$data["appid"] = $this->config["app_id"];
397 1
		$data["begin_time"] = $begin_time;
398 1
		$data["end_time"] = $end_time;
399 1
		$data["offset"] = $offset;
400 1
		$data["limit"] = $limit;
401 1
		$data["sign"] = $this->sign($data,WechatPay::SIGNTYPE_HMACSHA256);
402 1
		$result = $this->post(self::URL_BATCHQUERYCOMMENT, $data, true); //cert is required
403 1
		return $result;
404
	}
405
406
	/**
407
	 * 支付结果通知处理
408
	 * @param $notify_data array|string 通知数据
409
	 * @param $callback callable 回调
410
	 * @return null
411
	 * @throws Exception
412
	 */
413 2
	public function onPaidNotify($notify_data,callable $callback = null){
414 2
		if(!is_array($notify_data)) $notify_data = $this->xml2array($notify_data);
415 2
		if(!$this->validateSign($notify_data)) throw new Exception('Invalid paid notify data');
416 1
		if($callback && is_callable($callback)){
417 1
			return call_user_func_array( $callback , [$notify_data] );
418
		}
419
	}
420
421
	/**
422
	 * 退款结果通知处理
423
	 * @param string|array $notify_data 通知数据(XML/array)
424
	 * @param callable $callback 回调
425
	 * @return mixed
426
	 * @throws Exception
427
	 */
428 2
	public function onRefundedNotify($notify_data,callable $callback = null){
429 2
		if(!is_array($notify_data)) $notify_data = $this->xml2array($notify_data);
430 2
		if(!$this->validateSign($notify_data)) throw new Exception('Invalid refund notify data');
431 1
		if($callback && is_callable($callback)){
432 1
			return call_user_func_array( $callback ,[$notify_data] );
433
		}
434
	}
435
436
	/**
437
	 * 验证数据签名
438
	 * @param $data array 数据数组
439
	 * @return boolean 数据校验结果
440
	 */
441 5
	public function validateSign($data) {
442 5
		if (!isset($data["sign"])) {
443 1
			return false;
444
		}
445 4
		$sign = $data["sign"];
446 4
		unset($data["sign"]);
447 4
		return $this->sign($data) == $sign;
448
	}
449
450
	/**
451
	 * 响应微信支付后台通知
452
	 * @param array $data
453
	 * @param string $return_code 返回状态码 SUCCESS/FAIL
454
	 * @param string $return_msg  返回信息
455
	 * @param bool $print
456
	 * @return string
457
	 */
458 1
	public function responseNotify($print = true,$data = [],$return_code="SUCCESS", $return_msg= 'OK') {
459 1
		$data["return_code"] = $return_code;
460 1
		if ($return_msg) {
461 1
			$data["return_msg"] = $return_msg;
462
		}
463 1
		$xml = $this->array2xml($data);
464 1
		if($print === true) print $xml;
465 1
		else return $xml;
466
	}
467
468
	/**
469
	 * 交易保障
470
	 * @link https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_8&index=8
471
	 * @param string $interface_url
472
	 * @param string $execution_time
473
	 * @param string $return_code
474
	 * @param string $result_code
475
	 * @param string $user_ip
476
	 * @param string $out_trade_no
477
	 * @param string $time
478
	 * @param string $device_info
479
	 * @param string $return_msg
480
	 * @param string $err_code
481
	 * @param string $err_code_des
482
	 * @return array
483
	 */
484 1
	public function report($interface_url,$execution_time,$return_code,$result_code,$user_ip,$out_trade_no = null,$time = null,$device_info = null,
485
	                       $return_msg = null,$err_code = null,$err_code_des = null){
486 1
		$data = array();
487 1
		$data["appid"] = $this->config["app_id"];
488 1
		$data["interface_url"] = $interface_url;
489 1
		$data["execution_time"] = $execution_time;
490 1
		$data["return_code"] = $return_code;
491 1
		$data["result_code"] = $result_code;
492 1
		$data["user_ip"] = $user_ip;
493 1
		if($out_trade_no) $data["out_trade_no"] = $out_trade_no;
494 1
		if($time) $data["time"] = $time;
495 1
		if($device_info) $data["device_info"] = $device_info;
496 1
		if($return_msg) $data["return_msg"] = $return_msg;
497 1
		if($err_code) $data["err_code"] = $err_code;
498 1
		if($err_code_des) $data["err_code_des"] = $err_code_des;
499 1
		return $this->post(self::URL_REPORT, $data, false);
500
	}
501
502
	/**
503
	 * 转换短链接
504
	 * @link https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_9&index=8
505
	 * @param $longurl
506
	 * @return string
507
	 */
508 1
	public function shortUrl($longurl){
509 1
		$data = array();
510 1
		$data["appid"] = $this->config["app_id"];
511 1
		$data["long_url"] = $longurl;
512 1
		$result = $this->post(self::URL_SHORTURL,$data,false);
513 1
		return $result['short_url'];
514
	}
515
516 4
	/**
517 4
	 * sandbox环境获取验签秘钥
518 3
	 * @link https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=23_1
519 3
	 * @return array
520 3
	 */
521 2
	public function getSignKey(){
522
		$data = array();
523 1
		$data["mch_id"] = $this->config["mch_id"];
524 2
		$result = $this->post($this->getSignKeyUrl,$data,false);
525
		return $result['sandbox_signkey'];
526
	}
527
528
	/**
529
	 * 获取JSAPI所需要的页面参数
530
	 * @param string $url
531
	 * @param string $ticket
532 1
	 * @return array
533 1
	 */
534 1
	public function getSignPackage($url, $ticket = null){
535 1
		if(!$ticket) $ticket = $this->getTicket();
536 1
		$timestamp = time();
537
		$nonceStr = $this->getNonceStr();
538
		$rawString = "jsapi_ticket=$ticket&noncestr=$nonceStr&timestamp=$timestamp&url=$url";
539
		$signature = sha1($rawString);
540
541
		$signPackage = array(
542
			"appId" => $this->config['app_id'],
543
			"nonceStr" => $nonceStr,
544
			"timestamp" => $timestamp,
545 1
			"url" => $url,
546 1
			"signature" => $signature,
547 1
			"rawString" => $rawString
548 1
		);
549 1
		return $signPackage;
550 1
	}
551
552
	/**
553 1
	 * 获取JSAPI Ticket
554 1
	 * @param boolean $cache
555 1
	 * @return string
556 1
	 */
557 1
	public function getTicket($cache = true){
558 1
		$ticket = null;
559
		$cacheKey = 'jsapi_ticket';
560 1
		if($cache === true){
561
			$data = $this->cacheProvider->get($cacheKey);
562
			if ($data && $data->expires_at > time()) {
563
				$ticket = $data->ticket;
564
			}
565
		}
566
		if(!$ticket){
567
			$data = $this->getWechatOAuth()->getTicket();
568 1
			if($cache === true){
569 1
				$this->cacheProvider->set($cacheKey,$data,time() + $data->expires_in);
570 1
			}
571 1
			$ticket = $data->ticket;
572 1
		}
573 1
		return $ticket;
574 1
	}
575
576
	protected function post($url, $data,$cert = true) {
577 1
		if(!isset($data['mch_id']) && !isset($data['mchid'])) $data["mch_id"] = $this->config["mch_id"];
578 1
		if(!isset($data['nonce_str'])) $data["nonce_str"] = $this->getNonceStr();
579 1
		if(!isset($data['sign'])) $data['sign'] = $this->sign($data);
580 1
		$this->requestXML = $this->responseXML = null;
581
		$this->requestArray = $this->responseArray = null;
582 1
583
		$this->requestArray = $data;
584 1
		$this->requestXML = $this->array2xml($data);
585
		$opts = [
586
			CURLOPT_SSL_VERIFYPEER => false,
587 39
			CURLOPT_SSL_VERIFYHOST => false,
588 39
			CURLOPT_RETURNTRANSFER => true,
589 39
			CURLOPT_TIMEOUT => 10
590 39
		];
591 39
		if($cert == true){
592 39
			$opts[CURLOPT_SSLCERTTYPE] = 'PEM';
593
			$opts[CURLOPT_SSLCERT] = $this->config['ssl_cert_path'];
594 39
			$opts[CURLOPT_SSLKEYTYPE] = 'PEM';
595 39
			$opts[CURLOPT_SSLKEY] = $this->config['ssl_key_path'];
596
		}
597 39
		$processResponse = true;
598 39
		if(in_array($url,[self::URL_DOWNLOADBILL,self::URL_DOWNLOAD_FUND_FLOW,self::URL_BATCHQUERYCOMMENT])){
599 39
			$processResponse = false;
600 39
		}
601
		if($this->sandbox === true) $url = "sandboxnew/{$url}";
602 39
603 32
		$content = $this->httpClient->post(self::API_ENDPOINT . $url,$this->requestXML,[],$opts);
604 32
		if(!$content) throw new Exception("Empty response with {$this->requestXML}");
605 32
606 32
		$this->responseXML = $content;
607
		if($processResponse)
608 39
			return $this->processResponseXML($this->responseXML);
609 39
		else return $this->responseXML;
610 3
	}
611
612 39
	/**
613
	 * @param $responseXML
614 39
	 * @return array
615 39
	 * @throws Exception
616
	 */
617 39
	private function processResponseXML($responseXML){
618 39
		$result = $this->xml2array($responseXML);
619 36
		$this->responseArray = $result;
620 3
		if(empty($result['return_code'])){
621
			throw new Exception("No return code presents in {$this->responseXML}");
622
		}
623
		$this->returnCode = $result["return_code"];
624
		$this->returnMsg = isset($result['return_msg'])?$result['return_msg']:'';
625
626
		if ($this->returnCode == "SUCCESS") {
627
			if(isset($result['result_code']) && $result['result_code'] == "FAIL"){
628 36
				$this->resultCode = $result['result_code'];
629 36
				$this->errCode = $result['err_code'];
630 36
				$this->errCodeDes = $result['err_code_des'];
631 36
				throw new Exception("[$this->errCode]$this->errCodeDes");
632 1
			}else{
633
				return $result;
634 35
			}
635 35
		} else if($this->returnCode == 'FAIL'){
636
			throw new Exception($this->returnMsg);
637 35
		}
638 29
	}
639 3
640 3
	public function sign($data,$sign_type = WechatPay::SIGNTYPE_MD5) {
641 3
		ksort($data);
642 3
		$string1 = "";
643
		foreach ($data as $k => $v) {
644 26
			if ($v && trim($v)!='') {
645
				$string1 .= "$k=$v&";
646 6
			}
647 6
		}
648
		$stringSignTemp = $string1 . "key=" . $this->config["api_key"];
649
		if($sign_type == WechatPay::SIGNTYPE_MD5){
650
			$sign = strtoupper(md5($stringSignTemp));
651 48
		}elseif($sign_type == WechatPay::SIGNTYPE_HMACSHA256){
652 48
			$sign = strtoupper(hash_hmac('sha256',$stringSignTemp,$this->config["api_key"]));
653 48
		}else throw new Exception("Not supported sign type - $sign_type");
654 48
		return $sign;
655 48
	}
656 48
657
	private function array2xml($array) {
658
		$xml = "<xml>" . PHP_EOL;
659 48
		foreach ($array as $k => $v) {
660 48
			if($v && trim($v)!='')
661 46
				$xml .= "<$k><![CDATA[$v]]></$k>" . PHP_EOL;
662 3
		}
663 2
		$xml .= "</xml>";
664 1
		return $xml;
665 47
	}
666
667
	private function xml2array($xml) {
668 40
		$array = [];
669 40
		$tmp = (array) simplexml_load_string($xml);
670 40
		foreach ( $tmp as $k => $v) {
671 40
			$array[$k] = (string) $v;
672 40
		}
673
		return $array;
674 40
	}
675 40
676
	protected function getNonceStr() {
677
		return substr(str_shuffle("abcdefghijklmnopqrstuvwxyz0123456789"),0,32);
678 38
	}
679
680
}