从 URL 解析域

我需要建立一个函数,解析域从一个 URL。

所以

http://google.com/dhasjkdas/sadsdds/sdda/sdads.html

或者

http://www.google.com/dhasjkdas/sadsdds/sdda/sdads.html

它应该返回 google.com

http://google.co.uk/dhasjkdas/sadsdds/sdda/sdads.html

它应该返回 google.co.uk

302073 次浏览

看看 parse_url():

$url = 'http://google.com/dhasjkdas/sadsdds/sdda/sdads.html';
$parse = parse_url($url);
echo $parse['host']; // prints 'google.com'

parse_url并不能很好地处理非常糟糕的错位网址,但是如果您通常期望像样的网址,那么它是可以的。

来自 http://us3.php.net/manual/en/function.parse-url.php#93983

由于某些奇怪的原因,parse _ url 返回主机(ex.example.com)作为 中没有提供任何方案时的路径 输入网址。所以我写了一个快速 功能来获得真正的主机:

function getHost($Address) {
$parseUrl = parse_url(trim($Address));
return trim($parseUrl['host'] ? $parseUrl['host'] : array_shift(explode('/', $parseUrl['path'], 2)));
}


getHost("example.com"); // Gives example.com
getHost("http://example.com"); // Gives example.com
getHost("www.example.com"); // Gives www.example.com
getHost("http://example.com/xyz"); // Gives example.com
$domain = str_ireplace('www.', '', parse_url($url, PHP_URL_HOST));

这将返回 http://google.com/http://www.google.com/google.com

下面是我做的代码,100% 找到只有域名,因为它需要 mozilla 子 tld 帐户。唯一需要检查的是如何缓存该文件,因此不必每次都查询 mozilla。

由于一些奇怪的原因,像 co.uk 这样的域名不在列表中,所以你必须进行一些黑客攻击并手动添加它们。这不是最干净的解决方案,但我希望它能帮助某人。

//=====================================================
static function domain($url)
{
$slds = "";
$url = strtolower($url);


$address = 'http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1';
if(!$subtlds = @kohana::cache('subtlds', null, 60))
{
$content = file($address);
foreach($content as $num => $line)
{
$line = trim($line);
if($line == '') continue;
if(@substr($line[0], 0, 2) == '/') continue;
$line = @preg_replace("/[^a-zA-Z0-9\.]/", '', $line);
if($line == '') continue;  //$line = '.'.$line;
if(@$line[0] == '.') $line = substr($line, 1);
if(!strstr($line, '.')) continue;
$subtlds[] = $line;
//echo "{$num}: '{$line}'"; echo "<br>";
}
$subtlds = array_merge(Array(
'co.uk', 'me.uk', 'net.uk', 'org.uk', 'sch.uk', 'ac.uk',
'gov.uk', 'nhs.uk', 'police.uk', 'mod.uk', 'asn.au', 'com.au',
'net.au', 'id.au', 'org.au', 'edu.au', 'gov.au', 'csiro.au',
),$subtlds);


$subtlds = array_unique($subtlds);
//echo var_dump($subtlds);
@kohana::cache('subtlds', $subtlds);
}




preg_match('/^(http:[\/]{2,})?([^\/]+)/i', $url, $matches);
//preg_match("/^(http:\/\/|https:\/\/|)[a-zA-Z-]([^\/]+)/i", $url, $matches);
$host = @$matches[2];
//echo var_dump($matches);


preg_match("/[^\.\/]+\.[^\.\/]+$/", $host, $matches);
foreach($subtlds as $sub)
{
if (preg_match("/{$sub}$/", $host, $xyz))
preg_match("/[^\.\/]+\.[^\.\/]+\.[^\.\/]+$/", $host, $matches);
}


return @$matches[0];
}

原本应该100% 工作的代码似乎并不适合我,我确实对示例进行了一些补丁,但是发现了一些没有帮助的代码和问题。所以我把它改成了几个函数(省去了一直向 Mozilla 请求列表,并删除了缓存系统)。这已经针对一组1000个 URL 进行了测试,看起来是有效的。

function domain($url)
{
global $subtlds;
$slds = "";
$url = strtolower($url);


$host = parse_url('http://'.$url,PHP_URL_HOST);


preg_match("/[^\.\/]+\.[^\.\/]+$/", $host, $matches);
foreach($subtlds as $sub){
if (preg_match('/\.'.preg_quote($sub).'$/', $host, $xyz)){
preg_match("/[^\.\/]+\.[^\.\/]+\.[^\.\/]+$/", $host, $matches);
}
}


return @$matches[0];
}


