Analizando el dominio desde una URL

144

Necesito construir una función que analice el dominio desde una URL.

Entonces, con

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

o

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

debería volver google.com

con

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

Debería volver google.co.uk.

zuk1
fuente
9
@LightnessRacesinOrbit Esto es un poco más que simplemente "mirar en el manual". PHP parse_url()devuelve el host , no el dominio .
MrWhite
1
@ w3dk: Todavía habría sido un punto de partida fantástico, permitiendo que esta pregunta sea sobre esa limitación, en parse_urllugar de un vago "qué puedo hacer".
Carreras de ligereza en órbita
55
@LightnessRacesinOrbit su defensa es falsa dada su reputación - más simplemente puede admitir que no leyó la pregunta por completo
Andy Jones
44
@LightnessRacesinOrbit No necesariamente. support.suso.com/supki/…
Otoño Leonard

Respuestas:

297

Echa un vistazo a parse_url():

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

parse_url no maneja muy bien las URL maltratadas muy bien, pero está bien si generalmente espera URL decentes.

Owen
fuente
35
Una cosa que parse_url () no hace es solo devolver el dominio. Si agrega www.google.com o www.google.co.uk, también devolverá el host. ¿Alguna sugerencia para eso?
Gavin M. Roy
66
parse_urlno maneja subdominios, pero Purl sí: github.com/jwage/purl
Damien
1
parse_url()posiblemente analizaría las URL con un dominio que contiene guiones incorrectamente. No se pudo encontrar una prueba definitiva, pero echa un vistazo a este error . FILTER_VALIDATE_URLutiliza parse_url()internamente.
Xedin Desconocido el
8
O simplemente: print parse_url($url, PHP_URL_HOST))si no necesita la $parsematriz para nada más.
rybo111
98
$domain = str_ireplace('www.', '', parse_url($url, PHP_URL_HOST));

Esto devolvería google.comtanto para http://google.com/ ... como para http://www.google.com/ ...

Alix Axel
fuente
18
porque aún devolverá el servidor si ingresa "server.google.com" o "www3.google.com" ...
patrick
No todos los subdominios son www, crawl-66-249-66-1.googlebot.com, myblog.blogspot.com son algunos ejemplos.
rafark
23

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

por alguna extraña razón, parse_url devuelve el host (ej. ejemplo.com) como la ruta cuando no se proporciona ningún esquema en la url de entrada. Entonces escribí una función rápida para obtener el 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
fuente
No olvides citar tus cadenas como hosty path.
Gumbo
1
Si uso example.com, php muestra un aviso: ¿ Message: Undefined index: hostalguna idea para solucionar esto?
Zim3r
1
Lamentablemente, el subdominio todavía se incluye con este enfoque, vea su ejemplo # 3.
jenlampton
1
@ Zim3r Cambia la primera parte del ternario a !empty($parseUrl['host']).
Demonslay335
LOL si no tiene un esquema, no es una URL.
miken32
12

El código que estaba destinado a funcionar al 100% no parecía ser suficiente para mí, parcheé un poco el ejemplo pero encontré código que no estaba ayudando y problemas con él. así que lo cambié a un par de funciones (para guardar la solicitud de la lista de Mozilla todo el tiempo y eliminar el sistema de caché). Esto se ha probado con un conjunto de 1000 URL y parece 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;    
}

Entonces úsalo 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

Sé que debería haber convertido esto en una clase, pero no tuve tiempo.

Shaun
fuente
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
fuente
No funciona para mí tampoco: example.com // Incorrecto: cadena vacía example.com // Correcto: example.com www.example.com // Incorrecto: cadena vacía example.com/xyz // Correcto: example.com
jenlampton
Esta es una gran respuesta y merece más crédito. Simplemente agregue esta línea como la primera línea en la función y también resuelve los problemas de MangeshSathe y jenlampton: if ((substr ($ url, 0, strlen ('http: //')) <> 'http: //' ) && (substr ($ url, 0, strlen ('https: //')) <> 'https: //')) $ url = 'http: //'.$url;
Rick
4

Si desea extraer el host de la cadena http://google.com/dhasjkdas/sadsdds/sdda/sdads.html, el uso de parse_url () es una solución aceptable para usted.

Pero si desea extraer el dominio o sus partes, necesita un paquete que use la Lista de sufijos públicos . Sí, puede usar funciones de cadena alrededor de parse_url (), pero a veces producirá resultados incorrectos.

Recomiendo TLDExtract para el análisis de dominios, aquí hay un código de muestra que muestra 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
fuente
Muchas gracias por esta sugerencia. Odio agregar otra biblioteca para lo que parece ser una tarea simple, pero luego vi que esta cita en su archivo Léame se aplicaba a mí: "Todo el mundo se equivoca. Dividiendo en el '.' y tomar los últimos 2 elementos es muy útil solo si está pensando en, por ejemplo, dominios .com. Piense en analizar foros.bbc.co.uk por ejemplo: el ingenuo método de división anterior le dará 'co' como dominio y 'uk' como TLD, en lugar de 'bbc' y 'co.uk' respectivamente ".
Demonslay335
El resultado de dividir puntos, aunque no es lo que queremos que suceda en nuestros queridos dominios .co.uk, en realidad es el resultado correcto, el co es un segundo nivel y el Reino Unido es el nivel superior. El webmaster a menudo no se da cuenta de eso.
Chris
4

