Веб-разработка на PHP: эффективное управление доменами

Раздел: PHP -> Веб-разработка на PHP

Работа с доменами в PHP: методы и примеры

Наиболее эффективное решение - использование библиотеки pdp/domain (PHP Domain Parser). Она предоставляет полный набор функций для разбора, валидации и нормализации доменных имён, включая поддержку международных доменов (IDN) и актуального списка TLD.


composer require pdp/domain

App path php (работа с путями файлов в php)

Пример использования:


<?php
use Pdp\Domain;
use Pdp\TopLevelDomains;

$tlds = TopLevelDomains::fromICANN();
$domain = Domain::fromString('subdomain.example.co.uk', $tlds);

echo 'Регистрируемый домен: ' . $domain->registrable()->toString() . PHP_EOL;
echo 'Поддомен: ' . ($domain->subDomain() ? $domain->subDomain()->toString() : 'отсутствует') . PHP_EOL;
echo 'TLD: ' . $domain->suffix()->toString() . PHP_EOL;

App php domain (работа с доменами в php)

Регистрируемый домен: example.co.uk
Поддомен: subdomain
TLD: co.uk

Http user agent php (получение user-agent в php)

Пояснение: метод registrable() возвращает основное доменное имя (без поддоменов), subDomain() - поддомен (если есть), suffix() - суффикс (TLD). Библиотека автоматически определяет правильные TLD на основе списка ICANN.

Типичная ошибка: передача URL вместо чистого домена. Решение: предварительно извлекать хост из URL с помощью parse_url().

Как проверить, является ли строка корректным доменным именем с помощью встроенных функций?

В PHP есть функция filter_var() с флагом FILTER_VALIDATE_DOMAIN, доступная с PHP 7.


<?php
$domain = 'example.com';
if (filter_var($domain, FILTER_VALIDATE_DOMAIN)) {
    echo "Домен корректен";
} else {
    echo "Некорректный домен";
}

Config app php (конфигурация php приложения)

Домен корректен

создание скриптов php (создание скриптов php)

Однако фильтр не поддерживает международные домены (IDN) и проверяет только формат.

Проблема: для IDN необходимо сначала преобразовать в ASCII (Punycode) функцией idn_to_ascii().

Как извлечь домен из полного URL?

Используйте parse_url() для получения хоста, затем разберите его на домен и поддомен.


<?php
$url = 'https://user:pass@sub.example.com:8080/path?query=1#frag';
$host = parse_url($url, PHP_URL_HOST);
echo $host; // sub.example.com

App php route (маршрутизация в php приложении)

sub.example.com

Php create html (создание html в php)

Для отделения регистрируемого домена от поддомена можно применить библиотеку или регулярное выражение (но это ненадёжно).

Ошибка: parse_url() может вернуть false для некорректного URL. Всегда проверяйте результат.

Как валидировать домен с помощью регулярного выражения?

Простое регулярное выражение для ASCII-доменов:


<?php
$pattern = '/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,}$/i';
$domain = 'example.com';
if (preg_match($pattern, $domain)) {
    echo "Домен соответствует формату";
}

Default php app (настройки по умолчанию в php приложении)

Домен соответствует формату

Php веб сервисы (php веб-сервисы)

Но регулярное выражение не учитывает IDN и может устареть при появлении новых TLD.

Проблема: длина сегмента не должна превышать 63 символа, а общая длина домена - 253 символа. Регулярное выражение с этими ограничениями становится слишком сложным.

Как проверить, существует ли домен в DNS?

Функции checkdnsrr() и gethostbyname() позволяют проверить наличие записей DNS.


<?php
$domain = 'example.com';
if (checkdnsrr($domain, 'ANY')) {
    echo "Домен существует (обнаружены DNS-записи)";
} else {
    echo "Домен не найден";
}

Login php app (реализация входа пользователя в php)

Домен существует (обнаружены DNS-записи)

App php link (создание ссылок в php приложении)

Однако результат зависит от сети и DNS-кеширования.

Типичная ошибка: запрос может вернуть false из-за временного сбоя DNS. Рекомендуется реализовать повторные попытки.

Как работать с международными доменными именами (IDN)?

Используйте функции idn_to_ascii() и idn_to_utf8() для преобразования между Unicode и Punycode.


<?php
$idn = 'пример.рф';
$ascii = idn_to_ascii($idn, IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46);
echo $ascii; // xn--e1afmkfd.xn--p1ai

$back = idn_to_utf8($ascii, IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46);
echo $back; // пример.рф

App controller php (создание контроллера в php приложении)

xn--e1afmkfd.xn--p1ai
пример.рф

Важно указывать вариант INTL_IDNA_VARIANT_UTS46 для корректной обработки.

Ошибка: если расширение intl не установлено, функции не работают. Убедитесь, что оно включено.

- веб сайт php (веб-сайт на php)

Расширенные примеры работы с доменами в PHP

1. Полный конвейер валидации и разбора с pdp/domain, включая IDN

Пример

<?php
require 'vendor/autoload.php';

use Pdp\Domain;
use Pdp\TopLevelDomains;

function processDomain($input) {
    // Преобразование IDN в ASCII, если необходимо
    if (mb_detect_encoding($input) !== 'ASCII') {
        $input = idn_to_ascii($input, IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46);
        if ($input === false) {
            throw new \InvalidArgumentException('Некорректное международное доменное имя');
        }
    }
    
    $tlds = TopLevelDomains::fromICANN();
    $domain = Domain::fromString($input, $tlds);
    
    return [
        'full'          => $domain->toString(),
        'registrable'   => $domain->registrable()->toString(),
        'subdomain'     => $domain->subDomain() ? $domain->subDomain()->toString() : null,
        'suffix'        => $domain->suffix()->toString(),
        'publicSuffix'  => $domain->publicSuffix()->toString(),
    ];
}

