Парсинг домена из URL


152

Мне нужно создать функцию, которая анализирует домен по URL-адресу.

Итак, с

http://google.com/dhasjkdas/sadsdds/sdda/sdads.html

или

http://www.google.com/dhasjkdas/sadsdds/sdda/sdads.html

он должен вернуться google.com

с участием

http://google.co.uk/dhasjkdas/sadsdds/sdda/sdads.html

он должен вернуться google.co.uk .



10
@LightnessRacesinOrbit Это немного больше, чем просто «заглядывать в руководство». PHP parse_url()возвращает хост , а не домен .
MrWhite

1
@ w3dk: Это все равно была бы фантастическая отправная точка, если бы этот вопрос касался этого ограничения, parse_urlа не расплывчатого «что я могу сделать».
Гонки за легкостью на орбите

5
@LightnessRacesinOrbit, ваша защита неискренняя, учитывая вашу репутацию - проще говоря, вы можете признать, что не прочитали вопрос полностью
Энди Джонс

4
@LightnessRacesinOrbit Не обязательно. support.suso.com/supki/…
Осенний Леонард,

Ответы:


307

Проверять, выписываться parse_url() :

$url = 'http://google.com/dhasjkdas/sadsdds/sdda/sdads.html';
$parse = parse_url($url);
echo $parse['host']; // prints 'google.com'

parse_url не очень хорошо обрабатывает действительно сильно искаженные URL-адреса, но это нормально, если вы обычно ожидаете приличных URL-адресов.


35
Единственное, чего не делает parse_url (), - это только возвращать домен. Если вы добавите www.google.com или www.google.co.uk, он также вернет хост. Есть предложения по этому поводу?
Гэвин М. Рой


6
parse_urlне обрабатывают поддомены, но Purl делает: github.com/jwage/purl
Дэмиен

1
parse_url()возможно, неправильно проанализирует URL-адреса с доменом, который содержит дефисы. Не удалось найти определенных доказательств, но проверьте эту ошибку . FILTER_VALIDATE_URLиспользует parse_url()внутренне.
XedinUnknown 01

8
Или просто: print parse_url($url, PHP_URL_HOST))если вам ни $parseдля чего не нужен массив.
rybo111,

98
$domain = str_ireplace('www.', '', parse_url($url, PHP_URL_HOST));

Это вернет как google.comдля http://google.com/ ..., так и для http://www.google.com/ ...


18
потому что он все равно вернет сервер, если вы введете "server.google.com" или "www3.google.com" ...
Патрик

Не все субдомены являются www, crawl-66-249-66-1.googlebot.com, myblog.blogspot.com - вот лишь несколько примеров.
rafark

23

С http://us3.php.net/manual/en/function.parse-url.php#93983

по какой-то нечетной причине parse_url возвращает хост (например, example.com) в качестве пути, если во входном URL-адресе нет схемы. Итак, я написал быструю функцию для получения настоящего хоста:

function getHost($Address) { 
   $parseUrl = parse_url(trim($Address)); 
   return trim($parseUrl['host'] ? $parseUrl['host'] : array_shift(explode('/', $parseUrl['path'], 2))); 
} 

getHost("example.com"); // Gives example.com 
getHost("http://example.com"); // Gives example.com 
getHost("www.example.com"); // Gives www.example.com 
getHost("http://example.com/xyz"); // Gives example.com 

Не забудьте процитировать строки вроде hostи path.
Gumbo

1
Если я использую example.com, php отображает уведомление: Message: Undefined index: hostесть идеи, как это исправить?
Zim3r

1
К сожалению, субдомен все еще включен в этот подход, см. Ваш пример №3.
jenlampton

1
@ Zim3r Измените первую часть троичного на !empty($parseUrl['host']).
Demonslay335

LOL, если у него нет схемы, это не URL.
miken32

12

Код, который должен был работать на 100%, похоже, не помог мне, я немного исправил пример, но нашел код, который не помогал, и проблемы с ним. поэтому я изменил его на несколько функций (чтобы не запрашивать список из Mozilla все время и удалять систему кеширования). Это было протестировано на наборе из 1000 URL-адресов и, похоже, сработало.

