Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
64 / 64 |
|
100.00% |
23 / 23 |
CRAP | |
100.00% |
1 / 1 |
AbstractRequestResponse | |
100.00% |
64 / 64 |
|
100.00% |
23 / 23 |
48 | |
100.00% |
1 / 1 |
setHeaders | |
100.00% |
3 / 3 |
|
100.00% |
1 / 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.2.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 | * Set all headers (clear out any existing headers) |
46 | * |
47 | * @param array $headers |
48 | * @return AbstractRequestResponse |
49 | */ |
50 | public function setHeaders(array $headers): AbstractRequestResponse |
51 | { |
52 | $this->headers = []; |
53 | $this->addHeaders($headers); |
54 | |
55 | return $this; |
56 | } |
57 | |
58 | /** |
59 | * Add a header |
60 | * |
61 | * @param Header|string|int $header |
62 | * @param ?string $value |
63 | * @return AbstractRequestResponse |
64 | */ |
65 | public function addHeader(Header|string|int $header, ?string $value = null): AbstractRequestResponse |
66 | { |
67 | if ($header instanceof Header) { |
68 | $this->headers[$header->getName()] = $header; |
69 | } else { |
70 | if (is_numeric($header) && str_contains($value, ':')) { |
71 | $header = Header::parse($value); |
72 | $this->headers[$header->getName()] = $header; |
73 | } else { |
74 | $this->headers[$header] = new Header($header, $value); |
75 | } |
76 | } |
77 | |
78 | return $this; |
79 | } |
80 | |
81 | /** |
82 | * Add all headers |
83 | * |
84 | * @param array $headers |
85 | * @return AbstractRequestResponse |
86 | */ |
87 | public function addHeaders(array $headers): AbstractRequestResponse |
88 | { |
89 | foreach ($headers as $header => $value) { |
90 | if ($value instanceof Header) { |
91 | $this->addHeader($value); |
92 | } else { |
93 | $this->addHeader($header, $value); |
94 | } |
95 | } |
96 | return $this; |
97 | } |
98 | |
99 | /** |
100 | * Get a header |
101 | * |
102 | * @param string $name |
103 | * @return mixed |
104 | */ |
105 | public function getHeader(string $name): mixed |
106 | { |
107 | return $this->headers[$name] ?? null; |
108 | } |
109 | |
110 | /** |
111 | * Get a header |
112 | * |
113 | * @param string $name |
114 | * @return mixed |
115 | */ |
116 | public function getHeaderAsString(string $name): mixed |
117 | { |
118 | return (string)$this->headers[$name] ?? null; |
119 | } |
120 | |
121 | /** |
122 | * Get header value |
123 | * |
124 | * @param string $name |
125 | * @param int $i |
126 | * @return mixed |
127 | */ |
128 | public function getHeaderValue(string $name, int $i = 0): mixed |
129 | { |
130 | return (isset($this->headers[$name])) ? $this->headers[$name]?->getValue($i) : null; |
131 | } |
132 | |
133 | /** |
134 | * Get header value as string |
135 | * |
136 | * @param string $name |
137 | * @param int $i |
138 | * @return string|null |
139 | */ |
140 | public function getHeaderValueAsString(string $name, int $i = 0): string|null |
141 | { |
142 | return (isset($this->headers[$name])) ? $this->headers[$name]?->getValueAsString($i) : null; |
143 | } |
144 | |
145 | /** |
146 | * Get all headers |
147 | * |
148 | * @return array |
149 | */ |
150 | public function getHeaders(): array |
151 | { |
152 | return $this->headers; |
153 | } |
154 | |
155 | /** |
156 | * Get all header values as associative array |
157 | * |
158 | * @param bool $asStrings |
159 | * @return array |
160 | */ |
161 | public function getHeadersAsArray(bool $asStrings = true): array |
162 | { |
163 | $headers = []; |
164 | |
165 | foreach ($this->headers as $name => $header) { |
166 | if (count($header->getValues()) == 1) { |
167 | $headers[$name] = ($asStrings) ? $header->getValueAsString(0) : $header->getValue(0); |
168 | } else { |
169 | $headers[$name] = ($asStrings) ? $header->getValuesAsStrings() : $header->getValues(); |
170 | } |
171 | } |
172 | return $headers; |
173 | } |
174 | |
175 | /** |
176 | * Get all header values formatted string |
177 | * |
178 | * @param mixed $status |
179 | * @param string $eol |
180 | * @return string |
181 | */ |
182 | public function getHeadersAsString(mixed $status = null, string $eol = "\r\n"): string |
183 | { |
184 | $headers = ''; |
185 | |
186 | if (is_string($status)) { |
187 | $headers = $status . $eol; |
188 | } |
189 | |
190 | foreach ($this->headers as $header) { |
191 | $headers .= $header . $eol; |
192 | } |
193 | |
194 | return $headers; |
195 | } |
196 | |
197 | /** |
198 | * Determine if there are headers |
199 | * |
200 | * @return bool |
201 | */ |
202 | public function hasHeaders(): bool |
203 | { |
204 | return (count($this->headers) > 0); |
205 | } |
206 | |
207 | /** |
208 | * Has a header |
209 | * |
210 | * @param string $name |
211 | * @return bool |
212 | */ |
213 | public function hasHeader(string $name): bool |
214 | { |
215 | return (isset($this->headers[$name])); |
216 | } |
217 | |
218 | /** |
219 | * Remove a header |
220 | * |
221 | * @param string $name |
222 | * @return AbstractRequestResponse |
223 | */ |
224 | public function removeHeader(string $name): AbstractRequestResponse |
225 | { |
226 | if (isset($this->headers[$name])) { |
227 | unset($this->headers[$name]); |
228 | } |
229 | |
230 | return $this; |
231 | } |
232 | |
233 | /** |
234 | * Remove all headers |
235 | * |
236 | * @return AbstractRequestResponse |
237 | */ |
238 | public function removeHeaders(): AbstractRequestResponse |
239 | { |
240 | $this->headers = []; |
241 | return $this; |
242 | } |
243 | |
244 | /** |
245 | * Set the body |
246 | * |
247 | * @param string|Body $body |
248 | * @return AbstractRequestResponse |
249 | */ |
250 | public function setBody(string|Body $body): AbstractRequestResponse |
251 | { |
252 | $this->body = ($body instanceof Body) ? $body : new Body($body); |
253 | return $this; |
254 | } |
255 | |
256 | /** |
257 | * Get the body |
258 | * |
259 | * @return Body |
260 | */ |
261 | public function getBody(): Body |
262 | { |
263 | return $this->body; |
264 | } |
265 | |
266 | /** |
267 | * Get body content |
268 | * |
269 | * @return mixed |
270 | */ |
271 | public function getBodyContent(): mixed |
272 | { |
273 | return ($this->body !== null) ? $this->body->getContent() : null; |
274 | } |
275 | |
276 | /** |
277 | * Get body content length |
278 | * |
279 | * @param bool $mb |
280 | * @return int |
281 | */ |
282 | public function getBodyContentLength(bool $mb = false): int |
283 | { |
284 | if ($this->body !== null) { |
285 | return ($mb) ? mb_strlen($this->body->getContent()) : strlen($this->body->getContent()); |
286 | } else { |
287 | return 0; |
288 | } |
289 | } |
290 | |
291 | /** |
292 | * Has a body |
293 | * |
294 | * @return bool |
295 | */ |
296 | public function hasBody(): bool |
297 | { |
298 | return ($this->body !== null); |
299 | } |
300 | |
301 | /** |
302 | * Has body content |
303 | * |
304 | * @return bool |
305 | */ |
306 | public function hasBodyContent(): bool |
307 | { |
308 | return (($this->body !== null) && $this->body->hasContent()); |
309 | } |
310 | |
311 | /** |
312 | * Decode the body |
313 | * |
314 | * @param ?string $body |
315 | * @return Body |
316 | */ |
317 | public function decodeBodyContent(?string $body = null): body |
318 | { |
319 | if ($body !== null) { |
320 | $this->setBody($body); |
321 | } |
322 | if (($this->hasHeader('Transfer-Encoding')) && (count($this->getHeader('Transfer-Encoding')->getValues()) == 1) && |
323 | (strtolower($this->getHeader('Transfer-Encoding')->getValue(0)) == 'chunked')) { |
324 | $this->body->setContent(Parser::decodeChunkedData($this->body->getContent())); |
325 | } |
326 | $contentEncoding = ($this->hasHeader('Content-Encoding') && (count($this->getHeader('Content-Encoding')->getValues()) == 1)) ? |
327 | $this->getHeader('Content-Encoding')->getValue(0) : null; |
328 | $this->body->setContent(Parser::decodeData($this->body->getContent(), $contentEncoding)); |
329 | |
330 | return $this->body; |
331 | } |
332 | |
333 | /** |
334 | * Remove the body |
335 | * |
336 | * @return AbstractRequestResponse |
337 | */ |
338 | public function removeBody(): AbstractRequestResponse |
339 | { |
340 | $this->body = null; |
341 | return $this; |
342 | } |
343 | |
344 | /** |
345 | * Magic method to get either the headers or body |
346 | * |
347 | * @param string $name |
348 | * @return mixed |
349 | */ |
350 | public function __get(string $name): mixed |
351 | { |
352 | return match ($name) { |
353 | 'headers' => $this->headers, |
354 | 'body' => $this->body, |
355 | default => null, |
356 | }; |
357 | } |
358 | |
359 | } |