Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
48.39% |
15 / 31 |
|
75.00% |
3 / 4 |
CRAP | |
0.00% |
0 / 1 |
ResponsePrinter | |
48.39% |
15 / 31 |
|
75.00% |
3 / 4 |
51.20 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getContentLength | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
5 | |||
output | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
3 | |||
execute | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
56 |
1 | <?php |
2 | |
3 | declare(strict_types=1); |
4 | |
5 | namespace PeServer\Core\Http; |
6 | |
7 | use PeServer\Core\Binary; |
8 | use PeServer\Core\Http\HttpMethod; |
9 | use PeServer\Core\Http\HttpResponse; |
10 | use PeServer\Core\Http\HttpStatus; |
11 | use PeServer\Core\Http\ICallbackContent; |
12 | use PeServer\Core\Text; |
13 | |
14 | /** |
15 | * HTTPレスポンス出力処理。 |
16 | * |
17 | * 本クラス処理前後(execute前後)には何も出力しないのがお行儀良い処理。 |
18 | */ |
19 | class ResponsePrinter |
20 | { |
21 | /** |
22 | * 生成。 |
23 | * |
24 | * @param HttpRequest $request |
25 | * @param HttpResponse $response |
26 | */ |
27 | public function __construct( |
28 | protected readonly HttpRequest $request, |
29 | protected readonly HttpResponse $response |
30 | ) { |
31 | } |
32 | |
33 | #region function |
34 | |
35 | /** |
36 | * 応答ヘッダ: Content-Length を取得。 |
37 | * |
38 | * @return int 0以上の場合は決定された出力byte数。負数は不明。 |
39 | * @phpstan-return non-negative-int|ICallbackContent::UNKNOWN |
40 | */ |
41 | private function getContentLength(): int |
42 | { |
43 | if ($this->response->content instanceof ICallbackContent) { |
44 | $length = $this->response->content->getLength(); |
45 | if (0 <= $length) { |
46 | return $length; |
47 | } |
48 | } elseif ($this->response->content instanceof Binary) { |
49 | return $this->response->content->count(); |
50 | } elseif (is_string($this->response->content)) { |
51 | return Text::getByteCount($this->response->content); |
52 | } |
53 | |
54 | return ICallbackContent::UNKNOWN; |
55 | } |
56 | |
57 | /** |
58 | * 応答本文出力処理。 |
59 | */ |
60 | private function output(): void |
61 | { |
62 | if ($this->response->content instanceof ICallbackContent) { |
63 | // 処理は自分で出力を頑張ること |
64 | $this->response->content->output(); |
65 | } elseif ($this->response->content instanceof Binary) { |
66 | echo $this->response->content->raw; |
67 | } else { |
68 | echo $this->response->content; |
69 | } |
70 | } |
71 | |
72 | /** |
73 | * 応答出力。 |
74 | * |
75 | * @return void |
76 | */ |
77 | public function execute(): void |
78 | { |
79 | // リダイレクト未設定の場合はステータスコード設定 |
80 | if (!$this->response->header->existsRedirect()) { |
81 | http_response_code($this->response->status->value); |
82 | } |
83 | |
84 | // 設定済みヘッダ出力 |
85 | foreach ($this->response->header->getHeaders() as $name => $value) { |
86 | header($name . ': ' . $value); |
87 | } |
88 | |
89 | if ($this->response->header->existsRedirect()) { |
90 | $redirect = $this->response->header->getRedirect(); |
91 | if ($redirect->status === HttpStatus::MovedPermanently) { |
92 | header('Location: ' . $redirect->url->toString()); |
93 | } else { |
94 | header('Location: ' . $redirect->url->toString(), true, $redirect->status->value); |
95 | } |
96 | return; |
97 | } |
98 | |
99 | // ヘッダ: Content-Length |
100 | $contentLength = $this->getContentLength(); |
101 | if (0 <= $contentLength) { |
102 | header('Content-Length: ' . $contentLength); |
103 | } |
104 | |
105 | if ($this->request->httpMethod === HttpMethod::Head) { |
106 | // HEAD 処理は出力を抑制 |
107 | return; |
108 | } |
109 | |
110 | $this->output(); |
111 | } |
112 | |
113 | #endregion |
114 | } |