Descubrí que la solución de @ philfreo (referenciada desde php.net) es bastante buena para obtener buenos resultados, pero en algunos casos muestra el mensaje de "aviso" y "Normas estrictas" de php. Aquí una versión fija de este 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
fuente
2

Aquí está el código que hice que 100% encuentra solo el nombre de dominio, ya que toma subtlds de mozilla para tener en cuenta. Lo único que tiene que verificar es cómo hacer caché de ese archivo, por lo que no consulta mozilla cada vez.

Por alguna extraña razón, los dominios como co.uk no están en la lista, por lo que debe realizar algún pirateo y agregarlos manualmente. No es la solución más limpia, pero espero que ayude a alguien.

//=====================================================
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
fuente
La razón por la cual el dominio co.ukno estaba en la lista, fue porque era una lista de TLD, no de dominios. El ccTLD ha cambiado mucho desde que se escribió esta respuesta. Notablemente: "Nominet ha aceptado nuevos registros directamente bajo .uk desde el 10 de junio de 2014 a las 08:00 BST, sin embargo, hay un período de reserva para los clientes existentes que ya tienen un .co.uk, .org.uk, .me.uk , .net.uk, .ltd.uk o .plc.uk para reclamar el dominio .uk correspondiente, que se ejecuta hasta las 07:59 BST del 10 de junio de 2019 ". ( Fuente )
ashleedawg
2

Puede pasar PHP_URL_HOST a la función 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
fuente
2
Esto es esencialmente lo mismo que la respuesta anterior, sin embargo, la pregunta requiere el dominio , que no es necesariamente el mismo que el host .
MrWhite
vea el comentario anterior sobre el esquema: por alguna extraña razón, parse_url devuelve el host (ej. ejemplo.com) como la ruta cuando no se proporciona ningún esquema en la url de entrada. Así que he escrito una función rápida para obtener el host real:
jenlampton
2

Considere reemplazar la solución aceptada con lo siguiente:

parse_url () siempre incluirá cualquier subdominio (s), por lo que esta función no analiza muy bien los nombres de dominio. Aquí hay unos ejemplos:

$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

En cambio, puede considerar esta solución pragmática. Cubrirá muchos, pero no todos los nombres de dominio; por ejemplo, los dominios de nivel inferior como 'sos.state.oh.us' no están cubiertos.

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

Finalmente, el analizador de dominios PHP de Jeremy Kendall le permite analizar el nombre de dominio desde una url. League URI Hostname Parser también hará el trabajo.

Kristoffer Bohmann
fuente
Hola, esto es bueno pero no funciona con direcciones IP. Aún así, buen trabajo.
MeCe
1

parse_url no funcionó para mí. Solo devolvió el camino. Pasando a lo básico usando php5.3 +:

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

He editado para ti:

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

Todos los tipos de URL (www.domain.ltd, sub1.subn.domain.ltd darán como resultado: domain.ltd.

Vida no encontrada
fuente
1

Estoy agregando esta respuesta tarde ya que esta es la respuesta que más aparece en Google ...

Puedes usar PHP para ...

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

para agarrar el host pero no el dominio privado al que se refiere el host. (Ejemplo www.google.co.ukes el host, pero google.co.ukes el dominio privado)

Para obtener el dominio privado, debe conocer la lista de sufijos públicos en los que se puede registrar un dominio privado. Esta lista está curada por Mozilla en https://publicsuffix.org/

El siguiente código funciona cuando ya se ha creado una matriz de sufijos públicos. Simplemente llame

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

con el 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
fuente
Según mis pruebas, parse_url necesita una URL bien formada. Si solo le da 'www.someDomain.com/path' entonces devolverá nulo. Por lo tanto, espera que estén presentes protocolos (como http o https).
Andy
0

Esto generalmente funcionará muy bien si la URL de entrada no es basura total. Elimina el subdominio.

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

Ejemplo

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

Salida: website.com

T. Brian Jones
fuente
0

Combinando las respuestas de worldofjr y Alix Axel en una pequeña función que manejará la mayoría de los 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
fuente
esta es una solución limitada
MGE
0
function getTrimmedUrl($link)
{
    $str = str_replace(["www.","https://","http://"],[''],$link);
    $link = explode("/",$str);
    return strtolower($link[0]);                
}
usuario3263025
fuente
-6

Solo úsalo como sigue ...

<?php
   echo $_SERVER['SERVER_NAME'];
?>
MD Maruf Hossain
fuente
1
Esto supone que el servidor es la url de la que desea recuperar el dominio. Ese no es el caso.
Overcode el