Функция PHP для получения поддомена URL


107

Есть ли в PHP функция для получения имени поддомена?

В следующем примере я хотел бы получить "en" часть URL:

en.example.com

6
У вас есть URL-адрес в виде строки, хранящейся в переменной, или откуда этот URL-адрес? В каком контексте? Пожалуйста, дополните.
Felix Kling

Не могли бы вы использовать регулярное выражение, которое делает что-то вроде (^|://)(.*)\.и захватывает .*? Я скорее отстой и с php, и с регулярным выражением, но это приходит на ум.
corsiKa

Что он должен получить en.foo.bar.example.comили en.example.co.uk?
Álvaro González

parse_url также может помочь
Swapnil

Ответы:


132

Вот однострочное решение:

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

Или используя ваш пример:

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

РЕДАКТИРОВАТЬ: Исправлено «только переменные должны передаваться по ссылке» путем добавления двойных скобок.


РЕДАКТИРОВАТЬ 2 : Начиная с PHP 5.4 вы можете просто сделать:

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

17
Только переменные должны передаваться по ссылке.
Tamás Pap

8
Разве в explode(...)[0]наши дни вы не можете просто работать вместо смены? Не занимается PHP уже несколько лет ..
Тор Валамо

Ошибка:Strict Standards: Only variables should be passed by reference.
Джастин

1
почти уверен, что вы можете (explode (...)) [0], хотя, должны работать с возвращаемым массивом, а не с парантезом функции (до 5.4)
Гарет Клаборн

3
Это решение не сработает, если кто-то наберет www.en.example.comи вернется wwwкак поддомен.
lolbas

65

Использует функцию parse_url .

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

$parsedUrl = parse_url($url);

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

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

Для нескольких поддоменов

$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 - Решает ли это проблему нескольких поддоменов, таких как usa.en.example.com? Просто интересно (кстати, мой собственный ответ - нет).
Джаред Фарриш,

@Jared, только что добавил решение для обнаружения нескольких поддоменов.
Майк Льюис,

1
@Mike - Будет ли это работать с tx.usa.en.example.com? (или science.news.bbc.co.uk )? (кстати, это не рабочая ссылка, это просто пример, хотя news.bbc.co.uk действительно работает)
Джаред Фарриш,

4
Это работает для всего, что имеет одно «словесное» TLD, например net, com, biz и т. Д. Однако, например, при работе с co.uk это не так. Как видно здесь, это действительно более сложная проблема.
Майк Льюис,

2
это также не удается, если субдомен отсутствует вообще.
raveren 03

32

Вы можете сделать это, сначала получив имя домена (например, sub.example.com => example.co.uk), а затем используя strstr для получения поддоменов.

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

Выходы:

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

2
Это кажется лучшим решением, так как оно также позволяет использовать домены без поддомена, а не повторно использовать доменное имя в качестве поддомена, являющегося частью перед первой точкой. Очень полезно для проверки существования поддомена.
Karl MW

Мне нужно было получить «базовый» домен (без поддомена), и я делал свое собственное решение, взрывая хост и получая последние элементы массива с помощью forцикла, но мне нужно было проверить их длину (чтобы определить, не были частью домена, например co.uk). На самом деле ваше решение намного проще, чем то, что делал я. Regex спасает жизни, спасибо!
Yoone

1
Замечательно ... это так хорошо работает для всех типов доменов и поддоменов ... хорошо.
jon

2
хотя это решение очень удобное и может работать почти во всех случаях, имейте в виду, что имена доменов могут содержать более 6 символов, например pvt.k12.ma.us, health.vnили даже k12.ak.us. Кроме того, имена доменов могут использовать китайский или русский набор символов, поэтому часть регулярного выражения [a-z\.]{2,6}не будет соответствовать им. Посмотрите здесь, чтобы получить пример имени домена: 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

Поскольку единственным надежным источником суффиксов домена являются регистраторы доменов, вы не можете найти субдомен без их ведома. На https://publicsuffix.org есть список со всеми суффиксами доменов . Этот сайт также ссылается на библиотеку PHP: https://github.com/jeremykendall/php-domain-parser .

Пожалуйста, найдите пример ниже. Я также добавил образец для en.test.co.uk, который является доменом с мультисуффиксом (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

Самое простое и быстрое решение.

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

4

Просто...

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

Просто прочтите $ match [1]

Рабочий пример

Он отлично работает с этим списком 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
PS - понятия не имею, что написано в русском тексте. Просто взял несколько случайных слов с ru.wikipedia.org ;)
Kamafeather

Разве это не украинское? .uaэто код страны для Украины.
nalply

Нет. Просто смешанная информация. Но я не уверен, я недостаточно хорош, чтобы их различать;)
Kamafeather

3
Что касается русского, то гугл-перевод с русского на английский возвращается как «опубликованные значения» (на случай, если кому-то было любопытно, как и мне)
Джереми Харрис

@Kamafeather, это выглядит пуленепробиваемым. Есть ли способ просто получить $match[1]роль? $match[0]кажется ненужным.
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
Есть более эффективные способы автоматического определения текущего хоста (например, $_SERVER['HTTP_HOST']), а затем полагаться на поддельный заголовок реферера, предполагая, что это основная идея ответа.
Мэтью

