如何使用PHP从URL获取基本域名?

时间:2010-07-09 09:34:31

标签: php

我需要从URL获取域名。以下示例都应返回google.com

google.com
images.google.com
new.images.google.com
www.google.com

同样,以下网址都应返回google.co.uk

google.co.uk
images.google.co.uk
new.images.google.co.uk
http://www.google.co.uk

我对使用正则表达式犹豫不决,因为domain.com/google.com之类的内容可能会返回错误的结果。

如何使用PHP获取顶级域名?这需要适用于所有平台和主机。

7 个答案:

答案 0 :(得分:17)

你可以这样做:

$urlData = parse_url($url);

$host = $urlData['host'];

**更新**

我能想到的最好的方法是绘制您想要处理的所有TLD的映射,因为某些TLD可能很棘手(co.uk)。

// you can add more to it if you want
$urlMap = array('com', 'co.uk');

$host = "";
$url = "http://www.google.co.uk";

$urlData = parse_url($url);
$hostData = explode('.', $urlData['host']);
$hostData = array_reverse($hostData);

if(array_search($hostData[1] . '.' . $hostData[0], $urlMap) !== FALSE) {
  $host = $hostData[2] . '.' . $hostData[1] . '.' . $hostData[0];
} elseif(array_search($hostData[0], $urlMap) !== FALSE) {
  $host = $hostData[1] . '.' . $hostData[0];
}

echo $host;

答案 1 :(得分:6)

顶级域名和二级域名的长度可能为2个字符,但注册的子域名长度必须至少为3个字符。

编辑:由于pjv的评论,我了解到澳大利亚域名是一个例外,因为它们允许5个TLD作为SLD(com,net,org,asn,id)示例:somedomain.com.au。我猜com.au是国家控制的域名“共享”。所以,从技术上讲,“com.au”仍然是“基础域”,但这没用。

编辑:有47,952个可能的三字母域名(模式:[a-zA-Z0-9] [a-zA-Z0-9 - ] [a-zA-Z0-9]或36 * 37 * 36)与最常见的TLDS(com,org等)中的8个相结合,我们有383,616种可能性 - 甚至没有添加整个TLD范围。 1个字母和2个字母的域名仍然存在,但未来无效。

google.com中的

- “google”是“com”

的子域名 在google.co.uk中 - “google”是“co”的子域,而“co”又是“uk”的子域名,或者是二级域名,因为“co”也是一个有效的顶级域名级域

在www.google.com中 - “www”是“google”的子域名,是“com”的子域名

“co.uk”不是有效的主机,因为没有有效的域名

按照这个假设,这个函数几乎在所有情况下都会返回正确的“basedomain”,而不需要“url map”。

如果您碰巧是极少数情况之一,也许您可​​以修改它以满足特定需求......