function get_tlds() {
$address = 'http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1';
$content = file($address);
foreach ($content as $num => $line) {
$line = trim($line);
if($line == '') continue;
if(@substr($line[0], 0, 2) == '/') continue;
$line = @preg_replace("/[^a-zA-Z0-9\.]/", '', $line);
if($line == '') continue;  //$line = '.'.$line;
if(@$line[0] == '.') $line = substr($line, 1);
if(!strstr($line, '.')) continue;
$subtlds[] = $line;
//echo "{$num}: '{$line}'"; echo "<br>";
}


$subtlds = array_merge(array(
'co.uk', 'me.uk', 'net.uk', 'org.uk', 'sch.uk', 'ac.uk',
'gov.uk', 'nhs.uk', 'police.uk', 'mod.uk', 'asn.au', 'com.au',
'net.au', 'id.au', 'org.au', 'edu.au', 'gov.au', 'csiro.au'
), $subtlds);


$subtlds = array_unique($subtlds);


return $subtlds;
}

那就好好利用

$subtlds = get_tlds();
echo domain('www.example.com') //outputs: example.com
echo domain('www.example.uk.com') //outputs: example.uk.com
echo domain('www.example.fr') //outputs: example.fr

我知道我应该把这个变成一门课,但是没时间。

Parse _ url 对我来说不起作用,它只返回了路径。使用 php5.3 + 切换到基础:

$url  = str_replace('http://', '', strtolower( $s->website));
if (strpos($url, '/'))  $url = strstr($url, '/', true);

如果输入的 URL 不是完全的垃圾,这通常会很好地工作。它删除了子域。

$host = parse_url( $Row->url, PHP_URL_HOST );
$parts = explode( '.', $host );
$parts = array_reverse( $parts );
$domain = $parts[1].'.'.$parts[0];

例子

输入: http://www2.website.com:8080/some/file/structure?some=parameters

输出: website.com

可以将 PHP _ URL _ HOST 作为第二个参数传递给 parse _ url 函数

$url = 'http://google.com/dhasjkdas/sadsdds/sdda/sdads.html';
$host = parse_url($url, PHP_URL_HOST);
print $host; // prints 'google.com'

我为你编辑了:

function getHost($Address) {
$parseUrl = parse_url(trim($Address));
$host = trim($parseUrl['host'] ? $parseUrl['host'] : array_shift(explode('/', $parseUrl['path'], 2)));


$parts = explode( '.', $host );
$num_parts = count($parts);


if ($parts[0] == "www") {
for ($i=1; $i < $num_parts; $i++) {
$h .= $parts[$i] . '.';
}
}else {
for ($i=0; $i < $num_parts; $i++) {
$h .= $parts[$i] . '.';
}
}
return substr($h,0,-1);
}

所有类型的 url (www.domain.ltd,sub1.subn.domain.ltd)将导致: domain.ltd。

$domain = parse_url($url, PHP_URL_HOST);
echo implode('.', array_slice(explode('.', $domain), -2, 2))
function get_domain($url = SITE_URL)
{
preg_match("/[a-z0-9\-]{1,63}\.[a-z\.]{2,6}$/", parse_url($url, PHP_URL_HOST), $_domain_tld);
return $_domain_tld[0];
}


get_domain('http://www.cdl.gr'); //cdl.gr
get_domain('http://cdl.gr'); //cdl.gr
get_domain('http://www2.cdl.gr'); //cdl.gr

只要像下面这样使用..。

<?php
echo $_SERVER['SERVER_NAME'];
?>

Worlddofjr阿里克斯 · 阿克塞尔的答案组合成一个小函数,可以处理大多数用例:

function get_url_hostname($url) {


$parse = parse_url($url);
return str_ireplace('www.', '', $parse['host']);


}


get_url_hostname('http://www.google.com/example/path/file.html'); // google.com

如果希望从字符串 http://google.com/dhasjkdas/sadsdds/sdda/sdads.html中提取主机,可以使用 parse _ url ()。

但是,如果您想提取域或其部分,您需要使用 公开后缀名单的包。是的,可以围绕 parse _ url ()使用字符串函数,但有时会产生不正确的结果。

对于域解析,我推荐使用 TLDExtract,下面的示例代码显示了差异:

$extract = new LayerShifter\TLDExtract\Extract();


# For 'http://google.com/dhasjkdas/sadsdds/sdda/sdads.html'


$url = 'http://google.com/dhasjkdas/sadsdds/sdda/sdads.html';


parse_url($url, PHP_URL_HOST); // will return google.com


$result = $extract->parse($url);
$result->getFullHost(); // will return 'google.com'
$result->getRegistrableDomain(); // will return 'google.com'
$result->getSuffix(); // will return 'com'


# For 'http://search.google.com/dhasjkdas/sadsdds/sdda/sdads.html'


$url = 'http://search.google.com/dhasjkdas/sadsdds/sdda/sdads.html';


parse_url($url, PHP_URL_HOST); // will return 'search.google.com'


$result = $extract->parse($url);
$result->getFullHost(); // will return 'search.google.com'
$result->getRegistrableDomain(); // will return 'google.com'

因为这个答案在谷歌上出现得最多,所以我会晚点添加这个答案。

您可以使用 PHP 来..。

$url = "www.google.co.uk";
$host = parse_url($url, PHP_URL_HOST);
// $host == "www.google.co.uk"

抓取 主持人而不是主机所引用的 私人领域。(示例 www.google.co.uk是主机,但 google.co.uk是私有域)

要获取私有域,您必须知道一个 可以注册私有域的公共后缀列表。这个列表恰好是由 Mozilla 在 https://publicsuffix.org/管理的

当已经创建了公共后缀数组时,下面的代码可以工作

$domain = get_private_domain("www.google.co.uk");

用剩下的密码。

// find some way to parse the above list of public suffix
// then add them to a PHP array
$suffix = [... all valid public suffix ...];


function get_public_suffix($host) {
$parts = split("\.", $host);
while (count($parts) > 0) {
if (is_public_suffix(join(".", $parts)))
return join(".", $parts);


array_shift($parts);
}


return false;
}


function is_public_suffix($host) {
global $suffix;
return isset($suffix[$host]);
}


function get_private_domain($host) {
$public = get_public_suffix($host);
$public_parts = split("\.", $public);
$all_parts = split("\.", $host);


$private = [];


for ($x = 0; $x < count($public_parts); ++$x)
$private[] = array_pop($all_parts);


if (count($all_parts) > 0)
$private[] = array_pop($all_parts);


return join(".", array_reverse($private));
}

我发现@philfreo 的解决方案(从 php.net 引用)很好地得到了很好的结果,但在某些情况下,它显示了 php 的“通知”和“严格标准”消息。这里是这个代码的固定版本。

function getHost($url) {
$parseUrl = parse_url(trim($url));
if(isset($parseUrl['host']))
{
$host = $parseUrl['host'];
}
else
{
$path = explode('/', $parseUrl['path']);
$host = $path[0];
}
return trim($host);
}


echo getHost("http://example.com/anything.html");           // example.com
echo getHost("http://www.example.net/directory/post.php");  // www.example.net
echo getHost("https://example.co.uk");                      // example.co.uk
echo getHost("www.example.net");                            // example.net
echo getHost("subdomain.example.net/anything");             // subdomain.example.net
echo getHost("example.net");                                // example.net

请考虑将已接受的解决办法替换为以下办法:

Parse _ url ()将始终包含任何子域,因此该函数不能很好地解析域名。 下面是一些例子:

$url = 'http://www.google.com/dhasjkdas/sadsdds/sdda/sdads.html';
$parse = parse_url($url);
echo $parse['host']; // prints 'www.google.com'


echo parse_url('https://subdomain.example.com/foo/bar', PHP_URL_HOST);
// Output: subdomain.example.com


echo parse_url('https://subdomain.example.co.uk/foo/bar', PHP_URL_HOST);
// Output: subdomain.example.co.uk

相反,您可以考虑这种务实的解决方案。 它将涵盖许多域名,但不是所有域名——例如,‘ sos.state.oh.us’等低级域名不包括在内。

function getDomain($url) {
$host = parse_url($url, PHP_URL_HOST);


if(filter_var($host,FILTER_VALIDATE_IP)) {
// IP address returned as domain
return $host; //* or replace with null if you don't want an IP back
}


$domain_array = explode(".", str_replace('www.', '', $host));
$count = count($domain_array);
if( $count>=3 && strlen($domain_array[$count-2])==2 ) {
// SLD (example.co.uk)
return implode('.', array_splice($domain_array, $count-3,3));
} else if( $count>=2 ) {
// TLD (example.com)
return implode('.', array_splice($domain_array, $count-2,2));
}
}


// Your domains
echo getDomain('http://google.com/dhasjkdas/sadsdds/sdda/sdads.html'); // google.com
echo getDomain('http://www.google.com/dhasjkdas/sadsdds/sdda/sdads.html'); // google.com
echo getDomain('http://google.co.uk/dhasjkdas/sadsdds/sdda/sdads.html'); // google.co.uk


// TLD
echo getDomain('https://shop.example.com'); // example.com
echo getDomain('https://foo.bar.example.com'); // example.com
echo getDomain('https://www.example.com'); // example.com
echo getDomain('https://example.com'); // example.com


// SLD
echo getDomain('https://more.news.bbc.co.uk'); // bbc.co.uk
echo getDomain('https://www.bbc.co.uk'); // bbc.co.uk
echo getDomain('https://bbc.co.uk'); // bbc.co.uk


// IP
echo getDomain('https://1.2.3.45');  // 1.2.3.45

最后,Jeremy Kendall 的 PHP 域解析器允许您从 URL 解析域名。

function getTrimmedUrl($link)
{
$str = str_replace(["www.","https://","http://"],[''],$link);
$link = explode("/",$str);
return strtolower($link[0]);
}

当我使用这个测试用例时,所有这些解决方案都不起作用:

public function getTestCases(): array
{
return [
//input                              expected
['http://google.com/dhasjkdas',      'google.com'],
['https://google.com/dhasjkdas',     'google.com'],
['https://www.google.com/dhasjkdas', 'google.com'],
['http://www.google.com/dhasjkdas',  'google.com'],
['www.google.com/dhasjkdas',         'google.com'],
['google.com/dhasjkdas',             'google.com'],
];
}

但是将这个答案包装到函数中在所有情况下都起作用: https://stackoverflow.com/a/65659814/5884988