Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1441 ariadna 1
<?php
2
 
3
/**
4
 * Slim Framework (https://slimframework.com)
5
 *
6
 * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
7
 */
8
 
9
declare(strict_types=1);
10
 
11
namespace Slim;
12
 
13
use Psr\Http\Message\ResponseInterface;
14
 
15
use function connection_status;
16
use function header;
17
use function headers_sent;
18
use function in_array;
19
use function min;
20
use function sprintf;
21
use function strlen;
22
use function strtolower;
23
 
24
use const CONNECTION_NORMAL;
25
 
26
class ResponseEmitter
27
{
28
    private int $responseChunkSize;
29
 
30
    public function __construct(int $responseChunkSize = 4096)
31
    {
32
        $this->responseChunkSize = $responseChunkSize;
33
    }
34
 
35
    /**
36
     * Send the response the client
37
     */
38
    public function emit(ResponseInterface $response): void
39
    {
40
        $isEmpty = $this->isResponseEmpty($response);
41
        if (headers_sent() === false) {
42
            $this->emitHeaders($response);
43
 
44
            // Set the status _after_ the headers, because of PHP's "helpful" behavior with location headers.
45
            // See https://github.com/slimphp/Slim/issues/1730
46
 
47
            $this->emitStatusLine($response);
48
        }
49
 
50
        if (!$isEmpty) {
51
            $this->emitBody($response);
52
        }
53
    }
54
 
55
    /**
56
     * Emit Response Headers
57
     */
58
    private function emitHeaders(ResponseInterface $response): void
59
    {
60
        foreach ($response->getHeaders() as $name => $values) {
61
            $first = strtolower($name) !== 'set-cookie';
62
            foreach ($values as $value) {
63
                $header = sprintf('%s: %s', $name, $value);
64
                header($header, $first);
65
                $first = false;
66
            }
67
        }
68
    }
69
 
70
    /**
71
     * Emit Status Line
72
     */
73
    private function emitStatusLine(ResponseInterface $response): void
74
    {
75
        $statusLine = sprintf(
76
            'HTTP/%s %s %s',
77
            $response->getProtocolVersion(),
78
            $response->getStatusCode(),
79
            $response->getReasonPhrase()
80
        );
81
        header($statusLine, true, $response->getStatusCode());
82
    }
83
 
84
    /**
85
     * Emit Body
86
     */
87
    private function emitBody(ResponseInterface $response): void
88
    {
89
        $body = $response->getBody();
90
        if ($body->isSeekable()) {
91
            $body->rewind();
92
        }
93
 
94
        $amountToRead = (int) $response->getHeaderLine('Content-Length');
95
        if (!$amountToRead) {
96
            $amountToRead = $body->getSize();
97
        }
98
 
99
        if ($amountToRead) {
100
            while ($amountToRead > 0 && !$body->eof()) {
101
                $length = min($this->responseChunkSize, $amountToRead);
102
                $data = $body->read($length);
103
                echo $data;
104
 
105
                $amountToRead -= strlen($data);
106
 
107
                if (connection_status() !== CONNECTION_NORMAL) {
108
                    break;
109
                }
110
            }
111
        } else {
112
            while (!$body->eof()) {
113
                echo $body->read($this->responseChunkSize);
114
                if (connection_status() !== CONNECTION_NORMAL) {
115
                    break;
116
                }
117
            }
118
        }
119
    }
120
 
121
    /**
122
     * Asserts response body is empty or status code is 204, 205 or 304
123
     */
124
    public function isResponseEmpty(ResponseInterface $response): bool
125
    {
126
        if (in_array($response->getStatusCode(), [204, 205, 304], true)) {
127
            return true;
128
        }
129
        $stream = $response->getBody();
130
        $seekable = $stream->isSeekable();
131
        if ($seekable) {
132
            $stream->rewind();
133
        }
134
        return $seekable ? $stream->read(1) === '' : $stream->eof();
135
    }
136
}