function domain($url)
{
    global $subtlds;
    $slds = "";
    $url = strtolower($url);

    $host = parse_url('http://'.$url,PHP_URL_HOST);

    preg_match("/[^\.\/]+\.[^\.\/]+$/", $host, $matches);
    foreach($subtlds as $sub){
        if (preg_match('/\.'.preg_quote($sub).'$/', $host, $xyz)){
            preg_match("/[^\.\/]+\.[^\.\/]+\.[^\.\/]+$/", $host, $matches);
        }
    }

    return @$matches[0];
}

function get_tlds() {
    $address = 'http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1';
    $content = file($address);
    foreach ($content as $num => $line) {
        $line = trim($line);
        if($line == '') continue;
        if(@substr($line[0], 0, 2) == '/') continue;
        $line = @preg_replace("/[^a-zA-Z0-9\.]/", '', $line);
        if($line == '') continue;  //$line = '.'.$line;
        if(@$line[0] == '.') $line = substr($line, 1);
        if(!strstr($line, '.')) continue;
        $subtlds[] = $line;
        //echo "{$num}: '{$line}'"; echo "<br>";
    }

    $subtlds = array_merge(array(
            'co.uk', 'me.uk', 'net.uk', 'org.uk', 'sch.uk', 'ac.uk', 
            'gov.uk', 'nhs.uk', 'police.uk', 'mod.uk', 'asn.au', 'com.au',
            'net.au', 'id.au', 'org.au', 'edu.au', 'gov.au', 'csiro.au'
        ), $subtlds);

    $subtlds = array_unique($subtlds);

    return $subtlds;    
}

Тогда используйте это как

$subtlds = get_tlds();
echo domain('www.example.com') //outputs: example.com
echo domain('www.example.uk.com') //outputs: example.uk.com
echo domain('www.example.fr') //outputs: example.fr

Я знаю, что должен был превратить это в урок, но не успел.


11
function get_domain($url = SITE_URL)
{
    preg_match("/[a-z0-9\-]{1,63}\.[a-z\.]{2,6}$/", parse_url($url, PHP_URL_HOST), $_domain_tld);
    return $_domain_tld[0];
}

get_domain('http://www.cdl.gr'); //cdl.gr
get_domain('http://cdl.gr'); //cdl.gr
get_domain('http://www2.cdl.gr'); //cdl.gr

У меня тоже ничего не работает: example.com // Неверно: пустая строка example.com // Правильно: example.com www.example.com // Неверно: пустая строка example.com/xyz // Правильно: example.com
jenlampton

Это отличный ответ, и он заслуживает большего доверия. Просто добавьте эту строку в качестве первой в функции, и она также решит проблемы MangeshSathe и jenlampton: if ((substr ($ url, 0, strlen ('http: //')) <> 'http: //' ) && (substr ($ url, 0, strlen ('https: //')) <> 'https: //')) $ url = 'http: //'.$url;
Rick

4

Если вы хотите извлечь хост из строки http://google.com/dhasjkdas/sadsdds/sdda/sdads.html , использование parse_url () является для вас приемлемым решением.

Но если вы хотите извлечь домен или его части, вам понадобится пакет, использующий список общедоступных суффиксов . Да, вы можете использовать строковые функции arround parse_url (), но иногда это дает неверные результаты.

Я рекомендую TLDExtract для разбора домена, вот пример кода, который показывает разницу:

$extract = new LayerShifter\TLDExtract\Extract();

# For 'http://google.com/dhasjkdas/sadsdds/sdda/sdads.html'

$url = 'http://google.com/dhasjkdas/sadsdds/sdda/sdads.html';

parse_url($url, PHP_URL_HOST); // will return google.com

$result = $extract->parse($url);
$result->getFullHost(); // will return 'google.com'
$result->getRegistrableDomain(); // will return 'google.com'
$result->getSuffix(); // will return 'com'

# For 'http://search.google.com/dhasjkdas/sadsdds/sdda/sdads.html'

$url = 'http://search.google.com/dhasjkdas/sadsdds/sdda/sdads.html';

