package.xml0000664000175000017500000001155112517702325011306 0ustar janjan Horde_Idna pear.horde.org IDNA backend normalization package Normalized access to various backends providing IDNA (Internationalized Domain Names in Applications) support. Michael Slusarz slusarz slusarz@horde.org yes 2015-04-28 1.0.3 1.0.0 stable stable BSD-2-Clause * [jan] Fix issues with certain locales like Turkish. 5.3.0 6.0.0alpha1 6.0.0alpha1 1.7.0 Horde_Exception pear.horde.org 2.0.0 3.0.0alpha1 3.0.0alpha1 Horde_Util pear.horde.org 2.0.0 3.0.0alpha1 3.0.0alpha1 intl 1.0.0 1.0.0 stable stable 2015-01-07 BSD-2-Clause * [mms] Initial release. 1.0.1 1.0.0 stable stable 2015-01-07 BSD-2-Clause * [jan] Fix install paths (Bug #13785). 1.0.2 1.0.0 stable stable 2015-04-13 BSD-2-Clause * [mms] Use intl extension, if installed, and fallback to a locally-patched version of the true/php-punycode package. 1.0.3 1.0.0 stable stable 2015-04-28 BSD-2-Clause * [jan] Fix issues with certain locales like Turkish. Horde_Idna-1.0.3/doc/Horde/Idna/COPYING0000664000175000017500000000246312517702325015340 0ustar janjanCopyright (c) 2014 TrueServer B.V. Copyright 2014-2015 Horde LLC. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE HORDE PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Horde_Idna-1.0.3/lib/Horde/Idna/Exception.php0000664000175000017500000000116612517702325016754 0ustar janjan * @category Horde * @copyright 2014-2015 Horde LLC * @license http://www.horde.org/licenses/bsd BSD * @package Idna */ class Horde_Idna_Exception extends Horde_Exception {} Horde_Idna-1.0.3/lib/Horde/Idna/Punycode.php0000664000175000017500000002363212517702325016606 0ustar janjan * @author Michael Slusarz * @category Horde * @copyright 2014 TrueServer B.V. * @copyright 2015 Horde LLC * @license http://www.horde.org/licenses/bsd BSD * @link http://tools.ietf.org/html/rfc3492 * @package Idna */ class Horde_Idna_Punycode { /** * Bootstring parameter values. */ const BASE = 36; const TMIN = 1; const TMAX = 26; const SKEW = 38; const DAMP = 700; const INITIAL_BIAS = 72; const INITIAL_N = 128; const PREFIX = 'xn--'; const DELIMITER = '-'; /** * Encode table. * * @param array */ protected static $_encodeTable = array( 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ); /** * Decode table. * * @param array */ protected static $_decodeTable = array( 'a' => 0, 'b' => 1, 'c' => 2, 'd' => 3, 'e' => 4, 'f' => 5, 'g' => 6, 'h' => 7, 'i' => 8, 'j' => 9, 'k' => 10, 'l' => 11, 'm' => 12, 'n' => 13, 'o' => 14, 'p' => 15, 'q' => 16, 'r' => 17, 's' => 18, 't' => 19, 'u' => 20, 'v' => 21, 'w' => 22, 'x' => 23, 'y' => 24, 'z' => 25, '0' => 26, '1' => 27, '2' => 28, '3' => 29, '4' => 30, '5' => 31, '6' => 32, '7' => 33, '8' => 34, '9' => 35 ); /** * Encode a domain to its Punycode version. * * @param string $input Domain name in Unicde to be encoded. * * @return string Punycode representation in ASCII. */ public function encode($input) { $parts = explode('.', $input); foreach ($parts as &$part) { $part = $this->_encodePart($part); } return implode('.', $parts); } /** * Encode a part of a domain name, such as tld, to its Punycode version. * * @param string $input Part of a domain name. * * @return string Punycode representation of a domain part. */ protected function _encodePart($input) { $codePoints = $this->_codePoints($input); $n = static::INITIAL_N; $bias = static::INITIAL_BIAS; $delta = 0; $h = $b = count($codePoints['basic']); $output = ''; foreach ($codePoints['basic'] as $code) { $output .= $this->_codePointToChar($code); } if ($input === $output) { return $output; } if ($b > 0) { $output .= static::DELIMITER; } $codePoints['nonBasic'] = array_unique($codePoints['nonBasic']); sort($codePoints['nonBasic']); $i = 0; $length = Horde_String::length($input, 'UTF-8'); while ($h < $length) { $m = $codePoints['nonBasic'][$i++]; $delta = $delta + ($m - $n) * ($h + 1); $n = $m; foreach ($codePoints['all'] as $c) { if (($c < $n) || ($c < static::INITIAL_N)) { ++$delta; } if ($c === $n) { $q = $delta; for ($k = static::BASE; ; $k += static::BASE) { $t = $this->_calculateThreshold($k, $bias); if ($q < $t) { break; } $code = $t + (($q - $t) % (static::BASE - $t)); $output .= static::$_encodeTable[$code]; $q = ($q - $t) / (static::BASE - $t); } $output .= static::$_encodeTable[$q]; $bias = $this->_adapt($delta, $h + 1, ($h === $b)); $delta = 0; ++$h; } } ++$delta; ++$n; } return static::PREFIX . $output; } /** * Decode a Punycode domain name to its Unicode counterpart. * * @param string $input Domain name in Punycode * * @return string Unicode domain name. */ public function decode($input) { $parts = explode('.', $input); foreach ($parts as &$part) { if (strpos($part, static::PREFIX) === 0) { $part = $this->_decodePart( substr($part, strlen(static::PREFIX)) ); } } return implode('.', $parts); } /** * Decode a part of domain name, such as tld. * * @param string $input Part of a domain name. * * @return string Unicode domain part. */ protected function _decodePart($input) { $n = static::INITIAL_N; $i = 0; $bias = static::INITIAL_BIAS; $output = ''; $pos = strrpos($input, static::DELIMITER); if ($pos !== false) { $output = substr($input, 0, $pos++); } else { $pos = 0; } $outputLength = strlen($output); $inputLength = strlen($input); /* Punycode lookup is case-insensitive. */ $input = Horde_String::lower($input); while ($pos < $inputLength) { $oldi = $i; $w = 1; for ($k = static::BASE; ; $k += static::BASE) { $digit = static::$_decodeTable[$input[$pos++]]; $i = $i + ($digit * $w); $t = $this->_calculateThreshold($k, $bias); if ($digit < $t) { break; } $w = $w * (static::BASE - $t); } $bias = $this->_adapt($i - $oldi, ++$outputLength, ($oldi === 0)); $n = $n + (int) ($i / $outputLength); $i = $i % ($outputLength); $output = Horde_String::substr($output, 0, $i, 'UTF-8') . $this->_codePointToChar($n) . Horde_String::substr($output, $i, $outputLength - 1, 'UTF-8'); ++$i; } return $output; } /** * Calculate the bias threshold to fall between TMIN and TMAX. * * @param integer $k * @param integer $bias * * @return integer */ protected function _calculateThreshold($k, $bias) { if ($k <= ($bias + static::TMIN)) { return static::TMIN; } elseif ($k >= ($bias + static::TMAX)) { return static::TMAX; } return $k - $bias; } /** * Bias adaptation. * * @param integer $delta * @param integer $numPoints * @param boolean $firstTime * * @return integer */ protected function _adapt($delta, $numPoints, $firstTime) { $delta = (int) ( ($firstTime) ? $delta / static::DAMP : $delta / 2 ); $delta += (int) ($delta / $numPoints); $k = 0; while ($delta > ((static::BASE - static::TMIN) * static::TMAX) / 2) { $delta = (int) ($delta / (static::BASE - static::TMIN)); $k = $k + static::BASE; } $k = $k + (int) (((static::BASE - static::TMIN + 1) * $delta) / ($delta + static::SKEW)); return $k; } /** * List code points for a given input. * * @param string $input * * @return array Multi-dimension array with basic, non-basic and * aggregated code points. */ protected function _codePoints($input) { $codePoints = array( 'all' => array(), 'basic' => array(), 'nonBasic' => array() ); $len = Horde_String::length($input, 'UTF-8'); for ($i = 0; $i < $len; ++$i) { $char = Horde_String::substr($input, $i, 1, 'UTF-8'); $code = $this->_charToCodePoint($char); if ($code < 128) { $codePoints['all'][] = $codePoints['basic'][] = $code; } else { $codePoints['all'][] = $codePoints['nonBasic'][] = $code; } } return $codePoints; } /** * Convert a single or multi-byte character to its code point. * * @param string $char * * @return integer */ protected function _charToCodePoint($char) { $code = ord($char[0]); if ($code < 128) { return $code; } elseif ($code < 224) { return (($code - 192) * 64) + (ord($char[1]) - 128); } elseif ($code < 240) { return (($code - 224) * 4096) + ((ord($char[1]) - 128) * 64) + (ord($char[2]) - 128); } return (($code - 240) * 262144) + ((ord($char[1]) - 128) * 4096) + ((ord($char[2]) - 128) * 64) + (ord($char[3]) - 128); } /** * Convert a code point to its single or multi-byte character * * @param integer $code * * @return string */ protected function _codePointToChar($code) { if ($code <= 0x7F) { return chr($code); } elseif ($code <= 0x7FF) { return chr(($code >> 6) + 192) . chr(($code & 63) + 128); } elseif ($code <= 0xFFFF) { return chr(($code >> 12) + 224) . chr((($code >> 6) & 63) + 128) . chr(($code & 63) + 128); } return chr(($code >> 18) + 240) . chr((($code >> 12) & 63) + 128) . chr((($code >> 6) & 63) + 128) . chr(($code & 63) + 128); } } Horde_Idna-1.0.3/lib/Horde/Idna.php0000664000175000017500000000470412517702325015017 0ustar janjan * @category Horde * @copyright 2014-2015 Horde LLC * @license http://www.horde.org/licenses/bsd BSD * @package Idna */ class Horde_Idna { /** * The backend to use. * * @var mixed */ protected static $_backend; /** * @throws Horde_Idna_Exception */ public static function encode($data) { switch ($backend = static::_getBackend()) { case 'INTL': return idn_to_ascii($data); case 'INTL_UTS46': return idn_to_ascii($data, 0, INTL_IDNA_VARIANT_UTS46); default: return $backend->encode($data); } } /** * @throws Horde_Idna_Exception */ public static function decode($data) { switch ($backend = static::_getBackend()) { case 'INTL': case 'INTL_UTS46': $parts = explode('.', $data); foreach ($parts as &$part) { if (strpos($part, 'xn--') === 0) { switch ($backend) { case 'INTL': $part = idn_to_utf8($part); break; case 'INTL_UTS46': $part = idn_to_utf8($part, 0, INTL_IDNA_VARIANT_UTS46); break; } } } return implode('.', $parts); default: return $backend->decode($data); } } /** * Return the IDNA backend. * * @return mixed IDNA backend (false if none available). */ protected static function _getBackend() { if (!isset(self::$_backend)) { if (extension_loaded('intl')) { /* Only available in PHP > 5.4.0 */ self::$_backend = defined('INTL_IDNA_VARIANT_UTS46') ? 'INTL_UTS46' : 'INTL'; } else { self::$_backend = new Horde_Idna_Punycode(); } } return self::$_backend; } } Horde_Idna-1.0.3/test/Horde/Idna/AllTests.php0000664000175000017500000000013212517702325016752 0ustar janjanrun(); Horde_Idna-1.0.3/test/Horde/Idna/bootstrap.php0000664000175000017500000000014312517702325017236 0ustar janjanassertEquals( $encoded, $idna->encode($decoded) ); } /** * @dataProvider domainNamesProvider */ public function testDecode($decoded, $encoded) { $idna = new Horde_Idna(); $this->assertEquals( $decoded, $idna->decode($encoded) ); } /** */ public function domainNamesProvider() { return array( // http://en.wikipedia.org/wiki/.test_(international_domain_name)#Test_TLDs array( 'مثال.إختبار', 'xn--mgbh0fb.xn--kgbechtv', ), array( 'مثال.آزمایشی', 'xn--mgbh0fb.xn--hgbk6aj7f53bba', ), array( '例子.测试', 'xn--fsqu00a.xn--0zwm56d', ), array( '例子.測試', 'xn--fsqu00a.xn--g6w251d', ), array( 'пример.испытание', 'xn--e1afmkfd.xn--80akhbyknj4f', ), array( 'उदाहरण.परीक्षा', 'xn--p1b6ci4b4b3a.xn--11b5bs3a9aj6g', ), array( 'παράδειγμα.δοκιμή', 'xn--hxajbheg2az3al.xn--jxalpdlp', ), array( '실례.테스트', 'xn--9n2bp8q.xn--9t4b11yi5a', ), array( 'בײַשפּיל.טעסט', 'xn--fdbk5d8ap9b8a8d.xn--deba0ad', ), array( '例え.テスト', 'xn--r8jz45g.xn--zckzah', ), array( 'உதாரணம்.பரிட்சை', 'xn--zkc6cc5bi7f6e.xn--hlcj6aya9esc7a', ), array( 'derhausüberwacher.de', 'xn--derhausberwacher-pzb.de', ), array( 'renangonçalves.com', 'xn--renangonalves-pgb.com', ), array( 'рф.ru', 'xn--p1ai.ru', ), array( 'δοκιμή.gr', 'xn--jxalpdlp.gr', ), array( 'ফাহাদ্১৯.বাংলা', 'xn--65bj6btb5gwimc.xn--54b7fta0cc', ), array( '𐌀𐌖𐌋𐌄𐌑𐌉·𐌌𐌄𐌕𐌄𐌋𐌉𐌑.gr', 'xn--uba5533kmaba1adkfh6ch2cg.gr', ), array( 'guangdong.广东', 'guangdong.xn--xhq521b', ), array( 'gwóźdź.pl', 'xn--gwd-hna98db.pl', ), ); } } Horde_Idna-1.0.3/test/Horde/Idna/phpunit.xml0000664000175000017500000000005612517702325016724 0ustar janjan