Формирование URL-адресов в PHP: практическое руководство
Основные методы построения URL в PHP
Наиболее эффективным решением для генерации ссылок в PHP является создание собственной функции, учитывающей базовый URL, путь и параметры запроса. Это обеспечивает единообразие, безопасность и лёгкость поддержки.
define('BASE_URL', 'https://example.com');
function buildUrl(string $path, array $params = []): string {
$url = rtrim(BASE_URL, '/') . '/' . ltrim($path, '/');
if (!empty($params)) {
$url .= '?' . http_build_query($params, '', '&', PHP_QUERY_RFC3986);
}
return $url;
}
// Пример использования
echo buildUrl('/catalog', ['category' => 'books', 'page' => 2]);
// Результат: https://example.com/catalog?category=books&page=2код ссылки php (код ссылки php)
Функция http_build_query корректно кодирует параметры, предотвращая XSS-атаки. Константа BASE_URL позволяет легко менять домен или протокол.
Как избежать двойных слешей в URL?
Если путь уже начинается со слеша, функция ltrim удалит его, а rtrim удалит слеш из BASE_URL. Однако при изменении константы может возникнуть дублирование. Решение: всегда задавать BASE_URL без завершающего слеша, а путь с ведущим слешем или без – функция сама нормализует.
Когда достаточно относительной ссылки?
Если документ и целевая страница находятся на одном домене, можно использовать относительный путь. Это упрощает перенос сайта между средами.
$relative = '/about/team';
echo 'О команде';
Почему обязательно использовать htmlspecialchars?
При выводе в HTML любые данные, включая URL, должны быть экранированы, чтобы избежать XSS. Использование htmlspecialchars с флагом ENT_QUOTES гарантирует безопасность.
Как добавить якорь (anchor) к ссылке?
Якорь добавляется после URL через символ #. Важно включать якорь после всех параметров запроса.
$url = 'https://example.com/page?section=faq#answer3';
// Сборка:
$base = 'https://example.com/page';
$params = ['section' => 'faq'];
$anchor = 'answer3';
$full = $base . '?' . http_build_query($params) . '#' . $anchor;
echo $full;
https://example.com/page?section=faq#answer3
Что если якорь содержит специальные символы?
Якорь не проходит URL-кодирование; он должен быть простым идентификатором. Если якорь формируется динамически, следует ограничить допустимые символы.
Как передать API-ключ в URL без утечки?
Для API-запросов часто требуется токен в query-параметре. Не рекомендуется включать его в URL для GET-запросов, лучше использовать заголовки. Если же необходимо, параметр следует передавать через http_build_query и хранить ключ в переменной окружения.
$apiKey = getenv('API_KEY');
$url = 'https://api.example.com/data?' . http_build_query(['key' => $apiKey, 'format' => 'json']);
echo $url;
Почему не стоит жестко прописывать ключ в коде?
Ключи доступа должны храниться вне репозитория (в .env). При выводе URL с ключом в логах или HTML он может быть скомпрометирован. Для внутренних запросов используйте curl с заголовком Authorization.
Как организовать дружественные URL для CMS?
Современные CMS используют роутинг, где URL собирается из маршрута и параметров. Пример с использованием простого роутера:
$routes = [
'product' => '/catalog/{id}/{slug}',
'page' => '/{slug}',
];
function route(string $name, array $params = []): string {
global $routes;
if (!isset($routes[$name])) return '#';
$url = $routes[$name];
foreach ($params as $key => $value) {
$url = str_replace('{'.$key.'}', rawurlencode($value), $url);
}
return $url;
}
// Генерация ссылки на товар с id=42 и slug='phone'
echo route('product', ['id' => 42, 'slug' => 'phone-mobile']);
/catalog/42/phone-mobile
Как избежать неопределенных параметров?
Если в шаблоне маршрута остались не замененные плейсхолдеры, URL будет содержать {param}. Следует проверять наличие всех ключей до замены.
Расширенные примеры генерации URL
Использование PSR-7 UriInterface
Компонент HTTP Foundation или Guzzle предоставляет объект Uri для работы с URL.
use GuzzleHttp\Psr7\Uri;
use GuzzleHttp\Psr7\Query;
$uri = new Uri('https://example.com/path');
$uri = $uri->withQuery(Query::build(['page' => 3, 'sort' => 'desc']));
echo $uri; // https://example.com/path?page=3&sort=desc
https://example.com/path?page=3&sort=desc
Метод withQuery заменяет строку запроса, обеспечивая корректное кодирование.
Генерация URL с поддоменом
Для мультисайтовых приложений динамически меняется поддомен.
$subdomain = 'shop';
$base = 'example.com';
$scheme = 'https';
$url = $scheme . '://' . $subdomain . '.' . $base . '/products';
echo $url; // https://shop.example.com/products
https://shop.example.com/products
Следует экранировать поддомен, если он берется из пользовательского ввода.
Создание ссылок с сохранением состояния пагинации
На странице результатов часто нужно сохранить все параметры кроме page.
$base = '/search';
$params = $_GET; // или массив
unset($params['page']); // удаляем текущий номер страницы
$url = $base . '?' . http_build_query($params);
// Для каждой страницы:
for ($i = 1; $i <= 5; $i++) {
$paginatedUrl = $url . '&page=' . $i;
echo 'Страница ' . $i . ' ';
}
/search?q=php&category=books&page=1
Использование http_build_query гарантирует, что спецсимволы будут закодированы.
Работа с URL-rewriting через .htaccess
При использовании mod_rewrite внутренние URL преобразуются. Генерация ссылок должна соответствовать внешнему виду.
// Внешний URL: /article/123/hello-world
// Внутренний: index.php?page=article&id=123
function articleUrl(int $id, string $slug): string {
return '/article/' . $id . '/' . rawurlencode($slug);
}
echo articleUrl(123, 'hello world'); // /article/123/hello%20world
/article/123/hello%20world
При выводе в HTML ссылку следует экранировать htmlspecialchars.
Сравнение urlencode и rawurlencode
urlencode кодирует пробел как '+', rawurlencode как '%20'. Для query-строки обычно используют rawurlencode для совместимости с RFC 3986, но PHP функции http_build_query по умолчанию использует '+'. Флаг PHP_QUERY_RFC3986 переключает на '%20'.
echo urlencode('hello world'); // hello+world
echo rawurlencode('hello world'); // hello%20world
hello+world hello%20world
При ручной сборке строки запроса рекомендуется использовать rawurlencode.