Funzione PHP per ottenere il sottodominio di un URL


107

Esiste una funzione in PHP per ottenere il nome del sottodominio?

Nell'esempio seguente vorrei ottenere la parte "en" dell'URL:

en.example.com

6
Hai un URL come stringa memorizzato in una variabile o da dove proviene questo URL? Qual è il contesto? Per favore approfondisci.
Felix Kling

Non potresti usare una regex che abbia qualcosa di simile (^|://)(.*)\.e catturi il .*? Preferisco fare schifo sia in php che in regex, ma questo mi viene in mente.
corsiKa

Cosa dovrebbe entrare en.foo.bar.example.como en.example.co.uk?
Álvaro González

parse_url può anche aiutare
Swapnil

Risposte:


132

Ecco una soluzione di una riga:

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

O usando il tuo esempio:

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

EDIT: corretto "solo le variabili devono essere passate per riferimento" aggiungendo doppie parentesi.


EDIT 2 : A partire da PHP 5.4 puoi semplicemente fare:

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

17
Solo le variabili dovrebbero essere passate per riferimento.
Tamás Pap

8
Non sei in grado di fare semplicemente explode(...)[0]invece di usare il turno in questi giorni? Non faccio PHP da diversi anni ..
Tor Valamo

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

1
abbastanza sicuro che puoi (esplodere (...)) [0] però, dovrebbe operare sull'array di ritorno invece della funzione paranthesis (prima della 5.4)
Garet Claborn

3
Questa soluzione non funzionerà nel caso in cui qualcuno digiti www.en.example.come quindi tornerà wwwcome sottodominio.
lolbas

65

Utilizza la funzione parse_url .

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

$parsedUrl = parse_url($url);

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

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

Per più sottodomini

$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 - Questo risolve il problema di più sottodomini, come usa.en.example.com? Mi chiedo solo (la mia risposta no, btw).
Jared Farrish

@ Jared, ho appena aggiunto una soluzione per rilevare più sottodomini.
Mike Lewis

1
@Mike - Funzionerà con tx.usa.en.example.com? (o science.news.bbc.co.uk )? (a proposito, questo non è un collegamento funzionante, solo un esempio, anche se news.bbc.co.uk funziona)
Jared Farrish

4
Funziona per tutto ciò che ha una sola "parola" TLD come net, com, biz ecc. Tuttavia, quando si ha a che fare con co.uk, ad esempio, non lo è. Come visto qui Questo è in realtà un problema più difficile da risolvere.
Mike Lewis

2
anche questo non riesce se non è presente alcun sottodominio.
raveren

32

Puoi farlo ottenendo prima il nome del dominio (ad es. Sub.example.com => example.co.uk) e quindi utilizzare strstr per ottenere i sottodomini.

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

Uscite:

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

2
Questa sembra la soluzione migliore in quanto consente anche domini senza un sottodominio, piuttosto che ri-sintonizzare il nome di dominio poiché il sottodominio è la parte prima del primo punto. Molto utile per verificare l'esistenza di un sottodominio.
Karl MW

Avevo bisogno di ottenere il dominio "base" (senza il sottodominio) e stavo creando la mia soluzione facendo esplodere l'host e ottenendo gli ultimi elementi dell'array con un forciclo, ma dovevo controllarne la lunghezza (per rilevare se facevano parte del dominio come "co.uk"). In realtà, la tua soluzione è molto più semplice di quello che stavo facendo. Regex salva vite, grazie!
Yoone

1
Fantastico .. funziona così bene per tutti i tipi di dominio e sottodomini .. bello.
jon

2
mentre questa soluzione è molto ordinato e può funzionare in quasi tutti i casi, essere consapevoli del fatto che i domini nomi potrebbero avere più di 6 caratteri, come pvt.k12.ma.us, health.vno anche k12.ak.us. Inoltre, i nomi di dominio possono utilizzare set di caratteri cinesi o russi in modo che la parte regex [a-z\.]{2,6}non li corrisponda. Controlla qui per avere un nome di dominio di esempio: 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

Poiché l'unica fonte affidabile per i suffissi di dominio sono i registrar di domini, non è possibile trovare il sottodominio a loro insaputa. C'è un elenco con tutti i suffissi di dominio su https://publicsuffix.org . Questo sito si collega anche a una libreria PHP: https://github.com/jeremykendall/php-domain-parser .

Di seguito trovi un esempio. Ho anche aggiunto l'esempio per en.test.co.uk che è un dominio con un suffisso multiplo (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

Soluzione più semplice e veloce.

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

4

Semplicemente...

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

Basta leggere $ match [1]

Esempio di lavoro

Funziona perfettamente con questo elenco di 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 - Non ho idea di cosa sia scritto nel testo russo. Ho appena preso alcune parole casuali da ru.wikipedia.org ;)
Kamafeather

Non è ucraino? .uaè il codice del paese per l'Ucraina.
nalply

No. Solo informazioni miste. Ma non ne sono sicuro, non sono abbastanza bravo per distinguerli;)
Kamafeather

3
Per quanto riguarda il russo, una traduzione google dal russo all'inglese torna come "valori pubblicati" (nel caso qualcuno fosse curioso come me)
Jeremy Harris

@Kamafeather questo sembra a prova di proiettile. Qualche modo per ottenere la $match[1]parte? $match[0]sembra inutile.
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
Esistono modi migliori per rilevare automaticamente l'host corrente (come $_SERVER['HTTP_HOST']) quindi affidarsi a un'intestazione del referrer che può essere falsificata, supponendo che questa sia l'idea generale alla base della risposta.
Matteo

Bene, stavo usando un vecchio pezzo di codice. L'esempio è ancora valido, tuttavia. Non è questa la radice della domanda.
Jared Farrish

