Created
August 8, 2023 12:11
-
-
Save anzz1/8da9351a0e29935743600affb08cfb27 to your computer and use it in GitHub Desktop.
idna.class.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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