Skip to content

Instantly share code, notes, and snippets.

@tf198
Created August 23, 2012 01:30
Show Gist options
  • Save tf198/3431098 to your computer and use it in GitHub Desktop.
Save tf198/3431098 to your computer and use it in GitHub Desktop.
Base encoder with customisable alphabets
<?php
class BaseX {
/** RFC4648 Base62 */
const BASE_64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
/** RFC4648 "URL and Filename safe" Base64 */
const URL_64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=";
/** URL and filename safe Base64 in UCA order */
const UCA_64 = "-_0123456789aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ=";
/** RFC4648 Base32 */
const BASE_32 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=";
/** Nice human readable Base32 alphabet */
const CROCKFORD_32 = "0123456789ABCDEFGHJKMNPQRSTVWXYZ=";
const CROCKFORD_32_DECODER = "oOiIlL001111"; // nice fault tolerance
/** RFC4648 "Extended Hex" alphabet */
const HEX_32 = "0123456789ABCDEFGHIJKLMNOPQRSTUV=";
static function bits($l) {
return (int) floor(log($l) / log(2));
}
static function encode($i, $charset, $pad=0) {
$l = strlen($charset);
$n = self::bits($l);
$mask = $l - 2;
$r = ($i == 0) ? $charset{0} : "";
while($i) {
$j = $i & $mask;
$r = $charset{$j} . $r;
$i >>= $n;
}
if($pad) {
$j = $pad - strlen($r);
if($j) $r = str_repeat($charset{0}, $j) . $r;
}
return $r;
}
static function decode($data, $charset) {
$l = strlen($charset);
$n = self::bits($l);
$result = 0;
$c = strlen($data);
for($i=0; $i<$c; $i++) {
if($data{$i} == $charset{$l-1}) continue; // padding
if($i > 0) $result <<= $n;
$result |= strpos($charset, $data{$i});
}
return $result;
}
static function normalize($data, $decoder=null) {
$data = strtoupper($data);
if($decoder) {
$p = strlen($decoder)/2;
$data = strtr($data, substr($decoder, 0, $p), substr($decoder, $p));
}
return $data;
}
static function validate($input, $charset) {
$enc = self::encode($input, $charset);
$dec = self::decode($enc, $charset);
//printf("%6d -> %4s -> %6d\n", $input, $enc, $dec);
assert($dec === $input);
}
}
if(realpath($_SERVER['SCRIPT_FILENAME']) != __FILE__) return;
// basic tests
$testset = array(0, 23, 496, 1024, 753812);
foreach($testset as $i) {
BaseX::validate($i, BaseX::BASE_32);
BaseX::validate($i, BaseX::CROCKFORD_32);
BaseX::validate($i, BaseX::BASE_64);
BaseX::validate($i, BaseX::UCA_64);
assert(strtoupper(base_convert($i, 10, 32)) == BaseX::encode($i, BaseX::HEX_32));
}
assert(BaseX::decode(BaseX::normalize('qo4m', BaseX::CROCKFORD_32_DECODER), BaseX::CROCKFORD_32) == 753812);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment