Completed
Pull Request — master (#167)
by
unknown
01:53
created

SapiEmitter   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 76
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 5
Bugs 0 Features 1
Metric Value
eloc 45
c 5
b 0
f 1
dl 0
loc 76
rs 10
ccs 27
cts 27
cp 1
wmc 15

4 Methods

Rating   Name   Duplication   Size   Complexity  
A emitBody() 0 19 6
A shouldOutputBody() 0 3 1
B emit() 0 38 7
A __construct() 0 3 1
1
<?php declare(strict_types=1);
2
3
namespace Yiisoft\Yii\Web\Emitter;
4
5
use Psr\Http\Message\ResponseInterface;
6
7
/**
8
 * SapiEmitter sends a response using PHP Server API
9
 */
10
final class SapiEmitter implements EmitterInterface
11
{
12
    private const NO_BODY_RESPONSE_CODES = [204, 205, 304];
13
    private $partSize;
14 4
15
    public function __construct(int $partSize = 8388608)
16 4
    {
17
        $this->partSize = $partSize;
18 4
    }
19 4
20 4
    public function emit(ResponseInterface $response, bool $withoutBody = false): bool
21 4
    {
22 4
        $status = $response->getStatusCode();
23 4
24 4
        header_remove();
25 4
        foreach ($response->getHeaders() as $header => $values) {
26
            foreach ($values as $value) {
27
                header(sprintf(
28
                    '%s: %s',
29 4
                    $header,
30
                    $value
31 4
                ), $header !== 'Set-Cookie', $status);
32 4
            }
33 4
        }
34 4
35 4
        $reason = $response->getReasonPhrase();
36 4
37
        header(sprintf(
38 4
            'HTTP/%s %d %s',
39 2
            $response->getProtocolVersion(),
40 2
            $status,
41 1
            $reason
42 1
        ), true, $status);
43
44
        if ($withoutBody === false && $this->shouldOutputBody($response)) {
45 2
            $contentLength = $response->getBody()->getSize();
46
            if ($response->hasHeader('Content-Length')) {
47 2
                $contentLengthHeader = $response->getHeader('Content-Length');
48
                $contentLength = array_shift($contentLengthHeader);
49
            }
50 4
            if ($contentLength !== null) {
51
                header(sprintf('Content-Length: %s', $contentLength), true, $status);
52
            }
53 3
54
            $this->emitBody($response);
55 3
        }
56
57
        return true;
58
    }
59
60
    private function emitBody(ResponseInterface $response): void
61
    {
62
        $body = $response->getBody();
63
        if ($body->isSeekable()) {
64
            $body->rewind();
65
        }
66
        $bytesToSend = $response->getBody()->getSize();
67
        if ($bytesToSend > 0) {
68
            while ($bytesToSend > 0 && !$body->eof()) {
69
                $toRead = \min($this->partSize, $bytesToSend);
70
                $data = $body->read($toRead);
71
                echo $data;
72
                $bytesToSend -= \strlen($data);
73
                \flush();
74
            }
75
        } else {
76
            while (!$body->eof()) {
77
                echo $body->read($this->partSize);
78
                \flush();
79
            }
80
        }
81
    }
82
83
    private function shouldOutputBody(ResponseInterface $response): bool
84
    {
85
        return !\in_array($response->getStatusCode(), self::NO_BODY_RESPONSE_CODES, true);
86
    }
87
}
88