From edac618d3483ce2ae1880639e688c8ceb71df390 Mon Sep 17 00:00:00 2001 From: ignace nyamagana butera Date: Tue, 25 Jun 2024 07:09:01 +0200 Subject: [PATCH] Improve documentation --- components/Components/Host.php | 27 +------------ docs/_data/menu.yml | 1 + docs/components/7.0/host.md | 6 +++ docs/components/7.0/modifiers.md | 30 ++++++++++++++ docs/interfaces/7.0/contracts.md | 10 +++-- docs/interfaces/7.0/ipv6.md | 41 +++++++++++++++++++ interfaces/IPv6/Converter.php | 68 ++++++++++++++++++++++++-------- 7 files changed, 137 insertions(+), 46 deletions(-) create mode 100644 docs/interfaces/7.0/ipv6.md diff --git a/components/Components/Host.php b/components/Components/Host.php index e13a8a2e..a1cf04b9 100644 --- a/components/Components/Host.php +++ b/components/Components/Host.php @@ -336,35 +336,12 @@ public function toUnicode(): ?string public function compress(): ?string { - if ('6' !== $this->ipVersion) { - return $this->host; - } - - /** @var string $ip */ - $ip = $this->getIp(); - if (! $this->hasZoneIdentifier) { - return '['. Converter::compress($ip) .']'; - } - - [$ipv6, $zoneId] = explode('%', $ip, 2); - - return '['. Converter::compress($ipv6) . '%' . $zoneId . ']'; + return Converter::compress($this->value()); } public function expand(): ?string { - if ('6' !== $this->ipVersion) { - return $this->host; - } - - /** @var string $ip */ - $ip = $this->getIp(); - [$ipv6, $zoneId] = explode('%', $ip, 2); - - return match ($this->hasZoneIdentifier) { - false => '['.Converter::expand($ipv6).']', - true => '['.Converter::expand($ipv6). '%' . $zoneId.']', - }; + return Converter::expand($this->value()); } public function getIpVersion(): ?string diff --git a/docs/_data/menu.yml b/docs/_data/menu.yml index a30d3f9f..1b091dd6 100644 --- a/docs/_data/menu.yml +++ b/docs/_data/menu.yml @@ -29,6 +29,7 @@ packages: URI Parser: '/interfaces/7.0/uri-parser-builder/' Query Parser: '/interfaces/7.0/query-parser-builder/' IPv4 Converter: '/interfaces/7.0/ipv4/' + IPv6 Converter: '/interfaces/7.0/ipv6/' IDN Converter: '/interfaces/7.0/idn/' '2.0': Documentation: diff --git a/docs/components/7.0/host.md b/docs/components/7.0/host.md index 2393b31e..f01810d7 100644 --- a/docs/components/7.0/host.md +++ b/docs/components/7.0/host.md @@ -73,8 +73,14 @@ public Host::isIpv6(): bool public Host::isIpFuture(): bool public Host::hasZoneIdentifier(): bool public Host::withoutZoneIdentifier(): self +public Host::compress(): string +public Host::expand(): string ~~~ +

The Host::compress and Host::expand, +are added in version 7.6.0 and normalized an IPv6 host, See the IPv6 Converter documentation page for more information. +

+ ### Host::fromIp This method allows creating a Host object from an IP. diff --git a/docs/components/7.0/modifiers.md b/docs/components/7.0/modifiers.md index 6718dca1..824ac745 100644 --- a/docs/components/7.0/modifiers.md +++ b/docs/components/7.0/modifiers.md @@ -368,6 +368,36 @@ echo Modifier::from($uri)->hostToOctal()->getUri(); //display 'http://0xc0a811/path/to/the/sky.php' ~~~ +### Modifier::hostToIpv6Compressed + +Normalizes the URI host content to a compressed IPv6 notation if possible. +See the [IPv6 Converter documentation](/components/7.0/ipv6/) page for more information. + +~~~php +hostToIpv6Compressed()->getUriString(); +//display 'http://[1050::5:0:300c:326b]/path/to/the/sky.php' +~~~ + +### Modifier::hostToIpv6Expanded + +Normalizes the URI host content to a expanded IPv6 notation if possible. +See the [IPv6 Converter documentation](/components/7.0/ipv6/) page for more information. + +~~~php +hostToIpv6Compressed()->getUriString(); +//display 'http://[::1]/path/to/the/sky.php' +~~~ + ### Modifier::removeZoneIdentifier Removes the host zone identifier if present diff --git a/docs/interfaces/7.0/contracts.md b/docs/interfaces/7.0/contracts.md index 3fd0c240..a55bf1d4 100644 --- a/docs/interfaces/7.0/contracts.md +++ b/docs/interfaces/7.0/contracts.md @@ -27,6 +27,8 @@ The `UriInterface` interface defines the following methods to access the URI str public UriInterface::getScheme(): ?string public UriInterface::getUserInfo(): ?string +public UriInterface::getUsername(): ?string +public UriInterface::getPassword(): ?string public UriInterface::getHost(): ?string public UriInterface::getPort(): ?int public UriInterface::getAuthority(): ?string @@ -51,7 +53,7 @@ Delimiter characters are not part of the URI component and **must not** be added null, - self::isValidIpv6($ipv6) => (string) inet_ntop((string) inet_pton((string) $ipv6)), - default => (string) $ipv6, + if ($host === null) { + return $host; + } + + $host = (string) $host; + if ($host === '') { + return $host; + } + + if (!str_starts_with($host, '[')) { + return $host; + } + + if (!str_ends_with($host, ']')) { + return $host; + } + + [$ipv6, $zoneIdentifier] = explode('%', substr($host, 1, -1), 2) + [1 => null]; + if (!filter_var($ipv6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { + return $host; + } + $ipv6Compressed = (string) inet_ntop((string) inet_pton((string) $ipv6)); + + return match ($zoneIdentifier) { + null => "[$ipv6Compressed]", + default => "[$ipv6Compressed%$zoneIdentifier]", }; } - public static function expand(Stringable|string|null $ipv6): ?string + public static function expand(Stringable|string|null $host): ?string { - if (null === $ipv6) { - return null; + if ($host === null) { + return $host; } - $ipv6 = (string) $ipv6; - if (!self::isValidIpv6($ipv6)) { - return $ipv6; + $host = (string) $host; + if ($host === '') { + return $host; } - $hex = (array) unpack("H*hex", (string) inet_pton($ipv6)); + if (!str_starts_with($host, '[')) { + return $host; + } - return implode(':', str_split(strtolower($hex['hex'] ?? ''), 4)); - } + if (!str_ends_with($host, ']')) { + return $host; + } - private static function isValidIpv6(Stringable|string|null $ipv6): bool - { - return (bool) filter_var((string) $ipv6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6); + [$ipv6, $zoneIdentifier] = explode('%', substr($host, 1, -1), 2) + [1 => null]; + if (!filter_var($ipv6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { + return $host; + } + + $hex = (array) unpack("H*hex", (string) inet_pton($ipv6)); + $ipv6Expanded = implode(':', str_split(strtolower($hex['hex'] ?? ''), 4)); + + return match ($zoneIdentifier) { + null => "[$ipv6Expanded]", + default => "[$ipv6Expanded%$zoneIdentifier]", + }; } }