Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
/*
4
 * This file is part of the Symfony package.
5
 *
6
 * (c) Fabien Potencier <fabien@symfony.com>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
 
12
namespace Symfony\Component\HttpFoundation;
13
 
14
/**
15
 * HeaderBag is a container for HTTP headers.
16
 *
17
 * @author Fabien Potencier <fabien@symfony.com>
18
 *
19
 * @implements \IteratorAggregate<string, list<string|null>>
20
 */
21
class HeaderBag implements \IteratorAggregate, \Countable
22
{
23
    protected const UPPER = '_ABCDEFGHIJKLMNOPQRSTUVWXYZ';
24
    protected const LOWER = '-abcdefghijklmnopqrstuvwxyz';
25
 
26
    /**
27
     * @var array<string, list<string|null>>
28
     */
29
    protected $headers = [];
30
    protected $cacheControl = [];
31
 
32
    public function __construct(array $headers = [])
33
    {
34
        foreach ($headers as $key => $values) {
35
            $this->set($key, $values);
36
        }
37
    }
38
 
39
    /**
40
     * Returns the headers as a string.
41
     */
42
    public function __toString(): string
43
    {
44
        if (!$headers = $this->all()) {
45
            return '';
46
        }
47
 
48
        ksort($headers);
49
        $max = max(array_map('strlen', array_keys($headers))) + 1;
50
        $content = '';
51
        foreach ($headers as $name => $values) {
52
            $name = ucwords($name, '-');
53
            foreach ($values as $value) {
54
                $content .= sprintf("%-{$max}s %s\r\n", $name.':', $value);
55
            }
56
        }
57
 
58
        return $content;
59
    }
60
 
61
    /**
62
     * Returns the headers.
63
     *
64
     * @param string|null $key The name of the headers to return or null to get them all
65
     *
66
     * @return array<string, array<int, string|null>>|array<int, string|null>
67
     */
68
    public function all(string $key = null): array
69
    {
70
        if (null !== $key) {
71
            return $this->headers[strtr($key, self::UPPER, self::LOWER)] ?? [];
72
        }
73
 
74
        return $this->headers;
75
    }
76
 
77
    /**
78
     * Returns the parameter keys.
79
     *
80
     * @return string[]
81
     */
82
    public function keys(): array
83
    {
84
        return array_keys($this->all());
85
    }
86
 
87
    /**
88
     * Replaces the current HTTP headers by a new set.
89
     */
90
    public function replace(array $headers = [])
91
    {
92
        $this->headers = [];
93
        $this->add($headers);
94
    }
95
 
96
    /**
97
     * Adds new headers the current HTTP headers set.
98
     */
99
    public function add(array $headers)
100
    {
101
        foreach ($headers as $key => $values) {
102
            $this->set($key, $values);
103
        }
104
    }
105
 
106
    /**
107
     * Returns the first header by name or the default one.
108
     */
109
    public function get(string $key, string $default = null): ?string
110
    {
111
        $headers = $this->all($key);
112
 
113
        if (!$headers) {
114
            return $default;
115
        }
116
 
117
        if (null === $headers[0]) {
118
            return null;
119
        }
120
 
121
        return (string) $headers[0];
122
    }
123
 
124
    /**
125
     * Sets a header by name.
126
     *
127
     * @param string|string[]|null $values  The value or an array of values
128
     * @param bool                 $replace Whether to replace the actual value or not (true by default)
129
     */
130
    public function set(string $key, string|array|null $values, bool $replace = true)
131
    {
132
        $key = strtr($key, self::UPPER, self::LOWER);
133
 
134
        if (\is_array($values)) {
135
            $values = array_values($values);
136
 
137
            if (true === $replace || !isset($this->headers[$key])) {
138
                $this->headers[$key] = $values;
139
            } else {
140
                $this->headers[$key] = array_merge($this->headers[$key], $values);
141
            }
142
        } else {
143
            if (true === $replace || !isset($this->headers[$key])) {
144
                $this->headers[$key] = [$values];
145
            } else {
146
                $this->headers[$key][] = $values;
147
            }
148
        }
149
 
150
        if ('cache-control' === $key) {
151
            $this->cacheControl = $this->parseCacheControl(implode(', ', $this->headers[$key]));
152
        }
153
    }
154
 
155
    /**
156
     * Returns true if the HTTP header is defined.
157
     */
158
    public function has(string $key): bool
159
    {
160
        return \array_key_exists(strtr($key, self::UPPER, self::LOWER), $this->all());
161
    }
162
 
163
    /**
164
     * Returns true if the given HTTP header contains the given value.
165
     */
166
    public function contains(string $key, string $value): bool
167
    {
168
        return \in_array($value, $this->all($key));
169
    }
170
 
171
    /**
172
     * Removes a header.
173
     */
174
    public function remove(string $key)
175
    {
176
        $key = strtr($key, self::UPPER, self::LOWER);
177
 
178
        unset($this->headers[$key]);
179
 
180
        if ('cache-control' === $key) {
181
            $this->cacheControl = [];
182
        }
183
    }
184
 
185
    /**
186
     * Returns the HTTP header value converted to a date.
187
     *
188
     * @throws \RuntimeException When the HTTP header is not parseable
189
     */
190
    public function getDate(string $key, \DateTime $default = null): ?\DateTimeInterface
191
    {
192
        if (null === $value = $this->get($key)) {
193
            return $default;
194
        }
195
 
196
        if (false === $date = \DateTime::createFromFormat(\DATE_RFC2822, $value)) {
197
            throw new \RuntimeException(sprintf('The "%s" HTTP header is not parseable (%s).', $key, $value));
198
        }
199
 
200
        return $date;
201
    }
202
 
203
    /**
204
     * Adds a custom Cache-Control directive.
205
     */
206
    public function addCacheControlDirective(string $key, bool|string $value = true)
207
    {
208
        $this->cacheControl[$key] = $value;
209
 
210
        $this->set('Cache-Control', $this->getCacheControlHeader());
211
    }
212
 
213
    /**
214
     * Returns true if the Cache-Control directive is defined.
215
     */
216
    public function hasCacheControlDirective(string $key): bool
217
    {
218
        return \array_key_exists($key, $this->cacheControl);
219
    }
220
 
221
    /**
222
     * Returns a Cache-Control directive value by name.
223
     */
224
    public function getCacheControlDirective(string $key): bool|string|null
225
    {
226
        return $this->cacheControl[$key] ?? null;
227
    }
228
 
229
    /**
230
     * Removes a Cache-Control directive.
231
     */
232
    public function removeCacheControlDirective(string $key)
233
    {
234
        unset($this->cacheControl[$key]);
235
 
236
        $this->set('Cache-Control', $this->getCacheControlHeader());
237
    }
238
 
239
    /**
240
     * Returns an iterator for headers.
241
     *
242
     * @return \ArrayIterator<string, list<string|null>>
243
     */
244
    public function getIterator(): \ArrayIterator
245
    {
246
        return new \ArrayIterator($this->headers);
247
    }
248
 
249
    /**
250
     * Returns the number of headers.
251
     */
252
    public function count(): int
253
    {
254
        return \count($this->headers);
255
    }
256
 
257
    protected function getCacheControlHeader()
258
    {
259
        ksort($this->cacheControl);
260
 
261
        return HeaderUtils::toString($this->cacheControl, ',');
262
    }
263
 
264
    /**
265
     * Parses a Cache-Control HTTP header.
266
     */
267
    protected function parseCacheControl(string $header): array
268
    {
269
        $parts = HeaderUtils::split($header, ',=');
270
 
271
        return HeaderUtils::combine($parts);
272
    }
273
}