Obtener entrada DNS raíz del servidor PHP; obtener el nombre de dominio sin www, etc.

StackOverflow https://stackoverflow.com/questions/1375647

  •  21-09-2019
  •  | 
  •  

Pregunta

¿Cómo se podría conseguir la entrada DNS raíz de $_SERVER['HTTP_HOST']?

Entrada:

example.co.uk
www.example.com
blog.example.com
forum.example.co.uk 

Salida:

example.co.uk
example.com
example.com
example.co.uk

EDIT: lista de búsqueda es muy largo

¿Fue útil?

Solución

Para este proyecto: http://drupal.org/project/parallel

Uso:

echo parallel_get_domain("www.robknight.org.uk") . "<br>";
echo parallel_get_domain("www.google.com") . "<br>";
echo parallel_get_domain("www.yahoo.com") . "<br>";

Funciones:

/**
 * Given host name returns top domain.
 *
 * @param $host
 *   String containing the host name: www.example.com
 *
 * @return string
 *   top domain: example.com
 */
function parallel_get_domain($host) {
  if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN' && strnatcmp(phpversion(),'5.3.0') < 0) {
    // This works 1/2 the time... CNAME doesn't work with nslookup
    for ($end_pieces = substr_count($host, '.'); $end_pieces > 0; $end_pieces--) {
      $test_domain = end(explode('.', $host, $end_pieces));
      if (checkdnsrr($test_domain)) {
          $domain = $test_domain;
          break;
      }
    }
    return isset($domain) ? $domain : FALSE;
  }
  else {
    // This always works
    $sections = explode('.', $host);
    array_unshift($sections, '');
    foreach($sections as $key => $value) {
      $parts[$key] = $value;
      $test_domain = implode('.', parallel_array_xor($parts, $sections));
      if (checkdnsrr($test_domain, 'NS') && !checkdnsrr($test_domain, 'CNAME')) {
        $domain = $test_domain;
        break;
      }
    }
    return isset($domain) ? $domain : FALSE;
  }
}

/**
 * Opposite of array_intersect().
 *
 * @param $array_a
 *   First array
 * @param $array_b
 *   Second array
 *
 * @return array
 */
function parallel_array_xor ($array_a, $array_b) {
  $union_array = array_merge($array_a, $array_b);
  $intersect_array = array_intersect($array_a, $array_b);
  return array_diff($union_array, $intersect_array);
}

/**
 * Win compatible version of checkdnsrr.
 *
 * checkdnsrr() support for Windows by HM2K <php [spat] hm2k.org>
 * http://us2.php.net/manual/en/function.checkdnsrr.php#88301
 *
 * @param $host
 *   String containing host name
 * @param $type
 *   String containing the DNS record type
 *
 * @return bool
 */
function parallel_win_checkdnsrr($host, $type='MX') {
  if (strtoupper(substr(PHP_OS, 0, 3)) != 'WIN') { return FALSE; }
  if (empty($host)) { return FALSE; }
  $types=array('A', 'MX', 'NS', 'SOA', 'PTR', 'CNAME', 'AAAA', 'A6', 'SRV', 'NAPTR', 'TXT', 'ANY');
  if (!in_array($type, $types)) {
    user_error("checkdnsrr() Type '$type' not supported", E_USER_WARNING);
    return FALSE;
  }
  @exec('nslookup -type=' . $type . ' ' . escapeshellcmd($host), $output);

  foreach($output as $line){
    if (preg_match('/^' . $host . '/', $line)) { return TRUE; }
  }
}

// Define checkdnsrr() if it doesn't exist
if (!function_exists('checkdnsrr')) {
  function checkdnsrr($host, $type='MX') {
    return parallel_win_checkdnsrr($host, $type);
  }
}

Salida - Windows:

org.uk
google.com
yahoo.com

Salida - Linux:

robknight.org.uk
google.com
yahoo.com

Otros consejos

Creo que es un poco mal definido.

