diff --git a/src/Punycode.php b/src/Punycode.php index fbc54dd..7fa211d 100644 --- a/src/Punycode.php +++ b/src/Punycode.php @@ -77,7 +77,14 @@ public function __construct($encoding = 'UTF-8') public function encode($input) { $input = mb_strtolower($input, $this->encoding); + + $isFQDN = false; + if (substr($input, -1) === '.') { + $isFQDN = true; + $input = substr($input, 0, -1); + } $parts = explode('.', $input); + foreach ($parts as &$part) { $length = strlen($part); if ($length < 1) { @@ -85,7 +92,12 @@ public function encode($input) } $part = $this->encodePart($part); } + $output = implode('.', $parts); + if ($isFQDN) { + $output .= '.'; + } + $length = strlen($output); if ($length > 255) { throw new DomainOutOfBoundsException(sprintf('A full domain name is limited to 255 octets (including the separators), %s given.', $length)); @@ -176,7 +188,14 @@ protected function encodePart($input) public function decode($input) { $input = strtolower($input); + + $isFQDN = false; + if (substr($input, -1) === '.') { + $isFQDN = true; + $input = substr($input, 0, -1); + } $parts = explode('.', $input); + foreach ($parts as &$part) { $length = strlen($part); if ($length > 63 || $length < 1) { @@ -190,6 +209,9 @@ public function decode($input) $part = $this->decodePart($part); } $output = implode('.', $parts); + if ($isFQDN) { + $output .= '.'; + } $length = strlen($output); if ($length > 255) { throw new DomainOutOfBoundsException(sprintf('A full domain name is limited to 255 octets (including the separators), %s given.', $length)); diff --git a/tests/PunycodeTest.php b/tests/PunycodeTest.php index 5c87223..e5e840d 100644 --- a/tests/PunycodeTest.php +++ b/tests/PunycodeTest.php @@ -150,6 +150,10 @@ public function domainNamesProvider() 'άέήίΰαβγδεζηθικλμνξοπρσστυφχ.com', 'xn--hxacdefghijklmnopqrstuvw0caz0a1a2a.com' ), + array( + '你好.世界.', + 'xn--6qq79v.xn--rhqv96g.' + ), ); } @@ -201,6 +205,12 @@ public function invalidUtf8DomainNamesProvider() '\TrueBV\Exception\LabelOutOfBoundsException', 'The length of any one label is limited to between 1 and 63 octets, but 0 given.', ), + array( + '你好.世界..', + '\TrueBV\Exception\LabelOutOfBoundsException', + 'The length of any one label is limited to between 1 and 63 octets, but 0 given.', + ), + ); } @@ -253,6 +263,11 @@ public function invalidAsciiDomainNameProvider() '\TrueBV\Exception\DomainOutOfBoundsException', 'A full domain name is limited to 255 octets (including the separators), 256 given.', ), + array( + 'xn--6qq79v.xn--rhqv96g..', + '\TrueBV\Exception\LabelOutOfBoundsException', + 'The length of any one label is limited to between 1 and 63 octets, but 0 given.', + ), ); } }