Completed
Push — master ( 3e15a8...ec1159 )
by Mihail
09:16
created

HeaderTrait.php (1 issue)

Severity
1
<?php declare(strict_types=1);
2
3
/*
4
 * This file is part of the Koded package.
5
 *
6
 * (c) Mihail Binev <[email protected]>
7
 *
8
 * Please view the LICENSE distributed with this source code
9
 * for the full copyright and license information.
10
 *
11
 */
12
13
namespace Koded\Http;
14
15
16
trait HeaderTrait
17
{
18
19
    /**
20
     * @var array Message headers.
21
     */
22
    protected $headers = [];
23
24
    /**
25
     * @var array Used for case-insensitivity header name checks
26
     */
27
    protected $headersMap = [];
28
29
    public function getHeaders(): array
30
    {
31
        return $this->headers;
32
    }
33
34
    public function getHeader($name): array
35
    {
36
        if (false === isset($this->headersMap[$name = strtolower($name)])) {
37
            return [];
38
        }
39
40
        if ($value = $this->headers[$this->headersMap[$name]]) {
41
            return (array)$value;
42
        }
43
44
        return [];
45
    }
46
47
    public function getHeaderLine($name): string
48
    {
49
        return join(',', $this->getHeader($name));
50
    }
51
52
    public function withHeader($name, $value): self
53
    {
54
        $instance = clone $this;
55
56
        $instance->headersMap[strtolower($name)] = $name;
57
        $instance->headers[$name]                = (array)$value;
58
59
        return $instance;
60
    }
61
62
    public function withHeaders(array $headers): self
63
    {
64
        $instance = clone $this;
65
66
        foreach ($headers as $name => $value) {
67
            $instance->normalizeHeader($name, $value, false);
68
        }
69
70
        return $instance;
71
    }
72
73
    public function withoutHeader($name): self
74
    {
75
        $instance = clone $this;
76
        $key      = strtolower($name);
77
        unset($instance->headersMap[$key], $instance->headers[$this->headersMap[$key]]);
78
79
        return $instance;
80
    }
81
82
    public function withAddedHeader($name, $value): self
83
    {
84
        $value    = (array)$value;
85
        $instance = clone $this;
86
87
        if (isset($instance->headersMap[$header = strtolower($name)])) {
0 ignored issues
show
The assignment to $header is dead and can be removed.
Loading history...
88
            $instance->headers[$name] = array_unique(array_merge((array)$this->headers[$name], $value));
89
        } else {
90
            $instance->headersMap[strtolower($name)] = $name;
91
            $instance->headers[$name]                = $value;
92
        }
93
94
        return $instance;
95
    }
96
97
    public function hasHeader($name): bool
98
    {
99
        return array_key_exists(strtolower($name), $this->headersMap);
100
    }
101
102
    public function replaceHeaders(array $headers)
103
    {
104
        $instance          = clone $this;
105
        $instance->headers = $instance->headersMap = [];
106
107
        foreach ($headers as $name => $value) {
108
            $instance->normalizeHeader($name, $value, false);
109
        }
110
111
        return $instance;
112
    }
113
114
    /**
115
     * Transforms the nested headers as a flatten array.
116
     * This method is not part of the PSR-7.
117
     *
118
     * @return array
119
     */
120
    public function getFlattenedHeaders(): array
121
    {
122
        $flattenHeaders = [];
123
        foreach ($this->headers as $name => $value) {
124
            $flattenHeaders[] = $name . ':' . join(',', (array)$value);
125
        }
126
127
        return $flattenHeaders;
128
    }
129
130
    public function getCanonicalizedHeaders(array $names = []): string
131
    {
132
        if (empty($names)) {
133
            $names = array_keys($this->headers);
134
        }
135
136
        if (!$headers = array_reduce($names, function($list, $name) {
137
            $name   = str_replace('_', '-', $name);
138
            $list[] = strtolower($name) . ':' . join(',', $this->getHeader($name));
139
140
            return $list;
141
        })) {
142
            return '';
143
        }
144
145
        sort($headers);
146
147
        return join("\n", $headers);
148
    }
149
150
    /**
151
     * @param string $name
152
     * @param string $value
153
     * @param bool   $skipKey
154
     *
155
     * @return void
156
     */
157
    protected function normalizeHeader(string $name, $value, bool $skipKey): void
158
    {
159
        if (false === $skipKey) {
160
            $name = ucwords(str_replace('_', '-', strtolower($name)), '-');
161
        }
162
163
        $this->headersMap[strtolower($name)] = $name;
164
165
        $this->headers[$name] = str_replace(["\r", "\n"], '', array_map('trim', (array)$value));
166
    }
167
168
    /**
169
     * @param array $headers Associative headers array
170
     *
171
     * @return static
172
     */
173
    protected function setHeaders(array $headers)
174
    {
175
        foreach (array_filter($headers, 'is_string', ARRAY_FILTER_USE_KEY) as $name => $value) {
176
            $this->normalizeHeader($name, $value, false);
177
        }
178
179
        return $this;
180
    }
181
}
182