3v4l.org

run code in 150+ php & hhvm versions
Bugs & Features
<?php class LinkedList { /** @var LinkedListBucket */ public $first; /** @var LinkedListBucket */ public $last; public $length = 0; public $min = PHP_INT_MAX; public function append(LinkedListBucket $bucket) { $this->last->next = $bucket; $this->last = $bucket; $this->length++; if ($bucket->codePoint < $this->min) { $this->min = $bucket->codePoint; } } public function insert(LinkedListBucket $after, LinkedListBucket $new) { $new->next = $after->next; $after->next = $new; if ($after === $this->last) { $this->last = $new; } $this->length++; if ($new->codePoint < $this->min) { $this->min = $new->codePoint; } } } class LinkedListBucket { public $pos; public $codePoint; public $raw; public $rawLen; /** @var LinkedListBucket */ public $next; public function __construct($pos, $codePoint, $raw = null, $rawLen = 0) { $this->pos = $pos; $this->codePoint = $codePoint; $this->raw = $raw; $this->rawLen = $rawLen; } } class Punycode { const BASE = 36; const T_MIN = 1; const T_MAX = 26; const SKEW = 38; const DAMP = 700; const INITIAL_BIAS = 72; const INITIAL_N = 128; private function decodeUtf8Character($input, $i, &$codePoint = null) { $input = array_values(unpack('C*', substr($input, $i, 4))); $count = count($input); switch (true) { case $count >= 2 && ($input[0] & 0xE0) === 0xC0 && ($input[1] & 0xC0) === 0x80: $codePoint = (($input[0] & 0x1F) << 6) | ($input[1] & 0x3F); return 2; case $count >= 3 && ($input[0] & 0xF0) === 0xE0 && (($input[1] ^ 0x40) & ($input[2] ^ 0x40) & 0xC0) === 0xC0: $codePoint = (($input[0] & 0x0F) << 12) | (($input[1] & 0x3F) << 6) | ($input[2] & 0x3F); return 3; case $count >= 4 && ($input[0] & 0xF8) === 0xF0 && (($input[1] ^ 0x40) & ($input[2] ^ 0x40) & ($input[3] ^ 0x40) & 0xC0) === 0xC0: $codePoint = (($input[0] & 0x07) << 18) | (($input[1] & 0x3F) << 12) | (($input[2] & 0x3F) << 6) | ($input[3] & 0x3F); return 4; } return 0; } private function encodeUtf8CodePoint($codePoint) { switch (true) { case $codePoint < 0x80: return pack('C*', $codePoint & 0x7F); case $codePoint < 0x0800: return pack('C*', (($codePoint & 0x07C0) >> 6) | 0xC0, ($codePoint & 0x3F) | 0x80); case $codePoint < 0x010000: return pack('C*', (($codePoint & 0xF000) >> 12) | 0xE0, (($codePoint & 0x0FC0) >> 6) | 0x80, ($codePoint & 0x3F) | 0x80); case $codePoint < 0x110000: return pack('C*', (($codePoint & 0x1C0000) >> 18) | 0xF0, (($codePoint & 0x03F000) >> 12) | 0x80, (($codePoint & 0x0FC0) >> 6) | 0x80, ($codePoint & 0x3F) | 0x80); } return false; } private function isDnsLabelChar($charCode) { return ($charCode >= 0x61 && $charCode <= 0x7A) // lower-case letter || ($charCode >= 0x30 && $charCode <= 0x39) // digit || $charCode === 0x2D // - || ($charCode >= 0x41 && $charCode <= 0x5A); // upper-case letter; } private function isPrintableLatin1Char($charCode) { return $charCode >= 0xA0; } private function adaptBias($delta, $numPoints, $first) { $delta = $first ? $delta / self::DAMP : $delta / 2; $delta += $delta / $numPoints; $div = self::BASE - self::T_MIN; $end = ($div * self::T_MAX) / 2; for ($k = 0; $delta > $end; $k += self::BASE) { $delta = (int)($delta / $div); } return $k + (($div + 1) * $delta) / ($delta + self::SKEW); } private function decodeDigit($digits, $index) { if (isset($digits[$index])) { $codePoint = ord($digits[$index]); if ($codePoint >= 0x61 && $codePoint <= 0x7A) { return $codePoint - 97; } else if ($codePoint >= 0x30 && $codePoint <= 0x39) { return $codePoint - 22; } } return false; } private function encodeDigit($digit) { if ($digit <= 25) { return $digit + 97; } else if ($digit <= 35) { return $digit + 22; } return false; } private function decodeLabel($input) { if (substr($input, 0, 4) !== 'xn--') { return $input; } $input = substr($input, 4); if (false !== $nonBasicCharsStart = strrpos($input, '-')) { $output = str_split(substr($input, 0, $nonBasicCharsStart), 1); $nonBasicChars = substr($input, $nonBasicCharsStart + 1); } else { $output = []; $nonBasicChars = $input; } $n = self::INITIAL_N; $bias = self::INITIAL_BIAS; $c = count($output) + 1; for ($i = $j = 0, $l = strlen($nonBasicChars); $j < $l; $i++) { $oldi = $i; $w = 1; for ($k = self::BASE;; $k+= self::BASE) { if (false === $digit = $this->decodeDigit($nonBasicChars, $j++)) { return false; } $i += $digit * $w; if ($k <= $bias) { $t = self::T_MIN; } else if ($k >= $bias + self::T_MAX) { $t = self::T_MAX; } else { $t = $k - $bias; } if ($digit < $t) { break; } $w *= (int) (self::BASE - $t); } $bias = $this->adaptBias($i - $oldi, $c, $oldi === 0); $n += (int)($i / $c); $i %= $c++; array_splice($output, $i, 0, [$this->encodeUtf8CodePoint($n)]); } return implode('', $output); } public function decode($input) { $output = []; foreach (explode('.', strtolower($input)) as $label) { if (false === $label = $this->decodeLabel($label)) { return false; } $output[] = $label; } return implode('.', $output); } private function getEncodingParts($input, &$output = null, &$nonBasicChars = null) { $isUtf8 = true; $output = []; $nonBasicChars = new LinkedList; for ($i = $p = 0, $l = strlen($input); $i < $l; $p++) { $charCode = ord($input[$i]); if ($charCode & 0x80) { if ($isUtf8) { if ($len = $this->decodeUtf8Character($input, $i, $codePoint)) { // undecoded data is stored for UTF-8 chars to facilitate conversion to latin1 if necessary $nonBasicChars->append(new LinkedListBucket($p, $codePoint, substr($input, $i, $len), $len)); $i += $len; } else { // not a valid UTF-8 code point, convert $nonBasicChars to latin1 representation if (!$this->isPrintableLatin1Char($charCode)) { return false; } $isUtf8 = false; if ($nonBasicChars->length > 0) { $offset = 0; $current = $nonBasicChars->first; do { $base = $current->pos; $current->pos += $offset; $current->codePoint = ord($current->raw[0]); for ($k = 1; $k < $current->rawLen; $k++) { $nonBasicChars->insert($current, new LinkedListBucket($base + ++$offset, ord($current->raw[$k]))); } } while($current = $current->next); } $nonBasicChars->append(new LinkedListBucket($i++, $charCode)); } } else if ($this->isPrintableLatin1Char($charCode)) { $nonBasicChars->append(new LinkedListBucket($i++, $charCode)); } else { return false; } } else if ($this->isDnsLabelChar($charCode)) { $output[] = $input[$i++]; } else { return false; } } return true; } private function encodeLabel($input) { /** @var LinkedList $nonBasicChars */ if (!$this->getEncodingParts($input, $output, $nonBasicChars)) { return false; } if ($nonBasicChars->length === 0) { return $input; } $n = self::INITIAL_N; $delta = 0; $bias = self::INITIAL_BIAS; $h = $b = count($output); if ($b > 0) { $output[] = '-'; } $current = $nonBasicChars->first; for ($l = $h + $nonBasicChars->length; $h < $l;) { $m = $nonBasicChars->min; $delta += ($m - $n) * ($h + 1); $n = $m; $i = 0; while ($i < $l && $current) { $c = $i === $current->pos ? $current->codePoint : ord($output[$i++]); if ($c < $n) { $delta++; } if ($c === $n) { $q = $delta; for ($k = self::BASE;; $k+= self::BASE) { if ($k <= $bias) { $t = self::T_MIN; } else if ($k >= $bias + self::T_MAX) { $t = self::T_MAX; } else { $t = $k - $bias; } if ($q < $t) { break; } $output[] = chr($this->encodeDigit($t + (($q - $t) % self::BASE - $t))); $q = ($q - $t) / (self::BASE - $t); } $output[] = chr($this->encodeDigit($q)); $bias = $this->adaptBias($delta, $h + 1, $h === $b); $delta = 0; $h++; } } $delta++; $n++; } return 'xn--' . implode('-', $output); } public function encode($input) { $output = []; foreach (explode('.', strtolower($input)) as $label) { if (false === $label = $this->encodeLabel($label)) { return false; } $output[] = $label; } return implode('.', $output); } } $punycode = new Punycode; $input = "www.xn---with-SUPER-MONKEYS-pc58ag80a8qai00g7n9n.com"; $decoded = $punycode->decode($input); $encoded = $punycode->encode($decoded); echo "Input: ", $input, "\n", "Decoded: ", $decoded, "\n", "Encoded: ", $encoded, "\n";
Output for 5.4.0 - 5.4.25
Warning: Creating default object from empty value in /in/vn5ud on line 16
Process exited with code 137.
Output for 5.3.0 - 5.3.28
Parse error: syntax error, unexpected '[' in /in/vn5ud on line 173
Process exited with code 255.