Верно, я использовал старый фрагмент кода. Однако пример все еще актуален. Не в этом корень вопроса.
Джаред Фарриш,

Чтобы добавить к этим комментариям выше, использование $ _SERVER ['HTTP_HOST'] может быть неэффективным, поскольку есть вероятность, что он не может быть установлен.
gmslzr

2

PHP 7.0: Использование функции разнесения и создание списка всех результатов.

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

Пример: sub.domain.com

echo $subdomain; 

Результат: sub

echo $host;

Результат: домен


Вы забываете подобные TLD .co.uk- ваш фрагмент не будет работать с этими TLD
Адриан

1

Я нашел лучшее и краткое решение:

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

Вызовет строгую ошибку. Вывод разнесения нельзя передать напрямую в array_shift.
YAAK

1

Для тех, кто получил сообщение «Ошибка: строгие стандарты: только переменные должны передаваться по ссылке». Используйте так:

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


Вопрос не в этом, но спасибо за ваш вклад.
FazoM


1

На самом деле не существует 100% динамического решения - я просто пытался понять это, и из-за различных расширений домена (DTL) эта задача была бы действительно сложной без фактического анализа всех этих расширений и проверки их каждый раз:

.com vs .co.uk vs org.uk

Самый надежный вариант - определить константу (или запись в базе данных и т. Д.), Которая хранит фактическое доменное имя, и удалить ее из $_SERVER['SERVER_NAME']использования.substr()

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

}

Теперь, если вы используете эту функцию, http://test.mymaindomain.co.ukона даст вам testили, если у вас есть несколько уровней поддоменов, http://another.test.mymaindomain.co.ukвы получите another.test- если, конечно, вы не обновите DOMAIN.

Надеюсь, это поможет.



1

Использование регулярного выражения, строковых функций, parse_url () или их комбинаций не является реальным решением. Просто протестируйте любое из предложенных решений с доменом test.en.example.co.uk, правильного результата не будет.

Правильное решение - использовать пакет, который анализирует домен с помощью списка общедоступных суффиксов . Я рекомендую TLDExtract , вот пример кода:

$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

это мое решение, оно работает с наиболее распространенными доменами, вы можете подогнать массив расширений по своему усмотрению:

$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

Я знаю, что очень опаздываю на игру, но начнем.

Я взял переменную сервера HTTP_HOST ( $_SERVER['HTTP_HOST']) и количество букв в домене (так что example.comэто было бы 11).

Затем я использовал substrфункцию, чтобы получить поддомен. я сделал

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

Я отрезал подстроку с 12 вместо 11, потому что подстроки начинаются с 1 для второго параметра. Итак, теперь, если вы ввели test.example.com, значение $subdomainбудет test.

Это лучше, чем использование, explodeпотому что, если в субдомене есть ., это не отключит его.


В вашем ответе отсутствовала начальная позиция "0". $ subdomain = substr ($ _ SERVER ['HTTP_HOST'], 0, $ numberOfLettersInSubdomain);
Джейми

0

если вы используете drupal 7

это поможет вам:

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

Начиная с PHP 5.3 вы можете использовать strstr () с параметром true

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

Это будет работать, только если wwwв начале строки нет. Слишком банальный подход.
FooBar

Это упростит жизнь другим разработчикам в команде, я бы предпочел использовать это, чем какой-нибудь продвинутый рег. Если вы хотите обрезать www, используйте trim ($ s, 'www'); или просто приспособьте его к своей бизнес-логике ...
тасманиски

1
Для полноты картины www это фактически субдомен. Это просто псевдоним самого доменного имени по историческим причинам.
Леви Моррисон

0

Попробуй это...

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

Я думаю, что было бы более полезно для OP и других посетителей, если бы вы добавили некоторые пояснения к своему намерению.
Репортер

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
строка # 7 должна быть$host = explode('.', isset($parsedUrl['path']) ? $parsedUrl['path'] : $parsedUrl['host']);
Kal

0

ты тоже можешь использовать это

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

0

Я делаю что-то вроде этого

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

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

$subdomain = $splitedByDot[0];

0

Мы используем эту функцию для обработки нескольких поддоменов, а несколько tld также обрабатывают ip и 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

Предположим, текущий url = sub.example.com

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

    if (count ($ host)> = 3) {
       echo "Главный домен =". $ host [1]. ".". $ host [0]. "& subdomain is =". $ host [2];
       // Основной домен = example.com & subdomain is = sub
    } else {
       echo "Главный домен =". $ host [1]. ".". $ host [0]. "& subdomain не найден";
       // «Основной домен = example.com & субдомен не найден»;
    }


-3

Если вы хотите только то, что было до первой менструации:

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

Что если в начале есть обработчик протокола, например http: //, https: //, ftp: // и т. Д.? ;)
Джаред Фарриш

@ Джаред, в строке, которую он хочет проанализировать, нет протокола ... Но если бы он был, я бы использовал parse_url()для извлечения хоста.
Мэтью

Итак, мы предоставили два подхода, которые будут уместны в разных контекстах.
Джаред Фарриш,

В основном, я просто рад, что кто-то не опубликовал ответ регулярного выражения (пока). Не говоря уже о том, что последняя строка моего ответа выполняет то же самое, что и ваш.
Джаред Фарриш,

А если имя хоста en.example.co.uk?
Marc B
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.