Passed
Push — v6 ( 95b370...25ce72 )
by 光春
03:13
created

SpiUtils::logCommunicationError()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 11
c 1
b 0
f 0
nc 2
nop 4
dl 0
loc 14
rs 9.9
1
<?php
2
class SpiUtils{
3
	private static $top_sign_list = "HTTP_TOP_SIGN_LIST";
0 ignored issues
show
introduced by
The private property $top_sign_list is not used, and could be removed.
Loading history...
4
	private static $timestamp = "timestamp";
0 ignored issues
show
introduced by
The private property $timestamp is not used, and could be removed.
Loading history...
5
	private static $header_real_ip = array("X_Real_IP", "X_Forwarded_For", "Proxy_Client_IP",
0 ignored issues
show
introduced by
The private property $header_real_ip is not used, and could be removed.
Loading history...
6
											"WL_Proxy_Client_IP", "HTTP_CLIENT_IP", "HTTP_X_FORWARDED_FOR");
7
	/**
8
	 * 校验SPI请求签名,适用于所有GET请求,及不包含文件参数的POST请求。
9
	 * 
10
	 * @param request 请求对象
0 ignored issues
show
Documentation Bug introduced by
The doc comment 请求对象 at position 0 could not be parsed: Unknown type name '请求对象' at position 0 in 请求对象.
Loading history...
11
	 * @param secret app对应的secret
12
	 * @return true:校验通过;false:校验不通过
0 ignored issues
show
Documentation Bug introduced by
The doc comment true:校验通过;false:校验不通过 at position 0 could not be parsed: Unknown type name 'true:校验通过;false:校验不通过' at position 0 in true:校验通过;false:校验不通过.
Loading history...
13
	 */
14
	public static function checkSign4FormRequest($secret){
15
		return self::checkSign(null,null,$secret);
16
	}
17
18
	/**
19
	 * 校验SPI请求签名,适用于请求体是xml/json等可用文本表示的POST请求。
20
	 * 
21
	 * @param request 请求对象
0 ignored issues
show
Documentation Bug introduced by
The doc comment 请求对象 at position 0 could not be parsed: Unknown type name '请求对象' at position 0 in 请求对象.
Loading history...
22
	 * @param body 请求体的文本内容
23
	 * @param secret app对应的secret
24
	 * @return true:校验通过;false:校验不通过
0 ignored issues
show
Documentation Bug introduced by
The doc comment true:校验通过;false:校验不通过 at position 0 could not be parsed: Unknown type name 'true:校验通过;false:校验不通过' at position 0 in true:校验通过;false:校验不通过.
Loading history...
25
	 */
26
	public static function checkSign4TextRequest($body,$secret){
27
		return self::checkSign(null,$body,$secret);
28
	}
29
	
30
	/**
31
	 * 校验SPI请求签名,适用于带文件上传的POST请求。
32
	 * 
33
	 * @param request 请求对象
0 ignored issues
show
Documentation Bug introduced by
The doc comment 请求对象 at position 0 could not be parsed: Unknown type name '请求对象' at position 0 in 请求对象.
Loading history...
34
	 * @param form 除了文件参数以外的所有普通文本参数的map集合
35
	 * @param secret app对应的secret
36
	 * @return true:校验通过;false:校验不通过
0 ignored issues
show
Documentation Bug introduced by
The doc comment true:校验通过;false:校验不通过 at position 0 could not be parsed: Unknown type name 'true:校验通过;false:校验不通过' at position 0 in true:校验通过;false:校验不通过.
Loading history...
37
	 */
38
	public static function checkSign4FileRequest($form, $secret){
39
		return self::checkSign($form, null, $secret);
40
	}
41
42
	private static function checkSign($form, $body, $secret) {
43
		$params = array();
44
		// 1. 获取header参数
45
		$headerMap = self::getHeaderMap();
46
		foreach ($headerMap as $k => $v){
47
			$params[$k] = $v ;
48
		}
49
50
		// 2. 获取url参数
51
		$queryMap = self::getQueryMap();
52
		foreach ($queryMap as $k => $v){
53
			$params[$k] = $v ;
54
		}
55
56
		// 3. 获取form参数
57
		if ($form == null && $body == null) {
58
			$formMap = self::getFormMap();
59
			foreach ($formMap as $k => $v){
60
				$params[$k] = $v ;
61
			}
62
		} else if ($form != null) {
63
			foreach ($form as $k => $v){
64
				$params[$k] = $v ;
65
			}
66
		}
67
68
		if($body == null){
69
			$body = file_get_contents('php://input');
70
		}
71
72
		$remoteSign = $queryMap["sign"];
73
		$localSign = self::sign($params, $body, $secret);
74
		if (strcmp($remoteSign, $localSign) == 0) {
75
			return true;
76
		} else {
77
			$paramStr = self::getParamStrFromMap($params);
78
			self::logCommunicationError($remoteSign,$localSign,$paramStr,$body);
79
			return false;
80
		}
81
	}
82
83
	private static function getHeaderMap() {
84
		$headerMap = array();
85
		$signList = $_SERVER['HTTP_TOP_SIGN_LIST']; // 只获取参与签名的头部字段
86
87
		if(!$signList) {
88
			return $headerMap;
89
		}
90
91
		$signList = trim($signList);
92
		if (strlen($signList) > 0){
93
			$params = split(",", $signList);
0 ignored issues
show
Deprecated Code introduced by
The function split() has been deprecated: 5.3.0 Use preg_split() instead ( Ignorable by Annotation )

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

93
			$params = /** @scrutinizer ignore-deprecated */ split(",", $signList);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
94
			foreach ($_SERVER as $k => $v){
95
				if (substr($k, 0, 5) == 'HTTP_'){
96
					foreach($params as $kk){
97
						$upperkey = strtoupper($kk);
98
						if(self::endWith($k,$upperkey)){
99
							$headerMap[$kk] = $v;
100
						}
101
					}
102
				}
103
			}
104
		}
105
		return $headerMap;
106
	}
107
108
	private static function getQueryMap(){
109
		$queryStr = $_SERVER["QUERY_STRING"];
110
		$resultArray = array();
111
		foreach (explode('&', $queryStr) as $pair) {
112
		    list($key, $value) = explode('=', $pair);
113
		    if (strpos($key, '.') !== false) {
114
		        list($subKey, $subVal) = explode('.', $key);
115
116
		        if (preg_match('/(?P<name>\w+)\[(?P<index>\w+)\]/', $subKey, $matches)) {
117
		            $resultArray[$matches['name']][$matches['index']][$subVal] = $value;
118
		        } else {
119
		            $resultArray[$subKey][$subVal] = urldecode($value);
120
		        }
121
		    } else {
122
		        $resultArray[$key] = urldecode($value);
123
		    }
124
		}
125
		return $resultArray;
126
	}
127
128
	private static function checkRemoteIp(){
0 ignored issues
show
Unused Code introduced by
The method checkRemoteIp() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
129
		$remoteIp = $_SERVER["REMOTE_ADDR"];
130
		foreach ($header_real_ip as $k){
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $header_real_ip seems to be never defined.
Loading history...
131
			$realIp = $_SERVER[$k];
132
			$realIp = trim($realIp);
133
			if(strlen($realIp) > 0 && strcasecmp("unknown",$realIp)){
134
				$remoteIp = $realIp;
135
				break;
136
			}
137
		}
138
		return self::startsWith($remoteIp,"140.205.144.") || self::startsWith($remoteIp,"40.205.145.");
139
	}
140
141
	private static function getFormMap(){
142
		$resultArray = array();
143
		foreach($_POST as $key=>$v) { 
144
			$resultArray[$key] = $v ;
145
		}
146
		return $resultArray ;	
147
	}
148
149
	private static function startsWith($haystack, $needle) {
150
    	return $needle === "" || strpos($haystack, $needle) === 0;
151
	}
152
153
	private static function endWith($haystack, $needle) {   
154
	    $length = strlen($needle);  
155
	    if($length == 0)
156
	    {    
157
	        return true;  
158
	    }  
159
	    return (substr($haystack, -$length) === $needle);
160
 	}
161
162
	private static function checkTimestamp(){
0 ignored issues
show
Unused Code introduced by
The method checkTimestamp() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
163
		$ts = $_POST['timestamp'];
164
		if($ts){
165
			$clientTimestamp = strtotime($ts);
166
			$current = $_SERVER['REQUEST_TIME'];
167
			return ($current - $clientTimestamp) <= 5*60*1000;
168
		}else{
169
			return false;
170
		}
171
	}
172
173
	private static function getParamStrFromMap($params){
174
		ksort($params);
175
		$stringToBeSigned = "";
176
		foreach ($params as $k => $v)
177
		{
178
			if(strcmp("sign", $k) != 0)
179
			{
180
				$stringToBeSigned .= "$k$v";
181
			}
182
		}
183
		unset($k, $v);
184
		return $stringToBeSigned;
185
	}
186
187
	private static function sign($params,$body,$secret){
188
		ksort($params);
189
190
		$stringToBeSigned = $secret;
191
		$stringToBeSigned .= self::getParamStrFromMap($params);
192
193
		if($body)
194
			$stringToBeSigned .= $body;
195
		$stringToBeSigned .= $secret;
196
		return strtoupper(md5($stringToBeSigned));
197
	}
198
199
	protected static function logCommunicationError($remoteSign, $localSign, $paramStr, $body)
200
	{
201
		$localIp = isset($_SERVER["SERVER_ADDR"]) ? $_SERVER["SERVER_ADDR"] : "CLI";
0 ignored issues
show
Unused Code introduced by
The assignment to $localIp is dead and can be removed.
Loading history...
202
		$logger = new TopLogger;
203
		$logger->conf["log_file"] = rtrim(TOP_SDK_WORK_DIR, '\\/') . '/' . "logs/top_comm_err_". date("Y-m-d") . ".log";
204
		$logger->conf["separator"] = "^_^";
205
		$logData = array(
206
		"checkTopSign error" ,
207
		"remoteSign=".$remoteSign ,
208
		"localSign=".$localSign ,
209
		"paramStr=".$paramStr ,
210
		"body=".$body
211
		);
212
		$logger->log($logData);
213
	}
214
	private static function clear_blank($str, $glue='')
0 ignored issues
show
Unused Code introduced by
The method clear_blank() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
215
	{
216
		$replace = array(" ", "\r", "\n", "\t"); return str_replace($replace, $glue, $str);
217
	}
218
}
219
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...