何のために「記号なしランダム文字列」を作るのか
まず、どんな場面で使うかをイメージしましょう。
URL パラメータに載せるトークンだけど、「+ や / などの記号は使いたくない」。
ユーザーに口頭で伝えるコード(電話サポートなど)なので、読み上げやすい文字だけにしたい。
システム間連携の ID として使うが、「記号が入ると相手側のバリデーションに引っかかる」。
こういうときに欲しくなるのが、
「英数字だけ、もしくは“記号を一切含まない”ランダム文字列」
です。
前の「ランダム文字列生成(英数字)」とほぼ同じ発想ですが、
ここでは「記号を絶対に含めない」という前提を、もう少し丁寧に整理していきます。
大前提:乱数は必ず「暗号論的に安全なもの」を使う
rand() / mt_rand() を避ける理由
ここは前回と同じですが、超重要なので改めて。
rand() や mt_rand() は「ゲーム用」「簡易シミュレーション用」の乱数です。
内部状態が推測されると、次に出る値もある程度予測できてしまいます。
なので、次のような用途では絶対に使ってはいけません。
認証・認可に関わるトークン
URL に載せる一意なコード
ユーザーごとの識別子(招待コードなど)
PHP で「セキュリティ的にちゃんとした乱数」を使いたいときは、
random_int()random_bytes()
のどちらかを使う、と覚えておいてください。
ここでは、扱いやすい random_int() を使います。
設計方針:「使う文字の集合」を先に決める
記号なし=どこまでを許すかを決める
「記号なし」といっても、実は幅があります。
数字だけ(0–9)
英字だけ(a–z, A–Z)
英数字(0–9, a–z, A–Z)
どれも「記号なし」です。
実務で一番よく使うのは「英数字(0–9, a–z, A–Z)」なので、
ここではそれを前提にします。
$chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
PHPこの「文字集合」からランダムに選んで並べる、というのが基本の考え方です。
実装:記号なしランダム文字列生成ユーティリティ
コアとなる関数の実装
/**
* 記号なし(英数字のみ)のランダム文字列を生成する
*
* @param int $length 生成する文字列の長さ
* @return string
*/
function random_string_no_symbols(int $length): string
{
if ($length <= 0) {
throw new InvalidArgumentException('length must be positive');
}
// 記号なし:0-9, a-z, A-Z
$chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$charsLength = strlen($chars);
$result = '';
for ($i = 0; $i < $length; $i++) {
// 0〜$charsLength-1 の範囲で、安全な乱数を取得
$index = random_int(0, $charsLength - 1);
$result .= $chars[$index];
}
return $result;
}
PHP使い方のイメージです。
echo random_string_no_symbols(8);
// 例: "a9F3kL0z"
echo random_string_no_symbols(32);
// 例: "G7k2Pq9sL0xZ1mN8cD4vB6tY3wR5hU"
PHPここでの重要ポイントは 2 つです。
- 「使う文字」を自分で明示的に決めていること。
- インデックスの取得に
random_int()を使っていること。
これで、「記号なし」「推測されにくい」という両方を満たせます。
バリエーション:数字だけ/英字だけにしたい場合
数字だけのランダム文字列
ワンタイム PIN コードなど、「数字だけでいい・むしろその方がいい」場面もあります。
function random_numeric_string(int $length): string
{
if ($length <= 0) {
throw new InvalidArgumentException('length must be positive');
}
$chars = '0123456789';
$charsLength = strlen($chars);
$result = '';
for ($i = 0; $i < $length; $i++) {
$index = random_int(0, $charsLength - 1);
$result .= $chars[$index];
}
return $result;
}
PHPecho random_numeric_string(6);
// 例: "493027"
PHP英字だけのランダム文字列
例えば、「テーブルのエイリアス名」「一時的なキー」など、
英字だけで十分な場面もあります。
function random_alpha_string(int $length): string
{
if ($length <= 0) {
throw new InvalidArgumentException('length must be positive');
}
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$charsLength = strlen($chars);
$result = '';
for ($i = 0; $i < $length; $i++) {
$index = random_int(0, $charsLength - 1);
$result .= $chars[$index];
}
return $result;
}
PHPecho random_alpha_string(10);
// 例: "aZkLmNpQrT"
PHPここまでくると、「使う文字集合を変えるだけで、いろんなパターンのランダム文字列が作れる」という感覚がつかめてきます。
実務での使いどころのイメージ
URL パラメータ用のトークン(記号なし)
例えば、メール認証用の URL に載せるトークン。
$token = random_string_no_symbols(48);
$url = 'https://example.com/verify-email?token=' . $token;
PHP英数字だけなので、URL エンコードのことをあまり気にせずに済みます。
(もちろん、厳密にはエンコードしてもよいですが、英数字だけならそのままでも安全です)
サポートセンターで読み上げる確認コード
電話サポートなどで、「お客様の確認コードは……」と読み上げる場面を想像してみてください。
a9F3-kL0z! のように記号が混ざっていると、
「ハイフンです」「ビックリマークです」と説明が増えてしまいます。
random_string_no_symbols(8) で作った英数字だけのコードなら、
読み上げも聞き取りもだいぶ楽になります。
まとめ:今日からの「記号なしランダム文字列生成」ユーティリティ
押さえておきたいポイントをコンパクトにまとめると、こうなります。
「記号なし」にしたいときは、まず「使う文字集合」を自分で決める(英数字・数字だけ・英字だけなど)。
セキュリティ用途なら、乱数は必ず random_int() / random_bytes() を使い、rand() / mt_rand() は使わない。
実装パターンは、「文字集合のインデックスを random_int() で選んで連結する」がシンプルで安全。
核になるコードは、これです。
function random_string_no_symbols(int $length): string
{
if ($length <= 0) {
throw new InvalidArgumentException('length must be positive');
}
$chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$charsLength = strlen($chars);
$result = '';
for ($i = 0; $i < $length; $i++) {
$index = random_int(0, $charsLength - 1);
$result .= $chars[$index];
}
return $result;
}
PHPもし、あなたのコードの中で「mt_rand() を使って適当に文字をつないでいる」箇所があれば、そこがこのユーティリティに差し替えるべきポイントです。
その一箇所を置き換えるだけで、「記号なし」「推測されにくい」ランダム文字列が手に入ります。
