50

一意のIDを作成したいのですが、のuniqid()ようなものを与えてい'492607b0ee414'ます。私が欲しいのは、tinyurlが与えるものに似たものです:'64k8ra'。短いほど良いです。唯一の要件は、明確な順序を持たないことと、一見ランダムな数字のシーケンスよりもきれいに見えることです。文字は数字よりも優先され、理想的には大文字と小文字が混在することはありません。エントリの数はそれほど多くないため(最大10000程度)、衝突のリスクは大きな要因ではありません。

任意の提案をいただければ幸いです。

4

16 に答える 16

45

指定された長さのランダムな文字を返す小さな関数を作成します。

<?php
function generate_random_letters($length) {
    $random = '';
    for ($i = 0; $i < $length; $i++) {
        $random .= chr(rand(ord('a'), ord('z')));
    }
    return $random;
}

次に、その情報を保存する場所に応じて、疑似コードで一意になるまでそれを呼び出します。

do {
    $unique = generate_random_letters(6);
} while (is_in_table($unique));
add_to_table($unique);

文字が辞書で単語を構成しないようにすることもできます。顧客が悪い味を見つけるものを避けるために、英語の辞書全体または単なる悪い言葉の辞書である可能性があります.

編集:これを追加するのは、使用しようとしているときに、大量のアイテムではない場合にのみ意味があることを追加します。これは、衝突が多くなるとかなり遅くなる可能性があるためです(既にテーブルにIDを取得しています)。もちろん、インデックス付きのテーブルが必要であり、衝突を避けるために ID の文字数を微調整する必要があります。この場合、6 文字で、26^6 = 308915776 の一意の ID (悪い言葉を差し引いたもの) があり、10000 の必要性に十分なはずです。

編集:文字と数字の組み合わせが必要な場合は、次のコードを使用できます。

$random .= rand(0, 1) ? rand(0, 9) : chr(rand(ord('a'), ord('z')));
于 2008-11-21T03:46:41.657 に答える
33

@ gen_uuid() by gord.

preg_replace には厄介な utf-8 の問題があり、uid に "+" または "/" が含まれることがあります。これを回避するには、パターンを明示的に utf-8 にする必要があります

function gen_uuid($len=8) {

    $hex = md5("yourSaltHere" . uniqid("", true));

    $pack = pack('H*', $hex);
    $tmp =  base64_encode($pack);

    $uid = preg_replace("#(*UTF8)[^A-Za-z0-9]#", "", $tmp);

    $len = max(4, min(128, $len));

    while (strlen($uid) < $len)
        $uid .= gen_uuid(22);

    return substr($uid, 0, $len);
}

それを見つけるのにかなりの時間がかかりました、おそらくそれは他の誰かの頭痛の種を救うでしょう

于 2010-08-21T12:32:35.700 に答える
29

より少ないコードでそれを実現できます。

function gen_uid($l=10){
    return substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyz"), 0, $l);
}

結果 (例):

  • cjnp56brdy
  • 9d5uv84zfa
  • ih162lryez
  • ri4ocf6tkj
  • xj04s83egi
于 2014-03-14T15:15:19.553 に答える
18

確実に一意の ID を取得するには、次の 2 つの方法があります。ID を非常に長く可変にすることで、衝突の可能性が非常に小さくなるようにする (GUID の場合のように) か、生成されたすべての ID をルックアップ用のテーブルに格納します (メモリまたは DB のいずれか)。またはファイル) 生成時に一意性を検証します。

このような短いキーを生成し、何らかの重複チェックなしでその一意性を保証する方法を本当に尋ねている場合、答えはできません。

于 2008-11-21T01:47:39.510 に答える
12

本当に簡単な解決策:

一意の ID を次のように作成します。

$id = 100;
base_convert($id, 10, 36);

元の値を再度取得します。

intval($str,36);

別のスタック オーバーフロー ページからのものであるため、これを信用することはできませんが、解決策は非常にエレガントで素晴らしいので、これを参照している人々のためにこのスレッドにコピーする価値があると思いました.

于 2010-01-21T22:31:37.170 に答える
12

これは、任意の長さのランダムなbase62に使用するルーチンです...

呼び出すと、などgen_uuid()の文字列が返されます。WJX0u0jV, E9EMaZ3P

デフォルトでは、これは 8 桁を返すため、64^8 またはおよそ 10^14 のスペースが返されます。多くの場合、これは衝突を非常にまれにするのに十分です。

それより大きいまたは小さい文字列の場合は、必要に応じて $len を渡します。満足するまで追加するため、長さに制限はありません [最大 128 文字の安全な制限で、削除できます]。

md5 [または必要に応じてsha1]でランダムソルトを使用するため、簡単にリバースエンジニアリングできないことに注意してください。

