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)です。4 と y の部分にはルールがあります。
- 真ん中あたりの
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,
]);
PHPUUID を使うメリットは、
- 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() に置き換えるのが、実務的にかなりコスパのいい改善ポイントです。
