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
Damiano
la source
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];
Michael Deal
la source
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
la source
@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
mazon
la source
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:[email protected]/path?argument=value#anchor';
  $array=parse_url($url);
  $array['host']=explode('.', $array['host']);

  echo $array['host'][0]; // returns 'en'
?>
JMW
la source
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;
Sascha Frinken
la source
5

Solution la plus simple et la plus rapide.

$sSubDomain = str_replace('.example.com','',$_SERVER['HTTP_HOST']);
Arjen
la source
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);
}
Kamafeather
la source
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, '.')); 
Jared Farrish
la source
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

Jeacovy Gayle
la source
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']));
Abbas de Zulqurnain
la source
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);

Naseer
la source
Ce n'était pas la question, mais merci pour votre contribution.
FazoM
1
$domain = 'sub.dev.example.com';
$tmp = explode('.', $domain); // split into parts
$subdomain = current($tmp);
print($subdomain);     // prints "sub"

Comme vu dans une question précédente: Comment obtenir le premier sous-domaine avec PHP?

Communauté
la source
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.

Sébastien Sulinski
la source
1

Simplement

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

Adam F
la source
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'
Oleksandr Fediashov
la source
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]);
Sergio Lopez Loya
la source
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
la source
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.

Piccolo
la source
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];
mohanad
la source
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
la source
0

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

echo strstr($_SERVER["HTTP_HOST"], '.', true); //prints en
tasmaniski
la source
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"
edCoder
la source
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);
}
itsazzad
la source
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));
XIMvad
la source
0

Je fais quelque chose comme ça

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

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

$subdomain = $splitedByDot[0];
Cheikh Althaf
la source
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;
    }
Javad Adib
la source
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";
    }

Khorshed Alam Shohel
la source
-3

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

list($sub) = explode('.', 'en.example.com', 2);
Matthieu
la source
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