PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / trunk
Yoast SEO – Advanced SEO with real-time guidance and built-in AI vtrunk
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
← All changes | vendor_prefixed/guzzlehttp/guzzle/src/Utils.php +121 -32 28.1 → trunk View file →
@@ -36,9 +36,9 @@
36 36 \var_dump($input);
37 37 // normalize float vs double
38 38 /** @var string $varDumpContent */
39 39 $varDumpContent = \ob_get_clean();
40 - return \str_replace('double(', 'float(', \rtrim($varDumpContent));
40 + return \str_replace('double(', 'float(', \rtrim($varDumpContent, " \n\r\t\x00\v"));
41 41 }
42 42 }
43 43 /**
44 44 * Parses an array of header lines into an associative array of headers.
@@ -50,9 +50,9 @@
50 50 {
51 51 $headers = [];
52 52 foreach ($lines as $line) {
53 53 $parts = \explode(':', $line, 2);
54 - $headers[\trim($parts[0])][] = isset($parts[1]) ? \trim($parts[1]) : null;
54 + $headers[\trim($parts[0], " \n\r\t\x00\v")][] = isset($parts[1]) ? \trim($parts[1], " \n\r\t\x00\v") : null;
55 55 }
56 56 return $headers;
57 57 }
58 58 /**
@@ -76,9 +76,9 @@
76 76 * Chooses and creates a default handler to use based on the environment.
77 77 *
78 78 * The returned handler is not wrapped by any default middlewares.
79 79 *
80 - * @param array{transport_sharing?: mixed} $handlerOptions Handler constructor options.
80 + * @param array{transport_sharing?: mixed, max_host_connections?: mixed, max_total_connections?: mixed, multiplex?: mixed} $handlerOptions Handler constructor options.
81 81 *
82 82 * @return callable(RequestInterface, array): Promise\PromiseInterface Returns the best handler for the given system.
83 83 *
84 84 * @throws \RuntimeException if no viable Handler is available.
@@ -84,39 +84,123 @@
84 84 * @throws \RuntimeException if no viable Handler is available.
85 85 */
86 86 public static function chooseHandler(array $handlerOptions = []) : callable
87 87 {
88 - $handler = null;
89 88 $sharingMode = \YoastSEO_Vendor\GuzzleHttp\Handler\CurlShareHandleState::normalizeMode($handlerOptions['transport_sharing'] ?? null, 'transport_sharing');
90 - $sharingRequested = $sharingMode !== \YoastSEO_Vendor\GuzzleHttp\TransportSharing::NONE;
91 - $sharingRequired = $sharingMode === \YoastSEO_Vendor\GuzzleHttp\TransportSharing::HANDLER_REQUIRE;
92 - $curlHandlerOptions = [];
93 - $curlSupported = \defined('CURLOPT_CUSTOMREQUEST') && \YoastSEO_Vendor\GuzzleHttp\Handler\CurlVersion::supportsCurlHandler() && (\function_exists('curl_multi_exec') || \function_exists('curl_exec'));
94 - if ($sharingRequired && !$curlSupported) {
89 + $sharingRequired = self::isTransportSharingRequired($sharingMode);
90 + $connectionCapsRequired = self::hasConnectionCapOptions($handlerOptions);
91 + $handler = self::createCurlHandler($sharingMode, $handlerOptions);
92 + if ($sharingRequired && $handler === null) {
95 93 throw new \RuntimeException('Required transport sharing requires the PHP cURL extension, curl_exec() or curl_multi_exec(), and libcurl 7.21.2 or higher.');
96 94 }
97 - if ($curlSupported) {
98 - if ($sharingRequested) {
99 - $shareState = \YoastSEO_Vendor\GuzzleHttp\Handler\CurlShareHandleState::fromOption($sharingMode);
100 - if ($shareState !== null) {
101 - $curlHandlerOptions['transport_sharing'] = $shareState;
102 - }
95 + if (\ini_get('allow_url_fopen')) {
96 + return self::addStreamHandler($handler, $sharingMode, $sharingRequired, self::connectionCapOptions($handlerOptions));
97 + }
98 + if ($handler !== null) {
99 + return $handler;
100 + }
101 + if ($connectionCapsRequired) {
102 + throw new \RuntimeException('Connection cap options require a cap-capable cURL multi handler or the allow_url_fopen ini setting for stream fallback.');
103 + }
104 + throw new \RuntimeException('GuzzleHttp requires cURL, the allow_url_fopen ini setting, or a custom HTTP handler.');
105 + }
106 + private static function isTransportSharingRequired(string $sharingMode) : bool
107 + {
108 + return $sharingMode === \YoastSEO_Vendor\GuzzleHttp\TransportSharing::HANDLER_REQUIRE;
109 + }
110 + /**
111 + * @param array{max_host_connections?: mixed, max_total_connections?: mixed} $handlerOptions
112 + */
113 + private static function hasConnectionCapOptions(array $handlerOptions) : bool
114 + {
115 + return self::connectionCapOptions($handlerOptions) !== [];
116 + }
117 + /**
118 + * @param array{max_host_connections?: mixed, max_total_connections?: mixed, multiplex?: mixed} $handlerOptions
119 + *
120 + * @return (callable(RequestInterface, array): Promise\PromiseInterface)|null
121 + */
122 + private static function createCurlHandler(string $sharingMode, array $handlerOptions) : ?callable
123 + {
124 + if (!\defined('CURLOPT_CUSTOMREQUEST') || !\YoastSEO_Vendor\GuzzleHttp\Handler\CurlVersion::supportsCurlHandler()) {
125 + return null;
126 + }
127 + $connectionCapOptions = self::connectionCapOptions($handlerOptions);
128 + if ($connectionCapOptions !== [] && (!\YoastSEO_Vendor\GuzzleHttp\Handler\CurlVersion::supportsConnectionCaps() || !\function_exists('curl_multi_exec'))) {
129 + return null;
130 + }
131 + $curlHandlerOptions = self::createCurlHandlerOptions($sharingMode);
132 + $curlMultiHandlerOptions = $curlHandlerOptions + $connectionCapOptions;
133 + if (($handlerOptions['multiplex'] ?? null) === \YoastSEO_Vendor\GuzzleHttp\Multiplexing::NONE) {
134 + // Forwarded to the CurlMultiHandler only: CurlHandler and
135 + // StreamHandler validate known options, and both satisfy NONE
136 + // per-request without a handler option.
137 + $curlMultiHandlerOptions['multiplex'] = \YoastSEO_Vendor\GuzzleHttp\Multiplexing::NONE;
138 + }
139 + if (\function_exists('curl_multi_exec') && \function_exists('curl_exec')) {
140 + $multiHandler = new \YoastSEO_Vendor\GuzzleHttp\Handler\CurlMultiHandler($curlMultiHandlerOptions);
141 + if ($connectionCapOptions !== []) {
142 + // Connection caps only govern transfers on the multi handle, so
143 + // the synchronous CurlHandler fast path would escape them.
144 + return $multiHandler;
103 145 }
104 - if (\function_exists('curl_multi_exec') && \function_exists('curl_exec')) {
105 - $handler = \YoastSEO_Vendor\GuzzleHttp\Handler\Proxy::wrapSync(new \YoastSEO_Vendor\GuzzleHttp\Handler\CurlMultiHandler($curlHandlerOptions), new \YoastSEO_Vendor\GuzzleHttp\Handler\CurlHandler($curlHandlerOptions));
106 - } elseif (\function_exists('curl_exec')) {
107 - $handler = new \YoastSEO_Vendor\GuzzleHttp\Handler\CurlHandler($curlHandlerOptions);
108 - } elseif (\function_exists('curl_multi_exec')) {
109 - $handler = new \YoastSEO_Vendor\GuzzleHttp\Handler\CurlMultiHandler($curlHandlerOptions);
146 + return \YoastSEO_Vendor\GuzzleHttp\Handler\Proxy::wrapSync($multiHandler, new \YoastSEO_Vendor\GuzzleHttp\Handler\CurlHandler($curlHandlerOptions));
147 + }
148 + if ($connectionCapOptions === [] && \function_exists('curl_exec')) {
149 + return new \YoastSEO_Vendor\GuzzleHttp\Handler\CurlHandler($curlHandlerOptions);
150 + }
151 + if (\function_exists('curl_multi_exec')) {
152 + return new \YoastSEO_Vendor\GuzzleHttp\Handler\CurlMultiHandler($curlMultiHandlerOptions);
153 + }
154 + return null;
155 + }
156 + /**
157 + * @return array<string, mixed>
158 + */
159 + private static function createCurlHandlerOptions(string $sharingMode) : array
160 + {
161 + if ($sharingMode === \YoastSEO_Vendor\GuzzleHttp\TransportSharing::NONE) {
162 + return [];
163 + }
164 + $shareState = \YoastSEO_Vendor\GuzzleHttp\Handler\CurlShareHandleState::fromOption($sharingMode);
165 + return $shareState === null ? [] : ['transport_sharing' => $shareState];
166 + }
167 + /**
168 + * @param array{max_host_connections?: mixed, max_total_connections?: mixed} $handlerOptions
169 + *
170 + * @return array{max_host_connections?: int, max_total_connections?: int}
171 + */
172 + private static function connectionCapOptions(array $handlerOptions) : array
173 + {
174 + $options = [];
175 + foreach (['max_host_connections', 'max_total_connections'] as $capOption) {
176 + $value = $handlerOptions[$capOption] ?? null;
177 + if ($value === null) {
178 + continue;
110 179 }
180 + if (!\is_int($value) || $value < 1) {
181 + throw new \YoastSEO_Vendor\GuzzleHttp\Exception\InvalidArgumentException(\sprintf('%s must be a positive integer.', $capOption));
182 + }
183 + $options[$capOption] = $value;
111 184 }
112 - if (\ini_get('allow_url_fopen')) {
113 - $streamHandler = new \YoastSEO_Vendor\GuzzleHttp\Handler\StreamHandler(['transport_sharing' => $sharingMode]);
114 - $handler = $handler ? \YoastSEO_Vendor\GuzzleHttp\Handler\Proxy::wrapStreaming($handler, $streamHandler) : $streamHandler;
115 - } elseif (!$handler) {
116 - throw new \RuntimeException('GuzzleHttp requires cURL, the allow_url_fopen ini setting, or a custom HTTP handler.');
185 + return $options;
186 + }
187 + /**
188 + * @param (callable(RequestInterface, array): Promise\PromiseInterface)|null $handler
189 + * @param array{max_host_connections?: int, max_total_connections?: int} $connectionCapOptions
190 + *
191 + * @return callable(RequestInterface, array): Promise\PromiseInterface
192 + */
193 + private static function addStreamHandler(?callable $handler, string $sharingMode, bool $sharingRequired, array $connectionCapOptions) : callable
194 + {
195 + $streamHandler = new \YoastSEO_Vendor\GuzzleHttp\Handler\StreamHandler(['transport_sharing' => $sharingMode] + $connectionCapOptions);
196 + if ($handler === null) {
197 + return $streamHandler;
117 198 }
118 - return $handler;
199 + if (!$sharingRequired) {
200 + $handler = \YoastSEO_Vendor\GuzzleHttp\Handler\Proxy::wrapTlsFallback($handler, $streamHandler);
201 + }
202 + return \YoastSEO_Vendor\GuzzleHttp\Handler\Proxy::wrapStreaming($handler, $streamHandler);
119 203 }
120 204 /**
121 205 * Get the default User-Agent string to use with Guzzle.
122 206 */
@@ -140,8 +224,9 @@
140 224 * @deprecated Utils::defaultCaBundle will be removed in guzzlehttp/guzzle:8.0. This method is not needed in PHP 5.6+.
141 225 */
142 226 public static function defaultCaBundle() : string
143 227 {
228 + \YoastSEO_Vendor\trigger_deprecation('guzzlehttp/guzzle', '7.1', '%s() is deprecated and will be removed in 8.0. This method is not needed in PHP 5.6+.', __METHOD__);
144 229 static $cached = null;
145 230 static $cafiles = [
146 231 // Red Hat, CentOS, Fedora (provided by the ca-certificates package)
147 232 '/etc/pki/tls/certs/ca-bundle.crt',
@@ -177,9 +262,9 @@
177 262 No system CA bundle could be found in any of the the common system locations.
178 263 PHP versions earlier than 5.6 are not properly configured to use the system's
179 264 CA bundle by default. In order to verify peer certificates, you will need to
180 265 supply the path on disk to a certificate bundle to the 'verify' request option:
181 -https://github.com/guzzle/guzzle/blob/7.12/docs/request-options.md#verify. If
266 +https://github.com/guzzle/guzzle/blob/7.15/docs/request-options.md#verify. If
182 267 you do not need a specific certificate bundle, then Mozilla provides a commonly
183 268 used CA bundle which can be downloaded here (provided by the maintainer of
184 269 cURL): https://curl.se/ca/cacert.pem. Once you have a CA bundle available on
185 270 disk, you can set the 'openssl.cafile' PHP ini setting to point to the path to
@@ -195,9 +280,9 @@
195 280 public static function normalizeHeaderKeys(array $headers) : array
196 281 {
197 282 $result = [];
198 283 foreach (\array_keys($headers) as $key) {
199 - $result[\strtolower((string) $key)] = $key;
284 + $result[\YoastSEO_Vendor\GuzzleHttp\Psr7\Utils::asciiToLower((string) $key)] = $key;
200 285 }
201 286 return $result;
202 287 }
203 288 /**
@@ -292,9 +377,9 @@
292 377 foreach ($noProxy as $area) {
293 378 if (!\is_string($area)) {
294 379 continue;
295 380 }
296 - $area = \trim($area);
381 + $area = \trim($area, " \n\r\t\x00\v");
297 382 // Always match on wildcards.
298 383 if ($area === '*') {
299 384 return \true;
300 385 }
@@ -332,9 +417,9 @@
332 417 * @return array{type: string, value: string, port: int|null, matchesRoot: bool}|array{type: string, value: string, prefix: int}|null
333 418 */
334 419 private static function parseNoProxyRule(string $area) : ?array
335 420 {
336 - $area = \trim($area);
421 + $area = \trim($area, " \n\r\t\x00\v");
337 422 if ($area === '' || $area === '*') {
338 423 return null;
339 424 }
340 425 if (\strpos($area, '/') !== \false) {
@@ -390,9 +475,9 @@
390 475 if ($host === '') {
391 476 return null;
392 477 }
393 478 }
394 - return ['type' => 'domain', 'value' => \strtolower($host), 'port' => $port, 'matchesRoot' => $matchesRoot];
479 + return ['type' => 'domain', 'value' => \YoastSEO_Vendor\GuzzleHttp\Psr7\Utils::asciiToLower($host), 'port' => $port, 'matchesRoot' => $matchesRoot];
395 480 }
396 481 /**
397 482 * @return array{0: string, 1: int|null}|null
398 483 */
@@ -547,11 +632,13 @@
547 632 *
548 633 * @throws InvalidArgumentException if the JSON cannot be decoded.
549 634 *
550 635 * @see https://www.php.net/manual/en/function.json-decode.php
636 + * @deprecated Utils::jsonDecode() will be removed in guzzlehttp/guzzle:8.0. Use PHP's json_decode() instead.
551 637 */
552 638 public static function jsonDecode(string $json, bool $assoc = \false, int $depth = 512, int $options = 0)
553 639 {
640 + \YoastSEO_Vendor\trigger_deprecation('guzzlehttp/guzzle', '7.15', '%s() is deprecated and will be removed in 8.0. Use PHP\'s json_decode() instead.', __METHOD__);
554 641 if ($depth < 1) {
555 642 throw new \YoastSEO_Vendor\GuzzleHttp\Exception\InvalidArgumentException('json_decode error: Maximum stack depth exceeded');
556 643 }
557 644 $data = \json_decode($json, $assoc, $depth, $options);
@@ -569,11 +656,13 @@
569 656 *
570 657 * @throws InvalidArgumentException if the JSON cannot be encoded.
571 658 *
572 659 * @see https://www.php.net/manual/en/function.json-encode.php
660 + * @deprecated Utils::jsonEncode() will be removed in guzzlehttp/guzzle:8.0. Use PHP's json_encode() instead.
573 661 */
574 662 public static function jsonEncode($value, int $options = 0, int $depth = 512) : string
575 663 {
664 + \YoastSEO_Vendor\trigger_deprecation('guzzlehttp/guzzle', '7.15', '%s() is deprecated and will be removed in 8.0. Use PHP\'s json_encode() instead.', __METHOD__);
576 665 $json = \json_encode($value, $options, $depth);
577 666 if (\JSON_ERROR_NONE !== \json_last_error()) {
578 667 throw new \YoastSEO_Vendor\GuzzleHttp\Exception\InvalidArgumentException('json_encode error: ' . \json_last_error_msg());
579 668 }