Переход туда, где отсутствует PHP parse_url(), - анализ только домена

PHP parse_url() имеет поле хоста, которое включает полный хост. Я ищу самый надежный (и наименее дорогостоящий) способ только вернуть домен и TLD.

Учитывая примеры:

Я ищу только google.com или google.co.uk. Я рассматривал таблицу действительных TLD/суффиксов и допускал только те и одно слово. Сделали бы это по-другому? Кто-нибудь знает о заранее подготовленном действительном REGEX для такого рода вещей?

Ответ 1

Как насчет чего-то подобного?

function getDomain($url) {
  $pieces = parse_url($url);
  $domain = isset($pieces['host']) ? $pieces['host'] : '';
  if (preg_match('/(?P<domain>[a-z0-9][a-z0-9\-]{1,63}\.[a-z\.]{2,6})$/i', $domain, $regs)) {
    return $regs['domain'];
  }
  return false;
}

Будет извлечено доменное имя с помощью классического parse_url, а затем найдите действительный домен без какого-либо субдомена (www является субдоменом). Не будет работать над такими вещами, как "localhost". Вернет false, если он ничего не соответствует.

//Редактировать:

Попробуйте:

echo getDomain('http://www.google.com/test.html') . '<br/>';
echo getDomain('https://news.google.co.uk/?id=12345') . '<br/>';
echo getDomain('http://my.subdomain.google.com/directory1/page.php?id=abc') . '<br/>';
echo getDomain('https://testing.multiple.subdomain.google.co.uk/') . '<br/>';
echo getDomain('http://nothingelsethan.com') . '<br/>';

И он должен вернуться:

google.com
google.co.uk
google.com
google.co.uk
nothingelsethan.com

Конечно, он ничего не вернет, если он не пройдет через parse_url, поэтому убедитесь, что он хорошо сформирован URL.

//Добавление:

Альнитак прав. Решение, представленное выше, будет работать в большинстве случаях, но не обязательно для всех, и их необходимо поддерживать, чтобы убедиться, например, что они не являются новым TLD с символами .morethan6 и т.д. Единственным надежным способом извлечения домена является использование сохраненного списка, такого как http://publicsuffix.org/. Это более болезненно сначала, но проще и надежнее в долгосрочной перспективе. Вам нужно убедиться, что вы понимаете плюсы и минусы каждого метода и то, как он соответствует вашему проекту.

Ответ 2

В настоящее время единственный "правильный" способ сделать это - использовать список, который поддерживается в http://publicsuffix.org/

Кстати, этот вопрос также в значительной степени дублируется:

В IETF есть попытки стандартизации, рассматривающие методы DNS, объявляющие, что конкретный node в дереве DNS используется для "публичных" регистраций, но они находятся на ранних стадиях разработки. Все популярные браузеры, отличные от IE, используют список publicsuffix.org.

Ответ 3

Существует также очень хороший порт Python tldextract module http://w-shadow.com/blog/2012/08/28/tldextract - это выходит за рамки parse_url и позволяет фактически получить домен/без субдомена.

С веб-сайта модуля:

$components = tldextract('http://www.bbc.co.uk');
echo $components->subdomain; // www
echo $components->domain;    // bbc
echo $components->tld;       // co.uk

Ответ 5

Конечно, это зависит от вашего конкретного варианта использования, но, вообще говоря, я бы не использовал поиск таблицы для TLD. Появляются новые TLD, и вы обычно не хотите их поддерживать нигде. Просто спросите меня, как часто мое имя [email protected] было отклонено из-за близорукости.

Думаю, я мог бы помочь лучше, если бы знал, почему вы не хотите www? Вам это нужно для электронных писем? Вы можете запросить записи MX в таких случаях, чтобы проверить (в конечном итоге) прием писем.

Вы также можете найти помощь с функциями PHP, связанными с записями DNS, чтобы узнать больше о них, см. http://php.net/dns_get_record.

Ответ 6

Просто доказательство, предполагая, что разрешенные tlds запомнены в хэш. Код может быть значительно сокращен.

<?php
    $urlCompoments=parse_url($theUrl);
    $chunk=explode('.',$urlComponents['host']);

    $tldIndex = count($chunk-1); // assume last chunk is tld
    $maxTldLen = 2; // assuming a tld can be in the form .com or .co.uk
    $cursor=1;
    $found=false;
    while(($cursor<=$maxTldLen) or $found) {
      $tls = implode('.',array_slice($chunk, -$cursor));
      $found=isset($tldSuffixesAllowed[$tld]);
      $cursor++;
    }
    if ($found){
       $tld=implode('.',array_slice($chunk, -$cursor));
    } else {
       // domain not recognized, do wathever you want
    }
?>

Ответ 7

Вам нужен пакет, который использует Public Suffix List, только таким образом вы можете корректно извлекать домены с двумя доменами третьего уровня (co.uk, a.bg, b.bg и т.д.) и многоуровневые субдомены. Regex, parse_url() или строковые функции никогда не приведут к абсолютно правильному результату.

Я рекомендую использовать TLD Extract. Вот пример кода:

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

$result = $extract->parse('http://www.google.co.uk/foo');
$result->getSubdomain(); // will return (string) 'www'
$result->getHostname(); // will return (string) 'google'
$result->getSuffix(); // will return (string) 'co.uk'
$result->getRegistrableDomain(); // will return (string) 'google.co.uk'

Ответ 8

Существует очень простое решение:

function get_domain($url) {
  $pieces = parse_url($url);
  return array_pop(explode('.', $pieces['host'], 2));
}

Неужели это сработает?