Fonction PHP pour obtenir le sous-domaine d'une URL


107

Existe-t-il une fonction en PHP pour obtenir le nom du sous-domaine?

Dans l'exemple suivant, je voudrais obtenir la partie "en" de l'URL:

en.example.com

6
Avez-vous une URL sous forme de chaîne stockée dans une variable ou d'où provient cette URL? Quel est le contexte? Veuillez préciser.
Felix Kling

Ne pourriez-vous pas utiliser une expression régulière qui a fait quelque chose comme (^|://)(.*)\.et capturer le .*? Je suis plutôt nul en php et en regex, mais cela me vient à l'esprit.
corsiKa

Que devrait-il entrer en.foo.bar.example.comou en.example.co.uk?
Álvaro González

parse_url peut aussi vous aider
Swapnil

Réponses:


132

Voici une solution en une ligne:

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

Ou en utilisant votre exemple:

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

EDIT: Correction de "seules les variables doivent être passées par référence" en ajoutant une double parenthèse.


EDIT 2 : À partir de PHP 5.4, vous pouvez simplement faire:

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

17
Seules les variables doivent être transmises par référence.
Tamás Pap

8
N'êtes-vous pas capable de faire explode(...)[0]au lieu d'utiliser shift de nos jours? Je n'ai pas fait de PHP depuis plusieurs années ..
Tor Valamo

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

1
assez sûr que vous pouvez (exploser (...)) [0] cependant, devrait fonctionner sur le tableau de retour au lieu de la fonction paranthesis (avant 5.4)
Garet Claborn

3
Cette solution ne fonctionnera pas au cas où quelqu'un entrerait www.en.example.comet reviendrait donc en wwwtant que sous-domaine.
lolbas

65

Utilise la fonction parse_url .

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

$parsedUrl = parse_url($url);

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

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

Pour plusieurs sous-domaines

$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 - Cela résout-il le problème de plusieurs sous-domaines, tels que usa.en.example.com? Je me demande juste (ma propre réponse ne le fait pas, d'ailleurs).
Jared Farrish

@Jared, vient d'ajouter une solution pour détecter plusieurs sous-domaines.
Mike Lewis

1
@Mike - Cela fonctionnera-t-il avec tx.usa.en.example.com? (ou science.news.bbc.co.uk )? (btw, ce n'est pas un lien fonctionnel, juste un exemple, bien que news.bbc.co.uk fonctionne)
Jared Farrish

4
Cela fonctionne pour tout ce qui a un seul TLD «mot» comme net, com, biz, etc. Cependant, lorsqu'il s'agit de co.uk, par exemple, ce n'est pas le cas. Comme on le voit ici, c'est en fait un problème plus difficile à résoudre.
Mike Lewis

2
cela échoue également s'il n'y a pas du tout de sous-domaine.
raveren

32

Vous pouvez le faire en obtenant d'abord le nom de domaine (par exemple, sub.example.com => exemple.co.uk), puis en utilisant strstr pour obtenir les sous-domaines.

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

Les sorties:

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

2
Cela semble la meilleure solution car elle permet également des domaines sans sous-domaine, plutôt que de retruner le nom de domaine en tant que sous-domaine étant la partie avant le premier point. Très utile pour vérifier l'existence d'un sous-domaine.
Karl MW

J'avais besoin d'obtenir le domaine "de base" (sans le sous-domaine), et je faisais ma propre solution en explosant l'hôte et en obtenant les derniers éléments du tableau avec une forboucle, mais j'ai dû vérifier leur longueur (pour détecter s'ils faisaient partie du domaine comme le "co.uk"). En fait, votre solution est bien plus simple que ce que je faisais. Regex sauve des vies, merci!
Yoone

1
Génial ... cela fonctionne si bien pour tous les types de domaines et sous-domaines ... sympa.
jon

2
alors que cette solution est très propre et peut travailler dans presque tous les cas, sachez que les domaines noms pourraient avoir plus de 6 caractères, comme pvt.k12.ma.us, health.vnou même k12.ak.us. En outre, les noms de domaine peuvent utiliser un jeu de caractères chinois ou russe afin que la partie regex [a-z\.]{2,6}ne les corresponde pas. Consultez ici pour avoir des exemples de noms de domaines: 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

Comme la seule source fiable pour les suffixes de domaine sont les bureaux d'enregistrement de domaine, vous ne pouvez pas trouver le sous-domaine à leur insu. Il existe une liste de tous les suffixes de domaine sur https://publicsuffix.org . Ce site renvoie également à une bibliothèque PHP: https://github.com/jeremykendall/php-domain-parser .

Veuillez trouver un exemple ci-dessous. J'ai également ajouté l'exemple pour en.test.co.uk qui est un domaine avec un suffixe multiple (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

Solution la plus simple et la plus rapide.

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

4

Simplement...

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

Il suffit de lire $ match [1]

Exemple de travail

Cela fonctionne parfaitement avec cette liste d'urls

$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 - Je n'ai aucune idée de ce que c'est écrit dans le texte russe. Je viens de prendre quelques mots occasionnels de ru.wikipedia.org ;)
Kamafeather

N'est-ce pas ukrainien? .uaest l'indicatif pays de l'Ukraine.
nalply

Nan. Juste des informations mitigées. Mais je ne suis pas sûr, je ne suis pas assez bon pour les distinguer;)
Kamafeather

3
En ce qui concerne le russe, une traduction google du russe vers l'anglais revient en tant que "valeurs publiées" (au cas où quelqu'un serait curieux comme moi)
Jeremy Harris

@Kamafeather cela a l'air à l'épreuve des balles. Un moyen d'obtenir la $match[1]pièce? $match[0]semble 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
Il existe de meilleures façons de détecter automatiquement l'hôte actuel (comme $_SERVER['HTTP_HOST']), puis de s'appuyer sur un en-tête de référence pouvant être falsifié, en supposant que c'est l'idée générale derrière la réponse.
Matthieu

Oui, j'utilisais un vieux morceau de code. L'exemple reste cependant valable. Ce n'est pas la racine de la question.
Jared Farrish

Juste pour ajouter à ces commentaires ci-dessus, se fier à $ _SERVER ['HTTP_HOST'] peut ne pas être efficace, car il est possible qu'il ne soit pas défini.
gmslzr

2

PHP 7.0: Utilisation de la fonction d'explosion et création d'une liste de tous les résultats.

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

Exemple: sub.domain.com

echo $subdomain; 

Résultat: sous

echo $host;

Résultat: domaine


Vous oubliez les TLD comme .co.uk- votre extrait ne fonctionnera pas avec ces TLD
Adrian Preuss

1

Ce que j'ai trouvé la meilleure solution courte est

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

Provoquera une erreur stricte. La sortie d'explosion ne peut pas être transmise directement à array_shift.
YAAK

1

Pour ceux qui obtiennent "Erreur: normes strictes: seules les variables doivent être transmises par référence". Utilisez comme ceci:

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


Ce n'était pas la question, mais merci pour votre contribution.
FazoM


1

Il n'y a pas vraiment de solution 100% dynamique - je viens d'essayer de le comprendre également et en raison des différentes extensions de domaine (DTL), cette tâche serait vraiment difficile sans analyser toutes ces extensions et les vérifier à chaque fois:

.com vs .co.uk vs org.uk

L'option la plus fiable est de définir une constante (ou une entrée de base de données, etc.) qui stocke le nom de domaine réel et le supprime de l' $_SERVER['SERVER_NAME']utilisationsubstr()

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

}

Maintenant, si vous utilisez cette fonction, http://test.mymaindomain.co.ukcela vous donnera testou si vous avez plusieurs niveaux de sous-domaine, http://another.test.mymaindomain.co.ukvous obtiendrez another.test- à moins bien sûr que vous ne mettiez à jour leDOMAIN .

J'espère que ça aide.


1

Simplement

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


1

En utilisant des expressions régulières, des fonctions de chaîne, parse_url () ou leurs combinaisons, ce n'est pas une vraie solution. Testez simplement l'une des solutions proposées avec domaintest.en.example.co.uk , il n'y aura pas de résultat correct.

La solution correcte est d'utiliser un package qui analyse le domaine avec la liste de suffixes publics . Je recommande TLDExtract , voici un exemple de code:

$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

c'est ma solution, cela fonctionne avec les domaines les plus courants, vous pouvez adapter le tableau d'extensions selon vos besoins:

$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

Je sais que je suis vraiment en retard au match, mais voilà.

Ce que j'ai fait, c'est de prendre la variable de serveur HTTP_HOST ( $_SERVER['HTTP_HOST']) et le nombre de lettres dans le domaine (donc pour example.comce serait 11).

Ensuite, j'ai utilisé la substrfonction pour obtenir le sous-domaine. J'ai fait

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

J'ai coupé la sous-chaîne à 12 au lieu de 11 car les sous-chaînes commencent à 1 pour le deuxième paramètre. Alors maintenant, si vous entrez test.example.com, la valeur de $subdomainserait test.

C'est mieux que d'utiliser explodecar si le sous-domaine contient un ., cela ne le coupera pas.


La position de départ "0" manquait dans votre réponse. $ subdomain = substr ($ _ SERVER ['HTTP_HOST'], 0, $ numberOfLettersInSubdomain);
Jamie

0

si vous utilisez drupal 7

cela vous aidera:

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

Depuis PHP 5.3, vous pouvez utiliser strstr () avec le paramètre true

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

Cela ne fonctionnera que s'il n'y a pas wwwde chaîne au début. Une approche un peu trop triviale.
FooBar

Cela simplifie les choses pour les autres développeurs de l'équipe, je préfère l'utiliser plutôt que des exp reg avancé. Si vous voulez couper www, utilisez trim ($ s, 'www'); ou ajustez-le simplement à votre logique métier ...
tasmaniski

1
Par souci d'exhaustivité, www est en fait un sous-domaine. Il est juste communément associé au nom de domaine lui-même pour des raisons historiques.
Levi Morrison

0

Essaye ça...

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

Je pense que ce serait plus utile pour le PO et les autres visiteurs, lorsque vous ajoutez des explications à votre intention.
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 ligne 7 devrait être$host = explode('.', isset($parsedUrl['path']) ? $parsedUrl['path'] : $parsedUrl['host']);
Kal

0

vous pouvez aussi l'utiliser

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

0

Je fais quelque chose comme ça

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

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

$subdomain = $splitedByDot[0];

0

Nous utilisons cette fonction pour gérer plusieurs sous - domaines et plusieurs tld gèrent également ip et 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

Supposons que l'url actuelle = sub.example.com

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

    if (count ($ hôte)> = 3) {
       echo "Le domaine principal est =". $ host [1]. ".". $ host [0]. "& subdomain is =". $ host [2];
       // Le domaine principal est = exemple.com & le sous-domaine est = sous
    } autre {
       echo "Le domaine principal est =". $ host [1]. ".". $ host [0]. "& subdomain not found";
       // "Le domaine principal est = exemple.com & sous-domaine introuvable";
    }


-3

Si vous ne voulez que ce qui précède les premières règles:

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

Et s'il y avait un gestionnaire de protocole au début, tel que http: //, https: //, ftp: //, etc ...? ;)
Jared Farrish

@Jared, il n'y a pas de protocole dans la chaîne qu'il cherche à analyser ... Mais s'il y en avait, j'utiliserais parse_url()pour extraire l'hôte.
Matthieu

Nous avons donc proposé deux approches qui seront appropriées dans différents contextes.
Jared Farrish

Surtout, je suis juste content que quelqu'un n'ait pas (encore) publié de réponse regex. Sans oublier que la dernière ligne de ma réponse accomplit également la même chose que la vôtre.
Jared Farrish

Et si le nom d'hôte est en.example.co.uk?
Marc B
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.