Funkcja PHP do pobrania subdomeny adresu URL

107

Czy w PHP jest funkcja pobierania nazwy subdomeny?

W poniższym przykładzie chciałbym uzyskać część „en” adresu URL:

en.example.com
Damiano
źródło
6
Czy masz adres URL jako ciąg przechowywany w zmiennej lub skąd pochodzi ten adres URL? Jaki jest kontekst? Proszę rozwinąć.
Felix Kling
Czy nie mógłbyś użyć wyrażenia regularnego, które robi coś podobnego (^|://)(.*)\.i przechwytuje .*? Wolę ssać zarówno php, jak i regex, ale przychodzi mi to na myśl.
corsiKa
Co powinno się dostać en.foo.bar.example.comlub en.example.co.uk?
Álvaro González
parse_url również może pomóc
Swapnil

Odpowiedzi:

132

Oto jedno liniowe rozwiązanie:

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

Lub na przykładzie:

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

EDYCJA: Naprawiono „tylko zmienne powinny być przekazywane przez odniesienie” poprzez dodanie podwójnych nawiasów.


EDYCJA 2 : Począwszy od PHP 5.4 możesz po prostu:

explode('.', 'en.example.com')[0];
Michael Deal
źródło
17
Tylko zmienne powinny być przekazywane przez odniesienie.
Tamás Pap
8
Czy w explode(...)[0]dzisiejszych czasach nie jesteś w stanie po prostu zrobić zamiast używać zmiany? Nie PHPing od kilku lat ...
Tor Valamo,
Błąd:Strict Standards: Only variables should be passed by reference.
Justin,
1
całkiem pewny, że możesz (eksplodować (...)) [0] jednak, powinien działać na tablicy wyników zamiast na parantezie funkcji (przed 5.4)
Garet Claborn
3
To rozwiązanie nie zadziała, jeśli ktoś wpisze www.en.example.comi wróci wwwjako subdomena.
lolbas
65

Używa funkcji parse_url .

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

$parsedUrl = parse_url($url);

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

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

Dla wielu subdomen

$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
źródło
@Mike Lewis - czy rozwiązuje to problem wielu subdomen, takich jak usa.pl.example.com? Po prostu się zastanawiam (przy okazji moja własna odpowiedź nie).
Jared Farrish
@Jared, właśnie dodałem rozwiązanie do wykrywania wielu subdomen.
Mike Lewis
1
@Mike - Czy to zadziała z tx.usa.en.example.com? (lub science.news.bbc.co.uk )? (btw, to nie działa link, tylko przykład, chociaż news.bbc.co.uk działa)
Jared Farrish
4
Działa to w przypadku wszystkiego, co ma jedno „słowo” TLD, jak np. Net, com, biz itp. Jednak w przypadku np. Co.uk tak nie jest. Jak widać tutaj W rzeczywistości jest to trudniejszy problem do rozwiązania.
Mike Lewis
2
to również zawodzi, jeśli w ogóle nie ma subdomeny.
raveren
32

Możesz to zrobić, najpierw pobierając nazwę domeny (np. Sub.example.com => example.co.uk), a następnie używając strstr, aby uzyskać subdomeny.

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

Wyjścia:

0 => sub1.sub2
1 => sub1
2 =>
3 => sub1.sub2.sub3
4 => sub1.sub2.sub3
5 => sub1.sub2
mazon
źródło
2
Wydaje się, że jest to najlepsze rozwiązanie, ponieważ pozwala również na domeny bez subdomeny, zamiast ponownego wybierania nazwy domeny jako subdomeny będącej częścią przed pierwszą kropką. Bardzo przydatne do sprawdzania istnienia subdomeny.
Karl MW,
Musiałem zdobyć domenę „podstawową” (bez subdomeny) i tworzyłem własne rozwiązanie, eksplodując hosta i pobierając forpętlę ostatnich elementów tablicy , ale musiałem sprawdzić ich długość (aby wykryć, czy były częścią domeny jak „co.uk”). W rzeczywistości twoje rozwiązanie jest znacznie prostsze niż to, co robiłem. Regex ratuje życie, dzięki!
Yoone
1
Świetnie… to działa tak dobrze dla wszystkich typów domen i subdomen… fajnie.
jon
2
podczas gdy takie rozwiązanie jest bardzo schludny i może pracować w prawie wszystkich przypadkach, należy pamiętać, że nazwy domen może mieć więcej niż 6 znaków, jak pvt.k12.ma.us, health.vnlub nawet k12.ak.us. Ponadto nazwy domen mogą używać zestawu znaków chińskich lub rosyjskich, więc część wyrażenia regularnego [a-z\.]{2,6}nie będzie do nich pasować. Sprawdź tutaj, aby zobaczyć przykładową nazwę domeny: publicsuffix.org/list
pomeh
12

http://php.net/parse_url

<?php
  $url = 'http://user:[email protected]/path?argument=value#anchor';
  $array=parse_url($url);
  $array['host']=explode('.', $array['host']);

  echo $array['host'][0]; // returns 'en'
?>
JMW
źródło
7

Ponieważ jedynym wiarygodnym źródłem sufiksów domen są rejestratorzy domen, nie możesz znaleźć subdomeny bez ich wiedzy. Lista wszystkich sufiksów domen znajduje się na https://publicsuffix.org . Ta strona zawiera również linki do biblioteki PHP: https://github.com/jeremykendall/php-domain-parser .

Poniżej przykład. Dodałem również przykład dla en.test.co.uk, który jest domeną z wieloma sufiksami (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;
Sascha Frinken
źródło
5

Najprostsze i najszybsze rozwiązanie.

$sSubDomain = str_replace('.example.com','',$_SERVER['HTTP_HOST']);
Arjen
źródło
4

Po prostu...

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

Po prostu przeczytaj $ match [1]

Przykład roboczy

Działa doskonale z tą listą adresów 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);
}
Kamafeather
źródło
2
PS - Nie mam pojęcia, co jest napisane w rosyjskim tekście. Właśnie wziąłem kilka przypadkowych słów z ru.wikipedia.org ;)
Kamafeather
Czy to nie ukraińskie? .uato kod kraju dla Ukrainy.
nalply
Nie. Po prostu pomieszane informacje. Ale nie jestem pewien, nie jestem wystarczająco dobry, aby je rozróżnić;)
Kamafeather
3
Jeśli chodzi o język rosyjski, tłumacz Google z rosyjskiego na angielski powraca jako „opublikowane wartości” (na wypadek, gdyby ktoś był ciekawy, tak jak ja)
Jeremy Harris
@Kamafeather to wygląda na kuloodporne. Jest jakiś sposób, żeby po prostu dostać tę $match[1]rolę? $match[0]wydaje się niepotrzebne.
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, '.')); 
Jared Farrish
źródło
1
Istnieją lepsze sposoby automatycznego wykrywania bieżącego hosta (np. $_SERVER['HTTP_HOST']), A następnie poleganie na fałszywym nagłówku strony odsyłającej, zakładając, że na tym właśnie polega ogólna idea odpowiedzi.
Matthew
Racja, użyłem starego fragmentu kodu. Przykład jest jednak nadal aktualny. To nie jest źródło pytania.
Jared Farrish
Podsumowując powyższe komentarze, poleganie na $ _SERVER ['HTTP_HOST'] może nie być skuteczne, ponieważ istnieje prawdopodobieństwo, że nie zostanie ustawione.
gmslzr
2

