Hàm PHP để lấy tên miền phụ của một URL


107

Có một hàm trong PHP để lấy tên của miền phụ không?

Trong ví dụ sau, tôi muốn lấy phần "en" của URL:

en.example.com

6
Bạn có URL dưới dạng chuỗi được lưu trữ trong một biến hay URL này đến từ đâu? Bối cảnh là gì? Xin hãy giải thích.
Felix Kling

Bạn không thể sử dụng một regex đã làm một cái gì đó giống như (^|://)(.*)\.và chụp .*? Tôi khá thích cả php và regex, nhưng điều này xuất hiện trong tâm trí.
corsiKa

Nó sẽ nhận được gì en.foo.bar.example.comhoặc en.example.co.uk?
Álvaro González

parse_url cũng có thể trợ giúp
Swapnil

Câu trả lời:


132

Đây là một giải pháp một dòng:

array_shift((explode('.', $_SERVER['HTTP_HOST'])));

Hoặc sử dụng ví dụ của bạn:

array_shift((explode('.', 'en.example.com')));

CHỈNH SỬA: Đã sửa lỗi "chỉ các biến nên được chuyển bằng tham chiếu" bằng cách thêm dấu ngoặc kép.


CHỈNH SỬA 2 : Bắt đầu từ PHP 5.4, bạn chỉ cần thực hiện:

explode('.', 'en.example.com')[0];

17
Chỉ các biến phải được truyền bằng tham chiếu.
Tamás Pap

8
Bạn không thể chỉ làm explode(...)[0]thay vì sử dụng ca làm việc những ngày này? Không được PHPing trong nhiều năm ..
Tor Valamo

Lỗi:Strict Standards: Only variables should be passed by reference.
Justin

1
khá chắc chắn bạn có thể (explode (...)) [0] tuy nhiên, nên được hoạt động trên các mảng lợi nhuận thay vì chức năng ngoặc (trước 5.4)
Garet Claborn

3
Giải pháp này sẽ không hoạt động trong trường hợp ai đó nhập vào www.en.example.comvà do đó sẽ trả về wwwdưới dạng tên miền phụ.
lolbas

65

Sử dụng hàm parse_url .

$url = 'http://en.example.com';

$parsedUrl = parse_url($url);

$host = explode('.', $parsedUrl['host']);

$subdomain = $host[0];
echo $subdomain;

Đối với nhiều miền phụ

$url = 'http://usa.en.example.com';

$parsedUrl = parse_url($url);

$host = explode('.', $parsedUrl['host']);

$subdomains = array_slice($host, 0, count($host) - 2 );
print_r($subdomains);

@Mike Lewis - Điều này có giải quyết được vấn đề của nhiều miền phụ, chẳng hạn như usa.en.example.com không? Chỉ tự hỏi (câu trả lời của riêng tôi không, btw).
Jared Farrish

@Jared, vừa thêm một giải pháp để phát hiện nhiều miền phụ.
Mike Lewis

1
@Mike - Điều đó có hoạt động với tx.usa.en.example.com không? (hoặc science.news.bbc.co.uk )? (btw, đó không phải là một liên kết đang hoạt động, chỉ là một ví dụ, mặc dù news.bbc.co.uk hoạt động)
Jared Farrish

4
Điều đó hoạt động đối với mọi thứ có một 'từ' TLD như net, com, biz, v.v. Tuy nhiên, ví dụ: khi giao dịch với co.uk, nó không. Như đã thấy ở đây Đây thực sự là một vấn đề khó giải hơn.
Mike Lewis

2
điều này cũng không thành công nếu không có tên miền phụ nào cả.
raveren

32

Bạn có thể làm điều này trước tiên bằng cách lấy tên miền (ví dụ: sub.example.com => example.co.uk) và sau đó sử dụng strstr để lấy các tên miền phụ.

$testArray = array(
    'sub1.sub2.example.co.uk',
    'sub1.example.com',
    'example.com',
    'sub1.sub2.sub3.example.co.uk',
    'sub1.sub2.sub3.example.com',
    'sub1.sub2.example.com'
);

foreach($testArray as $k => $v)
{
    echo $k." => ".extract_subdomains($v)."\n";
}

function extract_domain($domain)
{
    if(preg_match("/(?P<domain>[a-z0-9][a-z0-9\-]{1,63}\.[a-z\.]{2,6})$/i", $domain, $matches))
    {
        return $matches['domain'];
    } else {
        return $domain;
    }
}

function extract_subdomains($domain)
{
    $subdomains = $domain;
    $domain = extract_domain($subdomains);

    $subdomains = rtrim(strstr($subdomains, $domain, true), '.');

    return $subdomains;
}

Kết quả đầu ra:

0 => sub1.sub2
1 => sub1
2 =>
3 => sub1.sub2.sub3
4 => sub1.sub2.sub3
5 => sub1.sub2

2
Đây có vẻ là giải pháp tốt nhất vì nó cũng cho phép các miền không có miền phụ, thay vì chạy lại tên miền vì miền phụ là phần trước dấu chấm đầu tiên. Rất hữu ích để kiểm tra sự tồn tại của một miền phụ.
Karl MW

Tôi cần lấy miền "cơ sở" (không có miền phụ) và tôi đang đưa ra giải pháp của riêng mình bằng cách cho máy chủ lưu trữ và lấy các phần tử cuối cùng của mảng bằng một forvòng lặp, nhưng tôi phải kiểm tra độ dài của chúng (để phát hiện xem chúng có là một phần của miền như "co.uk"). Trên thực tế, giải pháp của bạn đơn giản hơn nhiều so với những gì tôi đang làm. Regex cứu sống, cảm ơn!
Yoone

1
Tuyệt vời .. điều này hoạt động rất tốt cho tất cả các loại tên miền và tên miền phụ .. tốt đẹp.
jon

2
trong khi giải pháp này là rất gọn gàng và có thể làm việc trong hầu hết mọi trường hợp, cần lưu ý rằng lĩnh vực tên có thể có nhiều hơn 6 ký tự, giống như pvt.k12.ma.us, health.vnhoặc thậm chí k12.ak.us. Ngoài ra, tên miền có thể sử dụng bộ ký tự tiếng Trung hoặc tiếng Nga, do đó phần regex [a-z\.]{2,6}sẽ không khớp với chúng. Kiểm tra tại đây để có tên miền mẫu: publicsuffix.org/list
pomeh

12

http://php.net/parse_url

<?php
  $url = 'http://user:password@sub.hostname.tld/path?argument=value#anchor';
  $array=parse_url($url);
  $array['host']=explode('.', $array['host']);

  echo $array['host'][0]; // returns 'en'
?>

7

Vì nguồn đáng tin cậy duy nhất cho các hậu tố tên miền là các công ty đăng ký tên miền, bạn không thể tìm thấy tên miền phụ mà họ không biết. Có một danh sách với tất cả các hậu tố tên miền tại https://publicsuffix.org . Trang web này cũng liên kết đến một thư viện PHP: https://github.com/jeremykendall/php-domain-parser .

Vui lòng tìm một ví dụ dưới đây. Tôi cũng đã thêm mẫu cho en.test.co.uk, một miền có nhiều hậu tố (co.uk).

<?php

require_once 'vendor/autoload.php';

$pslManager = new Pdp\PublicSuffixListManager();
$parser = new Pdp\Parser($pslManager->getList());
$host = 'http://en.example.com';
$url = $parser->parseUrl($host);

echo $url->host->subdomain;


$host = 'http://en.test.co.uk';
$url = $parser->parseUrl($host);

echo $url->host->subdomain;

5

Giải pháp đơn giản và nhanh nhất.

$sSubDomain = str_replace('.example.com','',$_SERVER['HTTP_HOST']);

4

Đơn giản...

    preg_match('/(?:http[s]*\:\/\/)*(.*?)\.(?=[^\/]*\..{2,5})/i', $url, $match);

Chỉ cần đọc $ match [1]

Ví dụ làm việc

Nó hoạt động hoàn hảo với danh sách url này

$url = array(
    'http://www.domain.com', // www
    'http://domain.com', // --nothing--
    'https://domain.com', // --nothing--
    'www.domain.com', // www
    'domain.com', // --nothing--
    'www.domain.com/some/path', // www
    'http://sub.domain.com/domain.com', // sub
    'опубликованному.значения.ua', // опубликованному ;)
    'значения.ua', // --nothing--
    'http://sub-domain.domain.net/domain.net', // sub-domain
    'sub-domain.third-Level_DomaIN.domain.uk.co/domain.net' // sub-domain
);

foreach ($url as $u) {
    preg_match('/(?:http[s]*\:\/\/)*(.*?)\.(?=[^\/]*\..{2,5})/i', $u, $match);
    var_dump($match);
}

2
Tái bút - Tôi không có bất kỳ ý tưởng nào về những gì nó được viết bằng văn bản tiếng Nga. Chỉ lấy một số từ bình thường từ ru.wikipedia.org ;)
Kamafeather

