Определение адреса сервера в PHP: hostname и IP

Раздел: Администрирование -> Веб-серверы

Получение адреса сервера в PHP: обзор методов

Как получить основное доменное имя сервера?

Наиболее прямым и эффективным решением является использование суперглобального массива $_SERVER['SERVER_NAME']. Эта переменная содержит имя хоста, указанное в конфигурации веб-сервера (обычно из директивы ServerName). Она не подвержена подмене со стороны клиента, так как формируется на стороне сервера.


<?php
$serverName = $_SERVER['SERVER_NAME'] ?? 'неопределено';
echo 'Имя сервера: ' . $serverName;
?>
  
Имя сервера: example.com
  

Пояснение: Оператор ?? (null coalescing) гарантирует, что при отсутствии ключа 'SERVER_NAME' (например, в CLI-режиме) будет использовано значение по умолчанию.

Типичные проблемы и ошибки:

  • Переменная может отсутствовать при запуске скрипта из командной строки (CLI). Решение: проверять наличие через isset() или использовать альтернативы.
  • В некоторых конфигурациях (Apache с UseCanonicalName Off) SERVER_NAME может совпадать с HTTP_HOST, что снижает надёжность. Рекомендуется явно настроить UseCanonicalName On.
  • При использовании виртуальных хостов без правильного ServerName значение может быть неожиданным.

Как получить имя хоста из HTTP-заголовка Host?

Переменная $_SERVER['HTTP_HOST'] содержит значение заголовка Host, отправленного клиентом. Это может быть как доменное имя, так и IP-адрес с портом.


<?php
$httpHost = $_SERVER['HTTP_HOST'] ?? 'неопределено';
echo 'HTTP Host: ' . $httpHost;
?>
  
HTTP Host: www.example.com:8080
  

Область применения: когда требуется получить точное значение, которое видит клиент (например, при генерации абсолютных ссылок для ответа).

Проблемы:

  • Значение может быть подделано злоумышленником (в запросе можно отправить произвольный заголовок). Это создаёт уязвимость при использовании без проверки.
  • При использовании прокси-серверов (например, nginx) HTTP_HOST может отличаться от реального сервера.
  • Отсутствует при запросах HTTP/1.0 без заголовка Host.

Как получить сетевое имя хоста в PHP без HTTP-запроса?

Функция gethostname() возвращает сетевое имя машины, на которой выполняется скрипт. Это полезно в CLI, cron-задачах или фоновых процессах, где нет HTTP-окружения.


<?php
$hostname = gethostname();
echo 'Hostname: ' . ($hostname ?: 'не удалось определить');
?>
  
Hostname: server01.local
  

Примечание: Функция возвращает результат системного вызова uname() или аналогичного. В некоторых контейнеризированных средах может вернуть идентификатор контейнера.

Возможные сложности:

  • В случае ошибки возвращает false.
  • Не подходит, если требуется публичное доменное имя сервера, а не внутреннее сетевое.

Как узнать IP-адрес сервера?

Переменная $_SERVER['SERVER_ADDR'] содержит IP-адрес, на котором работает веб-сервер.


<?php
$serverIp = $_SERVER['SERVER_ADDR'] ?? '0.0.0.0';
echo 'IP сервера: ' . $serverIp;
?>
  
IP сервера: 192.168.1.10
  

Использование: при необходимости логирования, ограничения доступа по IP или формирования URL.

Ошибки:

  • Если сервер имеет несколько IP-адресов, возвращается только один (привязанный к виртуальному хосту).
  • При использовании прокси может вернуть адрес прокси, а не конечного сервера.

Как получить hostname с помощью php_uname()?

Функция php_uname('n') возвращает имя узла (hostname) операционной системы. Это альтернатива gethostname().


<?php
$hostname = php_uname('n');
echo 'Hostname (uname): ' . $hostname;
?>
  
Hostname (uname): debian-web
  

Отличие: работает даже если gethostname() недоступна на старой версии PHP.

Проблемы:

  • Зависит от настроек системы, в контейнерах может быть неинформативно.
  • Не даёт информацию о домене.

Как получить hostname через системную команду?

Можно выполнить команду hostname через exec, shell_exec или system. Этот способ требует настроек безопасности.