Solo per sommare questi commenti sopra, fare affidamento su $ _SERVER ['HTTP_HOST'] potrebbe non essere efficiente, poiché è possibile che non venga impostato.
gmslzr

2

PHP 7.0: utilizzo della funzione explode e creazione di un elenco di tutti i risultati.

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

Esempio: sub.domain.com

echo $subdomain; 

Risultato: sub

echo $host;

Risultato: dominio


Dimentichi il TLD come .co.uk- il tuo snippet non funzionerà con questi TLD
Adrian Preuss

1

Quello che ho trovato è la soluzione migliore e breve

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

Causerà un errore rigoroso. L'output di explode non può essere passato direttamente a array_shift.
YAAK

1

Per coloro che ottengono "Errore: standard rigorosi: solo le variabili devono essere passate per riferimento". Usa in questo modo:

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


Non era questa la domanda, ma grazie per il tuo contributo.
FazoM


1

Non esiste davvero una soluzione dinamica al 100% - Ho solo cercato di capirlo e a causa delle diverse estensioni di dominio (DTL) questa attività sarebbe davvero difficile senza effettivamente analizzare tutte queste estensioni e controllarle ogni volta:

.com vs .co.uk vs org.uk

L'opzione più affidabile è definire una costante (o una voce di database ecc.) Che memorizzi il nome di dominio effettivo e rimuoverlo $_SERVER['SERVER_NAME']dall'utilizzosubstr()

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

}

Ora se stai usando questa funzione sotto http://test.mymaindomain.co.ukti darà testo se hai più livelli di sottodominio http://another.test.mymaindomain.co.ukotterrai another.test, a meno che, ovviamente, non aggiorni il file DOMAIN.

Spero che aiuti.


1

Semplicemente

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


1

Usare regex, funzioni stringa, parse_url () o le loro combinazioni non è una vera soluzione. Prova semplicemente una qualsiasi delle soluzioni proposte con il dominio test.en.example.co.uk, non ci sarà alcun risultato corretto.

La soluzione corretta è utilizzare il pacchetto che analizza il dominio con l'elenco dei suffissi pubblici . Raccomando TLDExtract , ecco il codice di esempio:

$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

questa è la mia soluzione, funziona con i domini più comuni, puoi adattare la gamma di estensioni di cui hai bisogno:

$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

So di essere davvero in ritardo per la partita, ma ecco qua.

Quello che ho fatto è stato prendere la variabile del server HTTP_HOST ( $_SERVER['HTTP_HOST']) e il numero di lettere nel dominio (quindi example.comsarebbe 11).

Quindi ho usato la substrfunzione per ottenere il sottodominio. L'ho fatto

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

Ho tagliato la sottostringa a 12 invece di 11 perché le sottostringhe iniziano su 1 per il secondo parametro. Quindi ora se hai inserito test.example.com, il valore di $subdomainsarebbe test.

Questo è meglio dell'uso explodeperché se il sottodominio contiene un ., questo non lo taglierà.


La posizione iniziale "0" mancava nella tua risposta. $ sottodominio = substr ($ _ SERVER ['HTTP_HOST'], 0, $ numberOfLettersInSubdomain);
Jamie

0

se stai usando drupal 7

questo ti aiuterà:

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

Da PHP 5.3 puoi usare strstr () con il parametro true

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

Funzionerà solo se non c'è wwwall'inizio della stringa. Approccio un po 'troppo banale.
FooBar

Questo semplifica le cose per gli altri sviluppatori del team, preferisco usarlo piuttosto che qualche esperienza di registrazione avanzata. Se vuoi tagliare www usa trim ($ s, 'www'); o semplicemente
adattalo

1
Per completezza, www è in realtà un sottodominio. È solo comunemente alias del nome di dominio stesso per ragioni storiche.
Levi Morrison

0

Prova questo...

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

Penso che sarebbe più utile per l'OP e per gli altri visitatori, se aggiungessi qualche spiegazione alla tua intenzione.
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
la linea 7 dovrebbe essere$host = explode('.', isset($parsedUrl['path']) ? $parsedUrl['path'] : $parsedUrl['host']);
Kal

0

puoi usare anche questo

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

0

Sto facendo qualcosa del genere

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

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

$subdomain = $splitedByDot[0];

0

Usiamo questa funzione per gestire più sottodomini e più tld gestiamo anche ip e 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

Supponiamo che l'URL corrente = sub.example.com

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

    if (count ($ host)> = 3) {
       echo "Il dominio principale è =". $ host [1]. ".". $ host [0]. "& il sottodominio è =". $ host [2];
       // Il dominio principale è = example.com e il sottodominio è = sub
    } altro {
       echo "Il dominio principale è =". $ host [1]. ".". $ host [0]. "& sottodominio non trovato";
       // "Il dominio principale è = esempio.com e sottodominio non trovato";
    }


-3

Se vuoi solo ciò che viene prima del primo periodo:

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

E se all'inizio fosse presente un gestore di protocollo, come http: //, https: //, ftp: //, ecc ...? ;)
Jared Farrish

@ Jared, non c'è alcun protocollo nella stringa che sta cercando di analizzare ... Ma se ci fosse, userei parse_url()per estrarre l'host.
Matteo

Quindi abbiamo fornito due approcci che saranno appropriati in diversi contesti.
Jared Farrish

Soprattutto, sono solo contento che qualcuno non abbia (ancora) pubblicato una risposta regex. Per non parlare dell'ultima riga della mia risposta, realizza anche la stessa cosa che fa la tua.
Jared Farrish

E se il nome host è en.example.co.uk?
Marc B
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.