Usted podría intentar hacer búsquedas de DNS para cada registro padre hasta que encuentre uno que no devuelve un registro.

/[^\.]+\.[escaped|list|of|domains]$/

Creo que debería funcionar.

A medida que has descubierto, algunos países utilizan un TLD solamente (ejemplo: .tv, .us), otros se subdividen a su país dominio de nivel superior (ejemplo: Reino Unido).

Lo ideal es que necesita una lista de búsqueda (que no pasará mucho tiempo) de TLD aprobados, y, si es subdividido, el TLD con cada subdivisión (por ejemplo, ".es" en lugar de ".uk") . Eso le dirá qué "puntos" (desde la derecha) para mantener. A continuación, pasar un punto a la izquierda de que (si se encuentra) y picar todo antes de él.

Sin una lista de búsqueda, se puede explotar el hecho de que las subdivisiones (.co, etc.) son sólo para los países (que tienen 2 letras TLD) y son yo sepa nunca más de 3 caracteres ellos mismos y son siempre las cartas, por lo es probable que se les puede reconocer con un patrón de expresión.

Editar No importa, la lista real de sufijos públicas es mucho más compleja. Vas a tener que utilizar una tabla de búsqueda para averiguar lo que el sufijo está, volver al punto anterior, y el asiento izquierdo. RegEx es una mala solución aquí. En su lugar, almacenar la lista de sufijos en un diccionario, entonces prueba en contra de su nombre de dominio, la poda de una porción de puntos a la vez desde la izquierda hasta llegar a un partido, a continuación, añadir de nuevo la parte que acaba recorta.

Nota: como se ha señalado en los comentarios, este método no funciona realmente en todos los casos. La razón de esto es que algunos dominios de nivel superior no se resuelven a direcciones IP, aunque la mayoría no. Por lo tanto, no es posible detectar si un nombre de pila es de nivel superior o nombre de dominio de nivel superior seudo simplemente comprobando si tiene una dirección IP. Por desgracia, esto probablemente significa que la única solución es una lista de búsqueda, teniendo en cuenta lo dominios de nivel superior son tratados inconsistente en la práctica.

repito: no se basan en el código de abajo a trabajar para usted. Lo dejo aquí sólo con fines educativos.

Hay una manera de hacer esto sin una lista de búsqueda. La lista puede ser poco fiable o incompleta, mientras que se garantiza que este método funcione:

<?php

function get_domain($url) {
    $dots = substr_count($url, '.');
    $domain = '';

    for ($end_pieces = $dots; $end_pieces > 0; $end_pieces--) {
        $test_domain = end(explode('.', $url, $end_pieces));

        if (dns_check_record($test_domain, 'A')) {
            $domain = $test_domain;
            break;
        }
    }

    return $domain;
}

$my_domain = get_domain('www.robknight.org.uk');

echo $my_domain;

?>

En este caso, se dará salida a 'robknight.org.uk'. Que funcionaría igual de bien para .com, .edu, .com.au, .ly o cualquier otro dominio de nivel superior que está operando en.

Funciona a partir de la derecha y hacer una verificación de DNS en la primera cosa que parece que podría ser un nombre de dominio viable. En el ejemplo anterior, se inicia con 'org.uk', pero descubre que este no es un nombre de dominio real, pero es un ccTLD. A continuación se pasa a comprobar 'robknight.org.uk', que es válida, y devuelve eso. Si el nombre de dominio había sido, digamos, 'www.php.net', habría comenzado marcando 'php.net', que es un nombre de dominio válido, y que habría regresado inmediatamente sin bucle. También debo señalar que si no se encuentra un nombre de dominio válido, se devuelve una cadena vacía ( '').

Este código puede ser inadecuado para el procesamiento de un gran número de nombres de dominio en un corto espacio de tiempo debido al tiempo necesario para que las búsquedas de DNS, pero es perfectamente bien para las búsquedas individuales o código que no es en tiempo crítico.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top