Управление URL-адресами на языке PHP
Основные методы работы с URL в PHP
Наиболее эффективный способ разбора и сборки URL - использование встроенных функций parse_url(), parse_str() и http_build_query(). Они обрабатывают все стандартные части адреса, включая схему, хост, порт, путь, параметры и фрагмент.
Как разобрать URL на составные части и извлечь параметры запроса?
Функция parse_url() возвращает ассоциативный массив со всеми компонентами. Для получения строки запроса и её преобразования в массив используется parse_str().
$url = 'https://user:pass@example.com:8080/path/to/page?name=John&age=30#section';
$parts = parse_url($url);
print_r($parts);
parse_str($parts['query'] ?? '', $query);
print_r($query);
Php проверить ссылку (проверить ссылку в php)
Array
(
[scheme] => https
[host] => example.com
[port] => 8080
[user] => user
[pass] => pass
[path] => /path/to/page
[query] => name=John&age=30
[fragment] => section
)
Array
(
[name] => John
[age] => 30
)
Id ссылки php (идентификатор ссылки в php)
Типичные ошибки:
- Попытка извлечь query без проверки на существование - если URL не содержит строки запроса, ключ 'query' отсутствует. Всегда используйте оператор ?? или isset().
- Игнорирование кодировки: parse_str() автоматически декодирует параметры, но если данные передавались с двойным кодированием, результат может быть неверным.
- Неверное использование parse_url() с относительными URL - для относительных адресов функция всё равно корректно выделит путь и query, но компоненты host, scheme будут отсутствовать.
Когда может потребоваться разбор URL без использования специальных функций?
Если нужно обработать URL, не соответствующий стандарту (например, с нестандартными символами) или когда требуется полный контроль над процессом, можно разобрать строку вручную с помощью explode() и substr().
$url = 'https://example.com/path?q=test#frag';
// Разделение на схему и остальное
$schemeEnd = strpos($url, '://');
$scheme = substr($url, 0, $schemeEnd);
$rest = substr($url, $schemeEnd + 3);
// Извлечение хоста и пути
$hostEnd = strpos($rest, '/');
$host = substr($rest, 0, $hostEnd);
$pathAndQuery = substr($rest, $hostEnd);
echo "Схема: $scheme\nХост: $host\nПуть+query: $pathAndQuery";
активная ссылка php (создание активной ссылки в php)
Схема: https Хост: example.com Путь+query: /path?q=test#frag
Php ссылки (работа с url и ссылками в php)
Такой подход не обрабатывает сложные случаи (порт, авторизация, множественные ?). Для production лучше использовать parse_url(). Ручной разбор оправдан только при обучении или для очень специфических форматов.
Как извлечь домен или путь с помощью регулярных выражений?
Регулярные выражения позволяют гибко извлекать части URL, но код становится менее читаемым и может содержать ошибки при обработке граничных случаев.
$url = 'http://www.example.com:8080/page?id=1';
preg_match('#^([a-z]+)://([^/:]+)(:\d+)?(/[^?#]*)#i', $url, $matches);
print_r($matches);
Php адрес страницы (адрес страницы в php)
Array
(
[0] => http://www.example.com:8080/page
[1] => http
[2] => www.example.com
[3] => :8080
[4] => /page
)
Php uri (получение uri в php)
Регулярные выражения сложно поддерживать, они не покрывают все RFC-правила URL. Рекомендуется использовать parse_url(), а не писать собственные шаблоны.
Как создать строку запроса из массива параметров?
Функция http_build_query() принимает ассоциативный массив и возвращает URL-кодированную строку. Можно указать числовой индекс, разделитель и другие параметры.
$params = ['name' => 'Иван', 'age' => 25, 'city' => 'Москва'];
$query = http_build_query($params, '', '&');
echo $query;
Php page url (url текущей страницы в php)
name=%D0%98%D0%B2%D0%B0%D0%BD&age=25&city=%D0%9C%D0%BE%D1%81%D0%BA%D0%B2%D0%B0
По умолчанию http_build_query() использует & в качестве разделителя (с учётом HTML-сущностей), но можно задать любой. Ошибка - забыть закодировать спецсимволы, но функция делает это автоматически.
Почему важно кодировать спецсимволы в URL и как это сделать?
Для кодирования отдельных частей URL применяются urlencode() (для query string) и rawurlencode() (для пути, соответствует RFC 3986). Декодирование выполняют urldecode() и rawurldecode().
$str = 'цена=100 & товар';
echo urlencode($str) . "\n";
echo rawurlencode($str);
%D1%86%D0%B5%D0%BD%D0%B0%3D100+%26+%D1%82%D0%BE%D0%B2%D0%B0%D1%80 %D1%86%D0%B5%D0%BD%D0%B0%3D100%20%26%20%D1%82%D0%BE%D0%B2%D0%B0%D1%80
Главная ошибка - применение urlencode() ко всему URL целиком, а не к его отдельным частям, что приводит к неправильному кодированию символов :// и ?. Также путают urlencode() и rawurlencode(): первый превращает пробел в +, второй - в %20.
Как убедиться, что строка является корректным URL?
Фильтр FILTER_VALIDATE_URL из filter_var() проверяет URL на соответствие стандарту. Возвращает сам URL в случае успеха или false.
$urls = [
'https://example.com',
'ftp://user@host',
'not a url',
'//example.com/path'
];
foreach ($urls as $url) {
echo filter_var($url, FILTER_VALIDATE_URL) ? "Валидный: $url" : "Невалидный: $url";
echo "\n";
}
Валидный: https://example.com Валидный: ftp://user@host Невалидный: not a url Невалидный: //example.com/path
FILTER_VALIDATE_URL считает URL без схемы невалидным, но протоколо-относительные ссылки (//example.com) часто встречаются на практике. Функция также не проверяет доступность хоста. Для более строгой проверки можно дополнительно разбирать URL через parse_url().
Как выполнить редирект на другой URL?
Перенаправление осуществляется отправкой HTTP-заголовка Location с помощью функции header(). Перед вызовом не должно быть вывода в браузер (даже пробелов). После заголовка обязательно вызывается exit или die.
$target = 'https://new-site.com/page';
header('Location: ' . $target);
exit;
Ошибка - попытка редиректа после вывода текста (например, после echo). Это вызывает предупреждение PHP и редирект может не сработать. Всегда проверяйте наличие вывода перед header(). Также не забудьте закодировать URL, если он содержит недопустимые символы.
Расширенные примеры обработки URL
Объединение относительного URL с базовым
Часто требуется преобразовать относительный адрес в абсолютный, используя базовый URL. Реализация учитывает все компоненты.
function resolveUrl($base, $relative) {
$baseParts = parse_url($base);
$relativeParts = parse_url($relative);
if (isset($relativeParts['scheme'])) {
return $relative;
}
$result = $baseParts['scheme'] . '://' . $baseParts['host'];
if (isset($baseParts['port'])) {
$result .= ':' . $baseParts['port'];
}
if ($relative[0] === '/') {
$result .= $relative;
} else {
$basePath = dirname($baseParts['path'] ?? '/');
if ($basePath === '\\') $basePath = '/';
$result .= $basePath . '/' . $relative;
}
if (isset($relativeParts['query'])) {
$result .= '?' . $relativeParts['query'];
}
if (isset($relativeParts['fragment'])) {
$result .= '#' . $relativeParts['fragment'];
}
return $result;
}
echo resolveUrl('https://example.com/dir/page.php?x=1', 'sub/file.html#top');
echo "\n";
echo resolveUrl('https://example.com/dir/page.php', '/new/path');
echo "\n";
echo resolveUrl('https://example.com/dir/page.php', '//other.com/path');
https://example.com/dir/sub/file.html#top https://example.com/new/path https://other.com/path
Парсинг строки запроса с поддержкой множественных значений
Стандартный parse_str() корректно обрабатывает массивы параметров, но если нужно сохранить порядок или обработать повторяющиеся ключи, можно использовать пользовательскую функцию.
function parseQueryCustom($queryString) {
$result = [];
foreach (explode('&', $queryString) as $pair) {
$parts = explode('=', $pair, 2);
$key = urldecode($parts[0]);
$value = isset($parts[1]) ? urldecode($parts[1]) : '';
if (isset($result[$key])) {
$result[$key] = is_array($result[$key]) ? $result[$key] : [$result[$key]];
$result[$key][] = $value;
} else {
$result[$key] = $value;
}
}
return $result;
}
$query = 'key1=a&key2=b&key1=c';
print_r(parseQueryCustom($query));
Array
(
[key1] => Array
(
[0] => a
[1] => c
)
[key2] => b
)
Кодирование и декодирование с учётом разных схем
При работе с путями URL важно использовать rawurlencode(), чтобы пробелы кодировались как %20, а не +. Пример создания полного URL из частей.
function buildUrl($scheme, $host, $port = null, $path = '', $query = [], $fragment = '') {
$url = $scheme . '://' . $host;
if ($port) $url .= ':' . $port;
$url .= '/' . ltrim(rawurlencode($path), '/');
if ($query) $url .= '?' . http_build_query($query, '', '&', PHP_QUERY_RFC3986);
if ($fragment) $url .= '#' . rawurlencode($fragment);
return $url;
}
echo buildUrl('https', 'example.com', 8080, 'путь/к странице', ['ключ' => 'значение'], 'якорь');
https://example.com:8080/%D0%BF%D1%83%D1%82%D1%8C/%D0%BA%20%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B5?%D0%BA%D0%BB%D1%8E%D1%87=%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5#%D1%8F%D0%BA%D0%BE%D1%80%D1%8C
Проверка доступности URL с помощью cURL
Хотя тема статьи не про cURL, в разделе "Взаимодействие с HTTP" уместно показать, как убедиться, что URL действительно отвечает (например, код 200).
function urlExists($url) {
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_NOBODY => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10
]);
curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return $httpCode === 200;
}
echo urlExists('https://httpstat.us/200') ? 'Существует' : 'Не найдено';
echo "\n";
echo urlExists('https://httpstat.us/404') ? 'Существует' : 'Не найдено';
Существует Не найдено
Безопасное получение содержимого удалённого URL с проверкой ошибок
При загрузке контента по URL нужно обрабатывать ошибки соединения, таймауты и некорректные ответы. Пример с file_get_contents() и контекстом.
function fetchUrl($url) {
$options = [
'http' => [
'method' => 'GET',
'timeout' => 5,
'ignore_errors' => true
]
];
$context = stream_context_create($options);
$result = @file_get_contents($url, false, $context);
if ($result === false) {
$error = error_get_last();
return "Ошибка: " . ($error['message'] ?? 'Неизвестная ошибка');
}
return $result;
}
echo fetchUrl('https://example.com');
Ошибки: file_get_contents() не поддерживает сложные сценарии (COOKIE, перенаправления, работа с SSL-сертификатами). Для серьёзных задач используйте cURL или библиотеку Guzzle.