Практическое получение веб-адреса в PHP: методы и нюансы

Раздел: Веб-разработка на PHP -> Параметры HTTP-запроса и серверные данные

Основные способы получения URL в PHP

Как собрать полный URL текущей страницы?

Наиболее универсальное решение - написать собственную функцию, которая объединяет все необходимые переменные $_SERVER. Это позволяет учесть протокол, хост, порт и путь с параметрами.


function getCurrentUrl() {
  $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
  $host = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? 'localhost';
  $port = $_SERVER['SERVER_PORT'] ?? 80;
  $uri = $_SERVER['REQUEST_URI'] ?? '/';

  // Добавляем порт только если он нестандартный
  $portPart = (($protocol === 'http' && $port != 80) || ($protocol === 'https' && $port != 443)) ? ':' . $port : '';

  return $protocol . '://' . $host . $portPart . $uri;
}

echo getCurrentUrl();

Php get client (получить данные клиента в php)

http://example.com/path/to/page?param=1

Php get url (получить url в php)

Функция проверяет наличие HTTPS, определяет хост из HTTP_HOST (или резервного SERVER_NAME), добавляет порт только если он отличается от стандартного для протокола, и возвращает полный URL.

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

  • Если скрипт работает через обратный прокси, переменная HTTPS может быть не установлена. В таком случае нужно проверять заголовок HTTP_X_FORWARDED_PROTO.
  • Если сайт доступен по нескольким доменам, HTTP_HOST вернет тот, который указал клиент. Для коррекции нужно использовать SERVER_NAME (если настроен корректно).
  • При работе с командной строкой (CLI) переменные $_SERVER могут отсутствовать. Следует добавить проверки на существование.

Как получить только путь и параметры (относительный URL)?


echo $_SERVER['REQUEST_URI'];
/index.php?utm_source=twitter

Переменная REQUEST_URI содержит путь от корня домена вместе с query-строкой. Это самый простой способ получить относительный адрес.

Ошибка: в некоторых конфигурациях Apache может отсутствовать, если не используется mod_rewrite или неправильно настроен FallbackResource. Решение - использовать $_SERVER['PATH_INFO'] или $_SERVER['ORIG_PATH_INFO'].

Как получить только имя скрипта (без параметров)?


echo $_SERVER['SCRIPT_NAME'];
echo $_SERVER['PHP_SELF'];
/scripts/index.php

Обе переменные показывают путь к текущему скрипту относительно корня, но PHP_SELF может содержать модификации от пользовательского ввода (уязвимость). Рекомендуется использовать SCRIPT_NAME.

Проблема: если в URL передан путь после имени скрипта (path info), PHP_SELF включает его, а SCRIPT_NAME - нет. Выбор зависит от задачи.

Как получить хост без протокола?


echo $_SERVER['HTTP_HOST'];
echo $_SERVER['SERVER_NAME'];
www.example.com

HTTP_HOST берется из HTTP-заголовка Host, а SERVER_NAME - из настройки сервера. Первый удобнее для динамических сред, второй - для стабильного имени.

Ошибка: при использовании виртуальных хостов SERVER_NAME может не совпадать с реальным доменом, если он задан как *.

Как определить, используется ли HTTPS?


$isHttps = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off');
echo $isHttps ? 'https' : 'http';
https

Проверка через HTTPS и SERVER_PORT не всегда надёжна за прокси. Альтернатива - заголовок HTTP_X_FORWARDED_PROTO.

Типичная ошибка: в некоторых окружениях $_SERVER['HTTPS'] может быть 'off' или пустым. Проверка на 'off' обязательна.

Как получить URL без GET-параметров?


$url = $_SERVER['REQUEST_URI'];
$path = strtok($url, '?');
echo $path;
// или
$parsed = parse_url($url);
echo $parsed['path'];
/products/category/123

Функция strtok отсекает все после первого вопроса, а parse_url возвращает массив с компонентами. Второй способ надёжнее.

Проблема: если в пути встречается символ ?, strtok сработает некорректно. parse_url безопаснее.

Как получить базовый URL сайта (протокол + хост)?


$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
$host = $_SERVER['HTTP_HOST'];
echo $protocol . '://' . $host;
https://example.com

Этот базовый URL часто используется для построения абсолютных ссылок на ресурсы или редиректов.

Ошибка: если порт нестандартный, нужно добавлять :port. Иначе ссылки будут вести не туда.

Как учесть обратный прокси (Nginx, Cloudflare)?


function getFromForwardedHeaders() {
  $protocol = $_SERVER['HTTP_X_FORWARDED_PROTO'] ?? (empty($_SERVER['HTTPS']) ? 'http' : 'https');
  $host = $_SERVER['HTTP_X_FORWARDED_HOST'] ?? $_SERVER['HTTP_HOST'];
  $port = $_SERVER['HTTP_X_FORWARDED_PORT'] ?? $_SERVER['SERVER_PORT'];
  $uri = $_SERVER['REQUEST_URI'];
  return $protocol . '://' . $host . ($port ? ':' . $port : '') . $uri;
}

// Вызов
echo getFromForwardedHeaders();
https://example.com/path

Прокси часто подставляют специальные заголовки (X-Forwarded-*). Их использование обязательно, если сайт за балансировщиком.

