# Eindeutige 5stellige ID erzeugen



## DaSuckOOr (22. August 2012)

Hi,

ich habe eine kleine php anwendung mit mysql datenbank. jetzt habe ich die Anforderung, dass ich eindeutige id's generien muss, die folgenden Anforderungen entsprechen

- id sollte ca. 5 stellen haben numerisch oder alphanumerisch
- id muss eindeutig sein, nach 1 monat wird die id wieder freigegeben
- es muss sich um eine random id handeln nicht 1 dann 2 dann 3 usw.#

hat jemand eine idee wie ich das am besten mit php und mysql löse?

danke!


----------



## chans (22. August 2012)

Hi DaSuck00r,

PHP stellt da eine Funktion von Haus aus zur Verfügung "Uniqid()"


```
<?php


$code = substr(uniqid(), 0, 5);

echo $code;

?>
```

Da die uniqid allerdings mehr als 5-stellig ist, schneidest du sie dir einfach auf 5 Zeichen zurecht ;-) Enthält Buchstaben und Zeichen - sowie von dir gewünscht.

Gruß
Chans


----------



## DaSuckOOr (22. August 2012)

ok super danke! Die Chance, dass innerhalb eines Monats die selbe 5-stellige ID erzeugt wird ist sehr gering und muss nicht behandelt werden oder?


----------



## ComFreek (22. August 2012)

So ganz ohne Check würde ich das nicht angehen. [phpf]uniqid[/phpf] ist in seiner vollen Länge (fast) eindeutig, aber sicher nicht nur die ersten 5 Stellen.
Die können freilich mehrmals gleich belegt werden.

Wie viele IDs musst du denn erzeugen? Bei 5 Stellen hast du 10^5 = 100.000 Möglichkeiten.


So ganz zufällig wird das nie funktionieren. Dazu musst du immer eine Prüfung auf Eindeutigkeit einbauen. Denn rein zufällig, können Ergebnisse immer n-fach auftreten.
Du musst es also von irgendeiner Größe abhängig machen.
[phpf]uniqid[/phpf] benutzt die Zeit (Mikrosekunden laut PHP Manual) als Faktor. Und die Länge verhindert natürlich auch Duplikate auf sehr lange Zeit.


----------



## alxy (22. August 2012)

Wenns auch nur Zahlen sein können, könntest du auch die letzten 5-6 Ziffern des Unix Timestamps verwenden... die kommen bestimmt nicht doppelt vor. (wobei du trotzdem gegenprüfen musst, falls zwei in der gleichen Sekunde generiert werden)


----------



## sheel (22. August 2012)

alxy hat gesagt.:


> die kommen bestimmt nicht doppelt vor


Warum denn nicht?
a) Wie du schon sagst, wenns in der selben Sekunde ist
b) ca. alle 28 Stunden wiederholt es sich.

Die letzten fünf Stellen -> 100000 weiter kommt es wieder vor
100000 Sekunden / 3600 = 27.77h


----------



## Bratkartoffel (23. August 2012)

Hi,

ich würde die ID wie oben beschrieben generieren und anschließend in eine Datenbank eintragen, wobei das Feld mit der ID unique ist. Schlägt das Eintragen fehl, wird eine neue ID erzeugt und wieder versucht einzufügen. Das ganze natürlich auf eine vernünftige Anzahl von Versuchen begrenzen und fertig.

Grüße,
BK


----------



## CPoly (23. August 2012)

```
<?php
	$counter = 0;
	echo base_convert(time() + $counter++, 10, 36);
?>
```

Wobei $counter geteilt werden muss (z.B. über die Datenbank), um Eindeutigkeit zu garantieren.

Willst du genau 5 Stellen, schneide vorne eine Zeichen weg (NICHT HINTEN. der hintere Teil ist der wichtigere).


----------



## SkyDevMent (23. August 2012)

