ฟังก์ชัน PHP เพื่อรับโดเมนย่อยของ URL


107

มีฟังก์ชันใน PHP เพื่อรับชื่อโดเมนย่อยหรือไม่?

ในตัวอย่างต่อไปนี้ฉันต้องการรับส่วน "en" ของ URL:

en.example.com

6
คุณมี URL เป็นสตริงที่เก็บไว้ในตัวแปรหรือ URL นี้มาจากไหน? บริบทคืออะไร? กรุณาอธิบายให้ละเอียด
Felix Kling

คุณไม่สามารถใช้นิพจน์ทั่วไปที่ทำสิ่งที่ชอบ(^|://)(.*)\.และจับภาพได้.*หรือไม่? ฉันค่อนข้างดูดทั้ง php และ regex แต่ก็อยู่ในใจ
corsiKa

สิ่งที่ควรได้รับen.foo.bar.example.comหรือen.example.co.uk?
ÁlvaroGonzález

parse_url สามารถช่วยได้
Swapnil

คำตอบ:


132

นี่เป็นวิธีแก้ปัญหาแบบบรรทัดเดียว:

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

หรือใช้ตัวอย่างของคุณ:

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

แก้ไข: แก้ไข "ตัวแปรเท่านั้นที่ควรถูกส่งผ่านโดยการอ้างอิง" โดยการเพิ่มวงเล็บคู่


แก้ไข 2 : เริ่มจากPHP 5.4คุณสามารถทำได้:

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

17
ควรส่งผ่านตัวแปรโดยการอ้างอิงเท่านั้น
Tamás Pap

8
วันนี้คุณทำexplode(...)[0]แทนการใช้กะได้หรือไม่? ไม่ได้รับ PHPing มาหลายปีแล้ว ..
Tor Valamo

ข้อผิดพลาด:Strict Standards: Only variables should be passed by reference.
จัสติน

1
ค่อนข้างแน่ใจว่าคุณสามารถ (ระเบิด (... )) [0] แม้ว่าควรจะทำงานบนอาร์เรย์ส่งคืนแทนการใช้ฟังก์ชัน paranthesis (ก่อน 5.4)
Garet Claborn

3
วิธีนี้จะใช้ไม่ได้ในกรณีที่มีคนพิมพ์www.en.example.comและจะกลับมาwwwเป็นโดเมนย่อย
lolbas

65

ใช้ฟังก์ชันparse_url

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

$parsedUrl = parse_url($url);

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

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

สำหรับหลายโดเมนย่อย

$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 - วิธีนี้ช่วยแก้ปัญหาของโดเมนย่อยหลาย ๆ โดเมนเช่น usa.en.example.com ได้หรือไม่ แค่สงสัย (คำตอบของตัวเองไม่ได้ btw)
Jared Farrish

@ Jared เพิ่งเพิ่มโซลูชันในการตรวจหาโดเมนย่อยหลายรายการ
Mike Lewis

1
@ ไมค์ - ใช้กับ tx.usa.en.example.com ได้ไหม (หรือscience.news.bbc.co.uk )? (btw นั่นไม่ใช่ลิงค์ที่ใช้งานได้เป็นเพียงตัวอย่างแม้ว่า news.bbc.co.uk จะใช้งานได้)
Jared Farrish

4
ซึ่งใช้ได้กับทุกสิ่งที่มี TLD 'word' เพียงคำเดียวเช่น net, com, biz เป็นต้นอย่างไรก็ตามเมื่อจัดการกับ co.uk ก็ไม่ได้ เท่าที่เห็นนี่นี้เป็นจริงปัญหาที่ยากที่จะแก้
Mike Lewis

2
สิ่งนี้จะล้มเหลวหากไม่มีโดเมนย่อยเลย
raveren

32

คุณสามารถทำได้โดยรับชื่อโดเมนก่อน (เช่น sub.example.com => example.co.uk) จากนั้นใช้ strstr เพื่อรับโดเมนย่อย

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

ผลลัพธ์:

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

2
นี่ดูเหมือนจะเป็นทางออกที่ดีที่สุดเนื่องจากยังอนุญาตให้ใช้โดเมนที่ไม่มีโดเมนย่อยแทนที่จะเรียกใช้ชื่อโดเมนอีกครั้งเนื่องจากโดเมนย่อยเป็นส่วนก่อนจุดแรก มีประโยชน์มากสำหรับการตรวจสอบการมีอยู่ของโดเมนย่อย
Karl MW

ฉันต้องการรับโดเมน "ฐาน" (โดยไม่มีโดเมนย่อย) และฉันกำลังสร้างโซลูชันของตัวเองโดยการระเบิดโฮสต์และรับองค์ประกอบสุดท้ายของอาร์เรย์ด้วยการforวนซ้ำ แต่ฉันต้องตรวจสอบความยาว (เพื่อตรวจสอบว่า เป็นส่วนหนึ่งของโดเมนเช่น "co.uk") อันที่จริงวิธีแก้ปัญหาของคุณง่ายกว่าที่ฉันทำอยู่มาก Regex ช่วยชีวิตขอบคุณ!
Yoone

1
เยี่ยมมาก .. ใช้งานได้ดีกับโดเมนและโดเมนย่อยทุกประเภท .. ดีจัง
จอน

2
ในขณะที่การแก้ปัญหานี้เป็นระเบียบมากและอาจทำงานในเกือบทุกกรณีจะต้องทราบว่าชื่อโดเมนอาจมีมากกว่า 6 ตัวอักษรเช่นpvt.k12.ma.us, หรือแม้กระทั่งhealth.vn k12.ak.usนอกจากนี้ชื่อโดเมนอาจใช้ชุดอักขระจีนหรือรัสเซียดังนั้นส่วนนิพจน์ทั่วไป[a-z\.]{2,6}จะไม่ตรงกับชื่อโดเมน ลองดูที่นี่เพื่อดูชื่อโดเมน: publicsuffix.org/list
pomeh


7

เนื่องจากแหล่งที่มาที่เชื่อถือได้เพียงแหล่งเดียวสำหรับส่วนต่อท้ายโดเมนคือผู้รับจดทะเบียนโดเมนคุณจึงไม่สามารถค้นหาโดเมนย่อยได้หากไม่มีความรู้ มีรายการที่มีคำต่อท้ายทุกโดเมนที่เป็นhttps://publicsuffix.org เว็บไซต์นี้ยังเชื่อมโยงไปยังห้องสมุด PHP A: https://github.com/jeremykendall/php-domain-parser

โปรดดูตัวอย่างด้านล่าง ฉันยังเพิ่มตัวอย่างสำหรับ en.test.co.uk ซึ่งเป็นโดเมนที่มีคำต่อท้ายหลายคำ (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;


4

เพียงแค่ ...

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

แค่อ่าน$ match [1]

ตัวอย่างการทำงาน

ทำงานได้อย่างสมบูรณ์กับรายการ URL นี้

$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
ปล - ฉันไม่รู้ว่ามันเขียนเป็นข้อความภาษารัสเซียว่าอะไร เพิ่งใช้คำพูดสบาย ๆ จากru.wikipedia.org ;)
Kamafeather

มันเป็นภาษายูเครนไม่ใช่เหรอ? .uaคือรหัสประเทศสำหรับยูเครน
nalply

ไม่ เพียงแค่ผสมข้อมูล แต่ฉันไม่แน่ใจฉันไม่ดีพอที่จะแยกแยะออก;)
Kamafeather

3
ในส่วนที่เกี่ยวกับภาษารัสเซีย Google แปลภาษาจากภาษารัสเซียเป็นภาษาอังกฤษจะกลับมาเป็น "ค่านิยมที่เผยแพร่แล้ว" (เผื่อว่าจะมีใครอยากรู้อยากเห็นเหมือนฉัน)
Jeremy Harris

@Kamafeather นี่ดูกันกระสุน วิธีใดที่จะได้รับ$match[1]ส่วน? $match[0]ดูเหมือนไม่จำเป็น
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
มีวิธีที่ดีกว่าในการตรวจหาโฮสต์ปัจจุบันโดยอัตโนมัติ (เช่น$_SERVER['HTTP_HOST']) จากนั้นอาศัยส่วนหัวผู้อ้างอิงที่สามารถปลอมแปลงได้โดยสมมติว่าเป็นแนวคิดทั่วไปที่อยู่เบื้องหลังคำตอบ
Matthew

ใช่ฉันใช้รหัสชิ้นเก่า ตัวอย่างยังคงยืนอยู่อย่างไรก็ตาม นั่นไม่ใช่ต้นตอของคำถาม
Jared Farrish

เพียงเพื่อเพิ่มความคิดเห็นเหล่านี้ด้านบนการใช้ $ _SERVER ['HTTP_HOST'] อาจไม่ได้ผลเนื่องจากอาจไม่มีการตั้งค่า
gmslzr

