Маршрут со специальными символами неправильно анализируется в Zend Framework 2

URI с немецкими специальными символами не работают (ошибка 404). У меня уже была эта проблема (здесь), и это было разрешено с помощью модификатора unicode и помощник пользовательского представления, который его использует.

Теперь у меня та же проблема с дочерним маршрутом Segment, но на этот раз подход с идентификатором юникода и настраиваемым помощником представления не работает.

Все запросы типа sld.tld/sport/sportäöüÄÖÜß/cityäöüÄÖÜß или sld.tld/sport/sportäöüÄÖÜß/cityäöüÄÖÜß/page/123 заканчиваются ошибкой 404.

/module/Catalog/config/module.config.php

<?php
return array(
    ...
    'router' => array(
        'routes' => array(
            'catalog' => array(
                ...
            ),
            'city' => array(
                ...
            ),
            // works correctly, if I remove the child route
            'sport' => array(
                'type'  => 'MyNamespace\Mvc\Router\Http\UnicodeRegex',
                'options' => array(
                    'regex' => '/catalog/(?<city>[\p{L}\p{Zs}]*)/(?<sport>[\p{L}\p{Zs}]*)',
                    'defaults' => array(
                        'controller' => 'Catalog\Controller\Catalog',
                        'action'     => 'list-courses',
                    ),
                    'spec'  => '/catalog/%city%/%sport%',
                ),
                'may_terminate' => true,
                'child_routes' => array(
                    'courses' => array(
                        'type'  => 'segment',
                        'options' => array(
                            'route' => '[/page/:page]',
                            'defaults' => array(
                                'controller' => 'Catalog\Controller\Catalog',
                                'action'     => 'list-courses',
                            ),
                        ),
                        'may_terminate' => true,
                    ),
                )
            ),
        ),
    ),
    ...
);

Я также пробовал это с дочерним маршрутом UnicodeRegex:

        'sport' => array(
            'type'  => 'MyNamespace\Mvc\Router\Http\UnicodeRegex',
            'options' => array(
                'regex' => '/catalog/(?<city>[\p{L}\p{Zs}]*)/(?<sport>[\p{L}\p{Zs}]*)',
                'defaults' => array(
                    'controller' => 'Catalog\Controller\Catalog',
                    'action'     => 'list-courses',
                ),
                'spec'  => '/catalog/%city%/%sport%',
            ),
            'may_terminate' => true,
            'child_routes' => array(
                'courses' => array(
                    'type'  => 'MyNamespace\Mvc\Router\Http\UnicodeRegex',
                    'options' => array(
                        'regex' => '/page/(?<page>[\p{N}]*)',
                        'defaults' => array(
                            'controller' => 'Catalog\Controller\Catalog',
                            'action'     => 'list-courses',
                        ),
                        'spec'  => '/page/%page%',
                    ),
                    'may_terminate' => true,
                ),
            )
        ),

Регулярное выражение Unicode

см. здесь

Сегмент Unicode

Расширяет Zend\Mvc\Router\Http\Segment и завершает ввод ВСЕХ вызовов preg_match(...) с помощью u:

Как заставить его работать?


person automatix    schedule 19.04.2013    source источник
comment
Я зарегистрировал это как ошибку в отслеживании проблем ZF2. Подписка там может помочь исправить этот апстрим.   -  person Caleb    schedule 17.03.2015


Ответы (1)


Только что взглянул на это, вам нужно изменить метод соответствия UnicodeRegex, чтобы он возвращал правильную длину для части URL-адреса, с которой он совпал, вот попытка исправить это, что, кажется, работает (по крайней мере, для меня) с ваша установка

public function match(Request $request, $pathOffset = null)
{
    if (!method_exists($request, 'getUri')) {
        return null;
    }

    $uri  = $request->getUri();
    $path = rawurldecode($uri->getPath());

    if ($pathOffset !== null) {
        $result = preg_match('(\G' . $this->regex . ')u', $path, $matches, null, $pathOffset);
    } else {
        $result = preg_match('(^' . $this->regex . '$)u', $path, $matches);
    }

    if (!$result) {
        return null;
    }

    foreach ($matches as $key => $value) {
        if (is_numeric($key) || is_int($key) || $value === '') {
            unset($matches[$key]);
        } else {
            $matches[$key] = rawurldecode($value);
        }
    }

    // at this point there's a mismatch between the length of the rawurlencoded path
    // that all other route helpers use, so we need to match their expectations
    // to do that we build the matched part from the spec, using the matched params 
    $url = $this->spec;
    $mergedParams = array_merge($this->defaults, $matches);
    foreach ($mergedParams as $key => $value) {
        $spec = '%' . $key . '%';
        if (strpos($url, $spec) !== false) {
            $url = str_replace($spec, rawurlencode($value), $url);
        }
    }
    // make sure the url we built from spec exists in the original uri path
    if (false === strpos($uri->getPath(), $url)) {
        return null;
    }
    // now we can get the matchedLength
    $matchedLength = strlen($url);

    return new RouteMatch($mergedParams, $matchedLength);
} 
person Crisp    schedule 19.04.2013
comment
Я только что попробовал его без UnicodeSegment -- и он все еще работает... Разве ВСЕ маршруты, используемые для запроса, не должны быть безопасными для юникода? - person automatix; 19.04.2013
comment
только если вы применяете ограничения юникода к параметрам в самом сегменте, в противном случае это не обязательно - person Crisp; 19.04.2013
comment
Для какой версии ZF2 противостоит данная модификация? Я столкнулся с почти такой же проблемой, но этот код у меня не работает, и я не смог выяснить, какие биты портировать для работы с 2.3.5. - person Caleb; 17.03.2015