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. Вот пример.

Другие вопросы по тегам