编辑:您必须将域字符串作为带有协议的URL(http://,ftp://等)传递,否则parse_url()将不会将其视为有效的URL(除非您要修改代码行为不同)

function basedomain( $str = '' )
{
    // $str must be passed WITH protocol. ex: http://domain.com
    $url = @parse_url( $str );
    if ( empty( $url['host'] ) ) return;
    $parts = explode( '.', $url['host'] );
    $slice = ( strlen( reset( array_slice( $parts, -2, 1 ) ) ) == 2 ) && ( count( $parts ) > 2 ) ? 3 : 2;
    return implode( '.', array_slice( $parts, ( 0 - $slice ), $slice ) );
}

如果您需要准确使用fopencurl来打开此网址: http://data.iana.org/TLD/tlds-alpha-by-domain.txt

然后将这些行读入数组并使用它来比较域部分

编辑:允许澳大利亚域名:

function au_basedomain( $str = '' )
{
    // $str must be passed WITH protocol. ex: http://domain.com
    $url = @parse_url( $str );
    if ( empty( $url['host'] ) ) return;
    $parts = explode( '.', $url['host'] );
    $slice = ( strlen( reset( array_slice( $parts, -2, 1 ) ) ) == 2 ) && ( count( $parts ) > 2 ) ? 3 : 2;
    if ( preg_match( '/\.(com|net|asn|org|id)\.au$/i', $url['host'] ) ) $slice = 3;
    return implode( '.', array_slice( $parts, ( 0 - $slice ), $slice ) );
}

重要补充说明:我不使用此功能来验证域名。它是通用代码,我只用于从全局$_SERVER['SERVER_NAME']中提取运行它的服务器的基本域,以便在各种内部脚本中使用。考虑到我只在美国境内工作,我从未遇到过pjv所询问的澳大利亚变种。它对内部使用很方便,但距离完整的域验证过程还有很长的路要走。如果您尝试以这种方式使用它,我建议不要因为有太多可能性来匹配无效域。

答案 2 :(得分:4)

尝试使用:http://php.net/manual/en/function.parse-url.php。这样的事情应该有效:

$urlParts = parse_url($yourUrl);
$hostParts = explode('.', $urlParts['host']);
$hostParts = array_reverse($hostParts);
$host = $hostParts[1] . '.' . $hostParts[0];

答案 3 :(得分:2)

与xil3混合回答这是我要检查localhost和ip,所以你也可以在开发环境中工作。
您仍需要定义要使用的TLD。除此之外一切正常。

<?php
function getTopLevelDomain($url){
    $urlData = parse_url($url);
    $urlHost = isset($urlData['host']) ? $urlData['host'] : '';
    $isIP = (bool)ip2long($urlHost);
    if($isIP){ /** To check if it's ip then return same ip */
        return $urlHost;
    }
    /** Add/Edit you TLDs here */
    $urlMap = array('com', 'com.pk', 'co.uk');

    $host = "";
    $hostData = explode('.', $urlHost);
    if(isset($hostData[1])){ /** To check "localhost" because it'll be without any TLDs */
        $hostData = array_reverse($hostData);

        if(array_search($hostData[1] . '.' . $hostData[0], $urlMap) !== FALSE) {
            $host = $hostData[2] . '.' . $hostData[1] . '.' . $hostData[0];
        } elseif(array_search($hostData[0], $urlMap) !== FALSE) {
            $host = $hostData[1] . '.' . $hostData[0];
        }
        return $host;
    }
    return ((isset($hostData[0]) && $hostData[0] != '') ? $hostData[0] : 'error no domain'); /* You can change this error in future */
}
?>

你可以像这样使用它

$string = 'http://googl.com.pk';
echo getTopLevelDomain( $string ) . '<br>';

$string = 'http://googl.com.pk:23';
echo getTopLevelDomain( $string ) . '<br>';

$string = 'http://googl.com';
echo getTopLevelDomain( $string ) . '<br>';

$string = 'http://googl.com:23';
echo getTopLevelDomain( $string ) . '<br>';

$string = 'http://adad.asdasd.googl.com.pk';
echo getTopLevelDomain( $string ) . '<br>';

$string = 'http://adad.asdasd.googl.com.pk:23';
echo getTopLevelDomain( $string ) . '<br>';

$string = 'http://adad.asdasd.googl.com';
echo getTopLevelDomain( $string ) . '<br>';

$string = 'http://adad.asdasd.googl.com:23';
echo getTopLevelDomain( $string ) . '<br>';

$string = 'http://192.168.0.101:23';
echo getTopLevelDomain( $string ) . '<br>';

$string = 'http://192.168.0.101';
echo getTopLevelDomain( $string ) . '<br>';

$string = 'http://localhost';
echo getTopLevelDomain( $string ) . '<br>';

$string = 'https;//';
echo getTopLevelDomain( $string ) . '<br>';

$string = '';
echo getTopLevelDomain( $string ) . '<br>';

你会得到像这样的字符串

的结果
googl.com.pk
googl.com.pk
googl.com
googl.com
googl.com.pk
googl.com.pk
googl.com
googl.com
192.168.0.101
192.168.0.101
localhost
error no domain
error no domain

答案 4 :(得分:0)

我不是PHP开发人员,我知道这不是完整的解决方案,但是我认为一般的问题实际上是确定所有可能的公共域名。

幸运的是,在https://publicsuffix.org/list/维护着一个公共域列表。该列表分为两部分。第一部分是公共域名,其中包括这些注释中列出的许多域名,例如.com.com.au。公共域名用===BEGIN ICANN DOMAINS======END ICANN DOMAINS===分隔。

如果仅加载ICANN DOMAINS列表,则可以标识顶级域名。但是需要PHP开发人员来解释如何有效地做到这一点:)

如果加载整个列表,那么您还可以获得有关私有子域的信息,例如github.io下的私有子域。

答案 5 :(得分:0)

您可能要使用公共后缀列表。

https://publicsuffix.org/

在php ypu中可以使用regdom库来做到这一点:

https://github.com/usrflo/registered-domain-libs/

答案 6 :(得分:-3)

使用此功能:

function getHost($url){
    if (strpos($url,"http://")){
        $httpurl=$url;
    } else {
        $httpurl="http://".$url;
    }
    $parse = parse_url($httpurl);
    $domain=$parse['host'];

    $portion=explode(".",$domain);
    $count=sizeof($portion)-1;
    if ($count>1){
        $result=$portion[$count-1].".".$portion[$count];
    } else {
        $result=$domain;
    }
    return $result;
}

回答示例网址的所有变体。