Analisando domínio de um URL

144

Preciso criar uma função que analise o domínio de uma URL.

Então com

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

ou

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

deveria retornar google.com

com

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

deve retornar google.co.uk.

zuk1
fonte
9
@LightnessRacesinOrbit Isso é um pouco mais do que apenas "procurar no manual". O PHP parse_url()retorna o host , não o domínio .
precisa saber é o seguinte
1
@ w3dk: Ainda teria sido um ponto de partida fantástico, permitindo que essa pergunta fosse sobre essa limitação, parse_urle não um vago "o que posso fazer".
Lightness Races in Orbit
5
@LightnessRacesinOrbit sua defesa é falso dada a sua reputação - de forma mais simples você pode admitir que você não leu a pergunta completamente
Andy Jones
4
@LightnessRacesinOrbit Não necessariamente. support.suso.com/supki/…
Autumn Leonard

Respostas:

297

Confira parse_url():

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

parse_url não lida muito bem com URLs muito mal confinados, mas é bom se você geralmente espera URLs decentes.

Owen
fonte
35
Uma coisa que parse_url () não faz é retornar apenas o domínio. Se você adicionar www.google.com ou www.google.com.br, ele também retornará o host. Alguma sugestão para isso?
Gavin M. Roy
6
parse_urlnão lidar com subdomínios, mas Purl faz: github.com/jwage/purl
Damien
1
parse_url()possivelmente analisaria URLs com um domínio que contenha hífens incorretamente. Não foi possível encontrar a prova definitiva, mas verifique este bug . FILTER_VALIDATE_URLusa parse_url()internamente.
XedinUnknown
8
Ou simplesmente: print parse_url($url, PHP_URL_HOST))se você não precisar da $parsematriz para mais nada.
Rybo111
98
$domain = str_ireplace('www.', '', parse_url($url, PHP_URL_HOST));

Este voltaria a google.comtanto para http://google.com/ ... e http://www.google.com/ ...

Alix Axel
fonte
18
porque ele ainda retornará o servidor se você colocar "server.google.com" ou "www3.google.com" ...
patrick
Nem todos os subdomínios são www, crawl-66-249-66-1.googlebot.com, myblog.blogspot.com são alguns exemplos.
Rafark
23

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

por algum motivo estranho, parse_url retorna o host (por exemplo, example.com) como o caminho quando nenhum esquema é fornecido no URL de entrada. Então, eu escrevi uma função rápida para obter o host real:

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
fonte
Não se esqueça de citar suas strings como hoste path.
Gumbo
1
Se eu usar o example.com, o php exibirá um aviso: Message: Undefined index: hostalguma idéia para corrigir isso?
Zim3r
1
Infelizmente, o subdomínio ainda está incluído nessa abordagem, veja seu exemplo # 3.
jenlampton
1
@ Zim3r Altere a primeira parte do ternário para !empty($parseUrl['host']).
precisa saber é o seguinte
LOL se não tiver um esquema, não é um URL.
miken32 2/01
12

O código que deveria funcionar 100% não pareceu cortá-lo para mim, eu fiz o patch um pouco do exemplo, mas encontrei o código que não estava ajudando e com problemas. então mudei para algumas funções (para salvar solicitando a lista do Mozilla o tempo todo e removendo o sistema de cache). Isso foi testado em um conjunto de 1000 URLs e parecia funcionar.

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;    
}

Então use-o como

$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

Eu sei que deveria ter transformado isso em uma aula, mas não tive tempo.

Shaun
fonte
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
fonte
Também
Esta é uma ótima resposta e merece mais crédito. Basta adicionar esta linha como a primeira linha na função e também resolver os problemas de MangeshSathe e jenlampton: if ((substr ($ url, 0, strlen ('http: //')) <> 'http: //' ) && (substr ($ url, 0, strlen ('https: //')) <> 'https: //')) $ url = 'http: //'.$url;
Rick
4

Se você deseja extrair o host da string http://google.com/dhasjkdas/sadsdds/sdda/sdads.html, o uso de parse_url () é uma solução aceitável para você.

Mas se você deseja extrair o domínio ou suas partes, precisará do pacote usando Public Suffix List . Sim, você pode usar as funções de seqüência de caracteres parse_url (), mas, às vezes, produz resultados incorretos.

Eu recomendo o TLDExtract para análise de domínio, aqui está um código de exemplo que mostra o 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
fonte
Muito obrigado por esta sugestão. Eu odeio adicionar outra biblioteca para o que parece ser uma tarefa simples, mas depois vi essa citação no leia-me aplicada a mim: "Todo mundo entende isso errado. Dividindo o '.' e tomar os dois últimos elementos é muito útil apenas se você estiver pensando em domínios simples, por exemplo, .com.Pense em analisar forums.bbc.co.uk, por exemplo: o método de divisão ingênuo acima fornecerá "co" como domínio e 'uk' como TLD, em vez de 'bbc' e 'co.uk', respectivamente. "
precisa saber é o seguinte
O resultado da divisão de pontos, embora não seja o que queremos que aconteça em nossos amados domínios .co.uk, na verdade é o resultado correto, o co sendo um segundo nível e o uk sendo o nível superior. O Webmaster geralmente não percebe isso.
27417 Chris
4