Проблема безопасности: заголовки X-Forwarded-* могут быть подделаны клиентом. Доверять им нужно только если прокси настроен на удаление внешних заголовков (например, через trusted proxies).

Расширенные примеры получения URL в PHP

Полная функция с поддержкой обратного прокси и настройками безопасности

Эта функция позволяет получать правильный URL в большинстве окружений: от обычного Apache до сложных балансировщиков.

Пример

function getCurrentUrlSecure(array $trustedProxies = []) {
  // 1. Определяем, можно ли доверять заголовкам прокси
  $clientIp = $_SERVER['REMOTE_ADDR'] ?? '';
  $useForwarded = in_array($clientIp, $trustedProxies, true) || empty($trustedProxies);

  // 2. Протокол
  if ($useForwarded && isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
    $protocol = $_SERVER['HTTP_X_FORWARDED_PROTO'];
  } else {
    $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
  }

  // 3. Хост
  if ($useForwarded && isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
    $host = $_SERVER['HTTP_X_FORWARDED_HOST'];
  } else {
    $host = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? 'localhost';
  }

  // 4. Порт
  if ($useForwarded && isset($_SERVER['HTTP_X_FORWARDED_PORT'])) {
    $port = (int)$_SERVER['HTTP_X_FORWARDED_PORT'];
  } else {
    $port = (int)($_SERVER['SERVER_PORT'] ?? 80);
  }

  // 5. Путь и параметры
  $uri = $_SERVER['REQUEST_URI'] ?? '/';

  // 6. Формируем порт (если нестандартный)
  $portPart = '';
  if (($protocol === 'http' && $port !== 80) || ($protocol === 'https' && $port !== 443)) {
    $portPart = ':' . $port;
  }

  return $protocol . '://' . $host . $portPart . $uri;
}

// Использование
echo getCurrentUrlSecure(['192.168.1.1', '10.0.0.1']);
https://example.com:8080/page?action=edit

В примере добавлена проверка доверенных прокси. Если IP клиента входит в список, используются forwarded-заголовки. Это предотвращает атаки с подделкой заголовков.

Разбор URL на компоненты с помощью parse_url

Пример

$url = 'https://user:pass@example.com:8080/path/to/page?name=john#section1';
$parts = parse_url($url);

print_r($parts);
Array
(
    [scheme] => https
    [host] => example.com
    [port] => 8080
    [user] => user
    [pass] => pass
    [path] => /path/to/page
    [query] => name=john
    [fragment] => section1
)

Обратная операция - http_build_url (из PECL) или сборка вручную. parse_url особенно полезна для преобразования относительных путей в абсолютные.

Получение базового URL (без пути и параметров) для построения ссылок

Пример

function getBaseUrl() {
  $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
  $host = $_SERVER['HTTP_HOST'];
  $port = $_SERVER['SERVER_PORT'];
  $portPart = (($protocol === 'http' && $port != 80) || ($protocol === 'https' && $port != 443)) ? ':' . $port : '';
  return $protocol . '://' . $host . $portPart;
}

$base = getBaseUrl();
$fullUrl = $base . '/assets/css/style.css';
echo $fullUrl;
http://example.com/assets/css/style.css

Базовый URL необходим для создания абсолютных ссылок на CSS, JS, изображения в многосайтовых установках или при отправке email.

Использование в маршрутизации (роутинг) для извлечения пути без параметров

Пример

$uri = $_SERVER['REQUEST_URI'];
$cleanPath = parse_url($uri, PHP_URL_PATH); // только путь

// Пример роутинга
switch (true) {
  case $cleanPath === '/' :
    $controller = 'HomeController';
    break;
  case preg_match('#^/blog/(\d+)$#', $cleanPath, $matches):
    $controller = 'BlogController';
    $id = $matches[1];
    break;
  default:
    http_response_code(404);
    $controller = 'ErrorController';
}
echo "Controller: $controller";
Controller: BlogController

При разработке собственного роутера важно отбросить GET-параметры и использовать только путь. parse_url справляется с этой задачей.

Безопасное получение URL через filter_input

Пример

$uri = filter_input(INPUT_SERVER, 'REQUEST_URI', FILTER_SANITIZE_URL);
if ($uri === false || $uri === null) {
  $uri = '/';
}
echo $uri;
/about?ref=home

Функция filter_input очищает значение от потенциально опасных символов, хотя для URL достаточно санитизации. Это альтернатива прямому доступу к $_SERVER.

Замечание: filter_input не проверяет существование ключа, нужно явно проверять на false/null.

Получение URL с учётом порта и сокета (CLI)

При запуске из командной строки переменные сервера обычно отсутствуют. Можно задать значения по умолчанию или взять из аргументов.

Пример

$protocol = 'http';
$host = 'localhost';
$port = 8000;
$uri = '/index.php';

if (php_sapi_name() === 'cli') {
  // Для встроенного сервера PHP порт передаётся через argv
  global $argv;
  if (isset($argv[1])) {
    $uri = $argv[1];
  }
}

echo "$protocol://$host:$port$uri";
http://localhost:8000/index.php

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

Получить URL в PHP - comments

En
Php get url (php)