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
Damiano
fuente
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];
Michael Deal
fuente
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
fuente
@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
mazon
fuente
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
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;
Sascha Frinken
fuente
5

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

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

Jeacovy Gayle
fuente
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']));
Zulqurnain abbas
fuente
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);

Naseer
fuente
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.

Sebastián Sulinski
fuente
1

Simplemente

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

Adam F
fuente
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'
Oleksandr Fediashov
fuente
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]);
Sergio López Loya
fuente
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
fuente
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á.

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

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

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

Estoy haciendo algo como esto

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

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

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

Khorshed Alam Shohel
fuente
-3

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

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