Skip to content

Instantly share code, notes, and snippets.

@joelharkes
Created August 5, 2019 13:07
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joelharkes/82ac4eb0fd8226649a6118562e3817c4 to your computer and use it in GitHub Desktop.
Save joelharkes/82ac4eb0fd8226649a6118562e3817c4 to your computer and use it in GitHub Desktop.
Crockford base 32 implementation (lower case version)
/**
* Crockford base32 encoding implementation (useable with random_bytes())
* see: https://www.crockford.com/base32.html.
*/
class CrockfordBase32
{
const BITS_5_RIGHT = 31;
const CHARS = '0123456789abcdefghjkmnpqrstvwxyz'; // lower-case
public function sanitize(string $input)
{
$lower = strtolower($input);
$cleaning = preg_replace('/o/', '0', $lower);
$cleaning = preg_replace('/[il]/', '1', $cleaning);
return preg_replace('/[^' . self::CHARS . ']/', '', $cleaning);
}
public function encode($data, $padRight = false)
{
$dataSize = strlen($data);
$res = '';
$remainder = 0;
$remainderSize = 0;
for ($i = 0; $i < $dataSize; ++$i) {
$b = ord($data[$i]);
$remainder = ($remainder << 8) | $b;
$remainderSize += 8;
while ($remainderSize > 4) {
$remainderSize -= 5;
$c = $remainder & (self::BITS_5_RIGHT << $remainderSize);
$c >>= $remainderSize;
$res .= static::CHARS[$c];
}
}
if ($remainderSize > 0) {
// remainderSize < 5:
$remainder <<= (5 - $remainderSize);
$c = $remainder & self::BITS_5_RIGHT;
$res .= static::CHARS[$c];
}
if ($padRight) {
$padSize = (8 - ceil(($dataSize % 5) * 8 / 5)) % 8;
$res .= str_repeat('=', $padSize);
}
return $res;
}
public function decode($data)
{
$data = rtrim($data, "=\x20\t\n\r\0\x0B");
$dataSize = strlen($data);
$buf = 0;
$bufSize = 0;
$res = '';
$charMap = array_flip(str_split(static::CHARS)); // char=>value map
$charMap += array_flip(str_split(strtoupper(static::CHARS))); // add upper-case alternatives
for ($i = 0; $i < $dataSize; ++$i) {
$c = $data[$i];
$b = $charMap[$c];
$buf = ($buf << 5) | $b;
$bufSize += 5;
if ($bufSize > 7) {
$bufSize -= 8;
$b = ($buf & (0xff << $bufSize)) >> $bufSize;
$res .= chr($b);
}
}
return $res;
}
}
$encoder = new CrockfordBase32();
$eightCharCode = $encoder->encode(random_bytes(5));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment