Completed
Push — master ( c52910...66a65c )
by lyu
02:53 queued 47s
created

AopClient::pageExecute()   C

Complexity

Conditions 10
Paths 15

Size

Total Lines 83

Duplication

Lines 29
Ratio 34.94 %

Code Coverage

Tests 0
CRAP Score 110

Importance

Changes 0
Metric Value
cc 10
nc 15
nop 2
dl 29
loc 83
ccs 0
cts 49
cp 0
crap 110
rs 6.5042
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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)){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
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;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $params = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
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)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
259
260
			// writeLog("本地文件字符集编码与表单提交编码不一致,请务必设置成一样,属性名分别为postCharset!");
261
			throw new Exception("文件编码:[" . $this->fileCharset . "] 与表单提交编码:[" . $this->postCharset . "]两者不一致!");
262
		}
263
264
		$iv=null;
0 ignored issues
show
Unused Code introduced by
$iv is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
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;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$sysParams was never initialized. Although not strictly required by PHP, it is generally a good practice to add $sysParams = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
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()){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
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("'","&apos;",$val);
350
				//$val = str_replace("\"","&quot;",$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)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
370
371
			// writeLog("本地文件字符集编码与表单提交编码不一致,请务必设置成一样,属性名分别为postCharset!");
372
			throw new Exception("文件编码:[" . $this->fileCharset . "] 与表单提交编码:[" . $this->postCharset . "]两者不一致!");
373
		}
374
375
		$iv = null;
0 ignored issues
show
Unused Code introduced by
$iv is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
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;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$sysParams was never initialized. Although not strictly required by PHP, it is generally a good practice to add $sysParams = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
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()){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
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);
0 ignored issues
show
Bug introduced by
The variable $respObject does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
488
489
		// 解密
490 View Code Duplication
		if (method_exists($request,"getNeedEncrypt") &&$request->getNeedEncrypt()){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
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) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
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') {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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') {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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') {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
594
595 View Code Duplication
		if($this->checkEmpty($this->alipayPublicKey)){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
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) {
0 ignored issues
show
Unused Code introduced by
The parameter $rsaPrivateKeyPem is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
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();
0 ignored issues
show
Unused Code introduced by
$encodes  is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
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 ;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$encodes was never initialized. Although not strictly required by PHP, it is generally a good practice to add $encodes = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
680
		}
681
		$chrtext = implode(",", $encodes);
0 ignored issues
show
Bug introduced by
The variable $encodes does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
682
683
		return $chrtext;
684
	}
685
686
	public function rsaDecrypt($data, $rsaPrivateKeyPem, $charset) {
0 ignored issues
show
Unused Code introduced by
The parameter $charset is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
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) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
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") {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
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}/";
0 ignored issues
show
Coding Style Comprehensibility introduced by
$re was never initialized. Although not strictly required by PHP, it is generally a good practice to add $re = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
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) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
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) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
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) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
821
822
		return $responseJSon->sign;
823
	}
824
825
	function parserXMLSignData($request, $responseContent) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
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) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1106
1107
		if ($this->debugInfo) {
1108
			echo "<br/>" . $content;
1109
		}
1110
1111
	}
1112
1113
1114
}