Phân tích tên miền từ một URL


144

Tôi cần xây dựng một chức năng phân tích tên miền từ một URL.

Vì vậy

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

hoặc là

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

nó sẽ trở lại google.com

với

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

nó sẽ trả về google.co.uk.



9
@LightnessRacesinOrbit Đây là một chút nhiều hơn là chỉ "tìm trong hướng dẫn". PHP parse_url()trả về máy chủ , không phải miền .
MrWhite

1
@ w3dk: Nó vẫn sẽ là một điểm khởi đầu tuyệt vời, cho phép câu hỏi này là về giới hạn đó parse_urlchứ không phải là "tôi có thể làm gì" mơ hồ.
Các cuộc đua nhẹ nhàng trong quỹ đạo

5
@LightnessRacesinHoàn vệ của bạn là không tôn trọng danh tiếng của bạn - đơn giản hơn là bạn có thể thừa nhận rằng bạn đã không đọc câu hỏi hoàn toàn
Andy Jones

4
@LightnessRacesinOrbit Không nhất thiết. support.suso.com/supki/ từ
Mùa thu Leonard

Câu trả lời:


297

Kiểm tra parse_url():

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

parse_url không xử lý các url thực sự rất tệ, nhưng vẫn ổn nếu bạn thường mong đợi các url tốt.


35
Một điều mà parse_url () không làm là chỉ trả về tên miền. Nếu bạn thêm www.google.com hoặc www.google.co.uk, nó cũng sẽ trả lại máy chủ. Bất kỳ đề nghị cho điều đó?
Gavin M. Roy


6
parse_urlkhông xử lý tên miền phụ, nhưng Purl thực hiện: github.com/jwage/purl
Damien

1
parse_url()có thể phân tích cú pháp URL với tên miền chứa dấu gạch ngang sai. Không thể tìm thấy bằng chứng xác định, nhưng hãy kiểm tra lỗi này . FILTER_VALIDATE_URLsử dụng parse_url()nội bộ.
XedinUn Unknown

8
Hoặc đơn giản là: print parse_url($url, PHP_URL_HOST))nếu bạn không cần $parsemảng cho bất cứ điều gì khác.
rybo111

98
$domain = str_ireplace('www.', '', parse_url($url, PHP_URL_HOST));

Điều này sẽ trả lại google.comcho cả http://google.com/ ... và http://www.google.com/ ...


18
Vì nó vẫn sẽ trả về máy chủ nếu bạn đặt "server.google.com" hoặc "www3.google.com" ...
patrick

Không phải tất cả các tên miền phụ là www, crawl-66-249-66-1.googlebot.com, myblog.blogspot.com là một vài ví dụ.
rafark

23

Từ http://us3.php.net/manual/en/feft.parse-url.php#93983

vì một số lý do kỳ lạ, parse_url trả về máy chủ (ví dụ: ví dụ.com) là đường dẫn khi không có lược đồ nào được cung cấp trong url đầu vào. Vì vậy, tôi đã viết một chức năng nhanh chóng để có được máy chủ thực sự:

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 

Đừng quên trích dẫn chuỗi của bạn như hostpath.
Gumbo

1
Nếu tôi sử dụng example.com, php sẽ hiển thị một thông báo: Message: Undefined index: hostcó ý tưởng nào để khắc phục điều này không?
Zim3r

1
Thật không may, tên miền phụ vẫn được bao gồm trong phương pháp này, xem ví dụ # 3 của bạn.
jenlampton

1
@ Zim3r Thay đổi phần đầu tiên của ternary thành !empty($parseUrl['host']).
Demonslay335

LOL nếu nó không có lược đồ thì đó không phải là URL.
miken32

12

Mã có nghĩa là hoạt động 100% dường như không cắt nó cho tôi, tôi đã vá ví dụ một chút nhưng tìm thấy mã không hữu ích và có vấn đề với nó. vì vậy tôi đã thay đổi nó thành một vài chức năng (để lưu yêu cầu danh sách từ Mozilla mọi lúc và xóa hệ thống bộ đệm). Điều này đã được thử nghiệm với một bộ 1000 URL và dường như hoạt động.

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

Sau đó sử dụng nó như

$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

Tôi biết tôi nên biến điều này thành một lớp học, nhưng không có thời gian.


11
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

Không hoạt động đối với tôi: example.com // Không chính xác: chuỗi rỗng example.com // Chính xác: example.com www.example.com // Không chính xác: chuỗi rỗng example.com/xyz // Chính xác: example.com
jenlampton

Đây là một câu trả lời tuyệt vời và xứng đáng tín dụng hơn. Chỉ cần thêm dòng này là dòng đầu tiên trong hàm và nó cũng giải quyết các vấn đề của MangeshSedit và jenlampton: if ((đế ($ url, 0, strlen ('http: //')) <> 'http: //' ) && (đế ($ url, 0, strlen ('https: //')) <> 'https: //')) $ url = 'http: //'.$url;
Rick

4

Nếu bạn muốn trích xuất máy chủ từ chuỗi http://google.com/dhasjkdas/sadsdds/sdda/sdads.html, việc sử dụng parse_url () là giải pháp chấp nhận được cho bạn.

Nhưng nếu bạn muốn trích xuất tên miền hoặc các phần của nó, bạn cần gói sử dụng Danh sách Suffix công khai . Có, bạn có thể sử dụng các hàm chuỗi arround parse_url (), nhưng đôi khi nó sẽ tạo ra kết quả không chính xác.

Tôi khuyên bạn nên TLDExtract để phân tích tên miền, đây là mã mẫu hiển thị diff:

$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'

Cảm ơn bạn rất nhiều vì lời đề nghị này. Tôi ghét việc thêm một thư viện khác cho những gì dường như là một nhiệm vụ đơn giản, nhưng sau đó tôi thấy câu trích dẫn này trên readme của họ áp dụng cho tôi: "Mọi người đều hiểu sai. Chia tách trên '.' và chỉ lấy 2 yếu tố cuối cùng đi một chặng đường dài nếu bạn đang nghĩ về các tên miền đơn giản như .com. Hãy suy nghĩ phân tích diễn đàn.bbc.co.uk chẳng hạn: phương pháp phân tách ngây thơ ở trên sẽ cung cấp cho bạn 'đồng' làm tên miền và 'uk' là TLD, thay vì 'bbc' và 'co.uk' tương ứng. "
Demonslay335

Kết quả cho việc phân tách các dấu chấm trong khi không phải là những gì chúng ta muốn xảy ra trên các tên miền .co.uk yêu quý của chúng tôi, thực sự là kết quả chính xác, đồng là cấp độ thứ hai với uk là cấp cao nhất. Quản trị trang web thường không nhận ra điều đó.
Chris

4

Tôi đã thấy rằng giải pháp của @ philfreo (được tham chiếu từ php.net) là khá tốt để có kết quả tốt nhưng trong một số trường hợp, nó hiển thị thông báo "thông báo" và "Tiêu chuẩn nghiêm ngặt" của php. Đây là một phiên bản cố định của mã này.

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

2

Đây là mã tôi đã thực hiện mà 100% chỉ tìm thấy tên miền, vì phải có tài khoản phụ mozilla vào tài khoản. Điều duy nhất bạn phải kiểm tra là cách bạn tạo bộ đệm của tệp đó, vì vậy bạn không truy vấn mozilla mỗi lần.

Vì một số lý do lạ, các tên miền như co.uk không có trong danh sách, vì vậy bạn phải thực hiện một số hack và thêm chúng theo cách thủ công. Giải pháp không sạch nhất của nó nhưng tôi hy vọng nó sẽ giúp được ai đó.

//=====================================================
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];
}

Lý do tên miền co.ukkhông có trong danh sách, là vì đó là danh sách của TLD chứ không phải tên miền. Các ccTLD đã thay đổi rất nhiều kể từ khi câu trả lời này được viết. Đáng chú ý: "Đăng ký mới trực tiếp dưới .uk đã được Nominet chấp nhận kể từ ngày 10 tháng 6 năm 2014 08:00 BST, tuy nhiên có thời hạn đặt chỗ cho những khách hàng hiện tại đã có .co.uk, .org.uk, .me.uk , .net.uk, .ltd.uk hoặc .plc.uk để yêu cầu tên miền .uk tương ứng, kéo dài đến 07:59 BST vào ngày 10 tháng 6 năm 2019. " ( Nguồn )
ashleedawg 19/12/18

2

Bạn có thể truyền PHP_URL_HOST vào hàm parse_url làm tham số thứ hai

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

2
Điều này về cơ bản giống như câu trả lời ở trên, tuy nhiên, câu hỏi là yêu cầu tên miền , không nhất thiết phải giống như máy chủ lưu trữ .
MrWhite

xem bình luận ở trên về lược đồ: vì một số lý do kỳ lạ, parse_url trả về máy chủ (ví dụ: ví dụ.com) là đường dẫn khi không có lược đồ nào được cung cấp trong url đầu vào. Vì vậy, tôi đã viết một chức năng nhanh chóng để có được máy chủ thực sự:
jenlampton


2

Vui lòng xem xét thay thế giải pháp được chấp nhận bằng cách sau:

parse_url () sẽ luôn bao gồm bất kỳ tên miền phụ nào, vì vậy hàm này không phân tích tên miền rất tốt. Dưới đây là một số ví dụ:

$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

Thay vào đó, bạn có thể xem xét giải pháp thực dụng này. Nó sẽ bao gồm nhiều, nhưng không phải tất cả các tên miền - ví dụ: các tên miền cấp thấp hơn như 'sos.state.oh.us' không được bảo hiểm.

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

Cuối cùng, Trình phân tích miền PHP của Jeremy Kendall cho phép bạn phân tích tên miền từ một url. League URI Hostname Parser cũng sẽ thực hiện công việc.


Xin chào, điều này tốt nhưng nó không hoạt động với địa chỉ IP. Tuy nhiên, công việc tuyệt vời.
MeCe

1

parse_url đã không làm việc cho tôi. Nó chỉ trở về con đường. Chuyển sang cơ bản bằng cách sử dụng php5.3 +:

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

1

Tôi đã chỉnh sửa cho bạn:

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

Tất cả các loại url (www.domain.ltd, sub1.subn.domain.ltd sẽ dẫn đến: domain.ltd.


1

Tôi đang thêm câu trả lời này vì đây là câu trả lời xuất hiện nhiều nhất trên Google ...

Bạn có thể sử dụng PHP để ...

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

để lấy máy chủ nhưng không phải miền riêng mà máy chủ đề cập đến. (Ví dụ www.google.co.uklà máy chủ lưu trữ, nhưng google.co.uklà miền riêng)

Để lấy tên miền riêng, bạn phải biết danh sách các hậu tố công khai mà người ta có thể đăng ký tên miền riêng. Danh sách này tình cờ được Mozilla quản lý tại https://publicsuffix.org/

Đoạn mã dưới đây hoạt động khi một mảng các hậu tố công khai đã được tạo. Chỉ cần gọi

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

với mã còn lại ...

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

Theo thử nghiệm của tôi, parse_url cần một URL được hình thành tốt. Nếu bạn chỉ đưa ra 'www.someDomain.com/path' thì nó sẽ trả về null. Vì vậy, nó mong đợi một giao thức (như http hoặc https) sẽ có mặt.
Andy

0

Điều này thường sẽ hoạt động rất tốt nếu URL đầu vào không phải là toàn bộ rác. Nó loại bỏ tên miền phụ.

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

Thí dụ

Đầu vào: http://www2.website.com:8080/some/file/structure?some=parameters

Đầu ra: website.com


0

Kết hợp các câu trả lời của worldofjrAlix Axel thành một chức năng nhỏ sẽ xử lý hầu hết các trường hợp sử dụng:

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

đây là giải pháp hạn chế
MGE

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


-6

Chỉ cần sử dụng như sau ...

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

1
Điều này giả sử máy chủ là url bạn muốn lấy tên miền từ đó. Đó không phải là trường hợp.
Mã hóa
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.