在Zend Framework 2中无法正确解析Route mit特殊字符

时间:2013-04-19 04:10:53

标签: php zend-framework2 http-status-code-404 zend-route zend-router

带有德语特殊字符的URI不起作用(错误404)。我已经遇到了这个问题(here),并且已经使用unicode modifiercustom view helper解决了这个问题。

现在我对Segment子路由有同样的问题,但这次使用unicode标识符和自定义视图助手的方法不起作用。

sld.tld/sport/sportäöüÄÖÜß/cityäöüÄÖÜßsld.tld/sport/sportäöüÄÖÜß/cityäöüÄÖÜß/page/123等Alle请求以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,
                ),
            )
        ),

UnicodeRegex

请参阅here

UnicodeSegment

扩展Zend\Mvc\Router\Http\Segment并使用preg_match(...)完成所有u次来电的输入:

如何让它运作?

1 个答案:

答案 0 :(得分:3)

刚看了一眼,你需要更改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);
}