URI с немецкими специальными символами не работают (ошибка 404) в Zend Framework 2
Я хочу получить список городов, где каждое название города связано и ссылается на страницу для этого города:
Ссылки (созданные в скрипте вида) выглядят так:
http://project.loc/catalog/Berlin (in the HTML source code url-encoded: Berlin)
http://project.loc/catalog/Erlangen (in the HTML source code url-encoded: Erlangen)
http://project.loc/catalog/Nürnberg (in the HTML source code url-encoded: N%C3%BCrnberg)
"Берлин", "Эрланген" и т. Д. Работают, но если название города содержит немецкий специальный символ (ä
, ö
, ü
, Ä
, Ö
, Ü
, или же ß
) как "Nürnberg", возникает ошибка 404:
Произошла ошибка 404 Страница не найдена. Запрашиваемый URL не может быть сопоставлен путем маршрутизации. Исключение не доступно
Зачем? И как заставить это работать?
Заранее спасибо!
РЕДАКТИРОВАТЬ:
Мои настройки роутера:
'router' => array(
'routes' => array(
'catalog' => array(
'type' => 'literal',
'options' => array(
'route' => '/catalog',
'defaults' => array(
'controller' => 'Catalog\Controller\Catalog',
'action' => 'list-cities',
),
),
'may_terminate' => true,
'child_routes' => array(
'city' => array(
'type' => 'segment',
'options' => array(
'route' => '/:city',
'constraints' => array(
'city' => '[a-zA-ZäöüÄÖÜß0-9_-]*',
),
'defaults' => array(
'controller' => 'Catalog\Controller\Catalog',
'action' => 'list-sports',
),
),
'may_terminate' => true,
'child_routes' => array(
// ...
),
),
),
),
),
),
1 ответ
Вам нужно изменить ограничения, вы можете использовать регулярное выражение, которое будет соответствовать символам UTF8, что-то вроде этого:
'/[\p{L}]+/u'
Обратите внимание на модификатор /u (юникод).
РЕДАКТИРОВАТЬ:
Проблема решена.
Объяснение:
RegEx Route сопоставляет URI с preg_match(...)
(строка 116 или 118 Zend\Mvc\Router\Http\Regex). Чтобы обработать строку со "специальными символами" (128+), необходимо передать модификатор шаблона u
в preg_match(...)
, Как это:
$thisRegex = '/catalog/(?<city>[\p{L}]*)';
$regexStr = '(^' . $thisRegex . '$)u'; // <-- here
$path = '/catalog/Nürnberg';
$matches = array();
preg_match($regexStr, $path, $matches);
И так как маршрут RegEx передает строку в кодировке URL preg_match(...)
, далее требуется режим, чтобы сначала декодировать строку:
$thisRegex = '/catalog/(?<city>[\p{L}]*)';
$regexStr = '(^' . $thisRegex . '$)u';
$path = rawurldecode('/catalog/N%C3%BCrnberg');
$matches = array();
preg_match($regexStr, $path, $matches);
Эти два шага не предусмотрены в маршруте RegEx, так что preg_match(...)
получает удар как '/catalog/N%C3%BCrnberg'
и пытается обработать это как регулярное выражение '/catalog/(?<city>[\\p{L}]*)/u'
Решение состоит в том, чтобы использовать пользовательский маршрут RegEx. Вот пример.