Không phải là tiếng Ukraina? .ualà mã quốc gia của Ukraine.
nalply

Không. Chỉ là thông tin hỗn hợp. Nhưng tôi không chắc, tôi không đủ giỏi để phân biệt chúng;)
Kamafeather

3
Liên quan đến sự Nga, một google dịch từ Nga sang tiếng Anh trở lại là "giá trị xuất bản" (trong trường hợp bất cứ ai tò mò như tôi đã được)
Jeremy Harris

@Kamafeather cái này có vẻ chống đạn. Bất kỳ cách nào để chỉ nhận được $match[1]một phần? $match[0]có vẻ không cần thiết.
Andres SK

3
$REFERRER = $_SERVER['HTTP_REFERER']; // Or other method to get a URL for decomposition

$domain = substr($REFERRER, strpos($REFERRER, '://')+3);
$domain = substr($domain, 0, strpos($domain, '/'));
// This line will return 'en' of 'en.example.com'
$subdomain = substr($domain, 0, strpos($domain, '.')); 

1
Có nhiều cách tốt hơn để tự động phát hiện máy chủ hiện tại (giống như $_SERVER['HTTP_HOST']) sau đó dựa vào tiêu đề liên kết giới thiệu có thể giả mạo, giả sử đó là ý tưởng chung đằng sau câu trả lời.
Matthew

