PHP Tips | 文字列処理:ランダム・生成 – UUID v4 生成

PHP PHP
スポンサーリンク

UUID v4 ってそもそも何者?

まずは「UUID v4」が何なのか、イメージから掴みましょう。

よく見るこの形の文字列が UUID です。

550e8400-e29b-41d4-a716-446655440000

特徴はこうです。

  • 32桁の16進数(0–9, a–f)が、8-4-4-4-12 に区切られている
  • 全体としてほぼ「二度と被らない」レベルで一意
  • v4 は「完全ランダムベース」の UUID

業務では、こんな場面でよく使われます。

  • データベースの主キー(ID)として使う
  • 外部に見せる識別子(URL に載せる ID など)として使う
  • ログやトレースの「リクエストID」として使う

「とにかく一意な ID が欲しい。でも連番だと推測されるし、意味も持たせたくない」
そんなときの定番フォーマットが UUID v4 です。


UUID v4 の形とルールをざっくり理解する

形だけ見るとこう

UUID v4 は、こういう形をしています。

xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx

x はランダムな16進数(0–9, a–f)です。
4y の部分にはルールがあります。

  • 真ん中あたりの 4 は「バージョン」を表す → v4 なので必ず 4
  • y の部分は「バリアント」を表す → 8, 9, a, b のどれか

つまり、「完全に全部ランダム」ではなく、
「一部のビットに“これは v4 だよ”という印を付けたランダム値」です。


PHP で UUID v4 を自前生成する基本パターン

コアは random_bytes(16)

UUID は 128ビット(16バイト)の値です。
v4 は「ランダムベース」なので、まずは 16バイトのランダム値を作ります。

$bytes = random_bytes(16);
PHP

ここで random_bytes() を使っているのが超重要です。
mt_rand() などではなく、「暗号論的に安全な乱数」を使うことで、
UUID の一意性・予測困難性を担保します。

バージョンとバリアントのビットをセットする

UUID v4 のルールに従うために、
16バイトのうち一部のビットを書き換えます。

  • 7バイト目(インデックス6)の上位4ビットを 0100(= 4)にする → バージョン4
  • 9バイト目(インデックス8)の上位2ビットを 10 にする → バリアント(8,9,a,b のどれか)

コードで書くとこうなります。

$bytes[6] = chr((ord($bytes[6]) & 0x0f) | 0x40); // バージョン4
$bytes[8] = chr((ord($bytes[8]) & 0x3f) | 0x80); // バリアント
PHP

ここが「UUID v4 らしさ」を作っている一番大事な部分です。

16進文字列にして、UUID 形式に整形する

最後に、バイト列を 16進文字列に変換し、
8-4-4-4-12 の形に区切ります。

$hex = bin2hex($bytes); // 32桁の16進文字列

$uuid = sprintf(
    '%s-%s-%s-%s-%s',
    substr($hex, 0, 8),
    substr($hex, 8, 4),
    substr($hex, 12, 4),
    substr($hex, 16, 4),
    substr($hex, 20, 12)
);
PHP

これで、UUID v4 の完成です。


まとめて関数化:UUID v4 生成ユーティリティ

完成版の関数

ここまでの流れを一つの関数にまとめると、こうなります。

/**
 * UUID v4 を生成する
 *
 * 例: 550e8400-e29b-41d4-a716-446655440000
 */
function uuid_v4(): string
{
    // 16バイトのランダム値を生成
    $bytes = random_bytes(16);

    // バージョン(4)をセット:7バイト目の上位4ビットを 0100 に
    $bytes[6] = chr((ord($bytes[6]) & 0x0f) | 0x40);

    // バリアントをセット:9バイト目の上位2ビットを 10 に
    $bytes[8] = chr((ord($bytes[8]) & 0x3f) | 0x80);

    // 16進文字列に変換
    $hex = bin2hex($bytes);

    // UUID 形式(8-4-4-4-12)に整形
    return sprintf(
        '%s-%s-%s-%s-%s',
        substr($hex, 0, 8),
        substr($hex, 8, 4),
        substr($hex, 12, 4),
        substr($hex, 16, 4),
        substr($hex, 20, 12)
    );
}
PHP

使い方はとてもシンプルです。

echo uuid_v4();
// 例: "f3a9c2b4-d6e7-4f01-8a23-45cd67ef8901"
PHP

毎回呼ぶたびに、ほぼ二度と被らない ID が生成されます。


実務での使いどころのイメージ

データベースの ID として使う

例えば、ユーザーIDを自動採番(1, 2, 3, …)ではなく、UUID にしたい場合。

$id = uuid_v4();

$stmt = $pdo->prepare('INSERT INTO users (id, name, email) VALUES (:id, :name, :email)');
$stmt->execute([
    ':id'    => $id,
    ':name'  => $name,
    ':email' => $email,
]);
PHP

UUID を使うメリットは、

  • ID から件数や登録順が推測されない
  • 複数のシステム・サーバーで同時に生成しても、衝突しにくい

というところにあります。

外部に見せる識別子として使う

例えば、URL に載せるリソースID。

$articleId = uuid_v4();

$url = 'https://example.com/articles/' . $articleId;
// https://example.com/articles/f3a9c2b4-d6e7-4f01-8a23-45cd67ef8901
PHP

連番 ID だと「/articles/1」「/articles/2」…と推測されやすいですが、
UUID なら「次の ID を当てる」のはほぼ不可能です。


まとめ:今日からの「UUID v4 生成」ユーティリティ

押さえておきたいポイントをコンパクトにまとめると、こうなります。

UUID v4 は「ランダムベースの 128ビット ID」で、形式は xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
生成には必ず random_bytes() を使い、一部のビットを「バージョン4」「バリアント」のルールに合わせて書き換える。
16進文字列にして 8-4-4-4-12 に区切れば、よく見る UUID の形になる。

核になる関数はこれです。

function uuid_v4(): string
{
    $bytes = random_bytes(16);

    $bytes[6] = chr((ord($bytes[6]) & 0x0f) | 0x40);
    $bytes[8] = chr((ord($bytes[8]) & 0x3f) | 0x80);

    $hex = bin2hex($bytes);

    return sprintf(
        '%s-%s-%s-%s-%s',
        substr($hex, 0, 8),
        substr($hex, 8, 4),
        substr($hex, 12, 4),
        substr($hex, 16, 4),
        substr($hex, 20, 12)
    );
}
PHP

もし、あなたのプロジェクトで「自前でなんとなくランダムな ID を作っている」箇所があれば、そこをこの uuid_v4() に置き換えるのが、実務的にかなりコスパのいい改善ポイントです。

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