php regex domain-name

Obtener el nombre de dominio(no el subdominio) en php



regex domain-name (11)

Aquí hay una función que escribí para obtener el dominio sin subdominio (s), independientemente de si el dominio usa un ccTLD o un nuevo estilo de TLD largo, etc. No hay búsqueda ni una gran variedad de TLD conocidos, y no hay expresiones regulares. . Puede ser mucho más corto usando el operador ternario y el anidamiento, pero lo amplié para facilitar la lectura.

// Per Wikipedia: "All ASCII ccTLD identifiers are two letters long, // and all two-letter top-level domains are ccTLDs." function topDomainFromURL($url) { $url_parts = parse_url($url); $domain_parts = explode(''.'', $url_parts[''host'']); if (strlen(end($domain_parts)) == 2 ) { // ccTLD here, get last three parts $top_domain_parts = array_slice($domain_parts, -3); } else { $top_domain_parts = array_slice($domain_parts, -2); } $top_domain = implode(''.'', $top_domain_parts); return $top_domain; }

Tengo una URL que puede ser cualquiera de los siguientes formatos:

http://example.com https://example.com http://example.com/foo http://example.com/foo/bar www.example.com example.com foo.example.com www.foo.example.com foo.bar.example.com http://foo.bar.example.com/foo/bar example.net/foo/bar

Esencialmente, necesito poder hacer coincidir cualquier URL normal. ¿Cómo puedo extraer example.com (o .net, sea lo que sea el tld. Necesito que funcione con cualquier TLD) de todos estos a través de una sola expresión regular?


Aquí hay uno que funciona para todos los dominios, incluidos aquellos con dominios de segundo nivel como "co.uk"

