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.