Obtenha a entrada ROOT DNS do servidor PHP; Obtenha o nome de domínio sem www, etc.

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

  •  21-09-2019
  •  | 
  •  

Pergunta

Como se conseguiria a entrada do DNS raiz de $_SERVER['HTTP_HOST']?

Entrada:

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

Resultado:

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

Editar: a lista de pesquisa é muito longo

Foi útil?

Solução

Para este projeto: 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>";

Funções:

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

Saída - Windows:

org.uk
google.com
yahoo.com

Saída - Linux:

robknight.org.uk
google.com
yahoo.com

Outras dicas

Eu acho que isso é um pouco mal definido.

Você pode tentar fazer pesquisas do DNS para cada registro dos pais até encontrar um que não retorne um registro A.

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

Acho que deve funcionar.

Como você descobriu, alguns países usam apenas um TLD (exemplo: .tv, .us), outros subdividem seu país TLD (Exemplo: Reino Unido).

Idealmente, você precisará de uma lista de pesquisa (não será longa) dos TLDs aprovados e, se subdividido, o TLD com cada subdivisão (por exemplo, ".co.uk" em vez de ".uk"). Isso lhe dirá quais "pontos" (da direita) para manter. Em seguida, mova um ponto à esquerda disso (se encontrado) e pique tudo antes dele.

Sem uma lista de pesquisa, você pode explorar o fato de que as subdivisões (.co, etc.) são apenas para países (que têm TLDs de 2 letras) e são afaik nunca mais que três caracteres e sempre são letras, então você provavelmente pode reconheça -os com um padrão regex.

Editar: Especialmente, a lista real de sufixos públicos é muito mais complexa. Você precisará usar uma tabela de pesquisa para descobrir qual é o sufixo, voltar ao ponto anterior e aparar à esquerda. Regex é uma solução ruim aqui. Em vez disso, armazene a lista de sufixos em um dicionário e teste seu nome de domínio, inclinando uma parte pontilhada de cada vez da esquerda até chegar a uma partida e adicione a parte que acabou de aparar.

Nota: Como apontado nos comentários, esse método não funciona em todos os casos. A razão para isso é que alguns domínios de nível superior resolvem os endereços IP, mesmo que a maioria não. Portanto, não é possível detectar se um determinado nome é o nome de domínio de nível superior ou pseudo-top, apenas verificando se ele tiver um endereço IP. Infelizmente, isso provavelmente significa que a única solução é uma lista de pesquisa, dado que os domínios de nível superior tratados inconsistentemente estão na prática.

Repito: não confie no código abaixo para funcionar para você. Deixo aqui apenas para fins educacionais.

Existe uma maneira de fazer isso sem uma lista de pesquisa. A lista pode não ser confiável ou incompleta, enquanto este método é garantido para funcionar:

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

?>

Nesse caso, ele produzirá 'robknight.org.uk'. Funcionaria igualmente bem para .com, .edu, .com.au, .ly ou qualquer outro domínio de nível superior em que você está operando.

Funciona começando da direita e fazendo uma verificação do DNS na primeira coisa que parece ser um nome de domínio viável. No exemplo acima, ele começa com 'org.uk', mas descobre que esse não é um nome de domínio real, mas é um CCTLD. Em seguida, segue para verificar 'robknight.org.uk', que é válido e retorna isso. Se o nome de domínio tivesse sido, digamos, 'www.php.net', teria começado verificando 'php.net', que é um nome de domínio válido, e teria retornado isso imediatamente sem loop. Devo também salientar que, se nenhum nome de domínio válido for encontrado, uma string vazia ('') será retornada.

Esse código pode ser inadequado para processar um grande número de nomes de domínio em um curto espaço de tempo devido ao tempo necessário para as pesquisas do DNS, mas é perfeitamente bom para pesquisas únicas ou código que não são críticos no tempo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top