Navigation
 Startseite
 Fachbücher
 Anzeigenmarkt
 Forum
 Webmaster News
 Script Newsletter
 Push Meldungen
 Kontakt
 Script Installation
 Php
 Php Tutorials
 Lernpfade
 Webhoster Vergleich
 Impressum

Community-Bereich
 kostenlos Registrieren
 Anmelden
 Benutzerliste

Script Datenbank
 Script Archiv
 Script Top 20
 Screenshots
 Testberichte

Suche
 

Unsere Php Scripts
 Counter Script
 Umfrage Script
 Bilder Upload Script
 Terminverwaltung
 Simple PHP Forum
 RSS Grabber

Tools und Generatoren
 .htpasswd Generator
 md5 Generator
 base64 Generator
 Markdown to HTML
 Colorpicker
 Unix timestamp Tool
 Unit Test Generator
 TLD Liste
 Webkatalog‑Verzeichnis

Artfiles.de
Bietet Serviceorientierte Internetdienstleistungen...
https://www.Artfiles.de
Hosterplus.de
Bekommen Sie Speicherplatz (Webspace), Domains und...
https://www.Hosterplus.de
 
 
 

PHP mt_srand(): Zufallszahlen reproduzierbar erzeugen

Sie befinden sich: Home > Php Tutorial > PHP mt_srand(): Zufallszahl...

PHP mt_srand(): Zufallszahlen reproduzierbar erzeugen
Veröffentlicht am:
23.09.2026
Hits / Besucher:
6
Sprache:
  Deutsch
Tutorial Art:
eigenes
Eingetragen von:
Merkliste:
 
Beschreibung

Ein Test schlägt einmal in zwanzig Durchläufen fehl. Die Testdaten sind jedes Mal andere, also lässt sich der Fehler nicht wiederholen und damit auch nicht untersuchen. Was hier fehlt, ist nicht besserer Zufall, sondern derselbe Zufall ein zweites Mal.

Illustration zum Tutorial: PHP mt_srand(): Zufallszahlen reproduzierbar erzeugen

Im Bild erzeugt derselbe Startwert zweimal dieselbe Zahlenreihe. Genau das ist die Aufgabe dieser Funktion, und sie hat mit der Qualität des Zufalls nichts zu tun.

Was PHP mt_srand() macht

PHP mt_srand() setzt den Startwert des Zufallsgenerators. Alles, was danach an Zufallszahlen erzeugt wird, ergibt sich rechnerisch aus diesem einen Wert. Setzt man ihn erneut auf dieselbe Zahl, beginnt die Folge von vorn, Wert für Wert identisch.

<?php

mt_srand(42);
echo mt_rand(1, 100), ' ', mt_rand(1, 100), ' ', mt_rand(1, 100);
// 64 30 72

mt_srand(42);
echo mt_rand(1, 100), ' ', mt_rand(1, 100), ' ', mt_rand(1, 100);
// 64 30 72

Beide Durchläufe liefern dieselben drei Zahlen, weil PHP mt_srand() den Generator zweimal in denselben Ausgangspunkt versetzt hat. Hier geht es also nicht darum, möglichst unvorhersehbare Werte zu bekommen, sondern darum, dieselben Werte erneut zu erhalten. Wer echten Zufall für Auswahl und Anzeige braucht, findet die passenden Wege in Zufällige Werte aus einem Array auswählen.

Die Signatur im Original

Die englische Beschreibung ist kurz und enthält trotzdem den Hinweis, der die häufigste Frage beantwortet:

mt_srand(int $seed = 0, int $mode = MT_RAND_MT19937): void


/* seed - an arbitrary integer seed value
mode - MT_RAND_MT19937 uses the fixed, correct Mersenne
Twister implementation, MT_RAND_PHP uses the
incorrect implementation that PHP shipped before 7.1
return- no return value

Seeds the random number generator. As of PHP 7.1.0 the random
number generator is seeded automatically, so there is usually
no need to call this function. It is only needed when a
reproducible sequence of values is required. */

Der letzte Satz räumt mit einem verbreiteten Muster auf. Ein Aufruf zur Verbesserung des Zufalls ist seit PHP 7.1 überflüssig, und in der Regel sogar schädlich.

Wie ein Pseudozufallsgenerator arbeitet

Um zu verstehen, warum PHP mt_srand() diese Wirkung hat, hilft ein Blick auf das Verfahren darunter. Der Generator hinter mt_rand() heißt Mersenne Twister und ist ein Rechenverfahren, kein Würfel. Er hält einen internen Zustand, gibt daraus einen Wert aus und verändert dabei den Zustand für den nächsten Aufruf.

flowchart TD
    A[mt_srand mit Startwert] --> B
    B[Interner Zustand] --> C[mt_rand aufrufen]
    C --> D[Wert zurueckgeben]
    C --> E[Zustand fortschreiben]
    E --> B
    A --> F[Gleicher Startwert]
    F --> G[Gleiche Folge]

Weil der Zustand mit jedem Aufruf weiterrückt, kommt es auf die Reihenfolge an. Schiebt sich irgendwo ein zusätzlicher Aufruf dazwischen, verschiebt sich alles danach.

<?php

mt_srand(7);
$a = mt_rand(1, 6);
$b = mt_rand(1, 6); // 3, 5

mt_srand(7);
$x = mt_rand(1, 6);
$hilfswert = mt_rand(1, 99); /* dieser Aufruf verschiebt alles */
$y = mt_rand(1, 6); // 3, dann 4 statt 5

Das ist der Grund, warum reproduzierbare Abläufe keine bedingten Zufallsaufrufe enthalten sollten. Ein if, das manchmal eine Zahl zieht und manchmal nicht, macht die Wiederholbarkeit zunichte.

Muss ich vor jedem mt_rand initialisieren?

Nein, und in altem Code steht genau deshalb oft etwas Schädliches. Vor PHP 7.1 kursierte das Muster, vor jedem Aufruf mit der aktuellen Zeit zu initialisieren. Seit PHP 7.1 initialisiert PHP den Generator beim ersten Bedarf selbst, und zwar aus einer geeigneten Quelle des Betriebssystems.

<?php

/* So stand es frueher haeufig im Code.
Die Zeit ist erratbar, also wird die Folge
dadurch schlechter statt besser. */
mt_srand(time());
$code = mt_rand(100000, 999999);

/* Heute genuegt der blosse Aufruf. */
$code = mt_rand(100000, 999999);

PHP mt_srand() gehört also nur dann in den Code, wenn Wiederholbarkeit ausdrücklich gewünscht ist. In jedem anderen Fall ist der Aufruf bestenfalls wirkungslos.

srand() oder mt_srand(): der Unterschied

Beide Funktionen stehen nebeneinander im Handbuch, und die Frage nach dem Unterschied taucht regelmäßig auf. Die Antwort ist seit PHP 7.1 unspektakulär: Es gibt keinen. srand() ist ein anderer Name für dieselbe Funktion, ebenso wie rand() und mt_rand() denselben Generator ansprechen.

<?php

srand(2026);
echo mt_rand(1, 1000); // 373

mt_srand(2026);
echo rand(1, 1000); // 373

Vor PHP 7.1 waren das tatsächlich zwei getrennte Generatoren mit unterschiedlichen Verfahren. Wer altem Code begegnet, in dem beide gemischt verwendet werden, kann das heute gefahrlos vereinheitlichen. Für neuen Code ist PHP mt_srand() die Schreibweise, die den Generator beim Namen nennt.

Der zweite Parameter und die alte Implementierung

Der zweite Parameter von PHP mt_srand() existiert aus einem einzigen Grund: PHP hatte den Mersenne Twister bis Version 7.1 fehlerhaft umgesetzt. Die Korrektur veränderte die erzeugten Folgen, was für alle problematisch war, die auf bestimmte Folgen angewiesen waren.

Konstante Verfahren Wann
MT_RAND_MT19937 korrekt Voreinstellung, für allen neuen Code
MT_RAND_PHP fehlerhaft, wie vor 7.1 nur um alte Folgen nachzustellen
<?php

/* Nur fuer den Fall, dass eine Folge aus einem alten
System exakt nachgestellt werden muss. */
mt_srand(12345, MT_RAND_PHP);
echo mt_rand(1, 1000);

Diese Konstante ist ein Werkzeug für Altbestände und keine Wahlmöglichkeit. Wer sie in neuem Code findet, sollte nachfragen, warum sie dort steht.

Praxis: einen fehlgeschlagenen Lauf wiederholen

Das eingangs beschriebene Problem löst sich, sobald der Startwert bekannt ist. PHP mt_srand() bekommt ihn dann nicht mehr zufällig, sondern aus der eigenen Hand. Statt ihn dem Zufall zu überlassen, erzeugt man ihn selbst, schreibt ihn ins Protokoll und arbeitet mit ihm weiter.

<?php

$startwert = (int) ($_ENV['TEST_SEED'] ?? random_int(1, PHP_INT_MAX));

mt_srand($startwert);
error_log('Testlauf mit Startwert ' . $startwert);

$daten = [];
for ($i = 0; $i < 1000; $i++) {
$daten[] = [
'menge' => mt_rand(1, 500),
'preis' => mt_rand(100, 99999) / 100,
];
}

