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

StreamClient::getRequestHeaders()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 17

Duplication

Lines 7
Ratio 41.18 %

Importance

Changes 0
Metric Value
cc 4
nc 4
nop 1
dl 7
loc 17
rs 9.7
c 0
b 0
f 0
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