Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
61 / 61 |
|
100.00% |
22 / 22 |
CRAP | |
100.00% |
1 / 1 |
AbstractRequestResponse | |
100.00% |
61 / 61 |
|
100.00% |
22 / 22 |
47 | |
100.00% |
1 / 1 |
addHeader | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
4 | |||
addHeaders | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
3 | |||
getHeader | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getHeaderAsString | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getHeaderValue | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
getHeaderValueAsString | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
getHeaders | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getHeadersAsArray | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
5 | |||
getHeadersAsString | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
3 | |||
hasHeaders | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
hasHeader | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
removeHeader | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
removeHeaders | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
setBody | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
getBody | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getBodyContent | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
getBodyContentLength | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
3 | |||
hasBody | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
hasBodyContent | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
decodeBodyContent | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
7 | |||
removeBody | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
__get | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | /** |
3 | * Pop PHP Framework (http://www.popphp.org/) |
4 | * |
5 | * @link https://github.com/popphp/popphp-framework |
6 | * @author Nick Sagona, III <dev@nolainteractive.com> |
7 | * @copyright Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com) |
8 | * @license http://www.popphp.org/license New BSD License |
9 | */ |
10 | |
11 | /** |
12 | * @namespace |
13 | */ |
14 | namespace Pop\Http; |
15 | |
16 | use Pop\Mime\Part\Header; |
17 | use Pop\Mime\Part\Body; |
18 | |
19 | /** |
20 | * Abstract HTTP request/response class |
21 | * |
22 | * @category Pop |
23 | * @package Pop\Http |
24 | * @author Nick Sagona, III <dev@nolainteractive.com> |
25 | * @copyright Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com) |
26 | * @license http://www.popphp.org/license New BSD License |
27 | * @version 5.0.0 |
28 | */ |
29 | abstract class AbstractRequestResponse implements RequestResponseInterface |
30 | { |
31 | |
32 | /** |
33 | * Headers |
34 | * @var array |
35 | */ |
36 | protected array $headers = []; |
37 | |
38 | /** |
39 | * Body |
40 | * @var ?Body |
41 | */ |
42 | protected ?Body $body = null; |
43 | |
44 | /** |
45 | * Add a header |
46 | * |
47 | * @param Header|string|int $header |
48 | * @param ?string $value |
49 | * @return AbstractRequestResponse |
50 | */ |
51 | public function addHeader(Header|string|int $header, ?string $value = null): AbstractRequestResponse |
52 | { |
53 | if ($header instanceof Header) { |
54 | $this->headers[$header->getName()] = $header; |
55 | } else { |
56 | if (is_numeric($header) && str_contains($value, ':')) { |
57 | $header = Header::parse($value); |
58 | $this->headers[$header->getName()] = $header; |
59 | } else { |
60 | $this->headers[$header] = new Header($header, $value); |
61 | } |
62 | } |
63 | |
64 | return $this; |
65 | } |
66 | |
67 | /** |
68 | * Add all headers |
69 | * |
70 | * @param array $headers |
71 | * @return AbstractRequestResponse |
72 | */ |
73 | public function addHeaders(array $headers): AbstractRequestResponse |
74 | { |
75 | foreach ($headers as $header => $value) { |
76 | if ($value instanceof Header) { |
77 | $this->addHeader($value); |
78 | } else { |
79 | $this->addHeader($header, $value); |
80 | } |
81 | } |
82 | return $this; |
83 | } |
84 | |
85 | /** |
86 | * Get a header |
87 | * |
88 | * @param string $name |
89 | * @return mixed |
90 | */ |
91 | public function getHeader(string $name): mixed |
92 | { |
93 | return $this->headers[$name] ?? null; |
94 | } |
95 | |
96 | /** |
97 | * Get a header |
98 | * |
99 | * @param string $name |
100 | * @return mixed |
101 | */ |
102 | public function getHeaderAsString(string $name): mixed |
103 | { |
104 | return (string)$this->headers[$name] ?? null; |
105 | } |
106 | |
107 | /** |
108 | * Get header value |
109 | * |
110 | * @param string $name |
111 | * @param int $i |
112 | * @return mixed |
113 | */ |
114 | public function getHeaderValue(string $name, int $i = 0): mixed |
115 | { |
116 | return (isset($this->headers[$name])) ? $this->headers[$name]?->getValue($i) : null; |
117 | } |
118 | |
119 | /** |
120 | * Get header value as string |
121 | * |
122 | * @param string $name |
123 | * @param int $i |
124 | * @return string|null |
125 | */ |
126 | public function getHeaderValueAsString(string $name, int $i = 0): string|null |
127 | { |
128 | return (isset($this->headers[$name])) ? $this->headers[$name]?->getValueAsString($i) : null; |
129 | } |
130 | |
131 | /** |
132 | * Get all headers |
133 | * |
134 | * @return array |
135 | */ |
136 | public function getHeaders(): array |
137 | { |
138 | return $this->headers; |
139 | } |
140 | |
141 | /** |
142 | * Get all header values as associative array |
143 | * |
144 | * @param bool $asStrings |
145 | * @return array |
146 | */ |
147 | public function getHeadersAsArray(bool $asStrings = true): array |
148 | { |
149 | $headers = []; |
150 | |
151 | foreach ($this->headers as $name => $header) { |
152 | if (count($header->getValues()) == 1) { |
153 | $headers[$name] = ($asStrings) ? $header->getValueAsString(0) : $header->getValue(0); |
154 | } else { |
155 | $headers[$name] = ($asStrings) ? $header->getValuesAsStrings() : $header->getValues(); |
156 | } |
157 | } |
158 | return $headers; |
159 | } |
160 | |
161 | /** |
162 | * Get all header values formatted string |
163 | * |
164 | * @param mixed $status |
165 | * @param string $eol |
166 | * @return string |
167 | */ |
168 | public function getHeadersAsString(mixed $status = null, string $eol = "\r\n"): string |
169 | { |
170 | $headers = ''; |
171 | |
172 | if (is_string($status)) { |
173 | $headers = $status . $eol; |
174 | } |
175 | |
176 | foreach ($this->headers as $header) { |
177 | $headers .= $header . $eol; |
178 | } |
179 | |
180 | return $headers; |
181 | } |
182 | |
183 | /** |
184 | * Determine if there are headers |
185 | * |
186 | * @return bool |
187 | */ |
188 | public function hasHeaders(): bool |
189 | { |
190 | return (count($this->headers) > 0); |
191 | } |
192 | |
193 | /** |
194 | * Has a header |
195 | * |
196 | * @param string $name |
197 | * @return bool |
198 | */ |
199 | public function hasHeader(string $name): bool |
200 | { |
201 | return (isset($this->headers[$name])); |
202 | } |
203 | |
204 | /** |
205 | * Remove a header |
206 | * |
207 | * @param string $name |
208 | * @return AbstractRequestResponse |
209 | */ |
210 | public function removeHeader(string $name): AbstractRequestResponse |
211 | { |
212 | if (isset($this->headers[$name])) { |
213 | unset($this->headers[$name]); |
214 | } |
215 | |
216 | return $this; |
217 | } |
218 | |
219 | /** |
220 | * Remove all headers |
221 | * |
222 | * @return AbstractRequestResponse |
223 | */ |
224 | public function removeHeaders(): AbstractRequestResponse |
225 | { |
226 | $this->headers = []; |
227 | return $this; |
228 | } |
229 | |
230 | /** |
231 | * Set the body |
232 | * |
233 | * @param string|Body $body |
234 | * @return AbstractRequestResponse |
235 | */ |
236 | public function setBody(string|Body $body): AbstractRequestResponse |
237 | { |
238 | $this->body = ($body instanceof Body) ? $body : new Body($body); |
239 | return $this; |
240 | } |
241 | |
242 | /** |
243 | * Get the body |
244 | * |
245 | * @return Body |
246 | */ |
247 | public function getBody(): Body |
248 | { |
249 | return $this->body; |
250 | } |
251 | |
252 | /** |
253 | * Get body content |
254 | * |
255 | * @return mixed |
256 | */ |
257 | public function getBodyContent(): mixed |
258 | { |
259 | return ($this->body !== null) ? $this->body->getContent() : null; |
260 | } |
261 | |
262 | /** |
263 | * Get body content length |
264 | * |
265 | * @param bool $mb |
266 | * @return int |
267 | */ |
268 | public function getBodyContentLength(bool $mb = false): int |
269 | { |
270 | if ($this->body !== null) { |
271 | return ($mb) ? mb_strlen($this->body->getContent()) : strlen($this->body->getContent()); |
272 | } else { |
273 | return 0; |
274 | } |
275 | } |
276 | |
277 | /** |
278 | * Has a body |
279 | * |
280 | * @return bool |
281 | */ |
282 | public function hasBody(): bool |
283 | { |
284 | return ($this->body !== null); |
285 | } |
286 | |
287 | /** |
288 | * Has body content |
289 | * |
290 | * @return bool |
291 | */ |
292 | public function hasBodyContent(): bool |
293 | { |
294 | return (($this->body !== null) && $this->body->hasContent()); |
295 | } |
296 | |
297 | /** |
298 | * Decode the body |
299 | * |
300 | * @param ?string $body |
301 | * @return Body |
302 | */ |
303 | public function decodeBodyContent(?string $body = null): body |
304 | { |
305 | if ($body !== null) { |
306 | $this->setBody($body); |
307 | } |
308 | if (($this->hasHeader('Transfer-Encoding')) && (count($this->getHeader('Transfer-Encoding')->getValues()) == 1) && |
309 | (strtolower($this->getHeader('Transfer-Encoding')->getValue(0)) == 'chunked')) { |
310 | $this->body->setContent(Parser::decodeChunkedData($this->body->getContent())); |
311 | } |
312 | $contentEncoding = ($this->hasHeader('Content-Encoding') && (count($this->getHeader('Content-Encoding')->getValues()) == 1)) ? |
313 | $this->getHeader('Content-Encoding')->getValue(0) : null; |
314 | $this->body->setContent(Parser::decodeData($this->body->getContent(), $contentEncoding)); |
315 | |
316 | return $this->body; |
317 | } |
318 | |
319 | /** |
320 | * Remove the body |
321 | * |
322 | * @return AbstractRequestResponse |
323 | */ |
324 | public function removeBody(): AbstractRequestResponse |
325 | { |
326 | $this->body = null; |
327 | return $this; |
328 | } |
329 | |
330 | /** |
331 | * Magic method to get either the headers or body |
332 | * |
333 | * @param string $name |
334 | * @return mixed |
335 | */ |
336 | public function __get(string $name): mixed |
337 | { |
338 | return match ($name) { |
339 | 'headers' => $this->headers, |
340 | 'body' => $this->body, |
341 | default => null, |
342 | }; |
343 | } |
344 | |
345 | } |