PR

PHPでユニークなIDを生成するuniqidの使い方を紹介

PHP

PHPには便利な関数がたくさんありますが、この記事では一意なユニークなIDを自動生成してくれるuniqid()という関数を紹介していきます。PHPでサイトを作成している方は覚えておくと便利な関数のひとつです。ぜひ読んで使い方と特徴を身につけましょう。

PHPのuniqid関数とは

PHPには便利な関数がたくさんありますが、この記事ではuniqidという関数を紹介していきます。uniqid関数とは現在時刻をもとに一意なIDを自動生成してくれる関数です。

uniqid関数を使うメリット

uniqidを使うメリットは簡単に一意の文字列(ID)を生成できることです。またuniqidを用いて生成されるIDは、実行したときの時刻に基づいて生成される文字列なので、基本的に被ることはありません。

ただし、複数人が同時に使用するような環境であれば、もしかしたらIDが被ってしまう可能性があるので、工夫が必要になります。そちらについては、後の章で説明します。

どんな時に使うのか

uniqidを使う場面は多岐にわたってありますが、一番イメージしやすいのは画像アップロード機構でしょう。画像などのファイルをサーバにアップロードするときにファイル名が被らないように適当なIDをファイル名とすることが多いですが、そのような時にこのuniqid関数を使えそうです。

7種類のuniqid関数の使い方

PHPのuniqid関数は引数を指定する場合と指定しない場合で挙動が異なります。もし引数に何も指定しない場合は、現在時刻の基づく13文字のIDが生成されます。

PHPマニュアルによるとuniqid関数の定義は
string uniqid ([ string $prefix = "" [, bool $more_entropy = false ]] )
となっています。つまり第一引数$prefixのデフォルトは空文字列""、第二引数$more_entropyのデフォルトはfalseです。

使い方1:$prefix を指定しない

uniqid関数の第一引数$prefixは接頭辞を指します。デフォルトは空文字列なので何も接頭辞は付きません。以下はPHPサンプルコードと実行結果例です。

<?php
echo uniqid();

実行結果
5c30b3885c48d

しかし、これだと先ほど言ったように、もしかしたらIDが被る可能性が出てきます。個人で使う分には、これでも良いでしょう。

使い方2:$prefix を指定する

次にuniqid関数の第一引数$prefixを指定した場合を見てみましょう。

<?php
echo uniqid("ABC");
echo "\n";
echo uniqid("123");
実行結果
ABC5c30b5fcc7f7d
1235c30b5fcc8125

このように$prefixの文字列が生成するIDの前に接頭辞として付加されます。ちなみに以下のPHPサンプルコードも同義です。

<?php
echo 'ABC'.uniqid();
echo "\n";
echo '123'.uniqid();

使い方3: true を指定する

次に第2引数の$more_entropytrueにした場合を見てみましょう。

<?php
echo uniqid( '' , true );
実行結果
5c32b69c7d5284.68064315

このように、falseのときは13文字だった生成IDと比べ、9文字長い計22文字のIDが生成されるようになります。

ここで注意する点は、もし第一引数の$prefixに何も指定しないとしても、第二引数を指定する場合は、上記PHPサンプルコードのように第一引数を指定してあげなければなりません。仮に以下のようなPHPサンプルコードを記述したとしても、長いIDは生成されません。

期待通りの結果にならない例

<?php
echo uniqid( true );
echo uniqid( $more_entropy = true ); // Pythonのような引数指定はPHPではできない

使い方4:乱数を使う – rand

「使い方3」まで紹介してきた方法は基本的なuniqid関数の使い方でした。しかしなにも工夫をせずにuniqid関数を使うと何度も言っているようにIDが被る可能性が出てきます。そこで他の関数と組み合わせてみましょう。

まずはrand()関数を使う場合です。rand()関数はPHPで扱える便利な関数の一つで、自動的に乱数生成をしてくれます。第一引数が最小値、第二引数が最大値です。デフォルトでは最小値は0、最大値はgetrandmax()関数で得られる値です。この値は環境によって異なる場合もありますが、筆者の環境では32767でした。

今回はこのrand()関数をuniqid()の$prefixに指定してみましょう。以下はPHPサンプルコードと、実行結果例です。

<?php
echo uniqid( rand() )."\n"; // 範囲指定なし
echo uniqid( rand(0,100) )."\n"; // 範囲指定あり0~100
実行結果
294785c32bddb1142a
595c32bddb1155f

この結果からではわかりにくいですが、「乱数+13文字のID」という形になっており、より重複しにくい形になりました。しかし乱数範囲が広いと、IDの桁数がバラバラになってしまうので、まだ工夫が必要そうです。