Eu descobri que a solução do @ philfreo (referenciada no php.net) é muito boa para obter bons resultados, mas em alguns casos mostra a mensagem "notice" e "Strict Standards" do php. Aqui uma versão fixa deste código.

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
fonte
2

Aqui está o código que fiz que 100% encontra apenas o nome de domínio, uma vez que são necessários os sub tlds do mozilla. A única coisa que você precisa verificar é como você faz o cache desse arquivo, para não consultar o mozilla toda vez.

Por alguma estranha razão, domínios como co.uk não estão na lista, então você deve fazer alguns hackers e adicioná-los manualmente. Não é a solução mais limpa, mas espero que ajude alguém.

//=====================================================
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
fonte
O motivo pelo qual o domínio co.uknão estava na lista era porque era uma lista de TLDs, não de domínios. O ccTLD mudou muito desde que esta resposta foi escrita. Notavelmente: "Novos registros diretamente sob .uk foram aceitos pela Nominet desde 10 de junho de 2014 às 08:00 BST; no entanto, há um período de reserva para clientes existentes que já possuem .co.uk, .org.uk, .me.uk , .net.uk, .ltd.uk ou .plc.uk para reivindicar o domínio .uk correspondente, que é executado até às 07:59 BST de 10 de junho de 2019. " ( Source )
ashleedawg
2

Você pode passar PHP_URL_HOST para a função parse_url como segundo parâmetro

$url = 'http://google.com/dhasjkdas/sadsdds/sdda/sdads.html';
$host = parse_url($url, PHP_URL_HOST);
print $host; // prints 'google.com'
Oleg Matei
fonte
2
Isso é essencialmente o mesmo que a resposta acima, no entanto, a pergunta está exigindo o domínio , que não é necessariamente o mesmo que o host .
MrWhite
veja o comentário acima sobre o esquema: por algum motivo estranho, parse_url retorna o host (por exemplo, exemplo.com) como o caminho quando nenhum esquema é fornecido no URL de entrada. Então eu escrevi uma função rápida de obter o verdadeiro host:
jenlampton
2

Por favor, considere substituir a solução aceita pelo seguinte:

parse_url () sempre incluirá qualquer subdomínio, portanto, essa função não analisa muito bem os nomes de domínio. aqui estão alguns exemplos:

$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

Em vez disso, você pode considerar esta solução pragmática. Ele abrangerá muitos, mas nem todos os nomes de domínio - por exemplo, domínios de nível inferior, como 'sos.state.oh.us', não são abordados.

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

Por fim, o Analisador de Domínio PHP de Jeremy Kendall permite analisar o nome do domínio a partir de um URL. O analisador de nome de host do URI da liga também fará o trabalho.

Kristoffer Bohmann
fonte
Oi, isso é bom, mas não funciona com endereços IP. Ainda assim, um ótimo trabalho.
MeCe 8/06/19
1

parse_url não funcionou para mim. Apenas retornou o caminho. Mudando para o básico usando o php5.3 +:

$url  = str_replace('http://', '', strtolower( $s->website));
if (strpos($url, '/'))  $url = strstr($url, '/', true);
Vai
fonte
1

Eu editei para você:

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);
}

Todo o tipo de URL (www.domínio.ltd, sub1.subn.domínio.ltd resultará em: domínio.ltd.

Vida NotFound
fonte
1

Estou adicionando esta resposta tarde, pois é a resposta que mais aparece no Google ...

Você pode usar o PHP para ...

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

para pegar o host, mas não o domínio privado ao qual o host se refere. (O exemplo www.google.co.uké o host, mas google.co.uké o domínio privado)

Para obter o domínio privado, é necessário conhecer a lista de sufixos públicos nos quais é possível registrar um domínio privado. Essa lista é organizada pela Mozilla em https://publicsuffix.org/

O código abaixo funciona quando uma matriz de sufixos públicos já foi criada. Basta ligar

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

com o código restante ...

// 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
fonte
Conforme meu teste, parse_url precisa de um URL bem formado. Se você simplesmente der 'www.someDomain.com/path', ele retornará nulo. Portanto, espera que um protocolo (como http ou https) esteja presente.
Andy
0

Isso geralmente funcionará muito bem se o URL de entrada não for totalmente lixo eletrônico. Remove o subdomínio.

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

Exemplo

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

Resultado: website.com

T. Brian Jones
fonte
0

Combinando as respostas de worldofjr e Alix Axel em uma pequena função que tratará da maioria dos casos de uso:

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
fonte
esta é uma solução limitada
MGE
0
function getTrimmedUrl($link)
{
    $str = str_replace(["www.","https://","http://"],[''],$link);
    $link = explode("/",$str);
    return strtolower($link[0]);                
}
user3263025
fonte
-1

Confira parse_url ()

Greg
fonte
-6

Basta usar como se segue ...

<?php
   echo $_SERVER['SERVER_NAME'];
?>
Mard Hossain
fonte
1
Isso pressupõe que o servidor seja o URL do qual você deseja recuperar o domínio. Esse não é o caso.
Overcode