Fix #702 Punycode error on attempting to handle long URLs

This commit is contained in:
Kijin Sung 2017-02-11 17:48:52 +09:00
parent 38e3c8282a
commit fd02fa968c
2 changed files with 48 additions and 8 deletions

View file

@ -183,38 +183,72 @@ class URL
/** /**
* Encode UTF-8 domain into IDNA (punycode) * Encode UTF-8 domain into IDNA (punycode)
* *
* @param string $domain * @param string $url
* @return string * @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')) if (function_exists('idn_to_ascii'))
{ {
return idn_to_ascii($domain); $new_domain = idn_to_ascii($domain);
} }
else else
{ {
$encoder = new \TrueBV\Punycode(); $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 * Convert IDNA (punycode) domain into UTF-8
* *
* @param string $domain * @param string $url
* @return string * @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')) if (function_exists('idn_to_utf8'))
{ {
return idn_to_utf8($domain); $new_domain = idn_to_utf8($domain);
} }
else else
{ {
$decoder = new \TrueBV\Punycode(); $decoder = new \TrueBV\Punycode();
return $decoder->decode($domain); $new_domain = $decoder->decode($domain);
} }
return substr_replace($url, $new_domain, $position, strlen($domain));
} }
} }

View file

@ -105,10 +105,16 @@ class URLTest extends \Codeception\TestCase\Test
public function testEncodeIdna() public function testEncodeIdna()
{ {
$this->assertEquals('xn--9i1bl3b186bf9e.xn--3e0b707e', Rhymix\Framework\URL::encodeIdna('퓨니코드.한국')); $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() public function testDecodeIdna()
{ {
$this->assertEquals('퓨니코드.한국', Rhymix\Framework\URL::decodeIdna('xn--9i1bl3b186bf9e.xn--3e0b707e')); $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'));
} }
} }