Bir URL'nin alt etki alanını almak için PHP işlevi


107

PHP'de alt etki alanının adını almak için bir işlev var mı?

Aşağıdaki örnekte, URL’nin "en" kısmını almak istiyorum:

en.example.com

6
Bir değişkende depolanan dize olarak bir URL'niz var mı veya bu URL nereden geliyor? Bağlam nedir? Lütfen detaylandırın.
Felix Kling

Böyle bir şey yapan (^|://)(.*)\.ve yakalayan bir normal ifade kullanamaz .*mısın? Hem php hem de regex'te emmeyi tercih ederim, ancak bu akla geliyor.
corsiKa

İçeri ne girmeli en.foo.bar.example.comya da en.example.co.uk?
Álvaro González

parse_url ayrıca yardımcı olabilir
Swapnil

Yanıtlar:


132

İşte tek satırlık bir çözüm:

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

Veya örneğinizi kullanarak:

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

DÜZENLEME: Çift parantez eklenerek "yalnızca değişkenler referans olarak iletilmelidir" düzeltildi.


DÜZENLEME 2 : PHP 5.4'ten başlayarak şunları yapabilirsiniz:

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

17
Yalnızca değişkenler referans olarak aktarılmalıdır.
Tamás Pap

8
explode(...)[0]Bugünlerde vardiya kullanmak yerine sadece yapamıyor musun? Birkaç yıldır PHP kullanmıyor ..
Tor Valamo

Hata:Strict Standards: Only variables should be passed by reference.
Justin

1
eminim ki (patlayabilir (...)) [0] işlev parantezi yerine dönüş dizisi üzerinde çalışıyor olmalı (5.4'ten önce)
Garet Claborn

3
Bu çözüm, birinin yazması durumunda işe yaramayacak www.en.example.comve bu nedenle wwwalt alan adı olarak dönecektir .
lolbas

65

Parse_url işlevini kullanır .

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

$parsedUrl = parse_url($url);

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

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

Birden çok alt alan için

$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 - Bu, usa.en.example.com gibi birden çok alt alan adı sorununu çözüyor mu? Sadece merak ediyorum (kendi cevabım değil, btw).
Jared Farrish

@Jared, birden fazla alt alanı algılamak için bir çözüm ekledi.
Mike Lewis

1
@Mike - Bu tx.usa.en.example.com ile çalışacak mı? (veya science.news.bbc.co.uk )? (btw, bu çalışan bir bağlantı değil, sadece bir örnek, ancak news.bbc.co.uk işe yarıyor)
Jared Farrish

4
Bu, net, com, biz vb. Gibi tek bir "kelime" TLD'si olan her şey için işe yarar. Ancak, örneğin co.uk ile uğraşırken işe yaramaz. Görüldüğü gibi burada bu çözmek için daha sert bir sorun aslında.
Mike Lewis

2
bu, alt alan adı yoksa da başarısız olur.
raveren

32

Bunu, önce alan adını (örn. Sub.example.com => example.co.uk) alarak ve ardından alt alanları almak için strstr kullanarak yapabilirsiniz.

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

Çıktılar:

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

2
Bu, alt alan adı ilk noktadan önceki kısım olduğu için alan adını yeniden düzenlemek yerine, alt alan adı olmayan alanlara da izin verdiği için en iyi çözüm gibi görünüyor. Bir alt alanın varlığını kontrol etmek için çok kullanışlıdır.
Karl MW

"Temel" etki alanını (alt etki alanı olmadan) almam gerekiyordu ve ana bilgisayarı patlatarak ve dizinin son öğelerini bir fordöngü ile alarak kendi çözümümü oluşturuyordum , ancak uzunluklarını kontrol etmeliydim ( "co.uk" gibi etki alanının bir parçasıydı). Aslında, çözümünüz benim yaptığımdan çok daha basit. Regex hayat kurtarır, teşekkürler!
Yoone

1
Harika .. bu, tüm alan türleri ve alt alanlar için çok iyi çalışıyor .. güzel.
jon

2
Bu çözüm çok düzgün ve çalışabilir ise neredeyse tüm durumlarda, etki adları 6'dan fazla karakter gibi sahip olabileceğinin farkında olmanız pvt.k12.ma.us, health.vnhatta k12.ak.us. Ayrıca, alan adları Çince veya Rusça karakter seti kullanıyor olabilir, böylece normal ifade kısmı [a-z\.]{2,6}bunlarla eşleşmez. Örnek alan adına sahip olmak için buraya göz atın: 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

Etki alanı sonekleri için tek güvenilir kaynak etki alanı kayıt şirketleri olduğundan, alt etki alanını onların bilgisi olmadan bulamazsınız. Https://publicsuffix.org adresinde tüm alan son eklerini içeren bir liste bulunmaktadır . Bu site aynı zamanda bir PHP kitaplığına da bağlanır: https://github.com/jeremykendall/php-domain-parser .

Lütfen aşağıda bir örnek bulun. Ayrıca çoklu sonek (co.uk) olan bir alan olan en.test.co.uk için örnek ekledim.

<?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

En basit ve en hızlı çözüm.

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

4

Basitçe ...

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

Sadece $ match [1] oku

Çalışma örneği

Bu url listesiyle mükemmel çalışıyor

$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
Not - Rusça metinde ne yazdığına dair hiçbir fikrim yok. Sadece bazı gündelik sözlerini yanlış ru.wikipedia.org ;)
Kamafeather

Ukraynalı değil mi? .uaUkrayna için ülke kodudur.
nalply

Hayır! Sadece karışık bilgiler. Ama emin değilim, onları ayırt edecek kadar iyi değilim;)
Kamafeather

