TopClient::execute()   F
last analyzed

Complexity

Conditions 19
Paths 1585

Size

Total Lines 120
Code Lines 69

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 19
eloc 69
c 1
b 0
f 0
nc 1585
nop 3
dl 0
loc 120
rs 0.3499

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
class TopClient
3
{
4
	public $appkey;
5
6
	public $secretKey;
7
8
	public $gatewayUrl = "http://gw.api.taobao.com/router/rest";
9
10
	public $format = "xml";
11
12
	public $connectTimeout;
13
14
	public $readTimeout;
15
16
	/** 是否打开入参check**/
17
	public $checkRequest = true;
18
19
	protected $signMethod = "md5";
20
21
	protected $apiVersion = "2.0";
22
23
	protected $sdkVersion = "top-sdk-php-20180326";
24
25
	public function getAppkey()
26
	{
27
		return $this->appkey;
28
	}
29
30
	public function __construct($appkey = "",$secretKey = ""){
31
		$this->appkey = $appkey;
32
		$this->secretKey = $secretKey ;
33
	}
34
35
	protected function generateSign($params)
36
	{
37
		ksort($params);
38
39
		$stringToBeSigned = $this->secretKey;
40
		foreach ($params as $k => $v)
41
		{
42
			if(!is_array($v) && "@" != substr($v, 0, 1))
43
			{
44
				$stringToBeSigned .= "$k$v";
45
			}
46
		}
47
		unset($k, $v);
48
		$stringToBeSigned .= $this->secretKey;
49
50
		return strtoupper(md5($stringToBeSigned));
51
	}
52
53
	public function curl($url, $postFields = null)
54
	{
55
		$ch = curl_init();
56
		curl_setopt($ch, CURLOPT_URL, $url);
57
		curl_setopt($ch, CURLOPT_FAILONERROR, false);
58
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
59
		if ($this->readTimeout) {
60
			curl_setopt($ch, CURLOPT_TIMEOUT, $this->readTimeout);
61
		}
62
		if ($this->connectTimeout) {
63
			curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->connectTimeout);
64
		}
65
		curl_setopt ( $ch, CURLOPT_USERAGENT, "top-sdk-php" );
66
		//https 请求
67
		if(strlen($url) > 5 && strtolower(substr($url,0,5)) == "https" ) {
68
			curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
69
			curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
70
		}
71
72
		if (is_array($postFields) && 0 < count($postFields))
73
		{
74
			$postBodyString = "";
75
			$postMultipart = false;
76
			foreach ($postFields as $k => $v)
77
			{
78
				if("@" != substr($v, 0, 1))//判断是不是文件上传
79
				{
80
					$postBodyString .= "$k=" . urlencode($v) . "&"; 
81
				}
82
				else//文件上传用multipart/form-data,否则用www-form-urlencoded
83
				{
84
					$postMultipart = true;
85
					if(class_exists('\CURLFile')){
86
						$postFields[$k] = new \CURLFile(substr($v, 1));
87
					}
88
				}
89
			}
90
			unset($k, $v);
91
			curl_setopt($ch, CURLOPT_POST, true);
92
			if ($postMultipart)
93
			{
94
				if (class_exists('\CURLFile')) {
95
				    curl_setopt($ch, CURLOPT_SAFE_UPLOAD, true);
0 ignored issues
show
introduced by
The constant CURLOPT_SAFE_UPLOAD has been deprecated: 7.0 Use <b>CURLFile</b> for uploads instead. ( Ignorable by Annotation )

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

95
				    curl_setopt($ch, /** @scrutinizer ignore-deprecated */ CURLOPT_SAFE_UPLOAD, true);
Loading history...
96
				} else {
97
				    if (defined('CURLOPT_SAFE_UPLOAD')) {
98
				        curl_setopt($ch, CURLOPT_SAFE_UPLOAD, false);
0 ignored issues
show
introduced by
The constant CURLOPT_SAFE_UPLOAD has been deprecated: 7.0 Use <b>CURLFile</b> for uploads instead. ( Ignorable by Annotation )

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

98
				        curl_setopt($ch, /** @scrutinizer ignore-deprecated */ CURLOPT_SAFE_UPLOAD, false);
Loading history...
99
				    }
100
				}
101
				curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
102
			}
103
			else
104
			{
105
				$header = array("content-type: application/x-www-form-urlencoded; charset=UTF-8");
106
				curl_setopt($ch,CURLOPT_HTTPHEADER,$header);
107
				curl_setopt($ch, CURLOPT_POSTFIELDS, substr($postBodyString,0,-1));
108
			}
109
		}
110
		$reponse = curl_exec($ch);
111
		
112
		if (curl_errno($ch))
113
		{
114
			throw new Exception(curl_error($ch),0);
115
		}
116
		else
117
		{
118
			$httpStatusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
119
			if (200 !== $httpStatusCode)
120
			{
121
				throw new Exception($reponse,$httpStatusCode);
0 ignored issues
show
Bug introduced by
It seems like $reponse can also be of type true; however, parameter $message of Exception::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

121
				throw new Exception(/** @scrutinizer ignore-type */ $reponse,$httpStatusCode);
Loading history...
122
			}
123
		}
124
		curl_close($ch);
125
		return $reponse;
126
	}
