Obtener el subdominio desde una URL

Obtener el subdominio desde una URL parece fácil al principio.

http://www.domain.example 

Escanee el primer período y luego devuelva lo que venga después del “http: //” …

Entonces recuerdas

 http://super.duper.domain.example 

Oh. Entonces piensas, está bien, ¡encuentra el último período, retrocede una palabra y obtén todo antes!

Entonces recuerdas

 http://super.duper.domain.co.uk 

Y has vuelto al punto de partida. ¿Alguien tiene alguna idea genial además de almacenar una lista de todos los TLD?

¿Alguien tiene alguna idea genial además de almacenar una lista de todos los TLD?

No, porque cada TLD difiere en lo que cuenta como un subdominio, dominio de segundo nivel, etc.

Tenga en cuenta que hay dominios de nivel superior, dominios de segundo nivel y subdominios. Técnicamente hablando, todo excepto el TLD es un subdominio.

En el ejemplo de domain.com.uk, el dominio es un subdominio, com es un dominio de segundo nivel y uk es el tld.

Entonces, la pregunta sigue siendo más compleja que a primera vista, y depende de cómo se gestione cada TLD. Necesitará una base de datos de todos los TLD que incluyan su partición particular, y lo que cuenta como un dominio de segundo nivel y un subdominio. Sin embargo, no hay demasiados TLD, por lo que la lista es razonablemente manejable, pero recostackr toda esa información no es trivial. Es posible que ya haya una lista disponible.

Parece que http://publicsuffix.org/ es una de esas listas: todos los sufijos comunes (.com, .co.uk, etc.) en una lista adecuada para la búsqueda. Todavía no será fácil analizarlo, pero al menos no tienes que mantener la lista.

Un “sufijo público” es aquel bajo el cual los usuarios de Internet pueden registrar nombres directamente. Algunos ejemplos de sufijos públicos son “.com”, “.co.uk” y “pvt.k12.wy.us”. La Lista de sufijos públicos es una lista de todos los sufijos públicos conocidos.

La Lista de sufijos públicos es una iniciativa de la Fundación Mozilla. Está disponible para su uso en cualquier software, pero fue creado originalmente para satisfacer las necesidades de los fabricantes de navegadores. Permite a los navegadores, por ejemplo:

  • Evite el uso de “supercookies” dañinos para la privacidad para sufijos de nombres de dominio de alto nivel
  • Resalta la parte más importante de un nombre de dominio en la interfaz de usuario
  • Ordene con precisión las entradas del historial por sitio

Al mirar la lista , puede ver que no es un problema trivial. Creo que una lista es la única forma correcta de lograr esto …

-Adán

Como dice Adam, no es fácil, y actualmente la única forma práctica es usar una lista.

Incluso entonces hay excepciones, por ejemplo, en .uk hay un puñado de dominios que son válidos inmediatamente en ese nivel que no están en .co.uk , por lo que deben agregarse como excepciones.

Así es como los principales navegadores hacen esto: es necesario asegurarse de que example.co.uk no pueda establecer una Cookie para .co.uk que luego se enviaría a cualquier otro sitio web bajo .co.uk .

La buena noticia es que ya hay una lista disponible en http://publicsuffix.org/ .

También hay algo de trabajo en el IETF para crear algún tipo de estándar que permita a los TLD declarar cómo es su estructura de dominio. Sin embargo, esto es algo complicado por .uk.com , que funciona como si fuera un sufijo público, pero no lo vende el registro .com .

Publicsuffix.org parece la manera de hacerlo. Hay muchas implementaciones para analizar fácilmente el contenido del archivo de archivo de datos publicsuffix:

Como ya dijeron Adam y John, publicsuffix.org es la forma correcta de hacerlo. Pero, si por alguna razón no puede usar este enfoque, aquí hay una heurística basada en una suposición que funciona para el 99% de todos los dominios:

Hay una propiedad que distingue (no todos, pero casi todos) los dominios “reales” de los subdominios y TLD y ese es el registro MX del DNS. Puede crear un algoritmo que busque esto: elimine las partes del nombre de host una por una y consulte el DNS hasta que encuentre un registro MX. Ejemplo:

 super.duper.domain.co.uk => no MX record, proceed duper.domain.co.uk => no MX record, proceed domain.co.uk => MX record found! assume that's the domain 

Aquí hay un ejemplo en php:

 function getDomainWithMX($url) { //parse hostname from URL //http://www.example.co.uk/index.php => www.example.co.uk $urlParts = parse_url($url); if ($urlParts === false || empty($urlParts["host"])) throw new InvalidArgumentException("Malformed URL"); //find first partial name with MX record $hostnameParts = explode(".", $urlParts["host"]); do { $hostname = implode(".", $hostnameParts); if (checkdnsrr($hostname, "MX")) return $hostname; } while (array_shift($hostnameParts) !== null); throw new DomainException("No MX record found"); } 

Acabo de escribir un progtwig para esto en clojure basado en la información de publicsuffix.org:

https://github.com/isaksky/url_dom

Por ejemplo:

 (parse "sub1.sub2.domain.co.uk") ;=> {:public-suffix "co.uk", :domain "domain.co.uk", :rule-used "*.uk"} 

Para una biblioteca de C (con generación de tabla de datos en Python), escribí http://code.google.com/p/domain-registry-provider/ que es rápido y eficiente desde el punto de vista del espacio.

La biblioteca usa ~ 30kB para las tablas de datos y ~ 10kB para el código C. No hay sobrecarga de inicio ya que las tablas se construyen en tiempo de comstackción. Consulte http://code.google.com/p/domain-registry-provider/wiki/DesignDoc para obtener más detalles.

Para comprender mejor el código de generación de tablas (Python), comience aquí: http://code.google.com/p/domain-registry-provider/source/browse/trunk/src/registry_tables_generator/registry_tables_generator.py

Para comprender mejor la API C, consulte: http://code.google.com/p/domain-registry-provider/source/browse/trunk/src/domain_registry/domain_registry.h

Como ya se dijo, la Lista de sufijos públicos es solo una forma de analizar correctamente el dominio. Para PHP puedes probar TLDExtract . Aquí hay un código de muestra:

 $extract = new LayerShifter\TLDExtract\Extract(); $result = $extract->parse('super.duper.domain.co.uk'); $result->getSubdomain(); // will return (string) 'super.duper' $result->getSubdomains(); // will return (array) ['super', 'duper'] $result->getHostname(); // will return (string) 'domain' $result->getSuffix(); // will return (string) 'co.uk' 

No está funcionando exactamente, pero tal vez puedas obtener una respuesta útil al intentar buscar el dominio pieza por pieza y verificar la respuesta, es decir, buscar ‘ http: // uk ‘, luego ‘ http://co.uk ‘ , luego ‘ http://dominio.com ‘. Cuando obtiene una respuesta sin errores, obtiene el dominio y el rest es subdominio.

A veces tienes que intentarlo 🙂

Editar:

Tom Leys señala en los comentarios que algunos dominios están configurados solo en el subdominio www, lo que nos daría una respuesta incorrecta en la prueba anterior. ¡Buen punto! Tal vez el mejor enfoque sería verificar cada parte con ‘ http: // www ‘ y ‘http: //’, y contar un golpe como un acierto para esa sección del nombre de dominio? Aún nos faltan algunos arreglos ‘alternativos’ como ‘web.domain.com’, pero no me he encontrado con ninguno de ellos por un tiempo 🙂

Utilice el URIBuilder y luego obtenga el atributo URIBUilder.host dividido en una matriz en “.” ahora tiene una matriz con el dominio dividido.

 echo tld('http://www.example.co.uk/test?123'); // co.uk /** * http://publicsuffix.org/ * http://www.alandix.com/blog/code/public-suffix/ * http://tobyinkster.co.uk/blog/2007/07/19/php-domain-class/ */ function tld($url_or_domain = null) { $domain = $url_or_domain ?: $_SERVER['HTTP_HOST']; preg_match('/^[az]+:\/\//i', $domain) and $domain = parse_url($domain, PHP_URL_HOST); $domain = mb_strtolower($domain, 'UTF-8'); if (strpos($domain, '.') === false) return null; $url = 'http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1'; if (($rules = file($url)) !== false) { $rules = array_filter(array_map('trim', $rules)); array_walk($rules, function($v, $k) use(&$rules) { if (strpos($v, '//') !== false) unset($rules[$k]); }); $segments = ''; foreach (array_reverse(explode('.', $domain)) as $s) { $wildcard = rtrim('*.'.$segments, '.'); $segments = rtrim($s.'.'.$segments, '.'); if (in_array('!'.$segments, $rules)) { $tld = substr($wildcard, 2); break; } elseif (in_array($wildcard, $rules) or in_array($segments, $rules)) { $tld = $segments; } } if (isset($tld)) return $tld; } return false; } 

Acabo de escribir una biblioteca objc: https://github.com/kejinlu/KKDomain

Puede utilizar esta API lib tld.js: JavaScript para trabajar contra nombres de dominio complejos, subdominios y URI.

 tldjs.getDomain('mail.google.co.uk'); // -> 'google.co.uk' 

Si obtiene el dominio raíz en el navegador. Puede usar esta lib AngusFu / browser-root-domain .

 var KEY = '__rT_dM__' + (+new Date()); var R = new RegExp('(^|;)\\s*' + KEY + '=1'); var Y1970 = (new Date(0)).toUTCString(); module.exports = function getRootDomain() { var domain = document.domain || location.hostname; var list = domain.split('.'); var len = list.length; var temp = ''; var temp2 = ''; while (len--) { temp = list.slice(len).join('.'); temp2 = KEY + '=1;domain=.' + temp; // try to set cookie document.cookie = temp2; if (R.test(document.cookie)) { // clear document.cookie = temp2 + ';expires=' + Y1970; return temp; } } }; 

Usar cookies es complicado.

Lista de sufijos comunes (.co.uk, .com, etcétera) para eliminar junto con http: // y solo tendrá “sub.domain” para trabajar en lugar de ” http: // sub”. domain.suffix “, o al menos eso es lo que probablemente haría.

El mayor problema es la lista de posibles sufijos. Hay mucho, después de todo.

Tras echar un rápido vistazo a la lista publicsuffix.org, parece que puede hacer una aproximación razonable eliminando los tres segmentos finales (“segmento”, que significa una sección entre dos puntos) de dominios donde el segmento final tiene dos caracteres de longitud, en el supuesto de que es un código de país y se subdividirá aún más. Si el segmento final es “nosotros” y el penúltimo segmento también tiene dos caracteres, elimine los últimos cuatro segmentos. En todos los demás casos, elimine los dos segmentos finales. p.ej:

  • http: //www.domain.example

“ejemplo” no son dos caracteres, por lo tanto, elimine “domain.example”, dejando “www”

  • http: //super.duper.domain.example

“ejemplo” no son dos caracteres, por lo tanto, elimine “domain.example”, dejando “super.duper”

“uk” es dos caracteres (pero no “nosotros”), por lo tanto, elimine “domain.co.uk”, dejando “super.duper”

“nosotros” son dos caracteres y es “nosotros”, más “wy” también son dos caracteres, por lo tanto, elimine “pvt.k12.wy.us”, dejando “foo”.

Tenga en cuenta que, aunque esto funciona para todos los ejemplos que he visto en las respuestas hasta el momento, sigue siendo solo una aproximación razonable. No es del todo correcto, aunque sospecho que es lo más parecido posible sin hacer / obtener una lista real para usar como referencia.