4 * @see https://github.com/laminas/laminas-httphandlerrunner for the canonical source repository
5 * @copyright https://github.com/laminas/laminas-httphandlerrunner/blob/master/COPYRIGHT.md
6 * @license https://github.com/laminas/laminas-httphandlerrunner/blob/master/LICENSE.md New BSD License
9 declare(strict_types=1);
11 namespace Laminas\HttpHandlerRunner\Emitter;
13 use Laminas\HttpHandlerRunner\Exception\EmitterException;
14 use Psr\Http\Message\ResponseInterface;
16 use function ob_get_length;
17 use function ob_get_level;
19 use function str_replace;
22 trait SapiEmitterTrait
25 * Checks to see if content has previously been sent.
27 * If either headers have been sent or the output buffer contains content,
28 * raises an exception.
30 * @throws EmitterException if headers have already been sent.
31 * @throws EmitterException if output is present in the output buffer.
33 private function assertNoPreviousOutput(): void
36 throw EmitterException::forHeadersSent();
39 if (ob_get_level() > 0 && ob_get_length() > 0) {
40 throw EmitterException::forOutputSent();
45 * Emit the status line.
47 * Emits the status line using the protocol version and status code from
48 * the response; if a reason phrase is available, it, too, is emitted.
50 * It is important to mention that this method should be called after
51 * `emitHeaders()` in order to prevent PHP from changing the status code of
52 * the emitted response.
54 * @see \Laminas\HttpHandlerRunner\Emitter\SapiEmitterTrait::emitHeaders()
56 private function emitStatusLine(ResponseInterface $response): void
58 $reasonPhrase = $response->getReasonPhrase();
59 $statusCode = $response->getStatusCode();
63 $response->getProtocolVersion(),
65 ($reasonPhrase ? ' ' . $reasonPhrase : '')
66 ), true, $statusCode);
70 * Emit response headers.
72 * Loops through each header, emitting each; if the header value
73 * is an array with multiple values, ensures that each is sent
74 * in such a way as to create aggregate headers (instead of replace
77 private function emitHeaders(ResponseInterface $response): void
79 $statusCode = $response->getStatusCode();
81 foreach ($response->getHeaders() as $header => $values) {
82 $name = $this->filterHeader($header);
83 $first = $name === 'Set-Cookie' ? false : true;
84 foreach ($values as $value) {
89 ), $first, $statusCode);
96 * Filter a header name to wordcase
98 private function filterHeader(string $header): string
100 return ucwords($header, '-');