Zufallszahl
Jnnbo
- php
Moin,
ich erzeige mit
md5(uniqid());
eine Zufallszahl für meine Einträge, wenn ich komplett fertig bin, sind es gut 10.000 Einträge. Wie hoch ist die Gefahr, dass ich damit doppelte Zahlenwerte habe?
Moin!
md5(uniqid());
eine Zufallszahl für meine Einträge, wenn ich komplett fertig bin, sind es gut 10.000 Einträge. Wie hoch ist die Gefahr, dass ich damit doppelte Zahlenwerte habe?
echo "<?php echo md5(uniqid()); ?>" | php | lc -c
ergibt 32.
Ein Blick auf die Ausgabe ergibt: Hexadezimal.
Ok. 15^32/10000 kann der Windows-Taschenrechner wohl nicht.
echo "15^32/10000" | bc
ergibt: 4314398832739891950041055679321289
Wie Wahrscheinlichkeit liegt also bei 1/4314398832739891950041055679321289
Jörg Reinholz
Moin!
ergibt: 4314398832739891950041055679321289
Und jetzt erzähle ich, warum das nicht stimmt:
echo "<?php echo uniqid(); ?>" | php | wc -c
Ergebnis: nur 13!
Ein Blick auf die Ausgabe sagt: Hexadezimal. Taschenrechner:
echo "15^13/10000" | bc
Ergebnis: 194619506835
Also nur: 1/194.619.506.835
Das ist nicht so sehr brauchbar. Im Lotto wird nämlich auch dauernd gewonnen.
Mithin macht es keinen Sinn die Ausgaben von uniqid() dirch md5 zu jagen. Wenn überhaupt, dann: md5( uniqid() . uniqid() . uniqid() )
Aber auch das wäre dumm, denn dann machst Du aus einer hexadezimalen Zahl mit 39 Stellen eine mit 32 Stellen, schränkst die Volatilität also ein.
Jörg Reinholz
Hallo Jörg,
Aber auch das wäre dumm, denn dann machst Du aus einer hexadezimalen Zahl mit 39 Stellen eine mit 32 Stellen, schränkst die Volatilität also ein.
was sollte ich dann deiner Meinung nach nehmen, dass ich eine "sichere" und einmalige Zahl habe, die man nicht so einfach erraten kann?
Moin!
was sollte ich dann deiner Meinung nach nehmen, dass ich eine "sichere" und einmalige Zahl habe, die man nicht so einfach erraten kann?
Tja. Wie wäre es, wenn Du schon
$zufall = uniqid() . uniqid() . uniqid();
nimmst, auf das md5() drumrum einfach zu verzichten - statt die Rechenleistung kontraproduktiv zu "missnutzen"?
Jörg Reinholz
Hallo Jörg,
Tja. Wie wäre es, wenn Du schon
$zufall = uniqid() . uniqid() . uniqid();
damit bekomme ich dann also so eine lange Zahl: 5526c7bd5371e5526c7bd537295526c7bd5375f Ok, nehme ich!
Moin!
$zufall = uniqid() . uniqid() . uniqid();
damit bekomme ich dann also so eine lange Zahl: 5526c7bd5371e5526c7bd537295526c7bd5375f Ok, nehme ich!
Naja, wenn da nicht noch was wäre:
5526c7bd5371e
5526c7bd53729
5526c7bd5375f
Diese "Zufallszahlen" unterscheiden sich viel zu wenig: nämlich, auf Grund des kurzen Zeitablaufes, nur in den letzten beiden Stellen.
Wenn es nur eindeutig sein soll, dann nimm nur uniqueid().
Wenn es "hinreichend wahrscheinlich eindeutig" und nicht zu erraten sein soll, dann nimm etwas wie:
sha1(mt_rand(0,mt_getrandmax()) .uniqid() . uniqid() . uniqid());
Aber Gnade Dir auf Windows-Systemen: da liefert mt_getrandmax() nämlich nur 2^15, also rund 32000
Hast Du aber PHP >= 5.3, dann nimm einfach:
$hex=bin2hex(openssl_random_pseudo_bytes(32));
Jörg Reinholz
Moin!
Genau genommen willst Du scheinbar etwas, was eindeutig ist, und zugleich etwas, was schwer zu erraten ist. Das kann man sich aus etwas (was eindeutig ist) und etwas (was schwer zu erraten ist) zusammenbauen:
Beispiel:
$hex = uniqid() . bin2hex(openssl_random_pseudo_bytes(32));
Jörg Reinholz
Moin!
Moin!
Genau genommen willst Du scheinbar etwas, was eindeutig ist, und zugleich etwas, was schwer zu erraten ist. Das kann man sich aus etwas (was eindeutig ist) und etwas (was schwer zu erraten ist) zusammenbauen:
Beispiel:
$hex = uniqid() . bin2hex(openssl_random_pseudo_bytes(32));
uniqid() ist aber nicht eindeutig! Ich habe Code in meiner Software, die aufgrund von Nicht-Eindeutigkeit von uniqid() noch einen Counter dranhängt, das wievielte Mal das jetzt ist.
Wenn du nicht in der Lage bist, 32 zufällige Bytes als ausreichend zufällig zu akzeptieren, dann erhöhe den Wert. Uniqid() liefert 13 Hexzahlen, also 6,5 Bytes. Aufgerundet wären das statt 32 also 39 Zufallsbytes, und das ist sogar extrem besser als uniqid(), weil dort die meisten Zahlen konstant sind.
Grüße Sven
Moin!
uniqid() ist aber nicht eindeutig! Ich habe Code in meiner Software, die aufgrund von Nicht-Eindeutigkeit von uniqid ()
Beschreibung von php.net: uniqueid() ... "Gibt eine eindeutige ID mit Präfix zurück, die auf der aktuellen Zeit in Mikrosekunden basiert."
Könntest Du bitte auf die, sehr wahrscheinlich vom Problem des TO doch recht ordentlich abweichenden Umstände eingehen, unter denen es Dir gelungen ist, mit unique_id() nicht unique ids zu erzeugen?
13 Stellen hex sind 6,5 Bbyte sind 54 bit, sind also 2^54 Millisekunden. Wiederholung ergo frühestens nach
Du müsstest ergo mit passender Software auf einem Mehrprozessorsystem die ids erzeugt haben oder auf sehr vielen Rechnern uniqueid() gestartet haben, wodurch es zu dem Umstand kam, dass die Uhrzeit jeweils bis auf die Millisekunde stimmte. Nicht ganz undenkbar.
Oder lief da was unter Windows? Kann das real microtime()?
Jörg Reinholz
Moin!
- 18014398509481984 Millisekunden
- 18014398509481 Sekunden
- 300239975158 Minuten
- 5003999585 Stunden
- 208499982 Tagen
- 570800 Jahren
- 142710 Rechnergenerationen (a 4 Jahre)
- 22833 mesnchl. Generationen (a 25 Jahre)
Falls Du es nicht glaubst:
root@lvps92-51-***.***:~# echo "<?php echo uniqid(); ?>" | php
5526fd583a759
Fast gleichzeitig:
trainer:~$ echo "<?php echo uniqid(); ?>" | php
5526fd531879d
Jörg Reinholz
Moin!
uniqid() ist aber nicht eindeutig! Ich habe Code in meiner Software, die aufgrund von Nicht-Eindeutigkeit von uniqid ()
Beschreibung von php.net: uniqueid() ... "Gibt eine eindeutige ID mit Präfix zurück, die auf der aktuellen Zeit in Mikrosekunden basiert."
Könntest Du bitte auf die, sehr wahrscheinlich vom Problem des TO doch recht ordentlich abweichenden Umstände eingehen, unter denen es Dir gelungen ist, mit unique_id() nicht unique ids zu erzeugen?
Unittests haben unregelmäßig Fehler angezeigt, deren Analyse ergeben hat, dass dieselbe uniqid() verwendet wurde, die schon einmal erzeugt worden war. Das Abfangen dieser speziellen Situation hat das Problem behoben.
Ach ja: Möglicherweise waren zwei Server parallel am Werk - warum die aber auf die Mikrosekunde identisch uniqid() aufgerufen bekommen haben sollen bei Requests, die mehrere Sekunden auseinanderliegen, ist nicht nachvollziehbar - es ist aber aufgrund der Entstehungsmethode von uniqid() jedenfalls nicht garantiert, dass es nicht zu Wiederholungen kommt. Wenn beispielsweise der ntpd im Hintergrund an der Uhr dreht, kommt eventuell dieselbe Uhrzeit zweimal. Servercluster, Mehrkernsysteme und virtualisierte Umgebungen (Cloud etc.) sind ja außerdem nichts ungewöhnliches.
13 Stellen hex sind 6,5 Bbyte sind 54 bit, sind also 2^54 Millisekunden. Wiederholung ergo frühestens nach
- 18014398509481984 Millisekunden
- 18014398509481 Sekunden
- 300239975158 Minuten
- 5003999585 Stunden
- 208499982 Tagen
- 570800 Jahren
- 142710 Rechnergenerationen (a 4 Jahre)
- 22833 mesnchl. Generationen (a 25 Jahre)
Du müsstest ergo mit passender Software auf einem Mehrprozessorsystem die ids erzeugt haben oder auf sehr vielen Rechnern uniqueid() gestartet haben, wodurch es zu dem Umstand kam, dass die Uhrzeit jeweils bis auf die Millisekunde stimmte. Nicht ganz undenkbar.
Es reicht, dass das undenkbare real passiert ist, und zwar so regelmäßig, dass nicht nur irgendein Testlauf unerwartet gescheitert ist, sondern nachprüfbar so häufig, dass es genervt hat.
Der Code für die uniqid() ist übrigens der hier: https://github.com/php/php-src/blob/master/ext/standard/uniqid.c#L72-L83
Acht Hexzahlen aus den Sekunden plus fünf Hexzahlen aus den Mikrosekunden, die zuvor modulo 0x100000 genommen wurden (was nichts ändert - Mikrosekunden werden nie größer als eine Million).
Grüße Sven
Moin!
Wenn beispielsweise der ntpd im Hintergrund an der Uhr dreht, kommt eventuell dieselbe Uhrzeit zweimal.
Das sollte eigentlich nicht passieren. Zumindest glaube ich gelesen zu haben, dass die Systemzeit dann nicht etwa hart verstellt wird, sondern dass die Differenz in mehreren Schritten angeglichen wird und es also keine zwei Zeitpunkte gibt, an welchen die gleiche Systemzeit zurück geliefert wird. Prinzipiell kann Linux sogar Nanosekunden zurückgeben
~> date +%s.%N
1428658410.775922668
also ist diese schrittweise Verstellung auch im Microsekunden-Bereich machbar.
Stellt sich die Frage, was Windows kann. In dem von Dir verlinkten Quelltext zur Funktion uniqid() glaube ich Hinweise gefunden zu haben, dass es zumindest auf 32-Bit-Windows-Systemen und auch mit cygwin.dll wohl das eine oder kleinere Problem bei derart feinen Zeitauflösungen gibt.
Was jetzt den Unit-Test bestrifft: Da braucht es unter Umständen nur ein Mehrprozessor-System und die entsprechende Anzahl von parallelen Threads. So könnte, genug Lotto vorausgesetzt durchaus so ein Konflikt in einem Unit-Test provozierbar sein, während er im Alltag nahezu ausgeschlossen ist.
In einem Punkt hast Du allerdings durchaus recht, denn der TO will was Blaues und was Rotes. Lila klingt nur so als wäre es das.
Das Blaue: Wenn ich eine Identifizierung brauche, dann sollte, genau wie Du trefflich vorschlägst, und wenn die Datenbank schon benutzt wird, deren Möglichkeit, eine (schlicht und einfach fortlaufende) ID zu generieren, auch genutzt werden. (Punkt!)
Das Rote: Wenn ein nicht erratbares Muster (String, Zahl) quasi als Passwort gewünscht wird, dann kann man das durch Zufall erzeugen (und hier ist ETWAS wie bin2hex(openssl_random_pseudo_bytes(32)) gewiss nicht die schlechteste Lösung, weil ja wohl kaum jemand etwas griffiges gegen openssl einzuwenden hat)
Am Ende der Story muss man das nur noch verbinden und, darum geht es hier wohl, die Daten nur ausliefern, wenn ID und "Passwort" stimmen.
Jörg Reinholz
Hallo Jörg,
Das Blaue: Wenn ich eine Identifizierung brauche, dann sollte, genau wie Du trefflich vorschlägst, und wenn die Datenbank schon benutzt wird, deren Möglichkeit, eine (schlicht und einfach fortlaufende) ID zu generieren, auch genutzt werden. (Punkt!)
Das Rote: Wenn ein nicht erratbares Muster (String, Zahl) quasi als Passwort gewünscht wird, dann kann man das durch Zufall erzeugen (und hier ist ETWAS wie bin2hex(openssl_random_pseudo_bytes(32)) gewiss nicht die schlechteste Lösung, weil ja wohl kaum jemand etwas griffiges gegen openssl einzuwenden hat)
da ich noch nicht upvoten darf, hier als kleiner Kommentar: Sehe ich genauso. Daumen hoch
Gruß, Dennis
da ich noch nicht upvoten darf, hier als kleiner Kommentar: Sehe ich genauso. Daumen hoch
Wer auch immer mir den "Daumen hoch" gegeben hat: Danke. Jetzt darf ich auch upvoten :-)
Gruß, Dennis
Moin!
Moin!
was sollte ich dann deiner Meinung nach nehmen, dass ich eine "sichere" und einmalige Zahl habe, die man nicht so einfach erraten kann?
Tja. Wie wäre es, wenn Du schon
$zufall = uniqid() . uniqid() . uniqid();
nimmst, auf das md5() drumrum einfach zu verzichten - statt die Rechenleistung kontraproduktiv zu "missnutzen"?
Reden wir von Zufallszahlen? Dann ist uniqid() so ziemlich das falscheste, was man nehmen kann, denn da gehen nur Parameter in die Bildung mit ein, die man kennen bzw, raten kann.
Siehe Handbuch: http://php.net/uniqid
Zitate:
Warning This function does not create random nor unpredictable strings. This function must not be used for security purposes. Use a cryptographically secure random function/generator and cryptographically secure hash functions to create unpredictable secure IDs.
Caution This function does not generate cryptographically secure tokens, in fact without being passed any additional parameters the return value is little different from microtime(). If you need to generate cryptographically secure tokens use openssl_random_pseudo_bytes().
Grundsätzlich kann man sagen, dass uniqid() mit dem Fortschritt der Zeit aufsteigende IDs erzeugt, weil die aktuelle Systemzeit in die Bildung der ID mit einfließt. Wie gut man Microtime erraten kann, kann man sich denken: Einfach auf die Uhr gucken verrät den größten Teil, unsicher sind allenfalls die Sekunden und Millisekunden.
Es hilft auch nichts, das Ergebnis von uniqid() in md5() reinzustecken, denn der Wertebereich von uniqid ist begrenzt: Es werden standardmäßig Strings von 13 Zeichen Länge aus dem Hexzahlenbereich 0-9A-F erzeugt. md5() ändert an diesem begrenzten Wertebereich nichts, d.h. es entstehen maximal soviele verschiedene MD5-Hashes, wie es 13-stellige Hexzahlen gibt - die restlichen mit MD5 erzeugbaren Werte werden nie produziert.
Kommen wir also zurück auf die Ausgangsfrage: Datenbank und Autoinkrement gefallen nicht, es soll etwas sein, was so eindeutig ist wie Autoinkrement, aber weniger einfach zu erraten.
Wenn man etwas nicht erraten soll, braucht man starken, kryptografischen Zufall. Und wenn etwas eindeutig sein soll, und man das sicherzustellen hat, braucht man eine Datenbank mit UNIQUE-Spalte, in die man den Zufallswert reinschreibt und dabei evtl. merkt, dass man den schon früher erzeugt hatte und einen neuen Wert ermitteln muß.
Wie man in PHP bestmöglich je nach Systemfähigkeiten Zufallsquellen anzapft, sieht man hier:
https://github.com/ircmaxell/password_compat/blob/6147131320e930186a37bc942ae067636302cf1c/lib/password.php#L102-L137
Das Schreiben des ermittelten Wertes in eine DB-Spalte mit UNIQUE-Index muss ich vermutlich nicht genauer ausführen.
Grüße Sven
Moin!
20:41 bzw 21:07 - und ich hatte nicht den Eindruck, dass du von der Nutzung von uniqid() abgerückt bist.
Grüße Sven
Moin!
20:41 bzw 21:07 - und ich hatte nicht den Eindruck, dass du von der Nutzung von uniqid() abgerückt bist.
Die derzeit als brauchbar angesehene Lösung verzichtet auch nicht darauf.
Jörg Reinholz
Moin!
Moin!
20:41 bzw 21:07 - und ich hatte nicht den Eindruck, dass du von der Nutzung von uniqid() abgerückt bist.
Die derzeit als brauchbar angesehene Lösung verzichtet auch nicht darauf.
Wer sieht die als brauchbar an?
Grüße Sven
Liebe Mitdenker, liebe Wissende, liebe Neugierige,
ja!
Und jetzt erzähle ich, warum das nicht stimmt:
Ergebnis: 194619506835
Also nur: 1/194.619.506.835
Das ist nicht so sehr brauchbar. Im Lotto wird nämlich auch dauernd gewonnen.
Mithin macht es keinen Sinn die Ausgaben von uniqid() dirch md5 zu jagen. Wenn überhaupt, dann: md5( uniqid() . uniqid() . uniqid() )
Uniqid('', true) sollte man immer ohne md5() benutzen, damit keine Doubletten entstehen können. Md5() könnte durchaus mal für zwei unterschiedliche Argumentwerte dasselbe Ergebnis liefern. Uniqid("", true) wird aber, wenn man es nicht direkt in aufeinanderfolgenden Statements benutzt, keine Doubletten liefern.
Aber auch das wäre dumm, denn dann machst Du aus einer hexadezimalen Zahl mit 39 Stellen eine mit 32 Stellen, schränkst die Volatilität also ein.
Spirituelle Grüße
Euer Robert
robert.r@online.de
Hallo
Ergebnis: 194619506835
Also nur: 1/194.619.506.835
Das ist nicht so sehr brauchbar. Im Lotto wird nämlich auch dauernd gewonnen.
Beim Lotto beträgt die Wahrscheinlichkeit (inkl. Superzahl) zirka 1/144 Mio.. Das ist gegenüber deinem Ergebnis mithin eine mehr als tausendfach höhere Wahrscheinlichkeit. Und dennoch gewinnen immer nur „die Anderen“. ;-)
Tschö, Auge
Hallo Jörg,
Ok. 15^32/10000 kann der Windows-Taschenrechner wohl nicht.
echo "15^32/10000" | bc
ergibt: 4314398832739891950041055679321289
Wie Wahrscheinlichkeit liegt also bei 1/4314398832739891950041055679321289
ok, damit kann ich leben, dann bin ich also auf dem richtigen Weg. Ich könnte natürlich auch mit der ID arbeiten, die von der Datenbank selber vergeben wird, ist mir aber zu unsicher, vor allem kann man die ID ohne Probleme erraten, so eine lange Zahl eher nicht.
Liebe Mitdenker, liebe Wissende, liebe Neugierige,
ja!
ich erzeige mit
md5(uniqid());
eine Zufallszahl
das ist keine echte Zufallszahl. Siehe Handbuch
Wenn der Wertebereich für die Zeit zuende ist, ist der Nummernkreis für die Unique-ID ausgeschöpft
für meine Einträge, wenn ich komplett fertig bin, sind es gut 10.000 Einträge. Wie hoch ist die Gefahr, dass ich damit doppelte Zahlenwerte habe?
Spirituelle Grüße
Euer Robert
robert.r@online.de
Hallo Jnnbo
ich erzeige mit
md5(uniqid());
eine Zufallszahl für meine Einträge, wenn ich komplett fertig bin, sind es gut 10.000 Einträge. Wie hoch ist die Gefahr, dass ich damit doppelte Zahlenwerte habe?
dass uniqid()
keine Zufallszahlen generiert, hat Sven ja schon beschrieben. uniqid()
macht wirklich nicht viel anderes, als eine Zeiteinheit, in (Dezimal-) Mikrosekunden gerechnet, in ein anderes Zahlensystem, hier das Hexadezimalsystem, zu überführen. Du kannst also (fast) beliebig damit hin-und-her rechnen. Dass das so ist, kannst Du auch schon am Quellcode sehen. Oder mal selbst Funktionen wie base_convert()
oder ähnliches ausprobieren. Andere haben sich da schon mit beschäftigt.
Auch dass MD5 daran nichts wirklich ändert oder die Sache im ungünstigsten Fall sogar verschlechtert, hat Jörg schon angesprochen. Sollte MD5 in dieser Hinsicht funktionieren, was es offensichtlich tut, wirst Du für denselben Input immer das gleiche Ergebnis erhalten.
Was Du machst ist also wohl Security through obscurity oder Obfuskation. Das ist im Normalfall ein nettes Gimmick, mehr nicht. Daran kannst Du auch durch die mehrfache Anwendung von uniqid()
nichts ändern. Du könntest mit ähnlichem Ergebnis auch die Cäsar-Verschlüsselung (in PHP z.B. str_rot13()
o.ä.) verwenden. Irgendwo hier im Forum gab's in letzter Zeit auch noch einen Beitrag zu base64_encode()
(finde ich gerade leider nicht, ändert aber auch nichts daran, dass das nichts mit Zufall zu tun hat, auch wenn es auf den ersten Blick so aussehen könnte).
Aber jetzt wieder zurück zu Deiner Frage:
Wie hoch ist die Gefahr, dass ich damit doppelte Zahlenwerte habe?
Wenn uniqid()
so funktioniert, wie es gedacht ist: Gleich null.
Ansonsten: Nahezu null. Denn würde uniqid()
Zufallszahlen generieren und wären diese absolut gleichverteilt, kannst Du Dir die Wahrscheinlichkeit mit Hilfe der Laplace-Formel ausrechnen. Ansonsten wird es etwas komplizierter, das Ergebnis dürfte aber in etwa das Gleiche sein. Auch wenn das häufig völlig an der eigenen Intuition verbeigeht, siehe z.B. das Geburtstagsparadoxon (welches ziemlich genau das beschreibt).
Gruß, Dennis
Lieber Dennis, liebe Mitdenker, liebe Wissende, liebe Neugierige,
ja!
Das ist ja nett, dass Du nochmal versucht hast, alles zusammenzufassen. Warum Du aber scheinbar mein Posting von 20:07 übersehen hast, in dem ich bereits darauf hinwies, dass man mit uniqid() -> Handbuch keine echten Zufallszahlen erzeugen kann, weiß ich noch nicht.
Viel wichtiger ist aber, dass Ihr hier alle immer noch meinen Hinweis auf die **Nicht-**Einmaligkeit der Zeichenfolgen im Posting von 20:38 missachtet.
Kleines Testskript zum Ausprobieren:
<?php ### unique_id.php ### Funktion uniqid() testen ### utf-8
header('Content-Type: text/html; CharSet=utf-8;');
$_uniqueid = array();
for ( $i = 0; $i < 5; $i++)
{
$_uniqueid[] = uniqid();
}
echo "<pre>\r\n";
echo htmlspecialchars(print_r($_uniqueid, 1));
echo "</pre>\r\n";
?>
Ich bekam da als Ausgabe:
Array
(
[0] => 55278b89c9817
[1] => 55278b89c9817
[2] => 55278b89c9817
[3] => 55278b89c9817
[4] => 55278b89c9817
)
Warum ich die IDs erst in ein Array geschrieben habe? Weil die Ausgabe auf die Standardausgabe Zeit kostet und die wollte ich hier zwischen den Aufrufen der Funktion bewusst kurz halten!
Nun schauen wir uns das Ganze nochmal mit uniqid('', true) an:
Array
(
[0] => 55278e43f3830
[1] => 55278e43f3830
[2] => 55278e43f3830
[3] => 55278e43f3830
[4] => 55278e43f3830
[5] => 55278e43f38307.48271792
[6] => 55278e43f38302.27676127
[7] => 55278e43f38302.30131205
[8] => 55278e43f38306.61604230
[9] => 55278e43f38305.26805643
)
Von 0 bis 5 mit uniqid() und von 5 bis 9 mit uniqid('', true);
Mit der von mir vorgeschlagenen Verwendung von uniqid('', true) ist also die Einmaligkeit der Zeichenfolge (auf meinem Rechner) gewährleistet.
Will man nun noch die Erratbarkeit verschlechtern, müsste man z.B. noch einen String mit mt_rand() -> Handbuch voranstellen (oder anhängen).
<?php ### unique_id.php ### Funktion uniqid() testen ### utf-8 ### ÄÖÜäöü
header('Content-Type: text/html; CharSet=utf-8;');
$_uniqueid = array();
for ( $i = 0; $i < 5; $i++)
{
$_uniqueid[] = uniqid();
}
for ( $i = 0; $i < 5; $i++)
{
$_uniqueid[] = uniqid('', true);
}
for ( $i = 0; $i < 5; $i++)
{
$_uniqueid[] = uniqid(mt_rand(1,99999), true);
}
echo "<pre>\r\n";
echo htmlspecialchars(print_r($_uniqueid, 1));
echo "</pre>\r\n";
?>
Array
(
[0] => 55278fb97caca
[1] => 55278fb97caca
[2] => 55278fb97caca
[3] => 55278fb97caca
[4] => 55278fb97caca
[5] => 55278fb97caca1.12090844
[6] => 55278fb97caca7.90725032
[7] => 55278fb97caca8.19101436
[8] => 55278fb97caca0.45335224
[9] => 55278fb97caca3.08279841
[10] => 6739155278fb97caca5.93560867
[11] => 4116255278fb97caca5.86801685
[12] => 6838855278fb97caca9.39616501
[13] => 4891355278fb97caca3.30257003
[14] => 486055278fb97caca4.84110264
)
Wie man in den Elementen 10 bis 14 unschwer erkennen kann, wird der String damit schwer erratbar und ist grantiert eineindeutig, solange es nur eine erzeugende Instanz gibt. Außerdem sieht man, dass bereits die kleine Zusatzaufgabe (mt_rand()) schon für eine neue Zeichenfolge im Stamm der von uniqid() erzeugten Zeichenkette sorgen kann.
Wenn man also nicht mit einem Uniqe-Index auf eine DBMS-Tabelle arbeiten kann, oder auch für das Anlegen von Dateien im Dateisystem nicht die Option 'x' benutzt (warum auch immer), und mit einem äußerst geringen restrisiko leben kann, dann ist das mMn die einzige Möglichkeit, die Anforderungen des OP zu erfüllen.
Spirituelle Grüße
Euer Robert
robert.r@online.de
Liebe Mitdenker, liebe Wissende, liebe Neugierige,
ja!
Jetzt fange ich schon genauso an, wie Fastix ;-)
Kleines modifiziertes Testskript zum Ausprobieren:
<?php ### unique_id.php ### Funktion uniqid() testen ### utf-8
header('Content-Type: text/html; CharSet=utf-8;');
$_uniqueid = array();
for ( $i = 0; $i < 5; $i++)
{
usleep(1);
$_uniqueid[] = uniqid();
}
echo "<pre>\r\n";
echo htmlspecialchars(print_r($_uniqueid, 1));
echo "</pre>\r\n";
?>
Die Microsekunde muss übrig sein! In Wirklichkeit wird die Wartezeit sogar etwas größer werden, da usleep() die Prozesskontrolle kurz zurück gibt und damit andere Prozesse zwischendurch angefangen werden.
Spirituelle Grüße
Euer Robert
robert.r@online.de
Moin!
Jetzt fange ich schon genauso an, wie Fastix ;-)
Na und? Ich sehe nichts schlechtes darin
Jetzt kann man ja seine eigenen Beiträge (oft) noch ändern…
Jörg Reinholz
Liebe Mitdenker, liebe Wissende, liebe Neugierige,
ja!
Moin!
Jetzt fange ich schon genauso an, wie Fastix ;-)
Na und? Ich sehe nichts schlechtes darin
- sich selbst zu korrigieren und zu verbessern
- eventuelle Missverständnisse selbst aufzuklären
- später vorausgesehene Probleme und deren Lösung zu zeigen
Jetzt kann man ja seine eigenen Beiträge (oft) noch ändern…
Ist ja auch besser, als das Denken einzustellen :-)
Ich musste trotzdem grinsen...
Spirituelle Grüße
Euer Robert
robert.r@online.de
Hallo Robert,
Das ist ja nett, dass Du nochmal versucht hast, alles zusammenzufassen. Warum Du aber scheinbar mein Posting von 20:07 übersehen hast, in dem ich bereits darauf hinwies, dass man mit uniqid() -> Handbuch keine echten Zufallszahlen erzeugen kann, weiß ich noch nicht.
da das eigentlich keine Zusammenfassung sein sollte, sondern eine kleine Ergänzung, habe ich auch nichts vergessen. Dass z.B. auch Sven zwischenzeitlich in den Quellcode geguckt hat, wusste ich noch nicht, als ich den Beitrag geschrieben habe.
Hätte ich eine Zusammenfassung schreiben wollen, hätte ich uniqid()
hat absolut gar nichts mit Zufallzahlen zu tun geschrieben.
Viel wichtiger ist aber, dass Ihr hier alle immer noch meinen Hinweis auf die **Nicht-**Einmaligkeit der Zeichenfolgen im Posting von 20:38 missachtet.
Das hat nichts mit Missachtung zu tun. uniqid()
macht genau das, was es soll. Nämlich mehr oder weniger Mikrosekunden aus dem Dezimal- ins Hexidezimalsystem zu überführen. Und in seinem Rahmen (zwei aufeinander folgende Aufrufe > 1 Mikrosekunde, keine konkurrierenden/parallelen Prozesse, absolut proportionale Systemzeit, also z.B. kein Umstellen der Systemzeit) ist dies absolut eindeutig. Dazu muss man aber nun mal wissen, was da im Hintergrund passiert.
Kleines Testskript zum Ausprobieren:
Das ist alles richtig. Es ändert aber nichts daran, dass Du mit uniqid
keinen echten Zufall erzeugen kannst. Du verwendest ja beispielsweise mt_rand()
, das erweist seinen Dienst auch ganz ohne uniqid()
.
Und wenn es Dir nur um die Eindeutigkeit geht, kannst Du auch einfach ein usleep()
oder so davor setzen. Oder noch besser eine while()
-Schleife drum herum basteln, die prüft, ob die Zahl schon existiert und das Statement sonst gegebenenfalls nochmals ausführt.
Gruß, Dennis