127
	public function curl_with_memory_file($url, $postFields = null, $fileFields = null)
128
	{
129
		$ch = curl_init();
130
		curl_setopt($ch, CURLOPT_URL, $url);
131
		curl_setopt($ch, CURLOPT_FAILONERROR, false);
132
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
133
		if ($this->readTimeout) {
134
			curl_setopt($ch, CURLOPT_TIMEOUT, $this->readTimeout);
135
		}
136
		if ($this->connectTimeout) {
137
			curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->connectTimeout);
138
		}
139
		curl_setopt ( $ch, CURLOPT_USERAGENT, "top-sdk-php" );
140
		//https 请求
141
		if(strlen($url) > 5 && strtolower(substr($url,0,5)) == "https" ) {
142
			curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
143
			curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
144
		}
145
		//生成分隔符
146
		$delimiter = '-------------' . uniqid();
147
		//先将post的普通数据生成主体字符串
148
		$data = '';
149
		if($postFields != null){
150
			foreach ($postFields as $name => $content) {
151
			    $data .= "--" . $delimiter . "\r\n";
152
			    $data .= 'Content-Disposition: form-data; name="' . $name . '"';
153
			    //multipart/form-data 不需要urlencode,参见 http:stackoverflow.com/questions/6603928/should-i-url-encode-post-data
154
			    $data .= "\r\n\r\n" . $content . "\r\n";
155
			}
156
			unset($name,$content);
157
		}
158
159
		//将上传的文件生成主体字符串
160
		if($fileFields != null){
161
			foreach ($fileFields as $name => $file) {
162
			    $data .= "--" . $delimiter . "\r\n";
163
			    $data .= 'Content-Disposition: form-data; name="' . $name . '"; filename="' . $file['name'] . "\" \r\n";
164
			    $data .= 'Content-Type: ' . $file['type'] . "\r\n\r\n";//多了个文档类型
165
166
			    $data .= $file['content'] . "\r\n";
167
			}
168
			unset($name,$file);
169
		}
170
		//主体结束的分隔符
171
		$data .= "--" . $delimiter . "--";
172
173
		curl_setopt($ch, CURLOPT_POST, true);
174
		curl_setopt($ch, CURLOPT_HTTPHEADER , array(
175
		    'Content-Type: multipart/form-data; boundary=' . $delimiter,
176
		    'Content-Length: ' . strlen($data))
177
		); 
178
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
179
		curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
180
181
		$reponse = curl_exec($ch);
182
		unset($data);
183
184
		if (curl_errno($ch))
185
		{
186
			throw new Exception(curl_error($ch),0);
187
		}
188
		else
