Skip to content

Instantly share code, notes, and snippets.

@MidnightLightning
Last active October 7, 2015 10:48
Show Gist options
  • Save MidnightLightning/3153316 to your computer and use it in GitHub Desktop.
Save MidnightLightning/3153316 to your computer and use it in GitHub Desktop.
ASCII encoding container

Representing binary data as Hex numbers has been a standard for a while, but using only sixteen printable characters when there's many more "safe" ASCII characters possible has lead to other sorts of numbering systems. This class allows you to define your own "number" progression and encode/decode integers through it. The Radix of the conversion used is the length of the string passed to the class, making it very customizable. Several standard character sets (many from RFC 4648) are included, or pass your own custom character string.

This implementation uses the BC Math PHP extension if it's installed to convert very large integers successfully.

<?php
// Hex to Base64
echo radix_convert(Radix::HEX_UPPER, Radix::DECIMAL, 'FF')."\n";

// Hex test
$r = new Radix('0123456789abcdef');
$str = 'ffffffffff';
for ($i=0; $i<10; $i++) {
	echo $str." => ";
	$rs = $r->decode($str);
	echo $rs." => ".$r->encode($rs)."\n";
	$str .= 'f';
}

// High-radix test
$r = new Radix(Radix::BASE_94); 
for ($i=0; $i<10; $i++) {
	$rand = bcpow(rand(1, 9999999999), 5);
	echo $rand." => ";
	$rs = $r->encode($rand);
	echo $rs." => ".$r->decode($rs)."\n";
}
<?php
class Radix {
private $str = '';
private $base;
const DECIMAL = '0123456789';
const HEX_UPPER = '0123456789ABCDEF';
const RFC4648_32 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'; // missing 0189
const BASE_32 = self::RFC4648_32;
const BASE_32_AMBIGUOUS = 'ABCDEFGHIJKMNPQRSTUVWXYZ23456789'; // missing O01L
const Z_BASE_32 = 'YBNDRFG8EJKMCPQXOT1UWISZA345h769'; // missing 01V2
const BASE_32_HEX = '0123456789ABCDEFGHIJKLMNOPQRSTUV';
const BASE_58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; // missing 0IOl
const RFC4648_64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
const BASE_64 = self::RFC4648_64;
const BASE_64_URL = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
const BASE_94 = '!"#$%&\'()*+,-./0123456789;:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'; // ASCII 33-126 inclusive
function __construct($str) {
$this->str = $str;
$this->base = strlen($this->str);
}
function encode($num) {
if ($num == 0) return $this->str[0]; // Edge case
$out = '';
while ($num > 0) {
if (function_exists('bcmod')) {
$out = $this->str[bcmod($num, $this->base)].$out;
$num = bcdiv($num, $this->base, 0);
} else {
$rem = fmod($num, $this->base);
$out = $this->str[$rem].$out;
$num = floor($num/$this->base);
}
}
return $out;
}
function decode($str) {
$out = 0;
$factor = 0;
while ($str != '') {
$c = substr($str, -1);
$pos = strpos($this->str, $c);
if (function_exists('bcadd')) {
$out = bcadd(bcmul(bcpow($this->base, $factor), $pos), $out);
} else {
$out += pow($this->base, $factor)*$pos;
}
$str = substr($str, 0, -1);
$factor++;
}
return $out;
}
}
function radix_convert($from, $to, $input) {
$from = new Radix($from);
$to = new Radix($to);
return $to->encode($from->decode($input));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment