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

WechatPay::rsaEncrypt()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 9
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 4
nop 2
dl 0
loc 9
ccs 8
cts 8
cp 1
crap 3
rs 10
c 0
b 0
f 0
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
}