PHP只从URL中提取主域而不是子域

时间:2011-11-03 12:56:25

标签: php

我在一个数组中有一组URL。有些只是域名(http://google.com),有些是子域名(http://test.google.com)。

我试图在没有子域的情况下从每个域中提取域部分。

parse_url($domain)

仍保留子域名。

还有其他办法吗?

3 个答案:

答案 0 :(得分:1)

如果您只关心实际的顶级域名,那么简单的答案就是在域名的最后一个点之前获取任何内容。

但是,如果您正在寻找“无论您从注册商处购买什么”,那就更加棘手了。 IANA授权每个国家/地区特定TLD授权给国家注册商,这意味着每个TLD的分配政策各不相同。着名的例子包括.co.uk,.org.uk等,但也有无数其他鲜为人知的(例如.priv.no)。

如果您需要一个能够针对现有的每个TLD正常运行的解决方案,您将需要研究每个TLD的政策,这是一项非常艰巨的任务,因为许多国家注册商都有可怕的网站,其政策不明确,只是为了制定它更加困惑,往往没有英文版。

但在实践中,您可能不需要考虑每个TLD或每个TLD中的每个可用子域。因此,一个实用的解决方案是编制一个您需要支持的已知的2部分(和更多)TLD列表。任何与该列表不匹配的内容,您都可以视为一部分TLD。像这样:

<?php
$special_domains = array('co.uk', 'org.uk, /* ... etc */');

function getDomain($domain)
{
    global $special_domains;

    for($i = 0; $i < count($special_domains); $i++)
    {
        if(substr($domain, -strlen($special_domains[i])) == $special_domains[i])
        {
            $domain = substr($domain, 0, -strlen($special_domains[i])));
            $lastdot = strrchr($domain, '.');

            return ($lastdot ? substr($domain, $lastdot) : $domain;
        }

        $domain = substr($domain, 0, strrchr($domain, "."));
        $lastdot = strrchr($domain, '.');

        return ($lastdot ? substr($domain, $lastdot) : $domain;
    }
}
?>

PS:我没有测试过这段代码所以可能需要进行一些修改,但基本逻辑应该没问题。

答案 1 :(得分:0)

.co.uk问题可能有解决办法。

我们假设如果可以注册* .co.uk,* .org.uk,* .mil.ae和类似的域名,那么就无法解析co.uk,org.uk的DNS和mil.ae.我查了一些网址,看起来确实如此。

然后你可以使用这样的东西:

$testdomains = array(
    'http://google.com',
    'http://probablynotexisting.com',
    'http://subdomain.bbc.co.uk', // should resolve into bbc.co.uk, because it is not possible to ping co.uk
    'http://bbc.co.uk'
);

foreach ($testdomains as $raw_domain) {

    $domain = join('.', array_slice(explode('.', parse_url($raw_domain, PHP_URL_HOST)), -2));

    $ip = gethostbyname($domain);

    if ($ip == $domain) {
        // failure, let's include another dot
        $domain = join('.', array_slice(explode('.', parse_url($raw_domain, PHP_URL_HOST)), -3));

        $ip = gethostbyname($domain);
        if ($ip == $domain) {
            // another failure, shall we give up and move on!
            echo $raw_domain . ": failed<br />\n";
            continue;
        }
    }

    echo $raw_domain . ' -> ' . $domain . ": ok [" . $ip . "]<br />\n";

}

输出如下:

http://google.com -> google.com: ok [72.14.204.147]
http://probablynotexisting.com: failed
http://subdomain.bbc.co.uk -> bbc.co.uk: ok [212.58.241.131]
http://bbc.co.uk -> bbc.co.uk: ok [212.58.241.131]

注意:解析DNS是一个缓慢的过程。

答案 2 :(得分:0)

让我们为你努力工作。从所讨论的子域/域的任何子域(不需要存在)的挖掘的AUTHORITY部分的第一个字段中提取所需的基础域。示例(在bash中不是php抱歉)...

dig @8.8.8.8 notexist.google.com|grep -A1 ';; AUTHORITY SECTION:'|tail -n1|sed "s/[[:space:]]\+/~/g"|cut -d'~' -f1
google.com.

dig @8.8.8.8 notexist.test.google.com|grep -A1 ';; AUTHORITY SECTION:'|tail -n1|sed "s/[[:space:]]\+/~/g"|cut -d'~' -f1
google.com.

dig @8.8.8.8 notexist.www.xn--zgb6acm.xn--mgberp4a5d4ar|grep -A1 ';; AUTHORITY SECTION:'|tail -n1|sed "s/[[:space:]]\+/~/g"|cut -d'~' -f1
xn--zgb6acm.xn--mgberp4a5d4ar.

其中

grep -A1过滤除了字符串;; AUTHORITY SECTION:以及后面的1行的所有行。

tail -n1只留下上述两行的最后一行。

sed "s/[[:space:]]\+/~/g"用一些自定义分隔符~替换dig的分隔符(一个或多个连续的空格或制表符)。可能是任何从未出现在线上的角色。

cut -d'~' -f1提取第一个字段,其中字段由上面的自定义分隔符分隔。