1 | <?php |
||
2 | /** |
||
3 | * Class StreamClient |
||
4 | * |
||
5 | * @created 23.02.2019 |
||
6 | * @author smiley <[email protected]> |
||
7 | * @copyright 2019 smiley |
||
8 | * @license MIT |
||
9 | */ |
||
10 | |||
11 | namespace chillerlan\HTTP\Psr18; |
||
12 | |||
13 | use chillerlan\HTTP\Utils\HeaderUtil; |
||
14 | use Psr\Http\Message\{RequestInterface, ResponseInterface}; |
||
15 | use function explode, file_get_contents, get_headers, in_array, intval, restore_error_handler, |
||
16 | set_error_handler, stream_context_create, strtolower, str_starts_with, trim; |
||
17 | |||
18 | class StreamClient extends HTTPClientAbstract{ |
||
19 | |||
20 | /** |
||
21 | * @inheritDoc |
||
22 | */ |
||
23 | public function sendRequest(RequestInterface $request):ResponseInterface{ |
||
24 | |||
25 | $errorHandler = function(int $errno, string $errstr):bool{ |
||
26 | $this->logger->error('StreamClient error #'.$errno.': '.$errstr); |
||
27 | |||
28 | throw new ClientException($errstr, $errno); |
||
29 | }; |
||
30 | |||
31 | set_error_handler($errorHandler); |
||
32 | |||
33 | $context = stream_context_create($this->getContextOptions($request)); |
||
34 | $requestUri = (string)$request->getUri()->withFragment(''); |
||
35 | $responseBody = file_get_contents($requestUri, false, $context); |
||
36 | $response = $this->createResponse(get_headers($requestUri, true, $context)); |
||
37 | |||
38 | restore_error_handler(); |
||
39 | |||
40 | $body = $this->streamFactory !== null |
||
41 | ? $this->streamFactory->createStream() |
||
42 | : $response->getBody() |
||
43 | ; |
||
44 | |||
45 | $body->write($responseBody); |
||
46 | $body->rewind(); |
||
47 | |||
48 | return $response->withBody($body); |
||
49 | } |
||
50 | |||
51 | /** |
||
52 | * |
||
53 | */ |
||
54 | protected function getContextOptions(RequestInterface $request):array{ |
||
55 | $method = $request->getMethod(); |
||
56 | $body = in_array($method, ['DELETE', 'PATCH', 'POST', 'PUT'], true) |
||
57 | ? $request->getBody()->getContents() |
||
58 | : null; |
||
59 | |||
60 | $options = [ |
||
61 | 'http' => [ |
||
62 | 'method' => $method, |
||
63 | 'header' => $this->getRequestHeaders($request), |
||
64 | 'content' => $body, |
||
65 | # 'protocol_version' => '1.1', // 1.1 is default from PHP 8.0 |
||
66 | 'user_agent' => $this->options->user_agent, |
||
0 ignored issues
–
show
Bug
Best Practice
introduced
by
![]() |
|||
67 | 'max_redirects' => 0, |
||
68 | 'timeout' => 5, |
||
69 | ], |
||
70 | 'ssl' => [ |
||
71 | 'verify_peer' => $this->options->ssl_verifypeer, |
||
0 ignored issues
–
show
The property
$ssl_verifypeer is declared protected in chillerlan\HTTP\HTTPOptions . Since you implement __get , consider adding a @property or @property-read.
![]() |
|||
72 | 'verify_depth' => 3, |
||
73 | 'peer_name' => $request->getUri()->getHost(), |
||
74 | 'ciphers' => 'HIGH:!SSLv2:!SSLv3', |
||
75 | 'disable_compression' => true, |
||
76 | ], |
||
77 | ]; |
||
78 | |||
79 | $ca = $this->options->ca_info_is_path ? 'capath' : 'cafile'; |
||
0 ignored issues
–
show
The property
$ca_info_is_path is declared protected in chillerlan\HTTP\HTTPOptions . Since you implement __get , consider adding a @property or @property-read.
![]() |
|||
80 | $options['ssl'][$ca] = $this->options->ca_info; |
||
0 ignored issues
–
show
The property
$ca_info is declared protected in chillerlan\HTTP\HTTPOptions . Since you implement __get , consider adding a @property or @property-read.
![]() |
|||
81 | |||
82 | return $options; |
||
83 | } |
||
84 | |||
85 | /** |
||
86 | * |
||
87 | */ |
||
88 | protected function getRequestHeaders(RequestInterface $request):array{ |
||
89 | $headers = []; |
||
90 | |||
91 | foreach($request->getHeaders() as $name => $values){ |
||
92 | $name = strtolower($name); |
||
93 | |||
94 | foreach($values as $value){ |
||
95 | // cURL requires a special format for empty headers. |
||
96 | // See https://github.com/guzzle/guzzle/issues/1882 for more details. |
||
97 | $headers[] = $value === '' ? $name.';' : $name.': '.$value; |
||
98 | } |
||
99 | } |
||
100 | |||
101 | return $headers; |
||
102 | } |
||
103 | |||
104 | /** |
||
105 | * @param string[] $headers |
||
106 | */ |
||
107 | protected function createResponse(array $headers):ResponseInterface{ |
||
108 | $h = []; |
||
109 | |||
110 | $httpversion = ''; |
||
111 | $statuscode = 0; |
||
112 | $statustext = ''; |
||
113 | |||
114 | foreach($headers as $k => $v){ |
||
115 | |||
116 | if($k === 0 && str_starts_with($v, 'HTTP')){ |
||
117 | $status = explode(' ', $v, 3); |
||
118 | |||
119 | $httpversion = explode('/', $status[0], 2)[1]; |
||
120 | $statuscode = intval($status[1]); |
||
121 | $statustext = trim($status[2]); |
||
122 | |||
123 | continue; |
||
124 | } |
||
125 | |||
126 | $h[$k] = $v; |
||
127 | } |
||
128 | |||
129 | $response = $this->responseFactory |
||
130 | ->createResponse($statuscode, $statustext) |
||
131 | ->withProtocolVersion($httpversion) |
||
132 | ; |
||
133 | |||
134 | foreach(HeaderUtil::normalize($h) as $k => $v){ |
||
135 | $response = $response->withAddedHeader($k, $v); |
||
136 | } |
||
137 | |||
138 | return $response; |
||
139 | } |
||
140 | |||
141 | } |
||
142 |