PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 18.4
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v18.4
28.5 28.4 28.3 28.2 28.1 28.0 27.9 27.8 27.7 27.6 27.5 trunk 18.0 18.1 18.2 18.3 18.4 18.4.1 18.5 18.5.1 18.6 18.7 18.8 18.9 19.0 All 129 releases
wordpress-seo / vendor_prefixed / guzzlehttp / psr7 / src / Utils.php

Utils.php in Yoast SEO – Advanced SEO with real-time guidance and built-in AI 18.4, at vendor_prefixed/guzzlehttp/psr7/src/Utils.php

356 lines 14.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace YoastSEO_Vendor\GuzzleHttp\Psr7;
4
5 use YoastSEO_Vendor\Psr\Http\Message\RequestInterface;
6 use YoastSEO_Vendor\Psr\Http\Message\ServerRequestInterface;
7 use YoastSEO_Vendor\Psr\Http\Message\StreamInterface;
8 use YoastSEO_Vendor\Psr\Http\Message\UriInterface;
9 final class Utils
10 {
11 /**
12 * Remove the items given by the keys, case insensitively from the data.
13 *
14 * @param iterable<string> $keys
15 *
16 * @return array
17 */
18 public static function caselessRemove($keys, array $data)
19 {
20 $result = [];
21 foreach ($keys as &$key) {
22 $key = \strtolower($key);
23 }
24 foreach ($data as $k => $v) {
25 if (!\in_array(\strtolower($k), $keys)) {
26 $result[$k] = $v;
27 }
28 }
29 return $result;
30 }
31 /**
32 * Copy the contents of a stream into another stream until the given number
33 * of bytes have been read.
34 *
35 * @param StreamInterface $source Stream to read from
36 * @param StreamInterface $dest Stream to write to
37 * @param int $maxLen Maximum number of bytes to read. Pass -1
38 * to read the entire stream.
39 *
40 * @throws \RuntimeException on error.
41 */
42 public static function copyToStream(\YoastSEO_Vendor\Psr\Http\Message\StreamInterface $source, \YoastSEO_Vendor\Psr\Http\Message\StreamInterface $dest, $maxLen = -1)
43 {
44 $bufferSize = 8192;
45 if ($maxLen === -1) {
46 while (!$source->eof()) {
47 if (!$dest->write($source->read($bufferSize))) {
48 break;
49 }
50 }
51 } else {
52 $remaining = $maxLen;
53 while ($remaining > 0 && !$source->eof()) {
54 $buf = $source->read(\min($bufferSize, $remaining));
55 $len = \strlen($buf);
56 if (!$len) {
57 break;
58 }
59 $remaining -= $len;
60 $dest->write($buf);
61 }
62 }
63 }
64 /**
65 * Copy the contents of a stream into a string until the given number of
66 * bytes have been read.
67 *
68 * @param StreamInterface $stream Stream to read
69 * @param int $maxLen Maximum number of bytes to read. Pass -1
70 * to read the entire stream.
71 *
72 * @return string
73 *
74 * @throws \RuntimeException on error.
75 */
76 public static function copyToString(\YoastSEO_Vendor\Psr\Http\Message\StreamInterface $stream, $maxLen = -1)
77 {
78 $buffer = '';
79 if ($maxLen === -1) {
80 while (!$stream->eof()) {
81 $buf = $stream->read(1048576);
82 // Using a loose equality here to match on '' and false.
83 if ($buf == null) {
84 break;
85 }
86 $buffer .= $buf;
87 }
88 return $buffer;
89 }
90 $len = 0;
91 while (!$stream->eof() && $len < $maxLen) {
92 $buf = $stream->read($maxLen - $len);
93 // Using a loose equality here to match on '' and false.
94 if ($buf == null) {
95 break;
96 }
97 $buffer .= $buf;
98 $len = \strlen($buffer);
99 }
100 return $buffer;
101 }
102 /**
103 * Calculate a hash of a stream.
104 *
105 * This method reads the entire stream to calculate a rolling hash, based
106 * on PHP's `hash_init` functions.
107 *
108 * @param StreamInterface $stream Stream to calculate the hash for
109 * @param string $algo Hash algorithm (e.g. md5, crc32, etc)
110 * @param bool $rawOutput Whether or not to use raw output
111 *
112 * @return string Returns the hash of the stream
113 *
114 * @throws \RuntimeException on error.
115 */
116 public static function hash(\YoastSEO_Vendor\Psr\Http\Message\StreamInterface $stream, $algo, $rawOutput = \false)
117 {
118 $pos = $stream->tell();
119 if ($pos > 0) {
120 $stream->rewind();
121 }
122 $ctx = \hash_init($algo);
123 while (!$stream->eof()) {
124 \hash_update($ctx, $stream->read(1048576));
125 }
126 $out = \hash_final($ctx, (bool) $rawOutput);
127 $stream->seek($pos);
128 return $out;
129 }
130 /**
131 * Clone and modify a request with the given changes.
132 *
133 * This method is useful for reducing the number of clones needed to mutate
134 * a message.
135 *
136 * The changes can be one of:
137 * - method: (string) Changes the HTTP method.
138 * - set_headers: (array) Sets the given headers.
139 * - remove_headers: (array) Remove the given headers.
140 * - body: (mixed) Sets the given body.
141 * - uri: (UriInterface) Set the URI.
142 * - query: (string) Set the query string value of the URI.
143 * - version: (string) Set the protocol version.
144 *
145 * @param RequestInterface $request Request to clone and modify.
146 * @param array $changes Changes to apply.
147 *
148 * @return RequestInterface
149 */
150 public static function modifyRequest(\YoastSEO_Vendor\Psr\Http\Message\RequestInterface $request, array $changes)
151 {
152 if (!$changes) {
153 return $request;
154 }
155 $headers = $request->getHeaders();
156 if (!isset($changes['uri'])) {
157 $uri = $request->getUri();
158 } else {
159 // Remove the host header if one is on the URI
160 if ($host = $changes['uri']->getHost()) {
161 $changes['set_headers']['Host'] = $host;
162 if ($port = $changes['uri']->getPort()) {
163 $standardPorts = ['http' => 80, 'https' => 443];
164 $scheme = $changes['uri']->getScheme();
165 if (isset($standardPorts[$scheme]) && $port != $standardPorts[$scheme]) {
166 $changes['set_headers']['Host'] .= ':' . $port;
167 }
168 }
169 }
170 $uri = $changes['uri'];
171 }
172 if (!empty($changes['remove_headers'])) {
173 $headers = self::caselessRemove($changes['remove_headers'], $headers);
174 }
175 if (!empty($changes['set_headers'])) {
176 $headers = self::caselessRemove(\array_keys($changes['set_headers']), $headers);
177 $headers = $changes['set_headers'] + $headers;
178 }
179 if (isset($changes['query'])) {
180 $uri = $uri->withQuery($changes['query']);
181 }
182 if ($request instanceof \YoastSEO_Vendor\Psr\Http\Message\ServerRequestInterface) {
183 $new = (new \YoastSEO_Vendor\GuzzleHttp\Psr7\ServerRequest(isset($changes['method']) ? $changes['method'] : $request->getMethod(), $uri, $headers, isset($changes['body']) ? $changes['body'] : $request->getBody(), isset($changes['version']) ? $changes['version'] : $request->getProtocolVersion(), $request->getServerParams()))->withParsedBody($request->getParsedBody())->withQueryParams($request->getQueryParams())->withCookieParams($request->getCookieParams())->withUploadedFiles($request->getUploadedFiles());
184 foreach ($request->getAttributes() as $key => $value) {
185 $new = $new->withAttribute($key, $value);
186 }
187 return $new;
188 }
189 return new \YoastSEO_Vendor\GuzzleHttp\Psr7\Request(isset($changes['method']) ? $changes['method'] : $request->getMethod(), $uri, $headers, isset($changes['body']) ? $changes['body'] : $request->getBody(), isset($changes['version']) ? $changes['version'] : $request->getProtocolVersion());
190 }
191 /**
192 * Read a line from the stream up to the maximum allowed buffer length.
193 *
194 * @param StreamInterface $stream Stream to read from
195 * @param int|null $maxLength Maximum buffer length
196 *
197 * @return string
198 */
199 public static function readLine(\YoastSEO_Vendor\Psr\Http\Message\StreamInterface $stream, $maxLength = null)
200 {
201 $buffer = '';
202 $size = 0;
203 while (!$stream->eof()) {
204 // Using a loose equality here to match on '' and false.
205 if (null == ($byte = $stream->read(1))) {
206 return $buffer;
207 }
208 $buffer .= $byte;
209 // Break when a new line is found or the max length - 1 is reached
210 if ($byte === "\n" || ++$size === $maxLength - 1) {
211 break;
212 }
213 }
214 return $buffer;
215 }
216 /**
217 * Create a new stream based on the input type.
218 *
219 * Options is an associative array that can contain the following keys:
220 * - metadata: Array of custom metadata.
221 * - size: Size of the stream.
222 *
223 * This method accepts the following `$resource` types:
224 * - `Psr\Http\Message\StreamInterface`: Returns the value as-is.
225 * - `string`: Creates a stream object that uses the given string as the contents.
226 * - `resource`: Creates a stream object that wraps the given PHP stream resource.
227 * - `Iterator`: If the provided value implements `Iterator`, then a read-only
228 * stream object will be created that wraps the given iterable. Each time the
229 * stream is read from, data from the iterator will fill a buffer and will be
230 * continuously called until the buffer is equal to the requested read size.
231 * Subsequent read calls will first read from the buffer and then call `next`
232 * on the underlying iterator until it is exhausted.
233 * - `object` with `__toString()`: If the object has the `__toString()` method,
234 * the object will be cast to a string and then a stream will be returned that
235 * uses the string value.
236 * - `NULL`: When `null` is passed, an empty stream object is returned.
237 * - `callable` When a callable is passed, a read-only stream object will be
238 * created that invokes the given callable. The callable is invoked with the
239 * number of suggested bytes to read. The callable can return any number of
240 * bytes, but MUST return `false` when there is no more data to return. The
241 * stream object that wraps the callable will invoke the callable until the
242 * number of requested bytes are available. Any additional bytes will be
243 * buffered and used in subsequent reads.
244 *
245 * @param resource|string|int|float|bool|StreamInterface|callable|\Iterator|null $resource Entity body data
246 * @param array $options Additional options
247 *
248 * @return StreamInterface
249 *
250 * @throws \InvalidArgumentException if the $resource arg is not valid.
251 */
252 public static function streamFor($resource = '', array $options = [])
253 {
254 if (\is_scalar($resource)) {
255 $stream = self::tryFopen('php://temp', 'r+');
256 if ($resource !== '') {
257 \fwrite($stream, $resource);
258 \fseek($stream, 0);
259 }
260 return new \YoastSEO_Vendor\GuzzleHttp\Psr7\Stream($stream, $options);
261 }
262 switch (\gettype($resource)) {
263 case 'resource':
264 /*
265 * The 'php://input' is a special stream with quirks and inconsistencies.
266 * We avoid using that stream by reading it into php://temp
267 */
268 $metaData = \stream_get_meta_data($resource);
269 if (isset($metaData['uri']) && $metaData['uri'] === 'php://input') {
270 $stream = self::tryFopen('php://temp', 'w+');
271 \fwrite($stream, \stream_get_contents($resource));
272 \fseek($stream, 0);
273 $resource = $stream;
274 }
275 return new \YoastSEO_Vendor\GuzzleHttp\Psr7\Stream($resource, $options);
276 case 'object':
277 if ($resource instanceof \YoastSEO_Vendor\Psr\Http\Message\StreamInterface) {
278 return $resource;
279 } elseif ($resource instanceof \Iterator) {
280 return new \YoastSEO_Vendor\GuzzleHttp\Psr7\PumpStream(function () use($resource) {
281 if (!$resource->valid()) {
282 return \false;
283 }
284 $result = $resource->current();
285 $resource->next();
286 return $result;
287 }, $options);
288 } elseif (\method_exists($resource, '__toString')) {
289 return \YoastSEO_Vendor\GuzzleHttp\Psr7\Utils::streamFor((string) $resource, $options);
290 }
291 break;
292 case 'NULL':
293 return new \YoastSEO_Vendor\GuzzleHttp\Psr7\Stream(self::tryFopen('php://temp', 'r+'), $options);
294 }
295 if (\is_callable($resource)) {
296 return new \YoastSEO_Vendor\GuzzleHttp\Psr7\PumpStream($resource, $options);
297 }
298 throw new \InvalidArgumentException('Invalid resource type: ' . \gettype($resource));
299 }
300 /**
301 * Safely opens a PHP stream resource using a filename.
302 *
303 * When fopen fails, PHP normally raises a warning. This function adds an
304 * error handler that checks for errors and throws an exception instead.
305 *
306 * @param string $filename File to open
307 * @param string $mode Mode used to open the file
308 *
309 * @return resource
310 *
311 * @throws \RuntimeException if the file cannot be opened
312 */
313 public static function tryFopen($filename, $mode)
314 {
315 $ex = null;
316 \set_error_handler(function () use($filename, $mode, &$ex) {
317 $ex = new \RuntimeException(\sprintf('Unable to open "%s" using mode "%s": %s', $filename, $mode, \func_get_args()[1]));
318 return \true;
319 });
320 try {
321 $handle = \fopen($filename, $mode);
322 } catch (\Throwable $e) {
323 $ex = new \RuntimeException(\sprintf('Unable to open "%s" using mode "%s": %s', $filename, $mode, $e->getMessage()), 0, $e);
324 }
325 \restore_error_handler();
326 if ($ex) {
327 /** @var $ex \RuntimeException */
328 throw $ex;
329 }
330 return $handle;
331 }
332 /**
333 * Returns a UriInterface for the given value.
334 *
335 * This function accepts a string or UriInterface and returns a
336 * UriInterface for the given value. If the value is already a
337 * UriInterface, it is returned as-is.
338 *
339 * @param string|UriInterface $uri
340 *
341 * @return UriInterface
342 *
343 * @throws \InvalidArgumentException
344 */
345 public static function uriFor($uri)
346 {
347 if ($uri instanceof \YoastSEO_Vendor\Psr\Http\Message\UriInterface) {
348 return $uri;
349 }
350 if (\is_string($uri)) {
351 return new \YoastSEO_Vendor\GuzzleHttp\Psr7\Uri($uri);
352 }
353 throw new \InvalidArgumentException('URI must be a string or UriInterface');
354 }
355 }
356