Как получить и проанализировать веб-адрес в PHP
Основные способы получения и обработки URL в PHP
При разработке веб-приложений часто требуется получить текущий URL, разобрать его на составляющие или проверить корректность. В PHP существует несколько подходов для работы с URL, каждый из которых подходит для определённых задач. Рассмотрим наиболее распространённые варианты.
Как получить полный URL текущей страницы?
Самый эффективный способ - использовать суперглобальный массив $_SERVER. Для формирования полного адреса потребуется собрать схему (HTTP/HTTPS), домен, порт и путь вместе с строкой запроса.
// Определение полного URL текущей страницы
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https://' : 'http://';
$host = $_SERVER['HTTP_HOST'];
$uri = $_SERVER['REQUEST_URI'];
$fullUrl = $protocol . $host . $uri;
echo $fullUrl;
// Результат: http://example.com/page?param=value
Пояснение шагов:
- Сначала проверяется наличие и значение $_SERVER['HTTPS'] - если не пусто и не равно 'off', значит используется защищённое соединение.
- Переменная $_SERVER['HTTP_HOST'] содержит домен и, возможно, порт (например, example.com:8080).
- Переменная $_SERVER['REQUEST_URI'] содержит путь и строку запроса (например, /page?param=value).
- Соединив части, получаем полный URL.
Типичные ошибки и способы их решения:
- На некоторых серверных конфигурациях $_SERVER['HTTPS'] может отсутствовать. Лучше дополнительно проверять через $_SERVER['SERVER_PORT'] (443 для HTTPS) или $_SERVER['REQUEST_SCHEME'] (если доступен).
- При использовании прокси-серверов реальный хост может передаваться в заголовке HTTP_X_FORWARDED_HOST, что требует отдельной обработки.
Как получить только путь без домена?
Если требуется лишь относительный путь, достаточно использовать $_SERVER['REQUEST_URI']. Однако он включает строку запроса. Для получения чистого пути можно применить функцию parse_url().
$uri = $_SERVER['REQUEST_URI']; // /page?param=value
$path = parse_url($uri, PHP_URL_PATH);
echo $path; // /page
Замечание: parse_url() работает как с полными, так и с относительными URL, возвращая указанную компоненту.
Проблемы: если URL содержит нестандартные символы (например, кириллицу), $_SERVER['REQUEST_URI'] может быть уже декодирован, а parse_url() может некорректно обработать кодировку. Рекомендуется применять rawurldecode() после разбора.
Как разобрать URL на составные части?
Функция parse_url() разбивает URL на схему, хост, порт, путь, строку запроса и фрагмент. Пример:
$url = 'https://user:pass@example.com:8080/path?name=value#fragment';
$parts = parse_url($url);
print_r($parts);
Результат будет ассоциативным массивом с ключами: scheme, host, port, user, pass, path, query, fragment.
Ошибка: parse_url() не проверяет валидность URL. Для полной проверки используйте filter_var() с флагом FILTER_VALIDATE_URL.
Как проверить, является ли строка корректным URL?
Встроенная фильтрация в PHP:
$url = 'https://example.com';
if (filter_var($url, FILTER_VALIDATE_URL)) {
echo 'URL корректен';
} else {
echo 'URL некорректен';
}
Флаг FILTER_VALIDATE_URL проверяет синтаксис, но не доступность ресурса.
Недостаток: не поддерживает многие реальные URL (например, с кириллическими доменами в IDN). Для таких случаев потребуется предварительная конвертация в Punycode через idn_to_ascii().
Как получить параметры запроса из URL?
Для строки запроса удобно использовать $_GET (если URL текущего запроса) или parse_str() для произвольной строки.
$queryString = 'name=John&age=30';
parse_str($queryString, $params);
print_r($params);
// Array ( [name] => John [age] => 30 )
Важно: parse_str() автоматически декодирует URL-кодированные символы.
При использовании $_GET нужно помнить, что значения уже обработаны и могут содержать небезопасные данные. Необходима санитизация перед использованием.
Как собрать URL из отдельных компонентов?
Для обратной задачи - формирования URL из массива параметров - применяют http_build_query().
$params = ['name' => 'John', 'age' => 30];
$query = http_build_query($params);
echo '/search?' . $query;
// /search?name=John&age=30
Функция корректно кодирует специальные символы.
Ошибка: если в параметрах есть массивы, http_build_query() добавляет квадратные скобки. Иногда это нежелательно, можно использовать второй параметр для настройки.
Как изменить отдельные части URL (например, заменить путь)?
Комбинация функций parse_url() и http_build_url() (из расширения PECL pecl_http) или ручное конструирование.
$oldUrl = 'http://example.com/old/page';
$parts = parse_url($oldUrl);
$parts['path'] = '/new/page';
$newUrl = $parts['scheme'] . '://' . $parts['host'] . $parts['path'];
echo $newUrl;
Для более сложных манипуляций можно использовать библиотеку, например, League/Url.
Проблема: если URL содержит порт, аутентификацию или фрагмент, простое склеивание может их потерять. Рекомендуется написать обёртку с учётом всех компонентов или использовать готовое решение.
Расширенные примеры работы с URL в PHP
Комплексное получение и нормализация текущего URL
Пример функции, которая возвращает полный URL с учётом возможных прокси и разных конфигураций сервера:
function getCurrentUrl() {
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
|| (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443)
? 'https://' : 'http://';
$host = $_SERVER['HTTP_HOST'] ?? '';
// Поддержка X-Forwarded-Host от прокси
if (!empty($_SERVER['HTTP_X_FORWARDED_HOST'])) {
$host = $_SERVER['HTTP_X_FORWARDED_HOST'];
}
$uri = $_SERVER['REQUEST_URI'] ?? '/';
return $protocol . $host . $uri;
}
echo getCurrentUrl();
// Пример вывода: https://example.com/path?q=test
// Результат (зависит от окружения): https://local.dev/myapp/index.php?page=1
Декодирование и анализ URL с кириллическими символами
PHP может получать URL уже декодированным. Для работы с не-ASCII символами необходимо их перекодировать.
$url = 'https://пример.рф/путь?имя=значение';
// Преобразование IDN домена
$asciiHost = idn_to_ascii(parse_url($url, PHP_URL_HOST));
echo $asciiHost; // xn--e1afmkfd.xn--p1ai
// Декодирование пути и query (если они не были декодированы)
$path = parse_url($url, PHP_URL_PATH);
$decodedPath = rawurldecode($path);
echo $decodedPath; // /путь
// Результат: xn--e1afmkfd.xn--p1ai /путь
Генерация URL с параметрами из массива и добавление к базовому URL
Создание ссылки с фильтрами или поисковыми параметрами:
$baseUrl = 'https://shop.example.com/catalog?category=books';
$filters = ['price_min' => 100, 'price_max' => 500, 'sort' => 'asc'];
$query = http_build_query($filters);
$fullUrl = $baseUrl . '&' . $query;
echo $fullUrl;
https://shop.example.com/catalog?category=books&price_min=100&price_max=500&sort=asc
Обратите внимание: используется символ &, так как в базовом URL уже есть параметр category. Если базовый URL не содержит параметров, следует добавлять ?.
Безопасное извлечение параметров из URL с проверкой на вредоносные данные
Фильтрация входных данных из строки запроса:
$rawUrl = 'http://example.com/page?name=&id=123';
$query = parse_url($rawUrl, PHP_URL_QUERY);
parse_str($query, $params);
// Санитизация значений
$safeParams = [];
foreach ($params as $key => $value) {
$safeParams[$key] = htmlspecialchars(strip_tags($value), ENT_QUOTES, 'UTF-8');
}
print_r($safeParams);
Array
(
[name] => <script>alert(1)</script>
[id] => 123
)
Разбор и модификация пути URL с помощью регулярных выражений
Извлечение сегментов пути, например, для реализации REST API:
$url = '/api/v2/users/42/profile';
preg_match('#^/api/(v[\d.]+)/([a-z]+)/(\d+)/([a-z]+)$#', $url, $matches);
print_r($matches);
Array
(
[0] => /api/v2/users/42/profile
[1] => v2
[2] => users
[3] => 42
[4] => profile
)
Метод полезен для маршрутизации, но требует аккуратности с кодировкой.
Проверка доступности URL через cURL
Проверка не только синтаксиса, но и существования ресурса по HTTP-коду:
function urlExists($url) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return ($httpCode >= 200 && $httpCode < 400);
}
$url = 'https://example.com';
var_dump(urlExists($url)); // bool(true) или false
bool(true)
Важно: не все URL, возвращающие 200, гарантируют наличие нужного контента, но это простой способ проверки доступности.