3
Rusça ile ilgili olarak, Rusça'dan İngilizceye bir google çevirisi "yayınlanmış değerler" olarak geri dönüyor (eğer biri benim gibi merak ediyorduysa)
Jeremy Harris

@Kamafeather bu kurşun geçirmez görünüyor. Rolü almanın bir yolu var $match[1]mı? $match[0]gereksiz görünüyor.
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']Cevabın arkasındaki genel fikrin bu olduğunu varsayarak , mevcut ana bilgisayarı (gibi ) otomatik olarak algılamanın ve ardından sahte bir yönlendirme başlığına güvenmenin daha iyi yolları vardır .
Matthew

Doğru, eski bir kod kullanıyordum. Ancak örnek hala geçerli. Sorunun kökü bu değil.
Jared Farrish

Sadece yukarıdaki yorumları eklemek için, $ _SERVER ['HTTP_HOST'] 'a güvenmek etkili olmayabilir, çünkü ayarlanamama ihtimali vardır.
gmslzr

2

PHP 7.0: Patlatma işlevini kullanarak tüm sonuçların bir listesini oluşturun.

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

Örnek: sub.domain.com

echo $subdomain; 

Sonuç: alt

echo $host;

Sonuç: etki alanı


.co.ukTLD'lerin beğenisini unutuyorsunuz - pasajınız bu TLD'lerle çalışmayacak
Adrian Preuss

1

En iyi ve kısa çözümü bulduğum şey

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

Kesin hataya neden olur. Patlatmanın çıktısı doğrudan array_shift'e geçirilemez.
YAAK

1

'Hata: Katı Standartlar: Yalnızca değişkenler referans olarak iletilmelidir.' Bunun gibi kullanın:

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


Soru bu değildi, ama girdiniz için teşekkürler.
FazoM


1

Gerçekten% 100 dinamik bir çözüm yok - Ben de anlamaya çalışıyorum ve farklı alan uzantıları (DTL) nedeniyle bu görev, tüm bu uzantıları gerçekten ayrıştırıp her seferinde kontrol etmeden gerçekten zor olurdu:

.com vs .co.uk vs org.uk

En güvenilir seçenek, gerçek alan adını saklayan bir sabit (veya veritabanı girişi vb.) Tanımlamak ve onu alan adından kaldırmaktır. $_SERVER['SERVER_NAME'] kullanıyorsubstr()

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

}

Şimdi bu işlevi kullanıyorsanız http://test.mymaindomain.co.uk, size verecektest veya birden fazla alt alan düzeyiniz http://another.test.mymaindomain.co.ukvarsa, alacaksınız another.test- tabii ki,DOMAIN .

Umarım bu yardımcı olur.


1

Basitçe

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


1

