Skip to content

Instantly share code, notes, and snippets.

@anzz1
Created August 8, 2023 12:11
Show Gist options
  • Save anzz1/8da9351a0e29935743600affb08cfb27 to your computer and use it in GitHub Desktop.
Save anzz1/8da9351a0e29935743600affb08cfb27 to your computer and use it in GitHub Desktop.
idna.class.php
<?php
class IDNA {
public static function encode($string) {
$parts = explode('.', $string);
foreach ($parts as &$part) {
$part = self::to_ascii($part);
if ($part === false) return false;
}
return implode('.', $parts);
}
public static function to_ascii($string) {
if (self::is_ascii($string)) return $string;
if (strpos($string, "xn--") === 0) return false;
$string = self::punycode_encode($string);
return ($string !== false ? "xn--$string" : false);
}
protected static function is_ascii($string) {
return (preg_match('/(?:[^\x00-\x7F])/', $string) !== 1);
}
protected static function utf8_to_codepoints($input) {
$codepoints = array();
$strlen = strlen($input);
for ($position = 0; $position < $strlen; $position++) {
$value = ord($input[$position]);
if ((~$value & 0x80) === 0x80) {
$character = $value;
$length = 1;
$remaining = 0;
}
elseif (($value & 0xE0) === 0xC0) {
$character = ($value & 0x1F) << 6;
$length = 2;
$remaining = 1;
}
elseif (($value & 0xF0) === 0xE0) {
$character = ($value & 0x0F) << 12;
$length = 3;
$remaining = 2;
}
elseif (($value & 0xF8) === 0xF0) {
$character = ($value & 0x07) << 18;
$length = 4;
$remaining = 3;
}
else {
return false;
}
if ($remaining > 0) {
if ($position + $length > $strlen) return false;
for ($position++; $remaining > 0; $position++) {
$value = ord($input[$position]);
if (($value & 0xC0) !== 0x80) {
return false;
}
$character |= ($value & 0x3F) << (--$remaining * 6);
}
$position--;
}
if ($length > 1 && $character <= 0x7F || $length > 2 && $character <= 0x7FF || $length > 3 && $character <= 0xFFFF ||
($character & 0xFFFE) === 0xFFFE || $character >= 0xFDD0 && $character <= 0xFDEF || ($character > 0xD7FF && $character < 0xF900 ||
$character < 0x20 || $character > 0x7E && $character < 0xA0 || $character > 0xEFFFD)) {
return false;
}
$codepoints[] = $character;
}
return $codepoints;
}
public static function punycode_encode($input) {
$output = '';
$n = 128;
$delta = 0;
$bias = 72;
$h = $b = 0;
$digits = 'abcdefghijklmnopqrstuvwxyz0123456789';
$extended = array();
$codepoints = self::utf8_to_codepoints($input);
if ($codepoints === false) return false;
foreach ($codepoints as $char) {
if ($char < 128) {
$output .= chr($char);
$h++;
}
elseif ($char < $n) {
return false;
}
else {
$extended[$char] = true;
}
}
$extended = array_keys($extended);
sort($extended);
$b = $h;
if (strlen($output) > 0) $output .= '-';
while ($h < count($codepoints)) {
$m = array_shift($extended);
$delta += ($m - $n) * ($h + 1);
$n = $m;
for ($num = 0; $num < count($codepoints); $num++) {
$c = $codepoints[$num];
if ($c < $n) {
$delta++;
}
elseif ($c === $n) {
$q = $delta;
for ($k = 36; ; $k += 36) {
if ($k <= ($bias + 1)) {
$t = 1;
}
elseif ($k >= ($bias + 26)) {
$t = 26;
}
else {
$t = $k - $bias;
}
if ($q < $t) {
break;
}
$digit = $t + (($q - $t) % (36 - $t));
$output .= $digits[$digit];
$q = floor(($q - $t) / (36 - $t));
}
$output .= $digits[$q];
$delta = ($h === $b) ? floor($delta / 700) : floor($delta / 2);
$delta += floor($delta / ($h + 1));
$i = 0;
$max = floor(((36 - 1) * 26) / 2);
while ($delta > $max) {
$delta = floor($delta / (36 - 1));
$i += 36;
}
$bias = $i + floor(((36 - 1 + 1) * $delta) / ($delta + 38));
$delta = 0;
$h++;
}
}
$delta++;
$n++;
}
return $output;
}
}
if (!function_exists("idn_to_ascii")) {
function idn_to_ascii($domain, $b=null, $c=null, $d=null) { return IDNA::encode($domain); }
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment