Analyse du domaine à partir d'une URL

144

J'ai besoin de créer une fonction qui analyse le domaine à partir d'une URL.

Donc avec

http://google.com/dhasjkdas/sadsdds/sdda/sdads.html

ou

http://www.google.com/dhasjkdas/sadsdds/sdda/sdads.html

ça devrait revenir google.com

avec

http://google.co.uk/dhasjkdas/sadsdds/sdda/sdads.html

il devrait revenir google.co.uk.

zuk1
la source
9
@LightnessRacesinOrbit C'est un peu plus que simplement "regarder dans le manuel". PHP parse_url()renvoie l' hôte , pas le domaine .
MrWhite
1
@ w3dk: Cela aurait toujours été un point de départ fantastique, permettant à cette question de porter sur cette limitation parse_urlplutôt que sur un vague "que puis-je faire".
Courses de légèreté en orbite le
5
@LightnessRacesinOrbit votre défense est malhonnête compte tenu de votre réputation - plus simplement, vous pouvez admettre que vous n'avez pas complètement lu la question
Andy Jones
4
@LightnessRacesinOrbit Pas nécessairement. support.suso.com/supki/…
Autumn Leonard

Réponses:

297

Découvrez parse_url():

$url = 'http://google.com/dhasjkdas/sadsdds/sdda/sdads.html';
$parse = parse_url($url);
echo $parse['host']; // prints 'google.com'

parse_url ne gère pas très bien les URL vraiment mal déformées, mais c'est bien si vous vous attendez généralement à des URL décentes.

Owen
la source
35
Une chose que parse_url () ne fait pas, c'est seulement retourner le domaine. Si vous ajoutez www.google.com ou www.google.co.uk, l'hôte sera également renvoyé. Des suggestions pour ça?
Gavin M. Roy
6
parse_urlne gère pas les sous-domaines, mais Purl le fait: github.com/jwage/purl
Damien
1
parse_url()analysera éventuellement les URL avec un domaine qui contient des tirets à tort. Impossible de trouver une preuve définitive, mais vérifiez ce bogue . FILTER_VALIDATE_URLutilise en parse_url()interne.
XedinUnknown
8
Ou simplement: print parse_url($url, PHP_URL_HOST))si vous n'avez besoin du $parsetableau pour rien d'autre.
rybo111
98
$domain = str_ireplace('www.', '', parse_url($url, PHP_URL_HOST));

Cela renverrait le google.compour http://google.com/ ... et http://www.google.com/ ...

Alix Axel
la source
18
car il renverra toujours le serveur si vous mettez "server.google.com" ou "www3.google.com" ...
patrick
Tous les sous-domaines ne sont pas www, crawl-66-249-66-1.googlebot.com, myblog.blogspot.com en sont quelques exemples.
rafark
23

De http://us3.php.net/manual/en/function.parse-url.php#93983

pour une raison étrange, parse_url renvoie l'hôte (ex. example.com) comme chemin lorsqu'aucun schéma n'est fourni dans l'url d'entrée. J'ai donc écrit une fonction rapide pour obtenir le vrai hôte:

function getHost($Address) { 
   $parseUrl = parse_url(trim($Address)); 
   return trim($parseUrl['host'] ? $parseUrl['host'] : array_shift(explode('/', $parseUrl['path'], 2))); 
} 

getHost("example.com"); // Gives example.com 
getHost("http://example.com"); // Gives example.com 
getHost("www.example.com"); // Gives www.example.com 
getHost("http://example.com/xyz"); // Gives example.com 
philfreo
la source
N'oubliez pas de citer vos chaînes comme hostet path.
Gumbo
1
Si j'utilise example.com, php affiche un avis: Message: Undefined index: hostdes idées pour résoudre ce problème?
Zim3r
1
Malheureusement, le sous-domaine est toujours inclus dans cette approche, voir votre exemple n ° 3.
jenlampton
1
@ Zim3r Remplacez la première partie du ternaire par !empty($parseUrl['host']).
Demonslay335
LOL s'il n'a pas de schéma, ce n'est pas une URL.
miken32 le
12

Le code qui était censé fonctionner à 100% ne semblait pas le couper pour moi, j'ai corrigé un peu l'exemple mais j'ai trouvé du code qui n'aidait pas et des problèmes avec lui. je l'ai donc changé en quelques fonctions (pour éviter de demander la liste à Mozilla tout le temps et de supprimer le système de cache). Cela a été testé sur un ensemble de 1000 URL et semble fonctionner.

function domain($url)
{
    global $subtlds;
    $slds = "";
    $url = strtolower($url);

    $host = parse_url('http://'.$url,PHP_URL_HOST);

    preg_match("/[^\.\/]+\.[^\.\/]+$/", $host, $matches);
    foreach($subtlds as $sub){
        if (preg_match('/\.'.preg_quote($sub).'$/', $host, $xyz)){
            preg_match("/[^\.\/]+\.[^\.\/]+\.[^\.\/]+$/", $host, $matches);
        }
    }

    return @$matches[0];
}

function get_tlds() {
    $address = 'http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1';
    $content = file($address);
    foreach ($content as $num => $line) {
        $line = trim($line);
        if($line == '') continue;
        if(@substr($line[0], 0, 2) == '/') continue;
        $line = @preg_replace("/[^a-zA-Z0-9\.]/", '', $line);
        if($line == '') continue;  //$line = '.'.$line;
        if(@$line[0] == '.') $line = substr($line, 1);
        if(!strstr($line, '.')) continue;
        $subtlds[] = $line;
        //echo "{$num}: '{$line}'"; echo "<br>";
    }

    $subtlds = array_merge(array(
            'co.uk', 'me.uk', 'net.uk', 'org.uk', 'sch.uk', 'ac.uk', 
            'gov.uk', 'nhs.uk', 'police.uk', 'mod.uk', 'asn.au', 'com.au',
            'net.au', 'id.au', 'org.au', 'edu.au', 'gov.au', 'csiro.au'
        ), $subtlds);

    $subtlds = array_unique($subtlds);

    return $subtlds;    
}

Ensuite, utilisez-le comme

$subtlds = get_tlds();
echo domain('www.example.com') //outputs: example.com
echo domain('www.example.uk.com') //outputs: example.uk.com
echo domain('www.example.fr') //outputs: example.fr

Je sais que j'aurais dû en faire une classe, mais je n'ai pas eu le temps.

Shaun
la source
11
function get_domain($url = SITE_URL)
{
    preg_match("/[a-z0-9\-]{1,63}\.[a-z\.]{2,6}$/", parse_url($url, PHP_URL_HOST), $_domain_tld);
    return $_domain_tld[0];
}

get_domain('http://www.cdl.gr'); //cdl.gr
get_domain('http://cdl.gr'); //cdl.gr
get_domain('http://www2.cdl.gr'); //cdl.gr
Nikmauro
la source
Cela ne fonctionne pas non plus pour moi: example.com // Incorrect: chaîne vide example.com // Correct: example.com www.example.com // Incorrect: chaîne vide example.com/xyz // Correct: example.com
jenlampton
C'est une excellente réponse et mérite plus de crédit. Ajoutez simplement cette ligne comme première ligne de la fonction et cela résout également les problèmes de MangeshSathe et jenlampton: if ((substr ($ url, 0, strlen ('http: //')) <> 'http: //' ) && (substr ($ url, 0, strlen ('https: //')) <> 'https: //')) $ url = 'http: //'.$url;
Rick
4

Si vous voulez extraire l'hôte de la chaîne http://google.com/dhasjkdas/sadsdds/sdda/sdads.html, l'utilisation de parse_url () est une solution acceptable pour vous.

Mais si vous voulez extraire le domaine ou ses parties, vous avez besoin d'un package qui utilise la liste de suffixes publics . Oui, vous pouvez utiliser des fonctions de chaîne autour de parse_url (), mais cela produira parfois des résultats incorrects.

Je recommande TLDExtract pour l'analyse de domaine, voici un exemple de code qui montre diff:

$extract = new LayerShifter\TLDExtract\Extract();

# For 'http://google.com/dhasjkdas/sadsdds/sdda/sdads.html'

$url = 'http://google.com/dhasjkdas/sadsdds/sdda/sdads.html';

parse_url($url, PHP_URL_HOST); // will return google.com

$result = $extract->parse($url);
$result->getFullHost(); // will return 'google.com'
$result->getRegistrableDomain(); // will return 'google.com'
$result->getSuffix(); // will return 'com'

# For 'http://search.google.com/dhasjkdas/sadsdds/sdda/sdads.html'

$url = 'http://search.google.com/dhasjkdas/sadsdds/sdda/sdads.html';

parse_url($url, PHP_URL_HOST); // will return 'search.google.com'

$result = $extract->parse($url);
$result->getFullHost(); // will return 'search.google.com'
$result->getRegistrableDomain(); // will return 'google.com'
Oleksandr Fediashov
la source
Merci beaucoup pour cette suggestion. Je déteste ajouter une autre bibliothèque pour ce qui semble être une tâche simple, mais j'ai ensuite vu cette citation sur leur readme appliquée à moi: "Tout le monde se trompe. Fractionnement sur le '.' et prendre les 2 derniers éléments ne va très loin que si vous pensez à des domaines simples, par exemple .com. Pensez à analyser forums.bbc.co.uk par exemple: la méthode de division naïve ci-dessus vous donnera «co» comme domaine et "uk" comme TLD, au lieu de "bbc" et "co.uk" respectivement. "
Demonslay335
Le résultat de la division des points alors que ce n'est pas ce que nous voulons arriver sur nos domaines .co.uk bien-aimés, est en fait le résultat correct, le co étant un deuxième niveau avec uk étant le niveau supérieur. Les webmasters ne s'en rendent souvent pas compte.
Chris
4

J'ai trouvé que la solution de @ philfreo (référencée sur php.net) est assez bien pour obtenir de bons résultats, mais dans certains cas, elle affiche le message "notice" et "Strict Standards" de php. Voici une version fixe de ce code.

function getHost($url) { 
   $parseUrl = parse_url(trim($url)); 
   if(isset($parseUrl['host']))
   {
       $host = $parseUrl['host'];
   }
   else
   {
        $path = explode('/', $parseUrl['path']);
        $host = $path[0];
   }
   return trim($host); 
} 

echo getHost("http://example.com/anything.html");           // example.com
echo getHost("http://www.example.net/directory/post.php");  // www.example.net
echo getHost("https://example.co.uk");                      // example.co.uk
echo getHost("www.example.net");                            // example.net
echo getHost("subdomain.example.net/anything");             // subdomain.example.net
echo getHost("example.net");                                // example.net
fatih
la source
2

Voici le code que j'ai créé qui ne trouve à 100% que le nom de domaine, car il prend en compte les sous tld mozilla. La seule chose que vous devez vérifier est de savoir comment créer le cache de ce fichier, de sorte que vous n'interrogez pas Mozilla à chaque fois.

Pour une raison étrange, des domaines comme co.uk ne sont pas dans la liste, vous devez donc faire des piratages et les ajouter manuellement. Ce n'est pas la solution la plus propre mais j'espère que cela aide quelqu'un.

//=====================================================
static function domain($url)
{
    $slds = "";
    $url = strtolower($url);

            $address = 'http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1';
    if(!$subtlds = @kohana::cache('subtlds', null, 60)) 
    {
        $content = file($address);
        foreach($content as $num => $line)
        {
            $line = trim($line);
            if($line == '') continue;
            if(@substr($line[0], 0, 2) == '/') continue;
            $line = @preg_replace("/[^a-zA-Z0-9\.]/", '', $line);
            if($line == '') continue;  //$line = '.'.$line;
            if(@$line[0] == '.') $line = substr($line, 1);
            if(!strstr($line, '.')) continue;
            $subtlds[] = $line;
            //echo "{$num}: '{$line}'"; echo "<br>";
        }
        $subtlds = array_merge(Array(
            'co.uk', 'me.uk', 'net.uk', 'org.uk', 'sch.uk', 'ac.uk', 
            'gov.uk', 'nhs.uk', 'police.uk', 'mod.uk', 'asn.au', 'com.au',
            'net.au', 'id.au', 'org.au', 'edu.au', 'gov.au', 'csiro.au',
            ),$subtlds);

        $subtlds = array_unique($subtlds);
        //echo var_dump($subtlds);
        @kohana::cache('subtlds', $subtlds);
    }


    preg_match('/^(http:[\/]{2,})?([^\/]+)/i', $url, $matches);
    //preg_match("/^(http:\/\/|https:\/\/|)[a-zA-Z-]([^\/]+)/i", $url, $matches);
    $host = @$matches[2];
    //echo var_dump($matches);

    preg_match("/[^\.\/]+\.[^\.\/]+$/", $host, $matches);
    foreach($subtlds as $sub) 
    {
        if (preg_match("/{$sub}$/", $host, $xyz))
        preg_match("/[^\.\/]+\.[^\.\/]+\.[^\.\/]+$/", $host, $matches);
    }

    return @$matches[0];
}
Luka
la source
La raison pour laquelle le domaine co.ukne figurait pas sur la liste, était qu'il s'agissait d'une liste de TLD, pas de domaines. Le ccTLD a beaucoup changé depuis que cette réponse a été écrite. Notamment: «Les nouvelles inscriptions directement sous .uk sont acceptées par Nominet depuis le 10 juin 2014 08:00 BST, cependant il y a une période de réservation pour les clients existants qui ont déjà un .co.uk, .org.uk, .me.uk , .net.uk, .ltd.uk ou .plc.uk pour réclamer le domaine .uk correspondant, qui s'exécute jusqu'à 07h59 BST le 10 juin 2019. " ( Source )
ashleedawg
2

Vous pouvez passer PHP_URL_HOST dans la fonction parse_url comme deuxième paramètre

$url = 'http://google.com/dhasjkdas/sadsdds/sdda/sdads.html';
$host = parse_url($url, PHP_URL_HOST);
print $host; // prints 'google.com'
Oleg Matei
la source
2
C'est essentiellement la même chose que la réponse ci-dessus, cependant, la question nécessite le domaine , qui n'est pas nécessairement le même que l' hôte .
MrWhite
voir le commentaire ci-dessus sur le schéma: pour une raison étrange, parse_url renvoie l'hôte (ex. example.com) comme chemin lorsqu'aucun schéma n'est fourni dans l'url d'entrée. J'ai donc écrit une fonction rapide pour obtenir le vrai hôte:
jenlampton
2

Veuillez envisager de remplacer la solution acceptée par ce qui suit:

parse_url () inclura toujours tous les sous-domaines, donc cette fonction n'analyse pas très bien les noms de domaine. Voici quelques exemples:

$url = 'http://www.google.com/dhasjkdas/sadsdds/sdda/sdads.html';
$parse = parse_url($url);
echo $parse['host']; // prints 'www.google.com'

echo parse_url('https://subdomain.example.com/foo/bar', PHP_URL_HOST);
// Output: subdomain.example.com

echo parse_url('https://subdomain.example.co.uk/foo/bar', PHP_URL_HOST);
// Output: subdomain.example.co.uk

Au lieu de cela, vous pouvez envisager cette solution pragmatique. Il couvrira de nombreux noms de domaine, mais pas tous - par exemple, les domaines de niveau inférieur tels que «sos.state.oh.us» ne sont pas couverts.

function getDomain($url) {
    $host = parse_url($url, PHP_URL_HOST);

    if(filter_var($host,FILTER_VALIDATE_IP)) {
        // IP address returned as domain
        return $host; //* or replace with null if you don't want an IP back
    }

    $domain_array = explode(".", str_replace('www.', '', $host));
    $count = count($domain_array);
    if( $count>=3 && strlen($domain_array[$count-2])==2 ) {
        // SLD (example.co.uk)
        return implode('.', array_splice($domain_array, $count-3,3));
    } else if( $count>=2 ) {
        // TLD (example.com)
        return implode('.', array_splice($domain_array, $count-2,2));
    }
}

// Your domains
    echo getDomain('http://google.com/dhasjkdas/sadsdds/sdda/sdads.html'); // google.com
    echo getDomain('http://www.google.com/dhasjkdas/sadsdds/sdda/sdads.html'); // google.com
    echo getDomain('http://google.co.uk/dhasjkdas/sadsdds/sdda/sdads.html'); // google.co.uk

// TLD
    echo getDomain('https://shop.example.com'); // example.com
    echo getDomain('https://foo.bar.example.com'); // example.com
    echo getDomain('https://www.example.com'); // example.com
    echo getDomain('https://example.com'); // example.com

// SLD
    echo getDomain('https://more.news.bbc.co.uk'); // bbc.co.uk
    echo getDomain('https://www.bbc.co.uk'); // bbc.co.uk
    echo getDomain('https://bbc.co.uk'); // bbc.co.uk

// IP
    echo getDomain('https://1.2.3.45');  // 1.2.3.45

Enfin, le PHP Domain Parser de Jeremy Kendall vous permet d'analyser le nom de domaine à partir d'une URL. L'analyseur de nom d'hôte d'URI de ligue fera également le travail.

Kristoffer Bohmann
la source
Salut, c'est bien mais cela ne fonctionne pas avec les adresses IP. Encore, excellent travail.
MeCe
1

parse_url n'a pas fonctionné pour moi. Il a seulement renvoyé le chemin. Passer aux bases en utilisant php5.3 +:

$url  = str_replace('http://', '', strtolower( $s->website));
if (strpos($url, '/'))  $url = strstr($url, '/', true);
Volonté
la source
1

J'ai édité pour vous:

function getHost($Address) { 
    $parseUrl = parse_url(trim($Address));
    $host = trim($parseUrl['host'] ? $parseUrl['host'] : array_shift(explode('/', $parseUrl['path'], 2))); 

    $parts = explode( '.', $host );
    $num_parts = count($parts);

    if ($parts[0] == "www") {
        for ($i=1; $i < $num_parts; $i++) { 
            $h .= $parts[$i] . '.';
        }
    }else {
        for ($i=0; $i < $num_parts; $i++) { 
            $h .= $parts[$i] . '.';
        }
    }
    return substr($h,0,-1);
}

Toutes les URL de type (www.domain.ltd, sub1.subn.domain.ltd aboutiront à: domain.ltd.

Pas trouvé la vie
la source
1

J'ajoute cette réponse tard car c'est la réponse qui apparaît le plus sur Google ...

Vous pouvez utiliser PHP pour ...

$url = "www.google.co.uk";
$host = parse_url($url, PHP_URL_HOST);
// $host == "www.google.co.uk"

pour récupérer l' hôte mais pas le domaine privé auquel l'hôte se réfère. (L'exemple www.google.co.ukest l'hôte, mais google.co.ukest le domaine privé)

Pour saisir le domaine privé, vous devez connaître la liste des suffixes publics sur lesquels on peut enregistrer un domaine privé. Cette liste est organisée par Mozilla à l' adresse https://publicsuffix.org/

Le code ci-dessous fonctionne lorsqu'un tableau de suffixes publics a déjà été créé. Appelez simplement

$domain = get_private_domain("www.google.co.uk");

avec le code restant ...

// find some way to parse the above list of public suffix
// then add them to a PHP array
$suffix = [... all valid public suffix ...];

function get_public_suffix($host) {
  $parts = split("\.", $host);
  while (count($parts) > 0) {
    if (is_public_suffix(join(".", $parts)))
      return join(".", $parts);

    array_shift($parts);
  }

  return false;
}

function is_public_suffix($host) {
  global $suffix;
  return isset($suffix[$host]);
}

function get_private_domain($host) {
  $public = get_public_suffix($host);
  $public_parts = split("\.", $public);
  $all_parts = split("\.", $host);

  $private = [];

  for ($x = 0; $x < count($public_parts); ++$x) 
    $private[] = array_pop($all_parts);

  if (count($all_parts) > 0)
    $private[] = array_pop($all_parts);

  return join(".", array_reverse($private));
}
Andy Jones
la source
Selon mes tests, parse_url a besoin d'une URL bien formée. Si vous donnez simplement «www.someDomain.com/path», il renverra null. Il s'attend donc à ce qu'un protocole (comme http ou https) soit présent.
Andy
0

Cela fonctionnera généralement très bien si l'URL d'entrée n'est pas totalement indésirable. Il supprime le sous-domaine.

$host = parse_url( $Row->url, PHP_URL_HOST );
$parts = explode( '.', $host );
$parts = array_reverse( $parts );
$domain = $parts[1].'.'.$parts[0];

Exemple

Contribution: http://www2.website.com:8080/some/file/structure?some=parameters

Production: website.com

T. Brian Jones
la source
0

Combinant les réponses de worldofjr et Alix Axel en une seule petite fonction qui gérera la plupart des cas d'utilisation:

function get_url_hostname($url) {

    $parse = parse_url($url);
    return str_ireplace('www.', '', $parse['host']);

}

get_url_hostname('http://www.google.com/example/path/file.html'); // google.com
Michael Giovanni Pumo
la source
c'est une solution limitée
MGE
0
function getTrimmedUrl($link)
{
    $str = str_replace(["www.","https://","http://"],[''],$link);
    $link = explode("/",$str);
    return strtolower($link[0]);                
}
user3263025
la source
-6

Utilisez simplement comme suit ...

<?php
   echo $_SERVER['SERVER_NAME'];
?>
Md. Maruf Hossain
la source
1
Cela suppose que le serveur est l'URL à partir de laquelle vous souhaitez récupérer le domaine. Ce n'est pas le cas.
Overcode