Маршрутизация и русские символы в URL: работа с index.php
Маршрутизация URL с русскими символами через index.php
Наиболее эффективный способ обработки русскоязычных URL в одностраничном приложении (Single Entry Point) — использование модуля mod_rewrite в паре с аккуратным декодированием кириллицы. Этот подход позволяет перенаправлять все запросы на index.php и при этом корректно передавать русские буквы, закодированные в URL как UTF-8.
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?path=$1 [L,QSA]
Сервер Apache передаёт переменную $_GET['path'] в сыром виде (процентная кодировка). В PHP необходимо применить rawurldecode() для восстановления русского текста.
$rawPath = $_GET['path'] ?? '';
$path = rawurldecode($rawPath);
// Пример: /категория/статья → 'категория/статья'
Типичные ошибки:
- Использование
urldecode()вместоrawurldecode()может привести к потере символа '+', который интерпретируется как пробел. - Двойное кодирование: если в .htaccess не указан флаг
B(без преобразования), Apache может повторно закодировать кириллицу. - Игнорирование настройки
AcceptPathInfo— в некоторых конфигурациях PATH_INFO теряется.
Какая конфигурация сервера обеспечивает передачу русских букв в URL без искажений?
Основной случай использования — любой сайт с русскоязычным контентом, где маршруты содержат кириллицу (например, /блог/статья-о-пхп). Метод гарантирует корректную работу с любыми серверами Apache, поддерживающими UTF-8.
Как обработать русский URL через PATH_INFO без mod_rewrite?
Если mod_rewrite недоступен, можно использовать переменную $_SERVER['PATH_INFO']. Она появляется, когда запрос приходит напрямую к index.php/path (слэш после имени файла). Сервер передаёт часть пути после имени скрипта в этой переменной.
// URL: http://example.com/index.php/русский-путь
$path = isset($_SERVER['PATH_INFO']) ? trim($_SERVER['PATH_INFO'], '/') : '';
$path = rawurldecode($path);
Проблема: PATH_INFO может отсутствовать в некоторых конфигурациях (например, Nginx или при включённом CGIPathInfo в php-fpm). Также теряются query-параметры после пути.
Как применить разбор REQUEST_URI вручную для русских URL?
Можно вручную извлечь путь из $_SERVER['REQUEST_URI'] и удалить имя скрипта. Этот метод не зависит от mod_rewrite.
$requestUri = $_SERVER['REQUEST_URI'];
$scriptName = $_SERVER['SCRIPT_NAME'];
$path = str_replace($scriptName, '', $requestUri);
$path = parse_url($path, PHP_URL_PATH);
$path = rawurldecode(trim($path, '/'));
Ошибки: если SCRIPT_NAME не совпадает с путём из-за символических ссылок или редиректов, разбор будет неверен. Также не обрабатывается ?query — его нужно удалять через parse_url.
Как реализовать маршрутизацию с русским URL через библиотеку FastRoute?
Библиотека nikic/fast-route поддерживает UTF-8 в шаблонах, если задать корректную обработку URI. Пример настройки:
$dispatcher = FastRoute\simpleDispatcher(function(FastRoute\RouteCollector $r) {
$r->addRoute('GET', '/блог/{slug:.*}', 'blog_handler');
});
$httpMethod = $_SERVER['REQUEST_METHOD'];
$uri = rawurldecode(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH));
$routeInfo = $dispatcher->dispatch($httpMethod, $uri);
Библиотека по умолчанию не производит декодирование, поэтому декодировать URI нужно до передачи в диспетчер. Регулярные выражения со специальными символами (например, . или +) в русском тексте могут нарушить шаблон.
Расширенные примеры обработки русских URL в index.php
Пример 1: mod_rewrite + rawurldecode с фильтром безопасности
# .htaccess
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?url=$1 [B,L,QSA]
# index.php
$url = $_GET['url'] ?? '';
$url = rawurldecode($url);
// Удаление небезопасных символов, кроме кириллицы, слешей и дефисов
$url = preg_replace('/[^\p{Cyrillic}\w\/-]/u', '', $url);
$segments = explode('/', $url);
print_r($segments);
Для URL /привет-мир/добро-пожаловать
Вывод:
Array
(
[0] => привет-мир
[1] => добро-пожаловать
)
Результат:
Массив сегментов пути с корректно восстановленной кириллицей.
Пример 2: Обработка через PATH_INFO с fallback на REQUEST_URI
function getRussianPath() {
if (isset($_SERVER['PATH_INFO']) && $_SERVER['PATH_INFO'] !== '') {
$path = $_SERVER['PATH_INFO'];
} else {
// Fallback: извлечение из REQUEST_URI
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$scriptName = dirname($_SERVER['SCRIPT_NAME']);
if ($scriptName === '/') $scriptName = '';
$path = substr($path, strlen($scriptName));
}
return rawurldecode(trim($path, '/'));
}
$path = getRussianPath();
echo "Путь: $path";
URL: http://example.com/index.php/русский/текст Путь: русский/текст
Пример 3: Использование parse_str с кириллическими параметрами в GET
// URL: index.php?page=новости&id=5
$page = $_GET['page'] ?? '';
$page = mb_convert_encoding($page, 'UTF-8', 'auto');
echo "Страница: $page<br>";
echo "ID: " . (int)($_GET['id'] ?? 0);
Страница: новости ID: 5
Если сервер не настроен на UTF-8, $_GET может содержать искажённые данные. Применение mb_convert_encoding с автоопределением исправляет ситуацию, но добавляет нагрузку. Лучше установить default_charset в UTF-8 в php.ini.
Пример 4: Ручная сборка маршрутизатора с поддержкой Unicode
class Router {
private array $routes = [];
public function add(string $pattern, callable $handler): void {
// Экранируем слеши, заменяем {param} на захватывающую группу
$pattern = preg_replace('/\//', '\/', $pattern);
$pattern = preg_replace('/\{([a-z]+)\}/', '(?P<$1>[^/]+)', $pattern);
$this->routes[] = [
'pattern' => '/^' . $pattern . '$/u',
'handler' => $handler
];
}
public function dispatch(string $uri): void {
$uri = rawurldecode($uri);
foreach ($this->routes as $route) {
if (preg_match($route['pattern'], $uri, $matches)) {
$params = array_filter($matches, 'is_string', ARRAY_FILTER_USE_KEY);
call_user_func($route['handler'], $params);
return;
}
}
// 404
}
}
$router = new Router();
$router->add('блог/{slug}', function($params) {
echo "Запрос блога со слагом: " . $params['slug'];
});
$router->dispatch($_SERVER['REQUEST_URI']);
URL: /блог/заметка-про-php Запрос блога со слагом: заметка-про-php
Пример 5: Обработка кириллических GET-параметров через mod_rewrite (без PATH_INFO)
# .htaccess
RewriteRule ^(.*)$ index.php [E=RAW_PATH:$1,END]
# index.php
$path = $_SERVER['REDIRECT_RAW_PATH'] ?? $_SERVER['RAW_PATH'] ?? '';
$path = rawurldecode($path);
// Дальнейшая обработка
Переменная окружения может называться по-разному в зависимости от версии Apache. Иногда требуется REDIRECT_RAW_PATH.