Função PHP para obter o subdomínio de um URL


107

Existe uma função no PHP para obter o nome do subdomínio?

No exemplo a seguir, gostaria de obter a parte "en" do URL:

en.example.com

6
Você tem uma URL como string armazenada em uma variável ou de onde vem essa URL? Qual é o contexto? Por favor elabore.
— Felix Kling

Você não poderia usar um regex que fizesse algo parecido (^|://)(.*)\.e capture o .*? Eu prefiro ser péssimo em php e regex, mas isso vem à mente.
— corsiKa

O que deve entrar en.foo.bar.example.comou en.example.co.uk?
— Álvaro González

parse_url também pode ajudar
— Swapnil

Respostas:


132

Aqui está uma solução de uma linha:

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

Ou usando seu exemplo:

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

EDIT: Corrigido "apenas variáveis ​​devem ser passadas por referência", adicionando parênteses duplos.


EDIT 2 : A partir do PHP 5.4, você pode simplesmente fazer:

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

17
Somente as variáveis ​​devem ser passadas por referência.
— Tamás Pap

8
Você não consegue apenas fazer em explode(...)[0]vez de usar o turno atualmente? Há vários anos que não faço PHP.
— Tor Valamo

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

1
com certeza você pode (explodir (...)) [0], porém, deve operar na matriz de retorno em vez da função parêntese (antes de 5.4)
— Garet Claborn

3
Esta solução não funcionará caso alguém digite www.en.example.come retorne wwwcomo subdomínio.
— lolbas

65

Usa a função parse_url .

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

$parsedUrl = parse_url($url);

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

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

Para vários subdomínios

$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 - Isso resolve o problema de vários subdomínios, como usa.en.example.com? Apenas pensando (minha própria resposta não, aliás).
— Jared Farrish

@Jared, acabou de adicionar uma solução para detectar vários subdomínios.
— Mike Lewis

1
@Mike - Isso funcionará com tx.usa.en.example.com? (ou science.news.bbc.co.uk )? (aliás, esse não é um link funcional, apenas um exemplo, embora news.bbc.co.uk funcione)
— Jared Farrish

4
Isso funciona para tudo que tem um único TLD de 'palavra' como net, com, biz etc. No entanto, ao lidar com co.uk, por exemplo, não funciona. Como visto aqui, este é realmente um problema mais difícil de resolver.
— Mike Lewis

2
isso também falhará se não houver subdomínio.
— raveren

32

Você pode fazer isso primeiro obtendo o nome do domínio (por exemplo, sub.example.com => example.co.uk) e, em seguida, use strstr para obter os subdomínios.

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

Saídas:

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

2
Esta parece ser a melhor solução, pois também permite domínios sem um subdomínio, em vez de refazer o nome do domínio como o subdomínio sendo a parte antes do primeiro ponto. Muito útil para verificar a existência de um subdomínio.
— Karl MW

Eu precisava obter o domínio "base" (sem o subdomínio), e estava fazendo minha própria solução explodindo o host e obtendo os últimos elementos da matriz com um forloop, mas tive que verificar seu comprimento (para detectar se eles eram parte do domínio, como "co.uk"). Na verdade, sua solução é muito mais simples do que o que eu estava fazendo. Regex salvar vidas, obrigado!
— Yoone

1
Incrível .. isso funciona tão bem para todos os tipos de domínio e subdomínios .. bom.
— jon

2
enquanto esta solução é muito limpo e pode trabalhar em quase todos os casos, estar ciente de que nomes de domínios pode ter mais de 6 caracteres, como pvt.k12.ma.us, health.vnou mesmo k12.ak.us. Além disso, os nomes de domínio podem usar o conjunto de caracteres chinês ou russo para que a parte do regex [a-z\.]{2,6}não corresponda a eles. Confira aqui para ter exemplos de nomes de domínios: 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

Como a única fonte confiável de sufixos de domínio são os registradores de domínio, você não pode encontrar o subdomínio sem seu conhecimento. Existe uma lista com todos os sufixos de domínio em https://publicsuffix.org . Este site também tem um link para uma biblioteca PHP: https://github.com/jeremykendall/php-domain-parser .

Por favor, encontre um exemplo abaixo. Também adicionei a amostra para en.test.co.uk, que é um domínio com um sufixo múltiplo (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

Solução mais simples e rápida.

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

4

Simplesmente...

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

Basta ler $ match [1]

Exemplo de trabalho

Funciona perfeitamente com esta lista de 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 - Não tenho ideia do que está escrito no texto russo. Peguei algumas palavras casuais de ru.wikipedia.org ;)
— Kamafeather

Não é ucraniano? .uaé o código do país da Ucrânia.
— basicamente

Não. Apenas informações misturadas. Mas não tenho certeza, não sou bom o suficiente para distingui-los;)
— Kamafeather

3
Em relação ao russo, uma tradução do google do russo para o inglês volta como "valores publicados" (caso alguém estivesse curioso como eu)
— Jeremy Harris,

@Kamafeather isso parece à prova de balas. Alguma maneira de conseguir o $match[1]papel? $match[0]parece desnecessário.
— 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
Existem maneiras melhores de detectar automaticamente o host atual (como $_SERVER['HTTP_HOST']) do que confiar em um cabeçalho de referência capaz de falsificar, assumindo que essa é a ideia geral por trás da resposta.
— Mateus