Đúng vậy, tôi đang sử dụng một đoạn mã cũ. Tuy nhiên, ví dụ vẫn có giá trị. Đó không phải là gốc rễ của câu hỏi.
Jared Farrish

Chỉ để thêm vào những nhận xét ở trên, việc dựa vào $ _SERVER ['HTTP_HOST'] có thể không hiệu quả, vì có khả năng nó không được đặt.
gmslzr 20/09/17

2

PHP 7.0: Sử dụng chức năng bùng nổ và tạo danh sách tất cả các kết quả.

list($subdomain,$host) = explode('.', $_SERVER["SERVER_NAME"]);

Ví dụ: sub.domain.com

echo $subdomain; 

Kết quả: phụ

echo $host;

Kết quả: miền


Bạn quên TLD's like .co.uk- đoạn mã của bạn sẽ không hoạt động với các TLD này
Adrian Preuss

1

Điều tôi tìm thấy giải pháp tốt nhất và ngắn gọn là

array_shift(explode(".",$_SERVER['HTTP_HOST']));

Sẽ gây ra lỗi Nghiêm ngặt. Đầu ra của sự bùng nổ không thể được chuyển trực tiếp đến array_shift.
YAAK

1

Đối với những người nhận được 'Lỗi: Tiêu chuẩn nghiêm ngặt: Chỉ các biến nên được chuyển qua tham chiếu.' Sử dụng như thế này:

$env = (explode(".",$_SERVER['HTTP_HOST'])); $env = array_shift($env);


Đó không phải là câu hỏi, mà là cảm ơn bạn đã đóng góp ý kiến.
FazoM


1

Không thực sự có một giải pháp động 100% - tôi cũng đang cố gắng tìm ra nó và do các phần mở rộng tên miền (DTL) khác nhau, nhiệm vụ này sẽ thực sự khó khăn nếu không thực sự phân tích cú pháp tất cả các phần mở rộng này và kiểm tra chúng mỗi lần:

.com vs .co.uk vs org.uk

Tùy chọn đáng tin cậy nhất là xác định một hằng số (hoặc mục nhập cơ sở dữ liệu, v.v.) lưu trữ tên miền thực và xóa nó khỏi việc $_SERVER['SERVER_NAME']sử dụngsubstr()

defined("DOMAIN")
    || define("DOMAIN", 'mymaindomain.co.uk');



function getSubDomain() {

    if (empty($_SERVER['SERVER_NAME'])) {

        return null;

    }

    $subDomain = substr($_SERVER['SERVER_NAME'], 0, -(strlen(DOMAIN)));

    if (empty($subDomain)) {

        return null;

    }

    return rtrim($subDomain, '.');

}

Bây giờ nếu bạn đang sử dụng chức năng này, http://test.mymaindomain.co.uknó sẽ cung cấp cho bạn testhoặc nếu bạn có nhiều cấp miền phụ, http://another.test.mymaindomain.co.ukbạn sẽ nhận được another.test- tất nhiên trừ khi bạn cập nhật DOMAIN.

