Eine Whois-Abfrage in PHP ist eine TCP-Verbindung auf Port 43: fsockopen() zum Whois-Server der Endung, Domainname plus \r\n senden, Antwort bis zum Verbindungsende lesen. Den zuständigen Server liefert whois.iana.org. Bei .de erwartet whois.denic.de das Format „-T dn,ace domain.de“ und antwortet bei freien Domains mit „Status: free“.
Whois ist eines der ältesten Protokolle, die heute noch laufen, und man merkt es. Es gibt kein Antwortformat, keine Fehlercodes und keine Kodierungsangabe. Jede Registry schreibt, was sie für richtig hält. Trotzdem ist Whois in PHP schnell gebaut, und für viele Länderendungen ist es nach wie vor die einzige Schnittstelle.
Wie eine Whois-Abfrage technisch abläuft
RFC 3912 beschreibt das gesamte Protokoll auf zwei Seiten: Der Client öffnet eine TCP-Verbindung auf Port 43, schickt eine Zeile mit \r\n am Ende und liest, bis der Server die Verbindung schließt. Mehr nicht. In PHP heißt das fsockopen(), fwrite() und eine Leseschleife.
Probier es vorher auf der Kommandozeile, dann weißt du, was dein Code bekommen sollte:
whois -h whois.denic.de -- "-T dn denic.de"
Die Antwort beginnt mit Nutzungsbedingungen und endet mit Nameservern und Status. Inhaberdaten fehlen, das ist bei der DENIC Absicht.
Whois-Abfrage in PHP mit fsockopen
Die Grundfunktion ist kurz. Wichtig sind zwei Timeouts: einer für den Verbindungsaufbau (fünfter Parameter von fsockopen()) und einer für das Lesen (stream_set_timeout()). Ohne den zweiten hängt dein Skript, wenn ein Server die Verbindung offen lässt.
<?php
declare(strict_types=1);
function whoisQuery(string $server, string $query, int $timeout = 10): string
{
$fp = @fsockopen($server, 43, $errno, $errstr, $timeout);
if ($fp === false) {
throw new RuntimeException("Keine Verbindung zu $server: $errstr ($errno)");
}
stream_set_timeout($fp, $timeout);
fwrite($fp, $query . "\r\n");
$response = '';
while (feof($fp) === false) {
$chunk = fread($fp, 8192);
if ($chunk === false || stream_get_meta_data($fp)['timed_out']) {
break;
}
$response .= $chunk;
}
fclose($fp);
return $response;
}
Den richtigen Whois-Server finden
Server-Namen hart zu kodieren funktioniert für .de und .com. Für alles andere fragst du whois.iana.org. Die IANA antwortet auf eine Endung mit einem Datensatz, in dem eine Zeile whois: den zuständigen Server nennt.
<?php
declare(strict_types=1);
function whoisServerFor(string $tld): ?string
{
static $cache = [];
if (array_key_exists($tld, $cache)) {
return $cache[$tld];
}
$answer = whoisQuery('whois.iana.org', $tld);
return $cache[$tld] = preg_match('/^whois:[ \t]+(\S+)/mi', $answer, $m) ? $m[1] : null;
}
Der Regex ist bewusst [ \t]+ statt \s+. Bei .dev ist die whois:-Zeile leer, und \s+ springt dann über den Zeilenumbruch und fängt das nächste Wort ein. Im ersten Testlauf kam für .dev deshalb der „Server“ status: heraus. Mit der korrigierten Version liefert die Funktion null, und .dev ist nur per RDAP-Abfrage in PHP erreichbar.
| Endung | Whois-Server laut IANA | Antwort bei freier Domain |
|---|---|---|
| .de | whois.denic.de | Status: free |
| .com / .net | whois.verisign-grs.com | No match for domain "NAME.COM". |
| .io | whois.nic.io | Domain not found. |
| .eu | whois.eu | Status: AVAILABLE |
| .dev | (keiner) | nur RDAP |
Der DENIC-Sonderfall und Thin Registries
Die DENIC erwartet bei Port-43-Abfragen eine Typangabe. -T dn,ace müller.de liefert die Domaindaten und akzeptiert Punycode wie Unicode. Ohne den Parameter bekommst du eine verkürzte Antwort.
Bei .com und .net ist es umgekehrt kompliziert. Verisign führt eine sogenannte Thin Registry: Sie kennt Nameserver, Daten und den Registrar, verweist für alles Weitere aber mit Registrar WHOIS Server: auf den Whois des Registrars. Die folgende Funktion fasst beide Fälle zusammen:
<?php
declare(strict_types=1);
function whois(string $domain): string
{
$ascii = idn_to_ascii($domain, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46);
if ($ascii === false) {
throw new InvalidArgumentException("Ungültiger Domainname: $domain");
}
$tld = substr(strrchr($ascii, '.'), 1);
$server = whoisServerFor($tld) ?? throw new RuntimeException("Kein Whois-Server für .$tld");
// DENIC erwartet ein eigenes Abfrageformat
$query = $server === 'whois.denic.de' ? "-T dn,ace $ascii" : $ascii;
$raw = whoisQuery($server, $query);
// Thin Registry (.com/.net): Verweis auf den Whois-Server des Registrars
if (preg_match('/Registrar WHOIS Server:\s*(\S+)/i', $raw, $m) && strcasecmp($m[1], $server) !== 0) {
try {
$raw .= "\n" . whoisQuery($m[1], $ascii);
} catch (RuntimeException) {
// Registrar-Server antwortet nicht: Registry-Daten reichen meist
}
}
return $raw;
}
Freie Domains im Whois erkennen
Weil es kein Standardformat gibt, bleibt dir nur eine Liste von Mustern. Die folgenden decken die häufigsten Registries ab, du wirst sie für deine Endungen ergänzen müssen.
<?php
declare(strict_types=1);
function looksFree(string $raw): bool
{
$patterns = [
'/^Status:\s*free/mi', // DENIC (.de)
'/^Status:\s*AVAILABLE/mi', // EURid (.eu)
'/^No match for/mi', // Verisign (.com, .net)
'/^Domain not found/mi', // u. a. .io
'/^NOT FOUND/mi',
'/^The queried object does not exist/mi',
];
foreach ($patterns as $p) {
if (preg_match($p, $raw)) {
return true;
}
}
return false;
}
foreach (['php.net', 'denic.de', 'gibt-es-sicher-nicht-4711.de', 'gibt-es-sicher-nicht-4711.com', 'nic.io', 'gibt-es-sicher-nicht-4711.io', 'müller.de'] as $d) {
$raw = whois($d);
echo str_pad($d, 32), looksFree($raw) ? 'frei' : 'vergeben', ' (', strlen($raw), " bytes)\n";
}
Die echte Ausgabe auf meinem Rechner:
php.net vergeben (6476 bytes)
denic.de vergeben (1128 bytes)
gibt-es-sicher-nicht-4711.de frei (50 bytes)
gibt-es-sicher-nicht-4711.com frei (2290 bytes)
nic.io vergeben (9853 bytes)
gibt-es-sicher-nicht-4711.io frei (2759 bytes)
müller.de vergeben (734 bytes)
Auffällig sind die 50 Bytes bei der freien .de-Domain: Die DENIC antwortet nur mit Domain: und Status: free. Der Gegenschluss gilt aber nicht. Erkennt kein Muster „frei“, heißt das nur, dass du die Antwort nicht verstanden hast. Für eine echte Verfügbarkeitsprüfung brauchst du deshalb eine verbindliche Quelle, wie im Beitrag zur Domain-Verfügbarkeit mit PHP beschrieben.
Felder aus der Whois-Antwort herausziehen
Meist willst du nicht den ganzen Text, sondern zwei, drei Werte: Ablaufdatum, Nameserver, Registrar. Die Feldnamen unterscheiden sich je Registry, also arbeitest du mit Alternativen im Regex. Bei Verisign heißt das Ablaufdatum Registry Expiry Date:, bei vielen Registrar-Servern Registrar Registration Expiration Date:. Die DENIC liefert gar kein Ablaufdatum, nur Changed: mit dem Zeitpunkt der letzten Änderung, und die Nameserver als Nserver:, teils mit IP-Adressen dahinter.
| Feld | Verisign (.com) | DENIC (.de) |
|---|---|---|
| Nameserver | Name Server: NS1.EXAMPLE.COM | Nserver: ns1.denic.de 77.67.63.106 … |
| Ablaufdatum | Registry Expiry Date: 2029-11-17T05:00:00Z | nicht vorhanden |
| Letzte Änderung | Updated Date: | Changed: |
| Status | Domain Status: clientTransferProhibited https://icann.org/epp#… | Status: connect |
Ein pragmatischer Ansatz: Nimm für Nameserver /^(?:Name Server|Nserver):\s*(\S+)/mi mit preg_match_all(), schreib alles klein und schneide einen abschließenden Punkt ab. Für Daten lohnt sich DateTimeImmutable mit Fehlerbehandlung, weil manche Registries 2029-11-17, andere 17-Nov-2029 schreiben. Wer Nameserver regelmäßig vergleichen will, ist mit DNS meist besser bedient als mit Whois; wie das als Cronjob aussieht, zeigt der Beitrag zum DNS-Monitoring mit PHP.
Noch ein Hinweis zu Umlaut-Domains: Bei der DENIC kannst du dank ace im Typparameter beide Schreibweisen senden. Andere Server akzeptieren nur Punycode und antworten auf müller.com mit „nicht gefunden“, obwohl xn--mller-kva.com registriert ist. Wandle deshalb immer vorher um. Die Details, auch zu ß und den IDNA-Flags, stehen im Artikel über Punycode in PHP.
Grenzen: Limits, Zeichensätze, Datenschutz
Whois-Server begrenzen Anfragen, ohne es zu sagen. Bei zu vielen Anfragen kommt eine Meldung wie „Query limit exceeded“, eine leere Antwort oder gar keine Verbindung. Beim Testen für diesen Artikel lieferte whois.denic.de nach einigen Dutzend Abfragen plötzlich 0 Bytes, ohne jede Fehlermeldung. Dein Code sollte eine leere Antwort deshalb als „unbekannt“ werten, nie als „frei“. Die Antwortkodierung ist ebenfalls nicht festgelegt: Manche Server liefern UTF-8, manche Latin-1. Wenn du Daten speicherst, prüfe mit mb_check_encoding() und konvertiere bei Bedarf.
Seit der DSGVO sind Inhaberdaten fast überall geschwärzt oder durch Platzhalter ersetzt. Wer Whois nutzt, um Kontaktdaten zu sammeln, wird enttäuscht und bewegt sich rechtlich auf dünnem Eis. Für technische Zwecke wie Ablaufdatum, Nameserver oder Registrar reicht die Auskunft.
Wenn du Whois nicht selbst parsen willst, liefert das MCP-Tool whois_lookup von betadomain dieselben Registry-Felder als JSON. Mehr dazu in der Dokumentation für Entwickler. Ist der Name laut Whois frei, kannst du ihn direkt in der betadomain-Suche eingeben und die Endung auf der Preisseite für .de vergleichen.
Schritt für Schritt
- Whois-Server ermittelnBei whois.iana.org die Endung abfragen und die Zeile „whois:“ auslesen, Ergebnis cachen.
- Abfrage formatierenDomain in Punycode wandeln. Für whois.denic.de „-T dn,ace“ voranstellen, sonst nur den Namen senden.
- Verbindung auf Port 43 öffnenMit fsockopen() verbinden, Timeout setzen, Abfrage mit \r\n senden und bis feof() lesen.
- Antwort auswertenNach registry-spezifischen Mustern wie „Status: free“ oder „No match for“ suchen und bei Thin Registries dem Registrar-Verweis folgen.
Domain gefunden? Prüfen und registrieren kannst du sie direkt bei betadomain – Jahrespreis ab 2,99 €.
Häufige Fragen
Warum bekomme ich bei .de keine Inhaberdaten per Whois?
Die DENIC gibt über Port 43 grundsätzlich keine Angaben zum Domaininhaber oder zu Ansprechpartnern heraus. Die Antwort enthält Nameserver, Status und das Datum der letzten Änderung. Inhaberdaten gibt es nur bei berechtigtem Interesse über ein Formular der DENIC.
Gibt es ein fertiges Whois-Paket für Composer?
Ja, io-developer/php-whois ist auf Packagist verfügbar und kennt Server und Antwortformate vieler Endungen. Für ein paar Endungen reicht eigener Code mit fsockopen(), für Hunderte Endungen spart das Paket viel Pflegeaufwand.
Wie viele Whois-Abfragen darf ich stellen?
Das legt jede Registry selbst fest und veröffentlicht es selten in Zahlen. Wer zu viele Anfragen schickt, wird für eine Weile gesperrt, oft ohne Fehlermeldung. Cache Ergebnisse und verteile Massenabfragen über die Zeit.
Warum hat .dev keinen Whois-Server?
Nicht jede Registry betreibt noch Port 43. Bei .dev liefert whois.iana.org keinen Whois-Eintrag, die Endung ist nur per RDAP abfragbar. Dein Code sollte dann auf RDAP ausweichen statt einen Fehler zu werfen.