parse_url($url, PHP_URL_HOST); // will return 'search.google.com'

$result = $extract->parse($url);
$result->getFullHost(); // will return 'search.google.com'
$result->getRegistrableDomain(); // will return 'google.com'

Большое спасибо за это предложение. Я ненавижу добавлять еще одну библиотеку для того, что кажется простой задачей, но потом я увидел в их файле readme эту цитату, примененную ко мне: «Все ошибаются. Разделение на '.' и использование последних двух элементов имеет большое значение, только если вы думаете о простых доменах, например .com. Подумайте, например, о парсинге forum.bbc.co.uk : наивный метод разделения, описанный выше, даст вам 'co' в качестве домена и 'uk' в качестве TLD вместо 'bbc' и 'co.uk' соответственно ".
Demonslay335

Результат разбиения точек на наши любимые домены .co.uk, хотя и не то, что мы хотим, на самом деле является правильным, поскольку co является вторым уровнем, а uk - верхним уровнем. Веб-мастера часто этого не осознают.
Крис

4

Я обнаружил, что решение @ philfreo (указанное на php.net) довольно хорошо для получения хорошего результата, но в некоторых случаях оно показывает сообщение php «уведомление» и «строгие стандарты». Вот исправленная версия этого кода.

function getHost($url) { 
   $parseUrl = parse_url(trim($url)); 
   if(isset($parseUrl['host']))
   {
       $host = $parseUrl['host'];
   }
   else
   {
        $path = explode('/', $parseUrl['path']);
        $host = $path[0];
   }
   return trim($host); 
} 

echo getHost("http://example.com/anything.html");           // example.com
echo getHost("http://www.example.net/directory/post.php");  // www.example.net
echo getHost("https://example.co.uk");                      // example.co.uk
echo getHost("www.example.net");                            // example.net
echo getHost("subdomain.example.net/anything");             // subdomain.example.net
echo getHost("example.net");                                // example.net

3

Пожалуйста, подумайте о замене принятого решения следующим:

parse_url () всегда будет включать любые поддомены, поэтому эта функция не очень хорошо разбирает доменные имена. Вот некоторые примеры:

$url = 'http://www.google.com/dhasjkdas/sadsdds/sdda/sdads.html';
$parse = parse_url($url);
echo $parse['host']; // prints 'www.google.com'

echo parse_url('https://subdomain.example.com/foo/bar', PHP_URL_HOST);
// Output: subdomain.example.com

echo parse_url('https://subdomain.example.co.uk/foo/bar', PHP_URL_HOST);
// Output: subdomain.example.co.uk

Вместо этого вы можете рассмотреть это прагматичное решение. Он будет охватывать многие, но не все доменные имена - например, домены более низкого уровня, такие как 'sos.state.oh.us', не покрываются.

function getDomain($url) {
    $host = parse_url($url, PHP_URL_HOST);

    if(filter_var($host,FILTER_VALIDATE_IP)) {
        // IP address returned as domain
        return $host; //* or replace with null if you don't want an IP back
    }

    $domain_array = explode(".", str_replace('www.', '', $host));
    $count = count($domain_array);
    if( $count>=3 && strlen($domain_array[$count-2])==2 ) {
        // SLD (example.co.uk)
        return implode('.', array_splice($domain_array, $count-3,3));
    } else if( $count>=2 ) {
        // TLD (example.com)
        return implode('.', array_splice($domain_array, $count-2,2));
    }
}

// Your domains
    echo getDomain('http://google.com/dhasjkdas/sadsdds/sdda/sdads.html'); // google.com
    echo getDomain('http://www.google.com/dhasjkdas/sadsdds/sdda/sdads.html'); // google.com
    echo getDomain('http://google.co.uk/dhasjkdas/sadsdds/sdda/sdads.html'); // google.co.uk

// TLD
    echo getDomain('https://shop.example.com'); // example.com
    echo getDomain('https://foo.bar.example.com'); // example.com
    echo getDomain('https://www.example.com'); // example.com
    echo getDomain('https://example.com'); // example.com

