Without using GPM, the following should work up to Base85 without to much trouble. Surprisingly, this appears to be slightly faster than GPM, probably because it does not goto hex first.
<?php
/**
* Devide a large number represented as a binary string in the specified base
* and return the remainder.
*
* @param string &$binary
* @param int $base
* @param int $start
*/
function divmod(&$binary, $base, $divisor, $start = 0)
{
/** @var int $size */
$size = strlen($binary);
// Do long division from most to least significant byte, keep remainder.
$remainder = 0;
for ($i = $start; $i < $size; $i++) {
// Get the byte value, 0-255 inclusive.
$digit = ord($binary[$i]);
// Shift the remainder left by base N bits, append the last byte.
$temp = ($remainder * $base) + $digit;
// Calculate the value for the current byte.
$binary[$i] = chr($temp / $divisor);
// Carry the remainder to the next byte.
$remainder = $temp % $divisor;
}
return $remainder;
}
/**
* Produce a base62 encoded string from a large binary number.
*
* @param string $binary
* return string
*/
function encodeBase62($binary)
{
$charMap = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
$base = strlen($charMap);
$size = strlen($binary);
$start = $size - strlen(ltrim($binary, "\0"));
$encoded = "";
for ($i = $start; $i < $size; ) {
// Do long division from most to least significant byte, keep remainder.
$idx = divmod($binary, 256, $base, $i);
$encoded = $charMap[$idx] . $encoded;
if (ord($binary[$i]) == 0) {
$i++; // Skip leading zeros produced by the long division.
}
}
$encoded = str_pad($encoded, $start, "0", STR_PAD_LEFT);
return $encoded;
}
/**
* Produce a large binary number from a base62 encoded string.
*
* @param string $ascii
* return string
*/
function decodeBase62($ascii)
{
$charMap = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
$base = strlen($charMap);
$size = strlen($ascii);
$start = $size - strlen(ltrim($ascii, "0"));
// Convert the ascii representation to binary string.
$binary = "";
for ($i = $start; $i < $size; $i++) {
$byte = strpos($charMap, $ascii[$i]);
if ($byte === false) {
throw new OutOfBoundsException("Invlaid encoding at offset '{$ascii[$i]}'");
}
$binary .= chr($byte);
}
$decode = "";
for ($i = 0; $i < $size; ) {
// Do long division from most to least significant byte, keep remainder.
$idx = divmod($binary, $base, 256, $i);
$decode = chr($idx) . $decode;
if (ord($binary[$i]) == 0) {
$i++; // Skip leading zeros produced by the long division.
}
}
$decode = ltrim($decode, "\0");
$decode = str_pad($decode, $start, "\0", STR_PAD_LEFT);
return $decode;
}
$data = pack("N*", 1234567890);
//$data = pack("C*", 0x49, 0x96, 0x02, 0xD2);
var_dump(unpack("N1", $data));
$base62 = encodeBase62($data);
var_dump( $base62 ); // "1ly7vk"
$decoded = decodeBase62($base62);
var_dump(unpack("N1", $decoded)); // 1234567890
var_dump( strcmp($decoded, $data) === 0 ); // true