Regex, string fonksiyonları, parse_url () veya bunların kombinasyonlarını kullanmak gerçek bir çözüm değildir. Önerilen çözümlerden herhangi birini alan adı ile test test.en.example.co.ukedin, herhangi bir doğru sonuç olmayacaktır.

Doğru çözüm, etki alanını Genel Son Ek Listesi ile ayrıştıran kullanım paketidir . Ben tavsiye TLDExtract , burada örnek kod:

$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

bu benim çözümüm, en yaygın alan adlarıyla çalışıyor, ihtiyacınız olan uzantı dizisini sığdırabilirsiniz:

$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

Oyuna gerçekten geç kaldığımı biliyorum ama işte başlıyor.

Yaptığım şey, HTTP_HOST sunucu değişkenini ( $_SERVER['HTTP_HOST']) ve etki alanındaki harf sayısını almaktı (yani example.com11 olurdu).

Daha sonra substralt alan adını almak için işlevi kullandım . yaptım

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

Alt dizeyi 11 yerine 12'de kestim çünkü alt dizeler ikinci parametre için 1'den başlıyor. Yani şimdi test.example.com'u girdiyseniz, değeri $subdomainolacaktır test.

Bu kullanmaktan daha iyidir explodeçünkü eğer alt alan adında bir .varsa, bu onu kesmeyecektir.


Cevabınızda "0" başlangıç ​​konumu eksikti. $ subdomain = substr ($ _ SERVER ['HTTP_HOST'], 0, $ numberOfLettersInSubdomain);
Jamie

0

drupal 7 kullanıyorsanız

Bu sana yardım edecek:

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 itibaren kullanabileceğiniz strstr () ile gerçek parametre

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

Bu sadece wwwdizge başlangıcında hiç yoksa çalışır . Biraz fazla önemsiz bir yaklaşım.
FooBar

Bu, ekipteki diğer geliştiriciler için işleri basitleştirir, bunu bazı gelişmiş kayıt exp'ları yerine kullanmayı tercih ederim. Www kırpmak istiyorsanız trim ($ s, 'www') kullanın; ya da sadece iş mantığınıza göre ayarlayın ...
tasmaniski

1
Tamlık aşkına, www olduğu aslında bir alt alan adıdır. Yalnızca tarihsel nedenlerden dolayı alan adının takma adıdır.
Levi Morrison

0

Bunu dene...

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

Bence, niyetinize bazı açıklamalar eklediğinizde, OP ve diğer ziyaretçiler için daha yararlı olacağını düşünüyorum.
Muhabir

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. satır$host = explode('.', isset($parsedUrl['path']) ? $parsedUrl['path'] : $parsedUrl['host']);
Kal

0

bunu da kullanabilirsin

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

0

Bunun gibi bir şey yapıyorum

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

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

$subdomain = $splitedByDot[0];

0

Bu işlevi birden çok alt alan adını işlemek için kullanıyoruz ve birden çok tld ayrıca ip ve localhost'u da işliyor.

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

Geçerli url = alt.örnek.com varsayalım

    $ ana bilgisayar = array_reverse (patlat ('.', $ _SERVER ['SERVER_NAME']));

    if (count ($ host)> = 3) {
       echo "Ana alan adı =". $ host [1]. ".". $ host [0]. "& subdomain =". $ host [2];
       // Ana alan = example.com & alt alan = = alt
    } Başka {
       echo "Ana alan adı =". $ host [1]. ".". $ host [0]. "& subdomain bulunamadı";
       // "Ana etki alanı = example.com & alt etki alanı bulunamadı";
    }


-3

Sadece ilk dönemden önce olanı istiyorsanız:

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

Ya başlangıçta http: //, https: //, ftp: //, vb. Gibi bir protokol işleyicisi varsa? ;)
Jared Farrish

@Jared, ayrıştırmak istediği dizede protokol yok ... Ama olsaydı parse_url(), ana bilgisayarı çıkarmak için kullanırdım .
Matthew

Bu nedenle, farklı bağlamlarda uygun olacak iki yaklaşım sağladık.
Jared Farrish

Temel olarak, birisinin (henüz) normal ifade yanıtı göndermemesine sevindim. Cevabımın son satırının da sizinki ile aynı şeyi yaptığından bahsetmiyorum bile.
Jared Farrish

Ve ana bilgisayar adı en.example.co.uk ise?
Marc B
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.