$result = processDomain('мой.сайт.пример.рф');
print_r($result);
Array
(
    [full] => мой.сайт.пример.рф
    [registrable] => пример.рф
    [subdomain] => мой.сайт
    [suffix] => рф
    [publicSuffix] => рф
)

В примере сначала определяется кодировка входной строки. Если она не ASCII, выполняется преобразование Punycode. Затем создаётся объект Domain и извлекаются все компоненты.

2. Разбор сложного URL с извлечением компонентов домена

Пример

<?php
$url = 'ftp://user:secret@deep.sub.domain.example.co.uk:2121/path/to/file?param=value#section';
$parts = parse_url($url);

$scheme   = $parts['scheme'] ?? '';
$host     = $parts['host'] ?? '';
$port     = $parts['port'] ?? 80;
$user     = $parts['user'] ?? '';
$pass     = $parts['pass'] ?? '';

// Используем pdp для разбора хоста
require 'vendor/autoload.php';
use Pdp\Domain;
use Pdp\TopLevelDomains;

$tlds = TopLevelDomains::fromICANN();
$domain = Domain::fromString($host, $tlds);

echo "Схема: $scheme\n";
echo "Регистрируемый домен: " . $domain->registrable()->toString() . "\n";
echo "Поддомен: " . ($domain->subDomain() ? $domain->subDomain()->toString() : 'нет') . "\n";
echo "TLD: " . $domain->suffix()->toString() . "\n";
echo "Пользователь: $user\n";
echo "Пароль: $pass\n";
echo "Порт: $port\n";
Схема: ftp
Регистрируемый домен: example.co.uk
Поддомен: deep.sub.domain
TLD: co.uk
Пользователь: user
Пароль: secret
Порт: 2121

3. Проверка DNS с таймаутом и повторными попытками

Пример

<?php
function checkDomainDNS($domain, $maxAttempts = 3, $timeout = 2) {
    for ($i = 1; $i <= $maxAttempts; $i++) {
        $result = @checkdnsrr($domain . '.', 'A', $timeout);
        if ($result !== false) {
            return true;
        }
        // Ожидание перед повторной попыткой
        if ($i < $maxAttempts) usleep(200000);
    }
    return false;
}

$domain = 'google.com';
if (checkDomainDNS($domain)) {
    echo "Домен $domain имеет A-запись";
} else {
    echo "Не удалось подтвердить существование $domain (возможно временная ошибка)";
}
Домен google.com имеет A-запись

4. Генерация списка поддоменов из шаблона

Пример

<?php
$baseDomain = 'example.com';
$subdomainParts = ['www', 'api', 'admin', 'mail', 'blog'];

$subdomains = array_map(function($sub) use ($baseDomain) {
    return "$sub.$baseDomain";
}, $subdomainParts);

print_r($subdomains);
Array
(
    [0] => www.example.com
    [1] => api.example.com
    [2] => admin.example.com
    [3] => mail.example.com
    [4] => blog.example.com
)

Такой подход удобен для предварительной проверки DNS всех поддоменов.

5. Валидация доменной части email-адреса с проверкой MX-записей

Пример

<?php
function validateEmailDomain($email) {
    $parts = explode('@', $email);
    if (count($parts) !== 2) return false;
    $domain = $parts[1];
    
    // Базовая валидация формата
    if (!filter_var($domain, FILTER_VALIDATE_DOMAIN)) return false;
    
    // Проверка наличия MX-записей
    if (!checkdnsrr($domain, 'MX')) return false;
    
    return true;
}

$emails = ['user@gmail.com', 'invalid@nonexistentdomain123456.local'];
foreach ($emails as $email) {
    echo "$email: " . (validateEmailDomain($email) ? 'допустим' : 'недопустим') . "\n";
}
user@gmail.com: допустим
invalid@nonexistentdomain123456.local: недопустим

6. Расширенное регулярное выражение с учётом ограничений длин

Пример

<?php
$pattern = '/\A
    (?:
        [a-z0-9]                     # первый символ буква или цифра
        (?:[a-z0-9-]{0,61}[a-z0-9])? # остальные символы, максимум 63 всего
    \.
    )+
    [a-z]{2,63}                      # TLD (буквы, от 2 до 63)
\z/ix';

$testDomains = ['example.com', 'sub-domain.example.co.uk', '-invalid.example.com', 'a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.com'];
foreach ($testDomains as $d) {
    echo "$d: " . (preg_match($pattern, $d) ? 'OK' : 'FAIL') . "\n";
}
example.com: OK
sub-domain.example.co.uk: OK
-invalid.example.com: FAIL
a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.com: FAIL (сегменты больше 63)

7. Работа с IDN: конвертация и сортировка

Пример

<?php
$domains = ['пример.рф', 'test.com', 'münchen.de', 'δοκιμή.gr'];

// Преобразование в ASCII для сортировки
$asciiDomains = array_map(function($d) {
    return idn_to_ascii($d, IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46);
}, $domains);

sort($asciiDomains);

// Обратное преобразование
$sorted = array_map(function($d) {
    return idn_to_utf8($d, IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46);
}, $asciiDomains);

print_r($sorted);
Array
(
    [0] => test.com
    [1] => münchen.de
    [2] => δοκιμή.gr
    [3] => пример.рф
)

Сортировка выполняется по слепому ASCII-представлению, затем результат возвращается в читаемом виде.

Работа с доменами в PHP - comments

En
App php domain (php)