1. 導入
Web開発において、データベースの連番IDをそのままURLに使用すると、URLが長くなり、推測されやすいという課題があります。これを解決する手法として、基数変換(n進数変換)が非常に有効です。特に62進数(0-9, a-z, A-Z)を用いることで、10進数では長い数字の羅列になるIDを、数文字の短い文字列に圧縮できます。本記事では、実務でそのまま使える汎用的な基数変換ロジックを解説します。
2. 基礎知識
基数変換とは、ある数値を別の進数表現に変換することです。10進数は0〜9の10個の文字を使用しますが、62進数では0〜9、a〜z、A〜Zの計62個の文字を使用します。これにより、短い桁数でより大きな数値を表現可能です。短縮URLサービスなどで、「ID: 1000000」を「4c92」のように短縮して表示するために使われます。
3. 実装/解決策
実装のポイントは、剰余(余り)と除算の繰り返しです。数値を基数(今回は62)で割った余りを変換後の文字として末尾から確定させていき、商を次の計算に回すことで変換を実現します。デコード(復元)処理では、各桁の文字に対応する数値を重み付けして合計します。
4. サンプルプログラム
以下に、任意の文字セットで基数変換を行うための汎用クラスの例を示します。
/
class BaseConverter {
// 使用する文字セット(0-9, a-z, A-Z)
private static $chars = ‘0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ’;
// 数値を文字列に変換(エンコード)
public static function encode($number) {
if ($number == 0) return self::$chars[0];
$result = ”;
$base = strlen(self::$chars);
while ($number > 0) {
$result = self::$chars[fmod($number, $base)] . $result;
$number = floor($number / $base);
}
return $result;
}
// 文字列を数値に変換(デコード)
public static function decode($str) {
$result = 0;
$base = strlen(self::$chars);
$str = strrev($str);
for ($i = 0; $i < strlen($str); $i++) {
$pos = strpos(self::$chars, $str[$i]);
// 文字が含まれていない場合はエラー
if ($pos === false) throw new Exception("無効な文字が含まれています");
$result += $pos pow($base, $i);
}
return $result;
}
}
// 実行例
$id = 1000000;
$encoded = BaseConverter::encode($id);
echo "エンコード結果: " . $encoded . "\n"; // 4c92
echo "デコード結果: " . BaseConverter::decode($encoded) . "\n"; // 1000000
?>
5. 応用・注意点
・URLセーフな文字選び: Base64などは「+」「/」が含まれますが、これらはURLにおいて特殊な意味を持つため、短縮URLに使用する際は「-」「_」などに置換する必要があります。上記のように「0-9, a-z, A-Z」のみで構成すると、置換の手間がなく安全です。
・順序のランダム化: 連続したIDが連続した文字列にならないようにしたい場合、文字セット($chars)の並び順をシャッフルすることで、推測困難な文字列を生成できます。
・負の数の扱い: 今回のコードは正の整数を前提としています。負の値を扱う場合は、先頭に符号を付与するなどのロジックを追加してください。