Certo, eu estava usando um código antigo. O exemplo ainda permanece, no entanto. Essa não é a raiz da questão.
— Jared Farrish

Só para somar os comentários acima, confiar em $ _SERVER ['HTTP_HOST'] pode não ser eficiente, pois há uma chance de que ele não esteja definido.
— gmslzr de

2

PHP 7.0: Use a função explodir e crie uma lista de todos os resultados.

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

Exemplo: sub.domain.com

echo $subdomain; 

Resultado: sub

echo $host;

Resultado: domínio


Você se esquece do tipo de TLD .co.uk- seu snippet não funcionará com esses TLDs
— Adrian Preuss

1

O que eu encontrei a melhor e mais curta solução é

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

Irá causar um erro estrito. A saída da explosão não pode ser passada diretamente para array_shift.
— YAAK

1

Para aqueles que receberem 'Erro: Padrões rígidos: apenas variáveis ​​devem ser passadas por referência. Use assim:

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


Essa não era a pergunta, mas obrigado por sua contribuição.
— FazoM


1

Na verdade, não existe uma solução 100% dinâmica - também estou tentando descobrir isso e, devido às diferentes extensões de domínio (DTL), essa tarefa seria realmente difícil sem realmente analisar todas essas extensões e verificá-las a cada vez:

.com vs .co.uk vs org.uk

A opção mais confiável é definir uma constante (ou entrada de banco de dados etc.) que armazena o nome de domínio real e removê-lo do $_SERVER['SERVER_NAME']usosubstr()

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

}

Agora, se você estiver usando esta função com o http://test.mymaindomain.co.ukque lhe dará testou se você tem vários níveis de sub-domínio http://another.test.mymaindomain.co.ukvocê vai ter another.test- a menos que você atualizar o DOMAIN.

Eu espero que isso ajude.


1

Simplesmente

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


1

Usar regex, funções de string, parse_url () ou suas combinações não é uma solução real. Basta testar qualquer uma das soluções propostas com domínio test.en.example.co.uk, não haverá nenhum resultado correto.

A solução correta é usar o pacote que analisa o domínio com a Lista de sufixos públicos . Eu recomendo TLDExtract , aqui está o código de amostra:

$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

esta é a minha solução, ela funciona com os domínios mais comuns, você pode ajustar a variedade de extensões conforme necessário:

$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

Eu sei que estou muito atrasado para o jogo, mas aqui vai.

O que fiz foi pegar a variável do servidor HTTP_HOST ( $_SERVER['HTTP_HOST']) e o número de letras no domínio (então para example.comele seria 11).

Então usei a substrfunção para obter o subdomínio. eu fiz

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

Cortei a substring em 12 em vez de 11 porque as substrings começam em 1 para o segundo parâmetro. Portanto, agora, se você inserisse test.example.com, o valor de $subdomainseria test.

Isso é melhor do que usar explodeporque se o subdomínio tiver um .nele, isso não o cortará.


A posição inicial "0" estava faltando em sua resposta. $ subdomain = substr ($ _ SERVER ['HTTP_HOST'], 0, $ numberOfLettersInSubdomain);
— Jamie

0

se você estiver usando drupal 7

isso vai te ajudar:

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

No PHP 5.3 você pode usar strstr () com o parâmetro true

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

Isso só funcionará se não houver wwwno início da string. Abordagem um pouco trivial demais.
— FooBar

Isso simplifica as coisas para outros desenvolvedores da equipe, prefiro usar isso do que alguma experiência de registro avançada. Se você quiser cortar www, use trim ($ s, 'www'); ou apenas ajustá-lo à sua lógica de negócios ...
— tasmaniski

1
Para fins de integridade, www é na verdade um subdomínio. É comumente um alias para o próprio nome de domínio por razões históricas.
— Levi Morrison de

0

Experimente isso ...

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

Acho que seria mais útil para o OP e outros visitantes, quando você acrescentasse alguma explicação à sua intenção.
— Repórter de

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
a linha 7 deveria ser$host = explode('.', isset($parsedUrl['path']) ? $parsedUrl['path'] : $parsedUrl['host']);
— Kal,

0

você pode usar isso também

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

0

Estou fazendo algo assim

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

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

$subdomain = $splitedByDot[0];

0

Usamos esta função para lidar com vários subdomínios e vários tld também para lidar com 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

Suponha que url atual = sub.example.com

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

    if (contagem ($ host)> = 3) {
       echo "Domínio principal is =". $ host [1]. ".". $ host [0]. "& subdomain is =". $ host [2];
       // Domínio principal is = example.com & subdomain is = sub
    } outro {
       echo "Domínio principal é =". $ host [1]. ".". $ host [0]. "& subdomínio não encontrado";
       // "Domínio principal is = example.com & subdomain not found";
    }


-3

Se você quiser apenas o que vem antes do primeiro período:

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

E se houver um manipulador de protocolo no início, como http: //, https: //, ftp: //, etc ...? ;)
— Jared Farrish

@Jared, não há protocolo na string que ele está tentando analisar ... Mas se houvesse, eu usaria parse_url()para extrair o host.
— Mateus

Portanto, fornecemos duas abordagens que serão apropriadas em contextos diferentes.
— Jared Farrish

Principalmente, estou feliz que alguém não postou uma resposta regex (ainda). Sem falar que a última linha da minha resposta também realiza a mesma coisa que a sua.
— Jared Farrish

E se o nome do host for en.example.co.uk?
— Marc B
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.