From fd02fa968c895209576baebed2aad543687dea25 Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Sat, 11 Feb 2017 17:48:52 +0900 Subject: [PATCH] Fix #702 Punycode error on attempting to handle long URLs --- common/framework/url.php | 50 +++++++++++++++++++++++++++----- tests/unit/framework/URLTest.php | 6 ++++ 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/common/framework/url.php b/common/framework/url.php index f810c0082..f41c5dc09 100644 --- a/common/framework/url.php +++ b/common/framework/url.php @@ -183,38 +183,72 @@ class URL /** * Encode UTF-8 domain into IDNA (punycode) * - * @param string $domain + * @param string $url * @return string */ - public static function encodeIdna($domain) + public static function encodeIdna($url) { + if (preg_match('@[:/#]@', $url)) + { + $domain = parse_url($url, \PHP_URL_HOST); + $position = strpos($url, $domain); + if ($position === false) + { + return $url; + } + } + else + { + $domain = $url; + $position = 0; + } + if (function_exists('idn_to_ascii')) { - return idn_to_ascii($domain); + $new_domain = idn_to_ascii($domain); } else { $encoder = new \TrueBV\Punycode(); - return $encoder->encode($domain); + $new_domain = $encoder->encode($domain); } + + return substr_replace($url, $new_domain, $position, strlen($domain)); } /** * Convert IDNA (punycode) domain into UTF-8 * - * @param string $domain + * @param string $url * @return string */ - public static function decodeIdna($domain) + public static function decodeIdna($url) { + if (preg_match('@[:/#]@', $url)) + { + $domain = parse_url($url, \PHP_URL_HOST); + $position = strpos($url, $domain); + if ($position === false) + { + return $url; + } + } + else + { + $domain = $url; + $position = 0; + } + if (function_exists('idn_to_utf8')) { - return idn_to_utf8($domain); + $new_domain = idn_to_utf8($domain); } else { $decoder = new \TrueBV\Punycode(); - return $decoder->decode($domain); + $new_domain = $decoder->decode($domain); } + + return substr_replace($url, $new_domain, $position, strlen($domain)); } } diff --git a/tests/unit/framework/URLTest.php b/tests/unit/framework/URLTest.php index ed60020ee..22c8c1a38 100644 --- a/tests/unit/framework/URLTest.php +++ b/tests/unit/framework/URLTest.php @@ -105,10 +105,16 @@ class URLTest extends \Codeception\TestCase\Test public function testEncodeIdna() { $this->assertEquals('xn--9i1bl3b186bf9e.xn--3e0b707e', Rhymix\Framework\URL::encodeIdna('퓨니코드.한국')); + $this->assertEquals('http://xn--9i1bl3b186bf9e.xn--3e0b707e', Rhymix\Framework\URL::encodeIdna('http://퓨니코드.한국')); + $this->assertEquals('//xn--9i1bl3b186bf9e.xn--3e0b707e#한글부분', Rhymix\Framework\URL::encodeIdna('//퓨니코드.한국#한글부분')); + $this->assertEquals('https://xn--9i1bl3b186bf9e.xn--3e0b707e/hello/world/라이믹스.php?i=4', Rhymix\Framework\URL::encodeIdna('https://퓨니코드.한국/hello/world/라이믹스.php?i=4')); } public function testDecodeIdna() { $this->assertEquals('퓨니코드.한국', Rhymix\Framework\URL::decodeIdna('xn--9i1bl3b186bf9e.xn--3e0b707e')); + $this->assertEquals('http://퓨니코드.한국', Rhymix\Framework\URL::decodeIdna('http://xn--9i1bl3b186bf9e.xn--3e0b707e')); + $this->assertEquals('//퓨니코드.한국#한글부분', Rhymix\Framework\URL::decodeIdna('//xn--9i1bl3b186bf9e.xn--3e0b707e#한글부분')); + $this->assertEquals('https://퓨니코드.한국/hello/world/라이믹스.php?i=4', Rhymix\Framework\URL::decodeIdna('https://xn--9i1bl3b186bf9e.xn--3e0b707e/hello/world/라이믹스.php?i=4')); } }