Tôi hi vọng cái này giúp được.


1

Đơn giản

reset(explode(".", $_SERVER['HTTP_HOST']))


1

Sử dụng regex, các hàm chuỗi, parse_url () hoặc các kết hợp của chúng thì đó không phải là giải pháp thực. Chỉ cần kiểm tra bất kỳ giải pháp được đề xuất nào với miền test.en.example.co.uk, sẽ không có bất kỳ kết quả chính xác nào.

Giải pháp đúng là sử dụng gói phân tích cú pháp miền với Danh sách hậu tố công khai . Tôi khuyên bạn nên TLDExtract , đây là mã mẫu:

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

$result = $extract->parse('test.en.example.co.uk');
$result->getSubdomain(); // will return (string) 'test.en'
$result->getSubdomains(); // will return (array) ['test', 'en']
$result->getHostname(); // will return (string) 'example'
$result->getSuffix(); // will return (string) 'co.uk'

1

đây là giải pháp của tôi, nó hoạt động với các miền phổ biến nhất, bạn có thể điều chỉnh mảng mở rộng khi bạn cần:

$SubDomain = explode('.', explode('|ext|', str_replace(array('.com', '.net', '.org'), '|ext|',$_SERVER['HTTP_HOST']))[0]);

0
// For www.abc.en.example.com 
$host_Array = explode(".",$_SERVER['HTTP_HOST']); // Get HOST as array www, abc, en, example, com
array_pop($host_Array); array_pop($host_Array);   // Remove com and exmaple
array_shift($host_Array);                         // Remove www (Optional)
echo implode($host_Array, ".");                   // Combine array abc.en

0

Tôi biết tôi thực sự muộn trò chơi, nhưng rồi đây.

Những gì tôi đã làm là lấy biến máy chủ HTTP_HOST ( $_SERVER['HTTP_HOST']) và số ký tự trong miền (vì vậy example.comnó sẽ là 11).

Sau đó, tôi sử dụng substrchức năng để lấy tên miền phụ. tôi đã làm

$numberOfLettersInSubdomain = strlen($_SERVER['HTTP_HOST'])-12
$subdomain = substr($_SERVER['HTTP_HOST'], $numberOfLettersInSubdomain);

Tôi cắt chuỗi con ở 12 thay vì 11 vì chuỗi con bắt đầu bằng 1 cho tham số thứ hai. Vì vậy, bây giờ nếu bạn nhập test.example.com, giá trị của $subdomainsẽ là test.

Điều này tốt hơn là sử dụng explodevì nếu miền phụ có .trong đó, điều này sẽ không cắt nó đi.


Vị trí bắt đầu "0" bị thiếu trong câu trả lời của bạn. $ subdomain = substr ($ _ SERVER ['HTTP_HOST'], 0, $ numberOfLettersInSubdomain);
Jamie

0

nếu bạn đang sử dụng drupal 7

Điều này sẽ giúp bạn:

global $base_path;
global $base_root;  
$fulldomain = parse_url($base_root);    
$splitdomain = explode(".", $fulldomain['host']);
$subdomain = $splitdomain[0];

0
$host = $_SERVER['HTTP_HOST'];
preg_match("/[^\.\/]+\.[^\.\/]+$/", $host, $matches);
$domain = $matches[0];
$url = explode($domain, $host);
$subdomain = str_replace('.', '', $url[0]);

echo 'subdomain: '.$subdomain.'<br />';
echo 'domain: '.$domain.'<br />';

0

Từ PHP 5.3, bạn có thể sử dụng strstr () với tham số true

echo strstr($_SERVER["HTTP_HOST"], '.', true); //prints en

Điều này sẽ chỉ hoạt động nếu không có wwwở đầu chuỗi. Một cách tiếp cận hơi quá tầm thường.
FooBar

Điều này đơn giản hóa mọi thứ cho các nhà phát triển khác trong nhóm, tôi muốn sử dụng điều này hơn là một số điểm kinh nghiệm đăng ký nâng cao. Nếu bạn muốn cắt www, hãy sử dụng trim ($ s, 'www'); hoặc chỉ cần điều chỉnh nó để logic kinh doanh của bạn ...
tasmaniski

1
Vì lợi ích đầy đủ, www thực sự là một tên miền phụ. Nó thường được đặt bí danh cho chính tên miền vì lý do lịch sử.
Levi Morrison,

0

Thử cái này...

