Функция PHP dns_get_record(): всё, что нужно знать
Функция PHP dns_get_record() позволяет получать различные типы DNS-записей для доменного имени. Узнайте, как её использовать.
Когда вашему коду нужно найти почтовый сервер для домена, проверить, что имя хоста разрешается, или прочитать SPF/TXT-записи для проверки доставляемости электронной почты, вам необходим доступ к системе доменных имён (DNS). Встроенная функция PHP dns_get_record() выполняет такой запрос на уровне протокола и возвращает записи в виде PHP array — без необходимости вызывать dig.
В этой главе рассматриваются сигнатура функции, типы записей, которые она может получать, точная структура возвращаемого array, способ чтения авторитативной и дополнительной секций DNS-ответа, а также подводные камни (в особенности разница между DNS_ANY и комбинацией конкретных констант).
Уведомление об устаревании.
dns_get_record()была помечена как устаревшая в PHP 8.3 и запланирована к удалению в следующем выпуске. В новом коде предпочтительнее использовать расширениеgetdns, стороннюю библиотеку резолвера (например,react/dns), или более узкие вспомогательные функцииcheckdnsrr()иgethostbyname(), когда вам нужен лишь ответ да/нет или единственная A-запись. Концепции, описанные ниже, по-прежнему применимы к этим альтернативам.
Что делает dns_get_record()
dns_get_record() запрашивает DNS для одного доменного имени и возвращает совпадающие ресурсные записи в виде array ассоциативных array. Вы выбираете, какой тип записи получить (A, MX, TXT и т.д.). В отличие от gethostbyname(), которая разрешает имя хоста только в один IPv4-адрес, dns_get_record() открывает доступ к полной записи — TTL, приоритет, цель и специфичные для типа поля.
Синтаксис
dns_get_record(
string $hostname,
int $type = DNS_ANY,
array &$authoritative_name_servers = null,
array &$additional_records = null,
bool $raw = false
): array|false| Параметр | Описание |
|---|---|
$hostname | Доменное имя для поиска, например "php.net". |
$type | Константа DNS_*, выбирающая тип записи. Необязательный; по умолчанию DNS_ANY. Можно объединять константы с помощью OR — `DNS_A |
&$authoritative_name_servers | Заполняется по ссылке авторитативными записями (NS) из секции authority DNS-ответа. |
&$additional_records | Заполняется по ссылке дополнительными (glue) записями, которые возвращает сервер. |
$raw | Когда true, запрашивает только точный $type и возвращает записи в сыром виде. По умолчанию false. |
Функция возвращает array записей или false в случае ошибки (например, когда хост не существует или резолвер недоступен).
Базовый запрос
Каждая возвращаемая запись — это ассоциативный array. Каждая запись содержит ключи host, class, type и ttl; остальные ключи зависят от типа записи.
<?php
$records = dns_get_record("php.net", DNS_A);
print_r($records);Типичный результат выглядит так (IP-адрес и TTL могут отличаться):
Array
(
[0] => Array
(
[host] => php.net
[class] => IN
[ttl] => 3600
[type] => A
[ip] => 185.85.0.29
)
)Поскольку результат — это обычный array, вы итерируете его с помощью foreach и читаете поля каждой записи напрямую:
<?php
foreach (dns_get_record("php.net", DNS_A) as $record) {
echo $record['host'] . " -> " . $record['ip'] . "\n";
}Распространённые типы записей
Передайте одну из этих констант DNS_* в качестве аргумента $type. Специфичные для типа ключи, которые можно ожидать, перечислены рядом с каждой.
| Константа | Запись | Специфичные для типа ключи |
|---|---|---|
DNS_A | IPv4-адрес | ip |
DNS_AAAA | IPv6-адрес | ipv6 |
DNS_MX | Почтовый обменник | pri, target |
DNS_NS | Авторитативный сервер имён | target |
DNS_CNAME | Каноническое имя (псевдоним) | target |
DNS_TXT | Текстовая запись (SPF, верификация) | txt, entries |
DNS_SOA | Начало зоны полномочий | mname, rname, serial, … |
DNS_ANY | Любой тип, возвращаемый резолвером | варьируется |
Чтобы получить несколько типов за один раз, объедините константы с помощью побитового оператора OR (|):
<?php
// A + MX records in a single call
$records = dns_get_record("php.net", DNS_A | DNS_MX);
foreach ($records as $record) {
echo $record['type'] . "\n";
}Подводный камень —
DNS_ANYvs комбинирование констант.DNS_ANYотправляет единственный запросANY, и многие резолверы и авторитативные серверы теперь отклоняют или усекают его (RFC 8482). Если вам нужны конкретные записи, объединяйте точные константы через OR (DNS_A | DNS_MX | DNS_TXT) вместо использованияDNS_ANY— это надёжнее и эффективнее.
Чтение авторитативных и дополнительных записей
Третий и четвёртый параметры заполняются по ссылке. Они открывают доступ к секциям authority и additional DNS-ответа, что полезно, когда вам нужны серверы имён, ответившие на запрос, или glue A-записи для цели MX:
<?php
$authns = [];
$addtl = [];
$records = dns_get_record("php.net", DNS_MX, $authns, $addtl);
echo "MX records: " . count($records) . "\n";
echo "Authoritative NS: " . count($authns) . "\n";
echo "Additional records: " . count($addtl) . "\n";Обработка ошибок
dns_get_record() возвращает false, когда запрос завершается неудачей. Всегда проверяйте это перед итерацией, иначе foreach над false вызовет предупреждение:
<?php
$records = dns_get_record("definitely-not-a-real-domain.invalid", DNS_A);
if ($records === false || $records === []) {
echo "No records found.\n";
} else {
print_r($records);
}Для простой проверки «существует ли эта запись?» функция checkdnsrr() легковеснее, поскольку возвращает boolean вместо построения полного array записей.
Практический пример: проверка MX домена электронной почты
Распространённый реальный случай использования — подтверждение того, что адрес электронной почты принадлежит домену, который действительно может принимать почту, — удобно делать после того, как filter_var() проверил формат адреса:
<?php
function domainCanReceiveMail(string $email): bool
{
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
return false;
}
$domain = substr(strrchr($email, "@"), 1);
$mx = dns_get_record($domain, DNS_MX);
return is_array($mx) && count($mx) > 0;
}
var_dump(domainCanReceiveMail("[email protected]")); // bool(true)Проверка формата и существования MX необходима, но недостаточна — они не доказывают, что конкретный почтовый ящик существует. Это дешёвый первичный фильтр, который отсеивает опечатки и одноразовые домены до попытки отправки.
Заключение
dns_get_record() предоставляет PHP прямой структурированный доступ к DNS-данным: выберите тип записи с помощью константы DNS_*, итерируйте возвращаемый array и читайте специфичные для типа поля. Предпочитайте объединение точных констант через OR вместо DNS_ANY, всегда защищайтесь от возврата false и обращайтесь к checkdnsrr() или gethostbyname(), когда вам нужен более узкий ответ. Поскольку функция находится на пути к удалению из PHP, изолируйте DNS-запросы за небольшим вспомогательным методом, чтобы позднее можно было перейти на расширение getdns или библиотеку резолвера без изменения остального кода.