PluginProbe
Depicter — Popup & Slider Builder / 1.9.2
Depicter — Popup & Slider Builder v1.9.2
4.8.1 trunk 1.0.0 1.1.0 1.1.2 1.1.4 1.1.6 1.1.7 1.1.8 1.1.9 1.2.0 1.3.0 1.3.1 1.3.2 1.3.3 1.3.5 1.3.8 1.5.0 1.5.1 1.5.2 1.5.5 1.6.0 1.6.1 1.6.2 1.7.0 All 76 releases
depicter / vendor / guzzlehttp / psr7 / src / MessageTrait.php

MessageTrait.php in Depicter — Popup & Slider Builder 1.9.2, at vendor/guzzlehttp/psr7/src/MessageTrait.php

270 lines 7.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace GuzzleHttp\Psr7;
4
5 use Psr\Http\Message\StreamInterface;
6
7 /**
8 * Trait implementing functionality common to requests and responses.
9 */
10 trait MessageTrait
11 {
12 /** @var array Map of all registered headers, as original name => array of values */
13 private $headers = [];
14
15 /** @var array Map of lowercase header name => original name at registration */
16 private $headerNames = [];
17
18 /** @var string */
19 private $protocol = '1.1';
20
21 /** @var StreamInterface|null */
22 private $stream;
23
24 public function getProtocolVersion()
25 {
26 return $this->protocol;
27 }
28
29 public function withProtocolVersion($version)
30 {
31 if ($this->protocol === $version) {
32 return $this;
33 }
34
35 $new = clone $this;
36 $new->protocol = $version;
37 return $new;
38 }
39
40 public function getHeaders()
41 {
42 return $this->headers;
43 }
44
45 public function hasHeader($header)
46 {
47 return isset($this->headerNames[strtolower($header)]);
48 }
49
50 public function getHeader($header)
51 {
52 $header = strtolower($header);
53
54 if (!isset($this->headerNames[$header])) {
55 return [];
56 }
57
58 $header = $this->headerNames[$header];
59
60 return $this->headers[$header];
61 }
62
63 public function getHeaderLine($header)
64 {
65 return implode(', ', $this->getHeader($header));
66 }
67
68 public function withHeader($header, $value)
69 {
70 $this->assertHeader($header);
71 $value = $this->normalizeHeaderValue($value);
72 $normalized = strtolower($header);
73
74 $new = clone $this;
75 if (isset($new->headerNames[$normalized])) {
76 unset($new->headers[$new->headerNames[$normalized]]);
77 }
78 $new->headerNames[$normalized] = $header;
79 $new->headers[$header] = $value;
80
81 return $new;
82 }
83
84 public function withAddedHeader($header, $value)
85 {
86 $this->assertHeader($header);
87 $value = $this->normalizeHeaderValue($value);
88 $normalized = strtolower($header);
89
90 $new = clone $this;
91 if (isset($new->headerNames[$normalized])) {
92 $header = $this->headerNames[$normalized];
93 $new->headers[$header] = array_merge($this->headers[$header], $value);
94 } else {
95 $new->headerNames[$normalized] = $header;
96 $new->headers[$header] = $value;
97 }
98
99 return $new;
100 }
101
102 public function withoutHeader($header)
103 {
104 $normalized = strtolower($header);
105
106 if (!isset($this->headerNames[$normalized])) {
107 return $this;
108 }
109
110 $header = $this->headerNames[$normalized];
111
112 $new = clone $this;
113 unset($new->headers[$header], $new->headerNames[$normalized]);
114
115 return $new;
116 }
117
118 public function getBody()
119 {
120 if (!$this->stream) {
121 $this->stream = Utils::streamFor('');
122 }
123
124 return $this->stream;
125 }
126
127 public function withBody(StreamInterface $body)
128 {
129 if ($body === $this->stream) {
130 return $this;
131 }
132
133 $new = clone $this;
134 $new->stream = $body;
135 return $new;
136 }
137
138 private function setHeaders(array $headers)
139 {
140 $this->headerNames = $this->headers = [];
141 foreach ($headers as $header => $value) {
142 if (is_int($header)) {
143 // Numeric array keys are converted to int by PHP but having a header name '123' is not forbidden by the spec
144 // and also allowed in withHeader(). So we need to cast it to string again for the following assertion to pass.
145 $header = (string) $header;
146 }
147 $this->assertHeader($header);
148 $value = $this->normalizeHeaderValue($value);
149 $normalized = strtolower($header);
150 if (isset($this->headerNames[$normalized])) {
151 $header = $this->headerNames[$normalized];
152 $this->headers[$header] = array_merge($this->headers[$header], $value);
153 } else {
154 $this->headerNames[$normalized] = $header;
155 $this->headers[$header] = $value;
156 }
157 }
158 }
159
160 /**
161 * @param mixed $value
162 *
163 * @return string[]
164 */
165 private function normalizeHeaderValue($value)
166 {
167 if (!is_array($value)) {
168 return $this->trimAndValidateHeaderValues([$value]);
169 }
170
171 if (count($value) === 0) {
172 throw new \InvalidArgumentException('Header value can not be an empty array.');
173 }
174
175 return $this->trimAndValidateHeaderValues($value);
176 }
177
178 /**
179 * Trims whitespace from the header values.
180 *
181 * Spaces and tabs ought to be excluded by parsers when extracting the field value from a header field.
182 *
183 * header-field = field-name ":" OWS field-value OWS
184 * OWS = *( SP / HTAB )
185 *
186 * @param mixed[] $values Header values
187 *
188 * @return string[] Trimmed header values
189 *
190 * @see https://tools.ietf.org/html/rfc7230#section-3.2.4
191 */
192 private function trimAndValidateHeaderValues(array $values)
193 {
194 return array_map(function ($value) {
195 if (!is_scalar($value) && null !== $value) {
196 throw new \InvalidArgumentException(sprintf(
197 'Header value must be scalar or null but %s provided.',
198 is_object($value) ? get_class($value) : gettype($value)
199 ));
200 }
201
202 $trimmed = trim((string) $value, " \t");
203 $this->assertValue($trimmed);
204
205 return $trimmed;
206 }, array_values($values));
207 }
208
209 /**
210 * @see https://tools.ietf.org/html/rfc7230#section-3.2
211 *
212 * @param mixed $header
213 *
214 * @return void
215 */
216 private function assertHeader($header)
217 {
218 if (!is_string($header)) {
219 throw new \InvalidArgumentException(sprintf(
220 'Header name must be a string but %s provided.',
221 is_object($header) ? get_class($header) : gettype($header)
222 ));
223 }
224
225 if ($header === '') {
226 throw new \InvalidArgumentException('Header name can not be empty.');
227 }
228
229 if (! preg_match('/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/D', $header)) {
230 throw new \InvalidArgumentException(
231 sprintf('"%s" is not valid header name.', $header)
232 );
233 }
234 }
235
236 /**
237 * @param string $value
238 *
239 * @return void
240 *
241 * @see https://tools.ietf.org/html/rfc7230#section-3.2
242 *
243 * field-value = *( field-content / obs-fold )
244 * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
245 * field-vchar = VCHAR / obs-text
246 * VCHAR = %x21-7E
247 * obs-text = %x80-FF
248 * obs-fold = CRLF 1*( SP / HTAB )
249 */
250 private function assertValue($value)
251 {
252 // The regular expression intentionally does not support the obs-fold production, because as
253 // per RFC 7230#3.2.4:
254 //
255 // A sender MUST NOT generate a message that includes
256 // line folding (i.e., that has any field-value that contains a match to
257 // the obs-fold rule) unless the message is intended for packaging
258 // within the message/http media type.
259 //
260 // Clients must not send a request with line folding and a server sending folded headers is
261 // likely very rare. Line folding is a fairly obscure feature of HTTP/1.1 and thus not accepting
262 // folding is not likely to break any legitimate use case.
263 if (! preg_match('/^[\x20\x09\x21-\x7E\x80-\xFF]*$/D', $value)) {
264 throw new \InvalidArgumentException(
265 sprintf('"%s" is not valid header value.', $value)
266 );
267 }
268 }
269 }
270