/*
Base‑36 encoding/decoding in PHP
------------------------------------------
Base‑36 digits: 0–9, A–Z
Encoding:
- Convert string → bytes (UTF‑8)
- Convert bytes → big integer (base‑256)
- Convert big integer → Base‑36
Decoding:
- Convert Base‑36 → big integer
- Convert big integer → bytes (base‑256)
- Convert bytes → original UTF‑8 string
We implement our own big‑integer using arrays of 32‑bit chunks.
*/
$BASE36_DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
/* Convert Base‑36 character → numeric value */
function base36_value($c) {
if ($c >= '0' && $c <= '9') return ord($c) - ord('0');
return ord($c) - ord('A') + 10;
}
/* Encode any string into Base‑36 */
function encode_to_base36($input) {
global $BASE36_DIGITS;
$bytes = unpack("C*", $input); // array of bytes
$number = [0]; // big integer (little‑endian 32‑bit chunks)
// Convert bytes → big integer (base‑256)
foreach ($bytes as $b) {
$carry = $b;
for ($i = 0; $i < count($number); $i++) {
$value = ($number[$i] * 256) + $carry;
$number[$i] = $value & 0xFFFFFFFF;
$carry = $value >> 32;
}
if ($carry > 0) {
$number[] = $carry;
}
}
// Convert big integer → Base‑36
$encoded = "";
while (!(count($number) == 1 && $number[0] == 0)) {
$remainder = 0;
for ($i = count($number) - 1; $i >= 0; $i--) {
$value = ($remainder << 32) | $number[$i];
$number[$i] = intdiv($value, 36);
$remainder = $value % 36;
}
while (count($number) > 1 && end($number) == 0) {
array_pop($number);
}
$encoded .= $BASE36_DIGITS[$remainder];
}
return strrev($encoded);
}
/* Decode Base‑36 back into original string */
function decode_from_base36($encoded) {
$encoded = strtoupper($encoded);
$number = [0]; // big integer
// Convert Base‑36 → big integer
foreach (str_split($encoded) as $c) {
$digit = base36_value($c);
$carry = $digit;
for ($i = 0; $i < count($number); $i++) {
$value = ($number[$i] * 36) + $carry;
$number[$i] = $value & 0xFFFFFFFF;
$carry = $value >> 32;
}
if ($carry > 0) {
$number[] = $carry;
}
}
// Convert big integer → bytes (base‑256)
$bytes = [];
while (!(count($number) == 1 && $number[0] == 0)) {
$remainder = 0;
for ($i = count($number) - 1; $i >= 0; $i--) {
$value = ($remainder << 32) | $number[$i];
$number[$i] = intdiv($value, 256);
$remainder = $value % 256;
}
while (count($number) > 1 && end($number) == 0) {
array_pop($number);
}
$bytes[] = $remainder;
}
$bytes = array_reverse($bytes);
return pack("C*", ...$bytes);
}
/* Usage */
$text = "Hello Universe!";
$encoded = encode_to_base36($text);
$decoded = decode_from_base36($encoded);
echo "Original: $text\n";
echo "Base-36 encoded: $encoded\n";
echo "Decoded: $decoded\n";
/*
run:
Original: Hello Universe!
Base-36 encoded: LP4N024HJ1YVBVD84Y8TYQP
Decoded: Hello Universe!
*/