PluginProbe
Solid Performance – Your No-Code Caching, Performance, & Page Speed Solution / trunk
Solid Performance – Your No-Code Caching, Performance, & Page Speed Solution vtrunk
2.0.1 trunk 1.0.0 1.1.0 1.2.0 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.4.1 1.4.2 1.5.0 1.6.0 1.6.1 1.7.0 1.7.1 1.8.0 1.9.0 2.0.0
solid-performance / src / Performance / Http / Header.php
src/Performance/Http
Header.php 5.8 KB 1 year ago Header_Factory.php 581 B 1 year ago Request.php 4.6 KB 3 months ago Request_Header_Factory.php 494 B 1 year ago Uri.php 689 B 3 months ago

Header.php in Solid Performance – Your No-Code Caching, Performance, & Page Speed Solution trunk, at src/Performance/Http/Header.php

264 lines 5.8 KB Raw Download Zip
1 <?php
2 /**
3 * Holds HTTP headers.
4 *
5 * @see Header_Factory
6 *
7 * @since 1.0.0
8 *
9 * @package SolidWP\Performance
10 */
11
12 declare( strict_types=1 );
13
14 namespace SolidWP\Performance\Http;
15
16 use SolidWP\Performance\StellarWP\Arrays\Arr;
17
18 /**
19 * Holds HTTP headers.
20 *
21 * @see Header_Factory
22 *
23 * @since 1.0.0
24 *
25 * @package SolidWP\Performance
26 */
27 class Header {
28
29 protected const UPPER = '_ABCDEFGHIJKLMNOPQRSTUVWXYZ';
30 protected const LOWER = '-abcdefghijklmnopqrstuvwxyz';
31
32 /**
33 * A list of response headers indexed by their header name.
34 *
35 * @var array<string, string[]>
36 */
37 private array $headers;
38
39 /**
40 * @param string[] $headers The list of raw HTTP headers.
41 */
42 public function __construct( array $headers = [] ) {
43 if ( $headers ) {
44 $this->normalize_headers( $headers );
45 } else {
46 $this->headers = [];
47 }
48 }
49
50 /**
51 * Returns headers.
52 *
53 * @param string|null $name The name of the header, or if null, all headers.
54 *
55 * @return array<string, string[]>
56 */
57 public function all( ?string $name = null ): array {
58 if ( null !== $name ) {
59 return $this->headers[ strtr( $name, self::UPPER, self::LOWER ) ] ?? [];
60 }
61
62 return $this->headers;
63 }
64
65 /**
66 * Returns only the specified headers.
67 *
68 * @param string ...$keys The header names to include.
69 *
70 * @return array<string, string[]>
71 */
72 public function only( string ...$keys ): array {
73 $included_keys = array_map(
74 static fn( $name ) => strtr( $name, self::UPPER, self::LOWER ),
75 $keys
76 );
77
78 return Arr::only( $this->headers, $included_keys );
79 }
80
81
82 /**
83 * Returns all headers except the ones provided.
84 *
85 * @param string ...$keys The header names to exclude.
86 *
87 * @return array<string, string[]>
88 */
89 public function except( string ...$keys ): array {
90 $excluded_keys = array_map(
91 static fn( $name ) => strtr( $name, self::UPPER, self::LOWER ),
92 $keys
93 );
94
95 return Arr::except( $this->headers, $excluded_keys );
96 }
97
98 /**
99 * Remove all existing headers and replace with the provided array.
100 *
101 * @param array<string, string[]> $headers The new headers to use.
102 *
103 * @return $this
104 */
105 public function replace( array $headers ): self {
106 $this->headers = [];
107
108 foreach ( $headers as $name => $values ) {
109 $this->set( $name, $values );
110 }
111
112 return $this;
113 }
114
115 /**
116 * Returns true if the HTTP header is defined.
117 *
118 * @param string $name The header name.
119 *
120 * @return bool
121 */
122 public function has( string $name ): bool {
123 return array_key_exists( strtr( $name, self::UPPER, self::LOWER ), $this->all() );
124 }
125
126 /**
127 * Returns the first header by name.
128 *
129 * @param string $name The header name.
130 *
131 * @return string|null
132 */
133 public function get( string $name ): ?string {
134 $headers = $this->all( $name );
135
136 if ( ! $headers ) {
137 return null;
138 }
139
140 if ( null === $headers[0] ) {
141 return null;
142 }
143
144 return implode( ', ', $headers );
145 }
146
147 /**
148 * Returns true if the given HTTP header contains the given value.
149 *
150 * @param string $name The header name.
151 * @param string $value The header value to look for.
152 */
153 public function contains( string $name, string $value ): bool {
154 $header = $this->get( $name );
155
156 if ( null === $header ) {
157 return false;
158 }
159
160 return str_contains( $header, $value );
161 }
162
163 /**
164 * Returns true if the given HTTP header starts with the given value.
165 *
166 * @param string $name The header name.
167 * @param string $value The header value to look for.
168 *
169 * @return bool
170 */
171 public function starts_with( string $name, string $value ): bool {
172 $headers = $this->all( $name );
173
174 if ( ! $headers ) {
175 return false;
176 }
177
178 foreach ( $headers as $header_value ) {
179 if ( str_starts_with( strtolower( $header_value ), strtolower( $value ) ) ) {
180 return true;
181 }
182 }
183
184 return false;
185 }
186
187 /**
188 * Sets a header by name.
189 *
190 * @param string $name The header name.
191 * @param string|string[]|null $values The value or an array of values.
192 * @param bool $replace Whether to replace the actual value or not (true by
193 * default).
194 */
195 public function set( string $name, $values, bool $replace = true ): void {
196 $name = strtr( $name, self::UPPER, self::LOWER );
197
198 if ( is_array( $values ) ) {
199 $values = array_values( $values );
200
201 if ( true === $replace || ! isset( $this->headers[ $name ] ) ) {
202 $this->headers[ $name ] = $values;
203 } else {
204 $this->headers[ $name ] = array_merge( $this->headers[ $name ], $values );
205 }
206 } elseif ( true === $replace || ! isset( $this->headers[ $name ] ) ) {
207 $this->headers[ $name ] = [ $values ];
208 } else {
209 $this->headers[ $name ][] = $values;
210 }
211 }
212
213 /**
214 * Removes a header.
215 *
216 * @param string $name The header name.
217 *
218 * @return void
219 */
220 public function remove( string $name ): void {
221 unset( $this->headers[ strtr( $name, self::UPPER, self::LOWER ) ] );
222 }
223
224 /**
225 * Converts the internal headers array into a flat array of header strings.
226 *
227 * @return string[] A flat array of headers in "header-name: value" format.
228 */
229 public function raw(): array {
230 $result = [];
231
232 foreach ( $this->headers as $name => $values ) {
233 foreach ( $values as $value ) {
234 $result[] = sprintf( '%s: %s', strtr( $name, self::UPPER, self::LOWER ), $value );
235 }
236 }
237
238 return $result;
239 }
240
241 /**
242 * Normalize and format the HTTP headers.
243 *
244 * @param string[] $headers The raw HTTP headers.
245 */
246 private function normalize_headers( array $headers ): void {
247 foreach ( $headers as $header => $content ) {
248 // Parse response type headers.
249 if ( str_contains( $content, ':' ) ) {
250 // Split the header into name and value parts.
251 [ $name, $value ] = explode( ':', $content, 2 ) + [ null, null ];
252
253 $name = strtr( trim( $name ), self::UPPER, self::LOWER );
254 $value = trim( $value );
255 } else {
256 $name = strtr( $header, self::UPPER, self::LOWER );
257 $value = $content;
258 }
259
260 $this->set( $name, $value, false );
261 }
262 }
263 }
264