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.6 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 All 130 releases
← All changes | vendor_prefixed/guzzlehttp/psr7/src/Uri.php +46 -9 28.1 → trunk View file →
@@ -72,14 +72,28 @@
72 72 {
73 73 if (self::isPathNoSchemeReference($url)) {
74 74 return self::parsePathNoSchemeReference($url);
75 75 }
76 - // Preserve bracketed IPv6 literals before encoding, including dotted IPv4 tails.
76 + // Preserve bracketed IPv6 literals before encoding, including dotted IPv4
77 + // tails. DEL (\x7F) is excluded so a raw-DEL host falls through to the
78 + // general path and is rejected rather than silently mutated by parse_url().
77 79 $prefix = '';
78 - if (\preg_match('%^([0-9A-Za-z+.-]+://\\[[0-9:.a-fA-F]+\\])(.*?)$%', $url, $matches)) {
80 + $ipv6Prefix = \preg_match('%\\A([0-9A-Za-z+.-]+://\\[[^\\]\\x00-\\x20\\x7F/?#@]+\\])(.*)\\z%s', $url, $matches);
81 + if ($ipv6Prefix === \false) {
82 + return \false;
83 + }
84 + if ($ipv6Prefix === 1) {
79 85 /** @var array{0:string, 1:string, 2:string} $matches */
86 + $suffix = $matches[2];
87 + // After the bracketed host only an optional numeric port and/or a
88 + // path, query, or fragment may follow. Anything else (for example
89 + // `:80@evil` or `:80x`) would let parse_url() reinterpret a
90 + // different host.
91 + if (\preg_match('%\\A(?::[0-9]*)?(?:[/?#].*)?\\z%s', $suffix) !== 1) {
92 + return \false;
93 + }
80 94 $prefix = $matches[1];
81 - $url = $matches[2];
95 + $url = $suffix;
82 96 }
83 97 /** @var string|null */
84 98 $encodedUrl = \preg_replace_callback('%[^:/@?&=#]+%usD', static function ($matches) {
85 99 return \urlencode($matches[0]);
@@ -340,11 +354,26 @@
340 354 {
341 355 if ($host === '') {
342 356 return;
343 357 }
344 - if (\preg_match('/[\\x00-\\x20\\x7F]/', $host)) {
358 + // Reject control characters and URI authority delimiters so getHost()
359 + // cannot disagree with the on-wire authority.
360 + $invalidHost = \preg_match('/[\\x00-\\x20\\x7F\\/\\?#@\\\\]/', $host);
361 + if ($invalidHost === \false) {
362 + throw new \RuntimeException('Unable to validate URI host: ' . \preg_last_error_msg());
363 + }
364 + if ($invalidHost === 1) {
345 365 throw new \InvalidArgumentException(\sprintf('Invalid host: "%s"', $host));
346 366 }
367 + if (\strpos($host, '[') !== \false || \strpos($host, ']') !== \false) {
368 + if ($host[0] !== '[' || \substr($host, -1) !== ']') {
369 + throw new \InvalidArgumentException(\sprintf('Invalid host: "%s"', $host));
370 + }
371 + return;
372 + }
373 + if (\strpos($host, ':') !== \false) {
374 + throw new \InvalidArgumentException(\sprintf('Invalid host: "%s"', $host));
375 + }
347 376 }
348 377 public function getScheme() : string
349 378 {
350 379 return $this->scheme;
@@ -499,9 +528,9 @@
499 528 {
500 529 if (!\is_string($scheme)) {
501 530 throw new \InvalidArgumentException('Scheme must be a string');
502 531 }
503 - $scheme = \strtr($scheme, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
532 + $scheme = \YoastSEO_Vendor\GuzzleHttp\Psr7\Utils::asciiToLower($scheme);
504 533 if ($scheme !== '' && !\preg_match('/^[a-z][a-z0-9.+-]*$/D', $scheme)) {
505 534 \YoastSEO_Vendor\trigger_deprecation('guzzlehttp/psr7', '2.11', 'Passing "%s" as a URI scheme is deprecated; guzzlehttp/psr7 3.0 requires URI schemes to match RFC 3986 syntax and begin with a letter.', $scheme);
506 535 }
507 536 return $scheme;
@@ -515,9 +544,9 @@
515 544 {
516 545 if (!\is_string($component)) {
517 546 throw new \InvalidArgumentException('User info must be a string');
518 547 }
519 - return \preg_replace_callback('/(?:[^%' . \YoastSEO_Vendor\GuzzleHttp\Psr7\Rfc3986::CHAR_UNRESERVED . \YoastSEO_Vendor\GuzzleHttp\Psr7\Rfc3986::CHAR_SUB_DELIMS . ']+|%(?![A-Fa-f0-9]{2}))/', [$this, 'rawurlencodeMatchZero'], $component);
548 + return $this->filterComponent('/(?:[^%' . \YoastSEO_Vendor\GuzzleHttp\Psr7\Rfc3986::CHAR_UNRESERVED . \YoastSEO_Vendor\GuzzleHttp\Psr7\Rfc3986::CHAR_SUB_DELIMS . ']+|%(?![A-Fa-f0-9]{2}))/', $component, 'Unable to filter URI user info');
520 549 }
521 550 /**
522 551 * @param mixed $host
523 552 *
@@ -527,9 +556,9 @@
527 556 {
528 557 if (!\is_string($host)) {
529 558 throw new \InvalidArgumentException('Host must be a string');
530 559 }
531 - $host = \strtr($host, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
560 + $host = \YoastSEO_Vendor\GuzzleHttp\Psr7\Utils::asciiToLower($host);
532 561 self::assertValidHost($host);
533 562 return $host;
534 563 }
535 564 /**
@@ -595,9 +624,9 @@
595 624 {
596 625 if (!\is_string($path)) {
597 626 throw new \InvalidArgumentException('Path must be a string');
598 627 }
599 - return \preg_replace_callback('/(?:[^' . \YoastSEO_Vendor\GuzzleHttp\Psr7\Rfc3986::CHAR_UNRESERVED . \YoastSEO_Vendor\GuzzleHttp\Psr7\Rfc3986::CHAR_SUB_DELIMS . '%:@\\/]++|%(?![A-Fa-f0-9]{2}))/', [$this, 'rawurlencodeMatchZero'], $path);
628 + return $this->filterComponent('/(?:[^' . \YoastSEO_Vendor\GuzzleHttp\Psr7\Rfc3986::CHAR_UNRESERVED . \YoastSEO_Vendor\GuzzleHttp\Psr7\Rfc3986::CHAR_SUB_DELIMS . '%:@\\/]++|%(?![A-Fa-f0-9]{2}))/', $path, 'Unable to filter URI path');
600 629 }
601 630 /**
602 631 * Filters the query string or fragment of a URI.
603 632 *
@@ -609,9 +638,17 @@
609 638 {
610 639 if (!\is_string($str)) {
611 640 throw new \InvalidArgumentException('Query and fragment must be a string');
612 641 }
613 - return \preg_replace_callback('/(?:[^' . \YoastSEO_Vendor\GuzzleHttp\Psr7\Rfc3986::CHAR_UNRESERVED . \YoastSEO_Vendor\GuzzleHttp\Psr7\Rfc3986::CHAR_SUB_DELIMS . '%:@\\/\\?]++|%(?![A-Fa-f0-9]{2}))/', [$this, 'rawurlencodeMatchZero'], $str);
642 + return $this->filterComponent('/(?:[^' . \YoastSEO_Vendor\GuzzleHttp\Psr7\Rfc3986::CHAR_UNRESERVED . \YoastSEO_Vendor\GuzzleHttp\Psr7\Rfc3986::CHAR_SUB_DELIMS . '%:@\\/\\?]++|%(?![A-Fa-f0-9]{2}))/', $str, 'Unable to filter URI query or fragment');
643 + }
644 + private function filterComponent(string $pattern, string $component, string $context) : string
645 + {
646 + $filtered = \preg_replace_callback($pattern, [$this, 'rawurlencodeMatchZero'], $component);
647 + if ($filtered === null) {
648 + throw new \RuntimeException($context . ': ' . \preg_last_error_msg());
649 + }
650 + return $filtered;
614 651 }
615 652 private function rawurlencodeMatchZero(array $match) : string
616 653 {
617 654 return \rawurlencode($match[0]);