$domain = 'en.example.com';
$tmp = explode('.', $domain);
$subdomain = current($tmp);
echo($subdomain);     // echo "en"

Tôi nghĩ rằng nó sẽ hữu ích hơn cho OP và những khách truy cập khác, khi bạn thêm một số giải thích vào nội dung của bạn.
Phóng viên

0
function get_subdomain($url=""){
    if($url==""){
        $url = $_SERVER['HTTP_HOST'];
    }
    $parsedUrl = parse_url($url);
    $host = explode('.', $parsedUrl['path']);
    $subdomains = array_slice($host, 0, count($host) - 2 );
    return implode(".", $subdomains);
}

1
dòng # 7 nên là$host = explode('.', isset($parsedUrl['path']) ? $parsedUrl['path'] : $parsedUrl['host']);
Kal

0

bạn cũng có thể sử dụng cái này

echo substr($_SERVER['HTTP_HOST'], 0, strrpos($_SERVER['HTTP_HOST'], '.', -5));

0

Tôi đang làm một cái gì đó như thế này

$url = https://en.example.com

$splitedBySlash = explode('/', $url);
$splitedByDot = explode('.', $splitedBySlash[2]);

$subdomain = $splitedByDot[0];

0

Chúng tôi sử dụng chức năng này để xử lý nhiều tên miền phụnhiều tld cũng xử lý ip và localhost

function analyse_host($_host)
    {
        $my_host   = explode('.', $_host);
        $my_result = ['subdomain' => null, 'root' => null, 'tld' => null];

        // if host is ip, only set as root
        if(filter_var($_host, FILTER_VALIDATE_IP))
        {
            // something like 127.0.0.5
            $my_result['root'] = $_host;
        }
        elseif(count($my_host) === 1)
        {
            // something like localhost
            $my_result['root'] = $_host;
        }
        elseif(count($my_host) === 2)
        {
            // like jibres.com
            $my_result['root'] = $my_host[0];
            $my_result['tld']  = $my_host[1];
        }
        elseif(count($my_host) >= 3)
        {
            // some conditons like
            // ermile.ac.ir
            // ermile.jibres.com
            // ermile.jibres.ac.ir
            // a.ermile.jibres.ac.ir

            // get last one as tld
            $my_result['tld']  = end($my_host);
            array_pop($my_host);

            // check last one after remove is probably tld or not
            $known_tld    = ['com', 'org', 'net', 'gov', 'co', 'ac', 'id', 'sch', 'biz'];
            $probably_tld = end($my_host);
            if(in_array($probably_tld, $known_tld))
            {
                $my_result['tld'] = $probably_tld. '.'. $my_result['tld'];
                array_pop($my_host);
            }

            $my_result['root'] = end($my_host);
            array_pop($my_host);

            // all remain is subdomain
            if(count($my_host) > 0)
            {
                $my_result['subdomain'] = implode('.', $my_host);
            }
        }

        return $my_result;
    }

0

Giả sử hiện tại url = sub.example.com

    $ host = array_reverse (boom ('.', $ _SERVER ['SERVER_NAME']));

    if (count ($ host)> = 3) {
       echo "Tên miền chính là =". $ host [1]. ".". $ host [0]. "& subdomain is =". $ host [2];
       // Tên miền chính là = example.com & tên miền phụ is = sub
    } khác {
       echo "Tên miền chính là =". $ host [1]. ".". $ host [0]. "& subdomain not found";
       // "Không tìm thấy tên miền chính là = example.com & tên miền phụ";
    }


-3

Nếu bạn chỉ muốn những gì đến trước kỳ đầu tiên:

list($sub) = explode('.', 'en.example.com', 2);

Điều gì sẽ xảy ra nếu có một trình xử lý giao thức ở đầu, chẳng hạn như http: //, https: //, ftp: //, v.v ...? ;)
Jared Farrish

@Jared, không có giao thức nào trong chuỗi mà anh ấy đang tìm cách phân tích cú pháp ... Nhưng nếu có, tôi sẽ sử dụng parse_url()để trích xuất máy chủ.
Matthew

Vì vậy, chúng tôi đã cung cấp hai cách tiếp cận sẽ phù hợp trong các bối cảnh khác nhau.
Jared Farrish

Về cơ bản, tôi rất vui vì ai đó đã không đăng câu trả lời regex (chưa). Chưa kể dòng cuối cùng của câu trả lời của tôi cũng hoàn thành điều tương tự như của bạn.
Jared Farrish

Và nếu tên máy chủ là en.example.co.uk?
Marc B
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.