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

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

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

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:password@sub.hostname.tld/path?argument=value#anchor';
  $array=parse_url($url);
  $array['host']=explode('.', $array['host']);

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

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;

5

Najprostsze i najszybsze rozwiązanie.

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

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

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

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


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']));

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


To nie było pytanie, ale dziękuję za wkład.
FazoM


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.



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'

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

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

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.


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

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

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

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

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"

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

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

0

Robię coś takiego

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

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

$subdomain = $splitedByDot[0];

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

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


-3

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

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

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.