<?php
$hostname = trim(shell_exec('hostname'));
echo 'Hostname (exec): ' . ($hostname ?: 'ошибка');
?>
  
Hostname (exec): web-srv-01
  

Когда применять: если встроенные функции PHP не дают нужного результата (например, при проблемах с локальными настройками).

Недостатки:

  • Может быть отключено в php.ini (директива disable_functions).
  • Создаёт дополнительную нагрузку и потенциальные риски безопасности (внедрение команд).

Расширенные примеры и сценарии

Построение полного URL сервера

Часто требуется сформировать базу URL (схема + хост + порт) для последующего использования в ссылках и перенаправлениях. Пример комбинирования методов:

Пример

<?php
function getServerUrl(): string {
    $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
    if (isset($_SERVER['REQUEST_SCHEME'])) {
        $scheme = $_SERVER['REQUEST_SCHEME'];
    }
    $host = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? 'localhost';
    $port = $_SERVER['SERVER_PORT'] ?? '80';
    // Убираем стандартный порт для чистого URL
    if (($scheme === 'http' && $port == 80) || ($scheme === 'https' && $port == 443)) {
        $port = '';
    } else {
        $port = ':' . $port;
    }
    return $scheme . '://' . $host . $port;
}
echo 'Базовый URL: ' . getServerUrl();
?>
Базовый URL: https://www.example.com:8080

Определение схемы (http/https) несколькими способами

Кроме $_SERVER['HTTPS'] можно использовать $_SERVER['REQUEST_SCHEME'] (доступен в PHP 5.5+ с некоторыми SAPI) или заголовок X-Forwarded-Proto при работе за прокси.

Пример

<?php
function detectScheme(): string {
    if (isset($_SERVER['REQUEST_SCHEME'])) {
        return $_SERVER['REQUEST_SCHEME'];
    }
    if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') {
        return 'https';
    }
    // Для прокси
    if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
        return strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']);
    }
    return 'http';
}
echo 'Схема: ' . detectScheme();
?>
Схема: https

Надёжная функция получения имени хоста с защитой от подмены

Для критичных приложений (например, генерация токенов) стоит использовать только $_SERVER['SERVER_NAME'] после предварительной валидации.

Пример

<?php
function getTrustedServerName(): string {
    $name = $_SERVER['SERVER_NAME'] ?? '';
    // Проверка, что имя хоста соответствует ожидаемым доменам
    $allowedDomains = ['example.com', 'api.example.com'];
    if (in_array($name, $allowedDomains, true)) {
        return $name;
    }
    // Если недопустимо, используем fallback
    return $allowedDomains[0];
}
echo 'Доверенное имя: ' . getTrustedServerName();
?>
Доверенное имя: example.com

Получение адреса сервера в CLI-скриптах

При выполнении скрипта из командной строки массив $_SERVER пуст или содержит только базовые записи. Рекомендуется использовать gethostname() или php_uname('n').

Пример

<?php
$hostname = gethostname() ?: php_uname('n');
echo 'Hostname (CLI): ' . $hostname . PHP_EOL;
echo 'IP (попытка): ' . gethostbyname($hostname);
?>
Hostname (CLI): dev-machine.local
IP (попытка): 192.168.1.5

Валидация IP-адреса сервера

При использовании $_SERVER['SERVER_ADDR'] может потребоваться проверка, что это действительно IPv4 или IPv6.

Пример

<?php
$serverIp = $_SERVER['SERVER_ADDR'] ?? '0.0.0.0';
if (filter_var($serverIp, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6)) {
    echo 'Корректный IP: ' . $serverIp;
} else {
    echo 'Некорректный IP или не получен';
}
?>
Корректный IP: 10.0.0.1

Получение внешнего IP через сторонний сервис (продвинутый сценарий)

Иногда нужен внешний публичный IP сервера. Такой адрес можно получить, обратившись к API (например, ifconfig.me), но это не является стандартным методом PHP.

Пример

<?php
$externalIp = file_get_contents('https://ifconfig.me/ip');
if ($externalIp !== false) {
    echo 'Внешний IP: ' . trim($externalIp);
} else {
    echo 'Не удалось получить внешний IP';
}
?>
Внешний IP: 203.0.113.42

Адрес сервера PHP (как получить в коде) - comments

En
адрес сервера php (php)