PHP parse_url () имеет поле хоста, которое включает полный хост. Я ищу самый надежный (и наименее дорогостоящий) способ только вернуть домен и TLD.
Учитывая примеры:
Я ищу только 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/
Кстати, этот вопрос также в значительной степени дублируется:
В 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)); }
Неужели это сработает?