<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
// (c) https://github.com/IgorVBelousov/php_idn
// (c) http://belousovv.ru/myscript/phpIDN
/**
* Finds the character code for a UTF-8 character: like ord() but for UTF-8.
*
* @author Nicolas Thouvenin <nthouvenin@gmail.com>
* @copyright 2008 Nicolas Thouvenin
* @license http://opensource.org/licenses/LGPL-2.1 LGPL v2.1
*/
function mso_ordUTF8($c, $index = 0, &$bytes = null)
{
$len = strlen($c);
$bytes = 0;
if ($index >= $len)
return false;
$h = ord($c{
$index});
if ($h <= 0x7F) {
$bytes = 1;
return $h;
} else if ($h < 0xC2)
return false;
else if ($h <= 0xDF && $index < $len - 1) {
$bytes = 2;
return ($h & 0x1F) << 6 | (ord($c{
$index + 1}) & 0x3F);
} else if ($h <= 0xEF && $index < $len - 2) {
$bytes = 3;
return ($h & 0x0F) << 12 | (ord($c{
$index + 1}) & 0x3F) << 6
| (ord($c{
$index + 2}) & 0x3F);
} else if ($h <= 0xF4 && $index < $len - 3) {
$bytes = 4;
return ($h & 0x0F) << 18 | (ord($c{
$index + 1}) & 0x3F) << 12
| (ord($c{
$index + 2}) & 0x3F) << 6
| (ord($c{
$index + 3}) & 0x3F);
} else
return false;
}
/**
* Encode UTF-8 domain name to IDN Punycode
*
* @param string $value Domain name
* @return string Encoded Domain name
*
* @author Igor V Belousov <igor@belousovv.ru>
* @copyright 2013, 2015 Igor V Belousov
* @license http://opensource.org/licenses/LGPL-2.1 LGPL v2.1
* @link http://belousovv.ru/myscript/phpIDN
*/
function mso_EncodePunycodeIDN($value)
{
if (function_exists('idn_to_ascii')) {
return idn_to_ascii($value);
}
/* search subdomains */
$sub_domain = explode('.', $value);
if (count($sub_domain) > 1) {
$sub_result = '';
foreach ($sub_domain as $sub_value) {
$sub_result .= '.' . mso_EncodePunycodeIDN($sub_value);
}
return substr($sub_result, 1);
}
/* http://tools.ietf.org/html/rfc3492#section-6.3 */
$n = 0x80;
$delta = 0;
$bias = 72;
$output = [];
$input = [];
$str = $value;
while (mb_strlen($str, 'UTF-8') > 0) {
array_push($input, mb_substr($str, 0, 1, 'UTF-8'));
$str = (version_compare(PHP_VERSION, '5.4.8', '<')) ? mb_substr($str, 1, mb_strlen($str, 'UTF-8'), 'UTF-8') : mb_substr($str, 1, null, 'UTF-8');
}
/* basic symbols */
$basic = preg_grep('/[\x00-\x7f]/', $input);
$b = $basic;
if ($b == $input) {
return $value;
}
$b = count($b);
if ($b > 0) {
$output = $basic;
/* add delimeter */
$output[] = '-';
}
unset($basic);
/* add prefix */
array_unshift($output, 'xn--');
$input_len = count($input);
$h = $b;
$ord_input = [];
while ($h < $input_len) {
$m = 0x10FFFF;
for ($i = 0; $i < $input_len; ++$i) {
$ord_input[$i] = mso_ordUtf8($input[$i]);
if (($ord_input[$i] >= $n) && ($ord_input[$i] < $m)) {
$m = $ord_input[$i];
}
}
if (($m - $n) > (0x10FFFF / ($h + 1))) {
return $value;
}
$delta += ($m - $n) * ($h + 1);
$n = $m;
for ($i = 0; $i < $input_len; ++$i) {
$c = $ord_input[$i];
if ($c < $n) {
++$delta;
if ($delta == 0) {
return $value;
}
}
if ($c == $n) {
$q = $delta;
for ($k = 36;; $k += 36) {
if ($k <= $bias) {
$t = 1;
} elseif ($k >= ($bias + 26)) {
$t = 26;
} else {
$t = $k - $bias;
}
if ($q < $t) {
break;
}
$tmp_int = $t + ($q - $t) % (36 - $t);
$output[] = chr(($tmp_int + 22 + 75 * ($tmp_int < 26)));
$q = ($q - $t) / (36 - $t);
}
$output[] = chr(($q + 22 + 75 * ($q < 26)));
/* http://tools.ietf.org/html/rfc3492#section-6.1 */
$delta = ($h == $b) ? $delta / 700 : $delta >> 1;
$delta += intval($delta / ($h + 1));
$k2 = 0;
while ($delta > 455) {
$delta /= 35;
$k2 += 36;
}
$bias = intval($k2 + 36 * $delta / ($delta + 38));
/* end section-6.1 */
$delta = 0;
++$h;
}
}
++$delta;
++$n;
}
return implode('', $output);
}
/**
* Decode IDN Punycode to UTF-8 domain name
*
* @param string $value Punycode
* @return string Domain name in UTF-8 charset
*
* @author Igor V Belousov <igor@belousovv.ru>
* @copyright 2013, 2015 Igor V Belousov
* @license http://opensource.org/licenses/LGPL-2.1 LGPL v2.1
* @link http://belousovv.ru/myscript/phpIDN
*/
function mso_DecodePunycodeIDN($value)
{
if (function_exists('idn_to_utf8')) {
return idn_to_utf8($value);
}
/* search subdomains */
$sub_domain = explode('.', $value);
if (count($sub_domain) > 1) {
$sub_result = '';
foreach ($sub_domain as $sub_value) {
$sub_result .= '.' . mso_DecodePunycodeIDN($sub_value);
}
return substr($sub_result, 1);
}
/* search prefix */
if (substr($value, 0, 4) != 'xn--') {
return $value;
} else {
$bad_input = $value;
$value = substr($value, 4);
}
$n = 0x80;
$i = 0;
$bias = 72;
$output = [];
/* search delimeter */
$d = strrpos($value, '-');
if ($d > 0) {
for ($j = 0; $j < $d; ++$j) {
$c = $value[$j];
$output[] = $c;
if ($c > 0x7F) {
return $bad_input;
}
}
++$d;
} else {
$d = 0;
}
while ($d < strlen($value)) {
$old_i = $i;
$w = 1;
for ($k = 36;; $k += 36) {
if ($d == strlen($value)) {
return $bad_input;
}
$c = $value[$d++];
$c = ord($c);
$digit = ($c - 48 < 10) ? $c - 22 : (
($c - 65 < 26) ? $c - 65 : (
($c - 97 < 26) ? $c - 97 : 36));
if ($digit > (0x10FFFF - $i) / $w) {
return $bad_input;
}
$i += $digit * $w;
if ($k <= $bias) {
$t = 1;
} elseif ($k >= $bias + 26) {
$t = 26;
} else {
$t = $k - $bias;
}
if ($digit < $t) {
break;
}
$w *= 36 - $t;
}
$delta = $i - $old_i;
/* http://tools.ietf.org/html/rfc3492#section-6.1 */
$delta = ($old_i == 0) ? $delta / 700 : $delta >> 1;
$count_output_plus_one = count($output) + 1;
$delta += intval($delta / $count_output_plus_one);
$k2 = 0;
while ($delta > 455) {
$delta /= 35;
$k2 += 36;
}
$bias = intval($k2 + 36 * $delta / ($delta + 38));
/* end section-6.1 */
if ($i / $count_output_plus_one > 0x10FFFF - $n) {
return $bad_input;
}
$n += intval($i / $count_output_plus_one);
$i %= $count_output_plus_one;
array_splice(
$output,
$i,
0,
html_entity_decode('&#' . $n . ';', ENT_NOQUOTES, 'UTF-8')
);
++$i;
}
return implode('', $output);
}
# end of file