Avatar ·

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

Всем привет! Я новичок в PHP и пытаюсь написать простую систему логирования, которая записывает, с какой страницы пользователь заходит на сайт. Мне нужно получить полный URL текущей страницы, включая протокол (http/https), домен и все GET-параметры. Я пробовал использовать `$_SERVER['REQUEST_URI']`, но он возвращает только путь, например `/page.php?id=123`. А мне нужно что-то вроде `https://mysite.com/page.php?id=123`. Пытался скомбинировать с `$_SERVER['HTTP_HOST']`, но в некоторых случаях получаю ошибки, особенно когда сайт работает через HTTPS. Вот мой текущий код: ```php $url = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; ``` Проблема в том, что: 1. Не учитывается HTTPS 2. Иногда `HTTP_HOST` отсутствует или содержит порт 3. На локальном сервере (OpenServer) всё ломается Подскажите, как правильно и надёжно получить полный URL? Хочется универсальное решение, которое будет работать и на продакшене, и на локальной машине. Спасибо! <<>>

Правильное получение полного URL в PHP

Ваша задача — классическая ситуация, с которой сталкивается почти каждый PHP-разработчик. Главная сложность в том, что $_SERVER — это суперглобальный массив, содержимое которого сильно зависит от конфигурации веб-сервера. Вот надёжное решение, которое учитывает все основные случаи.

Универсальная функция

function getFullUrl() {
    // Определяем протокол
    $protocol = 'http';
    if (
        (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') ||
        (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443) ||
        (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')
    ) {
        $protocol = 'https';
    }

    // Получаем хост (домен)
    $host = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? 'localhost';

    // Получаем URI (путь + GET параметры)
    $uri = $_SERVER['REQUEST_URI'] ?? '/';

    // Собираем полный URL
    return $protocol . '://' . $host . $uri;
}

Пояснение ключевых моментов

  • Протокол: проверяем три варианта — стандартный HTTPS, порт 443 (часто используется при reverse proxy) и заголовок X-Forwarded-Proto (для балансировщиков нагрузки).
  • Хост: используем HTTP_HOST (он включает порт, если он нестандартный), если его нет — SERVER_NAME, в крайнем случае — localhost.
  • URI: REQUEST_URI содержит всё, что идёт после домена, включая GET-параметры и якоря (#).

Дополнительные варианты

Если вам нужен URL без GET-параметров (только путь):

$urlWithoutQuery = strtok(getFullUrl(), '?');

Если нужен только базовый URL (протокол + домен):

function getBaseUrl() {
    $protocol = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') ? 'https' : 'http';
    $host = $_SERVER['HTTP_HOST'] ?? 'localhost';
    return $protocol . '://' . $host;
}

Важные замечания

  • Функция getFullUrl() работает корректно на 99% серверов, включая Apache, Nginx и OpenServer.
  • Для CLI-скриптов (запуск из командной строки) $_SERVER может быть пустым — в таких случаях функция вернёт http://localhost/.
  • Если ваш сайт работает за reverse proxy (например, Cloudflare или Nginx как прокси), обязательно проверяйте заголовок X-Forwarded-Proto — иначе вы всегда будете получать http, даже если реальное соединение HTTPS.

Используйте эту функцию в вашем логгере — она надёжна, проста и покрывает 99% реальных сценариев.

<<>>

Альтернативный подход: использование фильтров и обработка ошибок

Если вам нужно не просто получить URL, но и проверить его валидность, можно использовать комбинацию filter_var и запасных значений:

function safeGetFullUrl() {
    $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
    $host = filter_input(INPUT_SERVER, 'HTTP_HOST', FILTER_SANITIZE_URL) ?: 'localhost';
    $uri = filter_input(INPUT_SERVER, 'REQUEST_URI', FILTER_SANITIZE_URL) ?: '/';
    
    $url = $protocol . '://' . $host . $uri;
    
    // Проверка валидности URL
    if (filter_var($url, FILTER_VALIDATE_URL) === false) {
        // Запасной вариант — собираем вручную
        $url = $protocol . '://' . $host . '/' . ltrim($uri, '/');
    }
    
    return $url;
}

Плюсы этого подхода:

  • Безопаснее — использует filter_input вместо прямого доступа к массиву, что защищает от XSS-атак.
  • Валидация — проверяет, что получился корректный URL.
  • Обработка ошибок — если что-то пошло не так, функция всё равно вернёт рабочий URL.

Этот вариант особенно полезен, если вы выводите URL на страницу (например, в мета-теги) и хотите избежать инъекций.