function strip_subdomains($url){ # credits to gavingmiller for maintaining this list $second_level_domains = file_get_contents("https://raw.githubusercontent.com/gavingmiller/second-level-domains/master/SLDs.csv"); # presume sld first ... $possible_sld = implode(''.'', array_slice(explode(''.'', $url), -2)); # and then verify it if (strpos($second_level_domains, $possible_sld)){ return implode(''.'', array_slice(explode(''.'', $url), -3)); } else { return implode(''.'', array_slice(explode(''.'', $url), -2)); } }

Parece que hay una pregunta duplicada aquí: delete-subdomain-from-url-string-if-subdomain-is-found


Bueno, puedes usar parse_url para obtener el host:

$info = parse_url($url); $host = $info[''host''];

Entonces, puedes hacer algunas cosas elegantes para obtener solo el TLD y el Anfitrión

$host_names = explode(".", $host); $bottom_host_name = $host_names[count($host_names)-2] . "." . $host_names[count($host_names)-1];

No es muy elegante, pero debería funcionar.

Si quieres una explicación, aquí va:

Primero tomamos todo entre el esquema ( http:// , etc), usando las capacidades de parse_url para ... bueno ... analizar las URL. :)

Luego tomamos el nombre de host y lo separamos en una matriz en función de dónde caen los períodos, por lo que test.world.hello.myname se convertiría en:

array("test", "world", "hello", "myname");

Después de eso, tomamos la cantidad de elementos en la matriz (4).

Luego, restamos 2 de él para obtener la penúltima cadena (el nombre de host, o example , en su ejemplo)

Luego, restamos 1 de él para obtener la última cadena (porque las teclas de matriz comienzan en 0), también conocido como TLD

Luego combinamos esas dos partes con un punto, y usted tiene su nombre de host base.


Creo que la mejor manera de manejar este problema es:

$second_level_domains_regex = ''//.asn/.au$|/.com/.au$|/.net/.au$|/.id/.au$|/.org/.au$|/.edu/.au$|/.gov/.au$|/.csiro/.au$|/.act/.au$|/.nsw/.au$|/.nt/.au$|/.qld/.au$|/.sa/.au$|/.tas/.au$|/.vic/.au$|/.wa/.au$|/.co/.at$|/.or/.at$|/.priv/.at$|/.ac/.at$|/.avocat/.fr$|/.aeroport/.fr$|/.veterinaire/.fr$|/.co/.hu$|/.film/.hu$|/.lakas/.hu$|/.ingatlan/.hu$|/.sport/.hu$|/.hotel/.hu$|/.ac/.nz$|/.co/.nz$|/.geek/.nz$|/.gen/.nz$|/.kiwi/.nz$|/.maori/.nz$|/.net/.nz$|/.org/.nz$|/.school/.nz$|/.cri/.nz$|/.govt/.nz$|/.health/.nz$|/.iwi/.nz$|/.mil/.nz$|/.parliament/.nz$|/.ac/.za$|/.gov/.za$|/.law/.za$|/.mil/.za$|/.nom/.za$|/.school/.za$|/.net/.za$|/.co/.uk$|/.org/.uk$|/.me/.uk$|/.ltd/.uk$|/.plc/.uk$|/.net/.uk$|/.sch/.uk$|/.ac/.uk$|/.gov/.uk$|/.mod/.uk$|/.mil/.uk$|/.nhs/.uk$|/.police/.uk$/''; $domain = $_SERVER[''HTTP_HOST'']; $domain = explode(''.'', $domain); $domain = array_reverse($domain); if (preg_match($second_level_domains_regex, $_SERVER[''HTTP_HOST'']) { $domain = "$domain[2].$domain[1].$domain[0]"; } else { $domain = "$domain[1].$domain[0]"; }


Hay dos formas de extraer el subdominio de un host:

  1. El primer método que es más preciso es usar una base de datos de tlds (como https://publicsuffix.org/list/public_suffix_list.dat ) y hacer coincidir el dominio con ella. Esto es un poco pesado en algunos casos. Hay algunas clases de PHP para usarlo como php-domain-parser y TLDExtract .

  2. La segunda forma no es tan precisa como la primera, pero es muy rápida y puede dar la respuesta correcta en muchos casos, escribí esta función para ello:

    function get_domaininfo($url) { // regex can be replaced with parse_url preg_match("/^(https|http|ftp):////(.*?)///", "$url/" , $matches); $parts = explode(".", $matches[2]); $tld = array_pop($parts); $host = array_pop($parts); if ( strlen($tld) == 2 && strlen($host) <= 3 ) { $tld = "$host.$tld"; $host = array_pop($parts); } return array( ''protocol'' => $matches[1], ''subdomain'' => implode(".", $parts), ''domain'' => "$host.$tld", ''host''=>$host,''tld''=>$tld ); }

    Ejemplo:

    print_r(get_domaininfo(''http://mysubdomain.domain.co.uk/index.php''));

    Devoluciones:

    Array ( [protocol] => https [subdomain] => mysubdomain [domain] => domain.co.uk [host] => domain [tld] => co.uk )


Mi solución en https://gist.github.com/pocesar/5366899

y las pruebas están aquí http://codepad.viper-7.com/GAh1tP

Funciona con cualquier TLD y patrones de subdominio horribles (hasta 3 subdominios).

Hay una prueba incluida con muchos nombres de dominio.

No pegará la función aquí debido a la sangría extraña para el código en (podría tener bloques de código cercados como github)


No es posible obtener el nombre de dominio sin utilizar una lista de TLD para comparar, ya que existen muchos casos con la misma estructura y longitud:

  1. www.db.de (Subdominio) versus bbc.co.uk (Dominio)
  2. big.uk.com (SLD) versus www.uk.com (TLD)

La lista de sufijos públicos de Mozilla debería ser la mejor opción, ya que es utilizada por todos los principales navegadores :
https://publicsuffix.org/list/public_suffix_list.dat

Siéntase libre de usar mi función:

function tld_list($cache_dir=null) { // we use "/tmp" if $cache_dir is not set $cache_dir = isset($cache_dir) ? $cache_dir : sys_get_temp_dir(); $lock_dir = $cache_dir . ''/public_suffix_list_lock/''; $list_dir = $cache_dir . ''/public_suffix_list/''; // refresh list all 30 days if (file_exists($list_dir) && @filemtime($list_dir) + 2592000 > time()) { return $list_dir; } // use exclusive lock to avoid race conditions if (!file_exists($lock_dir) && @mkdir($lock_dir)) { // read from source $list = @fopen(''https://publicsuffix.org/list/public_suffix_list.dat'', ''r''); if ($list) { // the list is older than 30 days so delete everything first if (file_exists($list_dir)) { foreach (glob($list_dir . ''*'') as $filename) { unlink($filename); } rmdir($list_dir); } // now set list directory with new timestamp mkdir($list_dir); // read line-by-line to avoid high memory usage while ($line = fgets($list)) { // skip comments and empty lines if ($line[0] == ''/'' || !$line) { continue; } // remove wildcard if ($line[0] . $line[1] == ''*.'') { $line = substr($line, 2); } // remove exclamation mark if ($line[0] == ''!'') { $line = substr($line, 1); } // reverse TLD and remove linebreak $line = implode(''.'', array_reverse(explode(''.'', (trim($line))))); // we split the TLD list to reduce memory usage touch($list_dir . $line); } fclose($list); } @rmdir($lock_dir); } // repair locks (should never happen) if (file_exists($lock_dir) && mt_rand(0, 100) == 0 && @filemtime($lock_dir) + 86400 < time()) { @rmdir($lock_dir); } return $list_dir; } function get_domain($url=null) { // obtain location of public suffix list $tld_dir = tld_list(); // no url = our own host $url = isset($url) ? $url : $_SERVER[''SERVER_NAME'']; // add missing scheme ftp:// http:// ftps:// https:// $url = !isset($url[5]) || ($url[3] != '':'' && $url[4] != '':'' && $url[5] != '':'') ? ''http://'' . $url : $url; // remove "/path/file.html", "/:80", etc. $url = parse_url($url, PHP_URL_HOST); // replace absolute domain name by relative (http://www.dns-sd.org/TrailingDotsInDomainNames.html) $url = trim($url, ''.''); // check if TLD exists $url = explode(''.'', $url); $parts = array_reverse($url); foreach ($parts as $key => $part) { $tld = implode(''.'', $parts); if (file_exists($tld_dir . $tld)) { return !$key ? '''' : implode(''.'', array_slice($url, $key - 1)); } // remove last part array_pop($parts); } return ''''; }

Lo que hace especial:

  • acepta todas las entradas como URL, nombres de host o dominios con o sin esquema
  • la lista se descarga fila por fila para evitar el alto uso de memoria
  • crea un nuevo archivo por TLD en una carpeta de caché, por lo que get_domain() solo necesita verificar a través de file_exists() si existe, por lo que no necesita incluir una gran base de datos en cada solicitud como TLDExtract hace.
  • la lista se actualizará automáticamente cada 30 días

Prueba:

$urls = array( ''http://www.example.com'',// example.com ''http://subdomain.example.com'',// example.com ''http://www.example.uk.com'',// example.uk.com ''http://www.example.co.uk'',// example.co.uk ''http://www.example.com.ac'',// example.com.ac ''http://example.com.ac'',// example.com.ac ''http://www.example.accident-prevention.aero'',// example.accident-prevention.aero ''http://www.example.sub.ar'',// sub.ar ''http://www.congresodelalengua3.ar'',// congresodelalengua3.ar ''http://congresodelalengua3.ar'',// congresodelalengua3.ar ''http://www.example.pvt.k12.ma.us'',// example.pvt.k12.ma.us ''http://www.example.lib.wy.us'',// example.lib.wy.us ''com'',// empty ''.com'',// empty ''http://big.uk.com'',// big.uk.com ''uk.com'',// empty ''www.uk.com'',// www.uk.com ''.uk.com'',// empty ''.com'',// .com ''.foobarfoo'',// empty '''',// empty false,// empty '' '',// empty 1,// empty ''a'',// empty );

Versión reciente con explicaciones (alemán):
http://www.programmierer-forum.de/domainnamen-ermitteln-t244185.htm


Recomiendo usar la biblioteca TLDExtract para todas las operaciones con nombre de dominio.


Simplemente prueba esto:

<?php $host = $_SERVER[''HTTP_HOST'']; preg_match("/[^/.//]+/.[^/.//]+$/", $host, $matches); echo "domain name is: {$matches[0]}/n"; ?>


Tuve problemas con la solución proporcionada por pocesar. Cuando usaría, por ejemplo, subdomain.domain.nl, no devolvería domain.nl. En cambio, devolvería subdomain.domain.nl Otro problema era que domain.com.br devolvería com.br

No estoy seguro pero solucioné estos problemas con el siguiente código (espero que ayude a alguien, si es así soy un hombre feliz):

function get_domain($domain, $debug = false){ $original = $domain = strtolower($domain); if (filter_var($domain, FILTER_VALIDATE_IP)) { return $domain; } $debug ? print(''<strong style="color:green">&raquo;</strong> Parsing: ''.$original) : false; $arr = array_slice(array_filter(explode(''.'', $domain, 4), function($value){ return $value !== ''www''; }), 0); //rebuild array indexes if (count($arr) > 2){ $count = count($arr); $_sub = explode(''.'', $count === 4 ? $arr[3] : $arr[2]); $debug ? print(" (parts count: {$count})") : false; if (count($_sub) === 2){ // two level TLD $removed = array_shift($arr); if ($count === 4){ // got a subdomain acting as a domain $removed = array_shift($arr); } $debug ? print("<br>/n" . ''[*] Two level TLD: <strong>'' . join(''.'', $_sub) . ''</strong> '') : false; }elseif (count($_sub) === 1){ // one level TLD $removed = array_shift($arr); //remove the subdomain if (strlen($arr[0]) === 2 && $count === 3){ // TLD domain must be 2 letters array_unshift($arr, $removed); }elseif(strlen($arr[0]) === 3 && $count === 3){ array_unshift($arr, $removed); }else{ // non country TLD according to IANA $tlds = array( ''aero'', ''arpa'', ''asia'', ''biz'', ''cat'', ''com'', ''coop'', ''edu'', ''gov'', ''info'', ''jobs'', ''mil'', ''mobi'', ''museum'', ''name'', ''net'', ''org'', ''post'', ''pro'', ''tel'', ''travel'', ''xxx'', ); if (count($arr) > 2 && in_array($_sub[0], $tlds) !== false){ //special TLD don''t have a country array_shift($arr); } } $debug ? print("<br>/n" .''[*] One level TLD: <strong>''.join(''.'', $_sub).''</strong> '') : false; }else{ // more than 3 levels, something is wrong for ($i = count($_sub); $i > 1; $i--){ $removed = array_shift($arr); } $debug ? print("<br>/n" . ''[*] Three level TLD: <strong>'' . join(''.'', $_sub) . ''</strong> '') : false; } }elseif (count($arr) === 2){ $arr0 = array_shift($arr); if (strpos(join(''.'', $arr), ''.'') === false && in_array($arr[0], array(''localhost'',''test'',''invalid'')) === false){ // not a reserved domain $debug ? print("<br>/n" .''Seems invalid domain: <strong>''.join(''.'', $arr).''</strong> re-adding: <strong>''.$arr0.''</strong> '') : false; // seems invalid domain, restore it array_unshift($arr, $arr0); } } $debug ? print("<br>/n".''<strong style="color:gray">&laquo;</strong> Done parsing: <span style="color:red">'' . $original . ''</span> as <span style="color:blue">''. join(''.'', $arr) ."</span><br>/n") : false; return join(''.'', $arr); }


$onlyHostName = implode(''.'', array_slice(explode(''.'', parse_url($link, PHP_URL_HOST)), -2));