Web 上で信頼できる base62 変換が見つからなかったため、base64 の結果から文字を削除するこのアプローチが採用されました。

BSD ライセンスの下で自由に使用し、楽しんでください。

ゴード

function gen_uuid($len=8)
{
    $hex = md5("your_random_salt_here_31415" . uniqid("", true));

    $pack = pack('H*', $hex);

    $uid = base64_encode($pack);        // max 22 chars

    $uid = ereg_replace("[^A-Za-z0-9]", "", $uid);    // mixed case
    //$uid = ereg_replace("[^A-Z0-9]", "", strtoupper($uid));    // uppercase only

    if ($len<4)
        $len=4;
    if ($len>128)
        $len=128;                       // prevent silliness, can remove

    while (strlen($uid)<$len)
        $uid = $uid . gen_uuid(22);     // append until length achieved

    return substr($uid, 0, $len);
}
于 2009-10-04T13:39:57.710 に答える
6

前後に変換したい場合は、Id を使用して base-36 番号に変換するだけです。整数 ID を持つ任意のテーブルに使用できます。

function toUId($baseId, $multiplier = 1) {
    return base_convert($baseId * $multiplier, 10, 36);
}
function fromUId($uid, $multiplier = 1) {
    return (int) base_convert($uid, 36, 10) / $multiplier;
}

echo toUId(10000, 11111);
1u5h0w
echo fromUId('1u5h0w', 11111);
10000

頭のいい人なら、十分な id の例でおそらく理解できるでしょう。このあいまいさがセキュリティを置き換えないようにしてください。

于 2008-11-21T09:58:07.507 に答える
4

一意性チェックなしでこれを行う非常にクールなソリューションだと思うものを思いつきました。今後の訪問者のために共有したいと思いました。

カウンターは、一意性を保証する非常に簡単な方法です。データベースを使用している場合は、主キーも一意性を保証します。問題は、見栄えが悪く、脆弱である可能性があることです。それで、私はシーケンスを取り、それを暗号でごちゃ混ぜにしました。暗号は逆にすることができるので、各 ID が一意でありながらランダムに表示されることがわかります。

PHP ではなく Python ですが、ここにコードをアップロードしました: https://github.com/adecker89/Tiny-Unique-Identifiers

于 2012-02-08T05:15:06.177 に答える
3

文字は美しく、数字は醜い。ランダムな文字列が必要ですが、「醜い」ランダムな文字列は必要ありませんか?

乱数を作成し、航空会社が提供する予約「番号」のように、アルファ スタイル( base-26 ) で出力します。

私が知る限り、PHP には汎用の基本変換関数が組み込まれていないため、そのビットを自分でコーディングする必要があります。

別の方法:uniqid()数字を使用して削除します。

function strip_digits_from_string($string) {
    return preg_replace('/[0-9]/', '', $string);
}

または、それらを文字に置き換えます。

function replace_digits_with_letters($string) {
    return strtr($string, '0123456789', 'abcdefghij');
}
于 2008-11-21T02:11:40.333 に答える
1

次のように行うこともできます。

public static function generateCode($length = 6)
    {
        $az = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $azr = rand(0, 51);
        $azs = substr($az, $azr, 10);
        $stamp = hash('sha256', time());
        $mt = hash('sha256', mt_rand(5, 20));
        $alpha = hash('sha256', $azs);
        $hash = str_shuffle($stamp . $mt . $alpha);
        $code = ucfirst(substr($hash, $azr, $length));
        return $code;
    }
于 2013-02-26T10:08:43.200 に答える
1

この記事を見てみましょう

YouTube のように、bdd ID から短い一意の ID を生成する方法について説明します。

実際、この記事の関数は、数値を基数から別の基数に変換するPHP 関数 base_convertに非常に関連しています (ただし、基数は 36 までです)。

于 2014-02-20T13:39:06.317 に答える
1

ループ、文字列の連結、rand() への複数回の呼び出しなどの汚れた/コストのかかるものを使用せずに、きれいで読みやすい方法でそれを行うことができます。また、次を使用することをお勧めしますmt_rand()

function createRandomString($length)
{
    $random = mt_rand(0, (1 << ($length << 2)) - 1);
    return dechex($random);
}

どのような場合でも文字列を正確な長さにする必要がある場合は、16 進数をゼロで埋めてください。

function createRandomString($length)
{
    $random = mt_rand(0, (1 << ($length << 2)) - 1);
    $number = dechex($random);
    return str_pad($number, $length, '0', STR_PAD_LEFT);
}

