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)

«Берлин», «Эрланген» и т. д. работают, но если название города содержит немецкий специальный символ (ä, ö, ü, Ä, Ö, Ü или ß), например «Нюрнберг», возникает ошибка 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(
                    // ...
                    ),
                ),
            ),
        ),
    ),
),

person automatix    schedule 26.03.2013    source источник
comment
Разве не очевидно, что это не соответствует constraints, который вы определили?   -  person CBroe    schedule 26.03.2013
comment
Да ты прав. Я только что отредактировал настройки роутера. Это все еще не работает.   -  person automatix    schedule 26.03.2013
comment
Вы показали, как «выглядят» URL-адреса, но использовали ли вы правильную кодировку URL-адресов для этих специальных символов?   -  person CBroe    schedule 26.03.2013
comment
Нет, я этого не делал. Я установил названия городов в URI так, как они поступают из базы данных ($city->name, а не urlencode($city->name)).   -  person automatix    schedule 26.03.2013
comment
Если вы сами не кодируете специальные символы в URL-адресах, вы оставляете это на усмотрение клиента, и с этим вы можете легко столкнуться с проблемами с используемой кодировкой символов.   -  person CBroe    schedule 26.03.2013
comment
Если бы я использовал urlencode($city->name), я бы получил такие URI, как /catalog/N%25C3%25BCrnberg вместо /catalog/Nürnberg.   -  person automatix    schedule 26.03.2013
comment
Нет, %25C3%25BC будет дважды закодирован в URL-адресе ü%C3%BC будет правильным для ü в UTF-8. И современные браузеры по-прежнему отображают это как ü в строке состояния/адресной строке. Если вы неправильно кодируете специальные символы в URL, у вас могут возникнуть проблемы с браузером, использующим кодировку символов, отличную от UTF-8, и кодировать ее как, например, UTF-8. ISO-8859-1 ü, который будет просто %FC … и тогда вы действительно столкнетесь с проблемами при маршрутизации.   -  person CBroe    schedule 26.03.2013
comment
Я взглянул на HTML-код. На самом деле URI закодированы в URL-адресе (/catalog/N%C3%BCrnberg), ZF делает это по умолчанию. Я этого не знал и предоставил вам неверную информацию, извините. Кроме того, URI кодируется в URL-адресе.   -  person automatix    schedule 26.03.2013


Ответы (1)


Вам нужно изменить свои ограничения, вы можете использовать регулярное выражение, которое будет соответствовать символам UTF8, примерно так:

'/[\p{L}]+/u'

Обратите внимание на модификатор /u (юникод).

РЕДАКТИРОВАТЬ:

Проблема решена.

Объяснение:

Маршрут RegEx сопоставляет 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 Route передает строку в кодировке 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. Вот пример.

person Andrew    schedule 26.03.2013
comment
Спасибо! Это не работает для меня, но, возможно, я неправильно использую ваше регулярное выражение. Я заменил 'city' => '[a-zA-ZäöüÄÖÜß0-9_-]*', на 'city' => '/^\p{L}[\p{L} _.-]+$/u', - person automatix; 26.03.2013
comment
возможно, это был плохой пример, он просто иллюстрировал флаг /u. попробуйте '/[\p{L}]+/u' - person Andrew; 26.03.2013
comment
Наконец-то он работает! Спасибо за столь важную подсказку по модификатору! - person automatix; 27.03.2013
comment
Я уже разместил объяснение и ссылку на решение в качестве дополнения к вашему ответу. Что ты имеешь в виду? - person automatix; 02.04.2013
comment
Я добавил это в свой модификатор: /[\p{L}]+/u, но все еще не работает. Automatix, не могли бы вы поделиться тем, что вы использовали? - person ; 07.12.2015