Schlägt der Lauf fehl, steht der Startwert im Protokoll. Mit gesetzter Umgebungsvariable entsteht exakt derselbe Datensatz erneut, und der Fehler lässt sich untersuchen statt zu jagen.

Praxis: aus einem Schlüssel eine feste Folge ableiten

Manchmal soll dieselbe Eingabe immer zum selben Ergebnis führen, ohne dass eine Zuordnung gespeichert wird. Ein Kartengenerator, der aus einer Kartennummer immer dieselbe Landschaft baut, arbeitet nach diesem Prinzip.

<?php

function testname(string $schluessel): string
{
$vornamen = ['Anna', 'Bernd', 'Clara', 'Dirk', 'Eva'];
$nachnamen = ['Meier', 'Schulz', 'Krause', 'Weber'];

mt_srand(crc32($schluessel));

return $vornamen[mt_rand(0, 4)] . ' ' . $nachnamen[mt_rand(0, 3)];
}

echo testname('kunde-4711'); // immer derselbe Name
echo testname('kunde-4711'); /* und beim naechsten Mal auch */

Zwei Einschränkungen gehören dazu. crc32() ist eine Prüfsumme und keine Sicherheitsfunktion, die Zuordnung ist also nachvollziehbar. Und wer diesen Startwert setzt, verändert den Generator für den gesamten weiteren Ablauf, was in einem langlaufenden Skript unerwünschte Nebenwirkungen hat.

Betroffen sind nämlich nicht nur mt_rand(). Auch shuffle(), str_shuffle() und array_rand() greifen auf denselben Generator zu, weshalb ein vorher gesetzter Startwert auch ihre Ergebnisse festlegt.

<?php

$aufgaben = ['Bruchrechnen', 'Prozent', 'Dreisatz', 'Zinsen'];

mt_srand(99);
shuffle($aufgaben);
print_r($aufgaben);
// Prozent, Zinsen, Bruchrechnen, Dreisatz

mt_srand(99);
shuffle($aufgaben);
print_r($aufgaben);
// dieselbe Reihenfolge wie eben

Das ist der Weg für eine Aufgabenreihenfolge, die sich bei einer Wiederholung genauso zeigt wie beim ersten Mal. Ohne den gesetzten Startwert mischt shuffle() bei jedem Aufruf neu.

Wofür PHP mt_srand() ausdrücklich nicht taugt

Ein gesetzter Startwert macht jede daraus erzeugte Folge vorhersagbar. Das ist der Zweck der Funktion und zugleich der Grund, warum sie in sicherheitsrelevantem Code nichts verloren hat.

<?php

/* Falsch: wer den Startwert erraet, kennt jedes Token. */
mt_srand(time());
$token = bin2hex(pack('N', mt_rand()));

/* Richtig: kryptografisch sichere Quelle, kein Startwert. */
$token = bin2hex(random_bytes(16));
$code = random_int(100000, 999999);

Für Sitzungsschlüssel, Passwortrücksetzungen, Einmalcodes und alles, was jemand erraten könnte, gelten random_int() und random_bytes(). Diese Funktionen kennen bewusst keinen Startwert, weil Wiederholbarkeit dort ein Fehler wäre. Wie sich eindeutige Kennungen sauber erzeugen lassen, zeigt PHP uniqid zum Erzeugen und richtigen Einsetzen eindeutiger IDs.

Fazit

PHP mt_srand() ist kein Werkzeug für besseren Zufall, sondern für wiederholbaren. Seit PHP 7.1 initialisiert PHP den Generator von selbst, ein Aufruf mit der aktuellen Zeit verschlechtert das Ergebnis eher. srand() ist seither derselbe Aufruf unter anderem Namen.

Zwei Muster tragen in der Praxis: den Startwert protokollieren, um einen fehlgeschlagenen Lauf exakt zu wiederholen, und ihn aus einem fachlichen Schlüssel ableiten, wenn dieselbe Eingabe immer dasselbe Ergebnis liefern soll. Und eine Grenze gilt ohne Ausnahme: Sobald jemand den erzeugten Wert nicht erraten dürfen soll, ist random_int() die richtige Wahl und nicht der Weg über einen Startwert.

 


 

Kommentare (0)

Noch keine Kommentare. Sei der Erste!

Melde dich an, um einen Kommentar zu schreiben.
Bücherregal mit drei Büchern: 'PHP 4 - Grundlagen und Profiwissen' von Hanser Verlag, 'Webdesign in a Nutshell' von O'Reilly Verlag, und 'Webgestaltung' von Galileo Computing.