1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Kaylyu\Alipay\F2fpay\Base\Aop; |
4
|
|
|
|
5
|
|
|
|
6
|
|
|
use Kaylyu\Alipay\Kernel\Exceptions\Exception; |
7
|
|
|
|
8
|
|
|
class AopClient { |
9
|
|
|
//应用ID |
10
|
|
|
public $appId; |
11
|
|
|
//私钥文件路径 |
12
|
|
|
public $rsaPrivateKeyFilePath; |
13
|
|
|
|
14
|
|
|
//私钥值 |
15
|
|
|
public $rsaPrivateKey; |
16
|
|
|
//网关 |
17
|
|
|
public $gatewayUrl = "https://openapi.alipay.com/gateway.do"; |
18
|
|
|
//返回数据格式 |
19
|
|
|
public $format = "json"; |
20
|
|
|
//api版本 |
21
|
|
|
public $apiVersion = "1.0"; |
22
|
|
|
|
23
|
|
|
// 表单提交字符集编码 |
24
|
|
|
public $postCharset = "UTF-8"; |
25
|
|
|
|
26
|
|
|
|
27
|
|
|
public $alipayPublicKey = null; |
28
|
|
|
|
29
|
|
|
public $alipayrsaPublicKey; |
30
|
|
|
|
31
|
|
|
|
32
|
|
|
public $debugInfo = false; |
33
|
|
|
|
34
|
|
|
protected $fileCharset = "UTF-8"; |
35
|
|
|
|
36
|
|
|
private $RESPONSE_SUFFIX = "_response"; |
37
|
|
|
|
38
|
|
|
private $ERROR_RESPONSE = "error_response"; |
39
|
|
|
|
40
|
|
|
private $SIGN_NODE_NAME = "sign"; |
41
|
|
|
|
42
|
|
|
|
43
|
|
|
//加密XML节点名称 |
44
|
|
|
private $ENCRYPT_XML_NODE_NAME = "response_encrypted"; |
45
|
|
|
|
46
|
|
|
private $needEncrypt = false; |
47
|
|
|
|
48
|
|
|
|
49
|
|
|
//签名类型 |
50
|
|
|
public $signType = "RSA"; |
51
|
|
|
|
52
|
|
|
|
53
|
|
|
//加密密钥和类型 |
54
|
|
|
|
55
|
|
|
public $encryptKey; |
56
|
|
|
|
57
|
|
|
public $encryptType = "AES"; |
58
|
|
|
|
59
|
|
|
protected $alipaySdkVersion = "alipay-sdk-php-20161101"; |
60
|
|
|
|
61
|
|
|
public function generateSign($params, $signType = "RSA") { |
62
|
|
|
return $this->sign($this->getSignContent($params), $signType); |
63
|
|
|
} |
64
|
|
|
|
65
|
|
|
public function rsaSign($params, $signType = "RSA") { |
66
|
|
|
return $this->sign($this->getSignContent($params), $signType); |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
protected function getSignContent($params) { |
70
|
|
|
ksort($params); |
71
|
|
|
|
72
|
|
|
$stringToBeSigned = ""; |
73
|
|
|
$i = 0; |
74
|
|
|
foreach ($params as $k => $v) { |
75
|
|
|
if (false === $this->checkEmpty($v) && "@" != substr($v, 0, 1)) { |
76
|
|
|
|
77
|
|
|
// 转换成目标字符集 |
78
|
|
|
$v = $this->characet($v, $this->postCharset); |
79
|
|
|
|
80
|
|
|
if ($i == 0) { |
81
|
|
|
$stringToBeSigned .= "$k" . "=" . "$v"; |
82
|
|
|
} else { |
83
|
|
|
$stringToBeSigned .= "&" . "$k" . "=" . "$v"; |
84
|
|
|
} |
85
|
|
|
$i++; |
86
|
|
|
} |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
unset ($k, $v); |
90
|
|
|
return $stringToBeSigned; |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
protected function sign($data, $signType = "RSA") { |
94
|
|
View Code Duplication |
if($this->checkEmpty($this->rsaPrivateKeyFilePath)){ |
|
|
|
|
95
|
|
|
$priKey=$this->rsaPrivateKey; |
96
|
|
|
$res = "-----BEGIN RSA PRIVATE KEY-----\n" . |
97
|
|
|
wordwrap($priKey, 64, "\n", true) . |
98
|
|
|
"\n-----END RSA PRIVATE KEY-----"; |
99
|
|
|
}else { |
100
|
|
|
$priKey = file_get_contents($this->rsaPrivateKeyFilePath); |
101
|
|
|
$res = openssl_get_privatekey($priKey); |
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
($res) or die('您使用的私钥格式错误,请检查RSA私钥配置'); |
105
|
|
|
|
106
|
|
|
if ("RSA2" == $signType) { |
107
|
|
|
openssl_sign($data, $sign, $res, OPENSSL_ALGO_SHA256); |
108
|
|
|
} else { |
109
|
|
|
openssl_sign($data, $sign, $res); |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
if(!$this->checkEmpty($this->rsaPrivateKeyFilePath)){ |
113
|
|
|
openssl_free_key($res); |
114
|
|
|
} |
115
|
|
|
$sign = base64_encode($sign); |
116
|
|
|
return $sign; |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
|
120
|
|
|
protected function curl($url, $postFields = null) { |
121
|
|
|
$ch = curl_init(); |
122
|
|
|
curl_setopt($ch, CURLOPT_URL, $url); |
123
|
|
|
curl_setopt($ch, CURLOPT_FAILONERROR, false); |
124
|
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); |
125
|
|
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); |
126
|
|
|
|
127
|
|
|
$postBodyString = ""; |
128
|
|
|
$encodeArray = Array(); |
129
|
|
|
$postMultipart = false; |
130
|
|
|
|
131
|
|
|
|
132
|
|
|
if (is_array($postFields) && 0 < count($postFields)) { |
133
|
|
|
|
134
|
|
|
foreach ($postFields as $k => $v) { |
135
|
|
|
if ("@" != substr($v, 0, 1)) //判断是不是文件上传 |
136
|
|
|
{ |
137
|
|
|
|
138
|
|
|
$postBodyString .= "$k=" . urlencode($this->characet($v, $this->postCharset)) . "&"; |
139
|
|
|
$encodeArray[$k] = $this->characet($v, $this->postCharset); |
140
|
|
|
} else //文件上传用multipart/form-data,否则用www-form-urlencoded |
141
|
|
|
{ |
142
|
|
|
$postMultipart = true; |
143
|
|
|
$encodeArray[$k] = new \CURLFile(substr($v, 1)); |
144
|
|
|
} |
145
|
|
|
|
146
|
|
|
} |
147
|
|
|
unset ($k, $v); |
148
|
|
|
curl_setopt($ch, CURLOPT_POST, true); |
149
|
|
|
if ($postMultipart) { |
150
|
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $encodeArray); |
151
|
|
|
} else { |
152
|
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, substr($postBodyString, 0, -1)); |
153
|
|
|
} |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
if ($postMultipart) { |
157
|
|
|
|
158
|
|
|
$headers = array('content-type: multipart/form-data;charset=' . $this->postCharset . ';boundary=' . $this->getMillisecond()); |
159
|
|
|
} else { |
160
|
|
|
|
161
|
|
|
$headers = array('content-type: application/x-www-form-urlencoded;charset=' . $this->postCharset); |
162
|
|
|
} |
163
|
|
|
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); |
164
|
|
|
|
165
|
|
|
|
166
|
|
|
|
167
|
|
|
|
168
|
|
|
$reponse = curl_exec($ch); |
169
|
|
|
|
170
|
|
|
if (curl_errno($ch)) { |
171
|
|
|
|
172
|
|
|
throw new Exception(curl_error($ch), 0); |
173
|
|
|
} else { |
174
|
|
|
$httpStatusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); |
175
|
|
|
if (200 !== $httpStatusCode) { |
176
|
|
|
throw new Exception($reponse, $httpStatusCode); |
177
|
|
|
} |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
curl_close($ch); |
181
|
|
|
return $reponse; |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
protected function getMillisecond() { |
185
|
|
|
list($s1, $s2) = explode(' ', microtime()); |
186
|
|
|
return (float)sprintf('%.0f', (floatval($s1) + floatval($s2)) * 1000); |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
|
190
|
|
|
protected function logCommunicationError($apiName, $requestUrl, $errorCode, $responseTxt) { |
191
|
|
|
$localIp = isset ($_SERVER["SERVER_ADDR"]) ? $_SERVER["SERVER_ADDR"] : "CLI"; |
192
|
|
|
$logger = new LtLogger; |
193
|
|
|
$logger->conf["log_file"] = rtrim(AOP_SDK_WORK_DIR, '\\/') . '/' . "logs/aop_comm_err_" . $this->appId . "_" . date("Y-m-d") . ".log"; |
194
|
|
|
$logger->conf["separator"] = "^_^"; |
195
|
|
|
$logData = array( |
196
|
|
|
date("Y-m-d H:i:s"), |
197
|
|
|
$apiName, |
198
|
|
|
$this->appId, |
199
|
|
|
$localIp, |
200
|
|
|
PHP_OS, |
201
|
|
|
$this->alipaySdkVersion, |
202
|
|
|
$requestUrl, |
203
|
|
|
$errorCode, |
204
|
|
|
str_replace("\n", "", $responseTxt) |
205
|
|
|
); |
206
|
|
|
$logger->log($logData); |
207
|
|
|
} |
208
|
|
|
|
209
|
|
|
/** |
210
|
|
|
* 生成用于调用收银台SDK的字符串 |
211
|
|
|
* @param $request SDK接口的请求参数对象 |
212
|
|
|
* @return string |
213
|
|
|
* @author guofa.tgf |
214
|
|
|
*/ |
215
|
|
|
public function sdkExecute($request) { |
216
|
|
|
|
217
|
|
|
$this->setupCharsets($request); |
218
|
|
|
|
219
|
|
|
$params['app_id'] = $this->appId; |
|
|
|
|
220
|
|
|
$params['method'] = $request->getApiMethodName(); |
221
|
|
|
$params['format'] = $this->format; |
222
|
|
|
$params['sign_type'] = $this->signType; |
223
|
|
|
$params['timestamp'] = date("Y-m-d H:i:s"); |
224
|
|
|
$params['alipay_sdk'] = $this->alipaySdkVersion; |
225
|
|
|
$params['charset'] = $this->postCharset; |
226
|
|
|
|
227
|
|
|
$version = $request->getApiVersion(); |
228
|
|
|
$params['version'] = $this->checkEmpty($version) ? $this->apiVersion : $version; |
229
|
|
|
|
230
|
|
|
if ($notify_url = $request->getNotifyUrl()) { |
231
|
|
|
$params['notify_url'] = $notify_url; |
232
|
|
|
} |
233
|
|
|
|
234
|
|
|
$dict = $request->getApiParas(); |
235
|
|
|
$params['biz_content'] = $dict['biz_content']; |
236
|
|
|
|
237
|
|
|
ksort($params); |
238
|
|
|
|
239
|
|
|
$params['sign'] = $this->generateSign($params, $this->signType); |
240
|
|
|
|
241
|
|
|
foreach ($params as &$value) { |
242
|
|
|
$value = $this->characet($value, $params['charset']); |
243
|
|
|
} |
244
|
|
|
|
245
|
|
|
return http_build_query($params); |
246
|
|
|
} |
247
|
|
|
|
248
|
|
|
/* |
249
|
|
|
页面提交执行方法 |
250
|
|
|
@param:跳转类接口的request; $httpmethod 提交方式。两个值可选:post、get |
251
|
|
|
@return:构建好的、签名后的最终跳转URL(GET)或String形式的form(POST) |
252
|
|
|
auther:笙默 |
253
|
|
|
*/ |
254
|
|
|
public function pageExecute($request,$httpmethod = "POST") { |
255
|
|
|
|
256
|
|
|
$this->setupCharsets($request); |
257
|
|
|
|
258
|
|
View Code Duplication |
if (strcasecmp($this->fileCharset, $this->postCharset)) { |
|
|
|
|
259
|
|
|
|
260
|
|
|
// writeLog("本地文件字符集编码与表单提交编码不一致,请务必设置成一样,属性名分别为postCharset!"); |
261
|
|
|
throw new Exception("文件编码:[" . $this->fileCharset . "] 与表单提交编码:[" . $this->postCharset . "]两者不一致!"); |
262
|
|
|
} |
263
|
|
|
|
264
|
|
|
$iv=null; |
|
|
|
|
265
|
|
|
|
266
|
|
|
if(!$this->checkEmpty($request->getApiVersion())){ |
267
|
|
|
$iv=$request->getApiVersion(); |
268
|
|
|
}else{ |
269
|
|
|
$iv=$this->apiVersion; |
270
|
|
|
} |
271
|
|
|
|
272
|
|
|
//组装系统参数 |
273
|
|
|
$sysParams["app_id"] = $this->appId; |
|
|
|
|
274
|
|
|
$sysParams["version"] = $iv; |
275
|
|
|
$sysParams["format"] = $this->format; |
276
|
|
|
$sysParams["sign_type"] = $this->signType; |
277
|
|
|
$sysParams["method"] = $request->getApiMethodName(); |
278
|
|
|
$sysParams["timestamp"] = date("Y-m-d H:i:s"); |
279
|
|
|
$sysParams["alipay_sdk"] = $this->alipaySdkVersion; |
280
|
|
|
$sysParams["terminal_type"] = $request->getTerminalType(); |
281
|
|
|
$sysParams["terminal_info"] = $request->getTerminalInfo(); |
282
|
|
|
$sysParams["prod_code"] = $request->getProdCode(); |
283
|
|
|
$sysParams["notify_url"] = $request->getNotifyUrl(); |
284
|
|
|
$sysParams["return_url"] = $request->getReturnUrl(); |
285
|
|
|
$sysParams["charset"] = $this->postCharset; |
286
|
|
|
|
287
|
|
|
//获取业务参数 |
288
|
|
|
$apiParams = $request->getApiParas(); |
289
|
|
|
|
290
|
|
View Code Duplication |
if (method_exists($request,"getNeedEncrypt") &&$request->getNeedEncrypt()){ |
|
|
|
|
291
|
|
|
|
292
|
|
|
$sysParams["encrypt_type"] = $this->encryptType; |
293
|
|
|
|
294
|
|
|
if ($this->checkEmpty($apiParams['biz_content'])) { |
295
|
|
|
|
296
|
|
|
throw new Exception(" api request Fail! The reason : encrypt request is not supperted!"); |
297
|
|
|
} |
298
|
|
|
|
299
|
|
|
if ($this->checkEmpty($this->encryptKey) || $this->checkEmpty($this->encryptType)) { |
300
|
|
|
|
301
|
|
|
throw new Exception(" encryptType and encryptKey must not null! "); |
302
|
|
|
} |
303
|
|
|
|
304
|
|
|
if ("AES" != $this->encryptType) { |
305
|
|
|
|
306
|
|
|
throw new Exception("加密类型只支持AES"); |
307
|
|
|
} |
308
|
|
|
|
309
|
|
|
// 执行加密 |
310
|
|
|
$enCryptContent = encrypt($apiParams['biz_content'], $this->encryptKey); |
311
|
|
|
$apiParams['biz_content'] = $enCryptContent; |
312
|
|
|
|
313
|
|
|
} |
314
|
|
|
|
315
|
|
|
//print_r($apiParams); |
316
|
|
|
$totalParams = array_merge($apiParams, $sysParams); |
317
|
|
|
|
318
|
|
|
//待签名字符串 |
319
|
|
|
$preSignStr = $this->getSignContent($totalParams); |
320
|
|
|
|
321
|
|
|
//签名 |
322
|
|
|
$totalParams["sign"] = $this->generateSign($totalParams, $this->signType); |
323
|
|
|
|
324
|
|
|
if ("GET" == $httpmethod) { |
325
|
|
|
|
326
|
|
|
//拼接GET请求串 |
327
|
|
|
$requestUrl = $this->gatewayUrl."?".$preSignStr."&sign=".urlencode($totalParams["sign"]); |
328
|
|
|
|
329
|
|
|
return $requestUrl; |
330
|
|
|
} else { |
331
|
|
|
//拼接表单字符串 |
332
|
|
|
return $this->buildRequestForm($totalParams); |
333
|
|
|
} |
334
|
|
|
|
335
|
|
|
|
336
|
|
|
} |
337
|
|
|
|
338
|
|
|
/** |
339
|
|
|
* 建立请求,以表单HTML形式构造(默认) |
340
|
|
|
* @param $para_temp 请求参数数组 |
341
|
|
|
* @return 提交表单HTML文本 |
342
|
|
|
*/ |
343
|
|
|
protected function buildRequestForm($para_temp) { |
344
|
|
|
|
345
|
|
|
$sHtml = "<form id='alipaysubmit' name='alipaysubmit' action='".$this->gatewayUrl."?charset=".trim($this->postCharset)."' method='POST'>"; |
346
|
|
|
while (list ($key, $val) = each ($para_temp)) { |
347
|
|
|
if (false === $this->checkEmpty($val)) { |
348
|
|
|
//$val = $this->characet($val, $this->postCharset); |
349
|
|
|
$val = str_replace("'","'",$val); |
350
|
|
|
//$val = str_replace("\"",""",$val); |
351
|
|
|
$sHtml.= "<input type='hidden' name='".$key."' value='".$val."'/>"; |
352
|
|
|
} |
353
|
|
|
} |
354
|
|
|
|
355
|
|
|
//submit按钮控件请不要含有name属性 |
356
|
|
|
$sHtml = $sHtml."<input type='submit' value='ok' style='display:none;''></form>"; |
357
|
|
|
|
358
|
|
|
$sHtml = $sHtml."<script>document.forms['alipaysubmit'].submit();</script>"; |
359
|
|
|
|
360
|
|
|
return $sHtml; |
361
|
|
|
} |
362
|
|
|
|
363
|
|
|
|
364
|
|
|
public function execute($request, $authToken = null, $appInfoAuthtoken = null) { |
365
|
|
|
|
366
|
|
|
$this->setupCharsets($request); |
367
|
|
|
|
368
|
|
|
// // 如果两者编码不一致,会出现签名验签或者乱码 |
369
|
|
View Code Duplication |
if (strcasecmp($this->fileCharset, $this->postCharset)) { |
|
|
|
|
370
|
|
|
|
371
|
|
|
// writeLog("本地文件字符集编码与表单提交编码不一致,请务必设置成一样,属性名分别为postCharset!"); |
372
|
|
|
throw new Exception("文件编码:[" . $this->fileCharset . "] 与表单提交编码:[" . $this->postCharset . "]两者不一致!"); |
373
|
|
|
} |
374
|
|
|
|
375
|
|
|
$iv = null; |
|
|
|
|
376
|
|
|
|
377
|
|
|
if (!$this->checkEmpty($request->getApiVersion())) { |
378
|
|
|
$iv = $request->getApiVersion(); |
379
|
|
|
} else { |
380
|
|
|
$iv = $this->apiVersion; |
381
|
|
|
} |
382
|
|
|
|
383
|
|
|
|
384
|
|
|
//组装系统参数 |
385
|
|
|
$sysParams["app_id"] = $this->appId; |
|
|
|
|
386
|
|
|
$sysParams["version"] = $iv; |
387
|
|
|
$sysParams["format"] = $this->format; |
388
|
|
|
$sysParams["sign_type"] = $this->signType; |
389
|
|
|
$sysParams["method"] = $request->getApiMethodName(); |
390
|
|
|
$sysParams["timestamp"] = date("Y-m-d H:i:s"); |
391
|
|
|
$sysParams["auth_token"] = $authToken; |
392
|
|
|
$sysParams["alipay_sdk"] = $this->alipaySdkVersion; |
393
|
|
|
$sysParams["terminal_type"] = $request->getTerminalType(); |
394
|
|
|
$sysParams["terminal_info"] = $request->getTerminalInfo(); |
395
|
|
|
$sysParams["prod_code"] = $request->getProdCode(); |
396
|
|
|
$sysParams["notify_url"] = $request->getNotifyUrl(); |
397
|
|
|
$sysParams["charset"] = $this->postCharset; |
398
|
|
|
$sysParams["app_auth_token"] = $appInfoAuthtoken; |
399
|
|
|
|
400
|
|
|
|
401
|
|
|
//获取业务参数 |
402
|
|
|
$apiParams = $request->getApiParas(); |
403
|
|
|
|
404
|
|
View Code Duplication |
if (method_exists($request,"getNeedEncrypt") &&$request->getNeedEncrypt()){ |
|
|
|
|
405
|
|
|
|
406
|
|
|
$sysParams["encrypt_type"] = $this->encryptType; |
407
|
|
|
|
408
|
|
|
if ($this->checkEmpty($apiParams['biz_content'])) { |
409
|
|
|
|
410
|
|
|
throw new Exception(" api request Fail! The reason : encrypt request is not supperted!"); |
411
|
|
|
} |
412
|
|
|
|
413
|
|
|
if ($this->checkEmpty($this->encryptKey) || $this->checkEmpty($this->encryptType)) { |
414
|
|
|
|
415
|
|
|
throw new Exception(" encryptType and encryptKey must not null! "); |
416
|
|
|
} |
417
|
|
|
|
418
|
|
|
if ("AES" != $this->encryptType) { |
419
|
|
|
|
420
|
|
|
throw new Exception("加密类型只支持AES"); |
421
|
|
|
} |
422
|
|
|
|
423
|
|
|
// 执行加密 |
424
|
|
|
$enCryptContent = encrypt($apiParams['biz_content'], $this->encryptKey); |
425
|
|
|
$apiParams['biz_content'] = $enCryptContent; |
426
|
|
|
|
427
|
|
|
} |
428
|
|
|
|
429
|
|
|
|
430
|
|
|
//签名 |
431
|
|
|
$sysParams["sign"] = $this->generateSign(array_merge($apiParams, $sysParams), $this->signType); |
432
|
|
|
|
433
|
|
|
|
434
|
|
|
//系统参数放入GET请求串 |
435
|
|
|
$requestUrl = $this->gatewayUrl . "?"; |
436
|
|
View Code Duplication |
foreach ($sysParams as $sysParamKey => $sysParamValue) { |
|
|
|
|
437
|
|
|
$requestUrl .= "$sysParamKey=" . urlencode($this->characet($sysParamValue, $this->postCharset)) . "&"; |
438
|
|
|
} |
439
|
|
|
$requestUrl = substr($requestUrl, 0, -1); |
440
|
|
|
|
441
|
|
|
|
442
|
|
|
//发起HTTP请求 |
443
|
|
|
try { |
444
|
|
|
$resp = $this->curl($requestUrl, $apiParams); |
445
|
|
|
} catch (Exception $e) { |
446
|
|
|
|
447
|
|
|
$this->logCommunicationError($sysParams["method"], $requestUrl, "HTTP_ERROR_" . $e->getCode(), $e->getMessage()); |
448
|
|
|
return false; |
449
|
|
|
} |
450
|
|
|
|
451
|
|
|
//解析AOP返回结果 |
452
|
|
|
$respWellFormed = false; |
453
|
|
|
|
454
|
|
|
|
455
|
|
|
// 将返回结果转换本地文件编码 |
456
|
|
|
$r = iconv($this->postCharset, $this->fileCharset . "//IGNORE", $resp); |
457
|
|
|
|
458
|
|
|
|
459
|
|
|
|
460
|
|
|
$signData = null; |
461
|
|
|
|
462
|
|
View Code Duplication |
if ("json" == $this->format) { |
|
|
|
|
463
|
|
|
|
464
|
|
|
$respObject = json_decode($r); |
465
|
|
|
if (null !== $respObject) { |
466
|
|
|
$respWellFormed = true; |
467
|
|
|
$signData = $this->parserJSONSignData($request, $resp, $respObject); |
468
|
|
|
} |
469
|
|
|
} else if ("xml" == $this->format) { |
470
|
|
|
|
471
|
|
|
$respObject = @ simplexml_load_string($resp); |
472
|
|
|
if (false !== $respObject) { |
473
|
|
|
$respWellFormed = true; |
474
|
|
|
|
475
|
|
|
$signData = $this->parserXMLSignData($request, $resp); |
476
|
|
|
} |
477
|
|
|
} |
478
|
|
|
|
479
|
|
|
|
480
|
|
|
//返回的HTTP文本不是标准JSON或者XML,记下错误日志 |
481
|
|
|
if (false === $respWellFormed) { |
482
|
|
|
$this->logCommunicationError($sysParams["method"], $requestUrl, "HTTP_RESPONSE_NOT_WELL_FORMED", $resp); |
483
|
|
|
return false; |
484
|
|
|
} |
485
|
|
|
|
486
|
|
|
// 验签 |
487
|
|
|
$this->checkResponseSign($request, $signData, $resp, $respObject); |
|
|
|
|
488
|
|
|
|
489
|
|
|
// 解密 |
490
|
|
View Code Duplication |
if (method_exists($request,"getNeedEncrypt") &&$request->getNeedEncrypt()){ |
|
|
|
|
491
|
|
|
|
492
|
|
|
if ("json" == $this->format) { |
493
|
|
|
|
494
|
|
|
|
495
|
|
|
$resp = $this->encryptJSONSignSource($request, $resp); |
496
|
|
|
|
497
|
|
|
// 将返回结果转换本地文件编码 |
498
|
|
|
$r = iconv($this->postCharset, $this->fileCharset . "//IGNORE", $resp); |
499
|
|
|
$respObject = json_decode($r); |
500
|
|
|
}else{ |
501
|
|
|
|
502
|
|
|
$resp = $this->encryptXMLSignSource($request, $resp); |
503
|
|
|
|
504
|
|
|
$r = iconv($this->postCharset, $this->fileCharset . "//IGNORE", $resp); |
505
|
|
|
$respObject = @ simplexml_load_string($r); |
506
|
|
|
|
507
|
|
|
} |
508
|
|
|
} |
509
|
|
|
|
510
|
|
|
return $respObject; |
511
|
|
|
} |
512
|
|
|
|
513
|
|
|
/** |
514
|
|
|
* 转换字符集编码 |
515
|
|
|
* @param $data |
516
|
|
|
* @param $targetCharset |
517
|
|
|
* @return string |
518
|
|
|
*/ |
519
|
|
|
function characet($data, $targetCharset) { |
|
|
|
|
520
|
|
|
|
521
|
|
|
if (!empty($data)) { |
522
|
|
|
$fileType = $this->fileCharset; |
523
|
|
|
if (strcasecmp($fileType, $targetCharset) != 0) { |
524
|
|
|
$data = mb_convert_encoding($data, $targetCharset, $fileType); |
525
|
|
|
// $data = iconv($fileType, $targetCharset.'//IGNORE', $data); |
526
|
|
|
} |
527
|
|
|
} |
528
|
|
|
|
529
|
|
|
|
530
|
|
|
return $data; |
531
|
|
|
} |
532
|
|
|
|
533
|
|
|
public function exec($paramsArray) { |
534
|
|
|
if (!isset ($paramsArray["method"])) { |
535
|
|
|
trigger_error("No api name passed"); |
536
|
|
|
} |
537
|
|
|
$inflector = new LtInflector; |
538
|
|
|
$inflector->conf["separator"] = "."; |
539
|
|
|
$requestClassName = ucfirst($inflector->camelize(substr($paramsArray["method"], 7))) . "Request"; |
540
|
|
|
if (!class_exists($requestClassName)) { |
541
|
|
|
trigger_error("No such api: " . $paramsArray["method"]); |
542
|
|
|
} |
543
|
|
|
|
544
|
|
|
$session = isset ($paramsArray["session"]) ? $paramsArray["session"] : null; |
545
|
|
|
|
546
|
|
|
$req = new $requestClassName; |
547
|
|
|
foreach ($paramsArray as $paraKey => $paraValue) { |
548
|
|
|
$inflector->conf["separator"] = "_"; |
549
|
|
|
$setterMethodName = $inflector->camelize($paraKey); |
550
|
|
|
$inflector->conf["separator"] = "."; |
551
|
|
|
$setterMethodName = "set" . $inflector->camelize($setterMethodName); |
552
|
|
|
if (method_exists($req, $setterMethodName)) { |
553
|
|
|
$req->$setterMethodName ($paraValue); |
554
|
|
|
} |
555
|
|
|
} |
556
|
|
|
return $this->execute($req, $session); |
557
|
|
|
} |
558
|
|
|
|
559
|
|
|
/** |
560
|
|
|
* 校验$value是否非空 |
561
|
|
|
* if not set ,return true; |
562
|
|
|
* if is null , return true; |
563
|
|
|
**/ |
564
|
|
|
protected function checkEmpty($value) { |
565
|
|
|
if (!isset($value)) |
566
|
|
|
return true; |
567
|
|
|
if ($value === null) |
568
|
|
|
return true; |
569
|
|
|
if (trim($value) === "") |
570
|
|
|
return true; |
571
|
|
|
|
572
|
|
|
return false; |
573
|
|
|
} |
574
|
|
|
|
575
|
|
|
/** rsaCheckV1 & rsaCheckV2 |
576
|
|
|
* 验证签名 |
577
|
|
|
* 在使用本方法前,必须初始化AopClient且传入公钥参数。 |
578
|
|
|
* 公钥是否是读取字符串还是读取文件,是根据初始化传入的值判断的。 |
579
|
|
|
**/ |
580
|
|
View Code Duplication |
public function rsaCheckV1($params, $rsaPublicKeyFilePath,$signType='RSA') { |
|
|
|
|
581
|
|
|
$sign = $params['sign']; |
582
|
|
|
$params['sign_type'] = null; |
583
|
|
|
$params['sign'] = null; |
584
|
|
|
return $this->verify($this->getSignContent($params), $sign, $rsaPublicKeyFilePath,$signType); |
585
|
|
|
} |
586
|
|
View Code Duplication |
public function rsaCheckV2($params, $rsaPublicKeyFilePath, $signType='RSA') { |
|
|
|
|
587
|
|
|
print_r($params); |
588
|
|
|
$sign = $params['sign']; |
589
|
|
|
$params['sign'] = null; |
590
|
|
|
return $this->verify($this->getSignContent($params), $sign, $rsaPublicKeyFilePath, $signType); |
591
|
|
|
} |
592
|
|
|
|
593
|
|
|
function verify($data, $sign, $rsaPublicKeyFilePath, $signType = 'RSA') { |
|
|
|
|
594
|
|
|
|
595
|
|
View Code Duplication |
if($this->checkEmpty($this->alipayPublicKey)){ |
|
|
|
|
596
|
|
|
|
597
|
|
|
$pubKey= $this->alipayrsaPublicKey; |
598
|
|
|
$res = "-----BEGIN PUBLIC KEY-----\n" . |
599
|
|
|
wordwrap($pubKey, 64, "\n", true) . |
600
|
|
|
"\n-----END PUBLIC KEY-----"; |
601
|
|
|
}else { |
602
|
|
|
//读取公钥文件 |
603
|
|
|
$pubKey = file_get_contents($rsaPublicKeyFilePath); |
604
|
|
|
//转换为openssl格式密钥 |
605
|
|
|
$res = openssl_get_publickey($pubKey); |
606
|
|
|
} |
607
|
|
|
|
608
|
|
|
($res) or die('支付宝RSA公钥错误。请检查公钥文件格式是否正确'); |
609
|
|
|
|
610
|
|
|
//调用openssl内置方法验签,返回bool值 |
611
|
|
|
|
612
|
|
|
if ("RSA2" == $signType) { |
613
|
|
|
$result = (bool)openssl_verify($data, base64_decode($sign), $res, OPENSSL_ALGO_SHA256); |
614
|
|
|
} else { |
615
|
|
|
$result = (bool)openssl_verify($data, base64_decode($sign), $res); |
616
|
|
|
} |
617
|
|
|
|
618
|
|
|
if(!$this->checkEmpty($this->alipayPublicKey)) { |
619
|
|
|
//释放资源 |
620
|
|
|
openssl_free_key($res); |
621
|
|
|
} |
622
|
|
|
|
623
|
|
|
return $result; |
624
|
|
|
} |
625
|
|
|
|
626
|
|
|
public function checkSignAndDecrypt($params, $rsaPublicKeyPem, $rsaPrivateKeyPem, $isCheckSign, $isDecrypt) { |
627
|
|
|
$charset = $params['charset']; |
628
|
|
|
$bizContent = $params['biz_content']; |
629
|
|
|
if ($isCheckSign) { |
630
|
|
|
if (!$this->rsaCheckV2($params, $rsaPublicKeyPem)) { |
631
|
|
|
echo "<br/>checkSign failure<br/>"; |
632
|
|
|
exit; |
633
|
|
|
} |
634
|
|
|
} |
635
|
|
|
if ($isDecrypt) { |
636
|
|
|
return $this->rsaDecrypt($bizContent, $rsaPrivateKeyPem, $charset); |
637
|
|
|
} |
638
|
|
|
|
639
|
|
|
return $bizContent; |
640
|
|
|
} |
641
|
|
|
|
642
|
|
|
public function encryptAndSign($bizContent, $rsaPublicKeyPem, $rsaPrivateKeyPem, $charset, $isEncrypt, $isSign) { |
|
|
|
|
643
|
|
|
// 加密,并签名 |
644
|
|
|
if ($isEncrypt && $isSign) { |
645
|
|
|
$encrypted = $this->rsaEncrypt($bizContent, $rsaPublicKeyPem, $charset); |
646
|
|
|
$sign = $this->sign($bizContent); |
647
|
|
|
$response = "<?xml version=\"1.0\" encoding=\"$charset\"?><alipay><response>$encrypted</response><encryption_type>RSA</encryption_type><sign>$sign</sign><sign_type>RSA</sign_type></alipay>"; |
648
|
|
|
return $response; |
649
|
|
|
} |
650
|
|
|
// 加密,不签名 |
651
|
|
|
if ($isEncrypt && (!$isSign)) { |
652
|
|
|
$encrypted = $this->rsaEncrypt($bizContent, $rsaPublicKeyPem, $charset); |
653
|
|
|
$response = "<?xml version=\"1.0\" encoding=\"$charset\"?><alipay><response>$encrypted</response><encryption_type>RSA</encryption_type></alipay>"; |
654
|
|
|
return $response; |
655
|
|
|
} |
656
|
|
|
// 不加密,但签名 |
657
|
|
|
if ((!$isEncrypt) && $isSign) { |
658
|
|
|
$sign = $this->sign($bizContent); |
659
|
|
|
$response = "<?xml version=\"1.0\" encoding=\"$charset\"?><alipay><response>$bizContent</response><sign>$sign</sign><sign_type>RSA</sign_type></alipay>"; |
660
|
|
|
return $response; |
661
|
|
|
} |
662
|
|
|
// 不加密,不签名 |
663
|
|
|
$response = "<?xml version=\"1.0\" encoding=\"$charset\"?>$bizContent"; |
664
|
|
|
return $response; |
665
|
|
|
} |
666
|
|
|
|
667
|
|
|
public function rsaEncrypt($data, $rsaPublicKeyPem, $charset) { |
668
|
|
|
//读取公钥文件 |
669
|
|
|
$pubKey = file_get_contents($rsaPublicKeyPem); |
670
|
|
|
//转换为openssl格式密钥 |
671
|
|
|
$res = openssl_get_publickey($pubKey); |
672
|
|
|
$blocks = $this->splitCN($data, 0, 30, $charset); |
673
|
|
|
$chrtext = null; |
674
|
|
|
$encodes = array(); |
|
|
|
|
675
|
|
|
foreach ($blocks as $n => $block) { |
676
|
|
|
if (!openssl_public_encrypt($block, $chrtext , $res)) { |
677
|
|
|
echo "<br/>" . openssl_error_string() . "<br/>"; |
678
|
|
|
} |
679
|
|
|
$encodes[] = $chrtext ; |
|
|
|
|
680
|
|
|
} |
681
|
|
|
$chrtext = implode(",", $encodes); |
|
|
|
|
682
|
|
|
|
683
|
|
|
return $chrtext; |
684
|
|
|
} |
685
|
|
|
|
686
|
|
|
public function rsaDecrypt($data, $rsaPrivateKeyPem, $charset) { |
|
|
|
|
687
|
|
|
//读取私钥文件 |
688
|
|
|
$priKey = file_get_contents($rsaPrivateKeyPem); |
689
|
|
|
//转换为openssl格式密钥 |
690
|
|
|
$res = openssl_get_privatekey($priKey); |
691
|
|
|
$decodes = explode(',', $data); |
692
|
|
|
$strnull = ""; |
693
|
|
|
$dcyCont = ""; |
694
|
|
|
foreach ($decodes as $n => $decode) { |
695
|
|
|
if (!openssl_private_decrypt($decode, $dcyCont, $res)) { |
696
|
|
|
echo "<br/>" . openssl_error_string() . "<br/>"; |
697
|
|
|
} |
698
|
|
|
$strnull .= $dcyCont; |
699
|
|
|
} |
700
|
|
|
return $strnull; |
701
|
|
|
} |
702
|
|
|
|
703
|
|
|
function splitCN($cont, $n = 0, $subnum, $charset) { |
|
|
|
|
704
|
|
|
//$len = strlen($cont) / 3; |
705
|
|
|
$arrr = array(); |
706
|
|
|
for ($i = $n; $i < strlen($cont); $i += $subnum) { |
707
|
|
|
$res = $this->subCNchar($cont, $i, $subnum, $charset); |
708
|
|
|
if (!empty ($res)) { |
709
|
|
|
$arrr[] = $res; |
710
|
|
|
} |
711
|
|
|
} |
712
|
|
|
|
713
|
|
|
return $arrr; |
714
|
|
|
} |
715
|
|
|
|
716
|
|
|
function subCNchar($str, $start = 0, $length, $charset = "gbk") { |
|
|
|
|
717
|
|
|
if (strlen($str) <= $length) { |
718
|
|
|
return $str; |
719
|
|
|
} |
720
|
|
|
$re['utf-8'] = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xff][\x80-\xbf]{3}/"; |
|
|
|
|
721
|
|
|
$re['gb2312'] = "/[\x01-\x7f]|[\xb0-\xf7][\xa0-\xfe]/"; |
722
|
|
|
$re['gbk'] = "/[\x01-\x7f]|[\x81-\xfe][\x40-\xfe]/"; |
723
|
|
|
$re['big5'] = "/[\x01-\x7f]|[\x81-\xfe]([\x40-\x7e]|\xa1-\xfe])/"; |
724
|
|
|
preg_match_all($re[$charset], $str, $match); |
725
|
|
|
$slice = join("", array_slice($match[0], $start, $length)); |
726
|
|
|
return $slice; |
727
|
|
|
} |
728
|
|
|
|
729
|
|
|
function parserResponseSubCode($request, $responseContent, $respObject, $format) { |
|
|
|
|
730
|
|
|
|
731
|
|
|
if ("json" == $format) { |
732
|
|
|
|
733
|
|
|
$apiName = $request->getApiMethodName(); |
734
|
|
|
$rootNodeName = str_replace(".", "_", $apiName) . $this->RESPONSE_SUFFIX; |
735
|
|
|
$errorNodeName = $this->ERROR_RESPONSE; |
736
|
|
|
|
737
|
|
|
$rootIndex = strpos($responseContent, $rootNodeName); |
738
|
|
|
$errorIndex = strpos($responseContent, $errorNodeName); |
739
|
|
|
|
740
|
|
|
if ($rootIndex > 0) { |
741
|
|
|
// 内部节点对象 |
742
|
|
|
$rInnerObject = $respObject->$rootNodeName; |
743
|
|
|
} elseif ($errorIndex > 0) { |
744
|
|
|
|
745
|
|
|
$rInnerObject = $respObject->$errorNodeName; |
746
|
|
|
} else { |
747
|
|
|
return null; |
748
|
|
|
} |
749
|
|
|
|
750
|
|
|
// 存在属性则返回对应值 |
751
|
|
|
if (isset($rInnerObject->sub_code)) { |
752
|
|
|
|
753
|
|
|
return $rInnerObject->sub_code; |
754
|
|
|
} else { |
755
|
|
|
|
756
|
|
|
return null; |
757
|
|
|
} |
758
|
|
|
|
759
|
|
|
|
760
|
|
|
} elseif ("xml" == $format) { |
761
|
|
|
|
762
|
|
|
// xml格式sub_code在同一层级 |
763
|
|
|
return $respObject->sub_code; |
764
|
|
|
|
765
|
|
|
} |
766
|
|
|
|
767
|
|
|
|
768
|
|
|
} |
769
|
|
|
|
770
|
|
|
function parserJSONSignData($request, $responseContent, $responseJSON) { |
|
|
|
|
771
|
|
|
|
772
|
|
|
$signData = new SignData(); |
773
|
|
|
|
774
|
|
|
$signData->sign = $this->parserJSONSign($responseJSON); |
775
|
|
|
$signData->signSourceData = $this->parserJSONSignSource($request, $responseContent); |
776
|
|
|
|
777
|
|
|
|
778
|
|
|
return $signData; |
779
|
|
|
|
780
|
|
|
} |
781
|
|
|
|
782
|
|
View Code Duplication |
function parserJSONSignSource($request, $responseContent) { |
|
|
|
|
783
|
|
|
|
784
|
|
|
$apiName = $request->getApiMethodName(); |
785
|
|
|
$rootNodeName = str_replace(".", "_", $apiName) . $this->RESPONSE_SUFFIX; |
786
|
|
|
|
787
|
|
|
$rootIndex = strpos($responseContent, $rootNodeName); |
788
|
|
|
$errorIndex = strpos($responseContent, $this->ERROR_RESPONSE); |
789
|
|
|
|
790
|
|
|
|
791
|
|
|
if ($rootIndex > 0) { |
792
|
|
|
|
793
|
|
|
return $this->parserJSONSource($responseContent, $rootNodeName, $rootIndex); |
794
|
|
|
} else if ($errorIndex > 0) { |
795
|
|
|
|
796
|
|
|
return $this->parserJSONSource($responseContent, $this->ERROR_RESPONSE, $errorIndex); |
797
|
|
|
} else { |
798
|
|
|
|
799
|
|
|
return null; |
800
|
|
|
} |
801
|
|
|
|
802
|
|
|
|
803
|
|
|
} |
804
|
|
|
|
805
|
|
View Code Duplication |
function parserJSONSource($responseContent, $nodeName, $nodeIndex) { |
|
|
|
|
806
|
|
|
$signDataStartIndex = $nodeIndex + strlen($nodeName) + 2; |
807
|
|
|
$signIndex = strpos($responseContent, "\"" . $this->SIGN_NODE_NAME . "\""); |
808
|
|
|
// 签名前-逗号 |
809
|
|
|
$signDataEndIndex = $signIndex - 1; |
810
|
|
|
$indexLen = $signDataEndIndex - $signDataStartIndex; |
811
|
|
|
if ($indexLen < 0) { |
812
|
|
|
|
813
|
|
|
return null; |
814
|
|
|
} |
815
|
|
|
|
816
|
|
|
return substr($responseContent, $signDataStartIndex, $indexLen); |
817
|
|
|
|
818
|
|
|
} |
819
|
|
|
|
820
|
|
|
function parserJSONSign($responseJSon) { |
|
|
|
|
821
|
|
|
|
822
|
|
|
return $responseJSon->sign; |
823
|
|
|
} |
824
|
|
|
|
825
|
|
|
function parserXMLSignData($request, $responseContent) { |
|
|
|
|
826
|
|
|
|
827
|
|
|
|
828
|
|
|
$signData = new SignData(); |
829
|
|
|
|
830
|
|
|
$signData->sign = $this->parserXMLSign($responseContent); |
831
|
|
|
$signData->signSourceData = $this->parserXMLSignSource($request, $responseContent); |
832
|
|
|
|
833
|
|
|
|
834
|
|
|
return $signData; |
835
|
|
|
|
836
|
|
|
|
837
|
|
|
} |
838
|
|
|
|
839
|
|
View Code Duplication |
function parserXMLSignSource($request, $responseContent) { |
|
|
|
|
840
|
|
|
|
841
|
|
|
|
842
|
|
|
$apiName = $request->getApiMethodName(); |
843
|
|
|
$rootNodeName = str_replace(".", "_", $apiName) . $this->RESPONSE_SUFFIX; |
844
|
|
|
|
845
|
|
|
|
846
|
|
|
$rootIndex = strpos($responseContent, $rootNodeName); |
847
|
|
|
$errorIndex = strpos($responseContent, $this->ERROR_RESPONSE); |
848
|
|
|
// $this->echoDebug("<br/>rootNodeName:" . $rootNodeName); |
849
|
|
|
// $this->echoDebug("<br/> responseContent:<xmp>" . $responseContent . "</xmp>"); |
850
|
|
|
|
851
|
|
|
|
852
|
|
|
if ($rootIndex > 0) { |
853
|
|
|
|
854
|
|
|
return $this->parserXMLSource($responseContent, $rootNodeName, $rootIndex); |
855
|
|
|
} else if ($errorIndex > 0) { |
856
|
|
|
|
857
|
|
|
return $this->parserXMLSource($responseContent, $this->ERROR_RESPONSE, $errorIndex); |
858
|
|
|
} else { |
859
|
|
|
|
860
|
|
|
return null; |
861
|
|
|
} |
862
|
|
|
|
863
|
|
|
|
864
|
|
|
} |
865
|
|
|
|
866
|
|
View Code Duplication |
function parserXMLSource($responseContent, $nodeName, $nodeIndex) { |
|
|
|
|
867
|
|
|
$signDataStartIndex = $nodeIndex + strlen($nodeName) + 1; |
868
|
|
|
$signIndex = strpos($responseContent, "<" . $this->SIGN_NODE_NAME . ">"); |
869
|
|
|
// 签名前-逗号 |
870
|
|
|
$signDataEndIndex = $signIndex - 1; |
871
|
|
|
$indexLen = $signDataEndIndex - $signDataStartIndex + 1; |
872
|
|
|
|
873
|
|
|
if ($indexLen < 0) { |
874
|
|
|
return null; |
875
|
|
|
} |
876
|
|
|
|
877
|
|
|
|
878
|
|
|
return substr($responseContent, $signDataStartIndex, $indexLen); |
879
|
|
|
|
880
|
|
|
|
881
|
|
|
} |
882
|
|
|
|
883
|
|
|
function parserXMLSign($responseContent) { |
|
|
|
|
884
|
|
|
$signNodeName = "<" . $this->SIGN_NODE_NAME . ">"; |
885
|
|
|
$signEndNodeName = "</" . $this->SIGN_NODE_NAME . ">"; |
886
|
|
|
|
887
|
|
|
$indexOfSignNode = strpos($responseContent, $signNodeName); |
888
|
|
|
$indexOfSignEndNode = strpos($responseContent, $signEndNodeName); |
889
|
|
|
|
890
|
|
|
|
891
|
|
|
if ($indexOfSignNode < 0 || $indexOfSignEndNode < 0) { |
892
|
|
|
return null; |
893
|
|
|
} |
894
|
|
|
|
895
|
|
|
$nodeIndex = ($indexOfSignNode + strlen($signNodeName)); |
896
|
|
|
|
897
|
|
|
$indexLen = $indexOfSignEndNode - $nodeIndex; |
898
|
|
|
|
899
|
|
|
if ($indexLen < 0) { |
900
|
|
|
return null; |
901
|
|
|
} |
902
|
|
|
|
903
|
|
|
// 签名 |
904
|
|
|
return substr($responseContent, $nodeIndex, $indexLen); |
905
|
|
|
|
906
|
|
|
} |
907
|
|
|
|
908
|
|
|
/** |
909
|
|
|
* 验签 |
910
|
|
|
* @param $request |
911
|
|
|
* @param $signData |
912
|
|
|
* @param $resp |
913
|
|
|
* @param $respObject |
914
|
|
|
* @throws Exception |
915
|
|
|
*/ |
916
|
|
|
public function checkResponseSign($request, $signData, $resp, $respObject) { |
917
|
|
|
|
918
|
|
|
if (!$this->checkEmpty($this->alipayPublicKey) || !$this->checkEmpty($this->alipayrsaPublicKey)) { |
919
|
|
|
|
920
|
|
|
|
921
|
|
|
if ($signData == null || $this->checkEmpty($signData->sign) || $this->checkEmpty($signData->signSourceData)) { |
922
|
|
|
|
923
|
|
|
throw new Exception(" check sign Fail! The reason : signData is Empty"); |
924
|
|
|
} |
925
|
|
|
|
926
|
|
|
|
927
|
|
|
// 获取结果sub_code |
928
|
|
|
$responseSubCode = $this->parserResponseSubCode($request, $resp, $respObject, $this->format); |
929
|
|
|
|
930
|
|
|
|
931
|
|
|
if (!$this->checkEmpty($responseSubCode) || ($this->checkEmpty($responseSubCode) && !$this->checkEmpty($signData->sign))) { |
932
|
|
|
|
933
|
|
|
$checkResult = $this->verify($signData->signSourceData, $signData->sign, $this->alipayPublicKey, $this->signType); |
934
|
|
|
|
935
|
|
|
|
936
|
|
|
if (!$checkResult) { |
937
|
|
|
|
938
|
|
|
if (strpos($signData->signSourceData, "\\/") > 0) { |
939
|
|
|
|
940
|
|
|
$signData->signSourceData = str_replace("\\/", "/", $signData->signSourceData); |
941
|
|
|
|
942
|
|
|
$checkResult = $this->verify($signData->signSourceData, $signData->sign, $this->alipayPublicKey, $this->signType); |
943
|
|
|
|
944
|
|
|
if (!$checkResult) { |
945
|
|
|
throw new Exception("check sign Fail! [sign=" . $signData->sign . ", signSourceData=" . $signData->signSourceData . "]"); |
946
|
|
|
} |
947
|
|
|
|
948
|
|
|
} else { |
949
|
|
|
|
950
|
|
|
throw new Exception("check sign Fail! [sign=" . $signData->sign . ", signSourceData=" . $signData->signSourceData . "]"); |
951
|
|
|
} |
952
|
|
|
|
953
|
|
|
} |
954
|
|
|
} |
955
|
|
|
|
956
|
|
|
|
957
|
|
|
} |
958
|
|
|
} |
959
|
|
|
|
960
|
|
|
protected function setupCharsets($request) { |
961
|
|
|
if ($this->checkEmpty($this->postCharset)) { |
962
|
|
|
$this->postCharset = 'UTF-8'; |
963
|
|
|
} |
964
|
|
|
$str = preg_match('/[\x80-\xff]/', $this->appId) ? $this->appId : print_r($request, true); |
965
|
|
|
$this->fileCharset = mb_detect_encoding($str, "UTF-8, GBK") == 'UTF-8' ? 'UTF-8' : 'GBK'; |
966
|
|
|
} |
967
|
|
|
|
968
|
|
|
// 获取加密内容 |
969
|
|
|
|
970
|
|
View Code Duplication |
protected function encryptJSONSignSource($request, $responseContent) { |
|
|
|
|
971
|
|
|
|
972
|
|
|
$parsetItem = $this->parserEncryptJSONSignSource($request, $responseContent); |
973
|
|
|
|
974
|
|
|
$bodyIndexContent = substr($responseContent, 0, $parsetItem->startIndex); |
975
|
|
|
$bodyEndContent = substr($responseContent, $parsetItem->endIndex, strlen($responseContent) + 1 - $parsetItem->endIndex); |
976
|
|
|
|
977
|
|
|
$bizContent = decrypt($parsetItem->encryptContent, $this->encryptKey); |
978
|
|
|
return $bodyIndexContent . $bizContent . $bodyEndContent; |
979
|
|
|
|
980
|
|
|
} |
981
|
|
|
|
982
|
|
|
|
983
|
|
View Code Duplication |
private function parserEncryptJSONSignSource($request, $responseContent) { |
|
|
|
|
984
|
|
|
|
985
|
|
|
$apiName = $request->getApiMethodName(); |
986
|
|
|
$rootNodeName = str_replace(".", "_", $apiName) . $this->RESPONSE_SUFFIX; |
987
|
|
|
|
988
|
|
|
$rootIndex = strpos($responseContent, $rootNodeName); |
989
|
|
|
$errorIndex = strpos($responseContent, $this->ERROR_RESPONSE); |
990
|
|
|
|
991
|
|
|
|
992
|
|
|
if ($rootIndex > 0) { |
993
|
|
|
|
994
|
|
|
return $this->parserEncryptJSONItem($responseContent, $rootNodeName, $rootIndex); |
995
|
|
|
} else if ($errorIndex > 0) { |
996
|
|
|
|
997
|
|
|
return $this->parserEncryptJSONItem($responseContent, $this->ERROR_RESPONSE, $errorIndex); |
998
|
|
|
} else { |
999
|
|
|
|
1000
|
|
|
return null; |
1001
|
|
|
} |
1002
|
|
|
|
1003
|
|
|
|
1004
|
|
|
} |
1005
|
|
|
|
1006
|
|
|
|
1007
|
|
|
private function parserEncryptJSONItem($responseContent, $nodeName, $nodeIndex) { |
1008
|
|
|
$signDataStartIndex = $nodeIndex + strlen($nodeName) + 2; |
1009
|
|
|
$signIndex = strpos($responseContent, "\"" . $this->SIGN_NODE_NAME . "\""); |
1010
|
|
|
// 签名前-逗号 |
1011
|
|
|
$signDataEndIndex = $signIndex - 1; |
1012
|
|
|
|
1013
|
|
|
if ($signDataEndIndex < 0) { |
1014
|
|
|
|
1015
|
|
|
$signDataEndIndex = strlen($responseContent)-1 ; |
1016
|
|
|
} |
1017
|
|
|
|
1018
|
|
|
$indexLen = $signDataEndIndex - $signDataStartIndex; |
1019
|
|
|
|
1020
|
|
|
$encContent = substr($responseContent, $signDataStartIndex+1, $indexLen-2); |
1021
|
|
|
|
1022
|
|
|
|
1023
|
|
|
$encryptParseItem = new EncryptParseItem(); |
1024
|
|
|
|
1025
|
|
|
$encryptParseItem->encryptContent = $encContent; |
1026
|
|
|
$encryptParseItem->startIndex = $signDataStartIndex; |
1027
|
|
|
$encryptParseItem->endIndex = $signDataEndIndex; |
1028
|
|
|
|
1029
|
|
|
return $encryptParseItem; |
1030
|
|
|
|
1031
|
|
|
} |
1032
|
|
|
|
1033
|
|
|
// 获取加密内容 |
1034
|
|
|
|
1035
|
|
View Code Duplication |
protected function encryptXMLSignSource($request, $responseContent) { |
|
|
|
|
1036
|
|
|
|
1037
|
|
|
$parsetItem = $this->parserEncryptXMLSignSource($request, $responseContent); |
1038
|
|
|
|
1039
|
|
|
$bodyIndexContent = substr($responseContent, 0, $parsetItem->startIndex); |
1040
|
|
|
$bodyEndContent = substr($responseContent, $parsetItem->endIndex, strlen($responseContent) + 1 - $parsetItem->endIndex); |
1041
|
|
|
$bizContent = decrypt($parsetItem->encryptContent, $this->encryptKey); |
1042
|
|
|
|
1043
|
|
|
return $bodyIndexContent . $bizContent . $bodyEndContent; |
1044
|
|
|
|
1045
|
|
|
} |
1046
|
|
|
|
1047
|
|
View Code Duplication |
private function parserEncryptXMLSignSource($request, $responseContent) { |
|
|
|
|
1048
|
|
|
|
1049
|
|
|
|
1050
|
|
|
$apiName = $request->getApiMethodName(); |
1051
|
|
|
$rootNodeName = str_replace(".", "_", $apiName) . $this->RESPONSE_SUFFIX; |
1052
|
|
|
|
1053
|
|
|
|
1054
|
|
|
$rootIndex = strpos($responseContent, $rootNodeName); |
1055
|
|
|
$errorIndex = strpos($responseContent, $this->ERROR_RESPONSE); |
1056
|
|
|
// $this->echoDebug("<br/>rootNodeName:" . $rootNodeName); |
1057
|
|
|
// $this->echoDebug("<br/> responseContent:<xmp>" . $responseContent . "</xmp>"); |
1058
|
|
|
|
1059
|
|
|
|
1060
|
|
|
if ($rootIndex > 0) { |
1061
|
|
|
|
1062
|
|
|
return $this->parserEncryptXMLItem($responseContent, $rootNodeName, $rootIndex); |
1063
|
|
|
} else if ($errorIndex > 0) { |
1064
|
|
|
|
1065
|
|
|
return $this->parserEncryptXMLItem($responseContent, $this->ERROR_RESPONSE, $errorIndex); |
1066
|
|
|
} else { |
1067
|
|
|
|
1068
|
|
|
return null; |
1069
|
|
|
} |
1070
|
|
|
|
1071
|
|
|
|
1072
|
|
|
} |
1073
|
|
|
|
1074
|
|
|
private function parserEncryptXMLItem($responseContent, $nodeName, $nodeIndex) { |
1075
|
|
|
|
1076
|
|
|
$signDataStartIndex = $nodeIndex + strlen($nodeName) + 1; |
1077
|
|
|
|
1078
|
|
|
$xmlStartNode="<".$this->ENCRYPT_XML_NODE_NAME.">"; |
1079
|
|
|
$xmlEndNode="</".$this->ENCRYPT_XML_NODE_NAME.">"; |
1080
|
|
|
|
1081
|
|
|
$indexOfXmlNode=strpos($responseContent,$xmlEndNode); |
1082
|
|
|
if($indexOfXmlNode<0){ |
1083
|
|
|
|
1084
|
|
|
$item = new EncryptParseItem(); |
1085
|
|
|
$item->encryptContent = null; |
1086
|
|
|
$item->startIndex = 0; |
1087
|
|
|
$item->endIndex = 0; |
1088
|
|
|
return $item; |
1089
|
|
|
} |
1090
|
|
|
|
1091
|
|
|
$startIndex=$signDataStartIndex+strlen($xmlStartNode); |
1092
|
|
|
$bizContentLen=$indexOfXmlNode-$startIndex; |
1093
|
|
|
$bizContent=substr($responseContent,$startIndex,$bizContentLen); |
1094
|
|
|
|
1095
|
|
|
$encryptParseItem = new EncryptParseItem(); |
1096
|
|
|
$encryptParseItem->encryptContent = $bizContent; |
1097
|
|
|
$encryptParseItem->startIndex = $signDataStartIndex; |
1098
|
|
|
$encryptParseItem->endIndex = $indexOfXmlNode+strlen($xmlEndNode); |
1099
|
|
|
|
1100
|
|
|
return $encryptParseItem; |
1101
|
|
|
|
1102
|
|
|
} |
1103
|
|
|
|
1104
|
|
|
|
1105
|
|
|
function echoDebug($content) { |
|
|
|
|
1106
|
|
|
|
1107
|
|
|
if ($this->debugInfo) { |
1108
|
|
|
echo "<br/>" . $content; |
1109
|
|
|
} |
1110
|
|
|
|
1111
|
|
|
} |
1112
|
|
|
|
1113
|
|
|
|
1114
|
|
|
} |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.