Función PHP para obtener el subdominio de una URL


107

¿Existe una función en PHP para obtener el nombre del subdominio?

En el siguiente ejemplo, me gustaría obtener la parte "en" de la URL:

en.example.com

6
¿Tiene una URL como cadena almacenada en una variable o de dónde proviene esta URL? Cual es el contexto? Por favor elabora.
Felix Kling

¿No podrías usar una expresión regular que hiciera algo como (^|://)(.*)\.y capturara el .*? Prefiero apestar tanto en php como en regex, pero esto me viene a la mente.
corsiKa

¿Qué debería entrar en.foo.bar.example.como en.example.co.uk?
Álvaro González

parse_url también puede ayudar
Swapnil

Respuestas:


132

Aquí hay una solución de una línea:

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

O usando tu ejemplo:

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

EDITAR: Se corrigió "solo las variables deben pasarse por referencia" agregando doble paréntesis.


EDITAR 2 : A partir de PHP 5.4 , simplemente puede hacer:

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

17
Solo las variables deberían pasar por referencia.
Tamás Pap

8
¿No puedes simplemente hacer en explode(...)[0]lugar de usar turno en estos días? No he utilizado PHP durante varios años ..
Tor Valamo

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

1
bastante seguro de que puede (explotar (...)) [0] sin embargo, debería estar operando en la matriz de retorno en lugar de la función paranthesis (antes de 5.4)
Garet Claborn

3
Esta solución no funcionará en caso de que alguien ingrese www.en.example.comy, por lo tanto, regresará wwwcomo subdominio.
lolbas

65

Utiliza la función parse_url .

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

$parsedUrl = parse_url($url);

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

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

Para múltiples subdominios

$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: ¿resuelve esto el problema de varios subdominios, como usa.en.example.com? Solo me preguntaba (mi propia respuesta no lo hace, por cierto).
Jared Farrish

@Jared, acaba de agregar una solución para detectar múltiples subdominios.
Mike Lewis

1
@Mike - ¿Funcionará con tx.usa.en.example.com? (o science.news.bbc.co.uk )? (por cierto, ese no es un enlace que funcione, solo un ejemplo, aunque news.bbc.co.uk funciona)
Jared Farrish

4
Eso funciona para todo lo que tiene una sola "palabra" TLD como net, com, biz, etc. Sin embargo, cuando se trata de co.uk, por ejemplo, no es así. Como se ve aquí, este es en realidad un problema más difícil de resolver.
Mike Lewis

2
esto también falla si no hay ningún subdominio.
raveren

32

Puede hacer esto obteniendo primero el nombre de dominio (por ejemplo, sub.example.com => example.co.uk) y luego use strstr para obtener los subdominios.

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

Salidas:

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

2
Esta parece la mejor solución, ya que también permite dominios sin un subdominio, en lugar de volver a sintonizar el nombre de dominio ya que el subdominio es la parte anterior al primer punto. Muy útil para comprobar la existencia de un subdominio.
Karl MW

Necesitaba obtener el dominio "base" (sin el subdominio), y estaba creando mi propia solución explotando el host y obteniendo los últimos elementos de la matriz con un forbucle, pero tenía que verificar su longitud (para detectar si eran parte del dominio como "co.uk"). En realidad, su solución es mucho más simple que lo que estaba haciendo. Regex salva vidas, ¡gracias!
Yoone

1
Impresionante ... esto funciona muy bien para todos los tipos de dominio y subdominios ... agradable.
jon

2
Si bien esta solución es muy clara y puede funcionar en casi todos los casos, tenga en cuenta que los nombres de dominio pueden tener más de 6 caracteres, como pvt.k12.ma.us, health.vno incluso k12.ak.us. Además, los nombres de los dominios pueden usar un juego de caracteres chino o ruso para que la parte de expresiones regulares [a-z\.]{2,6}no coincida con ellos. Consulte aquí para obtener ejemplos de nombres de dominios: 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 la única fuente confiable de sufijos de dominio son los registradores de dominio, no puede encontrar el subdominio sin su conocimiento. Hay una lista con todos los sufijos de dominio en https://publicsuffix.org . Este sitio también tiene enlaces a una biblioteca PHP: https://github.com/jeremykendall/php-domain-parser .

Encuentre un ejemplo a continuación. También agregué la muestra para en.test.co.uk, que es un dominio con un sufijo múltiple (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

La solución más sencilla y rápida.

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

4

Simplemente...

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

Solo lee $ match [1]

Ejemplo de trabajo

Funciona perfectamente con esta lista de URL.

$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
PD: no tengo ni idea de lo que está escrito en el texto ruso. Solo tomé algunas palabras casuales de ru.wikipedia.org ;)
Kamafeather

¿No es ucraniano? .uaes el código de país de Ucrania.
nalply

No Solo información mixta. Pero no estoy seguro, no soy lo suficientemente bueno para distinguirlos;)
Kamafeather

3
En lo que respecta al ruso, un traductor de Google del ruso al inglés vuelve como "valores publicados" (en caso de que alguien tuviera curiosidad como yo)
Jeremy Harris

@Kamafeather esto parece a prueba de balas. ¿Alguna forma de conseguir el $match[1]papel? $match[0]parece innecesario.
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
Hay mejores formas de detectar automáticamente el host actual (como $_SERVER['HTTP_HOST']) y luego confiar en un encabezado de referencia que se pueda falsificar, asumiendo que esa es la idea general detrás de la respuesta.
Mateo