2

PHP 7.0: ใช้ฟังก์ชันระเบิดและสร้างรายการผลลัพธ์ทั้งหมด

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

ตัวอย่าง: sub.domain.com

echo $subdomain; 

ผลลัพธ์: ย่อย

echo $host;

ผลลัพธ์: โดเมน


คุณลืม TLD เช่น.co.uk- ตัวอย่างข้อมูลของคุณจะใช้ไม่ได้กับ TLD เหล่านี้
Adrian Preuss

1

สิ่งที่ฉันพบวิธีแก้ปัญหาที่สั้นและดีที่สุดคือ

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

จะทำให้เกิดข้อผิดพลาดอย่างเข้มงวด ไม่สามารถส่งเอาต์พุตของระเบิดไปยัง array_shift ได้โดยตรง
YAAK

1

สำหรับผู้ที่ได้รับ 'ข้อผิดพลาด: มาตรฐานที่เข้มงวด: ควรส่งผ่านตัวแปรเท่านั้นโดยการอ้างอิง' ใช้แบบนี้:

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


นั่นไม่ใช่คำถาม แต่ขอบคุณสำหรับข้อมูลของคุณ
FazoM


1

ไม่มีโซลูชันแบบไดนามิก 100% จริง ๆ - ฉันเพิ่งพยายามคิดออกเช่นกันและเนื่องจากส่วนขยายโดเมน (DTL) ที่แตกต่างกันงานนี้จะยากมากหากไม่ต้องแยกวิเคราะห์ส่วนขยายเหล่านี้ทั้งหมดและตรวจสอบทุกครั้ง:

.com vs .co.uk vs org.uk

ตัวเลือกที่น่าเชื่อถือที่สุดคือการกำหนดค่าคงที่ (หรือรายการฐานข้อมูลเป็นต้น) ที่เก็บชื่อโดเมนจริงและลบออกจากการ$_SERVER['SERVER_NAME']ใช้งานsubstr()

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, '.');

}

ตอนนี้หากคุณใช้ฟังก์ชันนี้ภายใต้http://test.mymaindomain.co.ukมันจะให้คุณtestหรือถ้าคุณมีโดเมนย่อยหลายระดับhttp://another.test.mymaindomain.co.ukคุณจะได้รับanother.test- เว้นแต่คุณจะอัปเดตไฟล์DOMAIN.

ฉันหวังว่านี่จะช่วยได้.



1

การใช้ regex ฟังก์ชันสตริง parse_url () หรือการรวมกันไม่ใช่วิธีแก้ปัญหาที่แท้จริง เพียงทดสอบโซลูชันที่เสนอด้วยโดเมนtest.en.example.co.ukจะไม่มีผลลัพธ์ที่ถูกต้อง

วิธีการแก้ปัญหาที่ถูกต้องคือแพคเกจการใช้งานที่แยกโดเมนสาธารณะรายการต่อท้าย ฉันขอแนะนำTLDExtractนี่คือโค้ดตัวอย่าง:

$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

นี่คือวิธีแก้ปัญหาของฉันมันใช้ได้กับโดเมนที่พบบ่อยที่สุดคุณสามารถใส่อาร์เรย์ของส่วนขยายได้ตามที่คุณต้องการ:

$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

ฉันรู้ว่าฉันเล่นเกมช้ามาก แต่นี่ไป

สิ่งที่ฉันทำคือรับตัวแปรเซิร์ฟเวอร์ HTTP_HOST ( $_SERVER['HTTP_HOST']) และจำนวนตัวอักษรในโดเมน (ดังนั้นexample.comมันจะเป็น 11)

จากนั้นฉันใช้substrฟังก์ชันเพื่อรับโดเมนย่อย ฉันทำ

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

