3v4l.org

run code in 300+ PHP versions simultaneously
<?php namespace Katoga\Allyourbase; /** * @author Katoga <katoga.cz@hotmail.com> */ class Base32 implements Transcoder { /** * A-Z, 2-7 * New RFC that obsoleted RFC3548, uses the same alphabet. * * @var int */ const RFC4648 = 1; /** * 0-9, A-V * "Extended hex" or "base32hex" * * @var int */ const RFC2938 = 2; /** * 0-9, A-Z without I, L, O, U * * @link http://www.crockford.com/wrmg/base32.html * @var int */ const CROCKFORD = 3; /** * @var string */ const PAD_CHAR = '='; const ENCODE = 1; const DECODE = 1; /** * @var array */ protected $alphabet = [ self::RFC4648 => [ self::ENCODE => [], self::DECODE => [], ], self::RFC2938 => [ self::ENCODE => [], self::DECODE => [], ], self::CROCKFORD => [ self::ENCODE => [], self::DECODE => [], ], ]; /** * @param string $input binary string * @param int $type alphabet type * @return string ascii string */ public function encode($input, $type = self::RFC4648) { $output = ''; if ($input !== '') { $alphabet = $this->getAlphabet($type); // create binary represantation of input string $binStr = ''; foreach (str_split($input) as $char) { // append 8 bits of source string // padding zeros needed for chars with ASCII position < 64 (up to '?') // or portions of splitted multibyte chars $binStr .= str_pad(decbin(ord($char)), 8, '0', STR_PAD_LEFT); } // pad binary string, its length has to be divisible by 5 $binStr = $this->pad($binStr, 5, '0'); // split binary string to 5bit chunks $binArr = explode(' ', trim(chunk_split($binStr, 5, ' '))); // encode foreach ($binArr as $binChar) { $output .= $alphabet[bindec($binChar)]; } // pad output, its length has to be divisible by 8 $output = $this->pad($output, 8, self::PAD_CHAR); } return $output; } /** * @param string $input ascii string * @param int $type alphabet type * @return string binary string * @throws DecodeFailedException */ public function decode($input, $type = self::RFC4648) { $output = ''; if ($input !== '') { $alphabet = $this->getDecodingAlphabet($type); // convert input to uppercase and remove trailing padding chars $input = rtrim(strtoupper($input), self::PAD_CHAR); $binStr = ''; foreach (str_split($input) as $ch) { if (!isset($alphabet[$ch])) { throw new DecodeFailedException(); } // append 5bit binary representation of encoded char $binStr .= str_pad((decbin($alphabet[$ch])), 5, '0', STR_PAD_LEFT); } // trim zeros from tight side of binary string, its length has to be divisible by 8 $binStr = $this->trim($binStr, 8, '0'); $binArr = explode(' ', trim(chunk_split($binStr, 8, ' '))); foreach ($binArr as $bin) { $output .= chr(bindec($bin)); } } return $output; } /** * Pads $string on right side with $char to length divisible by $factor * * @param string $string * @param int $factor * @param string $char */ protected function pad($string, $factor, $char) { $output = $string; $length = strlen($string); $modulo = $length % $factor; if ($modulo != 0) { $outputPaddedLength = $length + ($factor - $modulo); $output = str_pad($output, $outputPaddedLength, $char, STR_PAD_RIGHT); } return $output; } /** * Trims $char from right side of $string to length divisible by $factor * * @param string $string * @param int $factor * @param string $char */ protected function trim($string, $factor, $char) { $output = $string; $length = strlen($string); $modulo = $length % $factor; if ($modulo != 0) { $outputTrimmedLength = $length - $modulo; $output = substr($output, 0, $outputTrimmedLength); } return $output; } /** * @param int $type * @return array */ protected function getEncodingAlphabet($type) { return $this->alphabet[$type][self::ENCODE]; } /** * @param int $type * @return array */ protected function getDecodingAlphabet($type) { return $this->getAlphabet($type, self::DECODE); } /** * @param int $type * @param int $mode * @return array * @throws \InvalidArgumentException */ protected function getAlphabet($type, $mode) { if (!isset($this->alphabet[$type])) { throw new InvalidArgumentException(sprintf('Wrong alphabet requested: "%s"!', $type)); } if (!isset($this->alphabet[$type][$mode])) { throw new InvalidArgumentException(sprintf('Wrong mode requested: "%s"!', $mode)); } if (empty($this->alphabet[$type][$mode])) { // generate the requested alphabet switch ($type) { case self::RFC4648: $alphabet = array_merge( range('A', 'Z'), ['2', '3', '4', '5', '6', '7'] ); $this->alphabet[$type][self::ENCODE] = $alphabet; $this->alphabet[$type][self::DECODE] = array_flip($alphabet); break; case self::RFC2938: $alphabet = array_merge( ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], range('A', 'V') ); $this->alphabet[$type][self::ENCODE] = $alphabet; $this->alphabet[$type][self::DECODE] = array_flip($alphabet); break; case self::CROCKFORD: $alphabet = array_merge( ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], array_diff( range('A', 'Z'), ['I', 'L', 'O', 'U'] ) ); $this->alphabet[$type][self::ENCODE] = $alphabet; $decodeCrockford = array_merge( array_flip($alphabet), [ 'I' => 1, 'L' => 1, 'O' => 0 ] ); $lowercase = range('a', 'z'); unset($lowercase[20]); foreach ($lowercase as $ch) { $decodeCrockford[$ch] = $decodeCrockford[strtoupper($ch)]; } $this->alphabet[$type][self::DECODE] = $decodeCrockford; break; } } return $this->alphabet[$type][$mode]; } }

preferences:
44.32 ms | 402 KiB | 5 Q