Bien, estaba usando un código antiguo. Sin embargo, el ejemplo sigue en pie. Esa no es la raíz de la pregunta.
Jared Farrish

Solo para agregar estos comentarios anteriores, confiar en $ _SERVER ['HTTP_HOST'] puede no ser eficiente, ya que existe la posibilidad de que no esté configurado.
gmslzr

2

PHP 7.0: Usar la función de explosión y crear una lista de todos los resultados.

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

Ejemplo: sub.domain.com

echo $subdomain; 

Resultado: sub

echo $host;

Resultado: dominio


Olvidó el tipo de TLD .co.uk: su fragmento no funcionará con estos TLD
Adrian Preuss

1

Lo que encontré la mejor y más corta solución es

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

Causará un error estricto. La salida de explosión no se puede pasar directamente a array_shift.
YAAK

1

Para aquellos que obtienen 'Error: Estándares estrictos: solo las variables deben pasarse por referencia'. Use así:

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


Esa no era la pregunta, pero gracias por tu aporte.
FazoM


1

Realmente no hay una solución 100% dinámica; solo he estado tratando de resolverlo también y, debido a las diferentes extensiones de dominio (DTL), esta tarea sería realmente difícil sin analizar todas estas extensiones y verificarlas cada vez:

.com vs .co.uk vs org.uk

La opción más confiable es definir una constante (o entrada de base de datos, etc.) que almacene el nombre de dominio real y lo elimine del $_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, '.');

}

Ahora, si está usando esta función debajo http://test.mymaindomain.co.uk, obtendrá testo si tiene múltiples niveles de subdominio, http://another.test.mymaindomain.co.uka another.testmenos que, por supuesto, actualice elDOMAIN .

Espero que esto ayude.


1

Simplemente

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


1

Usar expresiones regulares, funciones de cadena, parse_url () o sus combinaciones no es una solución real. Simplemente pruebe cualquiera de las soluciones propuestas con domaintest.en.example.co.uk , no habrá ningún resultado correcto.

La solución correcta es usar un paquete que analiza el dominio con la lista de sufijos públicos . Recomiendo TLDExtract , aquí hay un código de muestra:

$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 es mi solución, funciona con los dominios más comunes, puede ajustar la matriz de extensiones que necesite:

$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

Sé que llego muy tarde al juego, pero aquí va.

Lo que hice fue tomar la variable del servidor HTTP_HOST ( $_SERVER['HTTP_HOST']) y el número de letras en el dominio (por example.comlo que sería 11).

Luego usé la substrfunción para obtener el subdominio. yo hice

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

Corté la subcadena en 12 en lugar de 11 porque las subcadenas comienzan en 1 para el segundo parámetro. Entonces, si ingresó test.example.com, el valor de $subdomainsería test.

Esto es mejor que usarlo explodeporque si el subdominio tiene un ., esto no lo cortará.


Faltaba la posición inicial "0" en su respuesta. $ subdominio = substr ($ _ SERVER ['HTTP_HOST'], 0, $ numberOfLettersInSubdomain);
Jamie

0

si estás usando drupal 7

Esto te ayudara:

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

Desde PHP 5.3 puede usar strstr () con verdadero parámetro

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

Esto solo funcionará si no hay wwwun inicio de cadena. Un enfoque demasiado trivial.
FooBar

Esto simplifica las cosas para otros desarrolladores en el equipo, prefiero usar esto que un reg exp avanzado. Si desea recortar www, use trim ($ s, 'www'); o simplemente ajústelo a la lógica de su negocio ...
tasmaniski

1
En aras de la integridad, en realidad www es un subdominio. Por lo general, se le asigna un alias al propio nombre de dominio por razones históricas.
Levi Morrison

0

Prueba esto...

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

Creo que sería más útil para el OP y otros visitantes, si agrega alguna explicación a su intención.
Reportero

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 línea # 7 debería ser$host = explode('.', isset($parsedUrl['path']) ? $parsedUrl['path'] : $parsedUrl['host']);
Kal

0

también puedes usar esto

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

0

Estoy haciendo algo como esto

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

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

$subdomain = $splitedByDot[0];

0

Usamos esta función para manejar múltiples subdominios y múltiples tld también manejamos ip y 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

Supongamos que url actual = sub.example.com

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

    if (count ($ host)> = 3) {
       echo "El dominio principal es =". $ host [1]. ".". $ host [0]. "& subdominio es =". $ host [2];
       // El dominio principal es = ejemplo.com y el subdominio es = sub
    } más {
       echo "El dominio principal es =". $ host [1]. ".". $ host [0]. "& subdominio no encontrado";
       // "El dominio principal es = example.com & subdominio no encontrado";
    }


-3

Si solo quiere lo que viene antes del primer período:

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

¿Qué pasa si hay un controlador de protocolo al principio, como http: //, https: //, ftp: //, etc ...? ;)
Jared Farrish

@Jared, no hay un protocolo en la cadena que está buscando analizar ... Pero si lo hubiera, lo usaría parse_url()para extraer el host.
Mateo

Por eso, hemos proporcionado dos enfoques que serán apropiados en diferentes contextos.
Jared Farrish

Principalmente, me alegro de que alguien no haya publicado una respuesta de expresión regular (todavía). Sin mencionar que la última línea de mi respuesta también logra lo mismo que la suya.
Jared Farrish

¿Y si el nombre de host es en.example.co.uk?
Marc B
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.