Completed
Push — master ( d546a0...fcda50 )
by smiley
01:36
created

StreamClient   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 116
Duplicated Lines 6.03 %

Coupling/Cohesion

Components 1
Dependencies 9

Importance

Changes 0
Metric Value
dl 7
loc 116
rs 10
c 0
b 0
f 0
wmc 11
lcom 1
cbo 9

3 Methods

Rating   Name   Duplication   Size   Complexity  
B sendRequest() 0 57 3
A getRequestHeaders() 7 17 4
A parseResponseHeaders() 0 21 4

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/**
3
 * Class StreamClient
4
 *
5
 * @filesource   StreamClient.php
6
 * @created      23.02.2019
7
 * @package      chillerlan\HTTP\Psr18
8
 * @author       smiley <[email protected]>
9
 * @copyright    2019 smiley
10
 * @license      MIT
11
 */
12
13
namespace chillerlan\HTTP\Psr18;
14
15
use Psr\Http\Message\{RequestInterface, ResponseInterface};
16
17
class StreamClient extends HTTPClientAbstract{
18
19
	/**
20
	 * @todo
21
	 *
22
	 * @inheritdoc
23
	 */
24
	public function sendRequest(RequestInterface $request):ResponseInterface{
25
		$uri     = $request->getUri();
26
		$method  = $request->getMethod();
27
		$headers = $this->getRequestHeaders($request);
28
29
		$body    = in_array($method, ['DELETE', 'PATCH', 'POST', 'PUT'], true)
30
			? $request->getBody()->getContents()
31
			: null;
32
33
		$context = stream_context_create([
34
			'http' => [
35
				'method'           => $method,
36
				'header'           => $headers,
37
				'content'          => $body,
38
				'protocol_version' => '1.1',
39
				'user_agent'       => $this->options->user_agent,
40
				'max_redirects'    => 0,
41
				'timeout'          => 5,
42
			],
43
			'ssl' => [
44
				'cafile'              => $this->options->ca_info,
45
				'verify_peer'         => $this->options->ssl_verifypeer,
46
				'verify_depth'        => 3,
47
				'peer_name'           => $uri->getHost(),
48
				'ciphers'             => 'HIGH:!SSLv2:!SSLv3',
49
				'disable_compression' => true,
50
			],
51
		]);
52
53
		$requestUri = (string)$uri->withFragment('');
54
55
		set_error_handler(function ($severity, $msg, $file, $line){
56
			throw new \ErrorException($msg, 0, $severity, $file, $line);
57
		});
58
59
		try{
60
			$responseBody    = file_get_contents($requestUri, false, $context);
61
			$responseHeaders = $this->parseResponseHeaders(get_headers($requestUri, 1, $context));
62
		}
63
		catch(\Exception $e){
64
			$this->logger->error('StreamClient error #'.$e->getCode().': '.$e->getMessage());
65
66
			throw new ClientException($e->getMessage(), $e->getCode());
67
		}
68
69
		restore_error_handler();
70
71
		$response = $this->responseFactory
72
			->createResponse($responseHeaders['statuscode'], $responseHeaders['statustext'])
73
			->withProtocolVersion($responseHeaders['httpversion'])
74
		;
75
76
		$response->getBody()->write($responseBody);
77
		$response->getBody()->rewind();
78
79
		return $response;
80
	}
81
82
	/**
83
	 * @param \Psr\Http\Message\RequestInterface $request
84
	 *
85
	 * @return array
86
	 */
87
	protected function getRequestHeaders(RequestInterface $request):array{
88
		$headers = [];
89
90
		foreach($request->getHeaders() as $name => $values){
91
			$name = strtolower($name);
92
93 View Code Duplication
			foreach($values as $value){
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...
94
				$value = (string)$value;
95
96
				// cURL requires a special format for empty headers.
97
				// See https://github.com/guzzle/guzzle/issues/1882 for more details.
98
				$headers[] = $value === '' ? $name.';' : $name.': '.$value;
99
			}
100
		}
101
102
		return $headers;
103
	}
104
105
	/**
106
	 * @param array $headers
107
	 *
108
	 * @return array
109
	 */
110
	protected function parseResponseHeaders(array $headers):array{
111
		$h = [];
112
113
		foreach($headers as $k => $v){
114
115
			if($k === 0 && substr($v, 0, 4) === 'HTTP'){
116
				$status = explode(' ', $v, 3);
117
118
				$h['httpversion'] = explode('/', $status[0], 2)[1];
119
				$h['statuscode']  = intval($status[1]);
120
				$h['statustext']  = trim($status[2]);
121
122
				continue;
123
			}
124
125
			$h[strtolower($k)] = $v;
126
127
		}
128
129
		return $h;
130
	}
131
132
}
133