uriurl-routingzend-framework2zend-framework-routingurl-helper

URIs with german special characters don't work (error 404) in Zend Framework 2


I want to get a list of cities, where each city name is linked and refers a page for this city:

enter image description here

The links (created in the view script) look like this:

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)

"Berlin", "Erlangen" etc. work, but if the city name contains a german special character (ä, ö, ü, Ä, Ö, Ü, or ß) like "Nürnberg", a 404 error occurs:

A 404 error occurred Page not found. The requested URL could not be matched by routing. No Exception available

Why? And how to get this working?

Thanks in advance!

EDIT:

My router settings:

'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(
                    // ...
                    ),
                ),
            ),
        ),
    ),
),

Solution

  • You need to change your constraints, you can use a regular expression which will match UTF8 characters, something like this:

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

    Notice the /u modifier (unicode).

    EDIT:

    The problem is resolved.

    Explanation:

    The RegEx Route maches the URIs with preg_match(...) (line 116 or 118 of Zend\Mvc\Router\Http\Regex). In order to mach a string with "special chars" (128+) one must pass the pattern modifier u to preg_match(...). Like this:

    $thisRegex = '/catalog/(?<city>[\p{L}]*)';
    $regexStr = '(^' . $thisRegex . '$)u'; // <-- here
    $path = '/catalog/Nürnberg';
    $matches = array();
    preg_match($regexStr, $path, $matches);
    

    And since RegEx Route passes a url-enccoded string to preg_match(...), it's furthermode needed to decode the string first:

    $thisRegex = '/catalog/(?<city>[\p{L}]*)';
    $regexStr = '(^' . $thisRegex . '$)u';
    $path = rawurldecode('/catalog/N%C3%BCrnberg');
    $matches = array();
    preg_match($regexStr, $path, $matches);
    

    These two steps are not provided in the RegEx Route, so that preg_match(...) gets a steing like '/catalog/N%C3%BCrnberg' and tries to mach it to a regex like '/catalog/(?<city>[\\p{L}]*)/u'

    The solution is to use a custom RegEx Route. Here is an example.