Completed
Push — master ( 2baebf...b22d69 )
by smiley
01:43
created

StreamClient::sendRequest()   A

Complexity

Conditions 3
Paths 6

Size

Total Lines 54

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 6
nop 1
dl 0
loc 54
rs 9.0036
c 0
b 0
f 0

How to fix   Long Method   

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
 * 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
		}catch(\Exception $e){
63
			throw new ClientException($e->getMessage(), $e->getCode());
64
		}
65
66
		restore_error_handler();
67
68
		$response = $this->responseFactory
69
			->createResponse($responseHeaders['statuscode'], $responseHeaders['statustext'])
70
			->withProtocolVersion($responseHeaders['httpversion'])
71
		;
72
73
		$response->getBody()->write($responseBody);
74
		$response->getBody()->rewind();
75
76
		return $response;
77
	}
78
79
	/**
80
	 * @param \Psr\Http\Message\RequestInterface $request
81
	 *
82
	 * @return array
83
	 */
84
	protected function getRequestHeaders(RequestInterface $request):array{
85
		$headers = [];
86
87
		foreach($request->getHeaders() as $name => $values){
88
			$name = strtolower($name);
89
90 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...
91
				$value = (string)$value;
92
93
				// cURL requires a special format for empty headers.
94
				// See https://github.com/guzzle/guzzle/issues/1882 for more details.
95
				$headers[] = $value === '' ? $name.';' : $name.': '.$value;
96
			}
97
		}
98
99
		return $headers;
100
	}
101
102
	/**
103
	 * @param array $headers
104
	 *
105
	 * @return array
106
	 */
107
	protected function parseResponseHeaders(array $headers):array{
108
		$h = [];
109
110
		foreach($headers as $k => $v){
111
112
			if($k === 0 && substr($v, 0, 4) === 'HTTP'){
113
				$status = explode(' ', $v, 3);
114
115
				$h['httpversion'] = explode('/', $status[0], 2)[1];
116
				$h['statuscode']  = intval($status[1]);
117
				$h['statustext']  = trim($status[2]);
118
119
				continue;
120
			}
121
122
			$h[strtolower($k)] = $v;
123
124
		}
125
126
		return $h;
127
	}
128
129
}
130