Функція PHP, щоб отримати субдомен URL


107

Чи є функція в PHP отримати назву субдомену?

У наступному прикладі я хотів би отримати "en" частину URL-адреси:

en.example.com

6
Чи є у вас URL-адреса як рядок, збережена у змінній або звідки походить ця URL-адреса? Що таке контекст? Будь ласка, докладно.
Фелікс Клінг

Не могли б ви використати регулярний вираз, який зробив щось на кшталт (^|://)(.*)\.і захопив .*? Я скоріше смоктав і на php, і на rgex, але це приходить на думку.
corsiKa

Що воно повинно потрапити en.foo.bar.example.comчи en.example.co.uk?
Альваро Гонсалес

parse_url також може допомогти
Swapnil

Відповіді:


132

Ось однорядне рішення:

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

Або використовуючи свій приклад:

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

EDIT: Виправлені "лише змінні повинні передаватися посиланням", додавши подвійні дужки.


EDIT 2 : Починаючи з PHP 5.4, ви можете просто зробити:

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

17
Тільки змінні повинні передаватися за посиланням.
Тамаш Пап

8
Хіба ви не можете просто зробити це explode(...)[0]замість того, щоб використовувати зміни в ці дні? Не був PHP протягом декількох років ..
Tor Valamo

Помилка:Strict Standards: Only variables should be passed by reference.
Джастін

1
майже впевнений, що ви можете (вибухнути (...)) [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? Просто цікаво (моя власна відповідь ні, btw).
Джаред Фарріш

@Jred, щойно додав рішення для виявлення кількох субдоменів.
Майк Льюїс

1
@Mike - Чи буде це працювати з tx.usa.en.example.com? (або science.news.bbc.co.uk )? (btw, це не робоче посилання, лише приклад, хоча news.bbc.co.uk справді працює)
Джаред Фарріш

4
Це працює для всього, що має одне «слово» TLD, як net, com, biz тощо. Однак, наприклад, при роботі з co.uk це не відбувається. Як бачимо тут, це насправді важче вирішити проблему.
Майк Льюїс

2
це також не вдається, якщо взагалі немає піддомену.
raveren

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
Що стосується російської мови, переклад Google з російської на англійську мову повертається як "опубліковані цінності" (на випадок, коли хтось цікавий, як я)
Джеремі Гарріс

@Kamafeather це виглядає бездоганним. Будь-який спосіб просто взяти $match[1]участь? $match[0]здається непотрібним.
Андрес СК

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: Використовуючи функцію explode та створити список усіх результатів.

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

Приклад: sub.domain.com

echo $subdomain; 

Результат: підр

echo $host;

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


Ви забуваєте подібні до TLD .co.uk- ваш фрагмент не працюватиме з цими TLD
Адріан

1

Що я знайшов найкраще і коротке рішення

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

Викличе сувору помилку. Виведення вибуху не може бути передано безпосередньо array_shift.
ЯАК

1

Для тих, хто отримує "Помилка: Суворі стандарти: Лише змінні повинні передаватися за посиланням." Використовуйте так:

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


Це не було питання, але дякую за ваш внесок.
FazoM


1

Насправді не стовідсоткове динамічне рішення - я просто намагався розібратися в цьому, і через різні розширення домену (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, не буде жодного правильного результату.

Правильним рішенням є використання пакету, який аналізує домен зі списком Public Suffix . Я рекомендую 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 () з істинним параметром

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

Це буде працювати лише в тому випадку, якщо немає wwwпри запуску рядка Трохи надто тривіальний підхід.
FooBar

Це спрощує речі для інших розробників в команді, я б скоріше скористався цим, ніж якийсь просунутий регп. Якщо ви хочете обрізати www, використовуйте обрізку ($ s, 'www'); або просто підлаштуйте його під свою логіку бізнесу ...
tasmaniski

1
Для повноти, www це насправді субдомен. Це просто часто псевдонім до доменного імені з історичних причин.
Леві Моррісон

0

Спробуйте це...

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

Думаю, було б кориснішим для ОП та для подальших відвідувачів, коли ви додасте пояснення до своїх намірів.
Репортер

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']);
Кал

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 (вибухнути ('.', $ _SERVER ['SERVER_NAME']));

    if (кол ($ хост)> = 3) {
       echo "Основний домен = =". $ host [1]. ".". $ host [0]. "& subdomain is =". $ host [2];
       // Основний домен = example.com, а субдомен - = суб
    } else {
       echo "Основний домен = =". $ host [1]. ".". $ host [0]. "& subdomain not found";
       // "Основний домен = example.com & субдомен не знайдено";
    }


-3

Якщо ви хочете лише те, що приходить до першого періоду:

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

Що робити, якщо на початку є обробник протоколу, такий як http: //, https: //, ftp: // і т.д. ...? ;)
Джаред Фарріш

@Jred, у рядку немає протоколу, який він шукає для розбору ... Але якби вони були, я б використав parse_url()для вилучення хоста.
Матвій

Тож ми запропонували два підходи, які будуть доречними у різних контекстах.
Джаред Фарріш

В основному, я просто радий, що хтось ще не опублікував зворотній зв'язок. Не кажучи вже про те, що останній рядок моєї відповіді також виконує те саме, що ви робите.
Джаред Фарріш

І якщо ім'я хоста en.example.co.uk?
Марк Б
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.