189
		{
190
			$httpStatusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
191
			if (200 !== $httpStatusCode)
192
			{
193
				throw new Exception($reponse,$httpStatusCode);
0 ignored issues
show
Bug introduced by
It seems like $reponse can also be of type true; however, parameter $message of Exception::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

193
				throw new Exception(/** @scrutinizer ignore-type */ $reponse,$httpStatusCode);
Loading history...
194
			}
195
		}
196
		curl_close($ch);
197
		return $reponse;
198
	}
199
200
	protected function logCommunicationError($apiName, $requestUrl, $errorCode, $responseTxt)
201
	{
202
		$localIp = isset($_SERVER["SERVER_ADDR"]) ? $_SERVER["SERVER_ADDR"] : "CLI";
203
		$logger = new TopLogger;
204
		$logger->conf["log_file"] = rtrim(TOP_SDK_WORK_DIR, '\\/') . '/' . "logs/top_comm_err_" . $this->appkey . "_" . date("Y-m-d") . ".log";
205
		$logger->conf["separator"] = "^_^";
206
		$logData = array(
207
		date("Y-m-d H:i:s"),
208
		$apiName,
209
		$this->appkey,
210
		$localIp,
211
		PHP_OS,
212
		$this->sdkVersion,
213
		$requestUrl,
214
		$errorCode,
215
		str_replace("\n","",$responseTxt)
216
		);
217
		$logger->log($logData);
218
	}
219
220
	public function execute($request, $session = null,$bestUrl = null)
221
	{
222
		$result =  new ResultSet(); 
223
		if($this->checkRequest) {
224
			try {
225
				$request->check();
226
			} catch (Exception $e) {
227
228
				$result->code = $e->getCode();
229
				$result->msg = $e->getMessage();
230
				return $result;
231
			}
232
		}
233
		//组装系统参数
234
		$sysParams["app_key"] = $this->appkey;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$sysParams was never initialized. Although not strictly required by PHP, it is generally a good practice to add $sysParams = array(); before regardless.
Loading history...
235
		$sysParams["v"] = $this->apiVersion;
236
		$sysParams["format"] = $this->format;
237
		$sysParams["sign_method"] = $this->signMethod;
238
		$sysParams["method"] = $request->getApiMethodName();
239
		$sysParams["timestamp"] = date("Y-m-d H:i:s");
240
		if (null != $session)
241
		{
242
			$sysParams["session"] = $session;
243
		}
244
		$apiParams = array();
0 ignored issues
show
Unused Code introduced by
The assignment to $apiParams is dead and can be removed.
Loading history...
245
		//获取业务参数
246
		$apiParams = $request->getApiParas();
247
248
249
		//系统参数放入GET请求串
250
		if($bestUrl){
251
			$requestUrl = $bestUrl."?";
252
			$sysParams["partner_id"] = $this->getClusterTag();
253
		}else{
254
			$requestUrl = $this->gatewayUrl."?";
255
			$sysParams["partner_id"] = $this->sdkVersion;
256
		}
257
		//签名
258
		$sysParams["sign"] = $this->generateSign(array_merge($apiParams, $sysParams));
259
260
		foreach ($sysParams as $sysParamKey => $sysParamValue)
261
		{
262
			// if(strcmp($sysParamKey,"timestamp") != 0)
263
			$requestUrl .= "$sysParamKey=" . urlencode($sysParamValue) . "&";
264
		}
265
266
		$fileFields = array();
267
		foreach ($apiParams as $key => $value) {
268
			if(is_array($value) && array_key_exists('type',$value) && array_key_exists('content',$value) ){
269
				$value['name'] = $key;
270
				$fileFields[$key] = $value;
271
				unset($apiParams[$key]);
272
			}
273
		}
274
275
		// $requestUrl .= "timestamp=" . urlencode($sysParams["timestamp"]) . "&";
276
		$requestUrl = substr($requestUrl, 0, -1);
277
278
		//发起HTTP请求
279
		try
280
		{
281
			if(count($fileFields) > 0){
282
				$resp = $this->curl_with_memory_file($requestUrl, $apiParams, $fileFields);
283
			}else{
284
				$resp = $this->curl($requestUrl, $apiParams);
285
			}
286
		}
287
		catch (Exception $e)
288
		{
289
			$this->logCommunicationError($sysParams["method"],$requestUrl,"HTTP_ERROR_" . $e->getCode(),$e->getMessage());
290
			$result->code = $e->getCode();
291
			$result->msg = $e->getMessage();
292
			return $result;
293
		}
294
295
		unset($apiParams);
296
		unset($fileFields);
297
		//解析TOP返回结果
298
		$respWellFormed = false;
299
		if ("json" == $this->format)
300
		{
301
			$respObject = json_decode($resp);
0 ignored issues
show
Bug introduced by
It seems like $resp can also be of type true; however, parameter $json of json_decode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

301
			$respObject = json_decode(/** @scrutinizer ignore-type */ $resp);
Loading history...
302
			if (null !== $respObject)
303
			{
304
				$respWellFormed = true;
305
				foreach ($respObject as $propKey => $propValue)
306
				{
307
					$respObject = $propValue;
308
				}
309
			}
310
		}
311
		else if("xml" == $this->format)
312
		{
313
			$respObject = @simplexml_load_string($resp);
0 ignored issues
show
Bug introduced by
It seems like $resp can also be of type true; however, parameter $data of simplexml_load_string() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

313
			$respObject = @simplexml_load_string(/** @scrutinizer ignore-type */ $resp);
Loading history...
314
			if (false !== $respObject)
315
			{
316
				$respWellFormed = true;
317
			}
318
		}
319
320
		//返回的HTTP文本不是标准JSON或者XML,记下错误日志
321
		if (false === $respWellFormed)
322
		{
323
			$this->logCommunicationError($sysParams["method"],$requestUrl,"HTTP_RESPONSE_NOT_WELL_FORMED",$resp);
324
			$result->code = 0;
325
			$result->msg = "HTTP_RESPONSE_NOT_WELL_FORMED";
326
			return $result;
327
		}
328
329
		//如果TOP返回了错误码,记录到业务错误日志中
330
		if (isset($respObject->code))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $respObject does not seem to be defined for all execution paths leading up to this point.
Loading history...
331
		{
332
			$logger = new TopLogger;
333
			$logger->conf["log_file"] = rtrim(TOP_SDK_WORK_DIR, '\\/') . '/' . "logs/top_biz_err_" . $this->appkey . "_" . date("Y-m-d") . ".log";
334
			$logger->log(array(
335
				date("Y-m-d H:i:s"),
336
				$resp
337
			));
338
		}
339
		return $respObject;
340
	}
