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

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

Solução mais simples e rápida.

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

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

Naseer
fonte
Essa não era a pergunta, mas obrigado por sua contribuição.
FazoM
1
$domain = 'sub.dev.example.com';
$tmp = explode('.', $domain); // split into parts
$subdomain = current($tmp);
print($subdomain);     // prints "sub"

Como visto na pergunta anterior: Como obter o primeiro subdomínio com PHP?

Comunidade
fonte
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.

Sebastian Sulinski
fonte
1

Simplesmente

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

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

Flautim
fonte
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];
Mohanad
fonte
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
fonte
0

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

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

Estou fazendo algo assim

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

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

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

Khorshed Alam Shohel
fonte
-3

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

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