もし文字列の長さを統一したい場合以下のような工夫があげられます。

<?php
echo uniqid( rand(1000,9999) )."\n"; // 桁が同じ数値の範囲で乱数生成

//0~1000の範囲で桁が少ない数字は 0 で桁埋めする ( str_pad()関数 を使用 )
echo uniqid( str_pad( rand(0,1000), 4, '0', STR_PAD_LEFT) )."\n";

使い方5:乱数を使う – mt_rand

mt_rand()関数はrand()関数よりも新しく、優れた乱数をより高速で返してくれると言われています使い方はrand()と同様です。デフォルトでは最小値が0、最大値はmt_getrandmax()関数で得られる値です。筆者の環境では2147483647でした。以下はPHPサンプルコードと実行結果例です。

<?php
echo uniqid( mt_rand() )."\n"; // 範囲指定なし
echo uniqid( mt_rand(0,1000) )."\n"; // 範囲指定あり
実行結果
15385397715c32c51d48bde
8225c32c51d48d1f

使い方6:乱数 + $more_entropy

今まで紹介した手法を組み合わせれば、もっと重複の無い良いIDが生成できそうです。以下のPHPサンプルコードは今まで紹介した乱数を接頭辞にする手法と第二引数をtrueにすることにより、より長く重複のないIDを生成する例です。

<?php
echo uniqid( mt_rand() , true ) . "\n";

// 桁数を揃えるなら
echo uniqid( str_pad(mt_rand(), 10, "0", STR_PAD_LEFT ) , true ) . "\n";

実行結果
8592219705c32caa7203bc7.01301673
07764676005c32caa7204c95.63071029

使い方7:md5 を指定してハッシュ化

最後に生成したIDをハッシュ化して暗号として扱えるものにしてみましょう。ハッシュ化とはある文字列を別の固定長文字列に変換することを指します。

またハッシュ化は不可逆変換なので、ハッシュ化された文字列から元の文字列を取り出すことは一般的に不可能です。そのためハッシュ化はパスワードの保護などによく使われています。

PHPではmd5()sh1()などのハッシュ化関数が用意されており、関数名はハッシュ化アルゴリズムの名称です。以下はuniqid()で生成したIDをハッシュ化する場合のPHPサンプルコードです。

<php
// uniqidでIDを生成
$userID1 = uniqid( mt_rand() , false );
$userID2 = uniqid( mt_rand(0,100) , true );
$userID3 = uniqid( str_pad(mt_rand(), 10, "0", STR_PAD_LEFT ) , true );

// ハッシュ化
echo md5( $userID1 )."\n";
echo md5( $userID2 )."\n";
echo md5( $userID3 )."\n";

実行結果
e9b8423e33d71f2cee35168a0729e140
a19cabcbcc3a2ea0490ac455e2987b13
684f6d1e72e551a0e2e8775decfc7d56

上の結果を見ると、uniqid()で生成されたIDの長さが違えど、必ず同じ長さのハッシュ値で、全く異なる文字列が生成されていることが分かります。ただしPHPマニュアルではmd5()sh1()はハッシュ化が高速であることから、パスワードの保護に使用することは薦めていません。

パスワードをハッシュ化する場合はpassword_hash()を使用するようにしましょう。パスワードのハッシュ化に関するマニュアルは以下のサイトに書いてあります。

uniqidを使うときに注意すること

一意のIDを自動生成してくれる便利なuniqid()ですが、何度も言うように重複する場合があったりするので、何かしら工夫が必要です。uniqid()を使用するにあたり注意すべき点をまとめます。

暗号としては脆弱

前述しましたがuniqid()を暗号として扱う場合は危険です。いくつかPHPのサンプルコードと実行結果例を見ていただきました。もうお気づきの方もいるかもしれませんが、uniqid()自体は不可逆変換ではありません。もう一度uniqid()の結果を見てみます。

<?php
echo uniqid()."\n";
echo uniqid()."\n";
echo uniqid()."\n";

実行結果
5c32f5a98b3c0
5c32f5a98b4bf
5c32f5a98b77e

uniqid()をほとんど同時刻に呼び出すと実行結果はかなり似てきます。この結果から、何度か実行すると変換規則が推測できてしまい、暗号としては使い物になりません。やはりuniqid()はファイル名の自動生成などに利用するのが最適でしょう。

まとめ

この記事ではPHPでサポートされているuniqid()という関数を紹介しました。単体では暗号としては使えませんが、色々な関数と組み合わせることにより、ファイル名や初回パスワードの発効などには便利な関数です。

ただし、パスワードとして扱う場合には、その後しっかりパスワード用のハッシュ化をして保管する必要があります。

タイトルとURLをコピーしました