Функция 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'
?>
JMW
источник
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);
}
Kamafeather
источник
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;

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

Jeacovy Gayle
источник
Вы забываете подобные 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

Просто

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

Адам Ф
источник
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"
edCoder
источник
Я думаю, что было бы более полезно для 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);
}
Itsazzad
источник
1
строка # 7 должна быть$host = explode('.', isset($parsedUrl['path']) ? $parsedUrl['path'] : $parsedUrl['host']);
Kal
0

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

echo substr($_SERVER['HTTP_HOST'], 0, strrpos($_SERVER['HTTP_HOST'], '.', -5));
XIMvad
источник
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