12

特にPHPで、常に一意のキーを取得することが保証される方法を探しています。

私は次のことをしました:

strtolower(substr(crypt(time()), 0, 7));

しかし、たまにキーが重複してしまうことがあります(まれですが、十分な場合があります)。

私もやろうと思った:

strtolower(substr(crypt(uniqid(rand(), true)), 0, 7));

しかし、PHPのWebサイトによると、uniqid()は、uniqid()が同じマイクロ秒で2回呼び出された場合、同じキーを生成する可能性があります。rand()を追加することはめったにありませんが、それでも可能だと思います。

上記の行の後に、LやOなどの文字も削除しているので、ユーザーの混乱を少なくします。これは重複の原因の一部かもしれませんが、それでも必要です。

私が考えているオプションの1つは、キーを生成するWebサイトを作成し、それをデータベースに保存して、完全に一意であることを確認することです。

他に何か考えはありますか?ある種のAPIを備えているか、単にキーを返すだけの、すでにこれを行っているWebサイトはありますか。http://userident.comを見つけましたが、キーが完全に一意であるかどうかはわかりません。

これは、ユーザー入力なしでバックグラウンドで実行する必要があります。

4

13 に答える 13

19

パスワードやユーザー ID などではなく、一意の値を生成する方法は 3 つしかありません。

  1. 効果的な GUID ジェネレーターを使用してください。これらは長く、縮小できません。一部のみを使用する場合は、失敗します。
  2. 数値の少なくとも一部は、単一のシーケンスから順次生成されます。綿毛またはエンコーディングを追加して、シーケンシャルに見えないようにすることができます。利点は、すぐに開始できることです。欠点は、単一のソースが必要なことです。単一ソースの制限に対する回避策は、ソースに番号を付けることです。そのため、[source #] + [seq #] を含めると、各ソースが独自のシーケンスを生成できます。
  3. 他の方法でそれらを生成し、以前に生成された値の単一の履歴と照合します。

他の方法は保証されません。基本的には 2 進数を生成していますが (これはコンピューターです)、16 進数、10 進数、Base64、または単語リストでエンコードできます。用途に合ったエンコーディングを選択してください。通常、ユーザーが入力したデータには、Base32 のバリエーションが必要です (これはヒントです)。

GUIDS についての注意: それらは、その長さとそれらを生成するために使用される方法から独自性の強さを獲得します。 128 ビット未満のものは安全ではありません。 乱数の生成以外にも、GUID をより一意にする特性があります。それらは実質的に唯一のものであり、完全に唯一のものではないことに注意してください。可能ですが、重複することは事実上不可能です。

GUIDS に関する更新された注意: これを書いてから、多くの GUID ジェネレーターが暗号的に安全な乱数ジェネレーターを使用していることを知りました (次に生成される数値を予測するのは困難または不可能であり、繰り返す可能性は低いです)。実際には 5 つの異なるUUID アルゴリズムがあります。アルゴリズム 4 は、現在 Microsoft が Windows GUID 生成 API に使用しているものです。GUIDは、Microsoft による UUID 標準の実装です。

更新: 7 ~ 16 文字が必要な場合は、方法 2 または 3 を使用する必要があります。

結論: 率直に言って、完全にユニークなものはありません。シーケンシャル ジェネレーターを使用したとしても、最終的には宇宙のすべてのアトムを使用してストレージを使い果たし、自分自身にループバックして繰り返します。あなたの唯一の希望は、その点に到達する前に宇宙の熱死です.

最高の乱数ジェネレーターでさえ、生成している乱数の合計サイズに等しい回数を繰り返す可能性があります。たとえば、四半期を取ります。これは完全にランダムなビット ジェネレーターであり、繰り返される確率は 2 分の 1 です。

したがって、すべてはあなたの独自性の限界にかかっています。1,099,511,627,776 の数値を 8 桁で 100% 一意にするには、シーケンスを使用してから base32 でエンコードします。過去の数字のリストと照合しない他の方法では、一意ではない可能性が n/1,099,511,627,776 (n = 以前に生成された数字の数) に等しいだけです。

于 2008-09-10T21:06:12.557 に答える
1

どのアルゴリズムでも重複が発生します。

したがって、既存のアルゴリズム*を使用して、重複をチェックすることをお勧めしますか?

*わずかな追加:uniqid()時間に基づいて一意でない可能性がある場合は、呼び出しのたびにインクリメントするグローバルカウンターも含めます。そうすれば、同じマイクロ秒でも何かが異なります。

于 2008-09-10T20:30:06.697 に答える
0

コードを書かないと、私のロジックは次のようになります。

許容できる文字からランダムな文字列を生成します。
次に、日付スタンプの半分(秒の一部とすべて)を前に追加し、残りの半分を最後(または必要に応じて中央のどこかに)に追加します。

ジョリーにとどまりなさい!
H

于 2008-09-10T20:20:48.950 に答える
0

元の方法を使用しているが、パスワードの前にユーザー名または電子メールアドレスを追加した場合、各ユーザーが1つのパスワードしか持てない場合は常に一意になります。

于 2008-09-10T20:22:25.140 に答える
0

同じ問題を扱っているこの記事に興味があるかもしれません。GUIDはグローバルに一意ですが、GUIDのサブストリングは一意ではありません

このアルゴリズムの目標は、時間と場所の組み合わせ(相対性理論のオタクの「時空座標」)を一意性の鍵として使用することです。ただし、タイムキーピングは完全ではないため、たとえば、2つのGUIDが同じマシンからすばやく連続して生成され、タイムスタンプが同じになるほど時間的に接近している可能性があります。そこで、一意化器が登場します。

于 2008-09-10T20:22:29.993 に答える
0

私は通常このようにします:

$this->password = '';

for($i=0; $i<10; $i++)
{
    if($i%2 == 0)
        $this->password .= chr(rand(65,90));
    if($i%3 == 0)
        $this->password .= chr(rand(97,122));
    if($i%4 == 0)
        $this->password .= chr(rand(48,57));
}

理論上の穴はいくつかあると思いますが、重複の問題は一度もありません。私は通常、一時的なパスワード(パスワードのリセット後など)に使用しますが、それでも十分に機能します。

于 2008-09-10T20:23:29.600 に答える
0

https://www.grc.com/passwords.htmで、Steve Gibsonによるパスワードジェネレータの安全性の高い実装(ソースはありませんが、その仕組みの詳細な説明があります)に興味があるかもしれません。

このサイトは巨大な64文字のパスワードを作成しますが、それらは完全にランダムであるため、最初の8文字(またはそれ以上)を簡単に使用して、安全性は低くなりますが「可能な限りランダム」なパスワードにすることができます。

編集:後の回答から、パスワードよりもGUIDのようなものが必要であることがわかりました。したがって、これはおそらくあなたが望むものではありません...

于 2008-09-10T20:27:48.560 に答える
0

Frank Kreugerがコメントしたように、GUIDジェネレーターを使用してください。

このように

于 2008-09-10T20:31:19.393 に答える
0

パスワードが一意でなければならない理由がまだわかりません。2 人のユーザーが同じパスワードを使用している場合の欠点は何ですか?

これは、一意の識別子だけでなく、ユーザー ID に関連付けられたパスワードについて話していることを前提としています。それあなたの探しているものなら、なぜ GUID を使わないのでしょうか?

于 2008-09-10T20:51:35.227 に答える
0

一意の値の作成とはあまり関係のない暗号化部分を無視して、私は通常これを使用します。

function GetUniqueValue()
{
   static $counter = 0; //initalized only 1st time function is called
   return strtr(microtime(), array('.' => '', ' ' => '')) . $counter++;
}

同じプロセスで呼び出されると、$counter が増加するため、値は常に同じプロセスで一意になります。

異なるプロセスで呼び出された場合、同じ値で 2 つの microtime() 呼び出しを取得するのは本当に運が悪いに違いありません。microtime() 呼び出しは通常、同じスクリプトで呼び出された場合も異なる値を持つと考えてください。

于 2010-03-18T19:49:59.173 に答える
0

最近、すばやく簡単なランダムな一意のキーが必要だったので、次のことを行いました。

$ukey = dechex(time()) . crypt( time() . md5(microtime() + mt_rand(0, 100000)) ); 

したがって、基本的には、UNIX 時間を秒単位で取得し、時間 + 乱数から生成されたランダムな md5 文字列を追加します。最高ではありませんが、頻度の低いリクエストにはかなり適しています。高速で動作します。

何千ものキーを生成してから繰り返しを探すテストを行いましたが、1 秒あたり約 800 キーで繰り返しはなく、悪くはありませんでした。mt_rand() に完全に依存していると思います

私は、1 分あたり約 1000 件の調査の送信率を取得する調査トラッカーに使用しています...したがって、今のところ (指を交差させて) 重複はありません。もちろん、レートは一定ではありません (1 日の特定の時間に送信されます) ため、これは失敗を証明するものでも、最善の解決策でもありません... ヒントでは、キーの一部として増分値を使用しています (私の場合、私はtime()を使用しましたが、もっと良いかもしれません)。

于 2009-09-15T11:58:50.377 に答える
0

あなたの問題の一部は、あなたが2つの別々の用途のために単一の機能を私たちにしようとしていることにあると私は信じています.passwordとtransaction_id

これらは実際には 2 つの異なる問題領域であり、一緒に対処しようとするのは実際には最善ではありません。

于 2008-09-11T21:11:09.757 に答える
-1

私は通常、ランダムな部分文字列(ユーザーの便宜のために、8〜32文字以下の文字数をランダム化します)または取得した値のMD5、時間、またはいくつかの組み合わせを実行します。よりランダムにするために、come value(たとえば、姓)のMD5を時間と連結し、MD5を再度実行してから、ランダムなサブストリングを取得します。はい、同じパスワードを取得できますが、その可能性はほとんどありません。

于 2008-09-10T20:26:37.237 に答える