I played with your code for a while, declared constants for your functions to use so that the static values didn't need to be regenerated with each call, added spacing around operators, curly braces for condition blocks, simplified expressions, reduced the total number of function calls, and generally made things more direct.
One point of concern is that you are using arithmetic to translate the values -- for this reason you will need to be wary of the upper limit for your system. It would be a good idea to throw
an exception when your calculation breaks the int max limit. Also, scientific notation can monkey wrench things too. I used number_format()
to prevent scientific notation while I was testing -- I don't know how much extra mileage this will grant you. This has been a fun rabbit hole to go down.
define('ALNUM_MAP', str_split('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'));
define('DIGIT_MAP', array_flip(ALNUM_MAP));
function idToString($id) {
if ($id < 62) {
return ALNUM_MAP[$id];
}
$string = '';
while ($id) {
$id = number_format($id, 0, '', '');
$string = ALNUM_MAP[$id % 62] . $string;
$id = (int)($id / 62);
}
return $string;
}
function stringToID($string) {
$id = 0;
for ($i = strlen($string) - 1, $pow = 0; $i >= 0; --$i, ++$pow) {
$id += DIGIT_MAP[$string[$i]] * (62 ** $pow);
}
return number_format($id, 0, '', '');
}
echo idToString(247698); // bcBi
echo "\n---\n";
echo stringToID('bcBi'); // 247698
echo "\n---\n";
//echo idToString(32611315596050636800); // M1ckM4ckUS4
//echo "\n---\n";
//echo stringToID('M1ckM4ckUS4'); // 32611315596050636800
//echo "\n---\n";
echo idToString(8483692923010050); // M1ckM4ckU
echo "\n---\n";
echo stringToID('M1ckM4ckU'); // 8483692923010050
That said, since you are starting with fully numeric values and you want to reduce their character count by converting to an alphanumeric string, then I have a far simpler way based on this answer that I post on Stack Overflow a couple years back. (Be sure that the incoming values are string-type, not integer-type.)
Code: (Demo)
define('ALNUM_MAP', str_split('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'));
define('DIGIT_MAP', array_flip(ALNUM_MAP));
function numToAlnum($num) {
return strtr($num, ALNUM_MAP);
}
function alnumToNum($alphaNum) {
return strtr($alphaNum, DIGIT_MAP);
}
$ids = ['4440', '464426', '43304441302845', '262018191701180', '273381111186152545352'];
foreach ($ids as $id) {
$idLength = strlen($id);
$alphaNum = numToAlnum($id);
$alNumLength = strlen($alphaNum);
$backToId = alnumToNum($alphaNum);
var_export(['original' => $id, 'encoded' => $alphaNum, 'decoded' => $backToId, 'reduction' => $idLength - $alNumLength]);
echo "\n---\n";
}
As stated in my SO post, using strtr()
is a fantastic technique because it is designed to translate the longest substring that it can find as it traverses the input string. This translation operates on a different algorithm, so it will not give exactly the same length reduction as your technique, but it will not suffer from any numeric/math-based side-effects either.