Получите корневую DNS-запись с php-сервера;получить доменное имя без www и т. д.

StackOverflow https://stackoverflow.com/questions/1375647

  •  21-09-2019
  •  | 
  •  

Вопрос

Как получить корневую запись DNS из $_SERVER['HTTP_HOST']?

Вход:

example.co.uk
www.example.com
blog.example.com
forum.example.co.uk 

Выход:

example.co.uk
example.com
example.com
example.co.uk

РЕДАКТИРОВАТЬ:Список поиска очень длинный

Это было полезно?

Решение

Для этого проекта: http://drupal.org/project/parallel

Использование:

echo parallel_get_domain("www.robknight.org.uk") . "<br>";
echo parallel_get_domain("www.google.com") . "<br>";
echo parallel_get_domain("www.yahoo.com") . "<br>";

Функции:

/**
 * Given host name returns top domain.
 *
 * @param $host
 *   String containing the host name: www.example.com
 *
 * @return string
 *   top domain: example.com
 */
function parallel_get_domain($host) {
  if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN' && strnatcmp(phpversion(),'5.3.0') < 0) {
    // This works 1/2 the time... CNAME doesn't work with nslookup
    for ($end_pieces = substr_count($host, '.'); $end_pieces > 0; $end_pieces--) {
      $test_domain = end(explode('.', $host, $end_pieces));
      if (checkdnsrr($test_domain)) {
          $domain = $test_domain;
          break;
      }
    }
    return isset($domain) ? $domain : FALSE;
  }
  else {
    // This always works
    $sections = explode('.', $host);
    array_unshift($sections, '');
    foreach($sections as $key => $value) {
      $parts[$key] = $value;
      $test_domain = implode('.', parallel_array_xor($parts, $sections));
      if (checkdnsrr($test_domain, 'NS') && !checkdnsrr($test_domain, 'CNAME')) {
        $domain = $test_domain;
        break;
      }
    }
    return isset($domain) ? $domain : FALSE;
  }
}

/**
 * Opposite of array_intersect().
 *
 * @param $array_a
 *   First array
 * @param $array_b
 *   Second array
 *
 * @return array
 */
function parallel_array_xor ($array_a, $array_b) {
  $union_array = array_merge($array_a, $array_b);
  $intersect_array = array_intersect($array_a, $array_b);
  return array_diff($union_array, $intersect_array);
}

/**
 * Win compatible version of checkdnsrr.
 *
 * checkdnsrr() support for Windows by HM2K <php [spat] hm2k.org>
 * http://us2.php.net/manual/en/function.checkdnsrr.php#88301
 *
 * @param $host
 *   String containing host name
 * @param $type
 *   String containing the DNS record type
 *
 * @return bool
 */
function parallel_win_checkdnsrr($host, $type='MX') {
  if (strtoupper(substr(PHP_OS, 0, 3)) != 'WIN') { return FALSE; }
  if (empty($host)) { return FALSE; }
  $types=array('A', 'MX', 'NS', 'SOA', 'PTR', 'CNAME', 'AAAA', 'A6', 'SRV', 'NAPTR', 'TXT', 'ANY');
  if (!in_array($type, $types)) {
    user_error("checkdnsrr() Type '$type' not supported", E_USER_WARNING);
    return FALSE;
  }
  @exec('nslookup -type=' . $type . ' ' . escapeshellcmd($host), $output);

  foreach($output as $line){
    if (preg_match('/^' . $host . '/', $line)) { return TRUE; }
  }
}

// Define checkdnsrr() if it doesn't exist
if (!function_exists('checkdnsrr')) {
  function checkdnsrr($host, $type='MX') {
    return parallel_win_checkdnsrr($host, $type);
  }
}

Вывод - Windows:

org.uk
google.com
yahoo.com

Вывод — Linux:

robknight.org.uk
google.com
yahoo.com

Другие советы

Я думаю, что это немного неточное определение.

Вы можете попробовать выполнить поиск DNS для каждой родительской записи, пока не найдете ту, которая не возвращает запись A.

/[^\.]+\.[escaped|list|of|domains]$/

Я думаю, это должно сработать.

Как вы обнаружили, некоторые страны используют только TLD (пример:.tv, .us), другие подразделяют TLD своей страны (пример:Великобритания).

В идеале вам понадобится список поиска (он не будет длинным) утвержденных TLD и, если он разделен, TLD с каждым подразделением (например, «.co.uk» вместо «.uk»).Это подскажет вам, какие «точки» (справа) оставить.Затем переместите одну точку влево от нее (если она есть) и нарежьте все, что находится перед ней.

Без списка поиска вы можете воспользоваться тем фактом, что подразделения (.co и т. д.) предназначены только для стран (которые имеют двухбуквенные TLD) и, AFAIK, сами никогда не содержат более трех символов и всегда представляют собой буквы, так что вы, вероятно, можете распознавать их с помощью шаблона регулярного выражения.

Редактировать: Неважно, фактический список общедоступных суффиксов гораздо сложнее.Вам понадобится использовать справочную таблицу, чтобы выяснить, что такое суффикс, вернуться к предыдущей точке и обрезать влево.RegEx здесь является плохим решением.Вместо этого сохраните список суффиксов в словаре, затем проверьте свое доменное имя, отсекая по одной пунктирной части слева, пока не найдете совпадение, а затем добавьте обратно только что отрезанную часть.

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

Я повторяю:не полагайтесь на то, что приведенный ниже код сработает на вас.Я оставляю это здесь только в образовательных целях.

Есть способ сделать это без списка поиска.Список может быть недостоверным или неполным, тогда как этот метод гарантированно сработает:

<?php

function get_domain($url) {
    $dots = substr_count($url, '.');
    $domain = '';

    for ($end_pieces = $dots; $end_pieces > 0; $end_pieces--) {
        $test_domain = end(explode('.', $url, $end_pieces));

        if (dns_check_record($test_domain, 'A')) {
            $domain = $test_domain;
            break;
        }
    }

    return $domain;
}

$my_domain = get_domain('www.robknight.org.uk');

echo $my_domain;

?>

В этом случае будет выведено «robknight.org.uk».Это будет одинаково хорошо работать для .com, .edu, .com.au, .ly или любого другого домена верхнего уровня, с которым вы работаете.

Это работает, начиная справа и выполняя проверку DNS для первого объекта, который выглядит как жизнеспособное доменное имя.В приведенном выше примере он начинается с «org.uk», но обнаруживает, что это не настоящее доменное имя, а ccTLD.Затем он переходит к проверке robknight.org.uk, который является действительный и возвращает это.Если бы доменное имя было, скажем, «www.php.net», оно началось бы с проверки «php.net», которое является допустимым именем домена, и вернуло бы его немедленно, без зацикливания.Я также должен отметить, что если действительное доменное имя не найдено, будет возвращена пустая строка ('').

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top