PHP 7.0: Użycie funkcji eksploduj i utwórz listę wszystkich wyników.

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

Przykład: sub.domain.com

echo $subdomain; 

Wynik: sub

echo $host;

Wynik: domena

Jeacovy Gayle
źródło
Zapominasz o TLD .co.uk- Twój fragment nie będzie działał z tymi TLD
Adrian Preuss
1

Najlepsze i krótkie rozwiązanie znalazłem

array_shift(explode(".",$_SERVER['HTTP_HOST']));
Zulqurnain abbas
źródło
Spowoduje ścisły błąd. Dane wyjściowe rozbijania nie mogą być przekazywane bezpośrednio do przesunięcia_tablicy.
YAAK
1

Dla tych, którzy otrzymają komunikat „Błąd: ścisłe standardy: tylko zmienne powinny być przekazywane przez odniesienie”. Użyj w ten sposób:

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

Naseer
źródło
To nie było pytanie, ale dziękuję za wkład.
FazoM
1
$domain = 'sub.dev.example.com';
$tmp = explode('.', $domain); // split into parts
$subdomain = current($tmp);
print($subdomain);     // prints "sub"

Jak widać w poprzednim pytaniu: Jak zdobyć pierwszą subdomenę za pomocą PHP?

Społeczność
źródło
1

Tak naprawdę nie ma rozwiązania w 100% dynamicznego - właśnie próbowałem to rozgryźć, a ze względu na różne rozszerzenia domeny (DTL) zadanie to byłoby naprawdę trudne bez faktycznego analizowania wszystkich tych rozszerzeń i sprawdzania ich za każdym razem:

.com vs .co.uk vs org.uk

Najbardziej niezawodną opcją jest zdefiniowanie stałej (lub wpis w bazie danych itp.), Która przechowuje rzeczywistą nazwę domeny i usunięcie jej z $_SERVER['SERVER_NAME']używaniasubstr()

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

}

Teraz, jeśli używasz tej funkcji w ramach http://test.mymaindomain.co.uk, da ci ona testlub jeśli masz wiele poziomów subdomeny http://another.test.mymaindomain.co.uk, otrzymasz another.test- chyba że oczywiście zaktualizujesz DOMAIN.

Mam nadzieję, że to pomoże.

Sebastian Sulinski
źródło
1

Po prostu

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

Adam F.
źródło
1

Używanie wyrażeń regularnych, funkcji łańcuchowych, parse_url () lub ich kombinacji nie jest prawdziwym rozwiązaniem. Po prostu przetestuj dowolne z proponowanych rozwiązań z domeną test.en.example.co.uk, nie będzie żadnego poprawnego wyniku.

