Определение адреса сервера в 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