从 php 服务器获取根 DNS 条目;获取不带www等的域名

发布于 2024-08-03 14:58:07 字数 405 浏览 3 评论 0原文

如何从 $_SERVER['HTTP_HOST'] 获取根 DNS 条目?

输入:

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

输出:

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

编辑: 查找列表很长

How would one get the root DNS entry from $_SERVER['HTTP_HOST']?

Input:

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

Output:

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

EDIT:
Lookup list is very long

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

固执像三岁 2024-08-10 14:58:07

对于此项目: http://drupal.org/project/parallel

用法:

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

功能:

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

输出 - Windows :

org.uk
google.com
yahoo.com

输出 - Linux:

robknight.org.uk
google.com
yahoo.com

For this project: http://drupal.org/project/parallel

Usage:

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

Functions:

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

Output - Windows:

org.uk
google.com
yahoo.com

Output - Linux:

robknight.org.uk
google.com
yahoo.com
蓝天 2024-08-10 14:58:07

我认为这有点不明确。

您可以尝试对每条父记录进行 DNS 查找,直到找到不返回 A 记录的记录。

I think that's a bit ill-defined.

You could try doing DNS lookups for each parent record until you find one that doesn't return an A record.

时光无声 2024-08-10 14:58:07
/[^\.]+\.[escaped|list|of|domains]$/

我认为这应该有效。

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

I think that should work.

星光不落少年眉 2024-08-10 14:58:07

正如您所发现的,一些国家/地区仅使用 TLD(例如:.tv、.us),其他国家/地区则细分其国家/地区 TLD(例如:uk)。

理想情况下,您需要一份已批准 TLD 的查找列表(不会很长),并且如果进行细分,还需要每个细分的 TLD(例如,“.co.uk”而不是“.uk”)。这会告诉您要保留哪些“点”(从右侧开始)。然后向其左侧移动一个点(如果找到)并砍掉它之前的所有内容。

如果没有查找列表,您可以利用以下事实:细分(.co 等)仅适用于国家/地区(具有 2 个字母的 TLD),并且据我所知,它们本身永远不会超过 3 个字符,并且始终是字母,因此您可以使用正则表达式模式识别它们。

编辑:没关系,公共后缀的实际列表要复杂得多。您将需要使用查找表来找出后缀是什么,返回到上一个点,然后向左修剪。正则表达式在这里是一个糟糕的解决方案。相反,将后缀列表存储在字典中,然后针对您的域名进行测试,从左侧一次删除一个点部分,直到找到匹配项,然后添加回刚刚删除的部分。

As you've discovered, some countries use a TLD only (example: .tv, .us), others subdivide their country TLD (example: uk).

Ideally, you'll need a lookup list (it won't be long) of approved TLDs, and, if subdivided, the TLD with each subdivision (e.g., ".co.uk" instead of ".uk"). That will tell you which "dots" (from the right) to keep. Then move one dot to the left of that (if found) and chop everything before it.

Without a lookup list, you can exploit the fact that the subdivisions (.co, etc.) are only for countries (which have 2-letter TLDs) and are AFAIK never more than 3 characters themselves and are always letters, so you can probably recognize them with a regex pattern.

Edit: Nevermind, the actual list of public suffixes is much more complex. You're going to need to use a lookup table to figure out what the suffix is, go back to the previous dot, and trim left. RegEx is a poor solution here. Instead, store the list of suffixes in a Dictionary, then test against your domain name, lopping off one dotted portion at a time from the left until you hit a match, then add back the part you just trimmed off.

执手闯天涯 2024-08-10 14:58:07

注意:正如评论中所指出的,此方法实际上并不适用于所有情况。其原因是某些顶级域确实解析为 IP 地址,即使大多数顶级域不解析。因此,仅仅通过检查一个给定的名称是否有IP地址是不可能检测它是否是顶级域名或伪顶级域名。不幸的是,这可能意味着唯一的解决方案是查找列表,因为实践中顶级域的处理方式不一致。

我再说一遍:不要依赖下面的代码为你工作。我将其留在这里仅用于教育目的。

有一种方法可以在不使用查找列表的情况下执行此操作。该列表可能不可靠或不完整,但此方法保证有效:

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

?>

在这种情况下,它将输出“robknight.org.uk”。它同样适用于 .com、.edu、.com.au、.ly 或您正在操作的任何其他顶级域。

它的工作原理是从右侧开始,对第一个看起来可能是可行的域名进行 DNS 检查。在上面的示例中,它以“org.uk”开头,但发现这不是一个实际的域名,而是一个 ccTLD。然后它继续检查“robknight.org.uk”,它有效,并返回该结果。如果域名是“www.php.net”,那么它将首先检查“php.net”(这是一个有效的域名),并且会立即返回该域名而不循环。我还应该指出,如果没有找到有效的域名,将返回一个空字符串('')。

由于 DNS 查找所需的时间,此代码可能不适合在短时间内处理大量域名,但对于单次查找或时间要求不严格的代码来说,它完全没问题。

Note: as pointed out in the comments, this method doesn't actually work in all cases. The reason for this is that some top-level domains do resolve to IP addresses, even if most do not. Therefore it's not possible to detect if a given name is top-level or pseudo-top-level domain name merely by checking if it has an IP address. Unfortunately, this probably means that the only solution is a lookup list, given how inconsistently treated top-level domains are in practice.

I repeat: do not rely on the code below to work for you. I leave it here for educational purposes only.

There is a way to do this without a lookup list. The list may be unreliable or incomplete, whereas this method is guaranteed to work:

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

?>

In this case, it will output 'robknight.org.uk'. It would work equally well for .com, .edu, .com.au, .ly or whatever other top-level domain you're operating on.

It works by starting from the right and doing a DNS check on the first thing that looks like it might be a viable domain name. In the example above, it starts with 'org.uk', but discovers that this is not an actual domain name, but is a ccTLD. It then moves on to check 'robknight.org.uk', which is valid, and returns that. If the domain name had been, say, 'www.php.net', it would have started by checking 'php.net', which is a valid domain name, and would have returned that immediately without looping. I should also point out that if no valid domain name is found, an empty string ('') will be returned.

This code may be unsuitable for processing a large number of domain names in a short space of time due to the time taken for DNS lookups, but it's perfectly fine for single lookups or code that isn't time-critical.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文