Prawidłowym rozwiązaniem jest użycie pakietu, który analizuje domenę z listą sufiksów publicznych . Polecam TLDExtract , oto przykładowy 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'
Oleksandr Fediashov
źródło
1

to jest moje rozwiązanie, działa z najpopularniejszymi domenami, możesz dopasować szereg rozszerzeń według potrzeb:

$SubDomain = explode('.', explode('|ext|', str_replace(array('.com', '.net', '.org'), '|ext|',$_SERVER['HTTP_HOST']))[0]);
Sergio Lopez Loya
źródło
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
Rahul Prasad
źródło
0

Wiem, że jestem naprawdę spóźniony na mecz, ale proszę bardzo.

To, co zrobiłem, to wziąłem zmienną serwera HTTP_HOST ( $_SERVER['HTTP_HOST']) i liczbę liter w domenie (więc example.combędzie to 11).

Następnie użyłem substrfunkcji, aby uzyskać subdomenę. Zrobiłem

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

Odcinam podciąg na 12 zamiast 11, ponieważ podciągi zaczynają się od 1 dla drugiego parametru. Więc teraz, jeśli wpiszesz test.example.com, wartość $subdomainbędzie test.

Jest to lepsze niż używanie, explodeponieważ jeśli subdomena ma w sobie znak ., nie spowoduje to odcięcia.

Pikolo
źródło
W Twojej odpowiedzi brakowało pozycji początkowej „0”. $ subdomena = substr ($ _ SERVER ['HTTP_HOST'], 0, $ numberOfLettersInSubdomain);
Jamie
0

jeśli używasz drupal 7

to ci pomoże:

global $base_path;
global $base_root;  
$fulldomain = parse_url($base_root);    
$splitdomain = explode(".", $fulldomain['host']);
$subdomain = $splitdomain[0];
mohanad
źródło
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 />';
Brynner Ferreira
źródło
0

Od PHP 5.3 możesz używać strstr () z prawdziwym parametrem

echo strstr($_SERVER["HTTP_HOST"], '.', true); //prints en
tasmaniski
źródło
To zadziała tylko wtedy, gdy nie ma wwwna początku łańcucha. Trochę zbyt banalne podejście.
FooBar
To upraszcza rzeczy innym programistom w zespole, wolałbym używać tego niż niektórych zaawansowanych reg exp. Jeśli chcesz przyciąć www, użyj trim ($ s, 'www'); lub po prostu dostosuj to do swojej logiki biznesowej ...
tasmaniski
1
Ze względu na kompletność www jest w rzeczywistości subdomeną. Jest po prostu często aliasowany do samej nazwy domeny ze względów historycznych.
Levi Morrison
0

Spróbuj tego...

$domain = 'en.example.com';
$tmp = explode('.', $domain);
$subdomain = current($tmp);
echo($subdomain);     // echo "en"
edCoder
źródło
Myślę, że byłoby to bardziej pomocne dla PO i dalszych gości, gdy dodasz jakieś wyjaśnienie do swoich zamiarów.
Reporter
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);
}
itsazzad
źródło
1
wiersz nr 7 powinien być$host = explode('.', isset($parsedUrl['path']) ? $parsedUrl['path'] : $parsedUrl['host']);
Kal
0

możesz też tego użyć

echo substr($_SERVER['HTTP_HOST'], 0, strrpos($_SERVER['HTTP_HOST'], '.', -5));
XIMvad
źródło
0

Robię coś takiego

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

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

$subdomain = $splitedByDot[0];
Sheik Althaf
źródło
0

Używamy tej funkcji do obsługi wielu subdomen, a wiele tld obsługuje również adresy IP i 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;
    }
Javad Adib
źródło
0

Załóżmy, że aktualny adres URL = sub.example.com

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

    if (count ($ host)> = 3) {
       echo "Domena główna to =". $ host [1]. ".". $ host [0]. "& subdomena to =". $ host [2];
       // Domena główna to = example.com & subdomena to = sub
    } else {
       echo "Domena główna to =". $ host [1]. ".". $ host [0]. "Nie znaleziono & subdomeny";
       // "Domena główna to = example.com & nie znaleziono subdomeny";
    }

Khorshed Alam Shohel
źródło
-3

Jeśli chcesz tylko tego, co nastąpi przed pierwszym okresem:

list($sub) = explode('.', 'en.example.com', 2);
Mateusz
źródło
Co jeśli na początku znajduje się program obsługi protokołu, taki jak http: //, https: //, ftp: //, itd ...? ;)
Jared Farrish
@Jared, nie ma protokołu w ciągu, który chce przeanalizować ... Ale gdyby istniał, użyłbym parse_url()do wyodrębnienia hosta.
Matthew
Dlatego przedstawiliśmy dwa podejścia, które będą odpowiednie w różnych kontekstach.
Jared Farrish
Przede wszystkim cieszę się, że ktoś nie opublikował odpowiedzi wyrażenia regularnego (jeszcze). Nie wspominając już o ostatniej linijce mojej odpowiedzi, która spełnia to samo, co twoja.
Jared Farrish
A jeśli nazwa hosta to en.example.co.uk?
Marc B