「理論的なバックドロー」は、PHP の機能に制限されているということですが、その場合、これはより哲学的な問題です;)とにかくそれを見てみましょう:

  • PHP は、このように 16 進数として表現できるものに制限があります。これは$length <= 8 、少なくとも32 ビット システムでは可能であり、PHP の制限は 4.294.967.295 である必要があります。
  • PHP の乱数ジェネレーターにも最大値があります。mt_rand() 少なくとも32 ビット システムでは、2.147.483.647 である必要があります。
  • したがって、理論的には 2.147.483.647 ID に制限されます。

話題に戻りdo { (generate ID) } while { (id is not uniqe) } (insert id)ましょう - 直観的な人には欠点が 1 つあります。

欠点:検証は悲観的です。このように行うには、常にデータベースでのチェックが必要です。十分なキースペース (たとえば、10,000 エントリに対して長さ 5) があると、衝突が頻繁に発生する可能性はほとんどなくなります。これは、UNIQUE KEY エラーの場合にのみデータを保存して再試行するだけで、リソースの消費が比較的少なくて済む可能性があるためです。

欠陥: ユーザー Aは、まだ取得されていないことが確認された ID を取得します。次に、コードはデータを挿入しようとします。しかしその間、ユーザー Bは同じループに入り、残念ながら同じ乱数を取得します。ユーザー Aはまだ保存されておらず、この ID はまだ空いていたからです。これで、システムはUser BまたはUser A のいずれかを保存し、2 番目の User を保存しようとすると、その間に同じ ID を持つ別のユーザーが既に存在します。

どのような場合でもその例外を処理する必要があり、新しく作成された ID で挿入を再試行する必要があります。悲観的なチェック ループ (再入力が必要) を維持しながらこれを追加すると、非常に醜く、コードを追跡するのが難しくなります。幸いなことに、これに対する解決策は、欠点に対する解決策と同じです。最初にそれを実行して、データを保存してみてください。UNIQUE KEY エラーの場合は、新しい ID で再試行してください。

于 2013-09-24T17:04:47.887 に答える
0

一意のIDの長いバージョンが必要な場合は、次を使用します。
$ uniqueid = sha1(md5(time()));

于 2012-08-07T09:11:28.460 に答える
0
function rand_str($len = 12, $type = '111', $add = null) {
    $rand = ($type[0] == '1'  ? 'abcdefghijklmnpqrstuvwxyz' : '') .
            ($type[1] == '1'  ? 'ABCDEFGHIJKLMNPQRSTUVWXYZ' : '') .
            ($type[2] == '1'  ? '123456789'                 : '') .
            (strlen($add) > 0 ? $add                        : '');

    if(empty($rand)) $rand = sha1( uniqid(mt_rand(), true) . uniqid( uniqid(mt_rand(), true), true) );

    return substr(str_shuffle( str_repeat($rand, 2) ), 0, $len);
}
于 2008-12-15T16:26:06.670 に答える
-1

ベスト アンサー:一意のデータベース ID が与えられた最小の一意の "Hash Like" 文字列 - PHP ソリューション、サード パーティのライブラリは必要ありません。

コードは次のとおりです。

<?php
/*
THE FOLLOWING CODE WILL PRINT:
A database_id value of 200 maps to 5K
A database_id value of 1 maps to 1
A database_id value of 1987645 maps to 16LOD
*/
$database_id = 200;
$base36value = dec2string($database_id, 36);
echo "A database_id value of 200 maps to $base36value\n";
$database_id = 1;
$base36value = dec2string($database_id, 36);
echo "A database_id value of 1 maps to $base36value\n";
$database_id = 1987645;
$base36value = dec2string($database_id, 36);
echo "A database_id value of 1987645 maps to $base36value\n";

// HERE'S THE FUNCTION THAT DOES THE HEAVY LIFTING...
function dec2string ($decimal, $base)
// convert a decimal number into a string using $base
{
    //DebugBreak();
   global $error;
   $string = null;

   $base = (int)$base;
   if ($base < 2 | $base > 36 | $base == 10) {
      echo 'BASE must be in the range 2-9 or 11-36';
      exit;
   } // if

   // maximum character string is 36 characters
   $charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';

   // strip off excess characters (anything beyond $base)
   $charset = substr($charset, 0, $base);

   if (!ereg('(^[0-9]{1,50}$)', trim($decimal))) {
      $error['dec_input'] = 'Value must be a positive integer with < 50 digits';
      return false;
   } // if

   do {
      // get remainder after dividing by BASE
      $remainder = bcmod($decimal, $base);

      $char      = substr($charset, $remainder, 1);   // get CHAR from array
      $string    = "$char$string";                    // prepend to output

      //$decimal   = ($decimal - $remainder) / $base;
      $decimal   = bcdiv(bcsub($decimal, $remainder), $base);

   } while ($decimal > 0);

   return $string;

}

?>
于 2014-08-04T19:28:22.867 に答える