PHP Tips | 文字列処理:ランダム・生成 – ランダム文字列生成(記号なし)

PHP PHP
スポンサーリンク

何のために「記号なしランダム文字列」を作るのか

まず、どんな場面で使うかをイメージしましょう。

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 つです。

  1. 「使う文字」を自分で明示的に決めていること。
  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;
}
PHP
echo 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;
}
PHP
echo 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() を使って適当に文字をつないでいる」箇所があれば、そこがこのユーティリティに差し替えるべきポイントです。
その一箇所を置き換えるだけで、「記号なし」「推測されにくい」ランダム文字列が手に入ります。

PHPPHP
スポンサーリンク
シェアする
@lifehackerをフォローする
スポンサーリンク
タイトルとURLをコピーしました