» Domainnamen / Hostnamen validieren

<base href> aus HTML-Quelltext auslesenNeuen Thread eröffnenNeue Antwort erstellenRelativen / absoluten Link in Deeplink umwandeln
AutorNachricht
Administrator 

Name: Marc
Geschlecht:
Anmeldedatum: 28.08.2004
Beiträge: 52423
Wohnort: Lohmar


Meine eBay-Auktionen:
04.03.2015, 19:42
zitieren

Ich hatte hier eine interessante Funktion gefunden, die allerdings wirklich alles genehmigt was als Hostname möglich ist. Also auch "localhost" oder schlicht "a":
function is_valid_domain_name($domain_name)
{
    return (preg_match("/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i", $domain_name) //valid chars check
            && preg_match("/^.{1,253}$/", $domain_name) //overall length check
            && preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $domain_name)   ); //length of each label
}

Ich wollte das etwas differenzierter. Außerdem wollte ich die Frage beantworten. Also ob es auch ohne Regex geht und wenn ja wie schnell das dann ist.

Mit viel Phantasie bin ich dann Variante um Variante durchgegangen bis ich das Ergebnis erzielt habe:
function filter_hostname($name, $domain_only=false) {
// entire hostname has a maximum of 253 ASCII characters
if (!($len = strlen($name)) || $len > 253
// .example.org and localhost- are not allowed
|| $name[0] == '.' || $name[0] == '-' || $name[ $len - 1 ] == '.' || $name[ $len - 1 ] == '-'
// a.de is the shortest possible domain name and needs one dot
|| ($domain_only && ($len < 4 || strpos($name, '.') === false))
// several combinations are not allowed
|| strpos($name, '..') !== false
|| strpos($name, '.-') !== false
|| strpos($name, '-.') !== false
// only letters, numbers, dot and hypen are allowed
|| preg_match('/[^a-z\d.-]/i', $name)
) {
return false;
}
// each label may contain up to 63 characters
$offset = 0;
while (($pos = strpos($name, '.', $offset)) !== false) {
if ($pos - $offset > 63) {
return false;
}
$offset = $pos + 1;
}
return $name;
}


Und hier die Basis für meine Tests:
<?php
function filter_hostname($name, $domain_only=false) {
// entire hostname has a maximum of 253 ASCII characters
if (!($len = strlen($name)) || $len > 253
// .example.org and localhost- are not allowed
|| $name[0] == '.' || $name[0] == '-' || $name[ $len - 1 ] == '.' || $name[ $len - 1 ] == '-'
// a.de is the shortest possible domain name and needs one dot
|| ($domain_only && ($len < 4 || strpos($name, '.') === false))
// several combinations are not allowed
|| strpos($name, '..') !== false
|| strpos($name, '.-') !== false
|| strpos($name, '-.') !== false
// only letters, numbers, dot and hypen are allowed
/*
// really slow
for ($i = 0; $i < $len; $i++) {
if (stripos('abcdefghijklmnopqrstuvwxyz0123456789.-', $name[$i]) === false) {
return false;
}
}
// really slow
while ($len--) {
if (stripos('abcdefghijklmnopqrstuvwxyz0123456789.-', $name[$len]) === false) {
return false;
}
}
// slow
|| str_ireplace(str_split('abcdefghijklmnopqrstuvwxyz0123456789.-'), '', $name)
// fast
|| !ctype_alnum(str_replace(array('-', '.'), '', $name))
*/
|| preg_match('/[^a-z\d.-]/i', $name)
) {
return false;
}
// each label may contain up to 63 characters
/*
// really slow
if (max(array_map('strlen', explode('.', $name))) > 63) {
return false;
}
// slow
$labels = explode('.', $name);
foreach ($labels as $label) {
if (strlen($label) > 63) {
return false;
}
}
// fast
if (!preg_match('/^[^\.]{1,63}(\.[^\.]{1,63})*$/', $name)) {
return false;
}
*/
$offset = 0;
while (($pos = strpos($name, '.', $offset)) !== false) {
if ($pos - $offset > 63) {
return false;
}
$offset = $pos + 1;
}
return $name;
}
function is_valid_domain_name($domain_name)
{
    return (preg_match("/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i", $domain_name) //valid chars check
            && preg_match("/^.{1,253}$/", $domain_name) //overall length check
            && preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $domain_name)   ); //length of each label
}
function is_valid_domain_name2($domain_name) {
return (
(($len = strlen($domain_name)) < 254 && $len) //overall length check
&& preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $domain_name) //length of each label
&& preg_match("/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i", $domain_name) //valid chars check
);
}
function is_valid_domain_name3($domain_name) {
return (
preg_match("/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i", $domain_name) //valid chars check
&& preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $domain_name) //length of each label
&& (($len = strlen($domain_name)) < 254 && $len) //overall length check
);
}
$domains = explode(',', 'example.com,sub.EXAMPLE.co.uk,xn--fsqu00a.xn--0zwm56d,xn--4gbrim.xn----ymcbaaajlc6dj7bxne2c.xn--wgbh1c,' . str_repeat('example', 9) . '.' . str_repeat('example', 9) . '.com,a,0,a.b,localhost,exa mple.com,example..com,example.com ,example-.com,.example.com,' . str_repeat('example', 9) . '.' . str_repeat('example', 10) . '.com,' . str_repeat('example', 9) . '.' . str_repeat('example', 9) . '.' . str_repeat('example', 9) . '.' . str_repeat('example', 9) . '.com,e--e.-om,e--e-.om,,<script,alert(,.,.., ,-,');
$real_world = explode(',', 'example.com,sub.EXAMPLE.co.uk,xn--fsqu00a.xn--0zwm56d,xn--4gbrim.xn----ymcbaaajlc6dj7bxne2c.xn--wgbh1c,a,0,a.b,localhost,exa mple.com,example..com,example.com ,example-.com,.example.com,e--e.-om,e--e-.om,,<script,alert(,.,.., ,-,');
// benchmark
$start_time = microtime(true);
for ($i = 0; $i < 10000; $i++) {
foreach ($real_world as $domain) {
if (!$i) {
echo filter_hostname($domain) . PHP_EOL;
}
filter_hostname($domain);
}
}
$end_time = microtime(true);
echo $end_time - $start_time;
filter_hostname($domain);// $domains: 0.43556308746338 $real_world: 0.33749794960022
is_valid_domain_name($domain);// $domains: 0.81832790374756 $real_world: 0.32248711585999
is_valid_domain_name2($domain);// $domains: 0.49456095695496 $real_world: 0.34724116325378
is_valid_domain_name3($domain);// $domains: 0.74682402610779 $real_world: 0.2913498878479
?>

Den Benchmark-Zeiten kann man entnehmen, dass es hier kaum relevante Unterschiede gibt, wenn man $real_world vergleicht. Und schlussendlich hat sich sogar herausgestellt, dass preg_match() schneller war als ctype_alnum(), aber grundsätzlich möglich ist es und bei überlangen Host-/Domainnamen trumpft die Funktion sogar auf.

Evtl. wäre is_valid_domain_name() sogar noch mal langsamer, wenn ich die gleiche Funktionalität, also die Unterscheidung zwischen Hostname und Domainname einbaue, aber dafür war ich dann ehrlich gesagt zu faul ;)

In jedem Fall interessant wie viel verschiedene Lösungswege es gibt und welche davon schneller ist als die andere.

Wenn ich mal die Zeit finde, werde ich die Funktion vielleicht mit dieser kombinieren:
http://www.programmierer-forum.de/domainnamen-ermitteln-t244185.htm



Verfasst am: 04.03.2015, 20:37
zitieren

Da der Filter wie gesagt recht weich ist akzeptiert er übrigens auch IP-Adressen. Also 127.0.0.1 ist bei $domain_only ebenfalls eine gültige Domain.

Hier könnte man zusätzlich mit diesem Check arbeiten:
filter_var('127.0.0.1', FILTER_VALIDATE_IP);

Wenn ich die Zeit finde aktualisiere ich den Code aber noch.

Verfasst am: 24.03.2015, 22:44
zitieren

Auf Basis von filter_hostname() kann ich mir nun die Root URL mit beliebigem Input verifizieren:
<?php
function build_root_url($url) {
// add scheme http://en.wikipedia.org/wiki/URI_scheme#Generic_syntax
if (!preg_match('~^[0-9a-z.\-+]{2,}://~i', $url)) {
$url = 'http://' . $url;
}
$scheme_pos = strpos($url, '://');
// this will fail if "http://example.com"
$first_slash_pos = strpos($url, '/', $scheme_pos + 3);
if ($first_slash_pos) {
// "http://example.com/foo/bar" becomes "http://example.com"
$url = substr($url, 0, $first_slash_pos);
}
// is the hostname valid?
if (!filter_hostname(substr($url, strpos($url, '://') + 3), true)) {
return false;
}
// "http://example.com" becomes "http://example.com/"
$url .= '/';
return $url;
}
$domains = explode(',', 'example,http://.example.com,example.com,http://example.com,http://example.com/,http://example.com/foo/bar,http://foo.example.com,foo.example.com');
foreach ($domains as $domain) {
echo $domain . ' --> ' . build_root_url($domain) . PHP_EOL;
}
?>

Ergebnis:
Zitatexample -->
http://.example.com -->
example.com --> http://example.com/
http://example.com --> http://example.com/
http://example.com/ --> http://example.com/
http://example.com/foo/bar --> http://example.com/
http://foo.example.com --> http://foo.example.com/
foo.example.com --> http://foo.example.com/
pn email
Gast 
24.03.2015, 22:44
zitieren

Mach mit!

Wenn Dir die Beiträge zum Thread "Domainnamen / Hostnamen validieren" gefallen haben oder Du noch Fragen hast oder Ergänzungen machen möchtest, solltest Du Dich gleich bei uns anmelden:



Registrierte Mitglieder genießen die folgenden Vorteile:
✔ kostenlose Mitgliedschaft
keine Werbung
✔ direkter Austausch mit Gleichgesinnten
✔ neue Fragen stellen oder Diskussionen starten
✔ schnelle Hilfe bei Problemen
✔ Bilder und Videos hochladen
✔ und vieles mehr...


Neuen Thread eröffnenNeue Antwort erstellen
Ähnliche BeiträgeRe:
Letzter Beitrag
Beiträge validieren
Hallo, ich wurde beauftragt herauszufinden, ob man mit mediawiki Beiträge erst validieren kann bevor sie live erscheinen. Ich finde es zwar eine Einschränkung :suspekt: , müsste aber doch technisch möglich sein? Ich habe die...
von phonky
2
159
04.08.2010, 09:37
phonky
Domain Namen ermitteln (in URL bzw Hostnamen)
Es ist gar nicht so einfach eine Domain aus einer URL zu ermitteln, denn es gibt viele URLs, die exakt den selben Aufbau besitzen, aber unterschiedliche Bedeutungen haben: - bbc.co.uk ist eine Domain - www.db.de ist eine Subdomain Man benötigt also...
[PHP]von mgutt
1
7.959
04.02.2017, 03:26
mgutt
Ungewöhnliche Domainnamen
Gibt ja schon lustige kobinationen von wegen ingeb.org oda sowas. Aba was ich da mal gefunden hab is ja mal was anderes. www.jews.kz Kasachische seite der jüdischen gemeinschaft... Geschmacklos oder...
von *Sly*
5
799
23.09.2007, 19:36
s-lab
© 2004 - 2025 www.programmierer-forum.de | Communities | Impressum |