ฉันตัดสตริงย่อยออกที่ 12 แทนที่จะเป็น 11 เนื่องจากสตริงย่อยเริ่มต้นที่ 1 สำหรับพารามิเตอร์ที่สอง ตอนนี้ถ้าคุณป้อน test.example.com ค่าของ$subdomainจะเป็นtestจะ

สิ่งนี้ดีกว่าการใช้explodeเพราะถ้าโดเมนย่อยมี.อยู่การดำเนินการนี้จะไม่ตัดออก


ตำแหน่งเริ่มต้น "0" หายไปในคำตอบของคุณ $ subdomain = substr ($ _ SERVER ['HTTP_HOST'], 0, $ numberOfLettersInSubdomain);
เจมี่

0

หากคุณใช้ drupal 7

สิ่งนี้จะช่วยคุณ:

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

จาก PHP 5.3 คุณสามารถใช้strstr ()กับพารามิเตอร์จริง

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

สิ่งนี้จะใช้ได้เฉพาะเมื่อไม่มีการwwwเริ่มต้นสตริง วิธีการเล็กน้อยเกินไป
FooBar

สิ่งนี้ทำให้สิ่งต่าง ๆ ง่ายขึ้นสำหรับนักพัฒนาคนอื่น ๆ ในทีมฉันควรใช้สิ่งนี้มากกว่า reg exp ขั้นสูง หากคุณต้องการตัด www ให้ใช้ trim ($ s, 'www'); หรือปรับให้เข้ากับตรรกะทางธุรกิจของคุณ ...
tasmaniski

1
เพื่อประโยชน์ครบถ้วนwww เป็นจริงโดเมนย่อย โดยทั่วไปมักใช้นามแฝงเป็นชื่อโดเมนด้วยเหตุผลทางประวัติศาสตร์
Levi Morrison

0

ลองนี่ ...

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

ฉันคิดว่ามันจะมีประโยชน์มากขึ้นสำหรับ OP และผู้เยี่ยมชมคนต่อไปเมื่อคุณเพิ่มคำอธิบายให้กับความตั้งใจของคุณ
ผู้สื่อข่าว

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
บรรทัด # 7 ควรเป็น$host = explode('.', isset($parsedUrl['path']) ? $parsedUrl['path'] : $parsedUrl['host']);
Kal

0

คุณสามารถใช้สิ่งนี้ได้เช่นกัน

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


0

เราใช้ฟังก์ชันนี้เพื่อจัดการโดเมนย่อยหลายโดเมนและtld หลายตัวก็จัดการ ip และ 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

สมมติว่า url ปัจจุบัน = sub.example.com

    $ host = array_reverse (ระเบิด ('.', $ _SERVER ['SERVER_NAME']));

    ถ้า (count ($ host)> = 3) {
       echo "โดเมนหลักคือ =". $ host [1]. ".". $ host [0]. "& subdomain คือ =". $ host [2];
       // โดเมนหลักคือ = example.com & โดเมนย่อยคือ = ย่อย
    } else {
       echo "Main domain is =". $ host [1]. ".". $ host [0]. "& subdomain not found";
       // "โดเมนหลักคือ = example.com & ไม่พบโดเมนย่อย";
    }


-3

หากคุณต้องการเฉพาะสิ่งที่มาก่อนช่วงเวลาแรก:

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

จะเกิดอะไรขึ้นถ้ามีตัวจัดการโปรโตคอลที่จุดเริ่มต้นเช่น http: //, https: //, ftp: // ฯลฯ ... ? ;)
Jared Farrish

@ จาเร็ดไม่มีโปรโตคอลในสตริงที่เขาต้องการแยกวิเคราะห์ ... แต่ถ้ามีฉันจะใช้parse_url()เพื่อแยกโฮสต์
Matthew

ดังนั้นเราจึงจัดเตรียมสองแนวทางซึ่งจะเหมาะสมในบริบทที่แตกต่างกัน
Jared Farrish

โดยหลักแล้วฉันแค่ดีใจที่มีคนไม่ได้โพสต์คำตอบ regex (ยัง) ไม่ต้องพูดถึงบรรทัดสุดท้ายของคำตอบของฉันก็สำเร็จเช่นเดียวกับที่คุณทำ
Jared Farrish

และถ้าชื่อโฮสต์คือ en.example.co.uk?
Marc B
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.