// SLD
    echo getDomain('https://more.news.bbc.co.uk'); // bbc.co.uk
    echo getDomain('https://www.bbc.co.uk'); // bbc.co.uk
    echo getDomain('https://bbc.co.uk'); // bbc.co.uk

// IP
    echo getDomain('https://1.2.3.45');  // 1.2.3.45

Наконец, PHP-анализатор домена Джереми Кендалла позволяет вам анализировать доменное имя из URL- адреса . Синтаксический анализатор имени хоста URI лиги также выполнит эту работу.


Привет, это хорошо, но не работает с IP-адресами. Тем не менее, отличная работа.
MeCe 08

2

Вот код, который я сделал, что 100% находит только доменное имя, так как для него нужны под-TLD Mozilla. Единственное, что вам нужно проверить, это то, как вы делаете кеш этого файла, чтобы вы не запрашивали Mozilla каждый раз.

По какой-то странной причине доменов, таких как co.uk, нет в списке, поэтому вам придется немного взломать и добавить их вручную. Это не самое чистое решение, но я надеюсь, что это кому-то поможет.

//=====================================================
static function domain($url)
{
    $slds = "";
    $url = strtolower($url);

            $address = 'http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1';
    if(!$subtlds = @kohana::cache('subtlds', null, 60)) 
    {
        $content = file($address);
        foreach($content as $num => $line)
        {
            $line = trim($line);
            if($line == '') continue;
            if(@substr($line[0], 0, 2) == '/') continue;
            $line = @preg_replace("/[^a-zA-Z0-9\.]/", '', $line);
            if($line == '') continue;  //$line = '.'.$line;
            if(@$line[0] == '.') $line = substr($line, 1);
            if(!strstr($line, '.')) continue;
            $subtlds[] = $line;
            //echo "{$num}: '{$line}'"; echo "<br>";
        }
        $subtlds = array_merge(Array(
            'co.uk', 'me.uk', 'net.uk', 'org.uk', 'sch.uk', 'ac.uk', 
            'gov.uk', 'nhs.uk', 'police.uk', 'mod.uk', 'asn.au', 'com.au',
            'net.au', 'id.au', 'org.au', 'edu.au', 'gov.au', 'csiro.au',
            ),$subtlds);

        $subtlds = array_unique($subtlds);
        //echo var_dump($subtlds);
        @kohana::cache('subtlds', $subtlds);
    }


    preg_match('/^(http:[\/]{2,})?([^\/]+)/i', $url, $matches);
    //preg_match("/^(http:\/\/|https:\/\/|)[a-zA-Z-]([^\/]+)/i", $url, $matches);
    $host = @$matches[2];
    //echo var_dump($matches);

    preg_match("/[^\.\/]+\.[^\.\/]+$/", $host, $matches);
    foreach($subtlds as $sub) 
    {
        if (preg_match("/{$sub}$/", $host, $xyz))
        preg_match("/[^\.\/]+\.[^\.\/]+\.[^\.\/]+$/", $host, $matches);
    }

    return @$matches[0];
}

Причина, по которой домен co.ukне был в списке, заключалась в том, что это был список TLD, а не доменов. CcTLD сильно изменился с момента написания этого ответа. Примечательно: «Новые регистрации непосредственно под .uk были приняты Nominet с 10 июня 2014 г., 08:00 BST, однако существует период резервирования для существующих клиентов, у которых уже есть .co.uk, .org.uk, .me.uk. , .net.uk, .ltd.uk или .plc.uk, чтобы заявить права на соответствующий домен .uk, который будет работать до 07:59 BST 10 июня 2019 г. " ( Источник )
ashleedawg

2

Вы можете передать PHP_URL_HOST в функцию parse_url в качестве второго параметра

$url = 'http://google.com/dhasjkdas/sadsdds/sdda/sdads.html';
$host = parse_url($url, PHP_URL_HOST);
print $host; // prints 'google.com'

2
По сути, это то же самое, что и ответ выше, однако вопрос требует домена , который не обязательно совпадает с хостом .
MrWhite

см. комментарий выше о схеме: по какой-то нечетной причине parse_url возвращает хост (например, example.com) в качестве пути, если во входном URL-адресе нет схемы. Итак, я написал быструю функцию, чтобы получить настоящего хозяина:
jenlampton


