Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
46 / 46
100.00% covered (success)
100.00%
6 / 6
CRAP
100.00% covered (success)
100.00%
1 / 1
ServerResponse
100.00% covered (success)
100.00%
46 / 46
100.00% covered (success)
100.00%
6 / 6
18
100.00% covered (success)
100.00%
1 / 1
 setStatus
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 send
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
6
 withSetCookie
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setCookie
100.00% covered (success)
100.00%
20 / 20
100.00% covered (success)
100.00%
1 / 1
8
 withDeleteCookie
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 deleteCookie
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace Tal;
4
5use InvalidArgumentException;
6use Tal\Psr7Extended\ServerResponseInterface;
7
8class ServerResponse extends Response implements ServerResponseInterface
9{
10    use ChangeableMessageTrait;
11
12    /** {@inheritDoc} */
13    public function setStatus($code, $reasonPhrase = '')
14    {
15        return parent::setStatus($code, $reasonPhrase);
16    }
17
18    /**
19     * Sends this response to the client.
20     *
21     * @param int $bufferSize Send maximum this amount of bytes.
22     * @param Server $server For testing proposes you can provide a Server object
23     * @return static
24     */
25    public function send(int $bufferSize = 8192, Server $server = null)
26    {
27        $server = $server ?? new Server();
28        foreach ($this->getHeaders() as $name => $values) {
29            if (strtolower($name) !== 'set-cookie') {
30                $server->header(sprintf('%s: %s', $name, implode(',', $values)), false);
31            } else {
32                foreach ($values as $value) {
33                    $server->header(sprintf('%s: %s', $name, $value), false);
34                }
35            }
36        }
37
38        $httpLine = sprintf(
39            'HTTP/%s %s %s',
40            $this->getProtocolVersion(),
41            $this->getStatusCode(),
42            $this->getReasonPhrase()
43        );
44        $server->header($httpLine, true, $this->getStatusCode());
45
46        $stream = $this->getBody();
47        if ($stream->isSeekable()) {
48            $stream->rewind();
49        }
50        while (!$stream->eof()) {
51            $server->echo($stream->read($bufferSize));
52        }
53        return $this;
54    }
55
56    /**
57     * Returns an instance with the Set-Cookie header.
58     *
59     * Instead of providing a timestamp it expects an max age in seconds.
60     *
61     * @link http://php.net/manual/en/function.setcookie.php
62     * @param $name
63     * @param string $value
64     * @param int $maxAge
65     * @param string $path
66     * @param string $domain
67     * @param bool $secure
68     * @param bool $httponly
69     * @param bool $sameSite
70     * @return ServerResponse
71     */
72    public function withSetCookie(
73        $name,
74        $value = "",
75        $maxAge = 0,
76        $path = "",
77        $domain = "",
78        $secure = false,
79        $httponly = false,
80        $sameSite = false
81    ) {
82        $new = clone $this;
83        return $new->setCookie($name, $value, $maxAge, $path, $domain, $secure, $httponly, $sameSite);
84    }
85
86    /**
87     * Adds a Set-Cookie header.
88     *
89     * Instead of providing a timestamp it expects an max age in seconds.
90     *
91     * @link http://php.net/manual/en/function.setcookie.php
92     * @param $name
93     * @param string $value
94     * @param int $maxAge
95     * @param string $path
96     * @param string $domain
97     * @param bool $secure
98     * @param bool $httponly
99     * @param bool $sameSite
100     * @return $this
101     */
102    public function setCookie(
103        $name,
104        $value = "",
105        $maxAge = 0,
106        $path = "",
107        $domain = "",
108        $secure = false,
109        $httponly = false,
110        $sameSite = false
111    ) {
112        if (preg_match('/[=,; \t\r\n\013\014]/', $name)) {
113            throw new InvalidArgumentException(
114                'Cookie names cannot contain any of the following \'=,; \t\r\n\013\014\''
115            );
116        }
117
118        $headerLine = sprintf('%s=%s', $name, urlencode($value));
119
120        if ($maxAge) {
121            $headerLine .= '; expires=' . gmdate('r', time() + $maxAge);
122            $headerLine .= '; Max-Age=' . max($maxAge, 0);
123        }
124
125        if ($path) {
126            $headerLine .= '; path=' . $path;
127        }
128
129        if ($domain) {
130            $headerLine .= '; domain=' . $domain;
131        }
132
133        if ($secure) {
134            $headerLine .= '; secure';
135        }
136
137        if ($httponly) {
138            $headerLine .= '; HttpOnly';
139        }
140
141        if ($sameSite) {
142            $headerLine .= '; SameSite=strict';
143        }
144
145        $this->addHeader('Set-Cookie', $headerLine);
146        return $this;
147    }
148
149    public function withDeleteCookie($name)
150    {
151        $new = clone $this;
152        return $new->deleteCookie($name);
153    }
154
155    public function deleteCookie($name)
156    {
157        $this->setCookie($name, 'deleted', -1);
158        return $this;
159    }
160}