341
342
	public function exec($paramsArray)
343
	{
344
		if (!isset($paramsArray["method"]))
345
		{
346
			trigger_error("No api name passed");
347
		}
348
		$inflector = new LtInflector;
0 ignored issues
show
Bug introduced by
The type LtInflector was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
349
		$inflector->conf["separator"] = ".";
350
		$requestClassName = ucfirst($inflector->camelize(substr($paramsArray["method"], 7))) . "Request";
351
		if (!class_exists($requestClassName))
352
		{
353
			trigger_error("No such api: " . $paramsArray["method"]);
354
		}
355
356
		$session = isset($paramsArray["session"]) ? $paramsArray["session"] : null;
357
358
		$req = new $requestClassName;
359
		foreach($paramsArray as $paraKey => $paraValue)
360
		{
361
			$inflector->conf["separator"] = "_";
362
			$setterMethodName = $inflector->camelize($paraKey);
363
			$inflector->conf["separator"] = ".";
364
			$setterMethodName = "set" . $inflector->camelize($setterMethodName);
365
			if (method_exists($req, $setterMethodName))
366
			{
367
				$req->$setterMethodName($paraValue);
368
			}
369
		}
370
		return $this->execute($req, $session);
371
	}
372
373
	private function getClusterTag()
374
    {
375
	    return substr($this->sdkVersion,0,11)."-cluster".substr($this->sdkVersion,11);
376
    }
377
}
378