1

parse_url у меня не работал. Это только вернуло путь. Переход к основам с использованием php5.3 +:

$url  = str_replace('http://', '', strtolower( $s->website));
if (strpos($url, '/'))  $url = strstr($url, '/', true);

1

Я отредактировал для вас:

function getHost($Address) { 
    $parseUrl = parse_url(trim($Address));
    $host = trim($parseUrl['host'] ? $parseUrl['host'] : array_shift(explode('/', $parseUrl['path'], 2))); 

    $parts = explode( '.', $host );
    $num_parts = count($parts);

    if ($parts[0] == "www") {
        for ($i=1; $i < $num_parts; $i++) { 
            $h .= $parts[$i] . '.';
        }
    }else {
        for ($i=0; $i < $num_parts; $i++) { 
            $h .= $parts[$i] . '.';
        }
    }
    return substr($h,0,-1);
}

URL всех типов (www.domain.ltd, sub1.subn.domain.ltd приведет к: domain.ltd.


1

Я добавляю этот ответ поздно, так как это ответ, который чаще всего появляется в Google ...

Вы можете использовать PHP для ...

$url = "www.google.co.uk";
$host = parse_url($url, PHP_URL_HOST);
// $host == "www.google.co.uk"

чтобы захватить хост, но не частный домен, на который ссылается хост. (Пример www.google.co.uk- это хост, но google.co.ukэто частный домен)

Чтобы получить частный домен, вам необходимо знать список общедоступных суффиксов, для которых можно зарегистрировать частный домен. Этот список курируется Mozilla по адресу https://publicsuffix.org/.

Приведенный ниже код работает, когда уже создан массив общедоступных суффиксов. Просто позвоните

$domain = get_private_domain("www.google.co.uk");

с оставшимся кодом ...

// find some way to parse the above list of public suffix
// then add them to a PHP array
$suffix = [... all valid public suffix ...];

function get_public_suffix($host) {
  $parts = split("\.", $host);
  while (count($parts) > 0) {
    if (is_public_suffix(join(".", $parts)))
      return join(".", $parts);

    array_shift($parts);
  }

  return false;
}

function is_public_suffix($host) {
  global $suffix;
  return isset($suffix[$host]);
}

function get_private_domain($host) {
  $public = get_public_suffix($host);
  $public_parts = split("\.", $public);
  $all_parts = split("\.", $host);

  $private = [];

  for ($x = 0; $x < count($public_parts); ++$x) 
    $private[] = array_pop($all_parts);

  if (count($all_parts) > 0)
    $private[] = array_pop($all_parts);

  return join(".", array_reverse($private));
}

Согласно моему тестированию, parse_url нужен правильно сформированный URL. Если вы просто укажете «www.someDomain.com/path», он вернет null. Таким образом, он ожидает наличия протоколов (например, http или https).
Энди

0

Как правило, это будет работать очень хорошо, если входной URL-адрес не является полным мусором. Удаляет поддомен.

$host = parse_url( $Row->url, PHP_URL_HOST );
$parts = explode( '.', $host );
$parts = array_reverse( $parts );
$domain = $parts[1].'.'.$parts[0];

пример

Вход: http://www2.website.com:8080/some/file/structure?some=parameters

Выход: website.com


0

Объединение ответов worldofjr и Аликс Аксель в одну небольшую функцию, которая будет обрабатывать большинство сценариев использования:

function get_url_hostname($url) {

    $parse = parse_url($url);
    return str_ireplace('www.', '', $parse['host']);

}

get_url_hostname('http://www.google.com/example/path/file.html'); // google.com

это ограниченное решение
MGE

0
function getTrimmedUrl($link)
{
    $str = str_replace(["www.","https://","http://"],[''],$link);
    $link = explode("/",$str);
    return strtolower($link[0]);                
}

-6

Просто используйте как следующее ...

<?php
   echo $_SERVER['SERVER_NAME'];
?>

1
Предполагается, что сервер - это URL-адрес, с которого вы хотите получить домен. Это не так.
Overcode
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.