5

重複の可能性がゼロ(または無視できる)で、ランダムな文字列と一意の文字列の両方を取得するための有効な方法が必要です。

範囲内の文字が必要[0-9A-z]です。

これは私がこれまでに持っているものです:

substr(sha1(mt_rand().uniqid()),0,22);  
4

5 に答える 5

8

PHPに対する最近の変更

これが実際にbcryptとパスワードのソルトについて話していることを知っているので、これを読んでいる人々に、自分のソルトシステムを手動でロールする代わりに、使用すべき関数を示すことができます。

password_hash($input, PASSWORD_DEFAULT);データベースに挿入するのに適したハッシュを生成するために使用します。これにより、ソルトが取得されます。

挿入:

$hash = password_hash($_POST["password"], PASSWORD_DEFAULT, ["cost" => 16]);
DB::table("users")->insert(["username" => $user, "password" => $hash]);
// or whatever database method you use to insert data

検証:

$hash = DB::table("users")->fetchByName($username)->select("password");
$input = $_POST["password"];

$verified = password_verify($input, $hash); // true if the password matches

PHP 5.5より前のバージョンでは、https://github.com/ircmaxell/password_compatをドロップインとして使用します1


ソルトをランダムに生成する場合、衝突の確率は次のようになります。

1 / [number of possible letters/numbers] ** [length]

22文字の文字列の場合、これは不可能なほど低くなります(まあ、不可能ではありませんが、無視できるほどです)

1 / (22 ** 60) = 1 / (3.51043 x 10**80)

見る?小さな


数学的誤謬

本当にランダムな文字列が必要な場合(注:これらの文字列は文字にマップされた数字の行にすぎません)、少し運が悪いです。
探しているのはCSPRNG(暗号論的に安全な疑似乱数ジェネレーター)です。一意性は必要ありません。

@Guaravが彼の回答で指摘したように、タイムスタンプをシードとして使用し、それをハッシュすることができます。これはUUID(128ビットのタイムスタンプの場合は一意のユニバーサル識別子)と呼ばれ、予測可能であり、いくつかの理由で不良になる可能性があります。

  1. このタイムスタンプを取得する精度が、このソルトの予測可能性を決定する要因になります。
  2. 時間を整数として秒単位でハッシュすると、非常に明確で推測しやすいソルトになります。

それでも、十分な精度で、タイムスタンプを一意のソルトとして使用できます。ランダムではありません(ランダムシードとして使用し、base10に変換する場合を除きます。これはまだ悪い考えです)。ナノ秒未満の時間を数え、それを一意のIDとして使用したい場合は、これを検討してください。PHPは、衝突する2つのサブナノ秒ID 1を与えるのに十分な速度で処理することはできません(ただし、検証する必要がないという意味ではありません)。


1:作曲家と一緒に動作します!

于 2013-02-03T16:10:12.080 に答える
4

これは私がいつかやっている方法です...

// chars
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-+';

// convert to array
$arr = str_split($chars, 1);

// shuffle the array
shuffle($arr);

// array to chars with 22 chars
echo substr(implode('', $arr), 0, 22);

出力

xd*thKM$B#13^)9!QkD@gU

ixXYL0GEHRf+SNn#gcJIq-

$0LruRlgpjv1XS8xZq)hwY

$G-MKXf@rI3hFwT4l9)j0u

一意であることを確認するために、いつでもデータベースをチェックインできます。繰り返される場合は、KEYを再生成します。

于 2013-02-03T16:13:36.203 に答える
2

私自身の質問の答えを確認することができます。 実際の注文IDを使用して(ユーザーに表示するためだけに)一意の注文IDを生成するにはどうすればよいですか?

ランダムな文字列の代わりにTimeStampを使用できます。

あなたの解決策に関しては、衝突の可能性がありますが、それは非常に低いレベルです。

于 2013-02-03T16:10:15.667 に答える
1

これが常に一意の値を返すことを保証するものではありませんが、リスクを大幅に最小限に抑えることができます。乱数生成アルゴリズムを使用すると、常に重複する可能性があります。

一意の値のみが生成されることを保証するために、以前に生成された値を検索して重複を破棄できます。

数式が重複する可能性を減らすためのいくつかの提案:

  • は使用しないでくださいsha1。これは、任意の入力に対して1つの一貫した出力を返すメソッドです。重複の可能性には影響しません。
  • の代わりにsha1、乱数を別の基数に変換することを検討してください(たとえば、基数36の数値は、データベースまたはランダム文字列出力で実行しているすべての文字に格納できる0〜9およびAZの文字を使用できます) 。しかし、私はここで実際に36に行くことはないでしょう、多分256+?
  • 文字列を22文字に制限しているので、substr実際には重複の可能性が少し高くなります。前の箇条書きで書いたことを使用して、乱数を切り捨てる必要のない22文字未満の文字列に変換します。
  • また、関数を使用して生の値をsubstr返すことで、この必要性をなくすことができます。これは、わずか20文字です。sha1
  • または、文字列を22文字に制限しないでください(何らかの理由で本当に必要な場合を除く)。
于 2013-02-03T16:18:10.800 に答える
-1

関数を使ってみませんかtime()

time()似たようなことをする必要がありました。一意のIDを維持するためのソリューションで、このようなPHP関数を使用して$reference_number = 'BFF-' . time();、BFFをビジネスロジックにとってより意味のあるものに変更できるソリューションになりました。このように、時間は常に一意であるため、生成されている新しいIDが以前に使用されたかどうかを心配する必要はありません。

これがお役に立てば幸いです

于 2014-03-12T08:39:02.217 に答える