```
<?php

class uniqID
{
	
	private function cryptSHA512($hash,$rounds)
	{
		$tmpHash = $hash;
		for($i = 0; $i <= $rounds; $i++)
		{
			$tmpHash = hash('sha512',$tmpHash);
		}
		return $tmpHash;
	}
	
	public function makeUniqID($rounds)
	{
 		$tmp1 = mt_rand(1,1000000000);
 		$tmp2 = mt_rand(1,1000000000);
 		$tmp1 = $this->cryptSHA512($tmp1,$rounds);
 		$tmp2 = $this->cryptSHA512($tmp2,$rounds);
 	
 		$tmp  = $tmp1 ^ $tmp2;
 		$tmp  = $this->cryptSHA512($tmp,$rounds); 
 		$tmp  = substr($tmp, 0, 5);
 		return $tmp;
 	}
}

$uniq = new uniqID();
echo $uniq->makeUniqID(10);
?>
```

Bei dieser Implementierung habe ich festgestellt das bei selbst wenn ich 5 mal hintereinadner 10.000 ID´s erzeugt habe kein Doppelt vorkam. Ein Möglichkeit die Zufälligkeit zu erhöhen ist eine weitere Multiplikation mit der lokalen Zeit.


----------



## basecolor (24. August 2012)

Hallo zusammen,

Was ich Persönliche benutze um eindeutige Benutzer IDs zu erzeugen ist folgender Code.
Bringt vielerlei vorteile 


```
<?php

function uuid($prefix = '') {
    $chars = md5(uniqid(mt_rand(), true));
    $uuid  = substr($chars,0,8) . '-';
    $uuid .= substr($chars,8,4) . '-';
    $uuid .= substr($chars,12,4) . '-';
    $uuid .= substr($chars,16,4) . '-';
    $uuid .= substr($chars,20,12);
    return $prefix . $uuid;
}

echo "<b>Benutzer ID:</b> " .uuid(). " !";
?>
```


----------



## DaSuckOOr (24. August 2012)

ok super, vielen Dank für eure Antworten! Da ich die IDs wahrscheinlich zyklisch alle 4 Wochen oder so löschen werde, komme ich mit der ein oder anderen Lösung sehr gut hin!


----------



## ikosaeder (26. März 2013)

Wie wäre es, wenn du einfach alle möglichen 5 stelligen Alphanumerischen ID's generierst und speicherst. 
Die Liste randomisierst (shuffle) du, und nimmst dann immer wenn du eine brauchst aus der Liste (pop).
Wenn die ID wieder freigegeben wird, hängst du sie einfach wieder dran (push),
Die Liste kannst du bei jedem push noch mal randomisieren (oder jedes 10. 100. Mal)


----------



## chmee (26. März 2013)

36^5 = 60.466.176 -> 60 Mio Einträge. Und da sind wir bei einer Grundsatzfrage. Wenn wir pro Sekunde 10 Generierungen machen, haben wir für 6 Mio. Sekunden (~70 Tage) eindeutige IDs. Diese pop/push-List ist ja nett gemeint und so falsch nicht, aber doch ganz schön auf den Putz gehauen  Läuft ne DB? Bei Nutzung einer ID Eintrag machen mit timestamp. Einmal am Tag per cron checken, und alle Einträge älter als x Tage löschen. Bei jeder Neugenerierung Abfrage, ob ID schon existiert, wenn Ja, neuer Versuch (wo ich aber von ausgehe, dass es dazu wohl verdammt selten kommen wird)

mfg chmee


----------



## MarcoPaulini (26. März 2013)

Du solltest dich einfach für eine der Methoden entscheiden. Entweder Unix-Timestamp, *uniqid()* oder was dir sonst noch so einfällt. Aber egal wieviele ID's innerhalb des Monats erstellt werden müssen und wie wahrscheinlich es ist, dass durch eine dieser Methoden zwei mal die selbe ID generiert wird, du solltest auf gar keinen Fall darauf verzichten zu prüfen, ob die ID bereits vorhanden ist. Man darf sich nicht darauf verlassen, dass schon nichts passieren wird. Wenn man mögliche Fehlerquellen erkennt, sollte man diese auch sofort ausschalten.
Das Überprüfen, ob die ID bereits in der Datenbank vorhanden ist geht ja schnell und es ist nur eine SQL-Abfrage. Wenn die ID bereits vorhanden ist, erstelle eine neue aber überprüfe diese erneut!


----------



## hela (27. März 2013)

Hallo,
wenn dieser Thread aufleben soll, dann möchte ich auch meinen Senf dazu geben:

Erst mal ist klar, dass man eine Zufallszahl mit der rand()-Funktion erzeugen kann. Der Rückgabewert ist aber vom Typ INTEGER und kein ID-Name. Mit der base_convert()-Funktion kann man aber einen zufälligen INTEGER-Wert in einen String konvertieren und wenn man eine Zahlenbasis größer 10 wählt, dann kriegt man außer den Zahlen von 0 bis 9 auch Buchstaben dazu. Bei der Zahlenbasis 16 (Hexadezimalwerte) sind das die Zeichen "a..f" und bei der Zahlenbasis 36 kriegt man "a..z".

Etwa so:

```
$idRand = base_convert(rand($intMin, $intMax), 10, 36);
```

Will man einen Zufallsnamen $idRand mit einer maximalen Länge von $length Zeichen (z.B. 5) erhalten, dann kann man den Wert von $intMax durch Konvertierung des Maximalstrings "zzzzz" in das Dezimalsystem berechnen:


```
$idLength = 5;
$strMax = str_repeat('z', $idLength);
$intMax = intval(base_convert($strMax, 36, 10));
```

In Abhängigkeit von Namenskonventionen für IDs ist u.U. auch die Festlegung eines bestimmten Minimalwertes für die Zufallszahlenerzeugung notwendig.
Wenn als $intMin einfach Null eingesetzt wird, dann erhält man auch Ergebnisnamen, die kürzer als 5 Zeichen sind. Das kann man verhindern, indem $strMin einfach eine Stelle weniger als $strMax bekommt und anschließend inkrementiert wird:


```
$strMin = substr($strMax, 1);
$intMin = 1 + base_convert($strMin, 36,10);
```

Weiterhin sollten IDs als erstes Zeichen einen Buchstaben haben. Das kann ebenfalls über den Minimalwert realisiert werden indem ein $strMin-Wert erzeugt wird, der als erstes Zeichen ein "a" hat:


```
$strMin = '9'.substr($strMax, 1);
$intMin = 1 + base_convert($strMin, 36,10);
```

Schon fertig. 
Ist eigentlich nicht kompliziert, oder?

*Auch noch wichtig:* Bei einem 32-Bit-System sollte man nur IDs erzeugen mit einer maximalen Zeichenlänge von 6.


----------



## chmee (27. März 2013)

Stand denn irgendwo, dass es kein String sein darf? Ich halte die Einschränkung des ersten Zeichen für unwichtig und unnötig - eher sogar kontraproduktiv, wenn diese id zB nicht erratbar sein soll. Angenommen, es werden nur 100 pro Tag ausgestellt und alle 7 Tage refreshed, dann kann diese id sehr wohl eine Sicherheitsmaßnahme sein, die unter der von Dir genannten Einschränkung leidet.

mfg chmee


----------



## hela (27. März 2013)

chmee hat gesagt.:


> Stand denn irgendwo, dass es kein String sein darf? Ich halte die Einschränkung des ersten Zeichen für unwichtig und unnötig - eher sogar kontraproduktiv, wenn diese id zB nicht erratbar sein soll...


Das verstehe ich nicht, wieso "kontraproduktiv"? Wenn du in einem HTML-Formular eine ID brauchst, dann unterliegt die Namensgebung diesen Konventionen.
Außerdem ist die Einschränkung, dass das erste Zeichen keine Zahl sein soll, eine Option.


----------



## chmee (27. März 2013)

Angenommen, Du hast ein Datenspeicher, anonym und zB 3 Tage haltbar, dann wäre die ID die einzige Möglichkeit, da ran zu kommen. Wenn diese ID "möglicherweise" aus Gründen der Datensicherheit quasi nicht erratbar sein soll, korrumpierst Du die statistische Vielfalt. Wenn diese ID als ID in einem HTML-Knoten benötigt würde, täte ich ein Zeichen (aus Gründen der Funktionsfähigkeit) vorsetzen anstatt die Stochastik zu beschränken.

mfg chmee


----------



## hela (27. März 2013)

chmee hat gesagt.:


> Angenommen, Du hast ein Datenspeicher, anonym und zB 3 Tage haltbar, dann wäre die ID die einzige Möglichkeit, da ran zu kommen...


Genau, dann muss man sich die ID irgendwie merken.



chmee hat gesagt.:


> Wenn diese ID "möglicherweise" aus Gründen der Datensicherheit quasi nicht erratbar sein soll, korrumpierst Du die statistische Vielfalt. Wenn diese ID als ID in einem HTML-Knoten benötigt würde, täte ich ein Zeichen (aus Gründen der Funktionsfähigkeit) vorsetzen anstatt die Stochastik zu beschränken.


Also ich erzeuge einen Namen, der 6 Zeichen lang sein soll und die einzelnen Zeichen des Namens bestehen aus den Zeichen "0..9" und "a..z". Ich beschränke dann meine "statische Vielfalt", indem ich beim ersten Zeichen nur die Zeichen "a..f" zulasse und habe damit etwa 28% der (ingesamt 2.087.017.473) möglichen Namen gestrichen. Nun meine Frage: Wieviel Namen sind gestrichen, wenn man nur Namen mit der Länge 5 erzeugt und dort ein festes Zeichen davor setzt?


----------



## chmee (27. März 2013)

36^5 = 60 Mio (alle 5 aus 36) + ein fix bringt eine stelle mehr, statistisch aber keine variation
5* 36^4 = 8,3 Mio (erstes aus 5 und 4 aus 36)
36^4 = 1,6Mio (4 aus 36) + eine fix eine stelle mehr (wie oben)

(weil ich mit 0-9a-z rechne = 36) Man könnte nun noch berechnen, um wieviel sich die Suchzeit verkürzt, wenn man zB 10 Suchdurchgänge/sek ansetzt. Verstehe ich Dich also so, dass Du lediglich einen fixen Buchstaben davor setzen willst, damit es HTML-konform ist..?

mfg chmee


----------



## hela (28. März 2013)

chmee hat gesagt.:


> Verstehe ich Dich also so, dass Du lediglich einen fixen Buchstaben davor setzen willst, damit es HTML-konform ist..?


Nein, du wolltes das weil du glaubst, dass dadurch "die Stochastik nicht beschränkt" wird.


			
				chmee hat gesagt.:
			
		

> Wenn diese ID als ID in einem HTML-Knoten benötigt würde, täte ich ein Zeichen (aus Gründen der Funktionsfähigkeit) vorsetzen anstatt die Stochastik zu beschränken.



Wenn also ein ID-Name mit den Zeichen "0..9" und "a..z" und einer *Länge von 5 Zeichen* gebildet werden soll, dann gibt es folgende Möglichkeiten:


Führende Leerzeichen im Namen sind erlaubt. Damit gibt es insgesamt (36^5 = *ca. 60,5 Mio.*) verschiedene Zeichenkombinationen bei der Namensbildung. So können die Namen dann aussehen:


```
koadz,  cs9o, fogh9, yl7o2,  gcik,
q6l3u, 2bwt5, rgena,    69,   6um,
  hx5, e32s5, ad1v2, x2u01,  c5ba,
t9ukm, c1y30,   523, nrkhj, zbcip
```

Im Namen sind keine führenden Leerzeichen erlaubt, dann gibt es (36^5 - 36^4 = *ca. 58,8 Mio.*) verschiedene Zeichenkombinationen für den ID-Namen. So können die Namen dann aussehen:


```
vs1c3, zbqir, roaxx, zd74g, 2kg4a,
ts8w1, 3co6f, k30vs, iyaxl, o6any,
6ksp2, wmgar, myqa1, ywich, 5mszt,
an3vd, 94unm, pvifn, latkp, eam3l
```

Wenn als erstes Zeichen im Namen nur die Zeichen "a..z" erlaubt sind, dann gibt es (36^5 - 10*36^4 = 26*36^4 = *ca. 43,7 Mio.*) Zeichenkombinationen. So können die Namen dann aussehen:


```
e9od2, sgw7m, fx17n, xi1th, zh9f6,
lk5lj, veyd5, evxfa, a4gf1, ywu68,
jfuyd, hr3pu, c50cn, fpoxn, lfhzd,
ysbp4, ogo80, s5gvt, dtmg3, jocd6
```


Wenn ein Name mit nur 4 Zufallszeichen erzeugt und ein konstantes Zeichen davorgesetzt wird, dann kommen (36^4 - 36^3 = *ca. 1,6 Mio.*) Zeichenkombinationen zur Anwendung. So können die Namen dann aussehen:


```
dz6bc, ddzrq, dw4q5, d70zh, dus1n,
di870, dnbq5, d35se, dvich, dlas6,
druly, dh9tg, dvwcd, dm45s, dvhi1,
d4ip6, d8z5s, d22y9, d2iiw, d7k22
```


Vielleicht ist so erkennbar, wo "die Stochastik beschränkt" wird.



chmee hat gesagt.:


> , um wieviel sich die Suchzeit verkürzt, wenn man zB 10 Suchdurchgänge/sek ansetzt.


Ich weiß auch gar nicht was du suchen willst. Die ID-Namen werden generiert ohne zu suchen.


----------



## chmee (28. März 2013)

Mein Ansinnen war lediglich, bei einem BruteForce-Angriff über die HTML-Schnittstelle/API die Chance auf ein gefundenes Token im Bereich der Aussichtslosigkeit zu halten. Dennoch bin ich mit Deinen Rechnungen nicht ganz glücklich. zB ist das Leerzeichen (bis Dato) kein Teil des Zeichenumfangs.

(Leerzeichen wäre ein weiteres Symbol im Zeichenschatz, das würde den Wert auf 37 erhöhen, ergo 37^5)

5 Zeichen a-z0-9 und Space =  *37^5* = 69Mio
5 Zeichen a-z0-9 =  *36^5* = 60,5 Mio
1 Zeichen a-f und 4 Zeichen a-z0-9 = *5* 36^4* = 8,3 Mio
4 Zeichen a-z0-9 = *36^4* = 1,6Mio

(siehe 3. Rechnung, da sind die Beispiele falsch, da Du erstes Zeichen a-f eingeschränkt hast)

Erweiterung um Großbuchstaben:

5 Zeichen a-zA-Z0-9 = *62^5* = 916Mio

Und jetzt war mein simpler Gedanke, es werden binnen eines Tages 1000 Token vergeben, nach 7 Tagen wird refreshed - im Schnitt gibt es also ~3.500 gültige Token. Heisst also, bei 36^5 Möglichkeiten ist die Erfolgschance 36^5/3500 = ~17.000. Nach statistisch 50% (8500) ist mit BruteForce ein Erfolg zu vermelden -> Bei 2 Versuchen/Sekunde ist nach 4250 Sekunden (70 Min) das erste gültige Token gefunden. Gibt der Server 10 Versuche her, ist es nach 14 Minuten geschehen.

Wir (ich) diskutieren grad einen Aspekt der Sicherheit, 5 Zeichen á 36 Symbolmöglichkeiten sind deutlich zu wenig um Sicherheit herzustellen. Wenn es "nur" um eine ID geht, die für eine zeitweilige Identifizierung herhalten soll, sind diese 5 Zeichen, wie auch immer sie geartet sind, völlig ausreichend.

mfg chmee


----------



## hela (28. März 2013)

Hallo chmee,

danke für den Hinweis auf den Schreibfehler in der dritten Rechnung. Richtig ist natürlich
365 - 10*364 = 26*364 = ca. 43,7 Mio.
Ich habe das inzwischen korrigiert. Eigentlich schade, dass wir aneinander vorbei reden.


----------



## chmee (28. März 2013)

Na, ich hab Deinen ersten Text nochmal gelesen. Ich hab mich letztlich nur (ob des Überfliegens) an den "weniger als 5 Zeichen" aufgehangen. Was Du aber gezeigt hast (was ich auch nicht wusste), dass man Zufallsfolgen mittels rand() und base_convert() erzeugen kann, die nicht nur aus Zahlen bestehen. Deswegen meinerseits ein Sorry für das vorschnelle Gegensprechen. Du bist an der Ausgangsfrage näher als ich )

mfg chmee


----------



## hela (28. März 2013)

Alles klar,
der Beitrag von cPoly hatte mich darauf gebracht. Leider habe ich das erst im November lesen können.


----------



## Jan-Frederik Stieler (17. August 2017)

Hallo,
wie bekomm ich den eine ID hin welche sich auch bei einem reload nicht mehr verändert.
Z.B. wenn eine Formularseite neugeladen wird und ich in den namens-attributen ne eindeutige ID benötige welche aber dynamisch generiert werden muss.

Gruß


----------

