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

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

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

  • http://www.google.com/foo , parse_url () возвращает www.google.com для хоста
  • http://www.google.co.uk/foo , parse_url () возвращает www.google.co.uk для хоста

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

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

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}\.[az\.]{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 через parse_url , поэтому убедитесь, что это хорошо сформированный URL.

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

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

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

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

  • Могу ли я улучшить проверку регулярного выражения для действительных доменных имен?
  • Получить поддомен с URL-адреса

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

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

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

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

Выкопал это из связанной должности, за идею сохранения таблицы: http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/src/effective_tld_names.dat?raw=1

Я бы предпочел не делать этого.

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

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

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

Просто доказательство, предполагая, что разрешенные 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 } ?> 

Вам нужен пакет, в котором используется 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' 

Это очень простое решение:

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

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